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.
This commit is contained in:
Joel Dice 2010-11-26 12:41:31 -07:00
parent 4f23601b56
commit 459f4d5194
16 changed files with 426 additions and 154 deletions

View File

@ -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 { }

View File

@ -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;
}

View File

@ -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;

View File

@ -572,10 +572,6 @@ public final class Class <T> implements Type, AnnotatedElement {
return (T) o;
}
public Object[] getSigners() {
return vmClass.addendum.signers;
}
public Package getPackage() {
if ((vmClass.vmFlags & PrimitiveFlag) != 0 || isArray()) {
return null;

View File

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

View File

@ -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<Finder*>
(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<char*>
(&byteArrayBody
(t, vm::methodName(t, method), 0)), methodName) == 0)
and (methodSpec == 0
or ::strcmp
(reinterpret_cast<char*>
(&byteArrayBody
(t, vm::methodName(t, method), 0)), methodName) == 0)
and (methodSpec == 0
or ::strcmp
(reinterpret_cast<char*>
(&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<uintptr_t>(code + image->thunks.native.start);
} else {
address = methodCompiled(t, method);
address = codeCompiled(t, methodCode(t, method));
}
static_cast<ListenPromise*>(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<uint8_t*>(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<uintptr_t*>
(t->m->heap->allocate(HeapCapacity));
uintptr_t* heapMap = static_cast<uintptr_t*>
(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<unsigned*>
(t->m->heap->allocate(image->classCount * sizeof(unsigned)));
image->bootClassCount = hashMapSize
(t, classLoaderMap(t, root(t, Machine::BootLoader)));
unsigned* bootClassTable = static_cast<unsigned*>
(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<unsigned*>
(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<unsigned*>
(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<uint8_t*>(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);

View File

@ -95,7 +95,7 @@ class MyClasspath : public Classpath {
virtual const char*
bootClasspath()
{
return BOOT_CLASSPATH;
return AVIAN_CLASSPATH;
}
virtual void

View File

@ -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<object>(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<object>(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

View File

@ -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<MyThread*>(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<uintptr_t>(code);
if (DebugCompile and (methodFlags(t, method) & ACC_NATIVE) == 0) {
if (DebugCompile) {
logCompile
(static_cast<MyThread*>(t),
reinterpret_cast<uint8_t*>(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<MyProcessor*>(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));

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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<uint8_t*>(&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<jlong>(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)),

View File

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

View File

@ -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);
}
}

View File

@ -48,4 +48,5 @@ THUNK(instanceOf64)
THUNK(makeNewGeneral64)
THUNK(makeNew64)
THUNK(set)
THUNK(getJClass)
THUNK(gcIfNecessary)

View File

@ -37,6 +37,14 @@
(type fieldAddendum avian/FieldAddendum)
(type classRuntimeData
(object arrayClass)
(object jclass)
(object pool))
(type methodRuntimeData
(object native))
(type pointer
(void* value))