// 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); }
void m2n_push_suspended_frame(VM_thread* thread, M2nFrame* m2nf, Registers* regs) { assert(m2nf); m2nf->p_lm2nf = (M2nFrame**)1; m2nf->method = NULL; m2nf->local_object_handles = NULL; m2nf->current_frame_type = FRAME_UNKNOWN; m2nf->rip = (POINTER_SIZE_INT)regs->get_ip(); m2nf->regs = regs; m2nf->prev_m2nf = m2n_get_last_frame(thread); m2n_set_last_frame(thread, m2nf); }
// 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); }
// function can be safe point & should be called with disable reqursion = 1 void exn_athrow_regs(Registers * regs, Class_Handle exn_class, bool java_code, bool transfer_control) { assert(!hythread_is_suspend_enabled()); assert(exn_class); #ifndef _IPF_ M2nFrame *cur_m2nf = (M2nFrame *) STD_ALLOCA(m2n_get_size()); M2nFrame *unw_m2nf; ManagedObject *exn_obj = NULL; StackIterator *si; DebugUtilsTI* ti = VM_Global_State::loader_env->TI; VM_thread* vmthread = p_TLS_vmthread; if (java_code) m2n_push_suspended_frame(vmthread, cur_m2nf, regs); else // Gregory - // Initialize cur_m2nf pointer in case we've crashed in native code that is unwindable, // e.g. in the code that sets non-unwindable state for the native code area cur_m2nf = m2n_get_last_frame(); BEGIN_RAISE_AREA; si = (StackIterator*) STD_ALLOCA(si_size()); si_fill_from_native(si); ManagedObject *local_exn_obj = NULL; exn_obj = exn_propagate_exception(si, &local_exn_obj, exn_class, NULL, NULL, NULL); //free local handles ObjectHandles* last_m2n_frame_handles = m2n_get_local_handles(cur_m2nf); if (last_m2n_frame_handles) { free_local_object_handles2(last_m2n_frame_handles); } if (ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_EXCEPTION_EVENT)) { VM_thread *thread = p_TLS_vmthread; NativeCodePtr callback = (NativeCodePtr) jvmti_exception_catch_callback; si_copy_to_registers(si, regs); vm_set_exception_registers(thread, *regs); si_set_callback(si, &callback); } else if (p_TLS_vmthread->restore_guard_page) { VM_thread *thread = p_TLS_vmthread; NativeCodePtr callback = (NativeCodePtr) exception_catch_callback; si_copy_to_registers(si, regs); vm_set_exception_registers(thread, *regs); si_set_callback(si, &callback); } si_copy_to_registers(si, regs); if (transfer_control) { // Let NCAI to continue single stepping in exception handler ncai_setup_signal_step(&vmthread->jvmti_thread, (NativeCodePtr)regs->get_ip()); set_exception_object_internal(exn_obj); si_transfer_control(si); assert(!"si_transfer_control should not return"); } unw_m2nf = si_get_m2n(si); //si_free(si); END_RAISE_AREA; set_exception_object_internal(exn_obj); m2n_set_last_frame(unw_m2nf); #endif } //exn_athrow_regs
/** * Attaches thread current thread to VM. */ jint vm_attach(JavaVM * java_vm, JNIEnv ** p_jni_env) { // It seems to be reasonable to have suspend enabled state here. // It is unsafe to perform operations which require suspend disabled // mode until current thread is not attaced to VM. assert(hythread_is_suspend_enabled()); vm_thread_t vm_thread = jthread_self_vm_thread_unsafe(); assert(vm_thread); // if the assertion is false we cannot notify the parent thread // that we started and it would hang in waitloop assert(vm_thread); jint status = jthread_allocate_vm_thread_pool(java_vm, vm_thread); if (status != JNI_OK) { return status; } // Create top level M2N frame. M2nFrame *p_m2n = (M2nFrame *) apr_palloc(vm_thread->pool, sizeof(M2nFrame)); if (!p_m2n) { return JNI_ENOMEM; } // Create local handles. ObjectHandles *p_handles = (ObjectHandles *) apr_palloc(vm_thread->pool, sizeof(ObjectHandlesNew)); if (!p_handles) { return JNI_ENOMEM; } vm_thread->jni_env = (JNIEnv *) apr_palloc(vm_thread->pool, sizeof(JNIEnv_Internal)); if (!vm_thread->jni_env) { return JNI_ENOMEM; } // Initialize JNI environment. JNIEnv_Internal *jni_env = (JNIEnv_Internal *) vm_thread->jni_env; jni_env->functions = &jni_vtable; jni_env->vm = (JavaVM_Internal *) java_vm; jni_env->reserved0 = (void *) 0x1234abcd; *p_jni_env = jni_env; m2n_null_init(p_m2n); m2n_set_last_frame(p_m2n); oh_null_init_handles(p_handles); m2n_set_local_handles(p_m2n, p_handles); m2n_set_frame_type(p_m2n, FRAME_NON_UNWINDABLE); gc_thread_init(&vm_thread->_gc_private_information); if (ti_is_enabled()) { vm_thread->jvmti_thread.owned_monitors_size = TM_INITIAL_OWNED_MONITOR_SIZE; vm_thread->jvmti_thread.owned_monitors = (jobject*)apr_palloc(vm_thread->pool, TM_INITIAL_OWNED_MONITOR_SIZE * sizeof(jobject)); void *addr = NULL; apr_status_t UNREF status = port_vmem_allocate(&addr, TM_JVMTI_MAX_BUFFER_SIZE, PORT_VMEM_MODE_READ | PORT_VMEM_MODE_WRITE | PORT_VMEM_MODE_EXECUTE); assert(status == APR_SUCCESS); vm_thread->jvmti_thread.jvmti_jit_breakpoints_handling_buffer = reinterpret_cast<jbyte *>(addr); assert(VM_Global_State::loader_env->TI); VM_Global_State::loader_env->TI->reportLocally(); } ((hythread_t)vm_thread)->java_status = TM_STATUS_INITIALIZED; assert(hythread_is_suspend_enabled()); return JNI_OK; }