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); }
/* * Inflates the compressed lockword into fat fat_monitor */ hythread_monitor_t VMCALL hythread_inflate_lock(hythread_thin_monitor_t *lockword_ptr) { hythread_monitor_t fat_monitor; IDATA status; IDATA fat_monitor_id; U_32 lockword; int i; // we don't need to write lock on lock_table during all this function because // the only invariant we need is 'fat lock is not in the fat lock table before we put it' // however this invariant is true because we hold monitor->mutex during this function // so it cannot be called twice for the signle monitor concurrently lockword = *lockword_ptr; if (IS_FAT_LOCK (lockword)) { return locktable_get_fat_monitor(FAT_LOCK_ID(lockword)); } #ifdef LOCK_RESERVATION // unreserve lock first if (IS_RESERVED(lockword)) { unreserve_self_lock(lockword_ptr); lockword = *lockword_ptr; } assert(!IS_RESERVED(lockword)); #endif assert(hythread_owns_thin_lock(tm_self_tls, lockword)); assert(!hythread_is_suspend_enabled()); CTRACE(("inflation begin for %x thread: %d", lockword, tm_self_tls->thread_id)); status = hythread_monitor_init(&fat_monitor, 0); // allocate fat fat_monitor //assert(status == TM_ERROR_NONE); if (status != TM_ERROR_NONE) { return NULL; } status = hythread_monitor_enter(fat_monitor); if (status != TM_ERROR_NONE) { return NULL; } for (i = RECURSION(lockword); i > 0; i--) { CTRACE(("inflate recursion monitor")); status = hythread_monitor_enter(fat_monitor); // transfer recursion count to fat fat_monitor assert(status == TM_ERROR_NONE); } fat_monitor_id = locktable_put_fat_monitor(fat_monitor); // put fat_monitor into lock table set_fat_lock_id(lockword_ptr, fat_monitor_id); CTRACE(("hythread_inflate_lock %d thread: %d\n", FAT_LOCK_ID(*lockword_ptr), tm_self_tls->thread_id)); //assert(FAT_LOCK_ID(*lockword_ptr) != 2); CTRACE(("FAT ID : 0x%x", *lockword_ptr)); #ifdef LOCK_RESERVATION assert(!IS_RESERVED(*lockword_ptr)); #endif return fat_monitor; }
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; }
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); }
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_throw_by_class_internal(Class* exc_class, 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()); #ifdef VM_LAZY_EXCEPTION //set_unwindable(false); jvalue args[3]; Method* exc_init = prepare_exc_creating( exc_class, args, exc_message, exc_cause); if (NULL == exc_init) { CTRACE(("%s", "exn_throw_by_class(),create exception and delegating to exn_throw_for_JIT()")); jthrowable exc_object = exn_create(exc_class, exc_message, exc_cause); exn_rethrow_if_pending(); //set_unwindable(true); exn_throw_object_internal(exc_object); } else { CTRACE(("%s", "exn_throw_by_class(), lazy delegating to exn_throw_for_JIT()")); //set_unwindable(true); // no return, so enable isn't required tmn_suspend_disable(); exn_throw_for_JIT(NULL, exc_class, exc_init, NULL, args); //tmn_suspend_enable(); } #else jthrowable exc_object = exn_create(exc_class, exc_message, exc_cause); exn_rethrow_if_pending(); exn_throw_object_internal(exc_object); #endif END_RAISE_AREA; }
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_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; }
// Return the type of incompatible class change exception Class_Handle exn_get_incompatible_class_change_exception_type() { assert(hythread_is_suspend_enabled()); Class *exn_clss; Global_Env *env = VM_Global_State::loader_env; String *exc_str = env->string_pool.lookup("java/lang/IncompatibleClassChangeError"); exn_clss = env->bootstrap_class_loader->LoadVerifyAndPrepareClass(env, exc_str); assert(exn_clss); return exn_clss; }
//FIXME LAZY EXCEPTION (2006.05.13) // cause can be null static Method* prepare_exc_creating(Class* exc_class, jvalue* args) { ASSERT_RAISE_AREA; assert(hythread_is_suspend_enabled()); // Finds corresponding constructor Method* exc_init = lookup_exc_constructor(exc_class, "()V"); // Check that constructor is found if (NULL == exc_init) { return prepare_exc_creating(exc_class, args, ""); } // Returns found constructor return exc_init; }
jthrowable create_exception(Class* exc_class, const char* exc_message, jthrowable exc_cause) { ASSERT_RAISE_AREA; assert(hythread_is_suspend_enabled()); jvalue args[3]; Method *exc_init = prepare_exc_creating(exc_class, args, exc_message, exc_cause); if (exc_init == NULL){ return NULL; } return create_exception(exc_class, exc_init, args); } // create_exception(Class *exc_class, const char *exc_message, jthrowable exc_cause)
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; }
jthrowable exn_create(Class* exc_class, const char* exc_message, jthrowable exc_cause) { ASSERT_RAISE_AREA; assert(hythread_is_suspend_enabled()); jthrowable exc_object = create_exception(exc_class, exc_message, exc_cause); if (exc_object == NULL) { exc_object = create_exception(exc_class, exc_message , NULL); if (exc_object == NULL) { return NULL; } init_cause(exc_object, exc_cause); } return exc_object; }
// Return the type of negative array size exception Class_Handle exn_get_negative_array_size_exception_type() { assert(hythread_is_suspend_enabled()); Class *exn_clss; Global_Env *env = VM_Global_State::loader_env; String *exc_str = env->string_pool.lookup("java/lang/NegativeArraySizeException"); exn_clss = env->bootstrap_class_loader->LoadVerifyAndPrepareClass(env, exc_str); assert(exn_clss); return exn_clss; }
static void class_report_failure(Class* target, uint16 cp_index, jthrowable exn) { ConstantPool& cp = target->get_constant_pool(); assert(cp.is_valid_index(cp_index)); assert(hythread_is_suspend_enabled()); assert(exn); tmn_suspend_disable(); target->lock(); if (!cp.is_entry_in_error(cp_index)) { // vvv - This should be atomic change cp.resolve_as_error(cp_index, exn); // ^^^ } target->unlock(); tmn_suspend_enable(); }
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; }
static Method* prepare_exc_creating(Class* exc_class, jvalue* args, const char* exc_message, jthrowable exc_cause) { ASSERT_RAISE_AREA; assert(hythread_is_suspend_enabled()); // Checks that it's corresponding method if (NULL == exc_message) { return prepare_exc_creating(exc_class, args, exc_cause); } // Checks that it's corresponding method if (NULL == exc_cause) { return prepare_exc_creating(exc_class, args, exc_message); } // Finds corresponding constructor Method* exc_init = lookup_exc_constructor(exc_class, "(Ljava/lang/String;Ljava/lang/Throwable;)V"); // Check that constructor is found if (NULL == exc_init){ return NULL; } // Creates string object tmn_suspend_disable_recursive(); ManagedObject *arg_obj = string_create_from_utf8(exc_message, (unsigned) strlen(exc_message)); if (!arg_obj) { exn_raise_object(VM_Global_State::loader_env->java_lang_OutOfMemoryError); return NULL; } jobject arg = oh_allocate_local_handle(); arg->object = arg_obj; tmn_suspend_enable_recursive(); // Fills arguments for constructor args[1].l = arg; args[2].l = exc_cause; // Returns found constructor return exc_init; }
// function is safe point & should be called in disable mode in safe enviroment ManagedObject* __stdcall get_exception_object_internal() { assert(!hythread_is_suspend_enabled()); if (NULL != p_TLS_vmthread->thread_exception.exc_object) { return p_TLS_vmthread->thread_exception.exc_object; } else if (NULL != p_TLS_vmthread->thread_exception.exc_class) { Exception* exception = (Exception*)&(p_TLS_vmthread->thread_exception); // suspend can be enabeled in safe enviroment tmn_suspend_enable(); jthrowable exc_object = create_exception(exception); tmn_suspend_disable(); return exc_object->object; } else { return NULL; } } // get_exc_object_internal
void init_cause(jthrowable exc_object, jthrowable exc_cause) { ASSERT_RAISE_AREA; assert(exc_cause); assert(hythread_is_suspend_enabled()); tmn_suspend_disable(); Class* exc_class = exc_object->object->vt()->clss; Method *init_cause_method = class_lookup_method_recursive(exc_class, "initCause", "(Ljava/lang/Throwable;)Ljava/lang/Throwable;"); assert(init_cause_method); jvalue args[2]; args[0].l = exc_object; args[1].l = exc_cause; jvalue ret_val; vm_execute_java_method_array((jmethodID) init_cause_method, &ret_val, args); tmn_suspend_enable(); }
static Vector_Handle vm_anewarray_resolved_array_type(Class *arr_clss, int length) { #ifdef VM_STATS UNSAFE_REGION_START VM_Statistics::get_vm_stats().num_anewarray++; UNSAFE_REGION_END #endif ASSERT_RAISE_AREA; assert(!hythread_is_suspend_enabled()); assert(!arr_clss->is_array_of_primitives()); unsigned sz = arr_clss->calculate_array_size(length); if (sz == 0) { tmn_suspend_enable(); if (length < 0) { exn_raise_by_name("java/lang/NegativeArraySizeException"); } else { exn_raise_by_name("java/lang/OutOfMemoryError", "VM doesn't support arrays of the requested size"); } tmn_suspend_disable(); return NULL; } assert((sz & NEXT_TO_HIGH_BIT_SET_MASK) == 0); Vector_Handle object_array = (Vector_Handle )gc_alloc(sz, arr_clss->get_allocation_handle(), vm_get_gc_thread_local()); #ifdef VM_STATS arr_clss->instance_allocated(sz); #endif //VM_STATS if (NULL == object_array) { exn_raise_object( VM_Global_State::loader_env->java_lang_OutOfMemoryError); return NULL; } set_vector_length(object_array, length); assert(get_vector_vtable(object_array) == arr_clss->get_vtable()); return object_array; } //vm_anewarray_resolved_array_type
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); } }
/** * 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; }
ManagedObject* Class::allocate_instance() { assert(!hythread_is_suspend_enabled()); //assert(is_initialized()); ManagedObject* new_instance = (ManagedObject*)vm_alloc_and_report_ti(m_instance_data_size, m_allocation_handle, vm_get_gc_thread_local(), this); if(new_instance == NULL) { return NULL; } #ifdef VM_STATS UNSAFE_REGION_START VM_Statistics::get_vm_stats().num_class_alloc_new_object++; instance_allocated(m_instance_data_size); UNSAFE_REGION_END #endif //VM_STATS return new_instance; }
jvmtiError interpreter_ti_getObject( jvmtiEnv* env, VM_thread *thread, jint depth, jint slot, jobject* value_ptr) { StackFrame *frame; // check error condition: JVMTI_ERROR_NULL_POINTER if( value_ptr == NULL ) return JVMTI_ERROR_NULL_POINTER; // check error condition: JVMTI_ERROR_NO_MORE_FRAMES // check error condition: JVMTI_ERROR_OPAQUE_FRAME // check error condition: JVMTI_ERROR_INVALID_SLOT jvmtiError err = interpreter_ti_getLocalCommon(env, thread, depth, slot, &frame); if (err != JVMTI_ERROR_NONE) return err; // TODO: check error condition: JVMTI_ERROR_TYPE_MISMATCH // partial check error condition: JVMTI_ERROR_TYPE_MISMATCH if (frame->locals.ref(slot) == 0) { return JVMTI_ERROR_TYPE_MISMATCH; } assert(hythread_is_suspend_enabled()); hythread_suspend_disable(); ManagedObject *obj = UNCOMPRESS_INTERP(frame->locals(slot).ref); if (NULL == obj) { *value_ptr = NULL; } else { ObjectHandle handle = oh_allocate_local_handle(); handle->object = obj; *value_ptr = (jobject) handle; } hythread_suspend_enable(); return JVMTI_ERROR_NONE; }
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; }
// Create an exception from a given type and a message. // Set cause to the current thread exception. static void compile_raise_exception(const char* name, const char* message, Method* method) { assert(hythread_is_suspend_enabled()); jthrowable old_exc = exn_get(); exn_clear(); const char* c = method->get_class()->get_name()->bytes; const char* m = method->get_name()->bytes; const char* d = method->get_descriptor()->bytes; size_t sz = 3 + // a space, a dot, and a terminator strlen(message) + method->get_class()->get_name()->len + method->get_name()->len + method->get_descriptor()->len; char* msg_raw = (char*)STD_MALLOC(sz); assert(msg_raw); sprintf(msg_raw, "%s%s.%s%s", message, c, m, d); assert(strlen(msg_raw) < sz); jthrowable new_exc = exn_create(name, msg_raw, old_exc); exn_raise_object(new_exc); STD_FREE(msg_raw); }
/** * Detaches current thread from VM. */ jint vm_detach(jobject java_thread) { assert(hythread_is_suspend_enabled()); hythread_t native_thread = jthread_get_native_thread(java_thread); assert(native_thread); vm_thread_t p_vm_thread = jthread_get_vm_thread(native_thread); assert(p_vm_thread); // Send Thread End event if(jvmti_should_report_event(JVMTI_EVENT_THREAD_END)) { jvmti_send_thread_start_end_event(p_vm_thread, 0); } // change java_status for native thread native_thread->java_status = TM_STATUS_ALLOCATED; if (native_thread == hythread_self()) { // Notify GC about thread detaching. // FIXME - GC notify detach thread works for current thread only gc_thread_kill(&p_vm_thread->_gc_private_information); } if (ti_is_enabled()) { apr_status_t UNREF status; status = port_vmem_free( p_vm_thread->jvmti_thread.jvmti_jit_breakpoints_handling_buffer, TM_JVMTI_MAX_BUFFER_SIZE); assert(status == APR_SUCCESS); } // Destroy current VM_thread pool and zero VM_thread structure jthread_deallocate_vm_thread_pool(p_vm_thread); return JNI_OK; }
static Class_Handle method_get_return_type_class(Method_Handle m) { assert(hythread_is_suspend_enabled()); Method *method = (Method *)m; Global_Env *env = VM_Global_State::loader_env; Java_Type UNUSED t = method->get_return_java_type(); assert(t == JAVA_TYPE_CLASS || t == JAVA_TYPE_ARRAY); const char *descr = method->get_descriptor()->bytes; while(*descr != ')') descr++; descr++; String *n; if(descr[0] == 'L') { descr++; size_t len = strlen(descr); n = env->string_pool.lookup(descr, len-1); } else { n = env->string_pool.lookup(descr); } Class *clss = method->get_class(); Class *c = clss->get_class_loader()->LoadVerifyAndPrepareClass(env, n); return c; } //method_get_return_type_class
static Method* prepare_exc_creating(Class* exc_class, jvalue* args, jthrowable exc_cause) { ASSERT_RAISE_AREA; assert(hythread_is_suspend_enabled()); // Checks that it's corresponding method if (NULL == exc_cause) { return prepare_exc_creating(exc_class, args); } // Finds corresponding constructor Method* exc_init = lookup_exc_constructor(exc_class, "(Ljava/lang/Throwable;)V"); // Check that constructor is found if (exc_init == NULL){ return prepare_exc_creating(exc_class, args, "", exc_cause); } // Fills arguments for constructor args[1].l = exc_cause; // Returns found constructor return exc_init; }