// exception catch support for JVMTI, also restore stack after Stack Overflow Error void jvmti_exception_catch_callback() { Registers regs = {0}; VM_thread *thread = p_TLS_vmthread; assert(thread); if (thread->regs) { regs = *(Registers*)thread->regs; } M2nFrame* m2n = (M2nFrame *) STD_ALLOCA(m2n_get_size()); m2n_push_suspended_frame(thread, m2n, ®s); M2nFrame* prev_m2n = m2n_get_previous_frame(m2n); StackIterator* si = (StackIterator*) STD_ALLOCA(si_size()); si_fill_from_registers(si, ®s, false, prev_m2n); // si_create_from_registers uses large stack space, // so guard page restored after its invoke, // but befor ti agent callback invokation, // because it should work on protected page. if (p_TLS_vmthread->restore_guard_page) { int res = port_thread_restore_guard_page(); if (res != 0) { Global_Env *env = VM_Global_State::loader_env; if (si_is_native(si)) { m2n_set_last_frame(prev_m2n); if ((interpreter_enabled() || (!prev_m2n) || (m2n_get_frame_type(prev_m2n) & FRAME_NON_UNWINDABLE))) { exn_raise_by_class(env->java_lang_StackOverflowError_Class); } else { //si_free(si); exn_throw_by_class(env->java_lang_StackOverflowError_Class); } } else { //si_free(si); exn_throw_by_class(env->java_lang_StackOverflowError_Class); } } p_TLS_vmthread->restore_guard_page = false; } if (!si_is_native(si)) { CodeChunkInfo* catch_cci = si_get_code_chunk_info(si); assert(catch_cci); Method* catch_method = catch_cci->get_method(); NativeCodePtr catch_method_location = si_get_ip(si); JIT* catch_method_jit = catch_cci->get_jit(); ManagedObject** exn_obj = (ManagedObject**) si_get_return_pointer(si); *exn_obj = jvmti_jit_exception_catch_event_callback_call( *exn_obj, catch_method_jit, catch_method, catch_method_location); } si_transfer_control(si); }
/* * Get Bytecodes * * For the method indicated by method, return the byte codes that * implement the method. The number of bytecodes is returned via * bytecode_count_ptr. The byte codes themselves are returned via * bytecodes_ptr. * * OPTIONAL Functionality. */ jvmtiError JNICALL jvmtiGetBytecodes(jvmtiEnv* env, jmethodID method, jint* bytecode_count_ptr, unsigned char** bytecodes_ptr) { TRACE("GetBytecodes called"); SuspendEnabledChecker sec; /* * Check given env & current phase. */ jvmtiPhase phases[] = {JVMTI_PHASE_START, JVMTI_PHASE_LIVE}; CHECK_EVERYTHING(); CHECK_CAPABILITY(can_get_bytecodes); /** * Check is_native_ptr */ if( !bytecode_count_ptr || !bytecodes_ptr ) { return JVMTI_ERROR_NULL_POINTER; } /** * Check method */ if( !method ) { return JVMTI_ERROR_INVALID_METHODID; } Method* mtd = (Method*)method; if( mtd->is_native() ) return JVMTI_ERROR_NATIVE_METHOD; if( mtd->get_byte_code_addr() == NULL ) return JVMTI_ERROR_OUT_OF_MEMORY; *bytecode_count_ptr = mtd->get_byte_code_size(); jvmtiError err = _allocate( *bytecode_count_ptr, bytecodes_ptr ); if( err != JVMTI_ERROR_NONE ) return err; memcpy( *bytecodes_ptr, mtd->get_byte_code_addr(), *bytecode_count_ptr ); if (interpreter_enabled()) { TIEnv *p_env = (TIEnv *)env; VMBreakPoints* vm_brpt = p_env->vm->vm_env->TI->vm_brpt; LMAutoUnlock lock(vm_brpt->get_lock()); for (VMBreakPoint* bpt = vm_brpt->find_method_breakpoint(method); bpt; bpt = vm_brpt->find_next_method_breakpoint(bpt, method)) { (*bytecodes_ptr)[bpt->location] = (unsigned char)bpt->saved_byte; } } return JVMTI_ERROR_NONE; }
static void ti_enumerate_thread(TIEnv *ti_env, VM_thread* thread) { TIIterationState *state = ti_env->iteration_state; state->root_kind = JVMTI_HEAP_ROOT_THREAD; state->thread_tag = ti_env->tags->get( (Managed_Object_Handle) jthread_self()->object); if (interpreter_enabled()) { interpreter.interpreter_ti_enumerate_thread((jvmtiEnv*)ti_env, thread); } else { jitted_ti_enumerate_thread((jvmtiEnv*)ti_env, thread); } }
// exception catch callback to restore stack after Stack Overflow Error void exception_catch_callback() { Registers regs = {0}; VM_thread *thread = p_TLS_vmthread; assert(thread); if (thread->regs) { regs = *(Registers*)thread->regs; } M2nFrame* m2n = (M2nFrame *) STD_ALLOCA(m2n_get_size()); m2n_push_suspended_frame(thread, m2n, ®s); M2nFrame* prev_m2n = m2n_get_previous_frame(m2n); StackIterator* si = (StackIterator*) STD_ALLOCA(si_size()); si_fill_from_registers(si, ®s, false, prev_m2n); // si_create_from_registers uses large stack space, // so guard page restored after its invoke. if (p_TLS_vmthread->restore_guard_page) { int res = port_thread_restore_guard_page(); if (res != 0) { Global_Env *env = VM_Global_State::loader_env; if (si_is_native(si)) { m2n_set_last_frame(prev_m2n); if ((interpreter_enabled() || (!prev_m2n) || (m2n_get_frame_type(prev_m2n) & FRAME_NON_UNWINDABLE))) { exn_raise_by_class(env->java_lang_StackOverflowError_Class); } else { //si_free(si); exn_throw_by_class(env->java_lang_StackOverflowError_Class); } } else { //si_free(si); exn_throw_by_class(env->java_lang_StackOverflowError_Class); } } p_TLS_vmthread->restore_guard_page = false; } si_transfer_control(si); }
IDATA jthread_throw_exception_object(jobject object) { if (interpreter_enabled()) { // FIXME - Function set_current_thread_exception does the same // actions as exn_raise_object, and it should be replaced. hythread_suspend_disable(); set_current_thread_exception(object->object); hythread_suspend_enable(); } else { if (is_unwindable()) { exn_throw_object(object); } else { ASSERT_RAISE_AREA; exn_raise_object(object); } } return 0; }
bool set_unwindable(bool unwindable) { M2nFrame* lastFrame = m2n_get_last_frame(); if (interpreter_enabled() || (!lastFrame)) { assert(!unwindable); return false; } int lastFrameType = m2n_get_frame_type(lastFrame); bool previousValue = !(lastFrameType & FRAME_NON_UNWINDABLE); if (unwindable) { lastFrameType &= ~FRAME_NON_UNWINDABLE; } else { lastFrameType |= FRAME_NON_UNWINDABLE; } m2n_set_frame_type( lastFrame, (frame_type) lastFrameType); return previousValue; }
jvmtiError JNICALL jvmtiGetLocalLong(jvmtiEnv* env, jthread thread, jint depth, jint slot, jlong* value_ptr) { TRACE("GetLocalLong called"); SuspendEnabledChecker sec; /* * Check given env & current phase. */ jvmtiPhase phases[] = {JVMTI_PHASE_LIVE}; CHECK_EVERYTHING(); CHECK_CAPABILITY(can_access_local_variables); // check error condition: JVMTI_ERROR_INVALID_THREAD // check error condition: JVMTI_ERROR_THREAD_NOT_ALIVE // check error condition: JVMTI_ERROR_ILLEGAL_ARGUMENT // check error condition: JVMTI_ERROR_NULL_POINTER jvmtiError err = GetLocal_checkArgs(env, &thread, depth, slot, value_ptr); if (err != JVMTI_ERROR_NONE) return err; bool thread_suspended = false; // Suspend thread before getting stacks vm_thread_t vm_thread; if (NULL != thread) { // Check that this thread is not current vm_thread = jthread_get_vm_thread_ptr_safe(thread); if (vm_thread != p_TLS_vmthread) { IDATA UNREF status = hythread_suspend_other((hythread_t)vm_thread); assert(TM_ERROR_NONE == status); thread_suspended = true; } } else vm_thread = p_TLS_vmthread; if (interpreter_enabled()) // check error condition: JVMTI_ERROR_INVALID_SLOT // check error condition: JVMTI_ERROR_OPAQUE_FRAME // check error condition: JVMTI_ERROR_NO_MORE_FRAMES // TODO: check error condition: JVMTI_ERROR_TYPE_MISMATCH err = interpreter.interpreter_ti_getLocal64(env, vm_thread, depth, slot, value_ptr); else { GET_JIT_FRAME_CONTEXT; tmn_suspend_disable(); OpenExeJpdaError result = jit->get_local_var(method, jfc, slot, VM_DATA_TYPE_INT64, value_ptr); si_free(si); tmn_suspend_enable(); err = jvmti_translate_jit_error(result); } if (thread_suspended) hythread_resume((hythread_t)vm_thread); return err; }
/** * General function to set value of local variable. * @param var_type type of the local variable * @param p_value pointer to the new variable value */ static jvmtiError set_local(jvmtiEnv* env, jthread thread, jint depth, jint slot, VM_Data_Type var_type, void* p_value) { SuspendEnabledChecker sec; /* * Check given env & current phase. */ jvmtiPhase phases[] = {JVMTI_PHASE_LIVE}; CHECK_EVERYTHING(); CHECK_CAPABILITY(can_access_local_variables); // check error condition: JVMTI_ERROR_INVALID_THREAD // check error condition: JVMTI_ERROR_THREAD_NOT_ALIVE // check error condition: JVMTI_ERROR_ILLEGAL_ARGUMENT jvmtiError err = GetLocal_checkArgs(env, &thread, depth, slot, p_value); if (err != JVMTI_ERROR_NONE) return err; // check error condition: JVMTI_ERROR_INVALID_OBJECT if (VM_DATA_TYPE_CLASS == var_type && ! is_valid_object(env, *(jobject*) p_value)) return JVMTI_ERROR_INVALID_OBJECT; bool thread_suspended = false; // Suspend thread before getting stacks vm_thread_t vm_thread; if (NULL != thread) { // Check that this thread is not current vm_thread = jthread_get_vm_thread_ptr_safe(thread); if (vm_thread != p_TLS_vmthread) { IDATA UNREF status = hythread_suspend_other((hythread_t)vm_thread); assert(TM_ERROR_NONE == status); thread_suspended = true; } } else vm_thread = p_TLS_vmthread; if (interpreter_enabled()) { // TODO: check error condition: JVMTI_ERROR_INVALID_SLOT // TODO: check error condition: JVMTI_ERROR_TYPE_MISMATCH // TODO: check error condition: JVMTI_ERROR_OPAQUE_FRAME // TODO: check error condition: JVMTI_ERROR_NO_MORE_FRAMES switch (var_type) { case VM_DATA_TYPE_CLASS: err = interpreter.interpreter_ti_setObject(env, vm_thread, depth, slot, *(jobject*) p_value); break; case VM_DATA_TYPE_INT32: case VM_DATA_TYPE_F4: err = interpreter.interpreter_ti_setLocal32(env, vm_thread, depth, slot, *(int*) p_value); break; case VM_DATA_TYPE_INT64: case VM_DATA_TYPE_F8: err = interpreter.interpreter_ti_setLocal64(env, vm_thread, depth, slot, *(int64*) p_value); break; default: DIE(("Error: unrecognized local variable type")); } } else { GET_JIT_FRAME_CONTEXT; tmn_suspend_disable(); OpenExeJpdaError result; switch (var_type) { case VM_DATA_TYPE_CLASS: if (NULL != *(jobject*) p_value) result = jit->set_local_var(method, jfc, slot, VM_DATA_TYPE_CLASS, &(*(ObjectHandle*) p_value)->object); else { ManagedObject *n = (ManagedObject *)VM_Global_State::loader_env->managed_null; result = jit->set_local_var(method, jfc, slot, VM_DATA_TYPE_CLASS, &n); } break; case VM_DATA_TYPE_INT32: case VM_DATA_TYPE_F4: case VM_DATA_TYPE_INT64: case VM_DATA_TYPE_F8: result = jit->set_local_var(method, jfc, slot, var_type, p_value); break; default: DIE(("Error: unrecognized local variable type")); } si_free(si); tmn_suspend_enable(); err = jvmti_translate_jit_error(result); } if (thread_suspended) hythread_resume((hythread_t)vm_thread); return err; }
bool is_unwindable() { M2nFrame* lastFrame = m2n_get_last_frame(); return !(interpreter_enabled() || (!lastFrame) || (m2n_get_frame_type(lastFrame) & FRAME_NON_UNWINDABLE)); }