// 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); }
// Interpter of VM Value Simulator::interpreter(AbstractComponent *_component, Thread *_thread, Value *__args, ArgNo __n) { // Create simulation context Simulator sim; sim.m_thread = _thread; sim.m_component = _component; sim.m_domain = _thread->get_current_domain(); sim.m_function = _thread->get_this_function(); sim.m_program = sim.m_function->get_program(); sim.m_argn = __n; sim.m_args = __args; sim.m_localn = sim.m_function->get_max_local_no(); sim.m_locals = (Value *)STD_ALLOCA(sizeof(Value) * sim.m_localn); sim.m_constantn = sim.m_program->get_constants_count(); sim.m_constants = sim.m_program->get_constant(0); sim.m_object_varn = sim.m_component->m_program->get_object_vars_count(); sim.m_object_vars = sim.m_component->m_object_vars; memset(sim.m_locals, 0, sizeof(Value) * sim.m_localn); // Set byte codes sim.m_byte_codes = sim.m_function->get_byte_codes_addr(); // Start simulation return sim.run(); }
bool field_can_link(Class* clss, Field* field, bool _static, bool putfield, bool _throw) { ASSERT_RAISE_AREA; if(_static?(!field->is_static()):(field->is_static())) { if(_throw) { exn_raise_by_name("java/lang/IncompatibleClassChangeError", field->get_class()->get_name()->bytes); } return false; } if(putfield && field->is_final()) { for(int fn = 0; fn < clss->get_number_of_fields(); fn++) { if(clss->get_field(fn) == field) { return true; } } if(_throw) { unsigned buf_size = clss->get_name()->len + field->get_class()->get_name()->len + field->get_name()->len + 15; char* buf = (char*)STD_ALLOCA(buf_size); memset(buf, 0, buf_size); sprintf(buf, " from %s to %s.%s", clss->get_name()->bytes, field->get_class()->get_name()->bytes, field->get_name()->bytes); jthrowable exc_object = exn_create("java/lang/IllegalAccessError", buf); exn_raise_object(exc_object); } return false; } return true; }
// 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); }
static bool method_can_link_special(Class* clss, unsigned index, Method* method, bool _throw) { ASSERT_RAISE_AREA; ConstantPool& cp = clss->get_constant_pool(); unsigned class_idx = cp.get_ref_class_index(index); unsigned class_name_idx = cp.get_class_name_index(class_idx); String* ref_class_name = cp.get_utf8_string(class_name_idx); if(method->get_name() == VM_Global_State::loader_env->Init_String && method->get_class()->get_name() != ref_class_name) { if(_throw) { exn_raise_by_name("java/lang/NoSuchMethodError", method->get_name()->bytes); } return false; } if(method->is_static()) { if(_throw) { exn_raise_by_name("java/lang/IncompatibleClassChangeError", method->get_class()->get_name()->bytes); } return false; } if(method->is_abstract()) { if(_throw) { tmn_suspend_enable(); unsigned buf_size = clss->get_name()->len + method->get_name()->len + method->get_descriptor()->len + 5; char* buf = (char*)STD_ALLOCA(buf_size); memset(buf, 0, buf_size); sprintf(buf, "%s.%s%s", clss->get_name()->bytes, method->get_name()->bytes, method->get_descriptor()->bytes); jthrowable exc_object = exn_create("java/lang/AbstractMethodError", buf); exn_raise_object(exc_object); tmn_suspend_disable(); } return false; } return true; }
static IDATA rt_jthread_monitor_enter(ManagedObject* monitor) { const unsigned handles_size = (unsigned)(sizeof(ObjectHandlesNew)+sizeof(ManagedObject*)*4); ObjectHandlesNew* handels = (ObjectHandlesNew *)STD_ALLOCA(handles_size); handels->capacity = 4; handels->size = 0; handels->next = NULL; m2n_set_local_handles(m2n_get_last_frame(), (ObjectHandles *) handels); ObjectHandle monitorJavaObj = oh_allocate_local_handle(); monitorJavaObj->object = monitor; IDATA result = jthread_monitor_enter(monitorJavaObj); free_local_object_handles2(m2n_get_local_handles(m2n_get_last_frame())); m2n_set_local_handles(m2n_get_last_frame(), NULL); return result; }
void Simulator::xCHKPARAM() { // Check the count & type of all arguments // Pad default if necessary if (m_argn < m_function->get_min_arg_no()) throw_error("Two few arguments to %s, expected %d, got %d.\n", m_function->get_name()->c_str(), m_function->get_min_arg_no(), m_argn); if (m_argn > m_function->get_min_arg_no() && !m_function->get_attrib() & Function::RANDOM_ARG) throw_error("Two many arguments to %s, expected %d, got %d.\n", m_function->get_name()->c_str(), m_function->get_max_arg_no(), m_argn); // Check types auto& parameters = (Parameters&)m_function->get_parameters(); Value *p = m_args; for (auto& it : parameters) { if (it->get_type() != p->m_type && (!it->is_nullable() || p->m_type != NIL)) // Type is not matched throw_error("Bad type of arguments %s, expected %s, got %s.\n", it->get_name()->c_str(), it->get_type(), p->m_type); } // Append the default parameters if necessary if (m_argn < m_function->get_min_arg_no()) { auto *new_args = (Value *)STD_ALLOCA(sizeof(Value) * m_function->get_max_arg_no()); memcpy(new_args, m_args, sizeof(Value) * m_argn); while (m_argn < m_function->get_min_arg_no()) { new_args[m_argn] = parameters[m_argn]->get_default(); m_argn++; } } }
static PORT_CDECL int thread_start_func(void* arg) { int err, result; port_tls_data_t* tlsdata = NULL; thread_start_struct_t* ptr = (thread_start_struct_t*)arg; port_threadfunc_t fun = ptr->fun; size_t stack_size = ptr->stack_size; arg = ptr->arg; STD_FREE(ptr); if (port_shared_data) { tlsdata = (port_tls_data_t*)STD_ALLOCA(sizeof(port_tls_data_t)); err = port_thread_attach_local(tlsdata, FALSE, FALSE, stack_size); assert(err == 0); } result = fun(arg); if (tlsdata) port_thread_detach(); return result; }
static bool method_can_link_virtual(Class* clss, unsigned cp_index, Method* method, bool _throw) { ASSERT_RAISE_AREA; if(method->is_static()) { if(_throw) { exn_raise_by_name("java/lang/IncompatibleClassChangeError", method->get_class()->get_name()->bytes); } return false; } if(method->get_class()->is_interface()) { if(_throw) { char* buf = (char*)STD_ALLOCA(clss->get_name()->len + method->get_name()->len + method->get_descriptor()->len + 2); sprintf(buf, "%s.%s%s", clss->get_name()->bytes, method->get_name()->bytes, method->get_descriptor()->bytes); jthrowable exc_object = exn_create("java/lang/AbstractMethodError", buf); exn_raise_object(exc_object); } return false; } return true; }
void JIT_execute_method_default(JIT_Handle jit, jmethodID methodID, jvalue *return_value, jvalue *args) { // Detecting errors with object headears on stack when using destructive // unwinding. void *lastFrame = p_TLS_vmthread->lastFrame; p_TLS_vmthread->lastFrame = (void*)&lastFrame; //printf("execute: push: prev = 0x%p, curr=0x%p\n", lastFrame, &lastFrame); // fprintf(stderr, "Not implemented\n"); Method *method = (Method*) methodID; TRACE("enter method " << method->get_class()->get_name()->bytes << " " << method->get_name()->bytes << " " << method->get_descriptor()->bytes); int sz = method->get_num_arg_slots(); void *meth_addr = method->get_code_addr(); U_32 *arg_words = (U_32*) STD_ALLOCA(sz * sizeof(U_32)); int argId = sz; int pos = 0; assert(!hythread_is_suspend_enabled()); if (!method->is_static()) { ObjectHandle handle = (ObjectHandle) args[pos++].l; assert(handle); arg_words[--argId] = (unsigned) handle->object; } const char *mtype = method->get_descriptor()->bytes + 1; assert(mtype != 0); for(; *mtype != ')'; mtype++) { switch(*mtype) { case JAVA_TYPE_CLASS: case JAVA_TYPE_ARRAY: { ObjectHandle handle = (ObjectHandle) args[pos++].l; arg_words[--argId] = (unsigned) (handle ? handle->object : 0); while(*mtype == '[') mtype++; if (*mtype == 'L') while(*mtype != ';') mtype++; } break; case JAVA_TYPE_SHORT: // sign extend arg_words[--argId] = (U_32)(I_32) args[pos++].s; break; case JAVA_TYPE_BYTE: // sign extend arg_words[--argId] = (U_32)(I_32) args[pos++].b; break; case JAVA_TYPE_INT: // sign extend arg_words[--argId] = (U_32)(I_32) args[pos++].i; break; case JAVA_TYPE_FLOAT: arg_words[--argId] = (I_32) args[pos++].i; break; case JAVA_TYPE_BOOLEAN: arg_words[--argId] = (I_32) args[pos++].z; break; case JAVA_TYPE_CHAR: // zero extend arg_words[--argId] = (I_32) args[pos++].c; break; case JAVA_TYPE_LONG: case JAVA_TYPE_DOUBLE: *(jlong*)&arg_words[argId-2] = args[pos++].j; argId -= 2; break; default: LDIE(53, "Unexpected java type"); } } assert(argId >= 0); jvalue *resultPtr = (jvalue*) return_value; Java_Type ret_type = method->get_return_java_type(); arg_words += argId; argId = sz - argId; static const IntFuncPtr invoke_managed_func = gen_invoke_int_managed_func(); static const FloatFuncPtr invoke_float_managed_func = gen_invoke_float_managed_func(); static const DoubleFuncPtr invoke_double_managed_func = gen_invoke_double_managed_func(); switch(ret_type) { case JAVA_TYPE_VOID: invoke_managed_func(arg_words, argId, meth_addr); break; case JAVA_TYPE_CLASS: case JAVA_TYPE_ARRAY: case JAVA_TYPE_STRING: { ManagedObject *ref = ((RefFuncPtr)invoke_managed_func)(arg_words, argId, meth_addr); ObjectHandle h = oh_allocate_local_handle(); if (ref != NULL) { h->object = ref; resultPtr->l = h; } else { resultPtr->l = NULL; } } break; case JAVA_TYPE_BOOLEAN: case JAVA_TYPE_BYTE: case JAVA_TYPE_CHAR: case JAVA_TYPE_SHORT: case JAVA_TYPE_INT: resultPtr->i = invoke_managed_func(arg_words, argId, meth_addr); break; case JAVA_TYPE_FLOAT: resultPtr->f = invoke_float_managed_func(arg_words, argId, meth_addr); break; case JAVA_TYPE_LONG: resultPtr->j = ((LongFuncPtr)invoke_managed_func)(arg_words, argId, meth_addr); break; case JAVA_TYPE_DOUBLE: resultPtr->d = invoke_double_managed_func(arg_words, argId, meth_addr); break; default: LDIE(53, "Unexpected java type"); } if (exn_raised()) { TRACE("Exception occured: " << exn_get_name()); if ((resultPtr != NULL) && (ret_type != JAVA_TYPE_VOID)) { resultPtr->l = 0; //clear result } } TRACE("exit method " << method->get_class()->get_name()->bytes << " " << method->get_name()->bytes << " " << method->get_descriptor()->bytes); // Detecting errors with object headears on stack when using destructive // unwinding. //printf("execute: pop: prev = 0x%p, curr=0x%p\n", &lastFrame, lastFrame); p_TLS_vmthread->lastFrame = lastFrame; }
// 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
// function can be safe point & should be called with disable reqursion = 1 void exn_throw_for_JIT(ManagedObject* exn_obj, Class_Handle exn_class, Method_Handle exn_constr, U_8* jit_exn_constr_args, jvalue* vm_exn_constr_args) { /* * !!!! NO LOGGER IS ALLOWED IN THIS FUNCTION !!! * !!!! RELEASE BUILD WILL BE BROKEN !!! * !!!! NO TRACE2, INFO, WARN, ECHO, ASSERT, ... */ assert(!hythread_is_suspend_enabled()); if(exn_raised()) { return; } ASSERT_NO_INTERPRETER ASSERT_RAISE_AREA; if ((exn_obj == NULL) && (exn_class == NULL)) { exn_class = VM_Global_State::loader_env->java_lang_NullPointerException_Class; } ManagedObject* local_exn_obj = exn_obj; StackIterator* si = (StackIterator*) STD_ALLOCA(si_size()); si_fill_from_native(si); if (exn_raised()) { return; } #ifndef _IPF_ assert(is_gc_frame_before_m2n_frame()); #endif // _IPF_ assert(!exn_raised()); if (si_is_past_end(si)) { //FIXME LAZY EXCEPTION (2006.05.12) // should be replaced by lazy version set_exception_object_internal(local_exn_obj); return; } si_transfer_all_preserved_registers(si); assert(!exn_raised()); DebugUtilsTI* ti = VM_Global_State::loader_env->TI; exn_obj = exn_propagate_exception(si, &local_exn_obj, exn_class, exn_constr, jit_exn_constr_args, vm_exn_constr_args); if (exn_raised()) { //si_free(si); return; } M2nFrame* m2nFrame = m2n_get_last_frame(); ObjectHandles* last_m2n_frame_handles = m2n_get_local_handles(m2nFrame); if (last_m2n_frame_handles) { free_local_object_handles2(last_m2n_frame_handles); } set_exception_object_internal(exn_obj); if (ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_EXCEPTION_EVENT)) { Registers regs = {0}; VM_thread *thread = p_TLS_vmthread; NativeCodePtr callback = (NativeCodePtr) jvmti_exception_catch_callback; si_copy_to_registers(si, ®s); vm_set_exception_registers(thread, regs); si_set_callback(si, &callback); } else if (p_TLS_vmthread->restore_guard_page) { Registers regs = {0}; VM_thread *thread = p_TLS_vmthread; NativeCodePtr callback = (NativeCodePtr) exception_catch_callback; si_copy_to_registers(si, ®s); vm_set_exception_registers(thread, regs); si_set_callback(si, &callback); } // don't put any call here si_transfer_control(si); } //exn_throw_for_JIT
// function can be safe point & should be called with disable recursion = 1 static ManagedObject * exn_propagate_exception( StackIterator * si, ManagedObject ** exn_obj, Class_Handle exn_class, Method_Handle exn_constr, U_8 * jit_exn_constr_args, jvalue* vm_exn_constr_args) { assert(!hythread_is_suspend_enabled()); ASSERT_RAISE_AREA; ASSERT_NO_INTERPRETER; assert(*exn_obj || exn_class); // Save the throw context StackIterator *throw_si = (StackIterator*) STD_ALLOCA(si_size()); memcpy(throw_si, si, si_size()); // Skip first frame if it is an M2nFrame (which is always a transition from managed to the throw code). // The M2nFrame will be removed from the thread's M2nFrame list but transfer control or copy to registers. if (si_is_native(si)) { si_goto_previous(si); } Method *interrupted_method; NativeCodePtr interrupted_method_location; JIT *interrupted_method_jit; bool restore_guard_page = p_TLS_vmthread->restore_guard_page; if (!si_is_native(si)) { CodeChunkInfo *interrupted_cci = si_get_code_chunk_info(si); assert(interrupted_cci); interrupted_method = interrupted_cci->get_method(); interrupted_method_location = si_get_ip(si); interrupted_method_jit = interrupted_cci->get_jit(); } else { interrupted_method = m2n_get_method(si_get_m2n(si)); interrupted_method_location = 0; interrupted_method_jit = 0; } if (NULL != *exn_obj) { // Gregory - When *exn_obj is NULL it means we're called from exn_athrow_regs // which means that IP points exactly to the right location. But // when *exn_obj is not NULL, it means that we're called from exn_throw_for_JIT // where *exn_obj is already constructed and is thrown by code via athrow. // So in this case IP reported by stack iterator is past the athrow bytecode // and should be moved back to be inside of bytecode location for interrupted // method. interrupted_method_location = (NativeCodePtr)((POINTER_SIZE_INT)interrupted_method_location - 1); // Determine the type of the exception for the type tests below. exn_class = (*exn_obj)->vt()->clss; } #ifdef VM_STATS assert(exn_class); exn_class->class_thrown(); UNSAFE_REGION_START VM_Statistics::get_vm_stats().num_exceptions++; UNSAFE_REGION_END #endif // VM_STATS // Remove single step breakpoints which could have been set on the // exception bytecode DebugUtilsTI *ti = VM_Global_State::loader_env->TI; if (ti->isEnabled() && ti->is_single_step_enabled()) { jvmti_thread_t jvmti_thread = jthread_self_jvmti(); ti->vm_brpt->lock(); if (NULL != jvmti_thread->ss_state) { jvmti_remove_single_step_breakpoints(ti, jvmti_thread); } ti->vm_brpt->unlock(); } // When VM is in shutdown stage we need to execute "finally" clause to // release monitors and propagate an exception to the upper frames. Class_Handle search_exn_class = !VM_Global_State::loader_env->IsVmShutdowning() ? exn_class : VM_Global_State::loader_env->JavaLangObject_Class; if (!si_is_native(si)) { bool same_frame = true; while (!si_is_past_end(si) && !si_is_native(si)) { CodeChunkInfo *cci = si_get_code_chunk_info(si); assert(cci); Method *method = cci->get_method(); JIT *jit = cci->get_jit(); assert(method && jit); NativeCodePtr ip = si_get_ip(si); bool is_ip_past = !!si_get_jit_context(si)->is_ip_past; #ifdef VM_STATS cci->num_throws++; #endif // VM_STATS // Examine this frame's exception handlers looking for a match unsigned num_handlers = cci->get_num_target_exception_handlers(); for (unsigned i = 0; i < num_handlers; i++) { Target_Exception_Handler_Ptr handler = cci->get_target_exception_handler_info(i); if (!handler) continue; if (handler->is_in_range(ip, is_ip_past) && handler->is_assignable(search_exn_class)) { // Found a handler that catches the exception. #ifdef VM_STATS cci->num_catches++; if (same_frame) { VM_Statistics::get_vm_stats().num_exceptions_caught_same_frame++; } if (handler->is_exc_obj_dead()) { VM_Statistics::get_vm_stats().num_exceptions_dead_object++; if (!*exn_obj) { VM_Statistics::get_vm_stats().num_exceptions_object_not_created++; } } #endif // VM_STATS if (restore_guard_page) { bool res = check_stack_size_enough_for_exception_catch(si_get_sp(si)); //must always be enough. otherwise program behavior is unspecified: finally blocks, monitor exits are not executed assert(res); if (!res) { break; } } // Setup handler context jit->fix_handler_context(method, si_get_jit_context(si)); si_set_ip(si, handler->get_handler_ip(), false); // Start single step in exception handler if (ti->isEnabled() && ti->is_single_step_enabled()) { jvmti_thread_t jvmti_thread = jthread_self_jvmti(); ti->vm_brpt->lock(); if (NULL != jvmti_thread->ss_state) { uint16 bc; NativeCodePtr ip = handler->get_handler_ip(); OpenExeJpdaError UNREF result = jit->get_bc_location_for_native(method, ip, &bc); assert(EXE_ERROR_NONE == result); jvmti_StepLocation method_start = {(Method *)method, ip, bc, false}; jvmti_set_single_step_breakpoints(ti, jvmti_thread, &method_start, 1); } ti->vm_brpt->unlock(); } // Create exception if necessary if (!*exn_obj && !handler->is_exc_obj_dead()) { assert(!exn_raised()); *exn_obj = create_lazy_exception(exn_class, exn_constr, jit_exn_constr_args, vm_exn_constr_args); } if (jvmti_is_exception_event_requested()) { // Create exception if necessary if (NULL == *exn_obj) { *exn_obj = create_lazy_exception(exn_class, exn_constr, jit_exn_constr_args, vm_exn_constr_args); } // Reload exception object pointer because it could have // moved while calling JVMTI callback *exn_obj = jvmti_jit_exception_event_callback_call(*exn_obj, interrupted_method_jit, interrupted_method, interrupted_method_location, jit, method, handler->get_handler_ip()); } CTRACE(("setting return pointer to %d", exn_obj)); si_set_return_pointer(si, (void **) exn_obj); //si_free(throw_si); return NULL; } } // No appropriate handler found, undo synchronization vm_monitor_exit_synchronized_method(si); jvalue ret_val = {(jlong)0}; jvmti_process_method_exception_exit_event( reinterpret_cast<jmethodID>(method), JNI_TRUE, ret_val, si); // Goto previous frame si_goto_previous(si); same_frame = false; } } // Exception propagates to the native code assert(si_is_native(si)); // The current thread exception is set to the exception and we return 0/NULL to the native code if (*exn_obj == NULL) { *exn_obj = create_lazy_exception(exn_class, exn_constr, jit_exn_constr_args, vm_exn_constr_args); } assert(!hythread_is_suspend_enabled()); CodeChunkInfo *catch_cci = si_get_code_chunk_info(si); Method *catch_method = NULL; if (catch_cci) catch_method = catch_cci->get_method(); // Reload exception object pointer because it could have // moved while calling JVMTI callback if (exn_raised()) { //si_free(throw_si); return NULL; } *exn_obj = jvmti_jit_exception_event_callback_call(*exn_obj, interrupted_method_jit, interrupted_method, interrupted_method_location, NULL, NULL, NULL); //si_free(throw_si); return *exn_obj; } //exn_propagate_exception
/** * Dumps graph node in file in DOT format. */ void vf_Graph::DumpDotGraph() { #if _VF_DEBUG /** * Graphviz has a hardcoded label length limit. Windows has a file * name length limit as well. */ const int MAX_LABEL_LENGTH = 80; // get class and method name const char *class_name = class_get_name(m_ctx->m_class); // create file name size_t len = strlen(class_name) + strlen(m_ctx->m_name) + strlen(m_ctx->m_descriptor) + 6; char *fname = (char *) STD_ALLOCA(len); sprintf(fname, "%s_%s%s", class_name, m_ctx->m_name, m_ctx->m_descriptor); char *f_start; char *pointer; if (len > MAX_LABEL_LENGTH) { f_start = fname + len - MAX_LABEL_LENGTH; // shift to the start of the nearest lexem for (pointer = f_start;; pointer++) { if (isalnum(*pointer)) { continue; } else if (!*pointer) { // end of the string break; } else { // record the first matching position f_start = pointer; break; } } } else { f_start = fname; } for (pointer = f_start;; pointer++) { if (isalnum(*pointer)) { continue; } else if (!*pointer) { // end of the string break; } else { *pointer = '_'; } } // pointer currently points to the end of the string sprintf(pointer, ".dot"); // create .dot file ofstream fout(f_start); if (fout.fail()) { VF_DEBUG("vf_Graph::DumpDotGraph: error opening file: " << f_start); return; } // create name of graph sprintf(fname, "%s.%s%s", class_name, m_ctx->m_name, m_ctx->m_descriptor); // print graph to file DumpDotHeader(f_start, fout); ResetNodeIterator(); while (HasMoreElements()) { DumpDotNode(GetNextNode(), fout); } DumpDotEnd(fout); // close file fout.flush(); fout.close(); #endif // _VF_DEBUG } // vf_Graph::DumpDotGraph