NativeCodePtr compile_me(Method* method) { ASSERT_RAISE_AREA; ASSERT_NO_INTERPRETER; TRACE("compile_me " << method); GcFrame gc; compile_protect_arguments(method, &gc); if (exn_raised()) { return NULL; } tmn_suspend_enable(); if (method->is_abstract()) { compile_raise_exception("java/lang/AbstractMethodError", "", method); tmn_suspend_disable(); return NULL; } DebugUtilsTI *ti = VM_Global_State::loader_env->TI; JIT_Result res = compile_do_compilation(method); if (res != JIT_SUCCESS) { INFO2("compile", "Cannot compile " << method); if (!exn_raised()) { compile_raise_exception("java/lang/InternalError", "Cannot compile ", method); } tmn_suspend_disable(); return NULL; } tmn_suspend_disable(); NativeCodePtr entry_point = method->get_code_addr(); INFO2("compile.code", "Compiled method " << method << ", entry " << entry_point); if (method->get_pending_breakpoints() != 0) jvmti_set_pending_breakpoints(method); if(ti->isEnabled() && ti->is_single_step_enabled() && !method->is_native()) { jvmti_thread_t jvmti_thread = jthread_self_jvmti(); assert(jvmti_thread); jvmti_set_single_step_breakpoints_for_method(ti, jvmti_thread, method); } return entry_point; } // compile_me
void exn_raise_by_class_internal(Class* exc_class, const char* exc_message, jthrowable exc_cause) { #ifdef VM_LAZY_EXCEPTION CTRACE(("%s", "exn_raise_object(), propagating lazy & non-destructively")); tmn_suspend_disable_recursive(); p_TLS_vmthread->thread_exception.exc_class = exc_class; p_TLS_vmthread->thread_exception.exc_message = exc_message; if (exc_cause != NULL) { p_TLS_vmthread->thread_exception.exc_cause = exc_cause->object; } else { p_TLS_vmthread->thread_exception.exc_cause = NULL; } tmn_suspend_enable_recursive(); #else assert(hythread_is_suspend_enabled()); jthrowable exc_object = exn_create(exc_class, exc_message, exc_cause); if (exn_raised()){ return; } exn_raise_object_internal(exc_object); #endif }
// // Given a class handle cl construct a class handle of the type // representing array of cl. // Class_Handle class_get_array_of_class(Class_Handle cl) { Global_Env *env = VM_Global_State::loader_env; Class *arr_clss = resolve_class_array_of_class(env, cl); assert(arr_clss || exn_raised()); return arr_clss; } // class_get_array_of_class
static JIT_Result compile_do_compilation(Method* method) { ASSERT_RAISE_AREA; assert(hythread_is_suspend_enabled()); tmn_suspend_disable(); class_initialize(method->get_class()); tmn_suspend_enable(); method->lock(); if (exn_raised()) { method->unlock(); return JIT_FAILURE; } else if (method->get_state() == Method::ST_Compiled) { method->unlock(); return JIT_SUCCESS; } else if (method->get_state()==Method::ST_NotCompiled && exn_raised()) { method->unlock(); return JIT_FAILURE; } else if(!check_available_stack_size(0x8000)) { method->unlock(); return JIT_FAILURE; } if (method->is_native()) { JIT_Result res = compile_prepare_native_method(method); if (res == JIT_SUCCESS) { compile_flush_generated_code(); method->set_state(Method::ST_Compiled); method->do_jit_recompiled_method_callbacks(); method->apply_vtable_patches(); } else { method->set_state(Method::ST_NotCompiled); compile_raise_exception("java/lang/UnsatisfiedLinkError", "Cannot load native ", method); } method->unlock(); return res; } else { // Call an execution manager to compile the method. // An execution manager is safe to call from multiple threads. method->unlock(); return VM_Global_State::loader_env->em_interface->CompileMethod(method); } }
static void m2n_free_local_handles() { assert(!hythread_is_suspend_enabled()); if (exn_raised()) { exn_rethrow(); } M2nFrame * m2n = m2n_get_last_frame(); free_local_object_handles3(m2n->local_object_handles); }
/* * Raw Monitor Wait * * Wait for notification of the raw monitor. * * REQUIRED Functionality. */ jvmtiError JNICALL jvmtiRawMonitorWait(jvmtiEnv* env, jrawMonitorID monitor, jlong millis) { jvmtiError res = (jvmtiError)jthread_raw_monitor_wait(monitor, millis); if (exn_raised() && res == JVMTI_ERROR_INTERRUPT) return JVMTI_ERROR_NONE; return res; } // jvmtiRawMonitorWait
jthrowable exn_create(const char *exc_name, const char *exc_message, jthrowable cause) { ASSERT_RAISE_AREA; assert(hythread_is_suspend_enabled()); Class *exc_class = get_exc_class(exc_name); if (exc_class == NULL) { assert(exn_raised()); return NULL; } return exn_create(exc_class, exc_message, cause); } // exn_create
void exn_raise_by_name_internal(const char* exc_name, const char* exc_message, jthrowable exc_cause) { assert(hythread_is_suspend_enabled()); Class *exc_class = get_exc_class(exc_name); if (exc_class == NULL) { assert(exn_raised()); return; } exn_raise_by_class_internal(exc_class, exc_message, exc_cause); }
Class_Handle class_find_class_from_loader(Class_Loader_Handle loader, const char* n, Boolean init) { ASSERT_RAISE_AREA; assert(hythread_is_suspend_enabled()); // -salikh char *new_name = strdup(n); char *p = new_name; while (*p) { if (*p == '.') *p = '/'; p++; } String* name = VM_Global_State::loader_env->string_pool.lookup(new_name); STD_FREE(new_name); Class* ch; if (loader) { ch = class_load_verify_prepare_by_loader_jni( VM_Global_State::loader_env, name, loader); } else { assert(hythread_is_suspend_enabled()); ch = class_load_verify_prepare_from_jni(VM_Global_State::loader_env, name); } if (!ch) return NULL; // All initialization from jni should not propagate exceptions and // should return to calling native method. if(init) { class_initialize_from_jni(ch); if (exn_raised()) { return NULL; } } if(exn_raised()) { return 0; } return ch; }
Method *interp_resolve_special_method(Class *clazz, int methodId) { assert(!hythread_is_suspend_enabled()); Compilation_Handle handle; handle.env = VM_Global_State::loader_env; handle.jit = 0; hythread_suspend_enable(); Method *method = resolve_special_method( (Compile_Handle*)&handle, clazz, methodId); hythread_suspend_disable(); if (!method) { if (!exn_raised()) class_throw_linking_error_for_interpreter(clazz, methodId, OPCODE_INVOKESPECIAL); } return method; }
Class* interp_resolve_class_new(Class *clazz, int classId) { assert(!hythread_is_suspend_enabled()); Compilation_Handle handle; handle.env = VM_Global_State::loader_env; handle.jit = 0; hythread_suspend_enable(); Class *objClass = resolve_class_new((Compile_Handle*)&handle, clazz, classId); hythread_suspend_disable(); if (!objClass) { if (!exn_raised()) class_throw_linking_error_for_interpreter(clazz, classId, OPCODE_NEW); } return objClass; }
Field* interp_resolve_static_field(Class *clazz, int fieldId, bool putfield) { assert(!hythread_is_suspend_enabled()); Compilation_Handle handle; handle.env = VM_Global_State::loader_env; handle.jit = 0; hythread_suspend_enable(); Field *field = resolve_static_field((Compile_Handle*)&handle, clazz, fieldId, putfield); hythread_suspend_disable(); if (!field) { if (!exn_raised()) class_throw_linking_error_for_interpreter(clazz, fieldId, putfield?OPCODE_PUTSTATIC:OPCODE_GETSTATIC); } return field; }
/** * Runs java.lang.Thread.detach() method. */ static jint run_java_detach(jthread java_thread) { assert(hythread_is_suspend_enabled()); JNIEnv *jni_env = jthread_get_JNI_env(java_thread); Global_Env *vm_env = jni_get_vm_env(jni_env); Class *thread_class = vm_env->java_lang_Thread_Class; static Method *detach = NULL; if (detach == NULL) { const char *method_name = "detach"; const char *descriptor = "(Ljava/lang/Throwable;)V"; detach = class_lookup_method(thread_class, method_name, descriptor); if (detach == NULL) { TRACE("Failed to find thread's detach method " << descriptor << " , exception = " << exn_get()); return TM_ERROR_INTERNAL; } } // Initialize arguments. jvalue args[2]; args[0].l = java_thread; if (vm_env->IsVmShutdowning()) { args[1].l = NULL; } else { args[1].l = exn_get(); } exn_clear(); hythread_suspend_disable(); vm_execute_java_method_array((jmethodID) detach, 0, args); hythread_suspend_enable(); if (exn_raised()) { TRACE ("java.lang.Thread.detach(Throwable) method completed with an exception: " << exn_get_name()); return TM_ERROR_INTERNAL; } return TM_ERROR_NONE; }
/* * Class: java_lang_VMClassRegistry * Method: getEnclosingClass * Signature: (Ljava/lang/Class;)Ljava/lang/Class; */ JNIEXPORT jclass JNICALL Java_java_lang_VMClassRegistry_getEnclosingClass (JNIEnv *, jclass, jclass jclazz) { assert(jclazz); Class* clazz = jclass_to_struct_Class(jclazz); unsigned idx = clazz->get_enclosing_class_index(); if (!idx) { idx = clazz->get_declaring_class_index(); } if (idx) { Class* outer_clss = clazz->_resolve_class(VM_Global_State::loader_env, idx); if (outer_clss) { return struct_Class_to_jclass(outer_clss); } if (!exn_raised()) { exn_raise_object(clazz->get_constant_pool().get_error_cause(idx)); } } return NULL; }
void exn_throw_by_name_internal(const char* exc_name, const char* exc_message, jthrowable exc_cause) { BEGIN_RAISE_AREA; // functions can be invoked in suspend disabled and enabled state if (!hythread_is_suspend_enabled()) { // exception is throwing, so suspend can be enabled safely tmn_suspend_enable(); } assert(hythread_is_suspend_enabled()); Class *exc_class = get_exc_class(exc_name); if (exc_class == NULL) { assert(exn_raised()); exn_rethrow(); return; // unreachable code } exn_throw_by_class_internal(exc_class, exc_message, exc_cause); END_RAISE_AREA; }
/* * Class: java_lang_VMClassRegistry * Method: getEnclosingMember * Signature: (Ljava/lang/Class;)Ljava/lang/reflect/Member; */ JNIEXPORT jobject JNICALL Java_java_lang_VMClassRegistry_getEnclosingMember (JNIEnv *jenv, jclass, jclass jclazz) { assert(jclazz); Class* clazz = jclass_to_struct_Class(jclazz); unsigned method_idx = clazz->get_enclosing_method_index(); if (method_idx) { unsigned c_idx = clazz->get_enclosing_class_index(); ASSERT(c_idx, ("No class for enclosing method")); Class* outer_clss = clazz->_resolve_class(VM_Global_State::loader_env, c_idx); if (outer_clss) { String* name = clazz->get_constant_pool().get_name_and_type_name(method_idx); String* desc = clazz->get_constant_pool().get_name_and_type_descriptor(method_idx); TRACE("Looking for enclosing method: class="<<outer_clss->get_name()->bytes <<"; name="<<name->bytes<<"; desc="<<desc->bytes); Method* enclosing = outer_clss->lookup_method(name, desc); if (enclosing) { if (enclosing->is_init()) { return reflection_reflect_constructor(jenv, enclosing); } else if (!enclosing->is_clinit()) { return reflection_reflect_method(jenv, enclosing); } } else { //FIXME: check RI compatibility, provide detailed message ThrowNew_Quick(jenv, "java/lang/NoSuchMethodException", "Invalid enclosing method declared"); } } else if (!exn_raised()) { exn_raise_object(clazz->get_constant_pool().get_error_cause(c_idx)); } } return NULL; }
jthrowable create_exception(Class* exc_class, Method* exc_init, jvalue* args) { ASSERT_RAISE_AREA; assert(hythread_is_suspend_enabled()); bool suspended_enabled = hythread_is_suspend_enabled(); if (suspended_enabled) { tmn_suspend_disable(); } ManagedObject *man_obj = class_alloc_new_object(exc_class); if (!man_obj) { exn_raise_object(VM_Global_State::loader_env->java_lang_OutOfMemoryError); if (suspended_enabled) { tmn_suspend_enable(); } return NULL; } jthrowable exc_object = oh_allocate_local_handle(); exc_object->object = man_obj; args[0].l = exc_object; if (exn_raised()) { //if RuntimeException or Error if (suspended_enabled) { tmn_suspend_enable(); } return NULL; } vm_execute_java_method_array((jmethodID) exc_init, 0, args); if (suspended_enabled) { tmn_suspend_enable(); } return exc_object; }
Class *get_exc_class(const char *exception_name) { ASSERT_RAISE_AREA; assert(hythread_is_suspend_enabled()); Global_Env *env = VM_Global_State::loader_env; String *exc_str = env->string_pool.lookup(exception_name); Class *exc_class = env->bootstrap_class_loader->LoadVerifyAndPrepareClass(env, exc_str); if (exc_class == NULL) { return NULL; } tmn_suspend_disable(); class_initialize(exc_class); tmn_suspend_enable(); if (exn_raised()) { return NULL; } return exc_class; }
JNIEXPORT jclass JNICALL Java_java_lang_VMClassRegistry_loadBootstrapClass (JNIEnv *jenv, jclass, jstring name) { // obtain char* for the name const char* buf = GetStringUTFChars(jenv, name, NULL); // set flag to detect if the requested class is not on the bootclasspath p_TLS_vmthread->class_not_found = true; Class_Handle clss = class_find_class_from_loader(NULL, buf, FALSE); ReleaseStringUTFChars(jenv, name, buf); if (clss) { // filter out primitive types for compatibility return clss->is_primitive() ? NULL : jni_class_from_handle(jenv, clss); } else { assert(exn_raised()); if(p_TLS_vmthread->class_not_found) { // the requested class is not on the bootclasspath // delegation model requires letting child loader(s) to continue // with searching on their paths, so reset the exception exn_clear(); } return NULL; } }
Field* Class::_resolve_field(Global_Env *env, unsigned cp_index) { lock(); if(m_const_pool.is_entry_in_error(cp_index)) { TRACE2("resolve.testing", "Constant pool entry " << cp_index << " already contains error."); unlock(); return NULL; } #ifdef ORDER if(m_const_pool.is_entry_resolved(cp_index, this)) {//ORDER unlock(); return m_const_pool.get_ref_field(cp_index); } #else if(m_const_pool.is_entry_resolved(cp_index)) { unlock(); return m_const_pool.get_ref_field(cp_index); } #endif // // constant pool entry hasn't been resolved yet // unsigned other_index = m_const_pool.get_ref_class_index(cp_index); unlock(); // // check error condition from resolve class // Class* other_clss = _resolve_class(env, other_index); if(!other_clss) { if(m_const_pool.is_entry_in_error(other_index)) { class_report_failure(this, cp_index, m_const_pool.get_error_cause(other_index)); } else { assert(exn_raised()); } return NULL; } uint16 name_and_type_index = m_const_pool.get_ref_name_and_type_index(cp_index); String* name = m_const_pool.get_name_and_type_name(name_and_type_index); String* desc = m_const_pool.get_name_and_type_descriptor(name_and_type_index); Field* field = other_clss->lookup_field_recursive(name, desc); if(field == NULL) { // // NoSuchFieldError // CLASS_REPORT_FAILURE(this, cp_index, "java/lang/NoSuchFieldError", other_clss->get_name()->bytes << "." << name->bytes << " of type " << desc->bytes << " while resolving constant pool entry at index " << cp_index << " in class " << get_name()->bytes); return NULL; } // // check access permissions // if(!can_access_member(field)) { // // IllegalAccessError // CLASS_REPORT_FAILURE(this, cp_index, "java/lang/IllegalAccessError", other_clss->get_name()->bytes << "." << name->bytes << " of type " << desc->bytes << " while resolving constant pool entry at index " << cp_index << " in class " << get_name()->bytes); return NULL; } lock(); m_const_pool.resolve_entry(cp_index, field); unlock(); return field; } // Class::_resolve_field
void exn_rethrow_if_pending() { if (exn_raised()) { exn_rethrow(); } } //exn_rethrow_if_pending
Method* Class::_resolve_method(Global_Env* env, unsigned cp_index) { lock(); if(m_const_pool.is_entry_in_error(cp_index)) { TRACE2("resolve.testing", "Constant pool entry " << cp_index << " already contains error."); unlock(); return NULL; } #ifdef ORDER if(m_const_pool.is_entry_resolved(cp_index, this)) {//ORDER unlock(); return m_const_pool.get_ref_method(cp_index); } #else if(m_const_pool.is_entry_resolved(cp_index)) {//ORDER unlock(); return m_const_pool.get_ref_method(cp_index); } #endif // // constant pool entry hasn't been resolved yet // unsigned other_index; other_index = m_const_pool.get_ref_class_index(cp_index); unlock(); // // check error condition from resolve class // Class* other_clss = _resolve_class(env, other_index); if(!other_clss) { if(m_const_pool.is_entry_in_error(other_index)) { class_report_failure(this, cp_index, m_const_pool.get_error_cause(other_index)); } else { assert(exn_raised()); } return NULL; } uint16 name_and_type_index = m_const_pool.get_ref_name_and_type_index(cp_index); String* name = m_const_pool.get_name_and_type_name(name_and_type_index); String* desc = m_const_pool.get_name_and_type_descriptor(name_and_type_index); // CONSTANT_Methodref must refer to a class, not an interface, and // CONSTANT_InterfaceMethodref must refer to an interface (vm spec 4.4.2) if(m_const_pool.is_methodref(cp_index) && other_clss->is_interface()) { CLASS_REPORT_FAILURE(this, cp_index, "java/lang/IncompatibleClassChangeError", other_clss->get_name()->bytes << " while resolving constant pool entry " << cp_index << " in class " << m_name->bytes); return NULL; } if(m_const_pool.is_interfacemethodref(cp_index) && !other_clss->is_interface()) { CLASS_REPORT_FAILURE(this, cp_index, "java/lang/IncompatibleClassChangeError", other_clss->get_name()->bytes << " while resolving constant pool entry " << cp_index << " in class " << m_name->bytes); return NULL; } Method* method = class_lookup_method_recursive(other_clss, name, desc); if(method == NULL) { // NoSuchMethodError CLASS_REPORT_FAILURE(this, cp_index, "java/lang/NoSuchMethodError", other_clss->get_name()->bytes << "." << name->bytes << desc->bytes << " while resolving constant pool entry at index " << cp_index << " in class " << m_name->bytes); return NULL; } if(method->is_abstract() && !other_clss->is_abstract()) { // AbstractMethodError CLASS_REPORT_FAILURE(this, cp_index, "java/lang/AbstractMethodError", other_clss->get_name()->bytes << "." << name->bytes << desc->bytes << " while resolving constant pool entry at index " << cp_index << " in class " << m_name->bytes); return NULL; } // // check access permissions // if(!can_access_member(method)) { // IllegalAccessError CLASS_REPORT_FAILURE(this, cp_index, "java/lang/IllegalAccessError", other_clss->get_name()->bytes << "." << name->bytes << desc->bytes << " while resolving constant pool entry at index " << cp_index << " in class " << m_name->bytes); return NULL; } lock(); m_const_pool.resolve_entry(cp_index, method); unlock(); return method; } //_resolve_method
// 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
// 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
Class* Class::_resolve_class(Global_Env* env, unsigned cp_index) { assert(hythread_is_suspend_enabled()); ConstantPool& cp = m_const_pool; lock(); if(cp.is_entry_in_error(cp_index)) { TRACE2("resolve.testing", "Constant pool entry " << cp_index << " already contains error."); unlock(); return NULL; } #ifdef ORDER if(cp.is_entry_resolved(cp_index, this)) {//ORDER unlock(); return cp.get_class_class(cp_index); } #else if(cp.is_entry_resolved(cp_index)) {//ORDER unlock(); return cp.get_class_class(cp_index); } #endif const String* classname = cp.get_utf8_string(cp.get_class_name_index(cp_index)); unlock(); // load the class in Class* other_clss = m_class_loader->LoadVerifyAndPrepareClass(env, classname); if(other_clss == NULL) { // FIXMECL should find out if this is VirtualMachineError assert(exn_raised()); class_report_failure(this, cp_index, exn_get()); exn_clear(); return NULL; } // Check access control: // referenced class should be public, // or referenced class & declaring class are the same, // or referenced class & declaring class are in the same runtime package, // or declaring class not checked // (the last case is needed for certain magic classes, // eg, reflection implementation) if(m_can_access_all || other_clss->is_public() || other_clss == this || m_package == other_clss->m_package) { lock(); cp.resolve_entry(cp_index, other_clss); unlock(); return other_clss; } // Check access control for inner classes: // access control checks is the same as for members if(strrchr(other_clss->get_name()->bytes, '$') != NULL && can_access_inner_class(env, other_clss)) { lock(); cp.resolve_entry(cp_index, other_clss); unlock(); return other_clss; } CLASS_REPORT_FAILURE(this, cp_index, "java/lang/IllegalAccessError", "from " << get_name()->bytes << " to " << other_clss->get_name()->bytes); // IllegalAccessError return NULL; } // Class::_resolve_class
bool Class::load_ancestors(Global_Env* env) { m_state = ST_LoadingAncestors; const String* superName = get_super_class_name(); if(superName == NULL) { if(env->InBootstrap() || get_name() != env->JavaLangClass_String) { // This class better be java.lang.Object if(get_name() != env->JavaLangObject_String) { // ClassFormatError std::stringstream ss; ss << get_name()->bytes << ": class does not have superclass " << "but the class is not java.lang.Object"; REPORT_FAILED_CLASS_CLASS(m_class_loader, this, "java/lang/ClassFormatError", ss.str().c_str()); return false; } } } else { // Load super class Class* superClass; m_super_class.name = NULL; superClass = m_class_loader->LoadVerifyAndPrepareClass(env, superName); if(superClass == NULL) { assert(exn_raised()); return false; } if(superClass->is_interface()) { REPORT_FAILED_CLASS_CLASS(m_class_loader, this, "java/lang/IncompatibleClassChangeError", "class " << m_name->bytes << " has interface " << superClass->get_name()->bytes << " as super class"); return false; } if(superClass->is_final()) { REPORT_FAILED_CLASS_CLASS(m_class_loader, this, "java/lang/VerifyError", m_name->bytes << " cannot inherit from final class " << superClass->get_name()->bytes); return false; } // super class was successfully loaded m_super_class.clss = superClass; if(m_super_class.cp_index) { m_const_pool.resolve_entry(m_super_class.cp_index, superClass); } // if it's an interface, its superclass must be java/lang/Object if(is_interface()) { if((env->JavaLangObject_Class != NULL) && (superClass != env->JavaLangObject_Class)) { std::stringstream ss; ss << get_name()->bytes << ": interface superclass is not java.lang.Object"; REPORT_FAILED_CLASS_CLASS(m_class_loader, this, "java/lang/ClassFormatError", ss.str().c_str()); return false; } } // Update the cha_first_child and cha_next_sibling fields. m_cha_first_child = NULL; if(has_super_class()) { m_cha_next_sibling = get_super_class()->m_cha_first_child; get_super_class()->m_cha_first_child = this; } } // // load in super interfaces // for(unsigned i = 0; i < m_num_superinterfaces; i++ ) { const String* intfc_name = m_superinterfaces[i].name; Class* intfc = m_class_loader->LoadVerifyAndPrepareClass(env, intfc_name); if(intfc == NULL) { assert(exn_raised()); return false; } if(!intfc->is_interface()) { REPORT_FAILED_CLASS_CLASS(m_class_loader, this, "java/lang/IncompatibleClassChangeError", get_name()->bytes << ": " << intfc->get_name()->bytes << " is not an interface"); return false; } // superinterface was successfully loaded m_superinterfaces[i].clss = intfc; if(m_superinterfaces[i].cp_index != 0) { // there are no constant pool entries for array classes m_const_pool.resolve_entry(m_superinterfaces[i].cp_index, intfc); } } // class, superclass, and superinterfaces successfully loaded m_state = ST_Loaded; if(!is_array()) m_package = m_class_loader->ProvidePackage(env, m_name, NULL); 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; }
/* * Class: java_lang_VMClassRegistry * Method: getSystemPackages * Signature: (I)[[Ljava/lang/String; */ JNIEXPORT jobjectArray JNICALL Java_java_lang_VMClassRegistry_getSystemPackages (JNIEnv *jenv, jclass, jint len) { Global_Env* genv = VM_Global_State::loader_env; ClassLoader* cl = static_cast<ClassLoader*> (genv->bootstrap_class_loader); Package_Table* ptab = cl->getPackageTable(); cl->Lock(); unsigned p_num = (unsigned)ptab->size(); if (p_num == (unsigned)len) { cl->Unlock(); return NULL; } const char ** pkgs = (const char **)STD_MALLOC(p_num * 2 * sizeof(char*)); size_t buf_len = 0; unsigned index = 0; for (Package_Table::const_iterator it = ptab->begin(), end = ptab->end(); it != end; ++it) { const char* name = pkgs[index++] = (*it).first->bytes; pkgs[index++] = (*it).second->get_jar(); size_t name_len = (*it).first->len; if (name_len > buf_len) { buf_len = name_len; } } cl->Unlock(); jclass string_class = struct_Class_to_java_lang_Class_Handle(genv->JavaLangString_Class); static Class* aos = genv->LoadCoreClass("[Ljava/lang/String;"); jclass string_array_class = struct_Class_to_java_lang_Class_Handle(aos); assert(string_class); assert(string_array_class); jobjectArray result = NewObjectArray(jenv, p_num, string_array_class, NULL); if (result) { char* buf = (char*)STD_MALLOC(buf_len + 1); p_num *= 2; for (index = 0; index < p_num; ) { jobjectArray pair = NewObjectArray(jenv, 2, string_class, NULL); if (!pair) { break; } SetObjectArrayElement(jenv, result, index/2, pair); char* name = strcpy(buf, pkgs[index++]); for (char* c = name; *c != '\0'; ++c) { if (*c == '/') { *c = '.'; } } jstring jname = NewStringUTF(jenv, name); if (!jname) { break; } SetObjectArrayElement(jenv, pair, 0, jname); const char * jar = pkgs[index++]; if (jar) { jstring js = NewStringUTF(jenv, jar); if (!js) break; SetObjectArrayElement(jenv, pair, 1, js); } } STD_FREE(buf); } STD_FREE(pkgs); assert(result || exn_raised()); return result; }