static bool is_valid_object(jvmtiEnv* env, jobject handle) { SuspendEnabledChecker sec; if (NULL == handle) return true; tmn_suspend_disable(); ManagedObject *obj = ((ObjectHandle) handle)->object; if (obj < (ManagedObject *)VM_Global_State::loader_env->heap_base || obj > (ManagedObject *)VM_Global_State::loader_env->heap_end) { tmn_suspend_enable(); return false; } Class *clss = obj->vt()->clss; ManagedObject *clsObj = struct_Class_to_java_lang_Class(clss); // ppervov: FIXME: there is an assertion in the above function which // is exactly the same as in the following if. So, this code will only // work in release and just assert in debug. if (clsObj->vt()->clss != VM_Global_State::loader_env->JavaLangClass_Class) { tmn_suspend_enable(); return false; } tmn_suspend_enable(); return true; }
/** * Returns all monitors owned by the specific thread. * * @param[in] java_thread thread which owns monitors * @param[out] monitor_count_ptr number of owned monitors * @param[out] monitors_ptr array of owned monitors */ IDATA VMCALL jthread_get_owned_monitors(jthread java_thread, jint *monitor_count_ptr, jobject **monitors_ptr) { assert(java_thread); assert(monitors_ptr); assert(monitor_count_ptr); IDATA status = hythread_global_lock(); if (status != TM_ERROR_NONE) { return status; } vm_thread_t vm_thread = jthread_get_vm_thread_from_java(java_thread); if (!vm_thread) { status = hythread_global_unlock(); return status; } jvmti_thread_t jvmti_thread = &vm_thread->jvmti_thread; if (!jvmti_thread) { status = hythread_global_unlock(); return status; } jobject *monitors = (jobject *) malloc(sizeof(jobject *) * jvmti_thread->owned_monitors_nmb); if (!monitors) { hythread_global_unlock(); return TM_ERROR_OUT_OF_MEMORY; } tmn_suspend_disable(); for (int i = 0; i < jvmti_thread->owned_monitors_nmb; i++) { jobject new_ref = oh_allocate_local_handle_from_jni(); if (NULL != new_ref) new_ref->object = jvmti_thread->owned_monitors[i]->object; else { tmn_suspend_enable(); hythread_global_unlock(); return TM_ERROR_OUT_OF_MEMORY; } // change the order of reported monitors to be compliant with RI monitors[jvmti_thread->owned_monitors_nmb - 1 - i] = new_ref; } tmn_suspend_enable(); *monitors_ptr = monitors; *monitor_count_ptr = jvmti_thread->owned_monitors_nmb; status = hythread_global_unlock(); return status; } // jthread_get_owned_monitors
// Note: Function runs from unwindable area before exception throwing // function can be safe point & should be called with disable recursion = 1 static ManagedObject *create_lazy_exception( Class_Handle exn_class, Method_Handle exn_constr, U_8 * exn_constr_args, jvalue* vm_exn_constr_args) { assert(!hythread_is_suspend_enabled()); bool unwindable = set_unwindable(false); ManagedObject* result; if (NULL == vm_exn_constr_args) { result = class_alloc_new_object_and_run_constructor( (Class*) exn_class, (Method*) exn_constr, exn_constr_args); } else { // exception is throwing, so suspend can be enabled safely tmn_suspend_enable(); jthrowable exc_object = create_exception( (Class*) exn_class, (Method*) exn_constr, vm_exn_constr_args); if (exc_object) { result = exc_object->object; } else { result = NULL; } tmn_suspend_disable(); } set_unwindable(unwindable); exn_rethrow_if_pending(); return result; } //create_object_lazily
//FIXME LAZY EXCEPTION (2006.05.06) //Find all usage and change to lazy use jthrowable exn_get() { assert(hythread_is_suspend_enabled()); // we can check heap references for equality to NULL // without disabling gc, because GC wouldn't change // null to non-null and vice versa. vm_thread_t vm_thread = p_TLS_vmthread; if ((NULL == vm_thread->thread_exception.exc_object) && (NULL == vm_thread->thread_exception.exc_class)) { return NULL; } // returned value which will contains jthrowable value of // curent thread exception jobject exc; if (NULL != vm_thread->thread_exception.exc_object) { tmn_suspend_disable(); exc = oh_allocate_local_handle(); exc->object = (ManagedObject *) vm_thread->thread_exception.exc_object; tmn_suspend_enable(); } else if (NULL != vm_thread->thread_exception.exc_class) { exc = exn_create((Exception*)&(vm_thread->thread_exception)); } else { LDIE(59, "It's impossible internal error in exception handling."); } return exc; } // exn_get
VMEXPORT // temporary solution for interpreter unplug Vector_Handle vm_new_vector_primitive(Class *vector_class, int length) { ASSERT_RAISE_AREA; assert(!hythread_is_suspend_enabled()); assert(vector_class->is_array_of_primitives()); unsigned sz = vector_class->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; } Vector_Handle vector = (Vector_Handle)gc_alloc(sz, vector_class->get_allocation_handle(), vm_get_gc_thread_local()); #ifdef VM_STATS vector_class->instance_allocated(sz); #endif //VM_STATS if (NULL == vector) { exn_raise_object( VM_Global_State::loader_env->java_lang_OutOfMemoryError); return 0; } set_vector_length(vector, length); assert(get_vector_vtable(vector) == vector_class->get_vtable()); return vector; }
void class_throw_linking_error(Class_Handle ch, unsigned index, unsigned opcode) { ASSERT_RAISE_AREA; tmn_suspend_enable(); ConstantPool& cp = ch->get_constant_pool(); if(cp.is_entry_in_error(index)) { exn_raise_object(cp.get_error_cause(index)); tmn_suspend_disable(); return; // will return in interpreter mode } switch(opcode) { case OPCODE_NEW: class_can_instantiate(cp.get_class_class(index), LINK_THROW_ERRORS); break; case OPCODE_PUTFIELD: field_can_link(ch, cp.get_ref_field(index), CAN_LINK_FROM_FIELD, LINK_WRITE_ACCESS, LINK_THROW_ERRORS); break; case OPCODE_GETFIELD: field_can_link(ch, cp.get_ref_field(index), CAN_LINK_FROM_FIELD, LINK_READ_ACCESS, LINK_THROW_ERRORS); break; case OPCODE_PUTSTATIC: field_can_link(ch, cp.get_ref_field(index), CAN_LINK_FROM_STATIC, LINK_WRITE_ACCESS, LINK_THROW_ERRORS); break; case OPCODE_GETSTATIC: field_can_link(ch, cp.get_ref_field(index), CAN_LINK_FROM_STATIC, LINK_READ_ACCESS, LINK_THROW_ERRORS); break; case OPCODE_INVOKEINTERFACE: method_can_link_interface(ch, index, cp.get_ref_method(index), LINK_THROW_ERRORS); break; case OPCODE_INVOKESPECIAL: method_can_link_special(ch, index, cp.get_ref_method(index), LINK_THROW_ERRORS); break; case OPCODE_INVOKESTATIC: method_can_link_static(ch, index, cp.get_ref_method(index), LINK_THROW_ERRORS); break; case OPCODE_INVOKEVIRTUAL: method_can_link_virtual(ch, index, cp.get_ref_method(index), LINK_THROW_ERRORS); break; default: // FIXME Potentially this can be any RuntimeException or Error // The most probable case is OutOfMemoryError. LWARN(5, "**Java exception occured during resolution under compilation"); exn_raise_object(VM_Global_State::loader_env->java_lang_OutOfMemoryError); //ASSERT(0, "Unexpected opcode: " << opcode); break; } tmn_suspend_disable(); }
static Method* prepare_exc_creating(Class* exc_class, jvalue* args, const char* exc_message) { 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); } // Finds corresponding constructor Method* exc_init = lookup_exc_constructor(exc_class, "(Ljava/lang/String;)V"); // Check that constructor is found if (NULL == exc_init){ return NULL; } // Creates string object tmn_suspend_disable(); 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); tmn_suspend_enable(); return NULL; } jobject arg = oh_allocate_local_handle(); arg->object = arg_obj; tmn_suspend_enable(); // Fills arguments for constructor args[1].l = arg; // Returns found constructor return exc_init; }
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; }
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
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(); }
// 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
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 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
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 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); } }
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_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; }
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; }
jvmtiError JNICALL jvmtiGetLocalLong(jvmtiEnv* env, jthread thread, jint depth, jint slot, jlong* value_ptr) { TRACE("GetLocalLong called"); SuspendEnabledChecker sec; /* * Check given env & current phase. */ jvmtiPhase phases[] = {JVMTI_PHASE_LIVE}; CHECK_EVERYTHING(); CHECK_CAPABILITY(can_access_local_variables); // check error condition: JVMTI_ERROR_INVALID_THREAD // check error condition: JVMTI_ERROR_THREAD_NOT_ALIVE // check error condition: JVMTI_ERROR_ILLEGAL_ARGUMENT // check error condition: JVMTI_ERROR_NULL_POINTER jvmtiError err = GetLocal_checkArgs(env, &thread, depth, slot, value_ptr); if (err != JVMTI_ERROR_NONE) return err; bool thread_suspended = false; // Suspend thread before getting stacks vm_thread_t vm_thread; if (NULL != thread) { // Check that this thread is not current vm_thread = jthread_get_vm_thread_ptr_safe(thread); if (vm_thread != p_TLS_vmthread) { IDATA UNREF status = hythread_suspend_other((hythread_t)vm_thread); assert(TM_ERROR_NONE == status); thread_suspended = true; } } else vm_thread = p_TLS_vmthread; if (interpreter_enabled()) // check error condition: JVMTI_ERROR_INVALID_SLOT // check error condition: JVMTI_ERROR_OPAQUE_FRAME // check error condition: JVMTI_ERROR_NO_MORE_FRAMES // TODO: check error condition: JVMTI_ERROR_TYPE_MISMATCH err = interpreter.interpreter_ti_getLocal64(env, vm_thread, depth, slot, value_ptr); else { GET_JIT_FRAME_CONTEXT; tmn_suspend_disable(); OpenExeJpdaError result = jit->get_local_var(method, jfc, slot, VM_DATA_TYPE_INT64, value_ptr); si_free(si); tmn_suspend_enable(); err = jvmti_translate_jit_error(result); } if (thread_suspended) hythread_resume((hythread_t)vm_thread); return err; }
/** * General function to set value of local variable. * @param var_type type of the local variable * @param p_value pointer to the new variable value */ static jvmtiError set_local(jvmtiEnv* env, jthread thread, jint depth, jint slot, VM_Data_Type var_type, void* p_value) { SuspendEnabledChecker sec; /* * Check given env & current phase. */ jvmtiPhase phases[] = {JVMTI_PHASE_LIVE}; CHECK_EVERYTHING(); CHECK_CAPABILITY(can_access_local_variables); // check error condition: JVMTI_ERROR_INVALID_THREAD // check error condition: JVMTI_ERROR_THREAD_NOT_ALIVE // check error condition: JVMTI_ERROR_ILLEGAL_ARGUMENT jvmtiError err = GetLocal_checkArgs(env, &thread, depth, slot, p_value); if (err != JVMTI_ERROR_NONE) return err; // check error condition: JVMTI_ERROR_INVALID_OBJECT if (VM_DATA_TYPE_CLASS == var_type && ! is_valid_object(env, *(jobject*) p_value)) return JVMTI_ERROR_INVALID_OBJECT; bool thread_suspended = false; // Suspend thread before getting stacks vm_thread_t vm_thread; if (NULL != thread) { // Check that this thread is not current vm_thread = jthread_get_vm_thread_ptr_safe(thread); if (vm_thread != p_TLS_vmthread) { IDATA UNREF status = hythread_suspend_other((hythread_t)vm_thread); assert(TM_ERROR_NONE == status); thread_suspended = true; } } else vm_thread = p_TLS_vmthread; if (interpreter_enabled()) { // TODO: check error condition: JVMTI_ERROR_INVALID_SLOT // TODO: check error condition: JVMTI_ERROR_TYPE_MISMATCH // TODO: check error condition: JVMTI_ERROR_OPAQUE_FRAME // TODO: check error condition: JVMTI_ERROR_NO_MORE_FRAMES switch (var_type) { case VM_DATA_TYPE_CLASS: err = interpreter.interpreter_ti_setObject(env, vm_thread, depth, slot, *(jobject*) p_value); break; case VM_DATA_TYPE_INT32: case VM_DATA_TYPE_F4: err = interpreter.interpreter_ti_setLocal32(env, vm_thread, depth, slot, *(int*) p_value); break; case VM_DATA_TYPE_INT64: case VM_DATA_TYPE_F8: err = interpreter.interpreter_ti_setLocal64(env, vm_thread, depth, slot, *(int64*) p_value); break; default: DIE(("Error: unrecognized local variable type")); } } else { GET_JIT_FRAME_CONTEXT; tmn_suspend_disable(); OpenExeJpdaError result; switch (var_type) { case VM_DATA_TYPE_CLASS: if (NULL != *(jobject*) p_value) result = jit->set_local_var(method, jfc, slot, VM_DATA_TYPE_CLASS, &(*(ObjectHandle*) p_value)->object); else { ManagedObject *n = (ManagedObject *)VM_Global_State::loader_env->managed_null; result = jit->set_local_var(method, jfc, slot, VM_DATA_TYPE_CLASS, &n); } break; case VM_DATA_TYPE_INT32: case VM_DATA_TYPE_F4: case VM_DATA_TYPE_INT64: case VM_DATA_TYPE_F8: result = jit->set_local_var(method, jfc, slot, var_type, p_value); break; default: DIE(("Error: unrecognized local variable type")); } si_free(si); tmn_suspend_enable(); err = jvmti_translate_jit_error(result); } if (thread_suspended) hythread_resume((hythread_t)vm_thread); return err; }