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))