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(); }
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; }
// // resolve constant pool reference to a method // used for invokespecial // Method* resolve_special_method_env(Global_Env *env, Class_Handle curr_clss, unsigned index, bool raise_exn) { ASSERT_RAISE_AREA; Method* method = curr_clss->_resolve_method(env, index); if(!method) { assert(curr_clss->get_constant_pool().is_entry_in_error(index)); if (raise_exn) { exn_raise_object(curr_clss->get_constant_pool().get_error_cause(index)); } return NULL; } if(curr_clss->is_super() && is_class_extended_class(curr_clss->get_super_class(), method->get_class()) && method->get_name() != env->Init_String) { Method* result_meth; for(Class* clss = curr_clss->get_super_class(); clss; clss = clss->get_super_class()) { result_meth = clss->lookup_method(method->get_name(), method->get_descriptor()); if(result_meth) { method = result_meth; break; } } } if(method && !method_can_link_special(curr_clss, index, method, raise_exn)) return NULL; return method; } //resolve_special_method_env
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 interp_throw_exception(const char* exc_name, const char* exc_message) { M2N_ALLOC_MACRO; assert(!hythread_is_suspend_enabled()); hythread_suspend_enable(); assert(hythread_is_suspend_enabled()); jthrowable exc_object = exn_create(exc_name, exc_message); exn_raise_object(exc_object); hythread_suspend_disable(); M2N_FREE_MACRO; }
Class_Handle type_info_get_class_no_exn(Type_Info_Handle tih) { // Store raised exception jthrowable exc_object = exn_get(); // Workaround to let JIT invoke class loader even if exception is pending exn_clear(); Class_Handle ch = type_info_get_class(tih); // To clear exn_class if set exn_clear(); // Restore saved exception if (exc_object) exn_raise_object(exc_object); return ch; } // type_info_get_class_no_exn
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; }
Method* resolve_interface_method_env(Global_Env *env, Class *clss, unsigned cp_index, bool raise_exn) { Method* method = clss->_resolve_method(env, cp_index); if (!method) { assert(clss->get_constant_pool().is_entry_in_error(cp_index)); if (raise_exn) { exn_raise_object(clss->get_constant_pool().get_error_cause(cp_index)); } return NULL; } if (!method_can_link_interface(clss, cp_index, method, raise_exn)) { return NULL; } return method; }
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; }
IDATA jthread_throw_exception_object(jobject object) { if (interpreter_enabled()) { // FIXME - Function set_current_thread_exception does the same // actions as exn_raise_object, and it should be replaced. hythread_suspend_disable(); set_current_thread_exception(object->object); hythread_suspend_enable(); } else { if (is_unwindable()) { exn_throw_object(object); } else { ASSERT_RAISE_AREA; exn_raise_object(object); } } return 0; }
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
/* * 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; }
Field* resolve_nonstatic_field_env(Global_Env* env, Class* clss, unsigned cp_index, unsigned putfield, bool raise_exn) { ASSERT_RAISE_AREA; Field *field = clss->_resolve_field(env, cp_index); if(!field) { assert(clss->get_constant_pool().is_entry_in_error(cp_index)); if (raise_exn) { exn_raise_object(clss->get_constant_pool().get_error_cause(cp_index)); } return NULL; } if(!field_can_link(clss, field, CAN_LINK_FROM_FIELD, putfield, raise_exn)) { return NULL; } return field; }
/* * 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; }
// 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); }
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; }