From 001000364dbfd7e0a430f0d56c6be101c82dc2b8 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 10 Aug 2009 07:56:16 -0600 Subject: [PATCH] add classloader parameter to functions which may directly or indirectly load classes; include methods inherited from interfaces (but not explicitly declared) in method tables and virtual tables of abstract classes --- classpath/java/lang/ClassLoader.java | 5 +- makefile | 2 + src/builtin.cpp | 35 +-- src/common.h | 6 + src/compile.cpp | 98 ++++---- src/gnu.cpp | 51 ++++- src/jnienv.cpp | 4 +- src/machine.cpp | 320 ++++++++++++++++++++------- src/machine.h | 39 ++-- src/process.h | 38 ++-- src/processor.h | 12 +- src/types.def | 5 +- 12 files changed, 429 insertions(+), 186 deletions(-) diff --git a/classpath/java/lang/ClassLoader.java b/classpath/java/lang/ClassLoader.java index 3a7012ac27..31006f21dc 100644 --- a/classpath/java/lang/ClassLoader.java +++ b/classpath/java/lang/ClassLoader.java @@ -33,7 +33,8 @@ public abstract class ClassLoader { return ClassLoader.class.getClassLoader(); } - private static native Class defineClass(byte[] b, int offset, int length); + private static native Class defineClass + (ClassLoader loader, byte[] b, int offset, int length); protected Class defineClass(String name, byte[] b, int offset, int length) { if (b == null) { @@ -44,7 +45,7 @@ public abstract class ClassLoader { throw new IndexOutOfBoundsException(); } - return defineClass(b, offset, length); + return defineClass(this, b, offset, length); } protected Class findClass(String name) throws ClassNotFoundException { diff --git a/makefile b/makefile index dc46e1c575..2896c66e48 100644 --- a/makefile +++ b/makefile @@ -371,6 +371,8 @@ gnu-overrides = \ java/lang/StringBuilder.class \ java/lang/StringBuilder\$$*.class \ java/lang/Thread.class \ + java/lang/Thread\$$*.class \ + java/lang/ThreadGroup.class \ java/lang/ThreadLocal.class \ java/lang/Throwable.class \ java/lang/ref/PhantomReference.class \ diff --git a/src/builtin.cpp b/src/builtin.cpp index 712dabce0f..c3d779b3de 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -11,17 +11,12 @@ #include "machine.h" #include "constants.h" #include "processor.h" +#include "util.h" using namespace vm; namespace { -inline void -replace(char a, char b, char* c) -{ - for (; *c; ++c) if (*c == a) *c = b; -} - int64_t search(Thread* t, object name, object (*op)(Thread*, object), bool replaceDots) @@ -177,15 +172,24 @@ extern "C" JNIEXPORT int64_t JNICALL Avian_java_lang_ClassLoader_defineClass (Thread* t, object, uintptr_t* arguments) { - object b = reinterpret_cast(arguments[0]); - int offset = arguments[1]; - int length = arguments[2]; + object loader = reinterpret_cast(arguments[0]); + PROTECT(t, loader); + + object b = reinterpret_cast(arguments[1]); + int offset = arguments[2]; + int length = arguments[3]; uint8_t* buffer = static_cast (t->m->heap->allocate(length)); memcpy(buffer, &byteArrayBody(t, b, offset), length); - object c = parseClass(t, buffer, length); + object c = parseClass(t, loader, buffer, length); t->m->heap->free(buffer, length); + + if (c) { + hashMapInsert(t, classLoaderMap(t, loader), className(t, c), c, + byteArrayHash); + } + return reinterpret_cast(c); } @@ -195,7 +199,7 @@ Avian_avian_SystemClassLoader_findLoadedClass { object name = reinterpret_cast(arguments[1]); - return search(t, name, findLoadedClass, true); + return search(t, name, findLoadedSystemClass, true); } extern "C" JNIEXPORT int64_t JNICALL @@ -204,7 +208,7 @@ Avian_avian_SystemClassLoader_findClass { object name = reinterpret_cast(arguments[1]); - return search(t, name, resolveClass, true); + return search(t, name, resolveSystemClass, true); } extern "C" JNIEXPORT int64_t JNICALL @@ -465,7 +469,8 @@ Avian_java_lang_reflect_Array_makeObjectArray object elementType = reinterpret_cast(arguments[0]); int length = arguments[1]; - return reinterpret_cast(makeObjectArray(t, elementType, length)); + return reinterpret_cast + (makeObjectArray(t, classLoader(t, elementType), elementType, length)); } extern "C" JNIEXPORT int64_t JNICALL @@ -767,8 +772,10 @@ Avian_java_lang_Throwable_resolveTrace PROTECT(t, trace); unsigned length = arrayLength(t, trace); + object elementType = arrayBody + (t, t->m->types, Machine::StackTraceElementType); object array = makeObjectArray - (t, arrayBody(t, t->m->types, Machine::StackTraceElementType), length); + (t, classLoader(t, elementType), elementType, length); PROTECT(t, array); object e = 0; diff --git a/src/common.h b/src/common.h index 10690c6046..1687cec28f 100644 --- a/src/common.h +++ b/src/common.h @@ -313,6 +313,12 @@ voidPointer(T function) return p; } +inline void +replace(char a, char b, char* c) +{ + for (; *c; ++c) if (*c == a) *c = b; +} + class Machine; class Thread; diff --git a/src/compile.cpp b/src/compile.cpp index add06d4845..219792036f 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -147,7 +147,7 @@ resolveTarget(MyThread* t, void* stack, object method) PROTECT(t, method); PROTECT(t, class_); - resolveClass(t, className(t, class_)); + resolveSystemClass(t, className(t, class_)); if (UNLIKELY(t->exception)) return 0; } @@ -164,7 +164,7 @@ resolveTarget(MyThread* t, object class_, unsigned index) if (classVmFlags(t, class_) & BootstrapFlag) { PROTECT(t, class_); - resolveClass(t, className(t, class_)); + resolveSystemClass(t, className(t, class_)); if (UNLIKELY(t->exception)) return 0; } @@ -2030,10 +2030,11 @@ longToFloat(int64_t a) } uint64_t -makeBlankObjectArray(MyThread* t, object class_, int32_t length) +makeBlankObjectArray(MyThread* t, object loader, object class_, int32_t length) { if (length >= 0) { - return reinterpret_cast(makeObjectArray(t, class_, length)); + return reinterpret_cast + (makeObjectArray(t, loader, class_, length)); } else { object message = makeString(t, "%d", length); t->exception = makeNegativeArraySizeException(t, message); @@ -2226,6 +2227,9 @@ throw_(MyThread* t, object o) } else { t->exception = makeNullPointerException(t); } + + printTrace(t, t->exception); + unwind(t); } @@ -2746,7 +2750,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case anewarray: { uint16_t index = codeReadInt16(t, code, ip); - object class_ = resolveClassInPool(t, codePool(t, code), index - 1); + object class_ = resolveClassInPool(t, context->method, index - 1); if (UNLIKELY(t->exception)) return; Compiler::Operand* length = frame->popInt(); @@ -2757,7 +2761,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, 0, frame->trace(0, 0), BytesPerWord, - 3, c->register_(t->arch->thread()), frame->append(class_), length)); + 4, c->register_(t->arch->thread()), + frame->append(classLoader(t, methodClass(t, context->method))), + frame->append(class_), length)); } break; case areturn: { @@ -2810,7 +2816,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case checkcast: { uint16_t index = codeReadInt16(t, code, ip); - object class_ = resolveClassInPool(t, codePool(t, code), index - 1); + object class_ = resolveClassInPool(t, context->method, index - 1); if (UNLIKELY(t->exception)) return; Compiler::Operand* instance = c->peek(1, 0); @@ -3085,7 +3091,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case getstatic: { uint16_t index = codeReadInt16(t, code, ip); - object field = resolveField(t, codePool(t, code), index - 1); + object field = resolveField(t, context->method, index - 1); if (UNLIKELY(t->exception)) return; Compiler::Operand* table; @@ -3452,7 +3458,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case instanceof: { uint16_t index = codeReadInt16(t, code, ip); - object class_ = resolveClassInPool(t, codePool(t, code), index - 1); + object class_ = resolveClassInPool(t, context->method, index - 1); if (UNLIKELY(t->exception)) return; frame->pushInt @@ -3467,7 +3473,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint16_t index = codeReadInt16(t, code, ip); ip += 2; - object target = resolveMethod(t, codePool(t, code), index - 1); + object target = resolveMethod(t, context->method, index - 1); if (UNLIKELY(t->exception)) return; assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); @@ -3502,7 +3508,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case invokespecial: { uint16_t index = codeReadInt16(t, code, ip); - object target = resolveMethod(t, codePool(t, code), index - 1); + object target = resolveMethod(t, context->method, index - 1); if (UNLIKELY(t->exception)) return; object class_ = methodClass(t, context->method); @@ -3520,7 +3526,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case invokestatic: { uint16_t index = codeReadInt16(t, code, ip); - object target = resolveMethod(t, codePool(t, code), index - 1); + object target = resolveMethod(t, context->method, index - 1); if (UNLIKELY(t->exception)) return; assert(t, methodFlags(t, target) & ACC_STATIC); @@ -3533,7 +3539,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case invokevirtual: { uint16_t index = codeReadInt16(t, code, ip); - object target = resolveMethod(t, codePool(t, code), index - 1); + object target = resolveMethod(t, context->method, index - 1); if (UNLIKELY(t->exception)) return; assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); @@ -3729,7 +3735,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (objectClass(t, v) == arrayBody(t, t->m->types, Machine::ByteArrayType)) { - object class_ = resolveClassInPool(t, pool, index - 1); + object class_ = resolveClassInPool(t, context->method, index - 1); if (UNLIKELY(t->exception)) return; frame->pushObject(frame->append(class_)); @@ -3934,7 +3940,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint16_t index = codeReadInt16(t, code, ip); uint8_t dimensions = codeBody(t, code, ip++); - object class_ = resolveClassInPool(t, codePool(t, code), index - 1); + object class_ = resolveClassInPool(t, context->method, index - 1); if (UNLIKELY(t->exception)) return; PROTECT(t, class_); @@ -3958,7 +3964,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case new_: { uint16_t index = codeReadInt16(t, code, ip); - object class_ = resolveClassInPool(t, codePool(t, code), index - 1); + object class_ = resolveClassInPool(t, context->method, index - 1); if (UNLIKELY(t->exception)) return; if (classVmFlags(t, class_) & (WeakReferenceFlag | HasFinalizerFlag)) { @@ -4008,7 +4014,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case putstatic: { uint16_t index = codeReadInt16(t, code, ip); - object field = resolveField(t, codePool(t, code), index - 1); + object field = resolveField(t, context->method, index - 1); if (UNLIKELY(t->exception)) return; object staticTable = 0; @@ -4310,12 +4316,13 @@ logCompile(MyThread* t, const void* code, unsigned size, const char* class_, } void -translateExceptionHandlerTable(MyThread* t, Compiler* c, object code, +translateExceptionHandlerTable(MyThread* t, Compiler* c, object method, intptr_t start) { - object oldTable = codeExceptionHandlerTable(t, code); + object oldTable = codeExceptionHandlerTable(t, methodCode(t, method)); + if (oldTable) { - PROTECT(t, code); + PROTECT(t, method); PROTECT(t, oldTable); unsigned length = exceptionHandlerTableLength(t, oldTable); @@ -4344,7 +4351,7 @@ translateExceptionHandlerTable(MyThread* t, Compiler* c, object code, object type; if (exceptionHandlerCatchType(oldHandler)) { type = resolveClassInPool - (t, codePool(t, code), exceptionHandlerCatchType(oldHandler) - 1); + (t, method, exceptionHandlerCatchType(oldHandler) - 1); if (UNLIKELY(t->exception)) return; } else { type = 0; @@ -4353,7 +4360,7 @@ translateExceptionHandlerTable(MyThread* t, Compiler* c, object code, set(t, newTable, ArrayBody + ((i + 1) * BytesPerWord), type); } - set(t, code, CodeExceptionHandlerTable, newTable); + set(t, methodCode(t, method), CodeExceptionHandlerTable, newTable); } } @@ -4942,8 +4949,8 @@ finish(MyThread* t, Allocator* allocator, Context* context) } } - translateExceptionHandlerTable(t, c, methodCode(t, context->method), - reinterpret_cast(start)); + translateExceptionHandlerTable + (t, c, context->method, reinterpret_cast(start)); if (UNLIKELY(t->exception)) return 0; translateLineNumberTable(t, c, methodCode(t, context->method), @@ -5020,15 +5027,15 @@ finish(MyThread* t, Allocator* allocator, Context* context) (&byteArrayBody(t, methodSpec(t, context->method), 0))); // for debugging: - if (false and + if (//false and strcmp (reinterpret_cast (&byteArrayBody(t, className(t, methodClass(t, context->method)), 0)), - "java/lang/Throwable") == 0 and + "org/eclipse/osgi/framework/internal/core/Constants") == 0 and strcmp (reinterpret_cast (&byteArrayBody(t, methodName(t, context->method), 0)), - "printStackTrace") == 0) + "getInternalSymbolicName") == 0) { trap(); } @@ -5825,6 +5832,8 @@ returnSpec(MyThread* t, object method) object returnClass(MyThread* t, object method) { + PROTECT(t, method); + int8_t* spec = returnSpec(t, method); unsigned length = strlen(reinterpret_cast(spec)); object name; @@ -5837,7 +5846,8 @@ returnClass(MyThread* t, object method) name = makeByteArray(t, length - 1); memcpy(&byteArrayBody(t, name, 0), spec + 1, length - 2); } - return resolveClass(t, name); + + return resolveClass(t, classLoader(t, methodClass(t, method)), name); } bool @@ -5959,7 +5969,7 @@ callContinuation(MyThread* t, object continuation, object result, PROTECT(t, nextContinuation); object method = resolveMethod - (t, "avian/Continuations", "rewind", + (t, t->m->loader, "avian/Continuations", "rewind", "(Ljava/lang/Runnable;Lavian/Callback;Ljava/lang/Object;" "Ljava/lang/Throwable;)V"); @@ -6030,7 +6040,7 @@ callWithCurrentContinuation(MyThread* t, object receiver) if (receiveMethod(t) == 0) { object m = resolveMethod - (t, "avian/CallbackReceiver", "receive", + (t, t->m->loader, "avian/CallbackReceiver", "receive", "(Lavian/Callback;)Ljava/lang/Object;"); if (m) { @@ -6040,7 +6050,7 @@ callWithCurrentContinuation(MyThread* t, object receiver) (t, t->m->types, Machine::ContinuationType); if (classVmFlags(t, continuationClass) & BootstrapFlag) { - resolveClass(t, vm::className(t, continuationClass)); + resolveSystemClass(t, vm::className(t, continuationClass)); } } } @@ -6078,7 +6088,7 @@ dynamicWind(MyThread* t, object before, object thunk, object after) if (windMethod(t) == 0) { object method = resolveMethod - (t, "avian/Continuations", "wind", + (t, t->m->loader, "avian/Continuations", "wind", "(Ljava/lang/Runnable;Ljava/util/concurrent/Callable;" "Ljava/lang/Runnable;)Lavian/Continuations$UnwindResult;"); @@ -6570,6 +6580,16 @@ class MyProcessor: public Processor { PROTECT(t, method); + if (false) { + compile(static_cast(t), + ::codeAllocator(static_cast(t)), 0, + resolveMethod(t, t->m->loader, + "java/beans/PropertyChangeSupport", + "firePropertyChange", + "(Ljava/beans/PropertyChangeEvent;)V")); + trap(); + } + compile(static_cast(t), ::codeAllocator(static_cast(t)), 0, method); @@ -6581,8 +6601,9 @@ class MyProcessor: public Processor { } virtual object - invokeList(Thread* t, const char* className, const char* methodName, - const char* methodSpec, object this_, va_list arguments) + invokeList(Thread* t, object loader, const char* className, + const char* methodName, const char* methodSpec, + object this_, va_list arguments) { if (UNLIKELY(t->exception)) return 0; @@ -6595,7 +6616,8 @@ class MyProcessor: public Processor { ArgumentList list (t, array, size, objectMask, this_, methodSpec, false, arguments); - object method = resolveMethod(t, className, methodName, methodSpec); + object method = resolveMethod + (t, loader, className, methodName, methodSpec); if (LIKELY(t->exception == 0)) { assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0)); @@ -7064,7 +7086,7 @@ fixupCode(Thread* t, uintptr_t* map, unsigned size, uint8_t* code, void fixupMethods(Thread* t, BootImage* image, uint8_t* code) { - for (HashMapIterator it(t, t->m->classMap); it.hasMore();) { + for (HashMapIterator it(t, classLoaderMap(t, t->m->loader)); it.hasMore();) { object c = tripleSecond(t, it.next()); if (classMethodTable(t, c)) { @@ -7194,7 +7216,9 @@ boot(MyThread* t, BootImage* image) syncInstructionCache(code, image->codeSize); - t->m->classMap = makeClassMap(t, classTable, image->classCount, heap); + object classMap = makeClassMap(t, classTable, image->classCount, heap); + set(t, t->m->loader, ClassLoaderMap, classMap); + t->m->stringMap = makeStringMap(t, stringTable, image->stringCount, heap); p->callTableSize = image->callCount; diff --git a/src/gnu.cpp b/src/gnu.cpp index 15aec5fd88..c14d050535 100644 --- a/src/gnu.cpp +++ b/src/gnu.cpp @@ -11,6 +11,7 @@ #include "machine.h" #include "constants.h" #include "processor.h" +#include "util.h" using namespace vm; @@ -48,7 +49,7 @@ NewDirectByteBuffer(Thread* t, void* address, jlong capacity) initSpec = "(I)V"; } - object pointerClass = resolveClass(t, pointerClassName); + object pointerClass = resolveClass(t, t->m->loader, pointerClassName); if (UNLIKELY(pointerClass == 0)) return 0; PROTECT(t, pointerClass); @@ -63,7 +64,7 @@ NewDirectByteBuffer(Thread* t, void* address, jlong capacity) if (UNLIKELY(t->exception)) return 0; object bufferClass = resolveClass - (t, "java/nio/DirectByteBufferImpl$ReadWrite"); + (t, t->m->loader, "java/nio/DirectByteBufferImpl$ReadWrite"); if (UNLIKELY(bufferClass == 0)) return 0; PROTECT(t, bufferClass); @@ -124,7 +125,7 @@ Avian_gnu_classpath_VMSystemProperties_preInit PROTECT(t, properties); object method = resolveMethod - (t, "java/util/Properties", "setProperty", + (t, t->m->loader, "java/util/Properties", "setProperty", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;"); if (UNLIKELY(t->exception)) { @@ -212,7 +213,7 @@ Avian_gnu_classpath_VMStackWalker_getClassContext if (skipCount == 0) { if (trace == 0) { trace = makeObjectArray - (t, arrayBody(t, t->m->types, Machine::ClassType), + (t, t->m->loader, arrayBody(t, t->m->types, Machine::ClassType), walker->count()); } @@ -240,7 +241,7 @@ Avian_gnu_classpath_VMStackWalker_getClassContext if (v.trace == 0) { v.trace = makeObjectArray - (t, arrayBody(t, t->m->types, Machine::ClassType), 0); + (t, t->m->loader, arrayBody(t, t->m->types, Machine::ClassType), 0); } return reinterpret_cast(v.trace); @@ -358,7 +359,14 @@ extern "C" JNIEXPORT int64_t JNICALL Avian_java_lang_VMClassLoader_defineClass (Thread* t, object, uintptr_t* arguments) { - uintptr_t args[] = { arguments[2], arguments[3], arguments[4] }; + uintptr_t args[] + = { arguments[0], arguments[2], arguments[3], arguments[4] }; + +// object name = reinterpret_cast(arguments[1]); +// char n[stringLength(t, name) + 1]; +// stringChars(t, name, n); +// fprintf(stderr, "define class %s in %p\n", n, +// reinterpret_cast(arguments[0])); return Avian_java_lang_ClassLoader_defineClass(t, 0, args); } @@ -409,18 +417,37 @@ Avian_java_lang_VMClassLoader_loadClass { uintptr_t args[] = { 0, arguments[0] }; +// object name = reinterpret_cast(arguments[0]); +// char n[stringLength(t, name) + 1]; +// stringChars(t, name, n); +// fprintf(stderr, "load bootstrap class %s in %p\n", n, t->m->loader); + return Avian_avian_SystemClassLoader_findClass(t, 0, args); } -extern "C" JNIEXPORT int64_t JNICALL -Avian_avian_SystemClassLoader_findLoadedClass -(Thread*, object, uintptr_t*); - extern "C" JNIEXPORT int64_t JNICALL Avian_java_lang_VMClassLoader_findLoadedClass (Thread* t, object, uintptr_t* arguments) { - uintptr_t args[] = { 0, arguments[1] }; + object loader = reinterpret_cast(arguments[0]); + + object map = classLoaderMap(t, loader); + if (map) { + PROTECT(t, loader); - return Avian_avian_SystemClassLoader_findLoadedClass(t, 0, args); + object name = reinterpret_cast(arguments[1]); + PROTECT(t, name); + + object n = makeByteArray(t, stringLength(t, name) + 1); + char* s = reinterpret_cast(&byteArrayBody(t, n, 0)); + stringChars(t, name, s); + + replace('.', '/', s); + + return reinterpret_cast + (hashMapFind + (t, classLoaderMap(t, loader), n, byteArrayHash, byteArrayEqual)); + } else { + return 0; + } } diff --git a/src/jnienv.cpp b/src/jnienv.cpp index ffd96025cc..8c4a96c639 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -223,7 +223,7 @@ FindClass(Thread* t, const char* name) object n = makeByteArray(t, strlen(name) + 1); replace('.', '/', name, &byteArrayBody(t, n, 0)); - return makeLocalReference(t, resolveClass(t, n)); + return makeLocalReference(t, resolveClass(t, t->m->loader, n)); } jint JNICALL @@ -1213,7 +1213,7 @@ NewObjectArray(Thread* t, jsize length, jclass class_, jobject init) { ENTER(t, Thread::ActiveState); - object a = makeObjectArray(t, *class_, length); + object a = makeObjectArray(t, classLoader(t, *class_), *class_, length); object value = (init ? *init : 0); for (jsize i = 0; i < length; ++i) { set(t, a, ArrayBody + (i * BytesPerWord), value); diff --git a/src/machine.cpp b/src/machine.cpp index 40420ee1cd..c8e84fe653 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -501,6 +501,8 @@ postCollect(Thread* t) void finalizeObject(Thread* t, object o) { + if (true) return; + if (t->state == Thread::ExitState) { // don't waste time running Java finalizers if we're exiting the // VM @@ -857,7 +859,7 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool) object name = singletonObject(t, pool, s.read2() - 1); PROTECT(t, name); - object interface = resolveClass(t, name); + object interface = resolveClass(t, classLoader(t, class_), name); if (UNLIKELY(t->exception)) return; PROTECT(t, interface); @@ -878,7 +880,8 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool) unsigned i = 0; for (HashMapIterator it(t, map); it.hasMore();) { - object interface = resolveClass(t, tripleFirst(t, it.next())); + object interface = resolveClass + (t, classLoader(t, class_), tripleFirst(t, it.next())); if (UNLIKELY(t->exception)) return; set(t, interfaceTable, ArrayBody + (i * BytesPerWord), interface); @@ -1164,6 +1167,68 @@ scanMethodSpec(Thread* t, const char* s, unsigned* parameterCount, *returnCode = fieldCode(t, *it.returnSpec()); } +object +addInterfaceMethods(Thread* t, object class_, object virtualMap, + unsigned* virtualCount, bool makeList) +{ + object itable = classInterfaceTable(t, class_); + if (itable) { + PROTECT(t, class_); + PROTECT(t, virtualMap); + PROTECT(t, itable); + + object list = 0; + PROTECT(t, list); + + object method = 0; + PROTECT(t, method); + + object vtable = 0; + PROTECT(t, vtable); + + unsigned stride = (classFlags(t, class_) & ACC_INTERFACE) ? 1 : 2; + for (unsigned i = 0; i < arrayLength(t, itable); i += stride) { + vtable = classVirtualTable(t, arrayBody(t, itable, i)); + if (vtable) { + for (unsigned j = 0; j < arrayLength(t, vtable); ++j) { + method = arrayBody(t, vtable, j); + object n = hashMapFindNode + (t, virtualMap, method, methodHash, methodEqual); + if (n == 0) { + method = makeMethod + (t, + methodVmFlags(t, method), + methodReturnCode(t, method), + methodParameterCount(t, method), + methodParameterFootprint(t, method), + methodFlags(t, method), + (*virtualCount)++, + 0, + methodName(t, method), + methodSpec(t, method), + class_, + 0, + 0); + + hashMapInsert(t, virtualMap, method, method, methodHash); + + if (makeList) { + if (list == 0) { + list = vm::makeList(t, 0, 0, 0); + } + listAppend(t, list, method); + } + } + } + } + } + + return list; + } + + return 0; +} + void parseMethodTable(Thread* t, Stream& s, object class_, object pool) { @@ -1180,38 +1245,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool) PROTECT(t, superVirtualTable); if (classFlags(t, class_) & ACC_INTERFACE) { - object itable = classInterfaceTable(t, class_); - if (itable) { - PROTECT(t, itable); - for (unsigned i = 0; i < arrayLength(t, itable); ++i) { - object vtable = classVirtualTable(t, arrayBody(t, itable, i)); - if (vtable) { - PROTECT(t, vtable); - for (unsigned j = 0; j < arrayLength(t, vtable); ++j) { - object method = arrayBody(t, vtable, j); - object n = hashMapFindNode - (t, virtualMap, method, methodHash, methodEqual); - if (n == 0) { - method = makeMethod - (t, - methodVmFlags(t, method), - methodReturnCode(t, method), - methodParameterCount(t, method), - methodParameterFootprint(t, method), - methodFlags(t, method), - virtualCount++, - 0, - methodName(t, method), - methodSpec(t, method), - class_, - 0, - 0); - hashMapInsert(t, virtualMap, method, method, methodHash); - } - } - } - } - } + addInterfaceMethods(t, class_, virtualMap, &virtualCount, false); } else { if (classSuper(t, class_)) { superVirtualTable = classVirtualTable(t, classSuper(t, class_)); @@ -1325,6 +1359,15 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool) set(t, class_, ClassMethodTable, methodTable); } + object abstractVirtuals; + if (classFlags(t, class_) & ACC_INTERFACE) { + abstractVirtuals = 0; + } else { + abstractVirtuals = addInterfaceMethods + (t, class_, virtualMap, &virtualCount, true); + } + PROTECT(t, abstractVirtuals); + bool populateInterfaceVtables = false; if (declaredVirtualCount == 0 @@ -1367,6 +1410,8 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool) ++ i; } } else { + populateInterfaceVtables = true; + if (superVirtualTable) { for (; i < arrayLength(t, superVirtualTable); ++i) { object method = arrayBody(t, superVirtualTable, i); @@ -1380,15 +1425,40 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool) set(t, vtable, ArrayBody + (i * BytesPerWord), pairFirst(t, p)); ++ i; } + + if (abstractVirtuals) { + PROTECT(t, abstractVirtuals); + + unsigned oldLength = arrayLength(t, classMethodTable(t, class_)); + object newMethodTable = makeArray + (t, oldLength + listSize(t, abstractVirtuals)); + + memcpy(&arrayBody(t, newMethodTable, 0), + &arrayBody(t, classMethodTable(t, class_), 0), + oldLength * sizeof(object)); + + mark(t, newMethodTable, ArrayBody, oldLength); + + unsigned mti = oldLength; + for (object p = listFront(t, abstractVirtuals); + p; p = pairSecond(t, p)) + { + set(t, newMethodTable, + ArrayBody + ((mti++) * BytesPerWord), pairFirst(t, p)); + + set(t, vtable, + ArrayBody + ((i++) * BytesPerWord), pairFirst(t, p)); + } + + assert(t, arrayLength(t, newMethodTable) == mti); + + set(t, class_, ClassMethodTable, newMethodTable); + } } assert(t, arrayLength(t, vtable) == i); set(t, class_, ClassVirtualTable, vtable); - - if ((classFlags(t, class_) & ACC_INTERFACE) == 0) { - populateInterfaceVtables = true; - } } if (populateInterfaceVtables) { @@ -1406,9 +1476,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool) object method = arrayBody(t, ivtable, j); method = hashMapFind (t, virtualMap, method, methodHash, methodEqual); - - // note that method may be null in the case of an abstract - // class + assert(t, method); set(t, vtable, ArrayBody + (j * BytesPerWord), method); } @@ -1480,7 +1548,7 @@ updateBootstrapClass(Thread* t, object bootstrapClass, object class_) } object -makeArrayClass(Thread* t, unsigned dimensions, object spec, +makeArrayClass(Thread* t, object loader, unsigned dimensions, object spec, object elementClass) { // todo: arrays should implement Cloneable and Serializable @@ -1502,7 +1570,7 @@ makeArrayClass(Thread* t, unsigned dimensions, object spec, 0, 0, elementClass, - t->m->loader, + loader, arrayLength(t, vtable)); t->m->processor->initVtable(t, c); @@ -1511,7 +1579,7 @@ makeArrayClass(Thread* t, unsigned dimensions, object spec, } object -makeArrayClass(Thread* t, object spec) +makeArrayClass(Thread* t, object loader, object spec) { PROTECT(t, spec); @@ -1551,11 +1619,28 @@ makeArrayClass(Thread* t, object spec) (t, t->m->bootstrapClassMap, elementSpec, byteArrayHash, byteArrayEqual); if (elementClass == 0) { - elementClass = resolveClass(t, elementSpec); + elementClass = resolveClass(t, loader, elementSpec); if (UNLIKELY(t->exception)) return 0; } - return makeArrayClass(t, dimensions, spec, elementClass); + return makeArrayClass(t, loader, dimensions, spec, elementClass); +} + +object +resolveArrayClass(Thread* t, object loader, object spec) +{ + object c = hashMapFind + (t, t->m->bootstrapClassMap, spec, byteArrayHash, byteArrayEqual); + + if (c) { + set(t, c, ClassVirtualTable, + classVirtualTable + (t, arrayBody(t, t->m->types, Machine::JobjectType))); + + return c; + } else { + return makeArrayClass(t, loader, spec); + } } void @@ -1714,9 +1799,10 @@ boot(Thread* t) classVmFlags(t, arrayBody(t, m->types, Machine::JvoidType)) |= PrimitiveFlag; - m->bootstrapClassMap = makeHashMap(t, 0, 0); + object classMap = makeHashMap(t, 0, 0); + set(t, t->m->loader, ClassLoaderMap, classMap); - m->classMap = makeHashMap(t, 0, 0); + m->bootstrapClassMap = makeHashMap(t, 0, 0); m->stringMap = makeWeakHashMap(t, 0, 0); @@ -1846,7 +1932,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder, referenceLock(0), libraries(0), loader(0), - classMap(0), + loadClassMethod(0), bootstrapClassMap(0), monitorMap(0), stringMap(0), @@ -1980,6 +2066,8 @@ Thread::init() m->localThread->set(this); } else { + assert(this, javaThread); + peer = parent->child; parent->child = this; } @@ -1990,9 +2078,11 @@ Thread::init() const unsigned NewState = 0; const unsigned NormalPriority = 5; + object group = makeThreadGroup(this, 0, 0); + this->javaThread = makeThread (this, reinterpret_cast(this), 0, 0, NewState, NormalPriority, - 0, 0, 0, m->loader, 0, 0, 0); + 0, 0, 0, m->loader, 0, 0, group); } } @@ -2378,7 +2468,7 @@ isAssignableFrom(Thread* t, object a, object b) if (classFlags(t, a) & ACC_INTERFACE) { if (classVmFlags(t, b) & BootstrapFlag) { - resolveClass(t, className(t, b)); + resolveSystemClass(t, className(t, b)); if (UNLIKELY(t->exception)) { t->exception = 0; return false; @@ -2517,17 +2607,20 @@ primitiveSize(Thread* t, unsigned code) } object -findLoadedClass(Thread* t, object spec) +findLoadedSystemClass(Thread* t, object spec) { PROTECT(t, spec); ACQUIRE(t, t->m->classLock); - return hashMapFind(t, t->m->classMap, spec, byteArrayHash, byteArrayEqual); + return hashMapFind(t, classLoaderMap(t, t->m->loader), spec, byteArrayHash, + byteArrayEqual); } object -parseClass(Thread* t, const uint8_t* data, unsigned size) +parseClass(Thread* t, object loader, const uint8_t* data, unsigned size) { + PROTECT(t, loader); + class Client : public Stream::Client { public: Client(Thread* t): t(t) { } @@ -2567,13 +2660,13 @@ parseClass(Thread* t, const uint8_t* data, unsigned size) 0, // fields 0, // methods 0, // static table - t->m->loader, + loader, 0);// vtable length PROTECT(t, class_); unsigned super = s.read2(); if (super) { - object sc = resolveClass(t, singletonObject(t, pool, super - 1)); + object sc = resolveClass(t, loader, singletonObject(t, pool, super - 1)); if (UNLIKELY(t->exception)) return 0; set(t, class_, ClassSuper, sc); @@ -2623,26 +2716,18 @@ parseClass(Thread* t, const uint8_t* data, unsigned size) } object -resolveClass(Thread* t, object spec) +resolveSystemClass(Thread* t, object spec) { PROTECT(t, spec); + ACQUIRE(t, t->m->classLock); object class_ = hashMapFind - (t, t->m->classMap, spec, byteArrayHash, byteArrayEqual); + (t, classLoaderMap(t, t->m->loader), spec, byteArrayHash, byteArrayEqual); if (class_ == 0) { if (byteArrayBody(t, spec, 0) == '[') { - class_ = hashMapFind - (t, t->m->bootstrapClassMap, spec, byteArrayHash, byteArrayEqual); - - if (class_) { - set(t, class_, ClassVirtualTable, - classVirtualTable - (t, arrayBody(t, t->m->types, Machine::JobjectType))); - } else { - class_ = makeArrayClass(t, spec); - } + class_ = resolveArrayClass(t, t->m->loader, spec); } else { char file[byteArrayLength(t, spec) + 6]; memcpy(file, &byteArrayBody(t, spec, 0), byteArrayLength(t, spec) - 1); @@ -2656,7 +2741,8 @@ resolveClass(Thread* t, object spec) } // parse class file - class_ = parseClass(t, region->start(), region->length()); + class_ = parseClass + (t, t->m->loader, region->start(), region->length()); region->dispose(); if (LIKELY(t->exception == 0)) { @@ -2667,11 +2753,12 @@ resolveClass(Thread* t, object spec) } object bootstrapClass = hashMapFind - (t, t->m->bootstrapClassMap, spec, byteArrayHash, byteArrayEqual); + (t, t->m->bootstrapClassMap, spec, byteArrayHash, + byteArrayEqual); if (bootstrapClass) { PROTECT(t, bootstrapClass); - + updateBootstrapClass(t, bootstrapClass, class_); class_ = bootstrapClass; } @@ -2682,7 +2769,8 @@ resolveClass(Thread* t, object spec) if (class_) { PROTECT(t, class_); - hashMapInsert(t, t->m->classMap, spec, class_, byteArrayHash); + hashMapInsert(t, classLoaderMap(t, t->m->loader), spec, class_, + byteArrayHash); } else if (t->exception == 0) { object message = makeString(t, "%s", &byteArrayBody(t, spec, 0)); t->exception = makeClassNotFoundException(t, message); @@ -2692,6 +2780,76 @@ resolveClass(Thread* t, object spec) return class_; } +object +resolveClass(Thread* t, object loader, object spec) +{ + if (loader == t->m->loader) { + return resolveSystemClass(t, spec); + } else { + PROTECT(t, loader); + PROTECT(t, spec); + + ACQUIRE(t, t->m->classLock); + + if (classLoaderMap(t, loader) == 0) { + object map = makeHashMap(t, 0, 0); + set(t, loader, ClassLoaderMap, map); + } + + object class_ = hashMapFind + (t, classLoaderMap(t, loader), spec, byteArrayHash, byteArrayEqual); + + if (class_ == 0) { + if (byteArrayBody(t, spec, 0) == '[') { + class_ = resolveArrayClass(t, loader, spec); + } else { + if (t->m->loadClassMethod == 0) { + object m = resolveMethod + (t, t->m->loader, "java/lang/ClassLoader", "loadClass", + "(Ljava/lang/String;)Ljava/lang/Class;"); + + if (m) { + t->m->loadClassMethod = m; + + object classLoaderClass = arrayBody + (t, t->m->types, Machine::ClassLoaderType); + + if (classVmFlags(t, classLoaderClass) & BootstrapFlag) { + resolveSystemClass(t, vm::className(t, classLoaderClass)); + } + } + } + + if (LIKELY(t->exception == 0)) { + object method = findMethod + (t, t->m->loadClassMethod, objectClass(t, loader)); + + if (LIKELY(t->exception == 0)) { + PROTECT(t, method); + + object specString = makeString + (t, "%s", &byteArrayBody(t, spec, 0)); + + class_ = t->m->processor->invoke(t, method, loader, specString); + } + } + } + } + + if (class_) { + PROTECT(t, class_); + + hashMapInsert(t, classLoaderMap(t, loader), spec, class_, + byteArrayHash); + } else if (t->exception == 0) { + object message = makeString(t, "%s", &byteArrayBody(t, spec, 0)); + t->exception = makeClassNotFoundException(t, message); + } + + return class_; + } +} + object resolveMethod(Thread* t, object class_, const char* methodName, const char* methodSpec) @@ -2748,8 +2906,9 @@ resolveField(Thread* t, object class_, const char* fieldName, } object -resolveObjectArrayClass(Thread* t, object elementSpec) +resolveObjectArrayClass(Thread* t, object loader, object elementSpec) { + PROTECT(t, loader); PROTECT(t, elementSpec); object spec; @@ -2770,7 +2929,7 @@ resolveObjectArrayClass(Thread* t, object elementSpec) byteArrayBody(t, spec, byteArrayLength(t, elementSpec) + 2) = 0; } - return resolveClass(t, spec); + return resolveClass(t, loader, spec); } bool @@ -2860,9 +3019,10 @@ initClass(Thread* t, object c) } object -makeObjectArray(Thread* t, object elementClass, unsigned count) +makeObjectArray(Thread* t, object loader, object elementClass, unsigned count) { - object arrayClass = resolveObjectArrayClass(t, className(t, elementClass)); + object arrayClass = resolveObjectArrayClass + (t, loader, className(t, elementClass)); PROTECT(t, arrayClass); object array = makeArray(t, count); @@ -2926,10 +3086,6 @@ findInHierarchy(Thread* t, object class_, object name, object spec, for (; o == 0 and class_; class_ = classSuper(t, class_)) { o = find(t, class_, name, spec); } - - if (o == 0 and find == findMethodInClass) { - o = findInInterfaces(t, originalClass, name, spec, find); - } } if (o == 0) { @@ -3153,7 +3309,7 @@ void visitRoots(Machine* m, Heap::Visitor* v) { v->visit(&(m->loader)); - v->visit(&(m->classMap)); + v->visit(&(m->loadClassMethod)); v->visit(&(m->bootstrapClassMap)); v->visit(&(m->monitorMap)); v->visit(&(m->stringMap)); @@ -3275,7 +3431,7 @@ void runJavaThread(Thread* t) { object method = resolveMethod - (t, "java/lang/Thread", "run", "(Ljava/lang/Thread;)V"); + (t, t->m->loader, "java/lang/Thread", "run", "(Ljava/lang/Thread;)V"); if (t->exception == 0) { t->m->processor->invoke(t, method, 0, t->javaThread); diff --git a/src/machine.h b/src/machine.h index ab3b038c55..a5e686238c 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1188,7 +1188,7 @@ class Machine { System::Monitor* referenceLock; System::Library* libraries; object loader; - object classMap; + object loadClassMethod; object bootstrapClassMap; object monitorMap; object stringMap; @@ -2070,7 +2070,7 @@ fieldSize(Thread* t, object field) } object -findLoadedClass(Thread* t, object spec); +findLoadedSystemClass(Thread* t, object spec); inline bool emptyMethod(Thread* t, object method) @@ -2081,15 +2081,26 @@ emptyMethod(Thread* t, object method) } object -parseClass(Thread* t, const uint8_t* data, unsigned length); +parseClass(Thread* t, object loader, const uint8_t* data, unsigned length); object -resolveClass(Thread* t, object name); +resolveClass(Thread* t, object loader, object name); inline object -resolveClass(Thread* t, const char* name) +resolveClass(Thread* t, object loader, const char* name) { - return resolveClass(t, makeByteArray(t, "%s", name)); + PROTECT(t, loader); + object n = makeByteArray(t, "%s", name); + return resolveClass(t, loader, n); +} + +object +resolveSystemClass(Thread* t, object name); + +inline object +resolveSystemClass(Thread* t, const char* name) +{ + return resolveSystemClass(t, makeByteArray(t, "%s", name)); } object @@ -2097,10 +2108,10 @@ resolveMethod(Thread* t, object class_, const char* methodName, const char* methodSpec); inline object -resolveMethod(Thread* t, const char* className, const char* methodName, - const char* methodSpec) +resolveMethod(Thread* t, object loader, const char* className, + const char* methodName, const char* methodSpec) { - object class_ = resolveClass(t, className); + object class_ = resolveClass(t, loader, className); if (LIKELY(t->exception == 0)) { return resolveMethod(t, class_, methodName, methodSpec); } else { @@ -2113,10 +2124,10 @@ resolveField(Thread* t, object class_, const char* fieldName, const char* fieldSpec); inline object -resolveField(Thread* t, const char* className, const char* fieldName, - const char* fieldSpec) +resolveField(Thread* t, object loader, const char* className, + const char* fieldName, const char* fieldSpec) { - object class_ = resolveClass(t, className); + object class_ = resolveClass(t, loader, className); if (LIKELY(t->exception == 0)) { return resolveField(t, class_, fieldName, fieldSpec); } else { @@ -2125,7 +2136,7 @@ resolveField(Thread* t, const char* className, const char* fieldName, } object -resolveObjectArrayClass(Thread* t, object elementSpec); +resolveObjectArrayClass(Thread* t, object loader, object elementSpec); bool classNeedsInit(Thread* t, object c); @@ -2140,7 +2151,7 @@ void initClass(Thread* t, object c); object -makeObjectArray(Thread* t, object elementClass, unsigned count); +makeObjectArray(Thread* t, object loader, object elementClass, unsigned count); object findInTable(Thread* t, object table, object name, object spec, diff --git a/src/process.h b/src/process.h index ad58e22c67..bc7b987ad8 100644 --- a/src/process.h +++ b/src/process.h @@ -37,13 +37,14 @@ codeReadInt32(Thread* t, object code, unsigned& ip) } inline object -resolveClassInObject(Thread* t, object container, unsigned classOffset) +resolveClassInObject(Thread* t, object loader, object container, + unsigned classOffset) { object o = cast(container, classOffset); if (objectClass(t, o) == arrayBody(t, t->m->types, Machine::ByteArrayType)) { PROTECT(t, container); - o = resolveClass(t, o); + o = resolveClass(t, loader, o); if (UNLIKELY(t->exception)) return 0; set(t, container, classOffset, o); @@ -52,34 +53,36 @@ resolveClassInObject(Thread* t, object container, unsigned classOffset) } inline object -resolveClassInPool(Thread* t, object pool, unsigned index) +resolveClassInPool(Thread* t, object method, unsigned index) { - object o = singletonObject(t, pool, index); + object o = singletonObject(t, codePool(t, methodCode(t, method)), index); if (objectClass(t, o) == arrayBody(t, t->m->types, Machine::ByteArrayType)) { - PROTECT(t, pool); + PROTECT(t, method); - o = resolveClass(t, o); + o = resolveClass(t, classLoader(t, methodClass(t, method)), o); if (UNLIKELY(t->exception)) return 0; - set(t, pool, SingletonBody + (index * BytesPerWord), o); + set(t, codePool(t, methodCode(t, method)), + SingletonBody + (index * BytesPerWord), o); } return o; } inline object -resolve(Thread* t, object pool, unsigned index, +resolve(Thread* t, object method, unsigned index, object (*find)(vm::Thread*, object, object, object), object (*makeError)(vm::Thread*, object)) { - object o = singletonObject(t, pool, index); + object o = singletonObject(t, codePool(t, methodCode(t, method)), index); if (objectClass(t, o) == arrayBody(t, t->m->types, Machine::ReferenceType)) { - PROTECT(t, pool); + PROTECT(t, method); object reference = o; PROTECT(t, reference); - object class_ = resolveClassInObject(t, o, ReferenceClass); + object class_ = resolveClassInObject + (t, classLoader(t, methodClass(t, method)), o, ReferenceClass); if (UNLIKELY(t->exception)) return 0; o = findInHierarchy @@ -87,22 +90,23 @@ resolve(Thread* t, object pool, unsigned index, find, makeError); if (UNLIKELY(t->exception)) return 0; - set(t, pool, SingletonBody + (index * BytesPerWord), o); + set(t, codePool(t, methodCode(t, method)), + SingletonBody + (index * BytesPerWord), o); } return o; } inline object -resolveField(Thread* t, object pool, unsigned index) +resolveField(Thread* t, object method, unsigned index) { - return resolve(t, pool, index, findFieldInClass, makeNoSuchFieldError); + return resolve(t, method, index, findFieldInClass, makeNoSuchFieldError); } inline object -resolveMethod(Thread* t, object pool, unsigned index) +resolveMethod(Thread* t, object method, unsigned index) { - return resolve(t, pool, index, findMethodInClass, makeNoSuchMethodError); + return resolve(t, method, index, findMethodInClass, makeNoSuchMethodError); } inline bool @@ -162,7 +166,7 @@ populateMultiArray(Thread* t, object array, int32_t* counts, &byteArrayBody(t, spec, 1), byteArrayLength(t, spec) - 1); - object class_ = resolveClass(t, elementSpec); + object class_ = resolveSystemClass(t, elementSpec); PROTECT(t, class_); for (int32_t i = 0; i < counts[index]; ++i) { diff --git a/src/processor.h b/src/processor.h index 0f2316f6c1..f7de71b425 100644 --- a/src/processor.h +++ b/src/processor.h @@ -101,8 +101,9 @@ class Processor { va_list arguments) = 0; virtual object - invokeList(Thread* t, const char* className, const char* methodName, - const char* methodSpec, object this_, va_list arguments) = 0; + invokeList(Thread* t, object loader, const char* className, + const char* methodName, const char* methodSpec, + object this_, va_list arguments) = 0; virtual void dispose(Thread* t) = 0; @@ -160,13 +161,14 @@ class Processor { } object - invoke(Thread* t, const char* className, const char* methodName, - const char* methodSpec, object this_, ...) + invoke(Thread* t, object loader, const char* className, + const char* methodName, const char* methodSpec, object this_, ...) { va_list a; va_start(a, this_); - object r = invokeList(t, className, methodName, methodSpec, this_, a); + object r = invokeList + (t, loader, className, methodName, methodSpec, this_, a); va_end(a); diff --git a/src/types.def b/src/types.def index b099fc3397..5afa48a8e8 100644 --- a/src/types.def +++ b/src/types.def @@ -6,7 +6,8 @@ (type singleton (array uintptr_t body)) -(type classLoader java/lang/ClassLoader) +(type classLoader java/lang/ClassLoader + (object map)) (type systemClassLoader avian/SystemClassLoader) @@ -128,6 +129,8 @@ (type thread java/lang/Thread) +(type threadGroup java/lang/ThreadGroup) + (type stackTraceElement java/lang/StackTraceElement) (type throwable java/lang/Throwable)