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