From 459f4d5194b9396fce2170d813da3d4fd0c937ef Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 26 Nov 2010 12:41:31 -0700 Subject: [PATCH] fix openjdk-src bootimage build The main change here is to use a lazily-populated vector to associate runtime data with classes instead of referencing them directly from the class which requires updating immutable references in the heap image. The other changes employ other strategies to avoid trying to update immutable references. --- classpath/avian/ClassAddendum.java | 6 +- classpath/avian/VMClass.java | 3 +- classpath/avian/VMMethod.java | 1 + classpath/java/lang/Class.java | 4 - makefile | 16 ++- src/bootimage.cpp | 214 +++++++++++++++++++++++------ src/classpath-avian.cpp | 2 +- src/classpath-openjdk.cpp | 86 +++++++++--- src/compile.cpp | 76 +++++++--- src/interpret.cpp | 6 +- src/jnienv.cpp | 26 +++- src/machine.cpp | 45 ++---- src/machine.h | 72 ++++++++-- src/process.cpp | 14 +- src/thunks.cpp | 1 + src/types.def | 8 ++ 16 files changed, 426 insertions(+), 154 deletions(-) diff --git a/classpath/avian/ClassAddendum.java b/classpath/avian/ClassAddendum.java index ce13dbe35a..adc45bbeb3 100644 --- a/classpath/avian/ClassAddendum.java +++ b/classpath/avian/ClassAddendum.java @@ -10,8 +10,4 @@ package avian; -public class ClassAddendum extends Addendum { - public volatile Class class_; - public Object[] signers; - public volatile Class arrayClass; -} +public class ClassAddendum extends Addendum { } diff --git a/classpath/avian/VMClass.java b/classpath/avian/VMClass.java index da9a64f832..b32ff7f689 100644 --- a/classpath/avian/VMClass.java +++ b/classpath/avian/VMClass.java @@ -16,6 +16,7 @@ public class VMClass { public short fixedSize; public byte arrayElementSize; public byte arrayDimensions; + public int runtimeDataIndex; public int[] objectMask; public byte[] name; public byte[] sourceFile; @@ -24,7 +25,7 @@ public class VMClass { public VMMethod[] virtualTable; public VMField[] fieldTable; public VMMethod[] methodTable; - public volatile avian.ClassAddendum addendum; + public avian.ClassAddendum addendum; public Object staticTable; public ClassLoader loader; } diff --git a/classpath/avian/VMMethod.java b/classpath/avian/VMMethod.java index 5a6754c034..e68d725242 100644 --- a/classpath/avian/VMMethod.java +++ b/classpath/avian/VMMethod.java @@ -18,6 +18,7 @@ public class VMMethod { public short flags; public short offset; public int nativeID; + public int runtimeDataIndex; public byte[] name; public byte[] spec; public MethodAddendum addendum; diff --git a/classpath/java/lang/Class.java b/classpath/java/lang/Class.java index 15e4053175..1a6ea4a382 100644 --- a/classpath/java/lang/Class.java +++ b/classpath/java/lang/Class.java @@ -572,10 +572,6 @@ public final class Class implements Type, AnnotatedElement { return (T) o; } - public Object[] getSigners() { - return vmClass.addendum.signers; - } - public Package getPackage() { if ((vmClass.vmFlags & PrimitiveFlag) != 0 || isArray()) { return null; diff --git a/makefile b/makefile index 9d1c1c63cc..c7394d2140 100644 --- a/makefile +++ b/makefile @@ -72,13 +72,13 @@ ifeq ($(build-platform),darwin) library-path-variable = DYLD_LIBRARY_PATH endif -ifdef openjdk +ifneq ($(openjdk),) openjdk-arch = $(arch) ifeq ($(arch),x86_64) openjdk-arch = amd64 endif - ifdef openjdk-src + ifneq ($(openjdk-src),) include openjdk-src.mk options := $(options)-openjdk-src classpath-objects = $(openjdk-objects) @@ -436,8 +436,7 @@ endif bootimage-generator-sources = $(src)/bootimage.cpp bootimage-generator-objects = \ $(call cpp-objects,$(bootimage-generator-sources),$(src),$(build)) -bootimage-generator = \ - $(build)/$(bootimage-platform)-$(build-arch)$(options)/bootimage-generator +bootimage-generator = $(build)/bootimage-generator bootimage-bin = $(build)/bootimage.bin bootimage-object = $(build)/bootimage-bin.o @@ -454,10 +453,11 @@ $(error "bootimage cross-builds not yet supported") endif vm-classpath-object = $(bootimage-object) - cflags += -DBOOT_IMAGE=\"bootimageBin\" + cflags += -DBOOT_IMAGE=\"bootimageBin\" -DAVIAN_CLASSPATH=\"\" else vm-classpath-object = $(classpath-object) - cflags += -DBOOT_CLASSPATH=\"[classpathJar]\" + cflags += -DBOOT_CLASSPATH=\"[classpathJar]\" \ + -DAVIAN_CLASSPATH=\"[classpathJar]\" endif driver-source = $(src)/main.cpp @@ -509,7 +509,7 @@ ifneq ($(classpath),avian) $(classpath-src)/avian/VMMethod.java \ $(classpath-src)/avian/resource/Handler.java - ifdef openjdk + ifneq ($(openjdk),) classpath-sources := $(classpath-sources) \ $(classpath-src)/avian/OpenJDK.java endif @@ -759,6 +759,8 @@ $(bootimage-generator): $(MAKE) mode=$(mode) \ arch=$(build-arch) \ platform=$(bootimage-platform) \ + openjdk=$(openjdk) \ + openjdk-src=$(openjdk-src) \ bootimage-generator= \ build-bootimage-generator=$(bootimage-generator) \ $(bootimage-generator) diff --git a/src/bootimage.cpp b/src/bootimage.cpp index bc9b847cd8..cda4abd2a0 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -23,6 +23,38 @@ using namespace vm; namespace { +const unsigned HeapCapacity = 768 * 1024 * 1024; + +// Notes on immutable references in the heap image: +// +// One of the advantages of a bootimage-based build is that reduces +// the overhead of major GCs at runtime since we can avoid scanning +// the pre-built heap image entirely. However, this only works if we +// can ensure that no part of the heap image (with an exception noted +// below) ever points to runtime-allocated objects. Therefore (most) +// references in the heap image are considered immutable, and any +// attempt to update them at runtime will cause the process to abort. +// +// However, some references in the heap image really must be updated +// at runtime: e.g. the static field table for each class. Therefore, +// we allocate these as "fixed" objects, subject to mark-and-sweep +// collection, instead of as "copyable" objects subject to copying +// collection. This strategy avoids the necessity of maintaining +// "dirty reference" bitsets at runtime for the entire heap image; +// each fixed object has its own bitset specific to that object. +// +// In addition to the "fixed" object solution, there are other +// strategies available to avoid attempts to update immutable +// references at runtime: +// +// * Table-based: use a lazily-updated array or vector to associate +// runtime data with heap image objects (see +// e.g. getClassRuntimeData in machine.cpp). +// +// * Update references at build time: for example, we set the names +// of primitive classes before generating the heap image so that we +// need not populate them lazily at runtime. + bool endsWith(const char* suffix, const char* s, unsigned length) { @@ -44,7 +76,11 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, DelayedPromise* addresses = 0; - for (Finder::Iterator it(t->m->finder); it.hasMore();) { + for (Finder::Iterator it + (static_cast + (systemClassLoaderFinder(t, root(t, Machine::BootLoader)))); + it.hasMore();) + { unsigned nameSize = 0; const char* name = it.next(&nameSize); @@ -53,7 +89,8 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, { // fprintf(stderr, "%.*s\n", nameSize - 6, name); object c = resolveSystemClass - (t, makeByteArray(t, "%.*s", nameSize - 6, name)); + (t, root(t, Machine::BootLoader), + makeByteArray(t, "%.*s", nameSize - 6, name), true); if (t->exception) return 0; @@ -62,21 +99,53 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, if (classMethodTable(t, c)) { for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) { object method = arrayBody(t, classMethodTable(t, c), i); - if ((methodCode(t, method) or (methodFlags(t, method) & ACC_NATIVE)) - and ((methodName == 0 + if (((methodName == 0 + or ::strcmp + (reinterpret_cast + (&byteArrayBody + (t, vm::methodName(t, method), 0)), methodName) == 0) + and (methodSpec == 0 or ::strcmp (reinterpret_cast (&byteArrayBody - (t, vm::methodName(t, method), 0)), methodName) == 0) - and (methodSpec == 0 - or ::strcmp - (reinterpret_cast - (&byteArrayBody - (t, vm::methodSpec(t, method), 0)), methodSpec) - == 0))) + (t, vm::methodSpec(t, method), 0)), methodSpec) + == 0))) { - t->m->processor->compileMethod - (t, zone, &constants, &calls, &addresses, method); + if (methodCode(t, method) + or (methodFlags(t, method) & ACC_NATIVE)) + { + PROTECT(t, method); + + t->m->processor->compileMethod + (t, zone, &constants, &calls, &addresses, method); + } + + object addendum = methodAddendum(t, method); + if (addendum and methodAddendumExceptionTable(t, addendum)) { + PROTECT(t, addendum); + + // resolve exception types now to avoid trying to update + // immutable references at runtime + for (unsigned i = 0; i < shortArrayLength + (t, methodAddendumExceptionTable(t, addendum)); ++i) + { + uint16_t index = shortArrayBody + (t, methodAddendumExceptionTable(t, addendum), i) - 1; + + object o = singletonObject + (t, addendumPool(t, addendum), index); + + if (objectClass(t, o) == type(t, Machine::ReferenceType)) { + o = resolveClass + (t, root(t, Machine::BootLoader), referenceName(t, o)); + + if (t->exception) return 0; + + set(t, addendumPool(t, addendum), + SingletonBody + (index * BytesPerWord), o); + } + } + } } } } @@ -89,7 +158,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, if (methodFlags(t, method) & ACC_NATIVE) { address = reinterpret_cast(code + image->thunks.native.start); } else { - address = methodCompiled(t, method); + address = codeCompiled(t, methodCode(t, method)); } static_cast(pointerValue(t, tripleSecond(t, calls))) @@ -131,14 +200,17 @@ visitRoots(Thread* t, BootImage* image, HeapWalker* w, object constants) { Machine* m = t->m; - for (HashMapIterator it(t, m->classMap); it.hasMore();) { + for (HashMapIterator it(t, classLoaderMap(t, root(t, Machine::BootLoader))); + it.hasMore();) + { w->visitRoot(tripleSecond(t, it.next())); } - image->loader = w->visitRoot(m->loader); + image->bootLoader = w->visitRoot(root(t, Machine::BootLoader)); + image->appLoader = w->visitRoot(root(t, Machine::AppLoader)); image->types = w->visitRoot(m->types); - m->processor->visitRoots(w); + m->processor->visitRoots(t, w); for (; constants; constants = tripleThird(t, constants)) { w->visitRoot(tripleFirst(t, constants)); @@ -177,9 +249,17 @@ makeHeapImage(Thread* t, BootImage* image, uintptr_t* heap, uintptr_t* map, unsigned size = objectSize(t, p); unsigned number; - if (currentObject - and (currentOffset * BytesPerWord) == ClassStaticTable) + if ((currentObject + and (currentOffset * BytesPerWord) == ClassStaticTable) + or instanceOf(t, type(t, Machine::SystemClassLoaderType), p)) { + // Static tables and system classloaders must be allocated + // as fixed objects in the heap image so that they can be + // marked as dirty and visited during GC. Otherwise, + // attempts to update references in these objects to point + // to runtime-allocated memory would fail because we don't + // scan non-fixed objects in the heap image during GC. + FixedAllocator allocator (t->m->system, reinterpret_cast(heap + position), (capacity - position) * BytesPerWord); @@ -296,40 +376,90 @@ writeBootImage(Thread* t, FILE* out, BootImage* image, uint8_t* code, PROTECT(t, constants); - const unsigned HeapCapacity = 32 * 1024 * 1024; + // this map will not be used when the bootimage is loaded, so + // there's no need to preserve it: + setRoot(t, Machine::ByteArrayMap, makeWeakHashMap(t, 0, 0)); + + // name all primitive classes so we don't try to update immutable + // references at runtime: + { object name = makeByteArray(t, "void"); + set(t, type(t, Machine::JvoidType), ClassName, name); + + name = makeByteArray(t, "boolean"); + set(t, type(t, Machine::JbooleanType), ClassName, name); + + name = makeByteArray(t, "byte"); + set(t, type(t, Machine::JbyteType), ClassName, name); + + name = makeByteArray(t, "short"); + set(t, type(t, Machine::JshortType), ClassName, name); + + name = makeByteArray(t, "char"); + set(t, type(t, Machine::JcharType), ClassName, name); + + name = makeByteArray(t, "int"); + set(t, type(t, Machine::JintType), ClassName, name); + + name = makeByteArray(t, "float"); + set(t, type(t, Machine::JfloatType), ClassName, name); + + name = makeByteArray(t, "long"); + set(t, type(t, Machine::JlongType), ClassName, name); + + name = makeByteArray(t, "double"); + set(t, type(t, Machine::JdoubleType), ClassName, name); + } + + collect(t, Heap::MajorCollection); + uintptr_t* heap = static_cast (t->m->heap->allocate(HeapCapacity)); uintptr_t* heapMap = static_cast (t->m->heap->allocate(heapMapSize(HeapCapacity))); memset(heapMap, 0, heapMapSize(HeapCapacity)); - // this map will not be used when the bootimage is loaded, so - // there's no need to preserve it: - t->m->byteArrayMap = makeWeakHashMap(t, 0, 0); - - collect(t, Heap::MajorCollection); - HeapWalker* heapWalker = makeHeapImage (t, image, heap, heapMap, HeapCapacity, constants); updateConstants(t, constants, code, codeMap, heapWalker->map()); - image->classCount = hashMapSize(t, t->m->classMap); - unsigned* classTable = static_cast - (t->m->heap->allocate(image->classCount * sizeof(unsigned))); + image->bootClassCount = hashMapSize + (t, classLoaderMap(t, root(t, Machine::BootLoader))); + + unsigned* bootClassTable = static_cast + (t->m->heap->allocate(image->bootClassCount * sizeof(unsigned))); { unsigned i = 0; - for (HashMapIterator it(t, t->m->classMap); it.hasMore();) { - classTable[i++] = heapWalker->map()->find(tripleSecond(t, it.next())); + for (HashMapIterator it + (t, classLoaderMap(t, root(t, Machine::BootLoader))); + it.hasMore();) + { + bootClassTable[i++] = heapWalker->map()->find + (tripleSecond(t, it.next())); } } - image->stringCount = hashMapSize(t, t->m->stringMap); + image->appClassCount = hashMapSize + (t, classLoaderMap(t, root(t, Machine::AppLoader))); + + unsigned* appClassTable = static_cast + (t->m->heap->allocate(image->appClassCount * sizeof(unsigned))); + + { unsigned i = 0; + for (HashMapIterator it + (t, classLoaderMap(t, root(t, Machine::AppLoader))); + it.hasMore();) + { + appClassTable[i++] = heapWalker->map()->find(tripleSecond(t, it.next())); + } + } + + image->stringCount = hashMapSize(t, root(t, Machine::StringMap)); unsigned* stringTable = static_cast (t->m->heap->allocate(image->stringCount * sizeof(unsigned))); { unsigned i = 0; - for (HashMapIterator it(t, t->m->stringMap); it.hasMore();) { + for (HashMapIterator it(t, root(t, Machine::StringMap)); it.hasMore();) { stringTable[i++] = heapWalker->map()->find (jreferenceTarget(t, tripleFirst(t, it.next()))); } @@ -344,17 +474,19 @@ writeBootImage(Thread* t, FILE* out, BootImage* image, uint8_t* code, fprintf(stderr, "class count %d string count %d call count %d\n" "heap size %d code size %d\n", - image->classCount, image->stringCount, image->callCount, + image->bootClassCount, image->stringCount, image->callCount, image->heapSize, image->codeSize); if (true) { fwrite(image, sizeof(BootImage), 1, out); - fwrite(classTable, image->classCount * sizeof(unsigned), 1, out); + fwrite(bootClassTable, image->bootClassCount * sizeof(unsigned), 1, out); + fwrite(appClassTable, image->appClassCount * sizeof(unsigned), 1, out); fwrite(stringTable, image->stringCount * sizeof(unsigned), 1, out); fwrite(callTable, image->callCount * sizeof(unsigned) * 2, 1, out); - unsigned offset = (image->classCount * sizeof(unsigned)) + unsigned offset = (image->bootClassCount * sizeof(unsigned)) + + (image->appClassCount * sizeof(unsigned)) + (image->stringCount * sizeof(unsigned)) + (image->callCount * sizeof(unsigned) * 2); @@ -384,16 +516,18 @@ main(int ac, const char** av) } System* s = makeSystem(0); - Heap* h = makeHeap(s, 128 * 1024 * 1024); - Finder* f = makeFinder(s, av[1], 0); + Heap* h = makeHeap(s, HeapCapacity * 2); + Classpath* c = makeClasspath(s, h, AVIAN_JAVA_HOME, AVIAN_EMBED_PREFIX); + Finder* f = makeFinder(s, h, av[1], 0); Processor* p = makeProcessor(s, h, false); BootImage image; - const unsigned CodeCapacity = 16 * 1024 * 1024; + const unsigned CodeCapacity = 128 * 1024 * 1024; uint8_t* code = static_cast(h->allocate(CodeCapacity)); p->initialize(&image, code, CodeCapacity); - Machine* m = new (h->allocate(sizeof(Machine))) Machine(s, h, f, p, 0, 0); + Machine* m = new (h->allocate(sizeof(Machine))) Machine + (s, h, f, 0, p, c, 0, 0); Thread* t = p->makeThread(m, 0, 0); enter(t, Thread::ActiveState); diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp index aacfb7e9d5..e86fae4079 100644 --- a/src/classpath-avian.cpp +++ b/src/classpath-avian.cpp @@ -95,7 +95,7 @@ class MyClasspath : public Classpath { virtual const char* bootClasspath() { - return BOOT_CLASSPATH; + return AVIAN_CLASSPATH; } virtual void diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 8d6c5994a5..4f18675a04 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -209,7 +209,7 @@ class MyClasspath : public Classpath { sb.append('\0'); this->classpath = sb.pointer; - sb.append(BOOT_CLASSPATH); + sb.append(AVIAN_CLASSPATH); sb.append(s->pathSeparator()); sb.append(javaHome); sb.append("/lib/rt.jar"); @@ -590,7 +590,8 @@ getFileAttributes } } else { object r = t->m->processor->invoke - (t, nativeInterceptOriginal(t, methodCode(t, method)), + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), reinterpret_cast(arguments[0]), file); return (r ? intValue(t, r) : 0); @@ -631,7 +632,8 @@ getLength return 0; } else { object r = t->m->processor->invoke - (t, nativeInterceptOriginal(t, methodCode(t, method)), + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), reinterpret_cast(arguments[0]), file); return (r ? longValue(t, r) : 0); @@ -703,7 +705,9 @@ openFile(Thread* t, object method, uintptr_t* arguments) = index + VirtualFileBase; } else { t->m->processor->invoke - (t, nativeInterceptOriginal(t, methodCode(t, method)), this_, path); + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + this_, path); } } @@ -740,7 +744,9 @@ readByteFromFile(Thread* t, object method, uintptr_t* arguments) } } else { object r = t->m->processor->invoke - (t, nativeInterceptOriginal(t, methodCode(t, method)), this_); + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + this_); return r ? intValue(t, r) : 0; } @@ -793,8 +799,9 @@ readBytesFromFile(Thread* t, object method, uintptr_t* arguments) } } else { object r = t->m->processor->invoke - (t, nativeInterceptOriginal(t, methodCode(t, method)), this_, dst, - offset, length); + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + this_, dst, offset, length); return r ? intValue(t, r) : 0; } @@ -837,7 +844,9 @@ skipBytesInFile(Thread* t, object method, uintptr_t* arguments) } } else { object r = t->m->processor->invoke - (t, nativeInterceptOriginal(t, methodCode(t, method)), this_, count); + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + this_, count); return r ? longValue(t, r) : 0; } @@ -870,7 +879,9 @@ availableBytesInFile(Thread* t, object method, uintptr_t* arguments) } } else { object r = t->m->processor->invoke - (t, nativeInterceptOriginal(t, methodCode(t, method)), this_); + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + this_); return r ? intValue(t, r) : 0; } @@ -901,7 +912,9 @@ closeFile(Thread* t, object method, uintptr_t* arguments) 0); } else { t->m->processor->invoke - (t, nativeInterceptOriginal(t, methodCode(t, method)), this_); + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + this_); } } @@ -926,7 +939,11 @@ intercept(Thread* t, object c, const char* name, const char* spec, object native = makeNativeIntercept(t, function, true, clone); - set(t, m, MethodCode, native); + PROTECT(t, native); + + object runtimeData = getMethodRuntimeData(t, m); + + set(t, runtimeData, MethodRuntimeDataNative, native); } } @@ -1196,7 +1213,7 @@ resolveParameterJTypes(Thread* t, object loader, object spec, object resolveExceptionJTypes(Thread* t, object loader, object addendum) { - if (addendum == 0) { + if (addendum == 0 or methodAddendumExceptionTable(t, addendum) == 0) { return makeObjectArray(t, type(t, Machine::JclassType), 0); } @@ -2470,8 +2487,9 @@ EXPORT(JVM_GetClassAnnotations)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); - return makeLocalReference - (t, addendumAnnotationTable(t, classAddendum(t, jclassVmClass(t, *c)))); + object addendum = classAddendum(t, jclassVmClass(t, *c)); + return addendum + ? makeLocalReference(t, addendumAnnotationTable(t, addendum)) : 0; } extern "C" JNIEXPORT jobjectArray JNICALL @@ -2537,7 +2555,12 @@ EXPORT(JVM_GetClassDeclaredMethods)(Thread* t, jclass c, jboolean publicOnly) ? 0 : addendumAnnotationTable(t, methodAddendum(t, vmMethod)); if (annotationTable) { - set(t, classAddendum(t, jclassVmClass(t, *c)), AddendumPool, + PROTECT(t, signature); + PROTECT(t, annotationTable); + + object runtimeData = getClassRuntimeData(t, jclassVmClass(t, *c)); + + set(t, runtimeData, ClassRuntimeDataPool, addendumPool(t, methodAddendum(t, vmMethod))); } @@ -2607,8 +2630,13 @@ EXPORT(JVM_GetClassDeclaredFields)(Thread* t, jclass c, jboolean publicOnly) ? 0 : addendumAnnotationTable(t, fieldAddendum(t, vmField)); if (annotationTable) { - set(t, classAddendum(t, jclassVmClass(t, *c)), AddendumPool, - addendumPool(t, fieldAddendum(t, vmField))); + PROTECT(t, signature); + PROTECT(t, annotationTable); + + object runtimeData = getClassRuntimeData(t, jclassVmClass(t, *c)); + + set(t, runtimeData, ClassRuntimeDataPool, + addendumPool(t, methodAddendum(t, vmField))); } object field = makeJfield @@ -2680,7 +2708,12 @@ EXPORT(JVM_GetClassDeclaredConstructors)(Thread* t, jclass c, ? 0 : addendumAnnotationTable(t, methodAddendum(t, vmMethod)); if (annotationTable) { - set(t, classAddendum(t, jclassVmClass(t, *c)), AddendumPool, + PROTECT(t, signature); + PROTECT(t, annotationTable); + + object runtimeData = getClassRuntimeData(t, jclassVmClass(t, *c)); + + set(t, runtimeData, ClassRuntimeDataPool, addendumPool(t, methodAddendum(t, vmMethod))); } @@ -2766,9 +2799,20 @@ EXPORT(JVM_GetClassConstantPool)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); - return makeLocalReference - (t, makeConstantPool - (t, addendumPool(t, classAddendum(t, jclassVmClass(t, *c))))); + object vmClass = jclassVmClass(t, *c); + object addendum = classAddendum(t, vmClass); + object pool; + if (addendum) { + pool = addendumPool(t, addendum); + } else { + pool = 0; + } + + if (pool == 0) { + pool = classRuntimeDataPool(t, getClassRuntimeData(t, vmClass)); + } + + return makeLocalReference(t, makeConstantPool(t, pool)); } extern "C" JNIEXPORT jint JNICALL diff --git a/src/compile.cpp b/src/compile.cpp index 6a46b5b39a..fdd909d127 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -2900,6 +2900,8 @@ handleMonitorEvent(MyThread* t, Frame* frame, intptr_t function) if (methodFlags(t, method) & ACC_SYNCHRONIZED) { Compiler::Operand* lock; if (methodFlags(t, method) & ACC_STATIC) { + PROTECT(t, method); + lock = frame->append(methodClass(t, method)); } else { lock = loadLocal(frame->context, 1, savedTargetIndex(t, method)); @@ -3716,6 +3718,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, and (fieldCode(t, field) == DoubleField or fieldCode(t, field) == LongField)) { + PROTECT(t, field); + c->call (c->constant (getThunk(t, acquireMonitorForObjectThunk), Compiler::AddressType), @@ -3729,6 +3733,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (instruction == getstatic) { assert(t, fieldFlags(t, field) & ACC_STATIC); + PROTECT(t, field); + if (fieldClass(t, field) != methodClass(t, context->method) and classNeedsInit(t, fieldClass(t, field))) { @@ -4127,7 +4133,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, unsigned instance = parameterFootprint - 1; - unsigned rSize = resultSize(t, methodReturnCode(t, target)); + int returnCode = methodReturnCode(t, target); + + unsigned rSize = resultSize(t, returnCode); Compiler::Operand* result = c->stackCall (c->call @@ -4143,13 +4151,13 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, 0, frame->trace(0, 0), rSize, - operandTypeForFieldCode(t, methodReturnCode(t, target)), + operandTypeForFieldCode(t, returnCode), parameterFootprint); frame->pop(parameterFootprint); if (rSize) { - pushReturnValue(t, frame, methodReturnCode(t, target), result); + pushReturnValue(t, frame, returnCode, result); } } break; @@ -4385,12 +4393,20 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (singletonIsObject(t, pool, index - 1)) { object v = singletonObject(t, pool, index - 1); if (objectClass(t, v) == type(t, Machine::ReferenceType)) { - object class_ = resolveClassInPool(t, context->method, index - 1); + v = resolveClassInPool(t, context->method, index - 1); if (UNLIKELY(t->exception)) return; + } - frame->pushObject(frame->append(getJClass(t, class_))); - } else if (objectClass(t, v) == type(t, Machine::ClassType)) { - frame->pushObject(frame->append(getJClass(t, v))); + if (objectClass(t, v) == type(t, Machine::ClassType)) { + frame->pushObject + (c->call + (c->constant + (getThunk(t, getJClassThunk), Compiler::AddressType), + 0, + frame->trace(0, 0), + BytesPerWord, + Compiler::ObjectType, + 2, c->register_(t->arch->thread()), frame->append(v))); } else { frame->pushObject(frame->append(v)); } @@ -4703,6 +4719,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (fieldClass(t, field) != methodClass(t, context->method) and classNeedsInit(t, fieldClass(t, field))) { + PROTECT(t, field); + c->call (c->constant (getThunk(t, tryInitClassThunk), Compiler::AddressType), @@ -4729,6 +4747,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, and (fieldCode(t, field) == DoubleField or fieldCode(t, field) == LongField)) { + PROTECT(t, field); + c->call (c->constant (getThunk(t, acquireMonitorForObjectThunk), @@ -4766,6 +4786,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* table; if (instruction == putstatic) { + PROTECT(t, field); + table = frame->append(staticTable); } else { table = frame->popObject(); @@ -6308,7 +6330,7 @@ invokeNativeSlow(MyThread* t, object method, void* function) uint64_t invokeNative2(MyThread* t, object method) { - object native = methodCode(t, method); + object native = methodRuntimeDataNative(t, getMethodRuntimeData(t, method)); if (nativeFast(t, native)) { return invokeNativeFast(t, method, nativeFunction(t, native)); } else { @@ -7276,7 +7298,7 @@ class MyProcessor: public Processor { return vm::makeMethod (t, vmFlags, returnCode, parameterCount, parameterFootprint, flags, - offset, 0, name, spec, addendum, class_, code); + offset, 0, 0, name, spec, addendum, class_, code); } virtual object @@ -7301,8 +7323,9 @@ class MyProcessor: public Processor { { return vm::makeClass (t, flags, vmFlags, fixedSize, arrayElementSize, arrayDimensions, - objectMask, name, sourceFile, super, interfaceTable, virtualTable, - fieldTable, methodTable, staticTable, addendum, loader, vtableLength); + 0, objectMask, name, sourceFile, super, interfaceTable, + virtualTable, fieldTable, methodTable, staticTable, addendum, loader, + vtableLength); } virtual void @@ -7664,11 +7687,11 @@ class MyProcessor: public Processor { codeAllocator.capacity = ExecutableAreaSizeInBytes; } - roots = makeArray(t, RootCount); - if (image) { local::boot(static_cast(t), image); } else { + roots = makeArray(t, RootCount); + setRoot(t, CallTable, makeArray(t, 128)); setRoot(t, MethodTreeSentinal, makeTreeNode(t, 0, 0, 0)); @@ -8069,7 +8092,7 @@ fixupMethods(Thread* t, object map, BootImage* image, uint8_t* code) if (classMethodTable(t, c)) { for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) { object method = arrayBody(t, classMethodTable(t, c), i); - if (methodCode(t, method) or (methodFlags(t, method) & ACC_NATIVE)) { + if (methodCode(t, method)) { assert(t, (methodCompiled(t, method) - image->codeBase) <= image->codeSize); @@ -8077,7 +8100,7 @@ fixupMethods(Thread* t, object map, BootImage* image, uint8_t* code) = (methodCompiled(t, method) - image->codeBase) + reinterpret_cast(code); - if (DebugCompile and (methodFlags(t, method) & ACC_NATIVE) == 0) { + if (DebugCompile) { logCompile (static_cast(t), reinterpret_cast(methodCompiled(t, method)), @@ -8180,11 +8203,16 @@ boot(MyThread* t, BootImage* image) t->m->heap->setImmortalHeap(heap, image->heapSize / BytesPerWord); - setRoot(t, Machine::BootLoader, bootObject(heap, image->bootLoader)); - setRoot(t, Machine::AppLoader, bootObject(heap, image->appLoader)); t->m->types = bootObject(heap, image->types); + t->m->roots = makeArray(t, Machine::RootCount); + + setRoot(t, Machine::BootLoader, bootObject(heap, image->bootLoader)); + setRoot(t, Machine::AppLoader, bootObject(heap, image->appLoader)); + MyProcessor* p = static_cast(t->m->processor); + + p->roots = makeArray(t, RootCount); setRoot(t, MethodTree, bootObject(heap, image->methodTree)); setRoot(t, MethodTreeSentinal, bootObject(heap, image->methodTreeSentinal)); @@ -8195,11 +8223,17 @@ boot(MyThread* t, BootImage* image) syncInstructionCache(code, image->codeSize); - set(t, root(t, Machine::BootLoader), ClassLoaderMap, makeClassMap - (t, bootClassTable, image->bootClassCount, heap)); + { object map = makeClassMap(t, bootClassTable, image->bootClassCount, heap); + set(t, root(t, Machine::BootLoader), ClassLoaderMap, map); + } - set(t, root(t, Machine::AppLoader), ClassLoaderMap, makeClassMap - (t, appClassTable, image->appClassCount, heap)); + systemClassLoaderFinder(t, root(t, Machine::BootLoader)) = t->m->bootFinder; + + { object map = makeClassMap(t, appClassTable, image->appClassCount, heap); + set(t, root(t, Machine::AppLoader), ClassLoaderMap, map); + } + + systemClassLoaderFinder(t, root(t, Machine::AppLoader)) = t->m->appFinder; setRoot(t, Machine::StringMap, makeStringMap (t, stringTable, image->stringCount, heap)); diff --git a/src/interpret.cpp b/src/interpret.cpp index f14b7084d0..530af13b44 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -656,7 +656,7 @@ invokeNative(Thread* t, object method) return VoidField; } - object native = methodCode(t, method); + object native = methodRuntimeDataNative(t, getMethodRuntimeData(t, method)); if (nativeFast(t, native)) { pushFrame(t, method); @@ -3045,7 +3045,7 @@ class MyProcessor: public Processor { { return vm::makeMethod (t, vmFlags, returnCode, parameterCount, parameterFootprint, flags, - offset, 0, name, spec, addendum, class_, code); + offset, 0, 0, name, spec, addendum, class_, code); } virtual object @@ -3069,7 +3069,7 @@ class MyProcessor: public Processor { unsigned vtableLength UNUSED) { return vm::makeClass - (t, flags, vmFlags, fixedSize, arrayElementSize, arrayDimensions, + (t, flags, vmFlags, fixedSize, arrayElementSize, arrayDimensions, 0, objectMask, name, sourceFile, super, interfaceTable, virtualTable, fieldTable, methodTable, addendum, staticTable, loader, 0); } diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 44cbb0cb91..b315dac3ae 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -430,7 +430,8 @@ methodID(Thread* t, object method) if (methodNativeID(t, method) == 0) { setRoot(t, Machine::JNIMethodTable, vectorAppend (t, root(t, Machine::JNIMethodTable), method)); - methodNativeID(t, method) = vectorSize(t, root(t, Machine::JNIMethodTable)); + methodNativeID(t, method) = vectorSize + (t, root(t, Machine::JNIMethodTable)); } } @@ -2036,6 +2037,27 @@ append(char** p, const char* value, unsigned length, char tail) } } +void +boot(Thread* t) +{ + enter(t, Thread::ActiveState); + + if (t->exception == 0) { + setRoot(t, Machine::NullPointerException, t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType)); + + if (t->exception == 0) { + setRoot(t, Machine::ArrayIndexOutOfBoundsException, + t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType)); + } + } + + t->m->classpath->boot(t); + + enter(t, Thread::IdleState); +} + } // namespace local } // namespace @@ -2349,5 +2371,7 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) *t = p->makeThread(*m, 0, 0); + local::boot(*t); + return 0; } diff --git a/src/machine.cpp b/src/machine.cpp index 0191e1d285..f2d6178318 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1314,6 +1314,7 @@ addInterfaceMethods(Thread* t, object class_, object virtualMap, methodFlags(t, method), (*virtualCount)++, 0, + 0, methodName(t, method), methodSpec(t, method), 0, @@ -1650,7 +1651,7 @@ parseAttributeTable(Thread* t, Stream& s, object class_, object pool) object body = makeByteArray(t, length); s.read(reinterpret_cast(&byteArrayBody(t, body, 0)), length); - object addendum = makeClassAddendum(t, pool, body, 0, 0, 0); + object addendum = makeClassAddendum(t, pool, body); set(t, class_, ClassAddendum, addendum); } else { @@ -1839,21 +1840,11 @@ resolveArrayClass(Thread* t, object loader, object spec, bool throw_) object resolveObjectArrayClass(Thread* t, object loader, object elementClass) { - object addendum = classAddendum(t, elementClass); - if (addendum) { - object arrayClass = classAddendumArrayClass(t, addendum); + { object arrayClass = classRuntimeDataArrayClass + (t, getClassRuntimeData(t, elementClass)); if (arrayClass) { return arrayClass; } - } else { - PROTECT(t, loader); - PROTECT(t, elementClass); - - ACQUIRE(t, t->m->classLock); - - object addendum = makeClassAddendum(t, 0, 0, 0, 0, 0); - - set(t, elementClass, ClassAddendum, addendum); } PROTECT(t, loader); @@ -1882,7 +1873,7 @@ resolveObjectArrayClass(Thread* t, object loader, object elementClass) object arrayClass = resolveClass(t, loader, spec); - set(t, classAddendum(t, elementClass), ClassAddendumArrayClass, + set(t, getClassRuntimeData(t, elementClass), ClassRuntimeDataArrayClass, arrayClass); return arrayClass; @@ -2104,7 +2095,7 @@ boot(Thread* t) { object bootCode = makeCode(t, 0, 0, 0, 0, 0, 0, 1); codeBody(t, bootCode, 0) = impdep1; object bootMethod = makeMethod - (t, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, bootCode); + (t, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, bootCode); PROTECT(t, bootMethod); #include "type-java-initializations.cpp" @@ -2349,6 +2340,8 @@ Thread::init() m->unsafe = false; + enter(this, ActiveState); + if (image) { m->processor->boot(this, image); } else { @@ -2358,6 +2351,8 @@ Thread::init() setRoot(this, Machine::ByteArrayMap, makeWeakHashMap(this, 0, 0)); setRoot(this, Machine::MonitorMap, makeWeakHashMap(this, 0, 0)); + setRoot(this, Machine::ClassRuntimeDataTable, makeVector(this, 0, 0)); + setRoot(this, Machine::MethodRuntimeDataTable, makeVector(this, 0, 0)); setRoot(this, Machine::JNIMethodTable, makeVector(this, 0, 0)); m->localThread->set(this); @@ -2373,25 +2368,6 @@ Thread::init() } threadPeer(this, javaThread) = reinterpret_cast(this); - - if (parent == 0) { - enter(this, Thread::ActiveState); - - if (exception == 0) { - setRoot(this, Machine::NullPointerException, m->classpath->makeThrowable - (this, Machine::NullPointerExceptionType)); - - if (exception == 0) { - setRoot(this, Machine::ArrayIndexOutOfBoundsException, - m->classpath->makeThrowable - (this, Machine::ArrayIndexOutOfBoundsExceptionType)); - } - } - - m->classpath->boot(this); - - enter(this, Thread::IdleState); - } } void @@ -3151,6 +3127,7 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size) 0, // fixed size 0, // array size 0, // array dimensions + 0, // runtime data index 0, // object mask referenceName (t, singletonObject(t, pool, name - 1)), diff --git a/src/machine.h b/src/machine.h index 77c821e522..17bd0b41c3 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1194,6 +1194,8 @@ class Machine { MonitorMap, StringMap, ByteArrayMap, + ClassRuntimeDataTable, + MethodRuntimeDataTable, JNIMethodTable, ShutdownHooks, ObjectsToFinalize, @@ -3056,28 +3058,70 @@ resolveMethod(Thread* t, object method, unsigned index) (t, classLoader(t, methodClass(t, method)), method, index); } +object +vectorAppend(Thread*, object, object); + inline object -getJClass(Thread* t, object c) +getClassRuntimeData(Thread* t, object c) { - if (classAddendum(t, c) == 0) { + if (classRuntimeDataIndex(t, c) == 0) { PROTECT(t, c); ACQUIRE(t, t->m->classLock); - object addendum = makeClassAddendum(t, 0, 0, 0, 0, 0); - - set(t, c, ClassAddendum, addendum); + if (classRuntimeDataIndex(t, c) == 0) { + object runtimeData = makeClassRuntimeData(t, 0, 0, 0); + + setRoot(t, Machine::ClassRuntimeDataTable, vectorAppend + (t, root(t, Machine::ClassRuntimeDataTable), runtimeData)); + + classRuntimeDataIndex(t, c) = vectorSize + (t, root(t, Machine::ClassRuntimeDataTable)); + } } - object jclass = classAddendumClass(t, classAddendum(t, c)); + return vectorBody(t, root(t, Machine::ClassRuntimeDataTable), + classRuntimeDataIndex(t, c) - 1); +} + +inline object +getMethodRuntimeData(Thread* t, object method) +{ + if (methodRuntimeDataIndex(t, method) == 0) { + PROTECT(t, method); + + ACQUIRE(t, t->m->classLock); + + if (methodRuntimeDataIndex(t, method) == 0) { + object runtimeData = makeMethodRuntimeData(t, 0); + + setRoot(t, Machine::MethodRuntimeDataTable, vectorAppend + (t, root(t, Machine::MethodRuntimeDataTable), runtimeData)); + + methodRuntimeDataIndex(t, method) = vectorSize + (t, root(t, Machine::MethodRuntimeDataTable)); + } + } + + return vectorBody(t, root(t, Machine::MethodRuntimeDataTable), + methodRuntimeDataIndex(t, method) - 1); +} + +inline object +getJClass(Thread* t, object c) +{ + object jclass = classRuntimeDataJclass(t, getClassRuntimeData(t, c)); if (jclass == 0) { PROTECT(t, c); ACQUIRE(t, t->m->classLock); - jclass = t->m->classpath->makeJclass(t, c); + jclass = classRuntimeDataJclass(t, getClassRuntimeData(t, c)); + if (jclass == 0) { + jclass = t->m->classpath->makeJclass(t, c); - set(t, classAddendum(t, c), ClassAddendumClass, jclass); + set(t, getClassRuntimeData(t, c), ClassRuntimeDataJclass, jclass); + } } return jclass; @@ -3111,12 +3155,15 @@ registerNative(Thread* t, object method, void* function) expect(t, methodFlags(t, method) & ACC_NATIVE); object native = makeNative(t, function, false); + PROTECT(t, native); - // ensure other threads only see the methodCode field populated - // once the object it points to has been populated: + object runtimeData = getMethodRuntimeData(t, method); + + // ensure other threads only see the methodRuntimeDataNative field + // populated once the object it points to has been populated: storeStoreMemoryBarrier(); - set(t, method, MethodCode, native); + set(t, runtimeData, MethodRuntimeDataNative, native); } inline void @@ -3126,7 +3173,7 @@ unregisterNatives(Thread* t, object c) for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) { object method = arrayBody(t, classMethodTable(t, c), i); if (methodFlags(t, method) & ACC_NATIVE) { - set(t, method, MethodCode, 0); + set(t, getMethodRuntimeData(t, method), MethodRuntimeDataNative, 0); } } } @@ -3152,6 +3199,7 @@ methodClone(Thread* t, object method) methodFlags(t, method), methodOffset(t, method), methodNativeID(t, method), + methodRuntimeDataIndex(t, method), methodName(t, method), methodSpec(t, method), methodAddendum(t, method), diff --git a/src/process.cpp b/src/process.cpp index c9ed7a4505..e4835592a7 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -232,7 +232,9 @@ resolveNative(Thread* t, object method) initClass(t, methodClass(t, method)); - if (LIKELY(t->exception == 0) and methodCode(t, method) == 0) { + if (LIKELY(t->exception == 0) + and methodRuntimeDataNative(t, getMethodRuntimeData(t, method)) == 0) + { object native = resolveNativeMethod(t, method); if (UNLIKELY(native == 0)) { object message = makeString @@ -246,11 +248,15 @@ resolveNative(Thread* t, object method) return; } - // ensure other threads only see the methodCode field populated - // once the object it points do has been populated: + PROTECT(t, native); + + object runtimeData = getMethodRuntimeData(t, method); + + // ensure other threads only see the methodRuntimeDataNative field + // populated once the object it points to has been populated: storeStoreMemoryBarrier(); - set(t, method, MethodCode, native); + set(t, runtimeData, MethodRuntimeDataNative, native); } } diff --git a/src/thunks.cpp b/src/thunks.cpp index f55c0018a9..9de7aaf263 100644 --- a/src/thunks.cpp +++ b/src/thunks.cpp @@ -48,4 +48,5 @@ THUNK(instanceOf64) THUNK(makeNewGeneral64) THUNK(makeNew64) THUNK(set) +THUNK(getJClass) THUNK(gcIfNecessary) diff --git a/src/types.def b/src/types.def index 68db65d187..ae746d76b4 100644 --- a/src/types.def +++ b/src/types.def @@ -37,6 +37,14 @@ (type fieldAddendum avian/FieldAddendum) +(type classRuntimeData + (object arrayClass) + (object jclass) + (object pool)) + +(type methodRuntimeData + (object native)) + (type pointer (void* value))