From 453ceb42ab856286fddfcca6cce77475d283a91e Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 15 Mar 2011 17:52:02 -0600 Subject: [PATCH] implement lazy class/field/method resolution in JIT compiler Unlike the interpreter, the JIT compiler tries to resolve all the symbols referenced by a method when compiling that method. However, this can backfire if a symbol cannot be resolved: we end up throwing an e.g. NoClassDefFoundError for code which may never be executed. This is particularly troublesome for code which supports multiple APIs, choosing one at runtime. The solution is to defer to stub code for symbols which can't be resolved at JIT compile time. Such a stub will try again at runtime to resolve the needed symbol and throw an appropriate error if it still can't be found. --- classpath/avian/VMField.java | 1 + src/compile.cpp | 1423 +++++++++++++++++++++++++--------- src/interpret.cpp | 178 ++--- src/machine.cpp | 50 +- src/machine.h | 191 ++++- src/thunks.cpp | 18 + src/vector.h | 1 + src/zone.h | 2 + test/LazyLoading.java | 184 +++++ 9 files changed, 1508 insertions(+), 540 deletions(-) create mode 100644 test/LazyLoading.java diff --git a/classpath/avian/VMField.java b/classpath/avian/VMField.java index 699a68e5f8..70752ac943 100644 --- a/classpath/avian/VMField.java +++ b/classpath/avian/VMField.java @@ -15,6 +15,7 @@ public class VMField { public byte code; public short flags; public short offset; + public short index; public byte[] name; public byte[] spec; public FieldAddendum addendum; diff --git a/src/compile.cpp b/src/compile.cpp index c9b00f1d9b..584e39d4cf 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -1202,7 +1202,8 @@ class Context { dirtyRoots(false), leaf(true), eventLog(t->m->system, t->m->heap, 1024), - protector(this) + protector(this), + resource(this) { } Context(MyThread* t): @@ -1227,7 +1228,8 @@ class Context { dirtyRoots(false), leaf(true), eventLog(t->m->system, t->m->heap, 0), - protector(this) + protector(this), + resource(this) { } ~Context() { @@ -1244,6 +1246,10 @@ class Context { if (executableAllocator) { executableAllocator->free(executableStart, executableSize); } + + eventLog.dispose(); + + zone.dispose(); } MyThread* thread; @@ -1268,6 +1274,7 @@ class Context { bool leaf; Vector eventLog; MyProtector protector; + MyResource resource; }; unsigned @@ -2232,27 +2239,109 @@ void compile(MyThread* t, FixedAllocator* allocator, BootContext* bootContext, object method); +object +resolveMethod(Thread* t, object pair) +{ + object reference = pairSecond(t, pair); + PROTECT(t, reference); + + object class_ = resolveClassInObject + (t, classLoader(t, methodClass(t, pairFirst(t, pair))), reference, + ReferenceClass); + + return findInHierarchy + (t, class_, referenceName(t, reference), referenceSpec(t, reference), + findMethodInClass, Machine::NoSuchMethodErrorType); +} + +int64_t +prepareMethodForCall(MyThread* t, object target) +{ + if (unresolved(t, methodAddress(t, target))) { + PROTECT(t, target); + + compile(t, codeAllocator(t), 0, target); + } + + if (methodFlags(t, target) & ACC_NATIVE) { + t->trace->nativeMethod = target; + } + return methodAddress(t, target); +} + int64_t findInterfaceMethodFromInstance(MyThread* t, object method, object instance) { if (instance) { - object target = findInterfaceMethod(t, method, objectClass(t, instance)); - - if (unresolved(t, methodAddress(t, target))) { - PROTECT(t, target); - - compile(t, codeAllocator(t), 0, target); - } - - if (methodFlags(t, target) & ACC_NATIVE) { - t->trace->nativeMethod = target; - } - return methodAddress(t, target); + return prepareMethodForCall + (t, findInterfaceMethod(t, method, objectClass(t, instance))); } else { throwNew(t, Machine::NullPointerExceptionType); } } +int64_t +findInterfaceMethodFromInstanceAndReference +(MyThread* t, object pair, object instance) +{ + PROTECT(t, instance); + + object method = resolveMethod(t, pair); + + return findInterfaceMethodFromInstance(t, method, instance); +} + +int64_t +findSpecialMethodFromReference(MyThread* t, object pair) +{ + PROTECT(t, pair); + + object target = resolveMethod(t, pair); + + object class_ = methodClass(t, pairFirst(t, pair)); + if (isSpecialMethod(t, target, class_)) { + target = findVirtualMethod(t, target, classSuper(t, class_)); + } + + assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); + + return prepareMethodForCall(t, target); +} + +int64_t +findStaticMethodFromReference(MyThread* t, object pair) +{ + object target = resolveMethod(t, pair); + + assert(t, methodFlags(t, target) & ACC_STATIC); + + return prepareMethodForCall(t, target); +} + +int64_t +findVirtualMethodFromReference(MyThread* t, object pair, object instance) +{ + PROTECT(t, instance); + + object target = resolveMethod(t, pair); + + target = findVirtualMethod(t, target, objectClass(t, instance)); + + assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); + + return prepareMethodForCall(t, target); +} + +int64_t +getJClassFromReference(MyThread* t, object pair) +{ + return reinterpret_cast + (getJClass + (t, resolveClass + (t, classLoader(t, methodClass(t, pairFirst(t, pair))), + referenceName(t, pairSecond(t, pair))))); +} + int64_t compareDoublesG(uint64_t bi, uint64_t ai) { @@ -2575,6 +2664,16 @@ makeBlankObjectArray(MyThread* t, object class_, int32_t length) } } +uint64_t +makeBlankObjectArrayFromReference(MyThread* t, object pair, + int32_t length) +{ + return makeBlankObjectArray + (t, resolveClass + (t, classLoader(t, methodClass(t, pairFirst(t, pair))), + referenceName(t, pairSecond(t, pair))), length); +} + uint64_t makeBlankArray(MyThread* t, unsigned type, int32_t length) { @@ -2709,6 +2808,17 @@ makeMultidimensionalArray(MyThread* t, object class_, int32_t dimensions, (t, class_, static_cast(t->stack) + offset, dimensions)); } +uint64_t +makeMultidimensionalArrayFromReference(MyThread* t, object pair, + int32_t dimensions, + int32_t offset) +{ + return makeMultidimensionalArray + (t, resolveClass + (t, classLoader(t, methodClass(t, pairFirst(t, pair))), + referenceName(t, pairSecond(t, pair))), dimensions, offset); +} + void NO_RETURN throwArrayIndexOutOfBounds(MyThread* t) { @@ -2751,12 +2861,206 @@ checkCast(MyThread* t, object class_, object o) } } +void +checkCastFromReference(MyThread* t, object pair, object o) +{ + PROTECT(t, o); + + object c = resolveClass + (t, classLoader(t, methodClass(t, pairFirst(t, pair))), + referenceName(t, pairSecond(t, pair))); + + checkCast(t, c, o); +} + +object +resolveField(Thread* t, object pair) +{ + object reference = pairSecond(t, pair); + PROTECT(t, reference); + + object class_ = resolveClassInObject + (t, classLoader(t, methodClass(t, pairFirst(t, pair))), reference, + ReferenceClass); + + return findInHierarchy + (t, class_, referenceName(t, reference), referenceSpec(t, reference), + findFieldInClass, Machine::NoSuchFieldErrorType); +} + +uint64_t +getFieldValue(Thread* t, object target, object field) +{ + switch (fieldCode(t, field)) { + case ByteField: + case BooleanField: + return cast(target, fieldOffset(t, field)); + + case CharField: + case ShortField: + return cast(target, fieldOffset(t, field)); + + case FloatField: + case IntField: + return cast(target, fieldOffset(t, field)); + + case DoubleField: + case LongField: + return cast(target, fieldOffset(t, field)); + + case ObjectField: + return cast(target, fieldOffset(t, field)); + + default: + abort(t); + } +} + +uint64_t +getStaticFieldValueFromReference(MyThread* t, object pair) +{ + object field = resolveField(t, pair); + PROTECT(t, field); + + ACQUIRE_FIELD_FOR_READ(t, field); + + return getFieldValue(t, classStaticTable(t, fieldClass(t, field)), field); +} + +uint64_t +getFieldValueFromReference(MyThread* t, object pair, object instance) +{ + PROTECT(t, instance); + + object field = resolveField(t, pair); + PROTECT(t, field); + + ACQUIRE_FIELD_FOR_READ(t, field); + + return getFieldValue(t, instance, field); +} + +void +setStaticLongFieldValueFromReference(MyThread* t, object pair, uint64_t value) +{ + object field = resolveField(t, pair); + PROTECT(t, field); + + ACQUIRE_FIELD_FOR_WRITE(t, field); + + cast + (classStaticTable(t, fieldClass(t, field)), fieldOffset(t, field)) = value; +} + +void +setLongFieldValueFromReference(MyThread* t, object pair, object instance, + uint64_t value) +{ + PROTECT(t, instance); + + object field = resolveField(t, pair); + PROTECT(t, field); + + ACQUIRE_FIELD_FOR_WRITE(t, field); + + cast(instance, fieldOffset(t, field)) = value; +} + +void +setStaticObjectFieldValueFromReference(MyThread* t, object pair, object value) +{ + PROTECT(t, value); + + object field = resolveField(t, pair); + PROTECT(t, field); + + ACQUIRE_FIELD_FOR_WRITE(t, field); + + set(t, classStaticTable(t, fieldClass(t, field)), fieldOffset(t, field), + value); +} + +void +setObjectFieldValueFromReference(MyThread* t, object pair, object instance, + object value) +{ + PROTECT(t, instance); + PROTECT(t, value); + + object field = resolveField(t, pair); + PROTECT(t, field); + + ACQUIRE_FIELD_FOR_WRITE(t, field); + + set(t, instance, fieldOffset(t, field), value); +} + +void +setFieldValue(MyThread* t, object target, object field, uint32_t value) +{ + switch (fieldCode(t, field)) { + case ByteField: + case BooleanField: + cast(target, fieldOffset(t, field)) = value; + break; + + case CharField: + case ShortField: + cast(target, fieldOffset(t, field)) = value; + break; + + case FloatField: + case IntField: + cast(target, fieldOffset(t, field)) = value; + break; + + default: + abort(t); + } +} + +void +setStaticFieldValueFromReference(MyThread* t, object pair, uint32_t value) +{ + object field = resolveField(t, pair); + PROTECT(t, field); + + ACQUIRE_FIELD_FOR_WRITE(t, field); + + setFieldValue(t, classStaticTable(t, fieldClass(t, field)), field, value); +} + +void +setFieldValueFromReference(MyThread* t, object pair, object instance, + uint32_t value) +{ + PROTECT(t, instance); + object field = resolveField(t, pair); + PROTECT(t, field); + + ACQUIRE_FIELD_FOR_WRITE(t, field); + + setFieldValue(t, instance, field, value); +} + uint64_t instanceOf64(Thread* t, object class_, object o) { return instanceOf(t, class_, o); } +uint64_t +instanceOfFromReference(Thread* t, object pair, object o) +{ + PROTECT(t, o); + + object c = resolveClass + (t, classLoader(t, methodClass(t, pairFirst(t, pair))), + referenceName(t, pairSecond(t, pair))); + + return instanceOf64(t, c, o); +} + uint64_t makeNewGeneral64(Thread* t, object class_) { @@ -2769,6 +3073,15 @@ makeNew64(Thread* t, object class_) return reinterpret_cast(makeNew(t, class_)); } +uint64_t +makeNewFromReference(Thread* t, object pair) +{ + return makeNewGeneral64 + (t, resolveClass + (t, classLoader(t, methodClass(t, pairFirst(t, pair))), + referenceName(t, pairSecond(t, pair)))); +} + uint64_t getJClass64(Thread* t, object class_) { @@ -2837,6 +3150,29 @@ pushReturnValue(MyThread* t, Frame* frame, unsigned code, } } +Compiler::Operand* +popField(MyThread* t, Frame* frame, int code) +{ + switch (code) { + case ByteField: + case BooleanField: + case CharField: + case ShortField: + case FloatField: + case IntField: + return frame->popInt(); + + case DoubleField: + case LongField: + return frame->popLong(); + + case ObjectField: + return frame->popObject(); + + default: abort(t); + } +} + Compiler::OperandType operandTypeForFieldCode(Thread* t, unsigned code) { @@ -3004,6 +3340,74 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target, bool tailCall) return tailCall; } +unsigned +methodReferenceParameterFootprint(Thread* t, object reference, bool isStatic) +{ + return parameterFootprint + (t, reinterpret_cast + (&byteArrayBody(t, referenceSpec(t, reference), 0)), isStatic); +} + +int +methodReferenceReturnCode(Thread* t, object reference) +{ + unsigned parameterCount; + unsigned returnCode; + scanMethodSpec + (t, reinterpret_cast + (&byteArrayBody(t, referenceSpec(t, reference), 0)), ¶meterCount, + &returnCode); + + return returnCode; +} + +void +compileReferenceInvoke(MyThread* t, Frame* frame, Compiler::Operand* method, + object reference, bool isStatic, bool tailCall) +{ + unsigned parameterFootprint + = methodReferenceParameterFootprint(t, reference, isStatic); + + int returnCode = methodReferenceReturnCode(t, reference); + + unsigned rSize = resultSize(t, returnCode); + + Compiler::Operand* result = frame->c->stackCall + (method, + tailCall ? Compiler::TailJump : 0, + frame->trace(0, 0), + rSize, + operandTypeForFieldCode(t, returnCode), + parameterFootprint); + + frame->pop(parameterFootprint); + + if (rSize) { + pushReturnValue(t, frame, returnCode, result); + } +} + +void +compileDirectReferenceInvoke(MyThread* t, Frame* frame, Thunk thunk, + object reference, bool isStatic, bool tailCall) +{ + Compiler* c = frame->c; + + PROTECT(t, reference); + + object pair = makePair(t, frame->context->method, reference); + + compileReferenceInvoke + (t, frame, c->call + (c->constant(getThunk(t, thunk), Compiler::AddressType), + 0, + frame->trace(0, 0), + BytesPerWord, + Compiler::AddressType, + 2, c->register_(t->arch->thread()), frame->append(pair)), + reference, isStatic, tailCall); +} + void handleMonitorEvent(MyThread* t, Frame* frame, intptr_t function) { @@ -3113,17 +3517,32 @@ returnsNext(MyThread* t, object code, unsigned ip) } bool -isTailCall(MyThread* t, object code, unsigned ip, object caller, object callee) +isTailCall(MyThread* t, object code, unsigned ip, object caller, + int calleeReturnCode) { return TailCalls and ((methodFlags(t, caller) & ACC_SYNCHRONIZED) == 0) and (not inTryBlock(t, code, ip - 1)) and (not needsReturnBarrier(t, caller)) and (methodReturnCode(t, caller) == VoidField - or methodReturnCode(t, caller) == methodReturnCode(t, callee)) + or methodReturnCode(t, caller) == calleeReturnCode) and returnsNext(t, code, ip); } +bool +isTailCall(MyThread* t, object code, unsigned ip, object caller, object callee) +{ + return isTailCall(t, code, ip, caller, methodReturnCode(t, callee)); +} + +bool +isReferenceTailCall(MyThread* t, object code, unsigned ip, object caller, + object calleeReference) +{ + return isTailCall + (t, code, ip, caller, methodReferenceReturnCode(t, calleeReference)); +} + void compile(MyThread* t, Frame* initialFrame, unsigned ip, int exceptionHandlerStart = -1); @@ -3524,19 +3943,34 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case anewarray: { uint16_t index = codeReadInt16(t, code, ip); - object class_ = resolveClassInPool(t, context->method, index - 1); + object reference = singletonObject + (t, codePool(t, methodCode(t, context->method)), index - 1); + + PROTECT(t, reference); + + object class_ = resolveClassInPool(t, context->method, index - 1, false); Compiler::Operand* length = frame->popInt(); + object argument; + Thunk thunk; + if (LIKELY(class_)) { + argument = class_; + thunk = makeBlankObjectArrayThunk; + } else { + argument = makePair(t, context->method, reference); + thunk = makeBlankObjectArrayFromReferenceThunk; + } + frame->pushObject (c->call - (c->constant - (getThunk(t, makeBlankObjectArrayThunk), Compiler::AddressType), + (c->constant(getThunk(t, thunk), Compiler::AddressType), 0, frame->trace(0, 0), BytesPerWord, Compiler::ObjectType, - 3, c->register_(t->arch->thread()), frame->append(class_), length)); + 3, c->register_(t->arch->thread()), frame->append(argument), + length)); } break; case areturn: { @@ -3594,17 +4028,33 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case checkcast: { uint16_t index = codeReadInt16(t, code, ip); - object class_ = resolveClassInPool(t, context->method, index - 1); + object reference = singletonObject + (t, codePool(t, methodCode(t, context->method)), index - 1); + + PROTECT(t, reference); + + object class_ = resolveClassInPool(t, context->method, index - 1, false); + + object argument; + Thunk thunk; + if (LIKELY(class_)) { + argument = class_; + thunk = checkCastThunk; + } else { + argument = makePair(t, context->method, reference); + thunk = checkCastFromReferenceThunk; + } Compiler::Operand* instance = c->peek(1, 0); c->call - (c->constant(getThunk(t, checkCastThunk), Compiler::AddressType), + (c->constant(getThunk(t, thunk), Compiler::AddressType), 0, frame->trace(0, 0), 0, Compiler::VoidType, - 3, c->register_(t->arch->thread()), frame->append(class_), instance); + 3, c->register_(t->arch->thread()), frame->append(argument), + instance); } break; case d2f: { @@ -3813,140 +4263,177 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case getstatic: { uint16_t index = codeReadInt16(t, code, ip); - object field = resolveField(t, context->method, index - 1); + object reference = singletonObject + (t, codePool(t, methodCode(t, context->method)), index - 1); - if ((fieldFlags(t, field) & ACC_VOLATILE) - and BytesPerWord == 4 - and (fieldCode(t, field) == DoubleField - or fieldCode(t, field) == LongField)) - { - PROTECT(t, field); + PROTECT(t, reference); - c->call - (c->constant - (getThunk(t, acquireMonitorForObjectThunk), Compiler::AddressType), - 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, - c->register_(t->arch->thread()), - frame->append(field)); - } + object field = resolveField(t, context->method, index - 1, false); - Compiler::Operand* table; - - 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))) - { - c->call - (c->constant - (getThunk(t, tryInitClassThunk), Compiler::AddressType), - 0, - frame->trace(0, 0), - 0, - Compiler::VoidType, - 2, c->register_(t->arch->thread()), - frame->append(fieldClass(t, field))); - } - - table = frame->append(classStaticTable(t, fieldClass(t, field))); - } else { - assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0); - - table = frame->popObject(); - - if (inTryBlock(t, code, ip - 3)) { - c->saveLocals(); - frame->trace(0, 0); - } - } - - switch (fieldCode(t, field)) { - case ByteField: - case BooleanField: - frame->pushInt - (c->load - (1, 1, c->memory - (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1), - BytesPerWord)); - break; - - case CharField: - frame->pushInt - (c->loadz - (2, 2, c->memory - (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1), - BytesPerWord)); - break; - - case ShortField: - frame->pushInt - (c->load - (2, 2, c->memory - (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1), - BytesPerWord)); - break; - - case FloatField: - frame->pushInt - (c->load - (4, 4, c->memory - (table, Compiler::FloatType, fieldOffset(t, field), 0, 1), - BytesPerWord)); - break; - - case IntField: - frame->pushInt - (c->load - (4, 4, c->memory - (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1), - BytesPerWord)); - break; - - case DoubleField: - frame->pushLong - (c->load - (8, 8, c->memory - (table, Compiler::FloatType, fieldOffset(t, field), 0, 1), 8)); - break; - - case LongField: - frame->pushLong - (c->load - (8, 8, c->memory - (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1), 8)); - break; - - case ObjectField: - frame->pushObject - (c->load - (BytesPerWord, BytesPerWord, - c->memory - (table, Compiler::ObjectType, fieldOffset(t, field), 0, 1), - BytesPerWord)); - break; - - default: - abort(t); - } - - if (fieldFlags(t, field) & ACC_VOLATILE) { - if (BytesPerWord == 4 + if (LIKELY(field)) { + if ((fieldFlags(t, field) & ACC_VOLATILE) + and BytesPerWord == 4 and (fieldCode(t, field) == DoubleField or fieldCode(t, field) == LongField)) { + PROTECT(t, field); + c->call (c->constant - (getThunk(t, releaseMonitorForObjectThunk), - Compiler::AddressType), + (getThunk(t, acquireMonitorForObjectThunk), Compiler::AddressType), 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, c->register_(t->arch->thread()), frame->append(field)); - } else { - c->loadBarrier(); } + + Compiler::Operand* table; + + 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))) + { + c->call + (c->constant + (getThunk(t, tryInitClassThunk), Compiler::AddressType), + 0, + frame->trace(0, 0), + 0, + Compiler::VoidType, + 2, c->register_(t->arch->thread()), + frame->append(fieldClass(t, field))); + } + + table = frame->append(classStaticTable(t, fieldClass(t, field))); + } else { + assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0); + + table = frame->popObject(); + + if (inTryBlock(t, code, ip - 3)) { + c->saveLocals(); + frame->trace(0, 0); + } + } + + switch (fieldCode(t, field)) { + case ByteField: + case BooleanField: + frame->pushInt + (c->load + (1, 1, c->memory + (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1), + BytesPerWord)); + break; + + case CharField: + frame->pushInt + (c->loadz + (2, 2, c->memory + (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1), + BytesPerWord)); + break; + + case ShortField: + frame->pushInt + (c->load + (2, 2, c->memory + (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1), + BytesPerWord)); + break; + + case FloatField: + frame->pushInt + (c->load + (4, 4, c->memory + (table, Compiler::FloatType, fieldOffset(t, field), 0, 1), + BytesPerWord)); + break; + + case IntField: + frame->pushInt + (c->load + (4, 4, c->memory + (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1), + BytesPerWord)); + break; + + case DoubleField: + frame->pushLong + (c->load + (8, 8, c->memory + (table, Compiler::FloatType, fieldOffset(t, field), 0, 1), 8)); + break; + + case LongField: + frame->pushLong + (c->load + (8, 8, c->memory + (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1), 8)); + break; + + case ObjectField: + frame->pushObject + (c->load + (BytesPerWord, BytesPerWord, + c->memory + (table, Compiler::ObjectType, fieldOffset(t, field), 0, 1), + BytesPerWord)); + break; + + default: + abort(t); + } + + if (fieldFlags(t, field) & ACC_VOLATILE) { + if (BytesPerWord == 4 + and (fieldCode(t, field) == DoubleField + or fieldCode(t, field) == LongField)) + { + c->call + (c->constant + (getThunk(t, releaseMonitorForObjectThunk), + Compiler::AddressType), + 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, + c->register_(t->arch->thread()), + frame->append(field)); + } else { + c->loadBarrier(); + } + } + } else { + int fieldCode = vm::fieldCode + (t, byteArrayBody(t, referenceSpec(t, reference), 0)); + + object pair = makePair(t, context->method, reference); + + unsigned rSize = resultSize(t, fieldCode); + Compiler::OperandType rType = operandTypeForFieldCode(t, fieldCode); + + Compiler::Operand* result; + if (instruction == getstatic) { + result = c->call + (c->constant + (getThunk(t, getStaticFieldValueFromReferenceThunk), + Compiler::AddressType), + 0, frame->trace(0, 0), rSize, rType, 2, + c->register_(t->arch->thread()), frame->append(pair)); + } else { + Compiler::Operand* instance = frame->popObject(); + + result = c->call + (c->constant + (getThunk(t, getFieldValueFromReferenceThunk), + Compiler::AddressType), + 0, frame->trace(0, 0), rSize, rType, 3, + c->register_(t->arch->thread()), frame->append(pair), + instance); + } + + pushReturnValue(t, frame, fieldCode, result); } } break; @@ -4213,14 +4700,34 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case instanceof: { uint16_t index = codeReadInt16(t, code, ip); - object class_ = resolveClassInPool(t, context->method, index - 1); + object reference = singletonObject + (t, codePool(t, methodCode(t, context->method)), index - 1); + + PROTECT(t, reference); + + object class_ = resolveClassInPool(t, context->method, index - 1, false); + + Compiler::Operand* instance = frame->popObject(); + + object argument; + Thunk thunk; + TraceElement* trace; + if (LIKELY(class_)) { + argument = class_; + thunk = instanceOf64Thunk; + trace = 0; + } else { + argument = makePair(t, context->method, reference); + thunk = instanceOfFromReferenceThunk; + trace = frame->trace(0, 0); + } frame->pushInt (c->call - (c->constant(getThunk(t, instanceOf64Thunk), Compiler::AddressType), - 0, 0, 4, Compiler::IntegerType, - 3, c->register_(t->arch->thread()), frame->append(class_), - frame->popObject())); + (c->constant(getThunk(t, thunk), Compiler::AddressType), + 0, trace, 4, Compiler::IntegerType, + 3, c->register_(t->arch->thread()), frame->append(argument), + instance)); } break; case invokeinterface: { @@ -4229,30 +4736,48 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint16_t index = codeReadInt16(t, code, ip); ip += 2; - object target = resolveMethod(t, context->method, index - 1); + object reference = singletonObject + (t, codePool(t, methodCode(t, context->method)), index - 1); - assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); + PROTECT(t, reference); - unsigned parameterFootprint = methodParameterFootprint(t, target); + object target = resolveMethod(t, context->method, index - 1, false); - unsigned instance = parameterFootprint - 1; + object argument; + Thunk thunk; + unsigned parameterFootprint; + int returnCode; + bool tailCall; + if (LIKELY(target)) { + assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); - int returnCode = methodReturnCode(t, target); + argument = target; + thunk = findInterfaceMethodFromInstanceThunk; + parameterFootprint = methodParameterFootprint(t, target); + returnCode = methodReturnCode(t, target); + tailCall = isTailCall(t, code, ip, context->method, target); + } else { + argument = makePair(t, context->method, reference); + thunk = findInterfaceMethodFromInstanceAndReferenceThunk; + parameterFootprint = methodReferenceParameterFootprint + (t, reference, false); + returnCode = methodReferenceReturnCode(t, reference); + tailCall = isReferenceTailCall + (t, code, ip, context->method, reference); + } unsigned rSize = resultSize(t, returnCode); Compiler::Operand* result = c->stackCall (c->call - (c->constant - (getThunk(t, findInterfaceMethodFromInstanceThunk), - Compiler::AddressType), + (c->constant(getThunk(t, thunk), Compiler::AddressType), 0, frame->trace(0, 0), BytesPerWord, Compiler::AddressType, - 3, c->register_(t->arch->thread()), frame->append(target), - c->peek(1, instance)), - 0, + 3, c->register_(t->arch->thread()), frame->append(argument), + c->peek(1, parameterFootprint - 1)), + tailCall ? Compiler::TailJump : 0, frame->trace(0, 0), rSize, operandTypeForFieldCode(t, returnCode), @@ -4269,18 +4794,30 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, context->leaf = false; uint16_t index = codeReadInt16(t, code, ip); - object target = resolveMethod(t, context->method, index - 1); - object class_ = methodClass(t, context->method); - if (isSpecialMethod(t, target, class_)) { - target = findVirtualMethod(t, target, classSuper(t, class_)); + object reference = singletonObject + (t, codePool(t, methodCode(t, context->method)), index - 1); + + PROTECT(t, reference); + + object target = resolveMethod(t, context->method, index - 1, false); + + if (LIKELY(target)) { + object class_ = methodClass(t, context->method); + if (isSpecialMethod(t, target, class_)) { + target = findVirtualMethod(t, target, classSuper(t, class_)); + } + + assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); + + bool tailCall = isTailCall(t, code, ip, context->method, target); + + compileDirectInvoke(t, frame, target, tailCall); + } else { + compileDirectReferenceInvoke + (t, frame, findSpecialMethodFromReferenceThunk, reference, false, + isReferenceTailCall(t, code, ip, context->method, reference)); } - - assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); - - bool tailCall = isTailCall(t, code, ip, context->method, target); - - compileDirectInvoke(t, frame, target, tailCall); } break; case invokestatic: { @@ -4288,13 +4825,24 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint16_t index = codeReadInt16(t, code, ip); - object target = resolveMethod(t, context->method, index - 1); + object reference = singletonObject + (t, codePool(t, methodCode(t, context->method)), index - 1); - assert(t, methodFlags(t, target) & ACC_STATIC); + PROTECT(t, reference); - if (not intrinsic(t, frame, target)) { - bool tailCall = isTailCall(t, code, ip, context->method, target); - compileDirectInvoke(t, frame, target, tailCall); + object target = resolveMethod(t, context->method, index - 1, false); + + if (LIKELY(target)) { + assert(t, methodFlags(t, target) & ACC_STATIC); + + if (not intrinsic(t, frame, target)) { + bool tailCall = isTailCall(t, code, ip, context->method, target); + compileDirectInvoke(t, frame, target, tailCall); + } + } else { + compileDirectReferenceInvoke + (t, frame, findStaticMethodFromReferenceThunk, reference, true, + isReferenceTailCall(t, code, ip, context->method, reference)); } } break; @@ -4303,36 +4851,62 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint16_t index = codeReadInt16(t, code, ip); - object target = resolveMethod(t, context->method, index - 1); + object reference = singletonObject + (t, codePool(t, methodCode(t, context->method)), index - 1); - assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); + PROTECT(t, reference); - unsigned parameterFootprint = methodParameterFootprint(t, target); + object target = resolveMethod(t, context->method, index - 1, false); - unsigned offset = ClassVtable + (methodOffset(t, target) * BytesPerWord); + if (LIKELY(target)) { + assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); - Compiler::Operand* instance = c->peek(1, parameterFootprint - 1); + unsigned parameterFootprint = methodParameterFootprint(t, target); - unsigned rSize = resultSize(t, methodReturnCode(t, target)); + unsigned offset = ClassVtable + + (methodOffset(t, target) * BytesPerWord); - bool tailCall = isTailCall(t, code, ip, context->method, target); + Compiler::Operand* instance = c->peek(1, parameterFootprint - 1); - Compiler::Operand* result = c->stackCall - (c->memory - (c->and_ - (BytesPerWord, c->constant(PointerMask, Compiler::IntegerType), - c->memory(instance, Compiler::ObjectType, 0, 0, 1)), - Compiler::ObjectType, offset, 0, 1), - tailCall ? Compiler::TailJump : 0, - frame->trace(0, 0), - rSize, - operandTypeForFieldCode(t, methodReturnCode(t, target)), - parameterFootprint); + unsigned rSize = resultSize(t, methodReturnCode(t, target)); - frame->pop(parameterFootprint); + bool tailCall = isTailCall(t, code, ip, context->method, target); - if (rSize) { - pushReturnValue(t, frame, methodReturnCode(t, target), result); + Compiler::Operand* result = c->stackCall + (c->memory + (c->and_ + (BytesPerWord, c->constant(PointerMask, Compiler::IntegerType), + c->memory(instance, Compiler::ObjectType, 0, 0, 1)), + Compiler::ObjectType, offset, 0, 1), + tailCall ? Compiler::TailJump : 0, + frame->trace(0, 0), + rSize, + operandTypeForFieldCode(t, methodReturnCode(t, target)), + parameterFootprint); + + frame->pop(parameterFootprint); + + if (rSize) { + pushReturnValue(t, frame, methodReturnCode(t, target), result); + } + } else { + PROTECT(t, reference); + + object pair = makePair(t, context->method, reference); + + compileReferenceInvoke + (t, frame, c->call + (c->constant(getThunk(t, findVirtualMethodFromReferenceThunk), + Compiler::AddressType), + 0, + frame->trace(0, 0), + BytesPerWord, + Compiler::AddressType, + 3, c->register_(t->arch->thread()), frame->append(pair), + c->peek(1, methodReferenceParameterFootprint + (t, reference, false) - 1)), + reference, false, isReferenceTailCall + (t, code, ip, context->method, reference)); } } break; @@ -4502,22 +5076,44 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (singletonIsObject(t, pool, index - 1)) { object v = singletonObject(t, pool, index - 1); + + loadMemoryBarrier(); + if (objectClass(t, v) == type(t, Machine::ReferenceType)) { - v = resolveClassInPool(t, context->method, index - 1); + object reference = v; + PROTECT(t, reference); + + v = resolveClassInPool(t, context->method, index - 1, false); + + if (UNLIKELY(v == 0)) { + frame->pushObject + (c->call + (c->constant + (getThunk(t, getJClassFromReferenceThunk), + Compiler::AddressType), + 0, + frame->trace(0, 0), + BytesPerWord, + Compiler::ObjectType, + 2, c->register_(t->arch->thread()), + frame->append(makePair(t, context->method, reference)))); + } } - if (objectClass(t, v) == type(t, Machine::ClassType)) { - frame->pushObject - (c->call - (c->constant - (getThunk(t, getJClass64Thunk), 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)); + if (v) { + if (objectClass(t, v) == type(t, Machine::ClassType)) { + frame->pushObject + (c->call + (c->constant + (getThunk(t, getJClass64Thunk), 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)); + } } } else { frame->pushInt @@ -4746,8 +5342,22 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint16_t index = codeReadInt16(t, code, ip); uint8_t dimensions = codeBody(t, code, ip++); - object class_ = resolveClassInPool(t, context->method, index - 1); - PROTECT(t, class_); + object reference = singletonObject + (t, codePool(t, methodCode(t, context->method)), index - 1); + + PROTECT(t, reference); + + object class_ = resolveClassInPool(t, context->method, index - 1, false); + + object argument; + Thunk thunk; + if (LIKELY(class_)) { + argument = class_; + thunk = makeMultidimensionalArrayThunk; + } else { + argument = makePair(t, context->method, reference); + thunk = makeMultidimensionalArrayFromReferenceThunk; + } unsigned offset = localOffset @@ -4756,12 +5366,12 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* result = c->call (c->constant - (getThunk(t, makeMultidimensionalArrayThunk), Compiler::AddressType), + (getThunk(t, thunk), Compiler::AddressType), 0, frame->trace(0, 0), BytesPerWord, Compiler::ObjectType, - 4, c->register_(t->arch->thread()), frame->append(class_), + 4, c->register_(t->arch->thread()), frame->append(argument), c->constant(dimensions, Compiler::IntegerType), c->constant(offset, Compiler::IntegerType)); @@ -4772,28 +5382,35 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case new_: { uint16_t index = codeReadInt16(t, code, ip); - object class_ = resolveClassInPool(t, context->method, index - 1); + object reference = singletonObject + (t, codePool(t, methodCode(t, context->method)), index - 1); - if (classVmFlags(t, class_) & (WeakReferenceFlag | HasFinalizerFlag)) { - frame->pushObject - (c->call - (c->constant - (getThunk(t, makeNewGeneral64Thunk), Compiler::AddressType), - 0, - frame->trace(0, 0), - BytesPerWord, - Compiler::ObjectType, - 2, c->register_(t->arch->thread()), frame->append(class_))); + PROTECT(t, reference); + + object class_ = resolveClassInPool(t, context->method, index - 1, false); + + object argument; + Thunk thunk; + if (LIKELY(class_)) { + argument = class_; + if (classVmFlags(t, class_) & (WeakReferenceFlag | HasFinalizerFlag)) { + thunk = makeNewGeneral64Thunk; + } else { + thunk = makeNew64Thunk; + } } else { - frame->pushObject - (c->call - (c->constant(getThunk(t, makeNew64Thunk), Compiler::AddressType), - 0, - frame->trace(0, 0), - BytesPerWord, - Compiler::ObjectType, - 2, c->register_(t->arch->thread()), frame->append(class_))); + argument = makePair(t, context->method, reference); + thunk = makeNewFromReferenceThunk; } + + frame->pushObject + (c->call + (c->constant(getThunk(t, thunk), Compiler::AddressType), + 0, + frame->trace(0, 0), + BytesPerWord, + Compiler::ObjectType, + 2, c->register_(t->arch->thread()), frame->append(argument))); } break; case newarray: { @@ -4826,165 +5443,237 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case putstatic: { uint16_t index = codeReadInt16(t, code, ip); - object field = resolveField(t, context->method, index - 1); + object reference = singletonObject + (t, codePool(t, methodCode(t, context->method)), index - 1); - object staticTable = 0; + PROTECT(t, reference); - if (instruction == putstatic) { - assert(t, fieldFlags(t, field) & ACC_STATIC); + object field = resolveField(t, context->method, index - 1, false); - if (fieldClass(t, field) != methodClass(t, context->method) - and classNeedsInit(t, fieldClass(t, field))) - { - PROTECT(t, field); + if (LIKELY(field)) { + int fieldCode = vm::fieldCode(t, field); + Compiler::Operand* value = popField(t, frame, fieldCode); - c->call - (c->constant - (getThunk(t, tryInitClassThunk), Compiler::AddressType), - 0, - frame->trace(0, 0), - 0, - Compiler::VoidType, - 2, c->register_(t->arch->thread()), - frame->append(fieldClass(t, field))); - } + object staticTable = 0; - staticTable = classStaticTable(t, fieldClass(t, field)); - } else { - assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0); + if (instruction == putstatic) { + assert(t, fieldFlags(t, field) & ACC_STATIC); - if (inTryBlock(t, code, ip - 3)) { - c->saveLocals(); - frame->trace(0, 0); - } - } + if (fieldClass(t, field) != methodClass(t, context->method) + and classNeedsInit(t, fieldClass(t, field))) + { + PROTECT(t, field); - if (fieldFlags(t, field) & ACC_VOLATILE) { - if (BytesPerWord == 4 - and (fieldCode(t, field) == DoubleField - or fieldCode(t, field) == LongField)) - { - PROTECT(t, field); + c->call + (c->constant + (getThunk(t, tryInitClassThunk), Compiler::AddressType), + 0, + frame->trace(0, 0), + 0, + Compiler::VoidType, + 2, c->register_(t->arch->thread()), + frame->append(fieldClass(t, field))); + } - c->call - (c->constant - (getThunk(t, acquireMonitorForObjectThunk), - Compiler::AddressType), - 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, - c->register_(t->arch->thread()), frame->append(field)); + staticTable = classStaticTable(t, fieldClass(t, field)); } else { - c->storeStoreBarrier(); + assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0); + + if (inTryBlock(t, code, ip - 3)) { + c->saveLocals(); + frame->trace(0, 0); + } } - } - Compiler::Operand* value; - switch (fieldCode(t, field)) { - case ByteField: - case BooleanField: - case CharField: - case ShortField: - case FloatField: - case IntField: { - value = frame->popInt(); - } break; + Compiler::Operand* table; - case DoubleField: - case LongField: { - value = frame->popLong(); - } break; + if (instruction == putstatic) { + PROTECT(t, field); - case ObjectField: { - value = frame->popObject(); - } break; + table = frame->append(staticTable); + } else { + table = frame->popObject(); + } - default: abort(t); - } + if (fieldFlags(t, field) & ACC_VOLATILE) { + if (BytesPerWord == 4 + and (fieldCode == DoubleField or fieldCode == LongField)) + { + PROTECT(t, field); - Compiler::Operand* table; + c->call + (c->constant + (getThunk(t, acquireMonitorForObjectThunk), + Compiler::AddressType), + 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, + c->register_(t->arch->thread()), frame->append(field)); + } else { + c->storeStoreBarrier(); + } + } - if (instruction == putstatic) { - PROTECT(t, field); + switch (fieldCode) { + case ByteField: + case BooleanField: + c->store + (BytesPerWord, value, 1, c->memory + (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1)); + break; - table = frame->append(staticTable); - } else { - table = frame->popObject(); - } - - switch (fieldCode(t, field)) { - case ByteField: - case BooleanField: - c->store - (BytesPerWord, value, 1, c->memory - (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1)); - break; - - case CharField: - case ShortField: - c->store - (BytesPerWord, value, 2, c->memory - (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1)); - break; + case CharField: + case ShortField: + c->store + (BytesPerWord, value, 2, c->memory + (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1)); + break; - case FloatField: - c->store - (BytesPerWord, value, 4, c->memory - (table, Compiler::FloatType, fieldOffset(t, field), 0, 1)); - break; + case FloatField: + c->store + (BytesPerWord, value, 4, c->memory + (table, Compiler::FloatType, fieldOffset(t, field), 0, 1)); + break; - case IntField: - c->store - (BytesPerWord, value, 4, c->memory - (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1)); - break; + case IntField: + c->store + (BytesPerWord, value, 4, c->memory + (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1)); + break; - case DoubleField: - c->store - (8, value, 8, c->memory - (table, Compiler::FloatType, fieldOffset(t, field), 0, 1)); - break; + case DoubleField: + c->store + (8, value, 8, c->memory + (table, Compiler::FloatType, fieldOffset(t, field), 0, 1)); + break; - case LongField: - c->store - (8, value, 8, c->memory - (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1)); - break; + case LongField: + c->store + (8, value, 8, c->memory + (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1)); + break; - case ObjectField: - if (instruction == putfield) { - c->call - (c->constant - (getThunk(t, setMaybeNullThunk), Compiler::AddressType), - 0, - frame->trace(0, 0), - 0, - Compiler::VoidType, - 4, c->register_(t->arch->thread()), table, - c->constant(fieldOffset(t, field), Compiler::IntegerType), value); - } else { - c->call - (c->constant(getThunk(t, setThunk), Compiler::AddressType), - 0, 0, 0, Compiler::VoidType, - 4, c->register_(t->arch->thread()), table, - c->constant(fieldOffset(t, field), Compiler::IntegerType), value); + case ObjectField: + if (instruction == putfield) { + c->call + (c->constant + (getThunk(t, setMaybeNullThunk), Compiler::AddressType), + 0, + frame->trace(0, 0), + 0, + Compiler::VoidType, + 4, c->register_(t->arch->thread()), table, + c->constant(fieldOffset(t, field), Compiler::IntegerType), + value); + } else { + c->call + (c->constant(getThunk(t, setThunk), Compiler::AddressType), + 0, 0, 0, Compiler::VoidType, + 4, c->register_(t->arch->thread()), table, + c->constant(fieldOffset(t, field), Compiler::IntegerType), + value); + } + break; + + default: abort(t); } - break; - default: abort(t); - } + if (fieldFlags(t, field) & ACC_VOLATILE) { + if (BytesPerWord == 4 + and (fieldCode == DoubleField or fieldCode == LongField)) + { + c->call + (c->constant + (getThunk(t, releaseMonitorForObjectThunk), + Compiler::AddressType), + 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, + c->register_(t->arch->thread()), frame->append(field)); + } else { + c->storeLoadBarrier(); + } + } + } else { + int fieldCode = vm::fieldCode + (t, byteArrayBody(t, referenceSpec(t, reference), 0)); - if (fieldFlags(t, field) & ACC_VOLATILE) { - if (BytesPerWord == 4 - and (fieldCode(t, field) == DoubleField - or fieldCode(t, field) == LongField)) - { - c->call - (c->constant - (getThunk(t, releaseMonitorForObjectThunk), - Compiler::AddressType), - 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, - c->register_(t->arch->thread()), frame->append(field)); - } else { - c->storeLoadBarrier(); + Compiler::Operand* value = popField(t, frame, fieldCode); + unsigned rSize = resultSize(t, fieldCode); + Compiler::OperandType rType = operandTypeForFieldCode(t, fieldCode); + + object pair = makePair(t, context->method, reference); + + switch (fieldCode) { + case ByteField: + case BooleanField: + case CharField: + case ShortField: + case FloatField: + case IntField: { + if (instruction == putstatic) { + c->call + (c->constant + (getThunk(t, setStaticFieldValueFromReferenceThunk), + Compiler::AddressType), + 0, frame->trace(0, 0), rSize, rType, 3, + c->register_(t->arch->thread()), frame->append(pair), + value); + } else { + Compiler::Operand* instance = frame->popObject(); + + c->call + (c->constant + (getThunk(t, setFieldValueFromReferenceThunk), + Compiler::AddressType), + 0, frame->trace(0, 0), rSize, rType, 4, + c->register_(t->arch->thread()), frame->append(pair), + instance, value); + } + } break; + + case DoubleField: + case LongField: { + if (instruction == putstatic) { + c->call + (c->constant + (getThunk(t, setStaticLongFieldValueFromReferenceThunk), + Compiler::AddressType), + 0, frame->trace(0, 0), rSize, rType, 4, + c->register_(t->arch->thread()), frame->append(pair), + static_cast(0), value); + } else { + Compiler::Operand* instance = frame->popObject(); + + c->call + (c->constant + (getThunk(t, setLongFieldValueFromReferenceThunk), + Compiler::AddressType), + 0, frame->trace(0, 0), rSize, rType, 5, + c->register_(t->arch->thread()), frame->append(pair), + instance, static_cast(0), value); + } + } break; + + case ObjectField: { + if (instruction == putstatic) { + c->call + (c->constant + (getThunk(t, setStaticObjectFieldValueFromReferenceThunk), + Compiler::AddressType), + 0, frame->trace(0, 0), rSize, rType, 3, + c->register_(t->arch->thread()), frame->append(pair), + value); + } else { + Compiler::Operand* instance = frame->popObject(); + + c->call + (c->constant + (getThunk(t, setObjectFieldValueFromReferenceThunk), + Compiler::AddressType), + 0, frame->trace(0, 0), rSize, rType, 4, + c->register_(t->arch->thread()), frame->append(pair), + instance, value); + } + } break; + + default: abort(t); } } } break; diff --git a/src/interpret.cpp b/src/interpret.cpp index 3da5ca97d5..482859e21f 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -1460,27 +1460,11 @@ interpret3(Thread* t, const int base) assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0); - if (UNLIKELY((fieldFlags(t, field) & ACC_VOLATILE) - and BytesPerWord == 4 - and (fieldCode(t, field) == DoubleField - or fieldCode(t, field) == LongField))) - { - PROTECT(t, field); - acquire(t, field); - } + PROTECT(t, field); + + ACQUIRE_FIELD_FOR_READ(t, field); pushField(t, popObject(t), field); - - if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) { - if (BytesPerWord == 4 - and (fieldCode(t, field) == DoubleField - or fieldCode(t, field) == LongField)) - { - release(t, field); - } else { - loadMemoryBarrier(); - } - } } else { exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; @@ -1498,26 +1482,9 @@ interpret3(Thread* t, const int base) if (UNLIKELY(classInit(t, fieldClass(t, field), 3))) goto invoke; - if (UNLIKELY((fieldFlags(t, field) & ACC_VOLATILE) - and BytesPerWord == 4 - and (fieldCode(t, field) == DoubleField - or fieldCode(t, field) == LongField))) - { - acquire(t, field); - } + ACQUIRE_FIELD_FOR_READ(t, field); pushField(t, classStaticTable(t, fieldClass(t, field)), field); - - if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) { - if (BytesPerWord == 4 - and (fieldCode(t, field) == DoubleField - or fieldCode(t, field) == LongField)) - { - release(t, field); - } else { - loadMemoryBarrier(); - } - } } goto loop; case goto_: { @@ -2460,80 +2427,61 @@ interpret3(Thread* t, const int base) assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0); PROTECT(t, field); - if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) { - if (BytesPerWord == 4 - and (fieldCode(t, field) == DoubleField - or fieldCode(t, field) == LongField)) - { - acquire(t, field); - } else { - storeStoreMemoryBarrier(); - } - } + { ACQUIRE_FIELD_FOR_WRITE(t, field); - switch (fieldCode(t, field)) { - case ByteField: - case BooleanField: - case CharField: - case ShortField: - case FloatField: - case IntField: { - int32_t value = popInt(t); - object o = popObject(t); - if (LIKELY(o)) { - switch (fieldCode(t, field)) { - case ByteField: - case BooleanField: - cast(o, fieldOffset(t, field)) = value; - break; + switch (fieldCode(t, field)) { + case ByteField: + case BooleanField: + case CharField: + case ShortField: + case FloatField: + case IntField: { + int32_t value = popInt(t); + object o = popObject(t); + if (LIKELY(o)) { + switch (fieldCode(t, field)) { + case ByteField: + case BooleanField: + cast(o, fieldOffset(t, field)) = value; + break; - case CharField: - case ShortField: - cast(o, fieldOffset(t, field)) = value; - break; + case CharField: + case ShortField: + cast(o, fieldOffset(t, field)) = value; + break; - case FloatField: - case IntField: - cast(o, fieldOffset(t, field)) = value; - break; + case FloatField: + case IntField: + cast(o, fieldOffset(t, field)) = value; + break; + } + } else { + exception = makeThrowable(t, Machine::NullPointerExceptionType); } - } else { - exception = makeThrowable(t, Machine::NullPointerExceptionType); - } - } break; + } break; - case DoubleField: - case LongField: { - int64_t value = popLong(t); - object o = popObject(t); - if (LIKELY(o)) { - cast(o, fieldOffset(t, field)) = value; - } else { - exception = makeThrowable(t, Machine::NullPointerExceptionType); - } - } break; + case DoubleField: + case LongField: { + int64_t value = popLong(t); + object o = popObject(t); + if (LIKELY(o)) { + cast(o, fieldOffset(t, field)) = value; + } else { + exception = makeThrowable(t, Machine::NullPointerExceptionType); + } + } break; - case ObjectField: { - object value = popObject(t); - object o = popObject(t); - if (LIKELY(o)) { - set(t, o, fieldOffset(t, field), value); - } else { - exception = makeThrowable(t, Machine::NullPointerExceptionType); - } - } break; + case ObjectField: { + object value = popObject(t); + object o = popObject(t); + if (LIKELY(o)) { + set(t, o, fieldOffset(t, field), value); + } else { + exception = makeThrowable(t, Machine::NullPointerExceptionType); + } + } break; - default: abort(t); - } - - if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) { - if (BytesPerWord == 4 - and (fieldCode(t, field) == DoubleField - or fieldCode(t, field) == LongField)) - { - release(t, field); - } else { - storeLoadMemoryBarrier(); + default: abort(t); } } @@ -2551,16 +2499,7 @@ interpret3(Thread* t, const int base) PROTECT(t, field); - if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) { - if (BytesPerWord == 4 - and (fieldCode(t, field) == DoubleField - or fieldCode(t, field) == LongField)) - { - acquire(t, field); - } else { - storeStoreMemoryBarrier(); - } - } + ACQUIRE_FIELD_FOR_WRITE(t, field); if (UNLIKELY(classInit(t, fieldClass(t, field), 3))) goto invoke; @@ -2603,17 +2542,6 @@ interpret3(Thread* t, const int base) default: abort(t); } - - if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) { - if (BytesPerWord == 4 - and (fieldCode(t, field) == DoubleField - or fieldCode(t, field) == LongField)) - { - release(t, field); - } else { - storeLoadMemoryBarrier(); - } - } } goto loop; case ret: { diff --git a/src/machine.cpp b/src/machine.cpp index 7c1863c8f3..e1bf8aadec 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1075,6 +1075,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool) code, flags, 0, // offset + i, singletonObject(t, pool, name - 1), singletonObject(t, pool, spec - 1), addendum, @@ -1270,20 +1271,6 @@ parseCode(Thread* t, Stream& s, object pool) return code; } -void -scanMethodSpec(Thread* t, const char* s, unsigned* parameterCount, - unsigned* returnCode) -{ - unsigned count = 0; - MethodSpecIterator it(t, s); - for (; it.hasNext(); it.next()) { - ++ count; - } - - *parameterCount = count; - *returnCode = fieldCode(t, *it.returnSpec()); -} - object addInterfaceMethods(Thread* t, object class_, object virtualMap, unsigned* virtualCount, bool makeList) @@ -2225,6 +2212,17 @@ doCollect(Thread* t, Heap::CollectionType type) } } +uint64_t +invokeLoadClass(Thread* t, uintptr_t* arguments) +{ + object method = reinterpret_cast(arguments[0]); + object loader = reinterpret_cast(arguments[1]); + object specString = reinterpret_cast(arguments[2]); + + return reinterpret_cast + (t->m->processor->invoke(t, method, loader, specString)); +} + } // namespace namespace vm { @@ -3342,8 +3340,6 @@ resolveClass(Thread* t, object loader, object spec, bool throw_) if (objectClass(t, loader) == type(t, Machine::SystemClassLoaderType)) { return resolveSystemClass(t, loader, spec, throw_); } else { - expect(t, throw_); - PROTECT(t, loader); PROTECT(t, spec); @@ -3384,9 +3380,23 @@ resolveClass(Thread* t, object loader, object spec, bool throw_) object specString = makeString(t, "%s", RUNTIME_ARRAY_BODY(s)); - object jc = t->m->processor->invoke(t, method, loader, specString); + uintptr_t arguments[] = { reinterpret_cast(method), + reinterpret_cast(loader), + reinterpret_cast(specString) }; + + object jc = reinterpret_cast + (runRaw(t, invokeLoadClass, arguments)); + if (LIKELY(jc)) { c = jclassVmClass(t, jc); + } else if (t->exception) { + if (throw_) { + object e = t->exception; + t->exception = 0; + vm::throw_(t, e); + } else { + t->exception = 0; + } } } @@ -3402,12 +3412,12 @@ resolveClass(Thread* t, object loader, object spec, bool throw_) hashMapInsert (t, classLoaderMap(t, loader), spec, c, byteArrayHash); - - return c; - } else { + } else if (throw_) { throwNew(t, Machine::ClassNotFoundExceptionType, "%s", &byteArrayBody(t, spec, 0)); } + + return c; } } diff --git a/src/machine.h b/src/machine.h index b784d6072a..11c9b7ce11 100644 --- a/src/machine.h +++ b/src/machine.h @@ -33,6 +33,12 @@ #define ACQUIRE_OBJECT(t, x) \ ObjectMonitorResource MAKE_NAME(monitorResource_) (t, x) +#define ACQUIRE_FIELD_FOR_READ(t, field) \ + FieldReadResource MAKE_NAME(monitorResource_) (t, field) + +#define ACQUIRE_FIELD_FOR_WRITE(t, field) \ + FieldReadResource MAKE_NAME(monitorResource_) (t, field) + #define ACQUIRE_RAW(t, x) RawMonitorResource MAKE_NAME(monitorResource_) (t, x) #define ENTER(t, state) StateResource MAKE_NAME(stateResource_) (t, state) @@ -2430,6 +2436,20 @@ fieldSize(Thread* t, object field) return fieldSize(t, fieldCode(t, field)); } +inline void +scanMethodSpec(Thread* t, const char* s, unsigned* parameterCount, + unsigned* returnCode) +{ + unsigned count = 0; + MethodSpecIterator it(t, s); + for (; it.hasNext(); it.next()) { + ++ count; + } + + *parameterCount = count; + *returnCode = fieldCode(t, *it.returnSpec()); +} + object findLoadedClass(Thread* t, object loader, object spec); @@ -2639,11 +2659,11 @@ findInHierarchyOrNull(Thread* t, object class_, object name, object spec, inline object findInHierarchy(Thread* t, object class_, object name, object spec, object (*find)(Thread*, object, object, object), - Machine::Type errorType) + Machine::Type errorType, bool throw_ = true) { object o = findInHierarchyOrNull(t, class_, name, spec, find); - if (o == 0) { + if (throw_ and o == 0) { throwNew(t, errorType, "%s %s not found in %s", &byteArrayBody(t, name, 0), &byteArrayBody(t, spec, 0), @@ -3332,93 +3352,208 @@ poolSize(Thread* t, object pool) inline object resolveClassInObject(Thread* t, object loader, object container, - unsigned classOffset) + unsigned classOffset, bool throw_ = true) { object o = cast(container, classOffset); + + loadMemoryBarrier(); + if (objectClass(t, o) == type(t, Machine::ByteArrayType)) { PROTECT(t, container); - o = resolveClass(t, loader, o); + o = resolveClass(t, loader, o, throw_); - set(t, container, classOffset, o); + if (o) { + storeStoreMemoryBarrier(); + + set(t, container, classOffset, o); + } } return o; } inline object -resolveClassInPool(Thread* t, object loader, object method, unsigned index) +resolveClassInPool(Thread* t, object loader, object method, unsigned index, + bool throw_ = true) { object o = singletonObject(t, codePool(t, methodCode(t, method)), index); + + loadMemoryBarrier(); + if (objectClass(t, o) == type(t, Machine::ReferenceType)) { PROTECT(t, method); - o = resolveClass(t, loader, referenceName(t, o)); + o = resolveClass(t, loader, referenceName(t, o), throw_); - set(t, codePool(t, methodCode(t, method)), - SingletonBody + (index * BytesPerWord), o); + if (o) { + storeStoreMemoryBarrier(); + + set(t, codePool(t, methodCode(t, method)), + SingletonBody + (index * BytesPerWord), o); + } } return o; } inline object -resolveClassInPool(Thread* t, object method, unsigned index) +resolveClassInPool(Thread* t, object method, unsigned index, + bool throw_ = true) { return resolveClassInPool(t, classLoader(t, methodClass(t, method)), - method, index); + method, index, throw_); } inline object resolve(Thread* t, object loader, object method, unsigned index, object (*find)(vm::Thread*, object, object, object), - Machine::Type errorType) + Machine::Type errorType, bool throw_ = true) { object o = singletonObject(t, codePool(t, methodCode(t, method)), index); - if (objectClass(t, o) == type(t, Machine::ReferenceType)) - { + + loadMemoryBarrier(); + + if (objectClass(t, o) == type(t, Machine::ReferenceType)) { PROTECT(t, method); object reference = o; PROTECT(t, reference); - object class_ = resolveClassInObject(t, loader, o, ReferenceClass); + object class_ = resolveClassInObject(t, loader, o, ReferenceClass, throw_); - o = findInHierarchy - (t, class_, referenceName(t, reference), referenceSpec(t, reference), - find, errorType); + if (class_) { + o = findInHierarchy + (t, class_, referenceName(t, reference), referenceSpec(t, reference), + find, errorType, throw_); - set(t, codePool(t, methodCode(t, method)), - SingletonBody + (index * BytesPerWord), o); + if (o) { + storeStoreMemoryBarrier(); + + set(t, codePool(t, methodCode(t, method)), + SingletonBody + (index * BytesPerWord), o); + } + } else { + o = 0; + } } return o; } inline object -resolveField(Thread* t, object loader, object method, unsigned index) +resolveField(Thread* t, object loader, object method, unsigned index, + bool throw_ = true) { return resolve(t, loader, method, index, findFieldInClass, - Machine::NoSuchFieldErrorType); + Machine::NoSuchFieldErrorType, throw_); } inline object -resolveField(Thread* t, object method, unsigned index) +resolveField(Thread* t, object method, unsigned index, bool throw_ = true) { return resolveField - (t, classLoader(t, methodClass(t, method)), method, index); + (t, classLoader(t, methodClass(t, method)), method, index, throw_); } +inline void +acquireFieldForRead(Thread* t, object field) +{ + if (UNLIKELY((fieldFlags(t, field) & ACC_VOLATILE) + and BytesPerWord == 4 + and (fieldCode(t, field) == DoubleField + or fieldCode(t, field) == LongField))) + { + acquire(t, field); + } +} + +inline void +releaseFieldForRead(Thread* t, object field) +{ + if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) { + if (BytesPerWord == 4 + and (fieldCode(t, field) == DoubleField + or fieldCode(t, field) == LongField)) + { + release(t, field); + } else { + loadMemoryBarrier(); + } + } +} + +class FieldReadResource { + public: + FieldReadResource(Thread* t, object o): o(o), protector(t, &(this->o)) { + acquireFieldForRead(protector.t, o); + } + + ~FieldReadResource() { + releaseFieldForRead(protector.t, o); + } + + private: + object o; + Thread::SingleProtector protector; +}; + +inline void +acquireFieldForWrite(Thread* t, object field) +{ + if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) { + if (BytesPerWord == 4 + and (fieldCode(t, field) == DoubleField + or fieldCode(t, field) == LongField)) + { + acquire(t, field); + } else { + storeStoreMemoryBarrier(); + } + } +} + +inline void +releaseFieldForWrite(Thread* t, object field) +{ + if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) { + if (BytesPerWord == 4 + and (fieldCode(t, field) == DoubleField + or fieldCode(t, field) == LongField)) + { + release(t, field); + } else { + storeLoadMemoryBarrier(); + } + } +} + +class FieldWriteResource { + public: + FieldWriteResource(Thread* t, object o): o(o), protector(t, &(this->o)) { + acquireFieldForWrite(protector.t, o); + } + + ~FieldWriteResource() { + releaseFieldForWrite(protector.t, o); + } + + private: + object o; + Thread::SingleProtector protector; +}; + inline object -resolveMethod(Thread* t, object loader, object method, unsigned index) +resolveMethod(Thread* t, object loader, object method, unsigned index, + bool throw_ = true) { return resolve(t, loader, method, index, findMethodInClass, - Machine::NoSuchMethodErrorType); + Machine::NoSuchMethodErrorType, throw_); } inline object -resolveMethod(Thread* t, object method, unsigned index) +resolveMethod(Thread* t, object method, unsigned index, bool throw_ = true) { return resolveMethod - (t, classLoader(t, methodClass(t, method)), method, index); + (t, classLoader(t, methodClass(t, method)), method, index, throw_); } object diff --git a/src/thunks.cpp b/src/thunks.cpp index 4d863ecca4..dce0885c96 100644 --- a/src/thunks.cpp +++ b/src/thunks.cpp @@ -1,5 +1,9 @@ THUNK(tryInitClass) THUNK(findInterfaceMethodFromInstance) +THUNK(findInterfaceMethodFromInstanceAndReference) +THUNK(findSpecialMethodFromReference) +THUNK(findStaticMethodFromReference) +THUNK(findVirtualMethodFromReference) THUNK(compareDoublesG) THUNK(compareDoublesL) THUNK(compareFloatsG) @@ -36,17 +40,31 @@ THUNK(intToFloat) THUNK(longToDouble) THUNK(longToFloat) THUNK(makeBlankObjectArray) +THUNK(makeBlankObjectArrayFromReference) THUNK(makeBlankArray) THUNK(lookUpAddress) THUNK(setMaybeNull) THUNK(acquireMonitorForObject) THUNK(releaseMonitorForObject) THUNK(makeMultidimensionalArray) +THUNK(makeMultidimensionalArrayFromReference) THUNK(throw_) THUNK(checkCast) +THUNK(checkCastFromReference) +THUNK(getStaticFieldValueFromReference) +THUNK(getFieldValueFromReference) +THUNK(setStaticFieldValueFromReference) +THUNK(setFieldValueFromReference) +THUNK(setStaticLongFieldValueFromReference) +THUNK(setLongFieldValueFromReference) +THUNK(setStaticObjectFieldValueFromReference) +THUNK(setObjectFieldValueFromReference) THUNK(instanceOf64) +THUNK(instanceOfFromReference) THUNK(makeNewGeneral64) THUNK(makeNew64) +THUNK(makeNewFromReference) THUNK(set) THUNK(getJClass64) +THUNK(getJClassFromReference) THUNK(gcIfNecessary) diff --git a/src/vector.h b/src/vector.h index b5aa9365b9..c952763dba 100644 --- a/src/vector.h +++ b/src/vector.h @@ -33,6 +33,7 @@ class Vector { void dispose() { if (data and minimumCapacity >= 0) { allocator->free(data, capacity); + data = 0; } } diff --git a/src/zone.h b/src/zone.h index fc412f3634..b73c0a8913 100644 --- a/src/zone.h +++ b/src/zone.h @@ -45,6 +45,8 @@ class Zone: public Allocator { next = seg->next; allocator->free(seg, sizeof(Segment) + seg->size); } + + segment = 0; } bool ensure(unsigned space) { diff --git a/test/LazyLoading.java b/test/LazyLoading.java new file mode 100644 index 0000000000..83dd4bc82c --- /dev/null +++ b/test/LazyLoading.java @@ -0,0 +1,184 @@ +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; + +public class LazyLoading { + private static boolean loadLazy; + + private static void expect(boolean v) { + if (! v) throw new RuntimeException(); + } + + private static File findClass(String name, File directory) { + for (File file: directory.listFiles()) { + if (file.isFile()) { + if (file.getName().equals(name + ".class")) { + return file; + } + } else if (file.isDirectory()) { + File result = findClass(name, file); + if (result != null) { + return result; + } + } + } + return null; + } + + private static byte[] read(File file) throws IOException { + byte[] bytes = new byte[(int) file.length()]; + FileInputStream in = new FileInputStream(file); + try { + if (in.read(bytes) != (int) file.length()) { + throw new RuntimeException(); + } + return bytes; + } finally { + in.close(); + } + } + + public static void main(String[] args) throws Exception { + Class c = new MyClassLoader(LazyLoading.class.getClassLoader()).loadClass + ("LazyLoading$Test"); + + c.getMethod("test").invoke(null); + } + + private static class MyClassLoader extends ClassLoader { + public MyClassLoader(ClassLoader parent) { + super(parent); + } + + protected Class findClass(String name) throws ClassNotFoundException { + try { + return defineClass + (name, read + (LazyLoading.findClass + (name, new File(System.getProperty("user.dir"))))); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public Class loadClass(String name) throws ClassNotFoundException { + if ("LazyLoading$Test".equals(name)) { + return findClass(name); + } else if ("LazyLoading$Lazy".equals(name) + || "LazyLoading$Interface".equals(name)) + { + if (loadLazy) { + return findClass(name); + } else { + throw new ClassNotFoundException(); + } + } else { + return super.loadClass(name); + } + } + + private Class defineClass(String name, byte[] bytes) { + return defineClass(name, bytes, 0, bytes.length); + } + } + + private static class Test { + public static void test() { + doTest(); + loadLazy = true; + doTest(); + } + + private static void doTest() { + if (loadLazy) { + // anewarray + Lazy[] array = new Lazy[1]; + + // new and invokespecial + Object lazy = new Lazy(); + + // checkcast + array[0] = (Lazy) lazy; + + // instanceof + expect(lazy instanceof Lazy); + + // invokeinterface + Interface i = array[0]; + expect(i.interfaceMethod() == 42); + + // invokestatic + expect(Lazy.staticMethod() == 43); + + // invokevirtual + expect(array[0].virtualMethod() == 44); + + // ldc + expect(Lazy.class == lazy.getClass()); + + // multianewarray + Lazy[][] multiarray = new Lazy[5][6]; + multiarray[2][3] = array[0]; + expect(multiarray[2][3] == array[0]); + + // getfield + expect(array[0].intField == 45); + + // getstatic + expect(Lazy.intStaticField == 46); + + // putfield int + array[0].intField = 47; + expect(array[0].intField == 47); + + // putfield long + array[0].longField = 48; + expect(array[0].longField == 48); + + // putfield object + Object x = new Object(); + array[0].objectField = x; + expect(array[0].objectField == x); + + // putstatic int + array[0].intStaticField = 49; + expect(array[0].intStaticField == 49); + + // putstatic long + array[0].longStaticField = 50; + expect(array[0].longStaticField == 50); + + // putstatic object + Object y = new Object(); + array[0].objectStaticField = y; + expect(array[0].objectStaticField == y); + } + } + } + + private interface Interface { + public int interfaceMethod(); + } + + private static class Lazy implements Interface { + public static int intStaticField = 46; + public static long longStaticField; + public static Object objectStaticField; + + public int intField = 45; + public long longField; + public Object objectField; + + public int interfaceMethod() { + return 42; + } + + public static int staticMethod() { + return 43; + } + + public int virtualMethod() { + return 44; + } + } +}