ObjectArray* Java_java_lang_Class_getDeclaredFields0(Env* env, Class* clazz, jboolean publicOnly) { if (CLASS_IS_PRIMITIVE(clazz) || CLASS_IS_ARRAY(clazz)) return NULL; Field* fields = rvmGetFields(env, clazz); if (rvmExceptionCheck(env)) return NULL; Field* field; jint length = 0; for (field = fields; field != NULL; field = field->next) { if (!publicOnly || FIELD_IS_PUBLIC(field)) { length++; } } ObjectArray* result = NULL; jint i = 0; for (field = fields; field != NULL; field = field->next) { if (!publicOnly || FIELD_IS_PUBLIC(field)) { Object* c = createFieldObject(env, field); if (!c) return NULL; if (!result) { result = rvmNewObjectArray(env, length, c->clazz, NULL, NULL); if (!result) return NULL; } result->values[i++] = c; } } return result; }
static jboolean parseElementValue(Env* env, void** attributes, Class* type, Object* classLoader, jvalue* result) { if (CLASS_IS_PRIMITIVE(type)) { switch (type->name[0]) { case 'Z': return parseBooleanElementValue(env, attributes, result); case 'B': return parseByteElementValue(env, attributes, result); case 'S': return parseShortElementValue(env, attributes, result); case 'C': return parseCharElementValue(env, attributes, result); case 'I': return parseIntElementValue(env, attributes, result); case 'J': return parseLongElementValue(env, attributes, result); case 'F': return parseFloatElementValue(env, attributes, result); case 'D': return parseDoubleElementValue(env, attributes, result); } } else if (CLASS_IS_ARRAY(type)) { return parseArrayElementValue(env, attributes, type, classLoader, result); } else if (type == java_lang_Class) { return parseClassElementValue(env, attributes, classLoader, result); } else if (type == java_lang_String) { return parseStringElementValue(env, attributes, result); } else if (CLASS_IS_ENUM(type) && type->superclass == java_lang_Enum) { return parseEnumElementValue(env, attributes, classLoader, result); } else if (CLASS_IS_ANNOTATION(type) && CLASS_IS_INTERFACE(type)) { return parseAnnotationElementValue(env, attributes, type, classLoader, result); } return FALSE; }
ObjectArray* Java_java_lang_Class_getDeclaredClasses0(Env* env, Class* clazz, jboolean publicOnly) { if (CLASS_IS_PRIMITIVE(clazz) || CLASS_IS_ARRAY(clazz)) return NULL; ObjectArray* result = rvmAttributeGetDeclaredClasses(env, clazz); if (!result || result->length == 0 || !publicOnly) { return result; } jint length = 0; jint i; for (i = 0; i < result->length; i++) { Class* c = (Class*) result->values[i]; if (CLASS_IS_PUBLIC(c)) { length++; } } if (length == 0) return NULL; ObjectArray* publicResult = rvmNewObjectArray(env, length, java_lang_Class, NULL, NULL); if (!publicResult) return NULL; jint index = 0; for (i = 0; i < result->length; i++) { Class* c = (Class*) result->values[i]; if (CLASS_IS_PUBLIC(c)) { publicResult->values[index++] = (Object*) c; } } return publicResult; }
ObjectArray* Java_java_lang_Class_getDeclaredMethods0(Env* env, Class* clazz, jboolean publicOnly) { if (CLASS_IS_PRIMITIVE(clazz) || CLASS_IS_ARRAY(clazz)) return NULL; Method* methods = rvmGetMethods(env, clazz); if (rvmExceptionCheck(env)) return NULL; Method* method; jint length = 0; for (method = methods; method != NULL; method = method->next) { if (!METHOD_IS_CONSTRUCTOR(method) && !METHOD_IS_CLASS_INITIALIZER(method)) { if (!publicOnly || METHOD_IS_PUBLIC(method)) { length++; } } } ObjectArray* result = NULL; jint i = 0; for (method = methods; method != NULL; method = method->next) { if (!METHOD_IS_CONSTRUCTOR(method) && !METHOD_IS_CLASS_INITIALIZER(method)) { if (!publicOnly || METHOD_IS_PUBLIC(method)) { Object* c = createMethodObject(env, method); if (!c) return NULL; if (!result) { result = rvmNewObjectArray(env, length, c->clazz, NULL, NULL); if (!result) return NULL; } result->values[i++] = c; } } } return result; }
static Class* createArrayClass(Env* env, Class* componentType) { jint length = strlen(componentType->name); char* desc = NULL; if (CLASS_IS_ARRAY(componentType) || CLASS_IS_PRIMITIVE(componentType)) { desc = rvmAllocateMemoryAtomic(env, length + 2); if (!desc) return NULL; desc[0] = '['; strcat(desc, componentType->name); } else { desc = rvmAllocateMemoryAtomic(env, length + 4); if (!desc) return NULL; desc[0] = '['; desc[1] = 'L'; strcat(desc, componentType->name); desc[length + 2] = ';'; } // TODO: Add clone() method. Class* clazz = rvmAllocateClass(env, desc, java_lang_Object, componentType->classLoader, CLASS_TYPE_ARRAY | CLASS_STATE_INITIALIZED | ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT, sizeof(Class), sizeof(Object), sizeof(Object), 0, 0, NULL, NULL); if (!clazz) return NULL; clazz->componentType = componentType; // Initialize methods to NULL to prevent rvmGetMethods() from trying to load the methods if called with this array class clazz->_methods = NULL; if (!rvmAddInterface(env, clazz, java_lang_Cloneable)) return NULL; if (!rvmAddInterface(env, clazz, java_io_Serializable)) return NULL; if (!rvmRegisterClass(env, clazz)) return NULL; return clazz; }
jboolean rvmIsAssignableFrom(Env* env, Class* s, Class* t) { // TODO: What if s or t are NULL? if (s == t || t == java_lang_Object) { return TRUE; } if (CLASS_IS_ARRAY(s)) { if (t == java_io_Serializable) { return TRUE; } if (t == java_lang_Cloneable) { return TRUE; } if (!CLASS_IS_ARRAY(t)) { return FALSE; } Class* componentType = s->componentType; if (CLASS_IS_PRIMITIVE(componentType)) { // s is a primitive array and can only be assigned to // class t if s == t or t == (Object|Serializable|Cloneable). But we // already know that s != t and t != (Object|Serializable|Cloneable) return FALSE; } return rvmIsAssignableFrom(env, componentType, t->componentType); } if (CLASS_IS_INTERFACE(t)) { // s or any of its parents must implement the interface t for (; s; s = s->superclass) { Interface* interface = rvmGetInterfaces(env, s); if (rvmExceptionCheck(env)) return FALSE; for (; interface != NULL; interface = interface->next) { if (rvmIsAssignableFrom(env, interface->interface, t)) { return TRUE; } } } return FALSE; } while (s && s != t) { s = s->superclass; } return s ? TRUE : FALSE; }
static void heapDumpCallback(void* ptr, unsigned char kind, size_t sz, void* data) { if ((kind == GC_gcj_kind || kind == objectArrayGCKind) && ptr) { Object* obj = (Object*) ptr; if (obj->clazz) { if (obj->clazz == java_lang_Class) { Class* clazz = (Class*) obj; fprintf(stderr, " n%p [label=\"Class %s]\n", clazz, clazz->name); //, clazz->classDataSize); if (clazz->_data) { fprintf(stderr, " n%p -> n%p\n", clazz, clazz->_data); } void** start = (void**) (((char*) clazz) + offsetof(Class, data)); void** end = (void**) (((char*) start) + clazz->classRefCount * sizeof(Object*)); dumpRefs(clazz, start, end); } else if (CLASS_IS_ARRAY(obj->clazz)) { if (obj->clazz->name[1] == 'C') { // Array of chars. Include the 29 first characters in the dump. char s[30]; memset(s, 0, sizeof(s)); jint length = ((Array*) obj)->length; length = length > sizeof(s) - 1 ? sizeof(s) - 1 : length; for (jint i = 0; i < length; i++) { s[i] = (char) ((CharArray*) obj)->values[i]; } fprintf(stderr, " n%p [label=\"%s[%d] = %s\"]\n", obj, obj->clazz->name, ((Array*) obj)->length, s); } else { fprintf(stderr, " n%p [label=\"%s[%d]\"]\n", obj, obj->clazz->name, ((Array*) obj)->length); if (!CLASS_IS_PRIMITIVE(obj->clazz->componentType)) { ObjectArray* array = (ObjectArray*) obj; void** start = (void**) (((char*) array) + offsetof(ObjectArray, values)); void** end = (void**) (((char*) start) + sizeof(Object*) * array->length); dumpRefs(array, start, end); } } } else { Class* clazz = obj->clazz; fprintf(stderr, " n%p [label=\"Instance %s\"]\n", obj, obj->clazz->name); while (clazz != NULL) { void** start = (void**) (((char*) obj) + clazz->instanceDataOffset); void** end = (void**) (((char*) start) + clazz->instanceRefCount * sizeof(Object*)); if (clazz == java_lang_ref_Reference) { void** referent_start = (void**) (((char*) obj) + java_lang_ref_Reference_referent->offset); void** referent_end = (void**) (((char*) referent_start) + sizeof(Object*)); //if (*referent_start) { //fprintf(stderr, "\t%p (weak)\n", *referent_start); //} dumpRefs(obj, start, referent_start); dumpRefs(obj, referent_end, end); } else { dumpRefs(obj, start, end); } clazz = clazz->superclass; } } } } }
static struct GC_ms_entry* markObject(GC_word* addr, struct GC_ms_entry* mark_stack_ptr, struct GC_ms_entry* mark_stack_limit, GC_word env) { Object* obj = (Object*) addr; if (obj == NULL || obj->clazz == NULL || obj->clazz->object.clazz != java_lang_Class) { // According to the comments in gc_mark.h the GC sometimes calls the mark_proc with unused objects. // Such objects have been cleared except for the first word which points to a free list link field. // A valid RovoVM Object must point to a Class and the Class of the Object's Class must be java.lang.Class. return mark_stack_ptr; } mark_stack_ptr = GC_MARK_AND_PUSH(obj->clazz, mark_stack_ptr, mark_stack_limit, NULL); if (obj->clazz == java_lang_Class) { // Class* Class* clazz = (Class*) obj; mark_stack_ptr = GC_MARK_AND_PUSH(clazz->_data, mark_stack_ptr, mark_stack_limit, NULL); mark_stack_ptr = GC_MARK_AND_PUSH((void*) clazz->name, mark_stack_ptr, mark_stack_limit, NULL); mark_stack_ptr = GC_MARK_AND_PUSH(clazz->classLoader, mark_stack_ptr, mark_stack_limit, NULL); mark_stack_ptr = GC_MARK_AND_PUSH(clazz->superclass, mark_stack_ptr, mark_stack_limit, NULL); mark_stack_ptr = GC_MARK_AND_PUSH(clazz->componentType, mark_stack_ptr, mark_stack_limit, NULL); mark_stack_ptr = GC_MARK_AND_PUSH(clazz->_interfaces, mark_stack_ptr, mark_stack_limit, NULL); mark_stack_ptr = GC_MARK_AND_PUSH(clazz->_fields, mark_stack_ptr, mark_stack_limit, NULL); mark_stack_ptr = GC_MARK_AND_PUSH(clazz->_methods, mark_stack_ptr, mark_stack_limit, NULL); void** start = (void**) (((char*) clazz) + offsetof(Class, data)); void** end = (void**) (((char*) start) + clazz->classRefCount * sizeof(Object*)); mark_stack_ptr = markRegion(start, end, mark_stack_ptr, mark_stack_limit); } else if (CLASS_IS_ARRAY(obj->clazz)) { if (!CLASS_IS_PRIMITIVE(obj->clazz->componentType)) { // Array of objects. Mark all values in the array. ObjectArray* array = (ObjectArray*) obj; void** start = (void**) (((char*) array) + offsetof(ObjectArray, values)); void** end = (void**) (((char*) start) + sizeof(Object*) * array->length); mark_stack_ptr = markRegion(start, end, mark_stack_ptr, mark_stack_limit); } } else { // Object* - for each Class in the hierarchy of obj's Class we mark the first instanceRefCount*sizeof(Object*) bytes Class* clazz = obj->clazz; while (clazz != NULL) { void** start = (void**) (((char*) obj) + clazz->instanceDataOffset); void** end = (void**) (((char*) start) + clazz->instanceRefCount * sizeof(Object*)); if (clazz == java_lang_ref_Reference) { // Don't mark the referent field void** referent_start = (void**) (((char*) obj) + java_lang_ref_Reference_referent->offset); void** referent_end = (void**) (((char*) referent_start) + sizeof(Object*)); mark_stack_ptr = markRegion(start, referent_start, mark_stack_ptr, mark_stack_limit); mark_stack_ptr = markRegion(referent_end, end, mark_stack_ptr, mark_stack_limit); } else { mark_stack_ptr = markRegion(start, end, mark_stack_ptr, mark_stack_limit); } clazz = clazz->superclass; } } return mark_stack_ptr; }
Object* rvmCloneObject(Env* env, Object* obj) { if (CLASS_IS_ARRAY(obj->clazz)) { return (Object*) rvmCloneArray(env, (Array*) obj); } jint size = obj->clazz->instanceDataSize; Object* copy = rvmAllocateMemoryForObject(env, obj->clazz); if (!copy) return NULL; memcpy(copy, obj, size); copy->lock = 0; return copy; }
static ObjectArray* listClasses(Env* env, Class* instanceofClazz, ClassLoader* classLoader, void* hash) { if (instanceofClazz && (CLASS_IS_ARRAY(instanceofClazz) || CLASS_IS_PRIMITIVE(instanceofClazz))) { return NULL; } ClassInfoHeader** base = getClassInfosBase(hash); uint32_t count = getClassInfosCount(hash); uint32_t i = 0; jint matches = count; TypeInfo* instanceofTypeInfo = instanceofClazz ? instanceofClazz->typeInfo : NULL; if (instanceofTypeInfo) { matches = 0; for (i = 0; i < count; i++) { ClassInfoHeader* header = base[i]; if ((header->flags & CI_ERROR) == 0) { if ((!CLASS_IS_INTERFACE(instanceofClazz) && rvmIsClassTypeInfoAssignable(env, header->typeInfo, instanceofTypeInfo)) || (CLASS_IS_INTERFACE(instanceofClazz) && rvmIsInterfaceTypeInfoAssignable(env, header->typeInfo, instanceofTypeInfo))) { matches++; } } } } if (matches == 0) return NULL; ObjectArray* result = rvmNewObjectArray(env, matches, java_lang_Class, NULL, NULL); if (!result) return NULL; jint j = 0; for (i = 0; i < count; i++) { ClassInfoHeader* header = base[i]; if ((header->flags & CI_ERROR) == 0) { if (!instanceofTypeInfo || ((!CLASS_IS_INTERFACE(instanceofClazz) && rvmIsClassTypeInfoAssignable(env, header->typeInfo, instanceofTypeInfo)) || (CLASS_IS_INTERFACE(instanceofClazz) && rvmIsInterfaceTypeInfoAssignable(env, header->typeInfo, instanceofTypeInfo)))) { result->values[j++] = (Object*) (header->clazz ? header->clazz : createClass(env, header, classLoader)); if (rvmExceptionOccurred(env)) return NULL; } } } return result; }
static void heapDumpCallback(void* ptr, unsigned char kind, size_t sz, void* data) { if (kind == objectGCKind || kind == largeArrayGCKind || kind == atomicObjectGCKind) { Object* obj = (Object*) ptr; if (obj->clazz == java_lang_Class) { Class* clazz = (Class*) obj; fprintf(stderr, "%p (class %s of size %d bytes)\n", clazz, clazz->name, clazz->classDataSize); if (clazz->_data) { fprintf(stderr, "\t%p\n", clazz->_data); } void** start = (void**) (((char*) clazz) + offsetof(Class, data)); void** end = (void**) (((char*) start) + clazz->classRefCount * sizeof(Object*)); dumpRefs(start, end); } else if (CLASS_IS_ARRAY(obj->clazz)) { fprintf(stderr, "%p (array of type %s of length %d elements)\n", obj, obj->clazz->name, ((Array*) obj)->length); if (!CLASS_IS_PRIMITIVE(obj->clazz->componentType)) { ObjectArray* array = (ObjectArray*) obj; void** start = (void**) (((char*) array) + offsetof(ObjectArray, values)); void** end = (void**) (((char*) start) + sizeof(Object*) * array->length); dumpRefs(start, end); } } else { Class* clazz = obj->clazz; fprintf(stderr, "%p (object of type %s of size %d bytes)\n", obj, clazz->name, clazz->instanceDataSize); while (clazz != NULL) { void** start = (void**) (((char*) obj) + clazz->instanceDataOffset); void** end = (void**) (((char*) start) + clazz->instanceRefCount * sizeof(Object*)); if (clazz == java_lang_ref_Reference) { void** referent_start = (void**) (((char*) obj) + java_lang_ref_Reference_referent->offset); void** referent_end = (void**) (((char*) referent_start) + sizeof(Object*)); if (*referent_start) { fprintf(stderr, "\t%p (weak)\n", *referent_start); } dumpRefs(start, referent_start); dumpRefs(referent_end, end); } else { dumpRefs(start, end); } clazz = clazz->superclass; } } } }
static struct GC_ms_entry* markObject(GC_word* addr, struct GC_ms_entry* mark_stack_ptr, struct GC_ms_entry* mark_stack_limit, GC_word env) { Object* obj = (Object*) addr; if (obj == NULL || obj->clazz == NULL || obj->clazz->object.clazz != java_lang_Class) { // According to the comments in gc_mark.h the GC sometimes calls the mark_proc with unused objects. // Such objects have been cleared except for the first word which points to a free list link field. // A valid RovoVM Object must point to a Class and the Class of the Object's Class must be java.lang.Class. return mark_stack_ptr; } // This mark procedure should never be called for array instances. assert(!CLASS_IS_ARRAY(obj->clazz)); mark_stack_ptr = GC_MARK_AND_PUSH(obj->clazz, mark_stack_ptr, mark_stack_limit, NULL); if (obj->clazz == java_lang_Class) { // Class* Class* clazz = (Class*) obj; mark_stack_ptr = GC_MARK_AND_PUSH(clazz->_data, mark_stack_ptr, mark_stack_limit, NULL); mark_stack_ptr = GC_MARK_AND_PUSH((void*) clazz->name, mark_stack_ptr, mark_stack_limit, NULL); mark_stack_ptr = GC_MARK_AND_PUSH(clazz->typeInfo, mark_stack_ptr, mark_stack_limit, NULL); mark_stack_ptr = GC_MARK_AND_PUSH(clazz->vitable, mark_stack_ptr, mark_stack_limit, NULL); mark_stack_ptr = GC_MARK_AND_PUSH(clazz->itables, mark_stack_ptr, mark_stack_limit, NULL); mark_stack_ptr = GC_MARK_AND_PUSH(clazz->classLoader, mark_stack_ptr, mark_stack_limit, NULL); mark_stack_ptr = GC_MARK_AND_PUSH(clazz->superclass, mark_stack_ptr, mark_stack_limit, NULL); mark_stack_ptr = GC_MARK_AND_PUSH(clazz->componentType, mark_stack_ptr, mark_stack_limit, NULL); mark_stack_ptr = GC_MARK_AND_PUSH(clazz->_interfaces, mark_stack_ptr, mark_stack_limit, NULL); mark_stack_ptr = GC_MARK_AND_PUSH(clazz->_fields, mark_stack_ptr, mark_stack_limit, NULL); mark_stack_ptr = GC_MARK_AND_PUSH(clazz->_methods, mark_stack_ptr, mark_stack_limit, NULL); void** start = (void**) (((char*) clazz) + offsetof(Class, data)); void** end = (void**) (((char*) start) + clazz->classRefCount * sizeof(Object*)); mark_stack_ptr = markRegion(start, end, mark_stack_ptr, mark_stack_limit); } else { // Object* - for each Class in the hierarchy of obj's Class we mark the first instanceRefCount*sizeof(Object*) bytes Class* clazz = obj->clazz; while (clazz != NULL) { void** start = (void**) (((char*) obj) + clazz->instanceDataOffset); void** end = (void**) (((char*) start) + clazz->instanceRefCount * sizeof(Object*)); if (clazz == java_lang_ref_Reference) { // Don't mark the referent field void** referent_start = (void**) (((char*) obj) + java_lang_ref_Reference_referent->offset); void** referent_end = (void**) (((char*) referent_start) + sizeof(Object*)); mark_stack_ptr = markRegion(start, referent_start, mark_stack_ptr, mark_stack_limit); mark_stack_ptr = markRegion(referent_end, end, mark_stack_ptr, mark_stack_limit); } else { mark_stack_ptr = markRegion(start, end, mark_stack_ptr, mark_stack_limit); } // Some classes use longs and ints to store pointers to GC allocated memory. // For each such class we need to mark those fields here. // Note: java.lang.Thread, java.lang.reflect.Constructor, java.lang.reflect.Method, // java.lang.reflect.Field also contain such fields but we don't have // to mark those because the Thread, Method and Field C structures those // point to are also referenced by other roots (the threads list, Class structures) // that prevent GCing. if (clazz == java_lang_Throwable) { // The 'stackState' field in java.lang.Throwable is a long but contains // a pointer to an address on the GCed heap. void** field_start = (void**) (((char*) obj) + java_lang_Throwable_stackState->offset); void** field_end = (void**) (((char*) field_start) + sizeof(jlong)); mark_stack_ptr = markRegion(field_start, field_end, mark_stack_ptr, mark_stack_limit); } else if (clazz == org_robovm_rt_bro_Struct) { // The 'handle' field in org.robovm.rt.bro.Struct (actually in its // superclass NativeObject) is a long but contains a pointer. // Possibly to an address on the GCed heap. void** field_start = (void**) (((char*) obj) + org_robovm_rt_bro_Struct_handle->offset); void** field_end = (void**) (((char*) field_start) + sizeof(jlong)); mark_stack_ptr = markRegion(field_start, field_end, mark_stack_ptr, mark_stack_limit); } else if (clazz == java_nio_MemoryBlock) { // The 'address' field in java.nio.MemoryBlock is a long but contains a pointer. // Possibly to an address on the GCed heap. void** field_start = (void**) (((char*) obj) + java_nio_MemoryBlock_address->offset); void** field_end = (void**) (((char*) field_start) + sizeof(jlong)); mark_stack_ptr = markRegion(field_start, field_end, mark_stack_ptr, mark_stack_limit); } clazz = clazz->superclass; } } return mark_stack_ptr; }
void rvmInitialize(Env* env, Class* clazz) { obtainClassLock(); // TODO: Throw java.lang.NoClassDefFoundError if state == CLASS_ERROR? if (CLASS_IS_STATE_ERROR(clazz)) { // TODO: Add the class' binary name in the message rvmThrowNew(env, java_lang_NoClassDefFoundError, "Could not initialize class ??"); releaseClassLock(); return; } if (!CLASS_IS_STATE_INITIALIZED(clazz) && !CLASS_IS_STATE_INITIALIZING(clazz)) { jint oldState = clazz->flags & CLASS_STATE_MASK; clazz->flags = (clazz->flags & (~CLASS_STATE_MASK)) | CLASS_STATE_INITIALIZING; if (clazz->superclass) { rvmInitialize(env, clazz->superclass); if (rvmExceptionOccurred(env)) { clazz->flags = (clazz->flags & (~CLASS_STATE_MASK)) | oldState; releaseClassLock(); return; } } TRACEF("Initializing class %s", clazz->name); void* initializer = clazz->initializer; if (!initializer) { if (!CLASS_IS_ARRAY(clazz) && !CLASS_IS_PROXY(clazz) && !CLASS_IS_PRIMITIVE(clazz)) { env->vm->options->classInitialized(env, clazz); } clazz->flags = (clazz->flags & (~CLASS_STATE_MASK)) | CLASS_STATE_INITIALIZED; releaseClassLock(); return; } CallInfo* callInfo = call0AllocateCallInfo(env, initializer, 1, 0, 0, 0, 0); call0AddPtr(callInfo, env); void (*f)(CallInfo*) = (void (*)(CallInfo*)) _call0; rvmPushGatewayFrame(env); TrycatchContext tc = {0}; tc.sel = CATCH_ALL_SEL; if (!rvmTrycatchEnter(env, &tc)) { f(callInfo); } rvmTrycatchLeave(env); rvmPopGatewayFrame(env); Object* exception = rvmExceptionClear(env); if (exception) { clazz->flags = (clazz->flags & (~CLASS_STATE_MASK)) | CLASS_STATE_ERROR; if (!rvmIsInstanceOf(env, exception, java_lang_Error)) { // If exception isn't an instance of java.lang.Error // we must wrap it in a java.lang.ExceptionInInitializerError Method* constructor = rvmGetInstanceMethod(env, java_lang_ExceptionInInitializerError, "<init>", "(Ljava/lang/Throwable;)V"); if (!constructor) return; Object* wrappedException = rvmNewObject(env, java_lang_ExceptionInInitializerError, constructor, exception); if (!wrappedException) return; exception = wrappedException; } rvmThrow(env, exception); releaseClassLock(); return; } if (!CLASS_IS_ARRAY(clazz) && !CLASS_IS_PROXY(clazz) && !CLASS_IS_PRIMITIVE(clazz)) { env->vm->options->classInitialized(env, clazz); } clazz->flags = (clazz->flags & (~CLASS_STATE_MASK)) | CLASS_STATE_INITIALIZED; } releaseClassLock(); }