From 5e740170f2dc4b3df89d0273abd8b0f1ef71fa23 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 31 Mar 2009 14:15:08 -0600 Subject: [PATCH 001/172] initial sketch of tail call optimization (non-virtual calls only, so far) --- src/assembler.h | 2 + src/compile.cpp | 412 ++++++++++++++++++++++++++++++++++++++--------- src/compiler.cpp | 117 +++++++++----- src/compiler.h | 1 + src/powerpc.cpp | 4 + src/types.def | 2 +- src/x86.cpp | 4 + 7 files changed, 420 insertions(+), 122 deletions(-) diff --git a/src/assembler.h b/src/assembler.h index c915cfe894..3cc4dadf33 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -277,6 +277,8 @@ class Assembler { virtual void updateCall(UnaryOperation op, bool assertAlignment, void* returnAddress, void* newTarget) = 0; + virtual unsigned constantCallSize() = 0; + virtual uintptr_t getConstant(const void* src) = 0; virtual void setConstant(void* dst, uintptr_t constant) = 0; diff --git a/src/compile.cpp b/src/compile.cpp index 6113452a7e..f10117fb40 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -426,15 +426,18 @@ class Context; class TraceElement: public TraceHandler { public: + const unsigned VirtualCall = 1 << 0; + const unsigned TailCall = 1 << 1; + TraceElement(Context* context, object target, - bool virtualCall, TraceElement* next): + unsigned flags, TraceElement* next): context(context), address(0), next(next), target(target), padIndex(0), padding(0), - virtualCall(virtualCall) + flags(flags) { } virtual void handleTrace(Promise* address, unsigned padIndex, @@ -453,10 +456,27 @@ class TraceElement: public TraceHandler { object target; unsigned padIndex; unsigned padding; - bool virtualCall; + unsigned flags; uintptr_t map[0]; }; +class TraceElementPromise: public Promise { + public: + TraceElementPromise(TraceElement* trace): trace(trace) { } + + virtual int64_t value() { + assert(s, resolved()); + return reinterpret_cast(trace->address); + } + + virtual bool resolved() { + return trace->address != 0; + } + + System* s; + TraceElement* trace; +}; + enum Event { PushContextEvent, PopContextEvent, @@ -1182,12 +1202,12 @@ class Frame { swapped(); } - TraceElement* trace(object target, bool virtualCall) { + TraceElement* trace(object target, unsigned flags) { unsigned mapSize = frameMapSizeInWords(t, context->method); TraceElement* e = context->traceLog = new (context->zone.allocate(sizeof(TraceElement) + (mapSize * BytesPerWord))) - TraceElement(context, target, virtualCall, context->traceLog); + TraceElement(context, target, flags, context->traceLog); ++ context->traceLogCount; @@ -1863,8 +1883,75 @@ emptyMethod(MyThread* t, object method) and (codeBody(t, methodCode(t, method), 0) == return_); } +Compiler::Operand* +compileDirectInvoke(MyThread* t, Frame* frame, object target, bool tailCall, + bool useThunk, unsigned rSize, Promise* addressPromise) +{ + if (tailCall and methodParameterFootprint(t, target) + > methodParameterFootprint(t, frame->context->method)) + { + return c->stackCall + (c->constant(tailHelperThunk(t)), + 0, + frame->trace(target, 0), + rSize, + methodParameterFootprint(t, target)); + } else if (tailCall and (methodFlags(t, target) & ACC_NATIVE)) { + return c->stackCall + (c->constant(nativeTailThunk(t)), + Compiler::TailCall, + frame->trace(target, TraceElement::TailCall), + trace, + rSize, + methodParameterFootprint(t, target)); + } else { + unsigned flags = (tailCall ? Compiler::TailCall : 0); + + if (useThunk) { + if (tailCall) { + Compiler::Operand* result = c->stackCall + (c->promiseConstant + (new (frame->context->zone.allocate(sizeof(TraceElementPromise))) + TraceElementPromise(t->m->system, frame->trace(0, 0))), + flags | Compiler::Aligned, + 0, + rSize, + methodParameterFootprint(t, target)); + + c->call(c->constant(defaultTailThunk(t)), + 0, + frame->trace(target, TraceElement::TailCall), + 0, + 0); + + return result; + } else { + return c->stackCall + (address, + flags | Compiler::Aligned, + frame->trace(target, 0), + rSize, + methodParameterFootprint(t, target)); + } + } else { + Compiler::Operand* address = + (addressPromise + ? c->promiseConstant(addressPromise) + : c->constant(methodAddress(t, target))); + + return c->stackCall + (c->promiseConstant(p), + flags, + tailCall ? 0 : frame->trace + ((methodFlags(t, target) & ACC_NATIVE) ? target, 0), + rSize, + methodParameterFootprint(t, target)); + } + } +} + void -compileDirectInvoke(MyThread* t, Frame* frame, object target) +compileDirectInvoke(MyThread* t, Frame* frame, object target, bool tailCall) { Compiler* c = frame->c; @@ -1885,42 +1972,20 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target) object pointer = makePointer(t, p); bc->calls = makeTriple(t, target, pointer, bc->calls); - object traceTarget - = (methodFlags(t, target) & ACC_NATIVE) ? target : 0; - - result = c->stackCall - (c->promiseConstant(p), - 0, - frame->trace(traceTarget, false), - rSize, - methodParameterFootprint(t, target)); + result = compileDirectInvoke + (t, frame, target, tailCall, false, rSize, p); } else { - result = c->stackCall - (c->constant(defaultThunk(t)), - Compiler::Aligned, - frame->trace(target, false), - rSize, - methodParameterFootprint(t, target)); + result = compileDirectInvoke + (t, frame, target, tailCall, true, rSize, 0); } } else if (methodAddress(t, target) == defaultThunk(t) or classNeedsInit(t, methodClass(t, target))) { - result = c->stackCall - (c->constant(defaultThunk(t)), - Compiler::Aligned, - frame->trace(target, false), - rSize, - methodParameterFootprint(t, target)); + result = compileDirectInvoke + (t, frame, target, tailCall, true, rSize, 0); } else { - object traceTarget - = (methodFlags(t, target) & ACC_NATIVE) ? target : 0; - - result = c->stackCall - (c->constant(methodAddress(t, target)), - 0, - frame->trace(traceTarget, false), - rSize, - methodParameterFootprint(t, target)); + result = compileDirectInvoke + (t, frame, target, tailCall, false, rSize, 0); } } @@ -1947,7 +2012,7 @@ handleMonitorEvent(MyThread* t, Frame* frame, intptr_t function) c->call(c->constant(function), 0, - frame->trace(0, false), + frame->trace(0, 0), 0, 2, c->thread(), lock); } @@ -2059,6 +2124,35 @@ inTryBlock(MyThread* t, object code, unsigned ip) return false; } +bool +needsReturnBarrier(MyThread* t, object method) +{ + return (methodFlags(t, method) & ConstructorFlag) + and (classFlags(t, methodClass(t, method)) & HasFinalMemberFlag); +} + +bool +isTailCall(MyThread* t, object code, unsigned ip, object caller, object callee) +{ + if (((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))) + { + switch (codeBody(t, code, ip)) { + case return_: + case areturn: + case ireturn: + case freturn: + case lreturn: + case dreturn: + return true; + } + } + return false; +} + void compile(MyThread* t, Frame* initialFrame, unsigned ip, int exceptionHandlerStart = -1); @@ -2104,7 +2198,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, c->call (c->constant(getThunk(t, gcIfNecessaryThunk)), 0, - frame->trace(0, false), + frame->trace(0, 0), 0, 1, c->thread()); } @@ -2204,7 +2298,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, c->call (c->constant(getThunk(t, setMaybeNullThunk)), 0, - frame->trace(0, false), + frame->trace(0, 0), 0, 4, c->thread(), array, c->add(4, c->constant(ArrayBody), @@ -2272,7 +2366,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, (c->call (c->constant(getThunk(t, makeBlankObjectArrayThunk)), 0, - frame->trace(0, false), + frame->trace(0, 0), BytesPerWord, 3, c->thread(), frame->append(class_), length)); } break; @@ -2314,7 +2408,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, c->call (c->constant(getThunk(t, throw_Thunk)), Compiler::NoReturn, - frame->trace(0, false), + frame->trace(0, 0), 0, 2, c->thread(), target); } return; @@ -2335,7 +2429,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, c->call (c->constant(getThunk(t, checkCastThunk)), 0, - frame->trace(0, false), + frame->trace(0, 0), 0, 3, c->thread(), frame->append(class_), instance); } break; @@ -2616,7 +2710,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, c->call (c->constant(getThunk(t, tryInitClassThunk)), 0, - frame->trace(0, false), + frame->trace(0, 0), 0, 2, c->thread(), frame->append(fieldClass(t, field))); } @@ -2643,7 +2737,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, c->call (c->constant(getThunk(t, acquireMonitorForObjectThunk)), - 0, frame->trace(0, false), 0, 2, c->thread(), fieldOperand); + 0, frame->trace(0, 0), 0, 2, c->thread(), fieldOperand); } switch (fieldCode(t, field)) { @@ -2697,7 +2791,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, { c->call (c->constant(getThunk(t, releaseMonitorForObjectThunk)), - 0, frame->trace(0, false), 0, 2, c->thread(), fieldOperand); + 0, frame->trace(0, 0), 0, 2, c->thread(), fieldOperand); } else { c->loadBarrier(); } @@ -2994,12 +3088,12 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, (c->constant (getThunk(t, findInterfaceMethodFromInstanceThunk)), 0, - frame->trace(0, false), + frame->trace(0, 0), BytesPerWord, 3, c->thread(), frame->append(target), c->peek(1, instance)), 0, - frame->trace(target, true), + frame->trace(target, TraceElement::VirtualCall), rSize, parameterFootprint); @@ -3023,7 +3117,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); - compileDirectInvoke(t, frame, target); + compileDirectInvoke + (t, frame, target, isTailCall(t, code, ip, context->method, target)); } break; case invokestatic: { @@ -3034,7 +3129,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, assert(t, methodFlags(t, target) & ACC_STATIC); - compileDirectInvoke(t, frame, target); + compileDirectInvoke + (t, frame, target, isTailCall(t, code, ip, context->method, target)); } break; case invokevirtual: { @@ -3059,7 +3155,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, (BytesPerWord, c->constant(PointerMask), c->memory(instance, 0, 0, 1)), offset, 0, 1), 0, - frame->trace(target, true), + frame->trace(target, TraceElement::VirtualCall), rSize, parameterFootprint); @@ -3441,14 +3537,14 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* target = frame->popObject(); c->call (c->constant(getThunk(t, acquireMonitorForObjectThunk)), - 0, frame->trace(0, false), 0, 2, c->thread(), target); + 0, frame->trace(0, 0), 0, 2, c->thread(), target); } break; case monitorexit: { Compiler::Operand* target = frame->popObject(); c->call (c->constant(getThunk(t, releaseMonitorForObjectThunk)), - 0, frame->trace(0, false), 0, 2, c->thread(), target); + 0, frame->trace(0, 0), 0, 2, c->thread(), target); } break; case multianewarray: { @@ -3468,7 +3564,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* result = c->call (c->constant(getThunk(t, makeMultidimensionalArrayThunk)), 0, - frame->trace(0, false), + frame->trace(0, 0), BytesPerWord, 4, c->thread(), frame->append(class_), c->constant(dimensions), c->constant(offset)); @@ -3488,7 +3584,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, (c->call (c->constant(getThunk(t, makeNewWeakReference64Thunk)), 0, - frame->trace(0, false), + frame->trace(0, 0), BytesPerWord, 2, c->thread(), frame->append(class_))); } else { @@ -3496,7 +3592,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, (c->call (c->constant(getThunk(t, makeNew64Thunk)), 0, - frame->trace(0, false), + frame->trace(0, 0), BytesPerWord, 2, c->thread(), frame->append(class_))); } @@ -3511,7 +3607,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, (c->call (c->constant(getThunk(t, makeBlankArrayThunk)), 0, - frame->trace(0, false), + frame->trace(0, 0), BytesPerWord, 3, c->thread(), c->constant(type), length)); } break; @@ -3544,7 +3640,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, c->call (c->constant(getThunk(t, tryInitClassThunk)), 0, - frame->trace(0, false), + frame->trace(0, 0), 0, 2, c->thread(), frame->append(fieldClass(t, field))); } @@ -3600,7 +3696,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, c->call (c->constant(getThunk(t, acquireMonitorForObjectThunk)), - 0, frame->trace(0, false), 0, 2, c->thread(), fieldOperand); + 0, frame->trace(0, 0), 0, 2, c->thread(), fieldOperand); } else { c->storeStoreBarrier(); } @@ -3635,7 +3731,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, c->call (c->constant(getThunk(t, setMaybeNullThunk)), 0, - frame->trace(0, false), + frame->trace(0, 0), 0, 4, c->thread(), table, c->constant(fieldOffset(t, field)), value); } else { @@ -3656,7 +3752,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, { c->call (c->constant(getThunk(t, releaseMonitorForObjectThunk)), - 0, frame->trace(0, false), 0, 2, c->thread(), fieldOperand); + 0, frame->trace(0, 0), 0, 2, c->thread(), fieldOperand); } else { c->storeLoadBarrier(); } @@ -3669,10 +3765,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, return; case return_: - if ((methodFlags(t, context->method) & ConstructorFlag) - and (classFlags(t, methodClass(t, context->method)) - & HasFinalMemberFlag)) - { + if (needsReturnBarrier(t, context->method)) { c->storeStoreBarrier(); } @@ -3909,6 +4002,28 @@ printSet(uintptr_t m, unsigned limit) } } +void +shiftLeftZeroPadded(void* data, int dataSizeInBytes, int shiftCountInBits) +{ + uint8_t* p = static_cast(data); + int shiftCountInBytes = shiftCountInBits / 8; + int shift = shiftCountInBits % 8; + + int count = dataSizeInBytes - shiftCountInBytes - 1; + for (int i = 0; i < count; ++i) { + int si = i + shiftCountInBytes; + p[i] = (p[si] >> shift) | ((p[si + 1] >> shift) << (8 - shift)); + } + + if (count >= 0) { + p[count] = (p[count + shiftCountInBytes] >> shift); + } + + for (int i = count + 1; i < dataSizeInBytes; ++i) { + p[i] = 0; + } +} + unsigned calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, unsigned stackPadding, unsigned eventIndex) @@ -4021,8 +4136,15 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, printSet(*roots, mapSize); fprintf(stderr, "\n"); } + memcpy(te->map, roots, mapSize * BytesPerWord); + if (te->flags & TraceElement::TailCall) { + shiftLeftZeroPadded + (te->map, mapSize * BytesPerWord, + usableFrameSize(t, context->method)); + } + eventIndex += BytesPerWord; } break; @@ -4172,7 +4294,7 @@ finish(MyThread* t, Allocator* allocator, Context* context) if (p->target) { insertCallNode (t, makeCallNode - (t, p->address->value(), p->target, p->virtualCall, 0)); + (t, p->address->value(), p->target, p->flags, 0)); } } @@ -4402,15 +4524,15 @@ compile(MyThread* t, Allocator* allocator, BootContext* bootContext, object method); void* -compileMethod2(MyThread* t) +compileMethod2(MyThread* t, uintptr_t ip) { - object node = findCallNode(t, t->arch->frameIp(t->stack)); + object node = findCallNode(t, ip); PROTECT(t, node); object target = callNodeTarget(t, node); PROTECT(t, target); - if (callNodeVirtualCall(t, node)) { + if (callNodeFlags(t, node) & TraceElement::VirtualCall) { target = resolveTarget(t, t->stack, target); } @@ -4422,15 +4544,19 @@ compileMethod2(MyThread* t) return 0; } else { void* address = reinterpret_cast(methodAddress(t, target)); - if (callNodeVirtualCall(t, node)) { + if (callNodeFlags(t, node) & TraceElement::VirtualCall) { classVtable (t, objectClass (t, resolveThisPointer(t, t->stack, target)), methodOffset(t, target)) = address; } else { + uintptr_t updateIp = ip; + if (callNode(t, node) & TraceElement::TailCall) { + updateIp -= t->arch->constantCallSize(); + } + updateCall - (t, Call, true, reinterpret_cast(callNodeAddress(t, node)), - address); + (t, Call, true, reinterpret_cast(updateIp), address); } return address; } @@ -4439,7 +4565,73 @@ compileMethod2(MyThread* t) uint64_t compileMethod(MyThread* t) { - void* r = compileMethod2(t); + uintptr_t ip; + if (t->tailAddress) { + ip = t->tailAddress; + t->tailAddress = 0; + } else { + ip = t->arch->frameIp(t->stack); + } + + void* r = compileMethod2(t, ip); + + if (UNLIKELY(t->exception)) { + unwind(t); + } else { + return reinterpret_cast(r); + } +} + +void* +tailCall2(MyThread* t, uintptr_t ip) +{ + object node = findCallNode(t, ip); + PROTECT(t, node); + + object target = callNodeTarget(t, node); + PROTECT(t, target); + + if (callNodeFlags(t, node) & TraceElement::VirtualCall) { + target = resolveTarget(t, t->stack, target); + } + + if (LIKELY(t->exception == 0)) { + compile(t, codeZone(t), 0, target); + } + + if (UNLIKELY(t->exception)) { + return 0; + } else { + void* base = t->base; + void* stack = t->stack; + t->arch->nextFrame(&stack, &base); + + if (t->arch->matchCall(t->arch->frameIp(stack), tailHelperThunk(t))) { + void* nextBase = base; + void* nextStack = stack; + t->arch->nextFrame(&nextStack, &nextBase); + + if (((reinterpret_cast(nextStack) + - reinterpret_cast(stack)) + / BytesPerWord) + - t->arch->frameFooterSize() + - t->arch->frameHeaderSize() + >= methodParameterFootprint(t, target)) + { + // there's room for the parameters in the previous frame, so use it + t->base = base; + t->stack = stack; + } + } + + return reinterpret_cast(methodAddress(t, target)); + } +} + +uint64_t +tailCall(MyThread* t) +{ + void* r = tailCall2(t, t->arch->frameIp(t->stack)); if (UNLIKELY(t->exception)) { unwind(t); @@ -4632,14 +4824,24 @@ uint64_t invokeNative(MyThread* t) { if (t->trace->nativeMethod == 0) { - object node = findCallNode(t, t->arch->frameIp(t->stack)); + uintptr_t ip; + if (t->tailAddress) { + ip = t->tailAddress; + t->tailAddress = 0; + } else { + ip = t->arch->frameIp(t->stack); + } + + object node = findCallNode(t, ip); object target = callNodeTarget(t, node); - if (callNodeVirtualCall(t, node)) { + if (callNodeFlags(t, node) & TraceElement::VirtualCall) { target = resolveTarget(t, t->stack, target); } t->trace->nativeMethod = target; } + assert(t, t->tailAddress == 0); + uint64_t result = 0; if (LIKELY(t->exception == 0)) { @@ -5396,7 +5598,7 @@ class MyProcessor: public Processor { table[index++] = callNodeAddress(t, p) - reinterpret_cast(code); table[index++] = w->map()->find(callNodeTarget(t, p)) - | (static_cast(callNodeVirtualCall(t, p)) << BootShift); + | (static_cast(callNodeFlags(t, node)) << BootShift); } } @@ -5494,7 +5696,7 @@ resizeTable(MyThread* t, object oldTable, unsigned newLength) object newNode = makeCallNode (t, callNodeAddress(t, oldNode), callNodeTarget(t, oldNode), - callNodeVirtualCall(t, oldNode), + callNodeFlags(t, oldNode), arrayBody(t, newTable, index)); set(t, newTable, ArrayBody + (index * BytesPerWord), newNode); @@ -5818,9 +6020,15 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, }; Zone zone(t->m->system, t->m->heap, 1024); + ThunkContext defaultContext(t, &zone); + unsigned defaultTailOffset; { Assembler* a = defaultContext.context.assembler; + + a->popReturnAddress(difference(&(t->tailAddress), t)); + + defaultTailOffset = a->length(); a->saveFrame(difference(&(t->stack), t), difference(&(t->base), t)); @@ -5838,10 +6046,35 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, a->endBlock(false)->resolve(0, 0); } + ThunkContext tailHelperContext(t, &zone); + + { Assembler* a = tailHelperContext.context.assembler; + + a->saveFrame(difference(&(t->stack), t), difference(&(t->base), t)); + + Assembler::Register thread(t->arch->thread()); + a->pushFrame(1, BytesPerWord, RegisterOperand, &thread); + + Assembler::Constant proc(&(tailHelperContext.promise)); + a->apply(LongCall, BytesPerWord, ConstantOperand, &proc); + + a->restoreFrame(difference(&(t->stack), t), difference(&(t->base), t)); + + Assembler::Register result(t->arch->returnLow()); + a->apply(Jump, BytesPerWord, RegisterOperand, &result); + + a->endBlock(false)->resolve(0, 0); + } + ThunkContext nativeContext(t, &zone); + unsigned nativeTailOffset; { Assembler* a = nativeContext.context.assembler; - + + a->popReturnAddress(difference(&(t->tailAddress), t)); + + nativeTailOffset = a->length(); + a->saveFrame(difference(&(t->stack), t), difference(&(t->base), t)); Assembler::Register thread(t->arch->thread()); @@ -5890,33 +6123,54 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, (codeSingletonSizeInBytes (t, defaultContext.context.assembler->length()) + codeSingletonSizeInBytes + (t, tailHelperContext.context.assembler->length()) + + codeSingletonSizeInBytes (t, nativeContext.context.assembler->length()) + codeSingletonSizeInBytes (t, aioobContext.context.assembler->length()) + codeSingletonSizeInBytes (t, p->thunkSize * ThunkCount))); - p->defaultThunk = finish + p->defaultTailThunk = finish (t, allocator, defaultContext.context.assembler, "default"); + p->defaultThunk = p->defaultTailThunk + defaultTailOffset; + { void* call; defaultContext.promise.listener->resolve (reinterpret_cast(voidPointer(compileMethod)), &call); if (image) { + image->defaultTailThunk = p->defaultTailThunk - imageBase; image->defaultThunk = p->defaultThunk - imageBase; image->compileMethodCall = static_cast(call) - imageBase; } } - p->nativeThunk = finish + p->tailHelperThunk = finish + (t, allocator, defaultContext.context.assembler, "tailHelper"); + + { void* call; + tailHelperContext.promise.listener->resolve + (reinterpret_cast(voidPointer(tailCall)), &call); + + if (image) { + image->tailHelperThunk = p->tailHelperThunk - imageBase; + image->tailHelperCall = static_cast(call) - imageBase; + } + } + + p->nativeTailThunk = finish (t, allocator, nativeContext.context.assembler, "native"); + p->nativeThunk = p->nativeTailThunk + nativeTailOffset; + { void* call; nativeContext.promise.listener->resolve (reinterpret_cast(voidPointer(invokeNative)), &call); if (image) { + image->nativeTailThunk = p->nativeTailThunk - imageBase; image->nativeThunk = p->nativeThunk - imageBase; image->invokeNativeCall = static_cast(call) - imageBase; } diff --git a/src/compiler.cpp b/src/compiler.cpp index f48fa446a6..08bb621689 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -2258,7 +2258,12 @@ class CallEvent: public Event { uint32_t registerMask = ~0; Stack* s = argumentStack; unsigned index = 0; - unsigned frameIndex = 0; + unsigned frameIndex; + if (flags & (Compiler::TailJump | Compiler::TailCall)) { + frameIndex = usableFrameSize(c); + } else { + frameIndex = 0; + } if (argumentCount) { while (true) { @@ -2308,56 +2313,59 @@ class CallEvent: public Event { (typeMask, registerMask & planRegisterMask, AnyFrameIndex))); } - int footprint = stackArgumentFootprint; - for (Stack* s = stackBefore; s; s = s->next) { - if (s->value) { - if (footprint > 0) { - if (DebugReads) { - fprintf(stderr, "stack arg read %p at %d of %d\n", - s->value, frameIndex, - usableFrameSize(c) + c->parameterFootprint); - } + if ((flags & (Compiler::TailJump | Compiler::TailCall)_ == 0) { + int footprint = stackArgumentFootprint; + for (Stack* s = stackBefore; s; s = s->next) { + if (s->value) { + if (footprint > 0) { + if (DebugReads) { + fprintf(stderr, "stack arg read %p at %d of %d\n", + s->value, frameIndex, + usableFrameSize(c) + c->parameterFootprint); + } - addRead(c, this, s->value, read - (c, SiteMask(1 << MemoryOperand, 0, frameIndex))); - } else { + addRead(c, this, s->value, read + (c, SiteMask(1 << MemoryOperand, 0, frameIndex))); + } else { + unsigned logicalIndex = ::frameIndex + (c, s->index + c->localFootprint); + + if (DebugReads) { + fprintf(stderr, "stack save read %p at %d of %d\n", + s->value, logicalIndex, + usableFrameSize(c) + c->parameterFootprint); + } + + addRead(c, this, s->value, read + (c, SiteMask(1 << MemoryOperand, 0, logicalIndex))); + } + } + + -- footprint; + + if (footprint == 0) { unsigned logicalIndex = ::frameIndex (c, s->index + c->localFootprint); - if (DebugReads) { - fprintf(stderr, "stack save read %p at %d of %d\n", - s->value, logicalIndex, - usableFrameSize(c) + c->parameterFootprint); - } + assert(c, logicalIndex >= frameIndex); - addRead(c, this, s->value, read - (c, SiteMask(1 << MemoryOperand, 0, logicalIndex))); + padding = logicalIndex - frameIndex; + padIndex = s->index + c->localFootprint; } + + ++ frameIndex; } - -- footprint; + popIndex + = usableFrameSize(c) + + c->parameterFootprint + - (stackBefore ? stackBefore->index + 1 - stackArgumentFootprint : 0) + - c->localFootprint; - if (footprint == 0) { - unsigned logicalIndex = ::frameIndex(c, s->index + c->localFootprint); + assert(c, static_cast(popIndex) >= 0); - assert(c, logicalIndex >= frameIndex); - - padding = logicalIndex - frameIndex; - padIndex = s->index + c->localFootprint; - } - - ++ frameIndex; + saveLocals(c, this); } - - popIndex - = usableFrameSize(c) - + c->parameterFootprint - - (stackBefore ? stackBefore->index + 1 - stackArgumentFootprint : 0) - - c->localFootprint; - - assert(c, static_cast(popIndex) >= 0); - - saveLocals(c, this); } virtual const char* name() { @@ -2365,8 +2373,33 @@ class CallEvent: public Event { } virtual void compile(Context* c) { - apply(c, (flags & Compiler::Aligned) ? AlignedCall : Call, BytesPerWord, - address->source, 0); + UnaryOperation op; + + if (flags & Compiler::TailJump) { + c->assembler->popFrame(); + + if (flags & Compiler::Aligned) { + op = AlignedJump; + } else { + op = Jump; + } + } else if (flags & Compiler::TailCall) { + c->assembler->popFrame(); + + if (flags & Compiler::Aligned) { + op = AlignedCall; + } else { + op = Call; + } + } else { + if (flags & Compiler::Aligned) { + op = AlignedCall; + } else { + op = Call; + } + } + + apply(c, op, BytesPerWord, address->source, 0); if (traceHandler) { traceHandler->handleTrace(codePromise(c, c->assembler->offset()), diff --git a/src/compiler.h b/src/compiler.h index db5f5963be..88fcee0351 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -27,6 +27,7 @@ class Compiler { static const unsigned Aligned = 1 << 0; static const unsigned NoReturn = 1 << 1; + static const unsigned TailCall = 1 << 2; class Operand { }; class StackElement { }; diff --git a/src/powerpc.cpp b/src/powerpc.cpp index 01f5a3e862..430e507585 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -1734,6 +1734,10 @@ class MyArchitecture: public Assembler::Architecture { } } + virtual unsigned constantCallSize() { + return 4; + } + virtual uintptr_t getConstant(const void* src) { const int32_t* p = static_cast(src); return (p[0] << 16) | (p[1] & 0xFFFF); diff --git a/src/types.def b/src/types.def index 1fadf50e39..2fa84d82e3 100644 --- a/src/types.def +++ b/src/types.def @@ -94,7 +94,7 @@ (type callNode (intptr_t address) (object target) - (uintptr_t virtualCall) + (uintptr_t flags) (object next)) (type array diff --git a/src/x86.cpp b/src/x86.cpp index 3e181bc775..39f35c4bf6 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -2088,6 +2088,10 @@ class MyArchitecture: public Assembler::Architecture { } } + virtual unsigned constantCallSize() { + return 5; + } + virtual uintptr_t getConstant(const void* src) { uintptr_t v; memcpy(&v, src, BytesPerWord); From fea92ed995bb6d8fc687c5f96dc15f9aaedf3de5 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 5 Apr 2009 15:42:10 -0600 Subject: [PATCH 002/172] more work on tail recursion We now create a unique thunk for each vtable position so as to avoid relying on using the return address to determine what method is to be compiled and invoked, since we will not have the correct return address in the case of a tail call. This required refactoring how executable memory is allocated in order to keep AOT compilation working. Also, we must always use the same register to hold the class pointer when compiling virtual calls, and ensure that the pointer stays there until the call instruction is executed so we know where to find it in the thunk. --- src/assembler.h | 2 + src/bootimage.cpp | 5 +- src/bootimage.h | 1 + src/compile.cpp | 351 +++++++++++++++++++++++++++++++++------------- src/compiler.cpp | 65 ++++++++- src/compiler.h | 5 +- src/machine.h | 12 +- src/posix.cpp | 34 ++--- src/processor.h | 7 +- src/types.def | 3 + src/windows.cpp | 2 - 11 files changed, 347 insertions(+), 140 deletions(-) diff --git a/src/assembler.h b/src/assembler.h index 3cc4dadf33..8c2a61ee44 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -274,6 +274,8 @@ class Assembler { virtual unsigned argumentRegisterCount() = 0; virtual int argumentRegister(unsigned index) = 0; + virtual bool matchCall(void* returnAddress, void* target) = 0; + virtual void updateCall(UnaryOperation op, bool assertAlignment, void* returnAddress, void* newTarget) = 0; diff --git a/src/bootimage.cpp b/src/bootimage.cpp index f2662631e1..3618e98333 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -37,7 +37,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, const char* methodName, const char* methodSpec) { unsigned size = 0; - t->m->processor->compileThunks(t, image, code, &size, capacity); + t->m->processor->initialize(t, image, code, &size, capacity); object constants = 0; PROTECT(t, constants); @@ -79,8 +79,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, == 0))) { t->m->processor->compileMethod - (t, zone, code, &size, capacity, &constants, &calls, &addresses, - method); + (t, zone, &constants, &calls, &addresses, method); } } } diff --git a/src/bootimage.h b/src/bootimage.h index ce83611583..54ccf136c2 100644 --- a/src/bootimage.h +++ b/src/bootimage.h @@ -39,6 +39,7 @@ class BootImage { unsigned types; unsigned methodTree; unsigned methodTreeSentinal; + unsigned virtualThunks; uintptr_t codeBase; diff --git a/src/compile.cpp b/src/compile.cpp index f10117fb40..5872933083 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -39,6 +39,8 @@ const unsigned MaxNativeCallFootprint = 4; const unsigned InitialZoneCapacityInBytes = 64 * 1024; +const unsigned ExecutableAreaSizeInBytes = 16 * 1024 * 1024; + class MyThread: public Thread { public: class CallTrace { @@ -123,6 +125,19 @@ resolveTarget(MyThread* t, void* stack, object method) } } +object +resolveTarget(MyThread* t, object class_, unsigned index) +{ + if (classVmFlags(t, class_) & BootstrapFlag) { + PROTECT(t, class_); + + resolveClass(t, className(t, class_)); + if (UNLIKELY(t->exception)) return 0; + } + + return arrayBody(t, classVirtualTable(t, class_), index); +} + object& methodTree(MyThread* t); @@ -1360,12 +1375,26 @@ tryInitClass(MyThread* t, object class_) if (UNLIKELY(t->exception)) unwind(t); } +FixedAllocator* +codeAllocator(MyThread* t); + int64_t findInterfaceMethodFromInstance(MyThread* t, object method, object instance) { if (instance) { - return methodAddress - (t, findInterfaceMethod(t, method, objectClass(t, instance))); + object target = findInterfaceMethod(t, method, objectClass(t, instance)); + + if (methodAddress(t, target) == defaultThunk(t)) { + PROTECT(t, target); + + compile(t, codeAllocator(t), 0, target); + } + + if (UNLIKELY(t->exception)) { + unwind(t); + } else { + return methodAddress(t, target); + } } else { t->exception = makeNullPointerException(t); unwind(t); @@ -3093,7 +3122,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, 3, c->thread(), frame->append(target), c->peek(1, instance)), 0, - frame->trace(target, TraceElement::VirtualCall), + frame->trace(0, 0), rSize, parameterFootprint); @@ -3149,15 +3178,32 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, unsigned rSize = resultSize(t, methodReturnCode(t, target)); - Compiler::Operand* result = c->stackCall - (c->memory - (c->and_ - (BytesPerWord, c->constant(PointerMask), - c->memory(instance, 0, 0, 1)), offset, 0, 1), - 0, - frame->trace(target, TraceElement::VirtualCall), - rSize, - parameterFootprint); + bool tailCall = isTailCall(t, code, ip, context->method, target); + + Compiler::Operand* result; + if (tailCall and methodParameterFootprint(t, target) + > methodParameterFootprint(t, context->method)) + { + result = c->stackCall + (c->constant(tailHelperThunk(t)), + 0, + frame->trace(target, TraceElement::VirtualCall), + rSize, + parameterFootprint); + } else { + c->freezeRegister(t->arch->returnLow(), + c->and_(BytesPerWord, c->constant(PointerMask), + c->memory(instance, 0, 0, 1))); + + result = c->stackCall + (c->memory(c->register_(t->arch->returnLow()), offset, 0, 1), + tailCall ? Compiler::TailCall : 0, + frame->trace(0, 0), + rSize, + parameterFootprint); + + c->thawRegister(t->arch->returnLow()); + } frame->pop(parameterFootprint); @@ -4155,9 +4201,6 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, return eventIndex; } -Zone* -codeZone(MyThread* t); - int compareTraceElementPointers(const void* va, const void* vb) { @@ -4532,32 +4575,21 @@ compileMethod2(MyThread* t, uintptr_t ip) object target = callNodeTarget(t, node); PROTECT(t, target); - if (callNodeFlags(t, node) & TraceElement::VirtualCall) { - target = resolveTarget(t, t->stack, target); - } - if (LIKELY(t->exception == 0)) { - compile(t, codeZone(t), 0, target); + compile(t, codeAllocator(t), 0, target); } if (UNLIKELY(t->exception)) { return 0; } else { void* address = reinterpret_cast(methodAddress(t, target)); - if (callNodeFlags(t, node) & TraceElement::VirtualCall) { - classVtable - (t, objectClass - (t, resolveThisPointer(t, t->stack, target)), methodOffset(t, target)) - = address; - } else { - uintptr_t updateIp = ip; - if (callNode(t, node) & TraceElement::TailCall) { - updateIp -= t->arch->constantCallSize(); - } - - updateCall - (t, Call, true, reinterpret_cast(updateIp), address); + uintptr_t updateIp = ip; + if (callNode(t, node) & TraceElement::TailCall) { + updateIp -= t->arch->constantCallSize(); } + + updateCall(t, Call, true, reinterpret_cast(updateIp), address); + return address; } } @@ -4582,6 +4614,46 @@ compileMethod(MyThread* t) } } +void* +compileVirtualMethod2(MyThread* t, object class_, unsigned index) +{ + PROTECT(t, class_); + + object target = resolveTarget(t, class_, index); + + if (LIKELY(t->exception == 0)) { + compile(t, codeAllocator(t), 0, target); + } + + if (UNLIKELY(t->exception)) { + return 0; + } else { + void* address = reinterpret_cast(methodAddress(t, target)); + if (address != nativeThunk(t, method)) { + classVtable(t, class_, methodOffset(t, target)) = address; + } + return address; + } +} + +uint64_t +compileVirtualMethod(MyThread* t) +{ + object class_ = t->virtualCallClass; + t->virtualCallClass = 0; + + unsigned index = t->virtualCallIndex; + t->virtualCallIndex = 0; + + void* r = compileVirtualMethod2(t, class_, index); + + if (UNLIKELY(t->exception)) { + unwind(t); + } else { + return reinterpret_cast(r); + } +} + void* tailCall2(MyThread* t, uintptr_t ip) { @@ -4596,7 +4668,7 @@ tailCall2(MyThread* t, uintptr_t ip) } if (LIKELY(t->exception == 0)) { - compile(t, codeZone(t), 0, target); + compile(t, codeAllocator(t), 0, target); } if (UNLIKELY(t->exception)) { @@ -5200,27 +5272,6 @@ processor(MyThread* t); class MyProcessor: public Processor { public: - class CodeAllocator: public Allocator { - public: - CodeAllocator(System* s): s(s) { } - - virtual void* tryAllocate(unsigned size) { - return s->tryAllocateExecutable(size); - } - - virtual void* allocate(unsigned size) { - void* p = tryAllocate(size); - expect(s, p); - return p; - } - - virtual void free(const void* p, unsigned size) { - s->freeExecutable(p, size); - } - - System* s; - }; - MyProcessor(System* s, Allocator* allocator): s(s), allocator(allocator), @@ -5233,9 +5284,11 @@ class MyProcessor: public Processor { methodTreeSentinal(0), objectPools(0), staticTableArray(0), - codeAllocator(s), - codeZone(s, &codeAllocator, 64 * 1024) - { } + virtualThunks(0), + codeAllocator(s, 0, 0) + { + expect(s, codeAllocator.base); + } virtual Thread* makeThread(Machine* m, object javaThread, Thread* parent) @@ -5292,11 +5345,8 @@ class MyProcessor: public Processor { virtual void initVtable(Thread* t, object c) { - void* compiled = reinterpret_cast - (::defaultThunk(static_cast(t))); - for (unsigned i = 0; i < classLength(t, c); ++i) { - classVtable(t, c, i) = compiled; + classVtable(t, c, i) = virtualThunk(static_cast(t), i); } } @@ -5399,7 +5449,8 @@ class MyProcessor: public Processor { PROTECT(t, method); - compile(static_cast(t), &codeZone, 0, method); + compile(static_cast(t), + ::codeAllocator(static_cast(t)), 0, method); if (LIKELY(t->exception == 0)) { return ::invoke(t, method, &list); @@ -5430,7 +5481,8 @@ class MyProcessor: public Processor { PROTECT(t, method); - compile(static_cast(t), &codeZone, 0, method); + compile(static_cast(t), + ::codeAllocator(static_cast(t)), 0, method); if (LIKELY(t->exception == 0)) { return ::invoke(t, method, &list); @@ -5460,7 +5512,8 @@ class MyProcessor: public Processor { PROTECT(t, method); - compile(static_cast(t), &codeZone, 0, method); + compile(static_cast(t), + ::codeAllocator(static_cast(t)), 0, method); if (LIKELY(t->exception == 0)) { return ::invoke(t, method, &list); @@ -5483,8 +5536,10 @@ class MyProcessor: public Processor { } virtual void dispose() { - codeZone.dispose(); - + if (codeAllocator.base) { + s->freeExecutable(codeAllocator.base, codeAllocator.capacity); + } + s->handleSegFault(0); allocator->free(this, sizeof(*this)); @@ -5551,37 +5606,34 @@ class MyProcessor: public Processor { return visitor.trace; } - virtual void compileThunks(Thread* vmt, BootImage* image, uint8_t* code, - unsigned* offset, unsigned capacity) + virtual void initialize(Thread* vmt, BootImage* image, uint8_t* code, + unsigned capacity) { - MyThread* t = static_cast(vmt); - FixedAllocator allocator(t, code + *offset, capacity); + codeAllocator.base = code; + codeAllocator.capacity = capacity; - ::compileThunks(t, &allocator, this, image, code); - - *offset += allocator.offset; + ::compileThunks + (static_cast(vmt), &codeAllocator, this, image, code); } - virtual void compileMethod(Thread* vmt, Zone* zone, uint8_t* code, - unsigned* offset, unsigned capacity, - object* constants, object* calls, - DelayedPromise** addresses, object method) + virtual void compileMethod(Thread* vmt, Zone* zone, object* constants, + object* calls, DelayedPromise** addresses, + object method) { MyThread* t = static_cast(vmt); - FixedAllocator allocator(t, code + *offset, capacity); BootContext bootContext(t, *constants, *calls, *addresses, zone); - compile(t, &allocator, &bootContext, method); + compile(t, &codeAllocator, &bootContext, method); *constants = bootContext.constants; *calls = bootContext.calls; *addresses = bootContext.addresses; - *offset += allocator.offset; } virtual void visitRoots(BootImage* image, HeapWalker* w) { image->methodTree = w->visitRoot(methodTree); image->methodTreeSentinal = w->visitRoot(methodTreeSentinal); + image->virtualThunks = w->visitRoot(virtualThunks); } virtual unsigned* makeCallTable(Thread* t, BootImage* image, HeapWalker* w, @@ -5606,6 +5658,9 @@ class MyProcessor: public Processor { } virtual void boot(Thread* t, BootImage* image) { + codeAllocator.base = s->tryAllocateExecutable(ExecutableAreaSizeInBytes); + codeAllocator.capacity = ExecutableAreaSizeInBytes; + if (image) { ::boot(static_cast(t), image); } else { @@ -5615,7 +5670,7 @@ class MyProcessor: public Processor { set(t, methodTree, TreeNodeLeft, methodTreeSentinal); set(t, methodTree, TreeNodeRight, methodTreeSentinal); - ::compileThunks(static_cast(t), &codeZone, this, 0, 0); + ::compileThunks(static_cast(t), &codeAllocator, this, 0, 0); } segFaultHandler.m = t->m; @@ -5636,9 +5691,9 @@ class MyProcessor: public Processor { object methodTreeSentinal; object objectPools; object staticTableArray; + object virtualThunks; SegFaultHandler segFaultHandler; - CodeAllocator codeAllocator; - Zone codeZone; + FixedAllocator codeAllocator; }; object @@ -5936,6 +5991,20 @@ fixupThunks(MyThread* t, BootImage* image, uint8_t* code) #undef THUNK } +void +fixupVirtualThunks(MyThread* t, BootImage* image, uint8_t* code) +{ + MyProcessor* p = processor(t); + + for (unsigned i = 0; i < wordArrayLength(t, p->virtualThunks); ++i) { + if (wordArrayBody(t, p->virtualThunks, 0)) { + wordArrayBody(t, p->virtualThunks, 0) + = (wordArrayBody(t, p->virtualThunks, 0) - image->codeBase) + + reinterpret_cast(code); + } + } +} + void boot(MyThread* t, BootImage* image) { @@ -5974,6 +6043,8 @@ boot(MyThread* t, BootImage* image) p->methodTree = bootObject(heap, image->methodTree); p->methodTreeSentinal = bootObject(heap, image->methodTreeSentinal); + p->virtualThunks = bootObject(heap, image->virtualThunks); + fixupCode(t, codeMap, codeMapSizeInWords, code, heap); syncInstructionCache(code, image->codeSize); @@ -5991,6 +6062,8 @@ boot(MyThread* t, BootImage* image) fixupThunks(t, image, code); + fixupVirtualThunks(t, image, code); + fixupMethods(t, image, code); t->m->bootstrapClassMap = makeHashMap(t, 0, 0); @@ -6046,6 +6119,38 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, a->endBlock(false)->resolve(0, 0); } + ThunkContext defaultVirtualContext(t, &zone); + + { Assembler* a = defaultVirtualContext.context.assembler; + + Assembler::Register class_(t->arch->returnLow()); + Assembler::Memory virtualCallClass + (t->arch->thread(), difference(&(t->virtualCallClass), t)); + a->apply(Move, BytesPerWord, RegisterOperand, &class_, + BytesPerWord, MemoryOperand, &virtualCallClass); + + Assembler::Register index(t->arch->returnHigh()); + Assembler::Memory virtualCallIndex + (t->arch->thread(), difference(&(t->virtualCallIndex), t)); + a->apply(Move, BytesPerWord, RegisterOperand, &index, + BytesPerWord, MemoryOperand, &virtualCallIndex); + + a->saveFrame(difference(&(t->stack), t), difference(&(t->base), t)); + + Assembler::Register thread(t->arch->thread()); + a->pushFrame(1, BytesPerWord, RegisterOperand, &thread); + + Assembler::Constant proc(&(defaultVirtualContext.promise)); + a->apply(LongCall, BytesPerWord, ConstantOperand, &proc); + + a->popFrame(); + + Assembler::Register result(t->arch->returnLow()); + a->apply(Jump, BytesPerWord, RegisterOperand, &result); + + a->endBlock(false)->resolve(0, 0); + } + ThunkContext tailHelperContext(t, &zone); { Assembler* a = tailHelperContext.context.assembler; @@ -6119,18 +6224,6 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, p->thunkSize = pad(tableContext.context.assembler->length()); - expect(t, codeZone(t)->ensure - (codeSingletonSizeInBytes - (t, defaultContext.context.assembler->length()) - + codeSingletonSizeInBytes - (t, tailHelperContext.context.assembler->length()) - + codeSingletonSizeInBytes - (t, nativeContext.context.assembler->length()) - + codeSingletonSizeInBytes - (t, aioobContext.context.assembler->length()) - + codeSingletonSizeInBytes - (t, p->thunkSize * ThunkCount))); - p->defaultTailThunk = finish (t, allocator, defaultContext.context.assembler, "default"); @@ -6147,6 +6240,20 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, } } + p->defaultVirtualThunk = finish + (t, allocator, defaultVirtualContext.context.assembler, "defaultVirtual"); + + { void* call; + defaultVirtualContext.promise.listener->resolve + (reinterpret_cast(voidPointer(compileVirtualMethod)), &call); + + if (image) { + image->defaultVirtualThunk = p->defaultVirtualThunk - imageBase; + image->compileVirtualMethodCall + = static_cast(call) - imageBase; + } + } + p->tailHelperThunk = finish (t, allocator, defaultContext.context.assembler, "tailHelper"); @@ -6249,6 +6356,51 @@ aioobThunk(MyThread* t) return reinterpret_cast(processor(t)->aioobThunk); } +uintptr_t +compileVirtualThunk(MyThread* t, unsigned index) +{ + Context context; + Assembler* a = context.assembler; + + Assembler::Constant indexConstant(index); + Assembler::Register indexRegister(t->arch->returnHigh()); + a->apply(Move, BytesPerWord, ConstantOperand, &indexConstant, + BytesPerWord, ConstantOperand, &indexRegister); + + Assembler::Constant thunk(defaultVirtualThunk(t)); + a->apply(Jump, BytesPerWord, ConstantOperand, &thunk); + + uint8_t* start = codeAllocator(t)->allocate(a->length()); + a->writeTo(start); +} + +uintptr_t +virtualThunk(MyThread* t, unsigned index) +{ + MyProcessor* p = processor(t); + + if (p->virtualThunks == 0 or wordArrayLength(t, p->virtualThunks) <= index) { + object newArray = makeWordArray(t, nextPowerOfTwo(index)); + if (p->virtualThunks) { + memcpy(&wordArrayBody(t, newArray, 0), + &wordArrayBody(t, p->virtualThunks, 0), + wordArrayLength(t, p->virtualThunks) * BytesPerWord); + } + p->virtualThunks = newArray; + } + + if (wordArrayBody(t, p->virtualThunks, index) == 0) { + ACQUIRE(t, t->m->classLock); + + if (wordArrayBody(t, p->virtualThunks, index) == 0) { + uintptr_t thunk = compileVirtualThunk(t, index); + wordArrayBody(t, p->virtualThunks, index) = thunk; + } + } + + return wordArrayBody(t, p->virtualThunks, index); +} + void compile(MyThread* t, Allocator* allocator, BootContext* bootContext, object method) @@ -6330,9 +6482,10 @@ methodTreeSentinal(MyThread* t) return processor(t)->methodTreeSentinal; } -Zone* -codeZone(MyThread* t) { - return &(processor(t)->codeZone); +FixedAllocator* +codeAllocator(MyThread* t) +{ + return &(processor(t)->codeAllocator); } } // namespace diff --git a/src/compiler.cpp b/src/compiler.cpp index 08bb621689..3812e2692d 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -1194,7 +1194,7 @@ pickTarget(Context* c, Read* read, bool intersectRead, ? 0 : Target::Penalty); Target best; - if ((mask.typeMask & (1 << RegisterOperand))) { + if (mask.typeMask & (1 << RegisterOperand)) { Target mine = pickRegisterTarget(c, read->value, mask.registerMask); mine.cost += registerPenalty; @@ -3842,6 +3842,61 @@ appendSaveLocals(Context* c) SaveLocalsEvent(c)); } +class FreezeRegisterEvent: public Event { + public: + FreezeRegisterEvent(Context* c, int number, Value* value): + Event(c), number(number), value(value) + { + addRead(c, this, value, fixedRegisterRead(c, number)); + } + + virtual const char* name() { + return "FreezeRegisterEvent"; + } + + virtual void compile(Context* c) { + c->registers[number].freeze(c, value); + + for (Read* r = reads; r; r = r->eventNext) { + popRead(c, this, r->value); + } + } + + int number; + Value* value; +}; + +void +appendFreezeRegister(Context* c, int number, Value* value) +{ + append(c, new (c->zone->allocate(sizeof(FreezeRegisterEvent))) + FreezeRegisterEvent(c, number, value)); +} + +class ThawRegisterEvent: public Event { + public: + ThawRegisterEvent(Context* c, int number): + Event(c), number(number) + { } + + virtual const char* name() { + return "ThawRegisterEvent"; + } + + virtual void compile(Context* c) { + c->registers[number].thaw(c, value); + } + + int number; +}; + +void +appendThawRegister(Context* c, int number, Value* value) +{ + append(c, new (c->zone->allocate(sizeof(ThawRegisterEvent))) + ThawRegisterEvent(c, number, value)); +} + class DummyEvent: public Event { public: DummyEvent(Context* c): @@ -4925,6 +4980,14 @@ class MyCompiler: public Compiler { return value(&c, s, s); } + virtual void freezeRegister(int number, Operand* value) { + appendFreezeRegister(&c, number, static_cast(value)); + } + + virtual void thawRegister(int number) { + appendThawRegister(&c, number); + } + Promise* machineIp() { return codePromise(&c, c.logicalCode[c.logicalIp]->lastEvent); } diff --git a/src/compiler.h b/src/compiler.h index 88fcee0351..6361f2bf25 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -60,8 +60,11 @@ class Compiler { Operand* index = 0, unsigned scale = 1) = 0; - virtual Operand* stack() = 0; virtual Operand* thread() = 0; + virtual Operand* stack() = 0; + + virtual void freezeRegister(int number, Operand* value) = 0; + virtual void thawRegister(int number) = 0; virtual void push(unsigned footprint) = 0; virtual void push(unsigned footprint, Operand* value) = 0; diff --git a/src/machine.h b/src/machine.h index c638156934..331c3bbc13 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1454,17 +1454,17 @@ expect(Thread* t, bool v) class FixedAllocator: public Allocator { public: - FixedAllocator(Thread* t, uint8_t* base, unsigned capacity): - t(t), base(base), offset(0), capacity(capacity) + FixedAllocator(System* s, uint8_t* base, unsigned capacity): + s(s), base(base), offset(0), capacity(capacity) { } virtual void* tryAllocate(unsigned) { - abort(t); + abort(s); } virtual void* allocate(unsigned size) { unsigned paddedSize = pad(size); - expect(t, offset + paddedSize < capacity); + expect(s, offset + paddedSize < capacity); void* p = base + offset; offset += paddedSize; @@ -1472,10 +1472,10 @@ class FixedAllocator: public Allocator { } virtual void free(const void*, unsigned) { - abort(t); + abort(s); } - Thread* t; + System* s; uint8_t* base; unsigned offset; unsigned capacity; diff --git a/src/posix.cpp b/src/posix.cpp index bc50ed9439..ad4a8c871a 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -63,8 +63,6 @@ const unsigned VisitSignalIndex = 0; const unsigned SegFaultSignalIndex = 1; const unsigned InterruptSignalIndex = 2; -const unsigned ExecutableAreaSizeInBytes = 16 * 1024 * 1024; - class MySystem; MySystem* system; @@ -518,9 +516,7 @@ class MySystem: public System { MySystem(): threadVisitor(0), - visitTarget(0), - executableArea(0), - executableOffset(0) + visitTarget(0) { expect(this, system == 0); system = this; @@ -559,33 +555,23 @@ class MySystem: public System { } virtual void* tryAllocateExecutable(unsigned sizeInBytes) { - if (executableArea == 0) { #ifdef __x86_64__ - const unsigned Extra = MAP_32BIT; + const unsigned Extra = MAP_32BIT; #else - const unsigned Extra = 0; + const unsigned Extra = 0; #endif - void* p = mmap(0, ExecutableAreaSizeInBytes, PROT_EXEC | PROT_READ - | PROT_WRITE, MAP_PRIVATE | MAP_ANON | Extra, -1, 0); + void* p = mmap(0, sizeInBytes, PROT_EXEC | PROT_READ + | PROT_WRITE, MAP_PRIVATE | MAP_ANON | Extra, -1, 0); - if (p != MAP_FAILED) { - executableArea = static_cast(p); - } - } - - if (executableArea - and executableOffset + pad(sizeInBytes) < ExecutableAreaSizeInBytes) - { - void* r = executableArea + executableOffset; - executableOffset += pad(sizeInBytes); - return r; - } else { + if (p == MAP_FAILED) { return 0; + } else { + return static_cast(p); } } - virtual void freeExecutable(const void*, unsigned) { - // ignore + virtual void freeExecutable(const void* p, unsigned sizeInBytes) { + munmap(p, sizeInBytes); } virtual bool success(Status s) { diff --git a/src/processor.h b/src/processor.h index 94177a9abd..3724b2c96d 100644 --- a/src/processor.h +++ b/src/processor.h @@ -117,12 +117,11 @@ class Processor { getStackTrace(Thread* t, Thread* target) = 0; virtual void - compileThunks(Thread* t, BootImage* image, uint8_t* code, unsigned* size, - unsigned capacity) = 0; + initialize(Thread* t, BootImage* image, uint8_t* code, + unsigned capacity) = 0; virtual void - compileMethod(Thread* t, Zone* zone, uint8_t* code, unsigned* offset, - unsigned capacity, object* constants, object* calls, + compileMethod(Thread* t, Zone* zone, object* constants, object* calls, DelayedPromise** addresses, object method) = 0; virtual void diff --git a/src/types.def b/src/types.def index 2fa84d82e3..6dd1bc6092 100644 --- a/src/types.def +++ b/src/types.def @@ -97,6 +97,9 @@ (uintptr_t flags) (object next)) +(type wordArray + (array uintptr_t body)) + (type array (noassert array object body)) diff --git a/src/windows.cpp b/src/windows.cpp index 01d7a24f99..6487e5165b 100644 --- a/src/windows.cpp +++ b/src/windows.cpp @@ -523,8 +523,6 @@ class MySystem: public System { } virtual void* tryAllocateExecutable(unsigned sizeInBytes) { - assert(this, sizeInBytes % LikelyPageSizeInBytes == 0); - return VirtualAlloc (0, sizeInBytes, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); } From 35d1c6e0684a3eb0e7913d9a436d5f0ec99deeda Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 6 Apr 2009 18:34:12 -0600 Subject: [PATCH 003/172] add SingleRead::successor; fix build errors The SingleRead::successor field is used (when non-null) to further constrain the SiteMask in SingleRead::intersect based on reads of successor values (as in the cases of moves and condensed-addressing combine and translate instructions). --- src/bootimage.h | 6 ++ src/compile.cpp | 194 +++++++++++++++++++++++++++++++++-------------- src/compiler.cpp | 65 +++++++++++----- src/compiler.h | 3 +- src/posix.cpp | 7 +- src/powerpc.cpp | 7 ++ src/x86.cpp | 13 +++- 7 files changed, 209 insertions(+), 86 deletions(-) diff --git a/src/bootimage.h b/src/bootimage.h index 54ccf136c2..c8df51c0c6 100644 --- a/src/bootimage.h +++ b/src/bootimage.h @@ -44,13 +44,19 @@ class BootImage { uintptr_t codeBase; unsigned defaultThunk; + unsigned defaultTailThunk; + unsigned defaultVirtualThunk; + unsigned tailHelperThunk; unsigned nativeThunk; + unsigned nativeTailThunk; unsigned aioobThunk; unsigned thunkTable; unsigned thunkSize; unsigned compileMethodCall; + unsigned compileVirtualMethodCall; + unsigned tailCallCall; unsigned invokeNativeCall; unsigned throwArrayIndexOutOfBoundsCall; diff --git a/src/compile.cpp b/src/compile.cpp index 5872933083..f27fdcb3a5 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -76,6 +76,9 @@ class MyThread: public Thread { ip(0), base(0), stack(0), + tailAddress(0), + virtualCallClass(0), + virtualCallIndex(0), trace(0), reference(0), arch(parent ? parent->arch : makeArchitecture(m->system)) @@ -86,6 +89,9 @@ class MyThread: public Thread { void* ip; void* base; void* stack; + void* tailAddress; + void* virtualCallClass; + uintptr_t virtualCallIndex; CallTrace* trace; Reference* reference; Assembler::Architecture* arch; @@ -441,8 +447,8 @@ class Context; class TraceElement: public TraceHandler { public: - const unsigned VirtualCall = 1 << 0; - const unsigned TailCall = 1 << 1; + static const unsigned VirtualCall = 1 << 0; + static const unsigned TailCall = 1 << 1; TraceElement(Context* context, object target, unsigned flags, TraceElement* next): @@ -477,7 +483,7 @@ class TraceElement: public TraceHandler { class TraceElementPromise: public Promise { public: - TraceElementPromise(TraceElement* trace): trace(trace) { } + TraceElementPromise(System* s, TraceElement* trace): s(s), trace(trace) { } virtual int64_t value() { assert(s, resolved()); @@ -1352,12 +1358,24 @@ objectPools(MyThread* t); uintptr_t defaultThunk(MyThread* t); +uintptr_t +defaultTailThunk(MyThread* t); + uintptr_t nativeThunk(MyThread* t); +uintptr_t +nativeTailThunk(MyThread* t); + +uintptr_t +tailHelperThunk(MyThread* t); + uintptr_t aioobThunk(MyThread* t); +uintptr_t +virtualThunk(MyThread* t, unsigned index); + uintptr_t methodAddress(Thread* t, object method) { @@ -1378,6 +1396,10 @@ tryInitClass(MyThread* t, object class_) FixedAllocator* codeAllocator(MyThread* t); +void +compile(MyThread* t, Allocator* allocator, BootContext* bootContext, + object method); + int64_t findInterfaceMethodFromInstance(MyThread* t, object method, object instance) { @@ -1916,6 +1938,8 @@ Compiler::Operand* compileDirectInvoke(MyThread* t, Frame* frame, object target, bool tailCall, bool useThunk, unsigned rSize, Promise* addressPromise) { + Compiler* c = frame->c; + if (tailCall and methodParameterFootprint(t, target) > methodParameterFootprint(t, frame->context->method)) { @@ -1930,7 +1954,6 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target, bool tailCall, (c->constant(nativeTailThunk(t)), Compiler::TailCall, frame->trace(target, TraceElement::TailCall), - trace, rSize, methodParameterFootprint(t, target)); } else { @@ -1956,11 +1979,11 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target, bool tailCall, return result; } else { return c->stackCall - (address, - flags | Compiler::Aligned, - frame->trace(target, 0), - rSize, - methodParameterFootprint(t, target)); + (c->constant(defaultThunk(t)), + flags | Compiler::Aligned, + frame->trace(target, 0), + rSize, + methodParameterFootprint(t, target)); } } else { Compiler::Operand* address = @@ -1969,10 +1992,10 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target, bool tailCall, : c->constant(methodAddress(t, target))); return c->stackCall - (c->promiseConstant(p), + (address, flags, tailCall ? 0 : frame->trace - ((methodFlags(t, target) & ACC_NATIVE) ? target, 0), + ((methodFlags(t, target) & ACC_NATIVE) ? target : 0, 0), rSize, methodParameterFootprint(t, target)); } @@ -1982,8 +2005,6 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target, bool tailCall, void compileDirectInvoke(MyThread* t, Frame* frame, object target, bool tailCall) { - Compiler* c = frame->c; - unsigned rSize = resultSize(t, methodReturnCode(t, target)); Compiler::Operand* result = 0; @@ -2043,7 +2064,7 @@ handleMonitorEvent(MyThread* t, Frame* frame, intptr_t function) 0, frame->trace(0, 0), 0, - 2, c->thread(), lock); + 2, c->register_(t->arch->thread()), lock); } } @@ -2229,7 +2250,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, 0, frame->trace(0, 0), 0, - 1, c->thread()); + 1, c->register_(t->arch->thread())); } // fprintf(stderr, "ip: %d map: %ld\n", ip, *(frame->map)); @@ -2329,7 +2350,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, 0, frame->trace(0, 0), 0, - 4, c->thread(), array, + 4, c->register_(t->arch->thread()), array, c->add(4, c->constant(ArrayBody), c->shl(4, c->constant(log(BytesPerWord)), index)), value); @@ -2397,7 +2418,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, 0, frame->trace(0, 0), BytesPerWord, - 3, c->thread(), frame->append(class_), length)); + 3, c->register_(t->arch->thread()), frame->append(class_), length)); } break; case areturn: { @@ -2439,7 +2460,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::NoReturn, frame->trace(0, 0), 0, - 2, c->thread(), target); + 2, c->register_(t->arch->thread()), target); } return; case bipush: @@ -2460,7 +2481,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, 0, frame->trace(0, 0), 0, - 3, c->thread(), frame->append(class_), instance); + 3, c->register_(t->arch->thread()), frame->append(class_), instance); } break; case d2f: { @@ -2741,7 +2762,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, 0, frame->trace(0, 0), 0, - 2, c->thread(), frame->append(fieldClass(t, field))); + 2, c->register_(t->arch->thread()), + frame->append(fieldClass(t, field))); } table = frame->append(classStaticTable(t, fieldClass(t, field))); @@ -2766,7 +2788,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, c->call (c->constant(getThunk(t, acquireMonitorForObjectThunk)), - 0, frame->trace(0, 0), 0, 2, c->thread(), fieldOperand); + 0, frame->trace(0, 0), 0, 2, c->register_(t->arch->thread()), + fieldOperand); } switch (fieldCode(t, field)) { @@ -2820,7 +2843,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, { c->call (c->constant(getThunk(t, releaseMonitorForObjectThunk)), - 0, frame->trace(0, 0), 0, 2, c->thread(), fieldOperand); + 0, frame->trace(0, 0), 0, 2, c->register_(t->arch->thread()), + fieldOperand); } else { c->loadBarrier(); } @@ -3094,7 +3118,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, (c->call (c->constant(getThunk(t, instanceOf64Thunk)), 0, 0, 4, - 3, c->thread(), frame->append(class_), frame->popObject())); + 3, c->register_(t->arch->thread()), frame->append(class_), + frame->popObject())); } break; case invokeinterface: { @@ -3119,7 +3144,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, 0, frame->trace(0, 0), BytesPerWord, - 3, c->thread(), frame->append(target), + 3, c->register_(t->arch->thread()), frame->append(target), c->peek(1, instance)), 0, frame->trace(0, 0), @@ -3583,14 +3608,14 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* target = frame->popObject(); c->call (c->constant(getThunk(t, acquireMonitorForObjectThunk)), - 0, frame->trace(0, 0), 0, 2, c->thread(), target); + 0, frame->trace(0, 0), 0, 2, c->register_(t->arch->thread()), target); } break; case monitorexit: { Compiler::Operand* target = frame->popObject(); c->call (c->constant(getThunk(t, releaseMonitorForObjectThunk)), - 0, frame->trace(0, 0), 0, 2, c->thread(), target); + 0, frame->trace(0, 0), 0, 2, c->register_(t->arch->thread()), target); } break; case multianewarray: { @@ -3612,8 +3637,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, 0, frame->trace(0, 0), BytesPerWord, - 4, c->thread(), frame->append(class_), c->constant(dimensions), - c->constant(offset)); + 4, c->register_(t->arch->thread()), frame->append(class_), + c->constant(dimensions), c->constant(offset)); frame->pop(dimensions); frame->pushObject(result); @@ -3632,7 +3657,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, 0, frame->trace(0, 0), BytesPerWord, - 2, c->thread(), frame->append(class_))); + 2, c->register_(t->arch->thread()), frame->append(class_))); } else { frame->pushObject (c->call @@ -3640,7 +3665,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, 0, frame->trace(0, 0), BytesPerWord, - 2, c->thread(), frame->append(class_))); + 2, c->register_(t->arch->thread()), frame->append(class_))); } } break; @@ -3655,7 +3680,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, 0, frame->trace(0, 0), BytesPerWord, - 3, c->thread(), c->constant(type), length)); + 3, c->register_(t->arch->thread()), c->constant(type), length)); } break; case nop: break; @@ -3688,7 +3713,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, 0, frame->trace(0, 0), 0, - 2, c->thread(), frame->append(fieldClass(t, field))); + 2, c->register_(t->arch->thread()), + frame->append(fieldClass(t, field))); } staticTable = classStaticTable(t, fieldClass(t, field)); @@ -3742,7 +3768,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, c->call (c->constant(getThunk(t, acquireMonitorForObjectThunk)), - 0, frame->trace(0, 0), 0, 2, c->thread(), fieldOperand); + 0, frame->trace(0, 0), 0, 2, c->register_(t->arch->thread()), + fieldOperand); } else { c->storeStoreBarrier(); } @@ -3779,12 +3806,14 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, 0, frame->trace(0, 0), 0, - 4, c->thread(), table, c->constant(fieldOffset(t, field)), value); + 4, c->register_(t->arch->thread()), table, + c->constant(fieldOffset(t, field)), value); } else { c->call (c->constant(getThunk(t, setThunk)), 0, 0, 0, - 4, c->thread(), table, c->constant(fieldOffset(t, field)), value); + 4, c->register_(t->arch->thread()), table, + c->constant(fieldOffset(t, field)), value); } break; @@ -3798,7 +3827,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, { c->call (c->constant(getThunk(t, releaseMonitorForObjectThunk)), - 0, frame->trace(0, 0), 0, 2, c->thread(), fieldOperand); + 0, frame->trace(0, 0), 0, 2, c->register_(t->arch->thread()), + fieldOperand); } else { c->storeLoadBarrier(); } @@ -4562,12 +4592,8 @@ updateCall(MyThread* t, UnaryOperation op, bool assertAlignment, t->arch->updateCall(op, assertAlignment, returnAddress, target); } -void -compile(MyThread* t, Allocator* allocator, BootContext* bootContext, - object method); - void* -compileMethod2(MyThread* t, uintptr_t ip) +compileMethod2(MyThread* t, void* ip) { object node = findCallNode(t, ip); PROTECT(t, node); @@ -4583,12 +4609,12 @@ compileMethod2(MyThread* t, uintptr_t ip) return 0; } else { void* address = reinterpret_cast(methodAddress(t, target)); - uintptr_t updateIp = ip; - if (callNode(t, node) & TraceElement::TailCall) { + uint8_t* updateIp = static_cast(ip); + if (callNodeFlags(t, node) & TraceElement::TailCall) { updateIp -= t->arch->constantCallSize(); } - updateCall(t, Call, true, reinterpret_cast(updateIp), address); + updateCall(t, Call, true, updateIp, address); return address; } @@ -4597,7 +4623,7 @@ compileMethod2(MyThread* t, uintptr_t ip) uint64_t compileMethod(MyThread* t) { - uintptr_t ip; + void* ip; if (t->tailAddress) { ip = t->tailAddress; t->tailAddress = 0; @@ -4629,7 +4655,7 @@ compileVirtualMethod2(MyThread* t, object class_, unsigned index) return 0; } else { void* address = reinterpret_cast(methodAddress(t, target)); - if (address != nativeThunk(t, method)) { + if (address != reinterpret_cast(nativeThunk(t))) { classVtable(t, class_, methodOffset(t, target)) = address; } return address; @@ -4639,7 +4665,7 @@ compileVirtualMethod2(MyThread* t, object class_, unsigned index) uint64_t compileVirtualMethod(MyThread* t) { - object class_ = t->virtualCallClass; + object class_ = static_cast(t->virtualCallClass); t->virtualCallClass = 0; unsigned index = t->virtualCallIndex; @@ -4655,7 +4681,7 @@ compileVirtualMethod(MyThread* t) } void* -tailCall2(MyThread* t, uintptr_t ip) +tailCall2(MyThread* t, void* ip) { object node = findCallNode(t, ip); PROTECT(t, node); @@ -4678,7 +4704,9 @@ tailCall2(MyThread* t, uintptr_t ip) void* stack = t->stack; t->arch->nextFrame(&stack, &base); - if (t->arch->matchCall(t->arch->frameIp(stack), tailHelperThunk(t))) { + if (t->arch->matchCall(t->arch->frameIp(stack), + reinterpret_cast(tailHelperThunk(t)))) + { void* nextBase = base; void* nextStack = stack; t->arch->nextFrame(&nextStack, &nextBase); @@ -4896,7 +4924,7 @@ uint64_t invokeNative(MyThread* t) { if (t->trace->nativeMethod == 0) { - uintptr_t ip; + void* ip; if (t->tailAddress) { ip = t->tailAddress; t->tailAddress = 0; @@ -5276,7 +5304,11 @@ class MyProcessor: public Processor { s(s), allocator(allocator), defaultThunk(0), + defaultTailThunk(0), + defaultVirtualThunk(0), + tailHelperThunk(0), nativeThunk(0), + nativeTailThunk(0), aioobThunk(0), callTable(0), callTableSize(0), @@ -5346,7 +5378,8 @@ class MyProcessor: public Processor { initVtable(Thread* t, object c) { for (unsigned i = 0; i < classLength(t, c); ++i) { - classVtable(t, c, i) = virtualThunk(static_cast(t), i); + classVtable(t, c, i) = reinterpret_cast + (virtualThunk(static_cast(t), i)); } } @@ -5650,7 +5683,7 @@ class MyProcessor: public Processor { table[index++] = callNodeAddress(t, p) - reinterpret_cast(code); table[index++] = w->map()->find(callNodeTarget(t, p)) - | (static_cast(callNodeFlags(t, node)) << BootShift); + | (static_cast(callNodeFlags(t, p)) << BootShift); } } @@ -5658,7 +5691,8 @@ class MyProcessor: public Processor { } virtual void boot(Thread* t, BootImage* image) { - codeAllocator.base = s->tryAllocateExecutable(ExecutableAreaSizeInBytes); + codeAllocator.base = static_cast + (s->tryAllocateExecutable(ExecutableAreaSizeInBytes)); codeAllocator.capacity = ExecutableAreaSizeInBytes; if (image) { @@ -5681,7 +5715,11 @@ class MyProcessor: public Processor { System* s; Allocator* allocator; uint8_t* defaultThunk; + uint8_t* defaultTailThunk; + uint8_t* defaultVirtualThunk; + uint8_t* tailHelperThunk; uint8_t* nativeThunk; + uint8_t* nativeTailThunk; uint8_t* aioobThunk; uint8_t* thunkTable; unsigned thunkSize; @@ -5965,11 +6003,23 @@ fixupThunks(MyThread* t, BootImage* image, uint8_t* code) MyProcessor* p = processor(t); p->defaultThunk = code + image->defaultThunk; + p->defaultTailThunk = code + image->defaultTailThunk; updateCall(t, LongCall, false, code + image->compileMethodCall, voidPointer(::compileMethod)); + p->defaultVirtualThunk = code + image->defaultVirtualThunk; + + updateCall(t, LongCall, false, code + image->compileVirtualMethodCall, + voidPointer(::compileVirtualMethod)); + + p->tailHelperThunk = code + image->tailHelperThunk; + + updateCall(t, LongCall, false, code + image->tailCallCall, + voidPointer(::tailCall)); + p->nativeThunk = code + image->nativeThunk; + p->nativeTailThunk = code + image->nativeTailThunk; updateCall(t, LongCall, false, code + image->invokeNativeCall, voidPointer(invokeNative)); @@ -6263,7 +6313,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, if (image) { image->tailHelperThunk = p->tailHelperThunk - imageBase; - image->tailHelperCall = static_cast(call) - imageBase; + image->tailCallCall = static_cast(call) - imageBase; } } @@ -6344,12 +6394,36 @@ defaultThunk(MyThread* t) return reinterpret_cast(processor(t)->defaultThunk); } +uintptr_t +defaultTailThunk(MyThread* t) +{ + return reinterpret_cast(processor(t)->defaultTailThunk); +} + +uintptr_t +defaultVirtualThunk(MyThread* t) +{ + return reinterpret_cast(processor(t)->defaultVirtualThunk); +} + +uintptr_t +tailHelperThunk(MyThread* t) +{ + return reinterpret_cast(processor(t)->tailHelperThunk); +} + uintptr_t nativeThunk(MyThread* t) { return reinterpret_cast(processor(t)->nativeThunk); } +uintptr_t +nativeTailThunk(MyThread* t) +{ + return reinterpret_cast(processor(t)->nativeTailThunk); +} + uintptr_t aioobThunk(MyThread* t) { @@ -6359,18 +6433,22 @@ aioobThunk(MyThread* t) uintptr_t compileVirtualThunk(MyThread* t, unsigned index) { - Context context; + Context context(t); Assembler* a = context.assembler; - Assembler::Constant indexConstant(index); + ResolvedPromise indexPromise(index); + Assembler::Constant indexConstant(&indexPromise); Assembler::Register indexRegister(t->arch->returnHigh()); a->apply(Move, BytesPerWord, ConstantOperand, &indexConstant, BytesPerWord, ConstantOperand, &indexRegister); - Assembler::Constant thunk(defaultVirtualThunk(t)); + ResolvedPromise defaultVirtualThunkPromise(defaultVirtualThunk(t)); + Assembler::Constant thunk(&defaultVirtualThunkPromise); a->apply(Jump, BytesPerWord, ConstantOperand, &thunk); - uint8_t* start = codeAllocator(t)->allocate(a->length()); + uint8_t* start = static_cast + (codeAllocator(t)->allocate(a->length())); + a->writeTo(start); } diff --git a/src/compiler.cpp b/src/compiler.cpp index 3812e2692d..894b567dce 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -286,6 +286,13 @@ intersect(const SiteMask& a, const SiteMask& b) intersectFrameIndexes(a.frameIndex, b.frameIndex)); } +bool +valid(const SiteMask& a) +{ + return a.typeMask + and ((a.typeMask & ~(1 << RegisterOperand)) or a.registerMask); +} + class Value: public Compiler::Operand { public: Value(Site* site, Site* target): @@ -1879,12 +1886,25 @@ release(Context* c, Resource* resource, Value* value UNUSED, Site* site UNUSED) class SingleRead: public Read { public: - SingleRead(const SiteMask& mask): - next_(0), mask(mask) + SingleRead(const SiteMask& mask, Value* successor): + next_(0), mask(mask), successor(successor) { } virtual bool intersect(SiteMask* mask) { - *mask = ::intersect(*mask, this->mask); + SiteMask result = ::intersect(*mask, this->mask); + + if (successor) { + Read* r = live(successor); + if (r) { + SiteMask intersection = result; + bool valid = r->intersect(&intersection); + if (valid and ::valid(intersection)) { + result = intersection; + } + } + } + + *mask = result; return true; } @@ -1904,15 +1924,16 @@ class SingleRead: public Read { Read* next_; SiteMask mask; + Value* successor; }; Read* -read(Context* c, const SiteMask& mask) +read(Context* c, const SiteMask& mask, Value* successor = 0) { assert(c, (mask.typeMask != 1 << MemoryOperand) or mask.frameIndex >= 0); return new (c->zone->allocate(sizeof(SingleRead))) - SingleRead(mask); + SingleRead(mask, successor); } Read* @@ -2681,15 +2702,19 @@ class MoveEvent: public Event { { assert(c, srcSelectSize <= srcSize); - addRead(c, this, src, read(c, srcLowMask)); - if (srcSelectSize > BytesPerWord) { - maybeSplit(c, src); - addRead(c, this, src->high, read(c, srcHighMask)); - } + bool noop = srcSelectSize >= dstSize; if (dstSize > BytesPerWord) { grow(c, dst); } + + addRead(c, this, src, read(c, srcLowMask, noop ? dst : 0)); + if (srcSelectSize > BytesPerWord) { + maybeSplit(c, src); + addRead(c, this, src->high, read + (c, srcHighMask, + noop and dstSize > BytesPerWord ? dst->high : 0)); + } } virtual const char* name() { @@ -2966,14 +2991,17 @@ class CombineEvent: public Event { addRead(c, this, first->high, read(c, firstHighMask)); } - addRead(c, this, second, read(c, secondLowMask)); - if (secondSize > BytesPerWord) { - addRead(c, this, second->high, read(c, secondHighMask)); - } - if (resultSize > BytesPerWord) { grow(c, result); } + + bool condensed = c->arch->condensedAddressing(); + + addRead(c, this, second, read(c, secondLowMask, condensed ? result : 0)); + if (secondSize > BytesPerWord) { + addRead(c, this, second->high, read + (c, secondHighMask, condensed ? result->high : 0)); + } } virtual const char* name() { @@ -3367,10 +3395,13 @@ class TranslateEvent: public Event { Event(c), type(type), size(size), value(value), result(result), resultLowMask(resultLowMask), resultHighMask(resultHighMask) { - addRead(c, this, value, read(c, valueLowMask)); + bool condensed = c->arch->condensedAddressing(); + + addRead(c, this, value, read(c, valueLowMask, condensed ? result : 0)); if (size > BytesPerWord) { - addRead(c, this, value->high, read(c, valueHighMask)); grow(c, result); + addRead(c, this, value->high, read + (c, valueHighMask, condensed ? result->high : 0)); } } diff --git a/src/compiler.h b/src/compiler.h index 6361f2bf25..4678d44614 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -60,8 +60,7 @@ class Compiler { Operand* index = 0, unsigned scale = 1) = 0; - virtual Operand* thread() = 0; - virtual Operand* stack() = 0; + virtual Operand* register_(int number) = 0; virtual void freezeRegister(int number, Operand* value) = 0; virtual void thawRegister(int number) = 0; diff --git a/src/posix.cpp b/src/posix.cpp index ad4a8c871a..9d5e112773 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -571,7 +571,7 @@ class MySystem: public System { } virtual void freeExecutable(const void* p, unsigned sizeInBytes) { - munmap(p, sizeInBytes); + munmap(const_cast(p), sizeInBytes); } virtual bool success(Status s) { @@ -766,11 +766,6 @@ class MySystem: public System { registerHandler(0, VisitSignalIndex); system = 0; - if (executableArea) { - int r UNUSED = munmap(executableArea, ExecutableAreaSizeInBytes); - assert(this, r == 0); - } - ::free(this); } diff --git a/src/powerpc.cpp b/src/powerpc.cpp index 430e507585..13d0ab819c 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -1713,6 +1713,13 @@ class MyArchitecture: public Assembler::Architecture { return index + 3; } + virtual bool matchCall(void* returnAddress, void* target) { + uint32_t* instruction = static_cast(returnAddress) - 1; + + return *instruction == bl(static_cast(target) + - reinterpret_cast(instruction)); + } + virtual void updateCall(UnaryOperation op UNUSED, bool assertAlignment UNUSED, void* returnAddress, void* newTarget) diff --git a/src/x86.cpp b/src/x86.cpp index 39f35c4bf6..0854ad1eb9 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -2057,9 +2057,16 @@ class MyArchitecture: public Assembler::Architecture { } } - virtual void updateCall(UnaryOperation op UNUSED, - bool assertAlignment UNUSED, void* returnAddress, - void* newTarget) + virtual bool matchCall(void* returnAddress, void* target) { + uint8_t* instruction = static_cast(returnAddress) - 5; + int32_t actualOffset; memcpy(&actualOffset, instruction + 1, 4); + void* actualTarget = static_cast(returnAddress) + actualOffset; + + return *instruction == 0xE8 and actualTarget == target; + } + + virtual void updateCall(UnaryOperation op, bool assertAlignment UNUSED, + void* returnAddress, void* newTarget) { if (BytesPerWord == 4 or op == Call or op == Jump) { uint8_t* instruction = static_cast(returnAddress) - 5; From dba72409aa99b8c211c50ec0413d551f4adaeddd Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 7 Apr 2009 18:55:43 -0600 Subject: [PATCH 004/172] move use of SingleRead::successor; fix build errors We now use SingleRead::successor in pickTarget, where we use it to determine the prefered target site for the successor without requiring the target to conform to that preference. The previous code made the preference a hard requirement, which is not desirable or even possible in general. --- src/assembler.h | 3 + src/compile.cpp | 4 +- src/compiler.cpp | 144 ++++++++++++++++++++++++++--------------------- src/compiler.h | 1 + src/x86.cpp | 32 +++++++++++ 5 files changed, 119 insertions(+), 65 deletions(-) diff --git a/src/assembler.h b/src/assembler.h index 8c2a61ee44..e208a5bc6e 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -31,6 +31,7 @@ enum UnaryOperation { AlignedCall, Jump, LongJump, + AlignedJump, JumpIfLess, JumpIfGreater, JumpIfLessOrEqual, @@ -318,7 +319,9 @@ class Assembler { virtual Architecture* arch() = 0; + virtual void popReturnAddress(unsigned addressOffset) = 0; virtual void saveFrame(unsigned stackOffset, unsigned baseOffset) = 0; + virtual void restoreFrame(unsigned stackOffset, unsigned baseOffset) = 0; virtual void pushFrame(unsigned argumentCount, ...) = 0; virtual void allocateFrame(unsigned footprint) = 0; virtual void popFrame() = 0; diff --git a/src/compile.cpp b/src/compile.cpp index f27fdcb3a5..979463fc7a 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -1957,7 +1957,7 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target, bool tailCall, rSize, methodParameterFootprint(t, target)); } else { - unsigned flags = (tailCall ? Compiler::TailCall : 0); + unsigned flags = (tailCall ? Compiler::TailJump : 0); if (useThunk) { if (tailCall) { @@ -6450,6 +6450,8 @@ compileVirtualThunk(MyThread* t, unsigned index) (codeAllocator(t)->allocate(a->length())); a->writeTo(start); + + return reinterpret_cast(start); } uintptr_t diff --git a/src/compiler.cpp b/src/compiler.cpp index 894b567dce..edcc82d3a2 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -257,6 +257,8 @@ class Read { { } virtual bool intersect(SiteMask* mask) = 0; + + virtual Value* successor() = 0; virtual bool valid() = 0; @@ -286,13 +288,6 @@ intersect(const SiteMask& a, const SiteMask& b) intersectFrameIndexes(a.frameIndex, b.frameIndex)); } -bool -valid(const SiteMask& a) -{ - return a.typeMask - and ((a.typeMask & ~(1 << RegisterOperand)) or a.registerMask); -} - class Value: public Compiler::Operand { public: Value(Site* site, Site* target): @@ -1191,18 +1186,11 @@ pickAnyFrameTarget(Context* c, Value* v) } Target -pickTarget(Context* c, Read* read, bool intersectRead, - unsigned registerReserveCount) +pickTarget(Context* c, Value* value, const SiteMask& mask, + unsigned registerPenalty, Target best) { - SiteMask mask; - read->intersect(&mask); - - unsigned registerPenalty = (c->availableRegisterCount > registerReserveCount - ? 0 : Target::Penalty); - - Target best; if (mask.typeMask & (1 << RegisterOperand)) { - Target mine = pickRegisterTarget(c, read->value, mask.registerMask); + Target mine = pickRegisterTarget(c, value, mask.registerMask); mine.cost += registerPenalty; @@ -1215,7 +1203,7 @@ pickTarget(Context* c, Read* read, bool intersectRead, if ((mask.typeMask & (1 << MemoryOperand)) && mask.frameIndex >= 0) { Target mine(mask.frameIndex, MemoryOperand, - frameCost(c, read->value, mask.frameIndex)); + frameCost(c, value, mask.frameIndex)); if (mine.cost == 0) { return mine; } else if (mine.cost < best.cost) { @@ -1223,6 +1211,40 @@ pickTarget(Context* c, Read* read, bool intersectRead, } } + return best; +} + +Target +pickTarget(Context* c, Read* read, bool intersectRead, + unsigned registerReserveCount) +{ + unsigned registerPenalty = (c->availableRegisterCount > registerReserveCount + ? 0 : Target::Penalty); + + SiteMask mask; + read->intersect(&mask); + + Target best; + + Value* successor = read->successor(); + if (successor) { + Read* r = live(successor); + if (r) { + SiteMask intersection = mask; + if (r->intersect(&intersection)) { + best = pickTarget(c, read->value, mask, registerPenalty, best); + if (best.cost == 0) { + return best; + } + } + } + } + + best = pickTarget(c, read->value, mask, registerPenalty, best); + if (best.cost == 0) { + return best; + } + if (intersectRead) { return best; } @@ -1887,27 +1909,18 @@ release(Context* c, Resource* resource, Value* value UNUSED, Site* site UNUSED) class SingleRead: public Read { public: SingleRead(const SiteMask& mask, Value* successor): - next_(0), mask(mask), successor(successor) + next_(0), mask(mask), successor_(successor) { } virtual bool intersect(SiteMask* mask) { - SiteMask result = ::intersect(*mask, this->mask); - - if (successor) { - Read* r = live(successor); - if (r) { - SiteMask intersection = result; - bool valid = r->intersect(&intersection); - if (valid and ::valid(intersection)) { - result = intersection; - } - } - } - - *mask = result; + *mask = ::intersect(*mask, this->mask); return true; } + + virtual Value* successor() { + return successor_; + } virtual bool valid() { return true; @@ -1924,7 +1937,7 @@ class SingleRead: public Read { Read* next_; SiteMask mask; - Value* successor; + Value* successor_; }; Read* @@ -1981,6 +1994,10 @@ class MultiRead: public Read { return result; } + virtual Value* successor() { + return 0; + } + virtual bool valid() { bool result = false; if (not visited) { @@ -2008,7 +2025,7 @@ class MultiRead: public Read { } lastRead = cell; -// fprintf(stderr, "append %p to %p for %p\n", r, lastTarget, this); + // fprintf(stderr, "append %p to %p for %p\n", r, lastTarget, this); lastTarget->value = r; } @@ -2020,7 +2037,7 @@ class MultiRead: public Read { void allocateTarget(Context* c) { Cell* cell = cons(c, 0, 0); -// fprintf(stderr, "allocate target for %p: %p\n", this, cell); + // fprintf(stderr, "allocate target for %p: %p\n", this, cell); if (lastTarget) { lastTarget->next = cell; @@ -2031,7 +2048,7 @@ class MultiRead: public Read { } Read* nextTarget() { -// fprintf(stderr, "next target for %p: %p\n", this, firstTarget); + // fprintf(stderr, "next target for %p: %p\n", this, firstTarget); Read* r = static_cast(firstTarget->value); firstTarget = firstTarget->next; @@ -2071,6 +2088,10 @@ class StubRead: public Read { return valid_; } + virtual Value* successor() { + return 0; + } + virtual bool valid() { return valid_; } @@ -2180,9 +2201,9 @@ addRead(Context* c, Event* e, Value* v, Read* r) } if (v->lastRead) { -// if (DebugReads) { -// fprintf(stderr, "append %p to %p for %p\n", r, v->lastRead, v); -// } + // if (DebugReads) { + // fprintf(stderr, "append %p to %p for %p\n", r, v->lastRead, v); + // } v->lastRead->append(c, r); } else { @@ -2334,7 +2355,7 @@ class CallEvent: public Event { (typeMask, registerMask & planRegisterMask, AnyFrameIndex))); } - if ((flags & (Compiler::TailJump | Compiler::TailCall)_ == 0) { + if ((flags & (Compiler::TailJump | Compiler::TailCall)) == 0) { int footprint = stackArgumentFootprint; for (Stack* s = stackBefore; s; s = s->next) { if (s->value) { @@ -2932,7 +2953,7 @@ getTarget(Context* c, Value* value, Value* result, const SiteMask& resultMask) preserve(c, v, s, r); } } else { - SingleRead r(resultMask); + SingleRead r(resultMask, 0); s = pickTargetSite(c, &r, true); v = result; addSite(c, result, s); @@ -3017,7 +3038,7 @@ class CombineEvent: public Event { ? getTarget(c, second->high, result->high, resultHighMask) : 0); -// fprintf(stderr, "combine %p and %p into %p\n", first, second, result); + // fprintf(stderr, "combine %p and %p into %p\n", first, second, result); apply(c, type, firstSize, first->source, source(first->high), secondSize, second->source, source(second->high), resultSize, low, high); @@ -3783,11 +3804,11 @@ frameFootprint(Context* c, Stack* s) void visit(Context* c, Link* link) { -// fprintf(stderr, "visit link from %d to %d fork %p junction %p\n", -// link->predecessor->logicalInstruction->index, -// link->successor->logicalInstruction->index, -// link->forkState, -// link->junctionState); + // fprintf(stderr, "visit link from %d to %d fork %p junction %p\n", + // link->predecessor->logicalInstruction->index, + // link->successor->logicalInstruction->index, + // link->forkState, + // link->junctionState); ForkState* forkState = link->forkState; if (forkState) { @@ -3795,7 +3816,7 @@ visit(Context* c, Link* link) ForkElement* p = forkState->elements + i; Value* v = p->value; v->reads = p->read->nextTarget(); -// fprintf(stderr, "next read %p for %p from %p\n", v->reads, v, p->read); + // fprintf(stderr, "next read %p for %p from %p\n", v->reads, v, p->read); if (not live(v)) { clearSites(c, v); } @@ -3828,7 +3849,7 @@ class BuddyEvent: public Event { } virtual void compile(Context* c) { -// fprintf(stderr, "original %p buddy %p\n", original, buddy); + // fprintf(stderr, "original %p buddy %p\n", original, buddy); assert(c, hasSite(original)); addBuddy(original, buddy); @@ -3886,7 +3907,7 @@ class FreezeRegisterEvent: public Event { } virtual void compile(Context* c) { - c->registers[number].freeze(c, value); + c->registerResources[number].freeze(c, value); for (Read* r = reads; r; r = r->eventNext) { popRead(c, this, r->value); @@ -3915,17 +3936,17 @@ class ThawRegisterEvent: public Event { } virtual void compile(Context* c) { - c->registers[number].thaw(c, value); + c->registerResources[number].thaw(c, 0); } int number; }; void -appendThawRegister(Context* c, int number, Value* value) +appendThawRegister(Context* c, int number) { append(c, new (c->zone->allocate(sizeof(ThawRegisterEvent))) - ThawRegisterEvent(c, number, value)); + ThawRegisterEvent(c, number)); } class DummyEvent: public Event { @@ -4418,9 +4439,9 @@ void restore(Context* c, Event* e, Snapshot* snapshots) { for (Snapshot* s = snapshots; s; s = s->next) { -// char buffer[256]; sitesToString(c, s->sites, buffer, 256); -// fprintf(stderr, "restore %p buddy %p sites %s live %p\n", -// s->value, s->value->buddy, buffer, live(s->value)); + // char buffer[256]; sitesToString(c, s->sites, buffer, 256); + // fprintf(stderr, "restore %p buddy %p sites %s live %p\n", + // s->value, s->value->buddy, buffer, live(s->value)); s->value->buddy = s->buddy; } @@ -5001,13 +5022,8 @@ class MyCompiler: public Compiler { return result; } - virtual Operand* stack() { - Site* s = registerSite(&c, c.arch->stack()); - return value(&c, s, s); - } - - virtual Operand* thread() { - Site* s = registerSite(&c, c.arch->thread()); + virtual Operand* register_(int number) { + Site* s = registerSite(&c, number); return value(&c, s, s); } diff --git a/src/compiler.h b/src/compiler.h index 4678d44614..b2fed6f48a 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -28,6 +28,7 @@ class Compiler { static const unsigned Aligned = 1 << 0; static const unsigned NoReturn = 1 << 1; static const unsigned TailCall = 1 << 2; + static const unsigned TailJump = 1 << 3; class Operand { }; class StackElement { }; diff --git a/src/x86.cpp b/src/x86.cpp index 0854ad1eb9..05ec897bfb 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -703,6 +703,21 @@ popR(Context* c, unsigned size, Assembler::Register* a) } } +void +popM(Context* c, unsigned size, Assembler::Memory* a) +{ + if (BytesPerWord == 4 and size == 8) { + Assembler::Memory ah(a->base, a->offset + 4, a->index, a->scale); + + popM(c, 4, a); + popM(c, 4, &ah); + } else { + assert(c, BytesPerWord == 4 or size == 8); + + encode(c, 0x8f, 0, a, false); + } +} + void addCarryCR(Context* c, unsigned size, Assembler::Constant* a, Assembler::Register* b); @@ -2290,6 +2305,11 @@ class MyAssembler: public Assembler { return arch_; } + virtual void popReturnAddress(unsigned addressOffset) { + Memory addressDst(rbx, addressOffset); + popM(&c, BytesPerWord, &addressDst); + } + virtual void saveFrame(unsigned stackOffset, unsigned baseOffset) { Register stack(rsp); Memory stackDst(rbx, stackOffset); @@ -2302,6 +2322,18 @@ class MyAssembler: public Assembler { BytesPerWord, MemoryOperand, &baseDst); } + virtual void restoreFrame(unsigned stackOffset, unsigned baseOffset) { + Register stack(rsp); + Memory stackDst(rbx, stackOffset); + apply(Move, BytesPerWord, MemoryOperand, &stackDst, + BytesPerWord, RegisterOperand, &stack); + + Register base(rbp); + Memory baseDst(rbx, baseOffset); + apply(Move, BytesPerWord, MemoryOperand, &baseDst, + BytesPerWord, RegisterOperand, &base); + } + virtual void pushFrame(unsigned argumentCount, ...) { struct { unsigned size; From 717f3596662ae4ecf2ceb82fb9dc2696cf9e0600 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 19 Apr 2009 16:36:11 -0600 Subject: [PATCH 005/172] implement "callee pops arguments" calling convention and refactor tail call code accordingly --- src/assembler.h | 10 +- src/bootimage.h | 4 - src/common.h | 9 +- src/compile.cpp | 342 +++++++++++++---------------------------------- src/compiler.cpp | 247 ++++++++++++++++++++-------------- src/powerpc.cpp | 72 +++++++++- src/x86.cpp | 101 ++++++++++++-- 7 files changed, 415 insertions(+), 370 deletions(-) diff --git a/src/assembler.h b/src/assembler.h index e208a5bc6e..0075ed1c8e 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -264,6 +264,8 @@ class Assembler { virtual int thread() = 0; virtual int returnLow() = 0; virtual int returnHigh() = 0; + virtual int virtualCallClass() = 0; + virtual int virtualCallIndex() = 0; virtual bool condensedAddressing() = 0; @@ -291,6 +293,8 @@ class Assembler { virtual unsigned frameHeaderSize() = 0; virtual unsigned frameReturnAddressSize() = 0; virtual unsigned frameFooterSize() = 0; + virtual unsigned returnAddressOffset() = 0; + virtual unsigned framePointerOffset() = 0; virtual void nextFrame(void** stack, void** base) = 0; virtual void plan @@ -319,12 +323,16 @@ class Assembler { virtual Architecture* arch() = 0; - virtual void popReturnAddress(unsigned addressOffset) = 0; virtual void saveFrame(unsigned stackOffset, unsigned baseOffset) = 0; virtual void restoreFrame(unsigned stackOffset, unsigned baseOffset) = 0; virtual void pushFrame(unsigned argumentCount, ...) = 0; virtual void allocateFrame(unsigned footprint) = 0; virtual void popFrame() = 0; + virtual void popFrameForTailCall(unsigned footprint, int offset, + int returnAddressSurrogate, + int framePointerSurrogate) = 0; + virtual void popFrameAndPopArgumentsAndReturn(unsigned argumentFootprint) + = 0; virtual void apply(Operation op) = 0; diff --git a/src/bootimage.h b/src/bootimage.h index c8df51c0c6..4472ac28ae 100644 --- a/src/bootimage.h +++ b/src/bootimage.h @@ -44,11 +44,8 @@ class BootImage { uintptr_t codeBase; unsigned defaultThunk; - unsigned defaultTailThunk; unsigned defaultVirtualThunk; - unsigned tailHelperThunk; unsigned nativeThunk; - unsigned nativeTailThunk; unsigned aioobThunk; unsigned thunkTable; @@ -56,7 +53,6 @@ class BootImage { unsigned compileMethodCall; unsigned compileVirtualMethodCall; - unsigned tailCallCall; unsigned invokeNativeCall; unsigned throwArrayIndexOutOfBoundsCall; diff --git a/src/common.h b/src/common.h index 0b5fc040a3..8ab02e4041 100644 --- a/src/common.h +++ b/src/common.h @@ -103,12 +103,19 @@ avg(unsigned a, unsigned b) return (a + b) / 2; } +inline unsigned +pad(unsigned n, unsigned alignment) +{ + return (n + (alignment - 1)) & ~(alignment - 1); +} + inline unsigned pad(unsigned n) { - return (n + (BytesPerWord - 1)) & ~(BytesPerWord - 1); + return pad(n, BytesPerWord); } + inline unsigned ceiling(unsigned n, unsigned d) { diff --git a/src/compile.cpp b/src/compile.cpp index 979463fc7a..881ff5d30b 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -27,7 +27,7 @@ vmCall(); namespace { -const bool DebugCompile = false; +const bool DebugCompile = true; const bool DebugNatives = false; const bool DebugCallTable = false; const bool DebugMethodTree = false; @@ -1358,18 +1358,9 @@ objectPools(MyThread* t); uintptr_t defaultThunk(MyThread* t); -uintptr_t -defaultTailThunk(MyThread* t); - uintptr_t nativeThunk(MyThread* t); -uintptr_t -nativeTailThunk(MyThread* t); - -uintptr_t -tailHelperThunk(MyThread* t); - uintptr_t aioobThunk(MyThread* t); @@ -1940,65 +1931,54 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target, bool tailCall, { Compiler* c = frame->c; - if (tailCall and methodParameterFootprint(t, target) - > methodParameterFootprint(t, frame->context->method)) - { - return c->stackCall - (c->constant(tailHelperThunk(t)), - 0, - frame->trace(target, 0), - rSize, - methodParameterFootprint(t, target)); - } else if (tailCall and (methodFlags(t, target) & ACC_NATIVE)) { - return c->stackCall - (c->constant(nativeTailThunk(t)), - Compiler::TailCall, - frame->trace(target, TraceElement::TailCall), - rSize, - methodParameterFootprint(t, target)); - } else { - unsigned flags = (tailCall ? Compiler::TailJump : 0); + unsigned flags = (tailCall ? Compiler::TailJump : 0); - if (useThunk) { - if (tailCall) { - Compiler::Operand* result = c->stackCall - (c->promiseConstant - (new (frame->context->zone.allocate(sizeof(TraceElementPromise))) - TraceElementPromise(t->m->system, frame->trace(0, 0))), - flags | Compiler::Aligned, - 0, - rSize, - methodParameterFootprint(t, target)); + if (useThunk or (tailCall and (methodFlags(t, target) & ACC_NATIVE))) { + if (tailCall) { + TraceElement* trace = frame->trace(target, TraceElement::TailCall); + Compiler::Operand* returnAddress = c->promiseConstant + (new (frame->context->zone.allocate(sizeof(TraceElementPromise))) + TraceElementPromise(t->m->system, trace));; - c->call(c->constant(defaultTailThunk(t)), - 0, - frame->trace(target, TraceElement::TailCall), - 0, - 0); + Compiler::Operand* result = c->stackCall + (returnAddress, + flags | Compiler::Aligned, + 0, + rSize, + methodParameterFootprint(t, target)); - return result; + c->store(BytesPerWord, returnAddress, BytesPerWord, + c->memory(c->register_(t->arch->thread()), + difference(&(t->tailAddress), t))); + + if (methodFlags(t, target) & ACC_NATIVE) { + c->jmp(c->constant(nativeThunk(t))); } else { - return c->stackCall - (c->constant(defaultThunk(t)), - flags | Compiler::Aligned, - frame->trace(target, 0), - rSize, - methodParameterFootprint(t, target)); + c->jmp(c->constant(defaultThunk(t))); } - } else { - Compiler::Operand* address = - (addressPromise - ? c->promiseConstant(addressPromise) - : c->constant(methodAddress(t, target))); + return result; + } else { return c->stackCall - (address, - flags, - tailCall ? 0 : frame->trace - ((methodFlags(t, target) & ACC_NATIVE) ? target : 0, 0), + (c->constant(defaultThunk(t)), + flags | Compiler::Aligned, + frame->trace(target, 0), rSize, methodParameterFootprint(t, target)); } + } else { + Compiler::Operand* address = + (addressPromise + ? c->promiseConstant(addressPromise) + : c->constant(methodAddress(t, target))); + + return c->stackCall + (address, + flags, + tailCall ? 0 : frame->trace + ((methodFlags(t, target) & ACC_NATIVE) ? target : 0, 0), + rSize, + methodParameterFootprint(t, target)); } } @@ -2225,6 +2205,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Frame* frame = &myFrame; Compiler* c = frame->c; Context* context = frame->context; + bool tailCall = false; object code = methodCode(t, context->method); PROTECT(t, code); @@ -2422,8 +2403,11 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } break; case areturn: { - handleExit(t, frame); - c->return_(BytesPerWord, frame->popObject()); + Compiler::Operand* value = frame->popObject(); + if (not tailCall) { + handleExit(t, frame); + c->return_(BytesPerWord, value); + } } return; case arraylength: { @@ -3171,8 +3155,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); - compileDirectInvoke - (t, frame, target, isTailCall(t, code, ip, context->method, target)); + tailCall = isTailCall(t, code, ip, context->method, target); + + compileDirectInvoke(t, frame, target, tailCall); } break; case invokestatic: { @@ -3183,8 +3168,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, assert(t, methodFlags(t, target) & ACC_STATIC); - compileDirectInvoke - (t, frame, target, isTailCall(t, code, ip, context->method, target)); + tailCall = isTailCall(t, code, ip, context->method, target); + + compileDirectInvoke(t, frame, target, tailCall); } break; case invokevirtual: { @@ -3203,32 +3189,22 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, unsigned rSize = resultSize(t, methodReturnCode(t, target)); - bool tailCall = isTailCall(t, code, ip, context->method, target); + tailCall = isTailCall(t, code, ip, context->method, target); - Compiler::Operand* result; - if (tailCall and methodParameterFootprint(t, target) - > methodParameterFootprint(t, context->method)) - { - result = c->stackCall - (c->constant(tailHelperThunk(t)), - 0, - frame->trace(target, TraceElement::VirtualCall), - rSize, - parameterFootprint); - } else { - c->freezeRegister(t->arch->returnLow(), - c->and_(BytesPerWord, c->constant(PointerMask), - c->memory(instance, 0, 0, 1))); + Compiler::Operand* classOperand = c->and_ + (BytesPerWord, c->constant(PointerMask), + c->memory(instance, 0, 0, 1)); - result = c->stackCall - (c->memory(c->register_(t->arch->returnLow()), offset, 0, 1), - tailCall ? Compiler::TailCall : 0, - frame->trace(0, 0), - rSize, - parameterFootprint); + c->freezeRegister(t->arch->virtualCallClass(), classOperand); - c->thawRegister(t->arch->returnLow()); - } + Compiler::Operand* result = c->stackCall + (c->memory(classOperand, offset, 0, 1), + tailCall ? Compiler::TailCall : 0, + frame->trace(0, 0), + rSize, + parameterFootprint); + + c->thawRegister(t->arch->virtualCallClass()); frame->pop(parameterFootprint); @@ -3251,8 +3227,11 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case ireturn: case freturn: { - handleExit(t, frame); - c->return_(4, frame->popInt()); + Compiler::Operand* value = frame->popInt(); + if (not tailCall) { + handleExit(t, frame); + c->return_(4, value); + } } return; case ishl: { @@ -3545,8 +3524,11 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case lreturn: case dreturn: { - handleExit(t, frame); - c->return_(8, frame->popLong()); + Compiler::Operand* value = frame->popLong(); + if (not tailCall) { + handleExit(t, frame); + c->return_(8, value); + } } return; case lshl: { @@ -3841,12 +3823,14 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, return; case return_: - if (needsReturnBarrier(t, context->method)) { - c->storeStoreBarrier(); - } + if (not tailCall) { + if (needsReturnBarrier(t, context->method)) { + c->storeStoreBarrier(); + } - handleExit(t, frame); - c->return_(0, 0); + handleExit(t, frame); + c->return_(0, 0); + } return; case sipush: @@ -4680,66 +4664,6 @@ compileVirtualMethod(MyThread* t) } } -void* -tailCall2(MyThread* t, void* ip) -{ - object node = findCallNode(t, ip); - PROTECT(t, node); - - object target = callNodeTarget(t, node); - PROTECT(t, target); - - if (callNodeFlags(t, node) & TraceElement::VirtualCall) { - target = resolveTarget(t, t->stack, target); - } - - if (LIKELY(t->exception == 0)) { - compile(t, codeAllocator(t), 0, target); - } - - if (UNLIKELY(t->exception)) { - return 0; - } else { - void* base = t->base; - void* stack = t->stack; - t->arch->nextFrame(&stack, &base); - - if (t->arch->matchCall(t->arch->frameIp(stack), - reinterpret_cast(tailHelperThunk(t)))) - { - void* nextBase = base; - void* nextStack = stack; - t->arch->nextFrame(&nextStack, &nextBase); - - if (((reinterpret_cast(nextStack) - - reinterpret_cast(stack)) - / BytesPerWord) - - t->arch->frameFooterSize() - - t->arch->frameHeaderSize() - >= methodParameterFootprint(t, target)) - { - // there's room for the parameters in the previous frame, so use it - t->base = base; - t->stack = stack; - } - } - - return reinterpret_cast(methodAddress(t, target)); - } -} - -uint64_t -tailCall(MyThread* t) -{ - void* r = tailCall2(t, t->arch->frameIp(t->stack)); - - if (UNLIKELY(t->exception)) { - unwind(t); - } else { - return reinterpret_cast(r); - } -} - uint64_t invokeNative2(MyThread* t, object method) { @@ -5304,11 +5228,8 @@ class MyProcessor: public Processor { s(s), allocator(allocator), defaultThunk(0), - defaultTailThunk(0), defaultVirtualThunk(0), - tailHelperThunk(0), nativeThunk(0), - nativeTailThunk(0), aioobThunk(0), callTable(0), callTableSize(0), @@ -5318,9 +5239,7 @@ class MyProcessor: public Processor { staticTableArray(0), virtualThunks(0), codeAllocator(s, 0, 0) - { - expect(s, codeAllocator.base); - } + { } virtual Thread* makeThread(Machine* m, object javaThread, Thread* parent) @@ -5377,7 +5296,7 @@ class MyProcessor: public Processor { virtual void initVtable(Thread* t, object c) { - for (unsigned i = 0; i < classLength(t, c); ++i) { + for (int i = classLength(t, c) - 1; i >= 0; --i) { classVtable(t, c, i) = reinterpret_cast (virtualThunk(static_cast(t), i)); } @@ -5715,11 +5634,8 @@ class MyProcessor: public Processor { System* s; Allocator* allocator; uint8_t* defaultThunk; - uint8_t* defaultTailThunk; uint8_t* defaultVirtualThunk; - uint8_t* tailHelperThunk; uint8_t* nativeThunk; - uint8_t* nativeTailThunk; uint8_t* aioobThunk; uint8_t* thunkTable; unsigned thunkSize; @@ -6003,7 +5919,6 @@ fixupThunks(MyThread* t, BootImage* image, uint8_t* code) MyProcessor* p = processor(t); p->defaultThunk = code + image->defaultThunk; - p->defaultTailThunk = code + image->defaultTailThunk; updateCall(t, LongCall, false, code + image->compileMethodCall, voidPointer(::compileMethod)); @@ -6013,13 +5928,7 @@ fixupThunks(MyThread* t, BootImage* image, uint8_t* code) updateCall(t, LongCall, false, code + image->compileVirtualMethodCall, voidPointer(::compileVirtualMethod)); - p->tailHelperThunk = code + image->tailHelperThunk; - - updateCall(t, LongCall, false, code + image->tailCallCall, - voidPointer(::tailCall)); - p->nativeThunk = code + image->nativeThunk; - p->nativeTailThunk = code + image->nativeTailThunk; updateCall(t, LongCall, false, code + image->invokeNativeCall, voidPointer(invokeNative)); @@ -6145,13 +6054,8 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, Zone zone(t->m->system, t->m->heap, 1024); ThunkContext defaultContext(t, &zone); - unsigned defaultTailOffset; { Assembler* a = defaultContext.context.assembler; - - a->popReturnAddress(difference(&(t->tailAddress), t)); - - defaultTailOffset = a->length(); a->saveFrame(difference(&(t->stack), t), difference(&(t->base), t)); @@ -6173,13 +6077,13 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, { Assembler* a = defaultVirtualContext.context.assembler; - Assembler::Register class_(t->arch->returnLow()); + Assembler::Register class_(t->arch->virtualCallClass()); Assembler::Memory virtualCallClass (t->arch->thread(), difference(&(t->virtualCallClass), t)); a->apply(Move, BytesPerWord, RegisterOperand, &class_, BytesPerWord, MemoryOperand, &virtualCallClass); - Assembler::Register index(t->arch->returnHigh()); + Assembler::Register index(t->arch->virtualCallIndex()); Assembler::Memory virtualCallIndex (t->arch->thread(), difference(&(t->virtualCallIndex), t)); a->apply(Move, BytesPerWord, RegisterOperand, &index, @@ -6201,35 +6105,10 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, a->endBlock(false)->resolve(0, 0); } - ThunkContext tailHelperContext(t, &zone); - - { Assembler* a = tailHelperContext.context.assembler; - - a->saveFrame(difference(&(t->stack), t), difference(&(t->base), t)); - - Assembler::Register thread(t->arch->thread()); - a->pushFrame(1, BytesPerWord, RegisterOperand, &thread); - - Assembler::Constant proc(&(tailHelperContext.promise)); - a->apply(LongCall, BytesPerWord, ConstantOperand, &proc); - - a->restoreFrame(difference(&(t->stack), t), difference(&(t->base), t)); - - Assembler::Register result(t->arch->returnLow()); - a->apply(Jump, BytesPerWord, RegisterOperand, &result); - - a->endBlock(false)->resolve(0, 0); - } - ThunkContext nativeContext(t, &zone); - unsigned nativeTailOffset; { Assembler* a = nativeContext.context.assembler; - a->popReturnAddress(difference(&(t->tailAddress), t)); - - nativeTailOffset = a->length(); - a->saveFrame(difference(&(t->stack), t), difference(&(t->base), t)); Assembler::Register thread(t->arch->thread()); @@ -6274,17 +6153,14 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, p->thunkSize = pad(tableContext.context.assembler->length()); - p->defaultTailThunk = finish + p->defaultThunk = finish (t, allocator, defaultContext.context.assembler, "default"); - p->defaultThunk = p->defaultTailThunk + defaultTailOffset; - { void* call; defaultContext.promise.listener->resolve (reinterpret_cast(voidPointer(compileMethod)), &call); if (image) { - image->defaultTailThunk = p->defaultTailThunk - imageBase; image->defaultThunk = p->defaultThunk - imageBase; image->compileMethodCall = static_cast(call) - imageBase; } @@ -6304,30 +6180,14 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, } } - p->tailHelperThunk = finish - (t, allocator, defaultContext.context.assembler, "tailHelper"); - - { void* call; - tailHelperContext.promise.listener->resolve - (reinterpret_cast(voidPointer(tailCall)), &call); - - if (image) { - image->tailHelperThunk = p->tailHelperThunk - imageBase; - image->tailCallCall = static_cast(call) - imageBase; - } - } - - p->nativeTailThunk = finish + p->nativeThunk = finish (t, allocator, nativeContext.context.assembler, "native"); - p->nativeThunk = p->nativeTailThunk + nativeTailOffset; - { void* call; nativeContext.promise.listener->resolve (reinterpret_cast(voidPointer(invokeNative)), &call); if (image) { - image->nativeTailThunk = p->nativeTailThunk - imageBase; image->nativeThunk = p->nativeThunk - imageBase; image->invokeNativeCall = static_cast(call) - imageBase; } @@ -6394,36 +6254,18 @@ defaultThunk(MyThread* t) return reinterpret_cast(processor(t)->defaultThunk); } -uintptr_t -defaultTailThunk(MyThread* t) -{ - return reinterpret_cast(processor(t)->defaultTailThunk); -} - uintptr_t defaultVirtualThunk(MyThread* t) { return reinterpret_cast(processor(t)->defaultVirtualThunk); } -uintptr_t -tailHelperThunk(MyThread* t) -{ - return reinterpret_cast(processor(t)->tailHelperThunk); -} - uintptr_t nativeThunk(MyThread* t) { return reinterpret_cast(processor(t)->nativeThunk); } -uintptr_t -nativeTailThunk(MyThread* t) -{ - return reinterpret_cast(processor(t)->nativeTailThunk); -} - uintptr_t aioobThunk(MyThread* t) { @@ -6438,19 +6280,23 @@ compileVirtualThunk(MyThread* t, unsigned index) ResolvedPromise indexPromise(index); Assembler::Constant indexConstant(&indexPromise); - Assembler::Register indexRegister(t->arch->returnHigh()); + Assembler::Register indexRegister(t->arch->virtualCallIndex()); a->apply(Move, BytesPerWord, ConstantOperand, &indexConstant, - BytesPerWord, ConstantOperand, &indexRegister); + BytesPerWord, RegisterOperand, &indexRegister); ResolvedPromise defaultVirtualThunkPromise(defaultVirtualThunk(t)); Assembler::Constant thunk(&defaultVirtualThunkPromise); a->apply(Jump, BytesPerWord, ConstantOperand, &thunk); + a->endBlock(false)->resolve(0, 0); + uint8_t* start = static_cast (codeAllocator(t)->allocate(a->length())); a->writeTo(start); + logCompile(t, start, a->length(), 0, "virtualThunk", 0); + return reinterpret_cast(start); } @@ -6460,7 +6306,7 @@ virtualThunk(MyThread* t, unsigned index) MyProcessor* p = processor(t); if (p->virtualThunks == 0 or wordArrayLength(t, p->virtualThunks) <= index) { - object newArray = makeWordArray(t, nextPowerOfTwo(index)); + object newArray = makeWordArray(t, nextPowerOfTwo(index + 1)); if (p->virtualThunks) { memcpy(&wordArrayBody(t, newArray, 0), &wordArrayBody(t, p->virtualThunks, 0), diff --git a/src/compiler.cpp b/src/compiler.cpp index edcc82d3a2..0a90033ce9 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -638,42 +638,43 @@ class Event { }; unsigned -usableFrameSize(Context* c) +totalFrameSize(Context* c) { - return c->alignedFrameSize - c->arch->frameFooterSize(); + return c->alignedFrameSize + + c->arch->frameHeaderSize() + + c->arch->argumentFootprint(c->parameterFootprint); } int -frameIndex(Context* c, int index) +frameIndex(Context* c, int localIndex) { - assert(c, static_cast - (usableFrameSize(c) + c->parameterFootprint - index - 1) >= 0); + assert(c, localIndex >= 0); + assert(c, localIndex < static_cast + (c->parameterFootprint + c->localFootprint)); - return usableFrameSize(c) + c->parameterFootprint - index - 1; + int index = c->alignedFrameSize + c->parameterFootprint - localIndex; + + if (localIndex < static_cast(c->parameterFootprint)) { + index += c->arch->frameHeaderSize(); + } else { + index -= c->arch->frameFooterSize(); + } + + assert(c, index >= 0); + + return index; } unsigned frameIndexToOffset(Context* c, unsigned frameIndex) { - return ((frameIndex >= usableFrameSize(c)) ? - (frameIndex - + (c->arch->frameFooterSize() * 2) - + c->arch->frameHeaderSize()) : - (frameIndex - + c->arch->frameFooterSize())) * BytesPerWord; + return (frameIndex + c->arch->frameFooterSize()) * BytesPerWord; } unsigned offsetToFrameIndex(Context* c, unsigned offset) { - unsigned normalizedOffset = offset / BytesPerWord; - - return ((normalizedOffset >= c->alignedFrameSize) ? - (normalizedOffset - - (c->arch->frameFooterSize() * 2) - - c->arch->frameHeaderSize()) : - (normalizedOffset - - c->arch->frameFooterSize())); + return (offset / BytesPerWord) - c->arch->frameFooterSize(); } class FrameIterator { @@ -1172,7 +1173,7 @@ pickAnyFrameTarget(Context* c, Value* v) { Target best; - unsigned count = usableFrameSize(c) + c->parameterFootprint; + unsigned count = totalFrameSize(c); for (unsigned i = 0; i < count; ++i) { Target mine(i, MemoryOperand, frameCost(c, v, i)); if (mine.cost == 1) { @@ -2271,8 +2272,7 @@ saveLocals(Context* c, Event* e) if (local->value) { if (DebugReads) { fprintf(stderr, "local save read %p at %d of %d\n", - local->value, ::frameIndex(c, li), - usableFrameSize(c) + c->parameterFootprint); + local->value, ::frameIndex(c, li), totalFrameSize(c)); } addRead(c, e, local->value, read @@ -2291,48 +2291,61 @@ class CallEvent: public Event { address(address), traceHandler(traceHandler), result(result), + returnAddressSurrogate(0), + framePointerSurrogate(0), popIndex(0), padIndex(0), padding(0), flags(flags), - resultSize(resultSize) + resultSize(resultSize), + stackArgumentFootprint(stackArgumentFootprint) { uint32_t registerMask = ~0; Stack* s = argumentStack; unsigned index = 0; unsigned frameIndex; + int returnAddressIndex = -1; + int framePointerIndex = -1; + if (flags & (Compiler::TailJump | Compiler::TailCall)) { - frameIndex = usableFrameSize(c); + assert(c, argumentCount == 0); + + unsigned base = c->alignedFrameSize - c->arch->frameFooterSize(); + returnAddressIndex = base + c->arch->returnAddressOffset(); + framePointerIndex = base + c->arch->framePointerOffset(); + + frameIndex = totalFrameSize(c) - c->arch->argumentFootprint + (stackArgumentFootprint); } else { frameIndex = 0; - } - if (argumentCount) { - while (true) { - Read* target; - if (index < c->arch->argumentRegisterCount()) { - int number = c->arch->argumentRegister(index); + if (argumentCount) { + while (true) { + Read* target; + if (index < c->arch->argumentRegisterCount()) { + int number = c->arch->argumentRegister(index); - if (DebugReads) { - fprintf(stderr, "reg %d arg read %p\n", number, s->value); + if (DebugReads) { + fprintf(stderr, "reg %d arg read %p\n", number, s->value); + } + + target = fixedRegisterRead(c, number); + registerMask &= ~(1 << number); + } else { + if (DebugReads) { + fprintf(stderr, "stack %d arg read %p\n", frameIndex, s->value); + } + + target = read(c, SiteMask(1 << MemoryOperand, 0, frameIndex)); + ++ frameIndex; } + addRead(c, this, s->value, target); - target = fixedRegisterRead(c, number); - registerMask &= ~(1 << number); - } else { - if (DebugReads) { - fprintf(stderr, "stack %d arg read %p\n", frameIndex, s->value); + if ((++ index) < argumentCount) { + s = s->next; + } else { + break; } - - target = read(c, SiteMask(1 << MemoryOperand, 0, frameIndex)); - ++ frameIndex; - } - addRead(c, this, s->value, target); - - if ((++ index) < argumentCount) { - s = s->next; - } else { - break; } } } @@ -2355,52 +2368,60 @@ class CallEvent: public Event { (typeMask, registerMask & planRegisterMask, AnyFrameIndex))); } - if ((flags & (Compiler::TailJump | Compiler::TailCall)) == 0) { - int footprint = stackArgumentFootprint; - for (Stack* s = stackBefore; s; s = s->next) { - if (s->value) { - if (footprint > 0) { - if (DebugReads) { - fprintf(stderr, "stack arg read %p at %d of %d\n", - s->value, frameIndex, - usableFrameSize(c) + c->parameterFootprint); - } + int footprint = stackArgumentFootprint; + for (Stack* s = stackBefore; s; s = s->next) { + if (s->value) { + if (footprint > 0) { + if (DebugReads) { + fprintf(stderr, "stack arg read %p at %d of %d\n", + s->value, frameIndex, totalFrameSize(c)); + } + if (static_cast(frameIndex) == returnAddressIndex) { + returnAddressSurrogate = s->value; + addRead(c, this, s->value, anyRegisterRead(c)); + } else if (static_cast(frameIndex) == framePointerIndex) { + framePointerSurrogate = s->value; + addRead(c, this, s->value, anyRegisterRead(c)); + } else { addRead(c, this, s->value, read (c, SiteMask(1 << MemoryOperand, 0, frameIndex))); - } else { - unsigned logicalIndex = ::frameIndex - (c, s->index + c->localFootprint); - - if (DebugReads) { - fprintf(stderr, "stack save read %p at %d of %d\n", - s->value, logicalIndex, - usableFrameSize(c) + c->parameterFootprint); - } - - addRead(c, this, s->value, read - (c, SiteMask(1 << MemoryOperand, 0, logicalIndex))); } } - - -- footprint; - - if (footprint == 0) { + else if ((flags & (Compiler::TailJump | Compiler::TailCall)) == 0) + { unsigned logicalIndex = ::frameIndex (c, s->index + c->localFootprint); - assert(c, logicalIndex >= frameIndex); + if (DebugReads) { + fprintf(stderr, "stack save read %p at %d of %d\n", + s->value, logicalIndex, totalFrameSize(c)); + } - padding = logicalIndex - frameIndex; - padIndex = s->index + c->localFootprint; + addRead(c, this, s->value, read + (c, SiteMask(1 << MemoryOperand, 0, logicalIndex))); } - - ++ frameIndex; } + -- footprint; + + if (footprint == 0) { + unsigned logicalIndex = ::frameIndex + (c, s->index + c->localFootprint); + + assert(c, logicalIndex >= frameIndex); + + padding = logicalIndex - frameIndex; + padIndex = s->index + c->localFootprint; + } + + ++ frameIndex; + } + + if ((flags & (Compiler::TailJump | Compiler::TailCall)) == 0) { popIndex - = usableFrameSize(c) - + c->parameterFootprint + = c->alignedFrameSize + - c->arch->frameFooterSize() - (stackBefore ? stackBefore->index + 1 - stackArgumentFootprint : 0) - c->localFootprint; @@ -2417,28 +2438,40 @@ class CallEvent: public Event { virtual void compile(Context* c) { UnaryOperation op; - if (flags & Compiler::TailJump) { - c->assembler->popFrame(); - - if (flags & Compiler::Aligned) { - op = AlignedJump; + if (flags & (Compiler::TailJump | Compiler::TailCall)) { + if (flags & Compiler::TailJump) { + if (flags & Compiler::Aligned) { + op = AlignedJump; + } else { + op = Jump; + } } else { - op = Jump; + if (flags & Compiler::Aligned) { + op = AlignedCall; + } else { + op = Call; + } } - } else if (flags & Compiler::TailCall) { - c->assembler->popFrame(); - if (flags & Compiler::Aligned) { - op = AlignedCall; - } else { - op = Call; - } + assert(c, returnAddressSurrogate == 0 + or returnAddressSurrogate->source->type(c) == RegisterOperand); + assert(c, framePointerSurrogate == 0 + or framePointerSurrogate->source->type(c) == RegisterOperand); + + int ras = (returnAddressSurrogate ? static_cast + (returnAddressSurrogate->source)->number : NoRegister); + int fps = (framePointerSurrogate ? static_cast + (framePointerSurrogate->source)->number : NoRegister); + + int offset + = static_cast(c->arch->argumentFootprint(c->parameterFootprint)) + - static_cast(c->arch->argumentFootprint(stackArgumentFootprint)); + + c->assembler->popFrameForTailCall(c->alignedFrameSize, offset, ras, fps); + } else if (flags & Compiler::Aligned) { + op = AlignedCall; } else { - if (flags & Compiler::Aligned) { - op = AlignedCall; - } else { - op = Call; - } + op = Call; } apply(c, op, BytesPerWord, address->source, 0); @@ -2461,11 +2494,14 @@ class CallEvent: public Event { Value* address; TraceHandler* traceHandler; Value* result; + Value* returnAddressSurrogate; + Value* framePointerSurrogate; unsigned popIndex; unsigned padIndex; unsigned padding; unsigned flags; unsigned resultSize; + unsigned stackArgumentFootprint; }; void @@ -2503,8 +2539,8 @@ class ReturnEvent: public Event { popRead(c, this, r->value); } - c->assembler->popFrame(); - c->assembler->apply(Return); + c->assembler->popFrameAndPopArgumentsAndReturn + (c->arch->argumentFootprint(c->parameterFootprint)); } Value* value; @@ -4875,7 +4911,7 @@ class MyCompiler: public Compiler { c.localFootprint = localFootprint; c.alignedFrameSize = alignedFrameSize; - unsigned frameResourceCount = usableFrameSize(&c) + parameterFootprint; + unsigned frameResourceCount = totalFrameSize(&c); c.frameResources = static_cast (c.zone->allocate(sizeof(FrameResource) * frameResourceCount)); @@ -4884,9 +4920,12 @@ class MyCompiler: public Compiler { new (c.frameResources + i) FrameResource; } + unsigned base = alignedFrameSize - c.arch->frameFooterSize(); + c.frameResources[base + c.arch->returnAddressOffset()].reserved = true; + c.frameResources[base + c.arch->framePointerOffset()].reserved = true; + // leave room for logical instruction -1 - unsigned codeSize = sizeof(LogicalInstruction*) - * (logicalCodeLength + 1); + unsigned codeSize = sizeof(LogicalInstruction*) * (logicalCodeLength + 1); c.logicalCode = static_cast (c.zone->allocate(codeSize)); memset(c.logicalCode, 0, codeSize); diff --git a/src/powerpc.cpp b/src/powerpc.cpp index 13d0ab819c..19c217a3e8 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -158,6 +158,8 @@ carry16(intptr_t v) const unsigned FrameFooterSize = 6; +const unsigned StackAlignmentInBytes = 16; + const int StackRegister = 1; const int ThreadRegister = 13; @@ -1699,8 +1701,12 @@ class MyArchitecture: public Assembler::Architecture { } } + virtual unsigned stackPadding(unsigned footprint) { + return max(footprint, StackAlignmentInWords); + } + virtual unsigned argumentFootprint(unsigned footprint) { - return footprint; + return max(pad(footprint, StackAlignmentInWords), StackAlignmentInWords); } virtual unsigned argumentRegisterCount() { @@ -1755,7 +1761,7 @@ class MyArchitecture: public Assembler::Architecture { } virtual unsigned alignFrameSize(unsigned sizeInWords) { - const unsigned alignment = 16 / BytesPerWord; + const unsigned alignment = StackAlignmentInBytes / BytesPerWord; return (ceiling(sizeInWords + FrameFooterSize, alignment) * alignment); } @@ -1963,13 +1969,71 @@ class MyAssembler: public Assembler { Memory stackSrc(StackRegister, 0); moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &stack); - Assembler::Register returnAddress(0); - Assembler::Memory returnAddressSrc(StackRegister, 8); + Register returnAddress(0); + Memory returnAddressSrc(StackRegister, 8); moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &returnAddress); issue(&c, mtlr(returnAddress.low)); } + virtual void popFrameForTailCall(unsigned footprint, + int offset, + int returnAddressSurrogate, + int framePointerSurrogate) + { + if (offset) { + Register tmp(0); + Memory returnAddressSrc(StackRegister, 8 + (footprint * BytesPerWord)); + moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &tmp); + + issue(&c, mtlr(tmp.low)); + + Memory stackSrc(StackRegister, footprint * BytesPerWord); + moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &tmp); + + Memory stackDst(StackRegister, (footprint - offset) * BytesPerWord); + moveAndUpdateRM(&c, BytesPerWord, &tmp, BytesPerWord, &stackDst); + + if (returnAddressSurrogate != NoRegister) { + assert(&c, offset > 0); + + Register ras(returnAddressSurrogate); + Memory dst(StackRegister, 8 + (offset * BytesPerWord)); + moveRM(&c, BytesPerWord, &ras, BytesPerWord, &dst); + } + + if (framePointerSurrogate != NoRegister) { + assert(&c, offset > 0); + + Register fps(framePointerSurrogate); + Memory dst(StackRegister, offset * BytesPerWord); + moveRM(&c, BytesPerWord, &fps, BytesPerWord, &dst); + } + } else { + popFrame(); + } + } + + virtual void popFrameAndPopArgumentsAndReturn(unsigned argumentFootprint) { + popFrame(); + + assert(c, argumentFootprint >= StackAlignmentInWords); + assert(c, (argumentFootprint % StackAlignmentInWords) == 0); + + if (argumentFootprint > StackAlignmentInWords) { + Register tmp(0); + Memory stackSrc(StackRegister, 0); + moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &tmp); + + Memory stackDst(StackRegister, + (argumentFootprint - StackAlignmentInWords) + * BytesPerWord); + moveAndUpdateRM(&c, BytesPerWord, &tmp, BytesPerWord, &stackDst); + } + + return_(&c); + } + virtual void apply(Operation op) { arch_->c.operations[op](&c); } diff --git a/src/x86.cpp b/src/x86.cpp index 05ec897bfb..53bce312d5 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -39,6 +39,9 @@ enum { const unsigned FrameHeaderSize = 2; +const unsigned StackAlignmentInBytes = 16; +const unsigned StackAlignmentInWords = StackAlignmentInBytes / BytesPerWord; + inline bool isInt8(intptr_t v) { @@ -2022,6 +2025,14 @@ class MyArchitecture: public Assembler::Architecture { return (BytesPerWord == 4 ? rdx : NoRegister); } + virtual int virtualCallClass() { + return rax; + } + + virtual int virtualCallIndex() { + return rdx; + } + virtual bool condensedAddressing() { return true; } @@ -2042,9 +2053,14 @@ class MyArchitecture: public Assembler::Architecture { } } + virtual unsigned stackPadding(unsigned footprint) { + return max(footprint > argumentRegisterCount() ? + footprint - argumentRegisterCount() : 0, + StackAlignmentInWords); + } + virtual unsigned argumentFootprint(unsigned footprint) { - return footprint > argumentRegisterCount() ? - footprint - argumentRegisterCount() : 0; + return max(pad(footprint, StackAlignmentInWords), StackAlignmentInWords); } virtual unsigned argumentRegisterCount() { @@ -2125,7 +2141,7 @@ class MyArchitecture: public Assembler::Architecture { } virtual unsigned alignFrameSize(unsigned sizeInWords) { - const unsigned alignment = 16 / BytesPerWord; + const unsigned alignment = StackAlignmentInBytes / BytesPerWord; return (ceiling(sizeInWords + FrameHeaderSize, alignment) * alignment) - FrameHeaderSize; } @@ -2146,6 +2162,14 @@ class MyArchitecture: public Assembler::Architecture { return 0; } + virtual unsigned returnAddressOffset() { + return 1; + } + + virtual unsigned framePointerOffset() { + return 0; + } + virtual void nextFrame(void** stack, void** base) { assert(&c, *static_cast(*base) != *base); @@ -2305,11 +2329,6 @@ class MyAssembler: public Assembler { return arch_; } - virtual void popReturnAddress(unsigned addressOffset) { - Memory addressDst(rbx, addressOffset); - popM(&c, BytesPerWord, &addressDst); - } - virtual void saveFrame(unsigned stackOffset, unsigned baseOffset) { Register stack(rsp); Memory stackDst(rbx, stackOffset); @@ -2392,6 +2411,72 @@ class MyAssembler: public Assembler { popR(&c, BytesPerWord, &base); } + virtual void popFrameForTailCall(unsigned footprint, + int offset, + int returnAddressSurrogate, + int framePointerSurrogate) + { + if (offset) { + Register tmp(c.client->acquireTemporary()); + + Memory returnAddressSrc(rsp, (footprint + 1) * BytesPerWord); + moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &tmp); + + Memory returnAddressDst(rsp, (footprint - offset + 1) * BytesPerWord); + moveRM(&c, BytesPerWord, &tmp, BytesPerWord, &returnAddressDst); + + c.client->releaseTemporary(tmp.low); + + Memory baseSrc(rbp, footprint * BytesPerWord); + Register base(rbp); + moveMR(&c, BytesPerWord, &baseSrc, BytesPerWord, &base); + + Register stack(rsp); + Constant footprintConstant(resolved(&c, footprint * BytesPerWord)); + addCR(&c, BytesPerWord, &footprintConstant, BytesPerWord, &stack); + + if (returnAddressSurrogate != NoRegister) { + assert(&c, offset > 0); + + Register ras(returnAddressSurrogate); + Memory dst(rsp, offset * BytesPerWord); + moveRM(&c, BytesPerWord, &ras, BytesPerWord, &dst); + } + + if (framePointerSurrogate != NoRegister) { + assert(&c, offset > 0); + + Register fps(framePointerSurrogate); + Memory dst(rsp, (offset - 1) * BytesPerWord); + moveRM(&c, BytesPerWord, &fps, BytesPerWord, &dst); + } + } else { + popFrame(); + } + } + + virtual void popFrameAndPopArgumentsAndReturn(unsigned argumentFootprint) { + popFrame(); + + assert(&c, argumentFootprint >= StackAlignmentInWords); + assert(&c, (argumentFootprint % StackAlignmentInWords) == 0); + + if (argumentFootprint > StackAlignmentInWords) { + Register returnAddress(rcx); + popR(&c, BytesPerWord, &returnAddress); + + Register stack(rsp); + Constant adjustment + (resolved(&c, (argumentFootprint - StackAlignmentInWords) + * BytesPerWord)); + addCR(&c, BytesPerWord, &adjustment, BytesPerWord, &stack); + + jumpR(&c, BytesPerWord, &returnAddress); + } else { + return_(&c); + } + } + virtual void apply(Operation op) { arch_->c.operations[op](&c); } From 3113ae74ebd320b1d540fd1958f0ef162cb1119e Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 22 Apr 2009 01:39:25 +0000 Subject: [PATCH 006/172] various bugfixes --- src/assembler.h | 6 ++---- src/compile.cpp | 26 ++++++++++++----------- src/compiler.cpp | 55 ++++++++++++++++++++++++++---------------------- src/compiler.h | 3 +-- src/x86.cpp | 26 ++++++++++++++--------- 5 files changed, 63 insertions(+), 53 deletions(-) diff --git a/src/assembler.h b/src/assembler.h index 0075ed1c8e..6d6033e38f 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -282,8 +282,6 @@ class Assembler { virtual void updateCall(UnaryOperation op, bool assertAlignment, void* returnAddress, void* newTarget) = 0; - virtual unsigned constantCallSize() = 0; - virtual uintptr_t getConstant(const void* src) = 0; virtual void setConstant(void* dst, uintptr_t constant) = 0; @@ -293,8 +291,8 @@ class Assembler { virtual unsigned frameHeaderSize() = 0; virtual unsigned frameReturnAddressSize() = 0; virtual unsigned frameFooterSize() = 0; - virtual unsigned returnAddressOffset() = 0; - virtual unsigned framePointerOffset() = 0; + virtual int returnAddressOffset() = 0; + virtual int framePointerOffset() = 0; virtual void nextFrame(void** stack, void** base) = 0; virtual void plan diff --git a/src/compile.cpp b/src/compile.cpp index 881ff5d30b..20cbca17bf 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -487,11 +487,11 @@ class TraceElementPromise: public Promise { virtual int64_t value() { assert(s, resolved()); - return reinterpret_cast(trace->address); + return trace->address->value(); } virtual bool resolved() { - return trace->address != 0; + return trace->address != 0 and trace->address->resolved(); } System* s; @@ -1943,7 +1943,7 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target, bool tailCall, Compiler::Operand* result = c->stackCall (returnAddress, flags | Compiler::Aligned, - 0, + trace, rSize, methodParameterFootprint(t, target)); @@ -1982,14 +1982,16 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target, bool tailCall, } } -void +bool compileDirectInvoke(MyThread* t, Frame* frame, object target, bool tailCall) { unsigned rSize = resultSize(t, methodReturnCode(t, target)); Compiler::Operand* result = 0; - if (not emptyMethod(t, target)) { + if (emptyMethod(t, target)) { + tailCall = false; + } else { BootContext* bc = frame->context->bootContext; if (bc) { if (methodClass(t, target) == methodClass(t, frame->context->method) @@ -2024,6 +2026,8 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target, bool tailCall) if (rSize) { pushReturnValue(t, frame, methodReturnCode(t, target), result); } + + return tailCall; } void @@ -3157,7 +3161,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, tailCall = isTailCall(t, code, ip, context->method, target); - compileDirectInvoke(t, frame, target, tailCall); + tailCall = compileDirectInvoke(t, frame, target, tailCall); } break; case invokestatic: { @@ -3170,7 +3174,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, tailCall = isTailCall(t, code, ip, context->method, target); - compileDirectInvoke(t, frame, target, tailCall); + tailCall = compileDirectInvoke(t, frame, target, tailCall); } break; case invokevirtual: { @@ -3199,7 +3203,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* result = c->stackCall (c->memory(classOperand, offset, 0, 1), - tailCall ? Compiler::TailCall : 0, + tailCall ? Compiler::TailJump : 0, frame->trace(0, 0), rSize, parameterFootprint); @@ -4594,11 +4598,9 @@ compileMethod2(MyThread* t, void* ip) } else { void* address = reinterpret_cast(methodAddress(t, target)); uint8_t* updateIp = static_cast(ip); - if (callNodeFlags(t, node) & TraceElement::TailCall) { - updateIp -= t->arch->constantCallSize(); - } - updateCall(t, Call, true, updateIp, address); + updateCall(t, (callNodeFlags(t, node) & TraceElement::TailCall) + ? Jump : Call, true, updateIp, address); return address; } diff --git a/src/compiler.cpp b/src/compiler.cpp index 0a90033ce9..6906be054f 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -649,10 +649,8 @@ int frameIndex(Context* c, int localIndex) { assert(c, localIndex >= 0); - assert(c, localIndex < static_cast - (c->parameterFootprint + c->localFootprint)); - int index = c->alignedFrameSize + c->parameterFootprint - localIndex; + int index = c->alignedFrameSize + c->parameterFootprint - localIndex - 1; if (localIndex < static_cast(c->parameterFootprint)) { index += c->arch->frameHeaderSize(); @@ -661,6 +659,7 @@ frameIndex(Context* c, int localIndex) } assert(c, index >= 0); + assert(c, static_cast(index) < totalFrameSize(c)); return index; } @@ -668,15 +667,31 @@ frameIndex(Context* c, int localIndex) unsigned frameIndexToOffset(Context* c, unsigned frameIndex) { + assert(c, frameIndex < totalFrameSize(c)); + return (frameIndex + c->arch->frameFooterSize()) * BytesPerWord; } unsigned offsetToFrameIndex(Context* c, unsigned offset) { + assert(c, static_cast + ((offset / BytesPerWord) - c->arch->frameFooterSize()) >= 0); + + assert(c, (offset / BytesPerWord) - c->arch->frameFooterSize() + < totalFrameSize(c)); + return (offset / BytesPerWord) - c->arch->frameFooterSize(); } +unsigned +frameBase(Context* c) +{ + return c->alignedFrameSize - 1 + - c->arch->frameFooterSize() + + c->arch->frameHeaderSize(); +} + class FrameIterator { public: class Element { @@ -2307,10 +2322,10 @@ class CallEvent: public Event { int returnAddressIndex = -1; int framePointerIndex = -1; - if (flags & (Compiler::TailJump | Compiler::TailCall)) { + if (flags & Compiler::TailJump) { assert(c, argumentCount == 0); - unsigned base = c->alignedFrameSize - c->arch->frameFooterSize(); + int base = frameBase(c); returnAddressIndex = base + c->arch->returnAddressOffset(); framePointerIndex = base + c->arch->framePointerOffset(); @@ -2387,9 +2402,7 @@ class CallEvent: public Event { addRead(c, this, s->value, read (c, SiteMask(1 << MemoryOperand, 0, frameIndex))); } - } - else if ((flags & (Compiler::TailJump | Compiler::TailCall)) == 0) - { + } else if ((flags & Compiler::TailJump) == 0) { unsigned logicalIndex = ::frameIndex (c, s->index + c->localFootprint); @@ -2405,7 +2418,7 @@ class CallEvent: public Event { -- footprint; - if (footprint == 0) { + if (footprint == 0 and (flags & Compiler::TailJump) == 0) { unsigned logicalIndex = ::frameIndex (c, s->index + c->localFootprint); @@ -2418,7 +2431,7 @@ class CallEvent: public Event { ++ frameIndex; } - if ((flags & (Compiler::TailJump | Compiler::TailCall)) == 0) { + if ((flags & Compiler::TailJump) == 0) { popIndex = c->alignedFrameSize - c->arch->frameFooterSize() @@ -2438,19 +2451,11 @@ class CallEvent: public Event { virtual void compile(Context* c) { UnaryOperation op; - if (flags & (Compiler::TailJump | Compiler::TailCall)) { - if (flags & Compiler::TailJump) { - if (flags & Compiler::Aligned) { - op = AlignedJump; - } else { - op = Jump; - } + if (flags & Compiler::TailJump) { + if (flags & Compiler::Aligned) { + op = AlignedJump; } else { - if (flags & Compiler::Aligned) { - op = AlignedCall; - } else { - op = Call; - } + op = Jump; } assert(c, returnAddressSurrogate == 0 @@ -2464,8 +2469,8 @@ class CallEvent: public Event { (framePointerSurrogate->source)->number : NoRegister); int offset - = static_cast(c->arch->argumentFootprint(c->parameterFootprint)) - - static_cast(c->arch->argumentFootprint(stackArgumentFootprint)); + = static_cast(c->arch->argumentFootprint(stackArgumentFootprint)) + - static_cast(c->arch->argumentFootprint(c->parameterFootprint)); c->assembler->popFrameForTailCall(c->alignedFrameSize, offset, ras, fps); } else if (flags & Compiler::Aligned) { @@ -4920,7 +4925,7 @@ class MyCompiler: public Compiler { new (c.frameResources + i) FrameResource; } - unsigned base = alignedFrameSize - c.arch->frameFooterSize(); + unsigned base = frameBase(&c); c.frameResources[base + c.arch->returnAddressOffset()].reserved = true; c.frameResources[base + c.arch->framePointerOffset()].reserved = true; diff --git a/src/compiler.h b/src/compiler.h index b2fed6f48a..98c5dfb620 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -27,8 +27,7 @@ class Compiler { static const unsigned Aligned = 1 << 0; static const unsigned NoReturn = 1 << 1; - static const unsigned TailCall = 1 << 2; - static const unsigned TailJump = 1 << 3; + static const unsigned TailJump = 1 << 2; class Operand { }; class StackElement { }; diff --git a/src/x86.cpp b/src/x86.cpp index 53bce312d5..b33b418263 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -673,6 +673,13 @@ alignedCallC(Context* c, unsigned size, Assembler::Constant* a) callC(c, size, a); } +void +alignedJumpC(Context* c, unsigned size, Assembler::Constant* a) +{ + new (c->zone->allocate(sizeof(AlignmentPadding))) AlignmentPadding(c); + jumpC(c, size, a); +} + void pushR(Context* c, unsigned size, Assembler::Register* a) { @@ -1938,6 +1945,8 @@ populateTables(ArchitectureContext* c) uo[index(Jump, C)] = CAST1(jumpC); uo[index(Jump, M)] = CAST1(jumpM); + uo[index(AlignedJump, C)] = CAST1(alignedJumpC); + uo[index(JumpIfEqual, C)] = CAST1(jumpIfEqualC); uo[index(JumpIfNotEqual, C)] = CAST1(jumpIfNotEqualC); uo[index(JumpIfGreater, C)] = CAST1(jumpIfGreaterC); @@ -2126,10 +2135,6 @@ class MyArchitecture: public Assembler::Architecture { } } - virtual unsigned constantCallSize() { - return 5; - } - virtual uintptr_t getConstant(const void* src) { uintptr_t v; memcpy(&v, src, BytesPerWord); @@ -2162,12 +2167,12 @@ class MyArchitecture: public Assembler::Architecture { return 0; } - virtual unsigned returnAddressOffset() { - return 1; + virtual int returnAddressOffset() { + return 0; } - virtual unsigned framePointerOffset() { - return 0; + virtual int framePointerOffset() { + return -1; } virtual void nextFrame(void** stack, void** base) { @@ -2427,12 +2432,13 @@ class MyAssembler: public Assembler { c.client->releaseTemporary(tmp.low); - Memory baseSrc(rbp, footprint * BytesPerWord); + Memory baseSrc(rsp, footprint * BytesPerWord); Register base(rbp); moveMR(&c, BytesPerWord, &baseSrc, BytesPerWord, &base); Register stack(rsp); - Constant footprintConstant(resolved(&c, footprint * BytesPerWord)); + Constant footprintConstant + (resolved(&c, (footprint - offset + 1) * BytesPerWord)); addCR(&c, BytesPerWord, &footprintConstant, BytesPerWord, &stack); if (returnAddressSurrogate != NoRegister) { From de84afe2fe5008c1888c390aad1a542a38f44bc5 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 25 Apr 2009 11:47:41 -0600 Subject: [PATCH 007/172] adjust stack if necessary after non-tail-call in case where callee pops arguments --- src/compiler.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/compiler.cpp b/src/compiler.cpp index 6906be054f..29daef0e12 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -2486,6 +2486,20 @@ class CallEvent: public Event { padIndex, padding); } + if ((flags & Compiler::TailJump) == 0) { + unsigned footprint = c->arch->argumentFootprint(stackArgumentFootprint); + if (footprint > c->arch->stackAlignmentInWords()) { + Assembler::Register stack(c->arch->stack()); + ResolvedPromise adjustmentPromise + ((footprint - c->arch->stackAlignmentInWords()) * BytesPerWord); + Assembler::Constant adjustmentConstant(&adjustmentPromise); + c->assembler->apply + (Subtract, BytesPerWord, ConstantOperand, &adjustmentConstant, + BytesPerWord, RegisterOperand, &stack, + BytesPerWord, RegisterOperand, &stack); + } + } + clean(c, this, stackBefore, localsBefore, reads, popIndex); if (resultSize and live(result)) { From 1ed7c0d94cf46390a4b602f511bf9c341846cb1c Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 25 Apr 2009 11:49:56 -0600 Subject: [PATCH 008/172] adapt native method call code to new calling convention --- src/assembler.h | 6 +++++- src/compile.cpp | 17 +++++++++++++---- src/powerpc.cpp | 31 +++++++++++++++++++++++++++++-- src/x86.cpp | 32 +++++++++++++++++++------------- 4 files changed, 66 insertions(+), 20 deletions(-) diff --git a/src/assembler.h b/src/assembler.h index 6d6033e38f..2ce04b44e7 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -273,10 +273,13 @@ class Assembler { virtual bool reserved(int register_) = 0; + virtual unsigned frameFootprint(unsigned footprint) = 0; virtual unsigned argumentFootprint(unsigned footprint) = 0; virtual unsigned argumentRegisterCount() = 0; virtual int argumentRegister(unsigned index) = 0; + virtual unsigned stackAlignmentInWords() = 0; + virtual bool matchCall(void* returnAddress, void* target) = 0; virtual void updateCall(UnaryOperation op, bool assertAlignment, @@ -322,7 +325,6 @@ class Assembler { virtual Architecture* arch() = 0; virtual void saveFrame(unsigned stackOffset, unsigned baseOffset) = 0; - virtual void restoreFrame(unsigned stackOffset, unsigned baseOffset) = 0; virtual void pushFrame(unsigned argumentCount, ...) = 0; virtual void allocateFrame(unsigned footprint) = 0; virtual void popFrame() = 0; @@ -331,6 +333,8 @@ class Assembler { int framePointerSurrogate) = 0; virtual void popFrameAndPopArgumentsAndReturn(unsigned argumentFootprint) = 0; + virtual void popFrameAndUpdateStackAndReturn(unsigned stackOffsetFromThread) + = 0; virtual void apply(Operation op) = 0; diff --git a/src/compile.cpp b/src/compile.cpp index 20cbca17bf..3d2457869a 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -378,7 +378,7 @@ alignedFrameSize(MyThread* t, object method) (localSize(t, method) - methodParameterFootprint(t, method) + codeMaxStack(t, methodCode(t, method)) - + t->arch->argumentFootprint(MaxNativeCallFootprint)); + + t->arch->frameFootprint(MaxNativeCallFootprint)); } unsigned @@ -4835,6 +4835,17 @@ invokeNative2(MyThread* t, object method) default: abort(t); } + + if (t->arch->argumentFootprint(footprint) + > t->arch->stackAlignmentInWords()) + { + t->stack = static_cast(t->stack) + + (t->arch->argumentFootprint(footprint) + - t->arch->stackAlignmentInWords()); + } + + t->stack = static_cast(t->stack) + - t->arch->frameReturnAddressSize(); } else { result = 0; } @@ -6119,9 +6130,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, Assembler::Constant proc(&(nativeContext.promise)); a->apply(LongCall, BytesPerWord, ConstantOperand, &proc); - a->popFrame(); - - a->apply(Return); + a->popFrameAndUpdateStackAndReturn(difference(&(t->stack), t)); a->endBlock(false)->resolve(0, 0); } diff --git a/src/powerpc.cpp b/src/powerpc.cpp index 19c217a3e8..dc1e315ebb 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -65,6 +65,7 @@ inline int sth(int rs, int ra, int i) { return D(44, rs, ra, i); } inline int sthx(int rs, int ra, int rb) { return X(31, rs, ra, rb, 407, 0); } inline int stw(int rs, int ra, int i) { return D(36, rs, ra, i); } inline int stwu(int rs, int ra, int i) { return D(37, rs, ra, i); } +inline int stwux(int rs, int ra, int i) { return X(31, rs, ra, rb, 183, 0); } inline int stwx(int rs, int ra, int rb) { return X(31, rs, ra, rb, 151, 0); } inline int add(int rt, int ra, int rb) { return XO(31, rt, ra, rb, 0, 266, 0); } inline int addc(int rt, int ra, int rb) { return XO(31, rt, ra, rb, 0, 10, 0); } @@ -907,9 +908,15 @@ moveAndUpdateRM(Context* c, unsigned srcSize UNUSED, Assembler::Register* src, { assert(c, srcSize == BytesPerWord); assert(c, dstSize == BytesPerWord); - assert(c, dst->index == NoRegister); - issue(c, stwu(src->low, dst->base, dst->offset)); + if (dst->index == NoRegister) { + issue(c, stwu(src->low, dst->base, dst->offset)); + } else { + assert(c, dst->offset == 0); + assert(c, dst->scale == 1); + + issue(c, stwux(src->low, dst->base, dst->index)); + } } void @@ -2034,6 +2041,26 @@ class MyAssembler: public Assembler { return_(&c); } + virtual void popFrameAndUpdateStackAndReturn(unsigned stackOffset) { + popFrame(); + + Register tmp1(0); + Memory stackSrc(StackRegister, 0); + moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &tmp1); + + Register tmp2(arch_->returnLow()); + Memory newStackSrc(ThreadRegister, stackOffsetFromThread); + moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &tmp2); + + Register stack(StackRegister); + subR(&c, BytesPerWord, &tmp2, &stack, &tmp2); + + Memory stackDst(StackRegister, 0, tmp2.low); + moveAndUpdateRM(&c, BytesPerWord, &tmp1, BytesPerWord, &stackDst); + + return_(&c); + } + virtual void apply(Operation op) { arch_->c.operations[op](&c); } diff --git a/src/x86.cpp b/src/x86.cpp index b33b418263..8bdd62e4e5 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -2062,7 +2062,7 @@ class MyArchitecture: public Assembler::Architecture { } } - virtual unsigned stackPadding(unsigned footprint) { + virtual unsigned frameFootprint(unsigned footprint) { return max(footprint > argumentRegisterCount() ? footprint - argumentRegisterCount() : 0, StackAlignmentInWords); @@ -2097,6 +2097,10 @@ class MyArchitecture: public Assembler::Architecture { } } + virtual unsigned stackAlignmentInWords() { + return StackAlignmentInWords; + } + virtual bool matchCall(void* returnAddress, void* target) { uint8_t* instruction = static_cast(returnAddress) - 5; int32_t actualOffset; memcpy(&actualOffset, instruction + 1, 4); @@ -2346,18 +2350,6 @@ class MyAssembler: public Assembler { BytesPerWord, MemoryOperand, &baseDst); } - virtual void restoreFrame(unsigned stackOffset, unsigned baseOffset) { - Register stack(rsp); - Memory stackDst(rbx, stackOffset); - apply(Move, BytesPerWord, MemoryOperand, &stackDst, - BytesPerWord, RegisterOperand, &stack); - - Register base(rbp); - Memory baseDst(rbx, baseOffset); - apply(Move, BytesPerWord, MemoryOperand, &baseDst, - BytesPerWord, RegisterOperand, &base); - } - virtual void pushFrame(unsigned argumentCount, ...) { struct { unsigned size; @@ -2483,6 +2475,20 @@ class MyAssembler: public Assembler { } } + virtual void popFrameAndUpdateStackAndReturn(unsigned stackOffsetFromThread) + { + popFrame(); + + Register returnAddress(rcx); + popR(&c, BytesPerWord, &returnAddress); + + Register stack(rsp); + Memory stackSrc(rbx, stackOffsetFromThread); + moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &stack); + + jumpR(&c, BytesPerWord, &returnAddress); + } + virtual void apply(Operation op) { arch_->c.operations[op](&c); } From 5354e36530cd0156592c099ae63ef0939954bef0 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 25 Apr 2009 17:31:24 -0600 Subject: [PATCH 009/172] fix unsafe stack pointer adjustment in vmInvoke --- src/compile-x86.S | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/compile-x86.S b/src/compile-x86.S index 8bc7d879e8..e204a2ab51 100644 --- a/src/compile-x86.S +++ b/src/compile-x86.S @@ -129,11 +129,10 @@ LOCAL(test): // call function call *12(%ebp) - // restore stack pointer - movl %ebp,%esp - - // restore callee-saved registers - subl $16,%esp + // restore stack pointer and callee-saved registers + movl %ebp,%ecx + subl $16,%ecx + movl %ecx,%esp movl 0(%esp),%ebx movl 4(%esp),%esi From 141862470b307decb5920d21a1f691044a6f18f6 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 25 Apr 2009 17:33:42 -0600 Subject: [PATCH 010/172] fix stack pointer adjustment in invokeNative2; pad frame size using Architecture::frameFootprint in MyProcessor::invoke to conform to new calling convention --- src/compile.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index 3d2457869a..3bd85c34fa 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -4836,16 +4836,17 @@ invokeNative2(MyThread* t, object method) default: abort(t); } - if (t->arch->argumentFootprint(footprint) + unsigned parameterFootprint = methodParameterFootprint(t, method); + if (t->arch->argumentFootprint(parameterFootprint) > t->arch->stackAlignmentInWords()) { t->stack = static_cast(t->stack) - + (t->arch->argumentFootprint(footprint) + + (t->arch->argumentFootprint(parameterFootprint) - t->arch->stackAlignmentInWords()); } t->stack = static_cast(t->stack) - - t->arch->frameReturnAddressSize(); + + t->arch->frameReturnAddressSize(); } else { result = 0; } @@ -5139,7 +5140,8 @@ invoke(Thread* thread, object method, ArgumentList* arguments) (t, reinterpret_cast(methodAddress(t, method)), arguments->array + arguments->position, count * BytesPerWord, - t->arch->alignFrameSize(count) * BytesPerWord, + t->arch->alignFrameSize(count + t->arch->frameFootprint(0)) + * BytesPerWord, returnType); } From 89221bfcfa6c0928af6382f67961da8fb5975fa6 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 25 Apr 2009 17:52:08 -0600 Subject: [PATCH 011/172] fix handling of virtual calls to native methods --- src/compile.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/compile.cpp b/src/compile.cpp index 3bd85c34fa..24fd2077fc 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -4641,7 +4641,9 @@ compileVirtualMethod2(MyThread* t, object class_, unsigned index) return 0; } else { void* address = reinterpret_cast(methodAddress(t, target)); - if (address != reinterpret_cast(nativeThunk(t))) { + if (methodFlags(t, target) & ACC_NATIVE) { + t->trace->nativeMethod = target; + } else { classVtable(t, class_, methodOffset(t, target)) = address; } return address; From 0245a94ab89ae105ccd618adf5142dd808f11347 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 25 Apr 2009 19:51:33 -0600 Subject: [PATCH 012/172] generate code in ReturnEvent if and only if the event is preceded by at least one non-tail-call --- src/compile.cpp | 97 +++++++++++++++++++++++++++--------------------- src/compiler.cpp | 25 ++++++++++++- 2 files changed, 78 insertions(+), 44 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index 24fd2077fc..b15c685291 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -2165,26 +2165,48 @@ needsReturnBarrier(MyThread* t, object method) and (classFlags(t, methodClass(t, method)) & HasFinalMemberFlag); } +bool +returnsNext(MyThread* t, object code, unsigned ip) +{ + switch (codeBody(t, code, ip)) { + case return_: + case areturn: + case ireturn: + case freturn: + case lreturn: + case dreturn: + return true; + + case goto_: { + uint32_t offset = codeReadInt16(t, code, ++ip); + uint32_t newIp = (ip - 3) + offset; + assert(t, newIp < codeLength(t, code)); + + return returnsNext(t, code, newIp); + } + + case goto_w: { + uint32_t offset = codeReadInt32(t, code, ++ip); + uint32_t newIp = (ip - 5) + offset; + assert(t, newIp < codeLength(t, code)); + + return returnsNext(t, code, newIp); + } + + default: + return false; + } +} + bool isTailCall(MyThread* t, object code, unsigned ip, object caller, object callee) { - if (((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))) - { - switch (codeBody(t, code, ip)) { - case return_: - case areturn: - case ireturn: - case freturn: - case lreturn: - case dreturn: - return true; - } - } - return false; + return (((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)) + and returnsNext(t, code, ip)); } void @@ -2209,7 +2231,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Frame* frame = &myFrame; Compiler* c = frame->c; Context* context = frame->context; - bool tailCall = false; object code = methodCode(t, context->method); PROTECT(t, code); @@ -2408,10 +2429,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case areturn: { Compiler::Operand* value = frame->popObject(); - if (not tailCall) { - handleExit(t, frame); - c->return_(BytesPerWord, value); - } + handleExit(t, frame); + c->return_(BytesPerWord, value); } return; case arraylength: { @@ -3159,9 +3178,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); - tailCall = isTailCall(t, code, ip, context->method, target); + bool tailCall = isTailCall(t, code, ip, context->method, target); - tailCall = compileDirectInvoke(t, frame, target, tailCall); + compileDirectInvoke(t, frame, target, tailCall); } break; case invokestatic: { @@ -3172,9 +3191,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, assert(t, methodFlags(t, target) & ACC_STATIC); - tailCall = isTailCall(t, code, ip, context->method, target); + bool tailCall = isTailCall(t, code, ip, context->method, target); - tailCall = compileDirectInvoke(t, frame, target, tailCall); + compileDirectInvoke(t, frame, target, tailCall); } break; case invokevirtual: { @@ -3193,7 +3212,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, unsigned rSize = resultSize(t, methodReturnCode(t, target)); - tailCall = isTailCall(t, code, ip, context->method, target); + bool tailCall = isTailCall(t, code, ip, context->method, target); Compiler::Operand* classOperand = c->and_ (BytesPerWord, c->constant(PointerMask), @@ -3232,10 +3251,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case ireturn: case freturn: { Compiler::Operand* value = frame->popInt(); - if (not tailCall) { - handleExit(t, frame); - c->return_(4, value); - } + handleExit(t, frame); + c->return_(4, value); } return; case ishl: { @@ -3529,10 +3546,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case lreturn: case dreturn: { Compiler::Operand* value = frame->popLong(); - if (not tailCall) { - handleExit(t, frame); - c->return_(8, value); - } + handleExit(t, frame); + c->return_(8, value); } return; case lshl: { @@ -3827,14 +3842,12 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, return; case return_: - if (not tailCall) { - if (needsReturnBarrier(t, context->method)) { - c->storeStoreBarrier(); - } - - handleExit(t, frame); - c->return_(0, 0); + if (needsReturnBarrier(t, context->method)) { + c->storeStoreBarrier(); } + + handleExit(t, frame); + c->return_(0, 0); return; case sipush: diff --git a/src/compiler.cpp b/src/compiler.cpp index 29daef0e12..499a71c380 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -620,6 +620,8 @@ class Event { virtual bool isBranch() { return false; } + virtual bool allTailCalls() { return false; } + Event* next; Stack* stackBefore; Local* localsBefore; @@ -2510,6 +2512,10 @@ class CallEvent: public Event { } } + virtual bool allTailCalls() { + return (flags & Compiler::TailJump) != 0; + } + Value* address; TraceHandler* traceHandler; Value* result; @@ -2535,6 +2541,15 @@ appendCall(Context* c, Value* address, unsigned flags, stackArgumentFootprint)); } +bool +followsOnlyTailCalls(Event* event) +{ + for (Link* p = event->predecessors; p; p = p->nextPredecessor) { + if (not p->predecessor->allTailCalls()) return false; + } + return true; +} + class ReturnEvent: public Event { public: ReturnEvent(Context* c, unsigned size, Value* value): @@ -2558,8 +2573,10 @@ class ReturnEvent: public Event { popRead(c, this, r->value); } - c->assembler->popFrameAndPopArgumentsAndReturn - (c->arch->argumentFootprint(c->parameterFootprint)); + if (not followsOnlyTailCalls(this)) { + c->assembler->popFrameAndPopArgumentsAndReturn + (c->arch->argumentFootprint(c->parameterFootprint)); + } } Value* value; @@ -3739,6 +3756,10 @@ class BranchEvent: public Event { virtual bool isBranch() { return true; } + virtual bool allTailCalls() { + return type == Jump and followsOnlyTailCalls(this); + } + UnaryOperation type; Value* address; }; From 630fde86f7f2780fa8dd98fcedf7b42782801d9c Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 25 Apr 2009 20:07:47 -0600 Subject: [PATCH 013/172] freeze registers in CallEvent::compile to ensure they are not used as temporaries by the assmebler --- src/compiler.cpp | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/src/compiler.cpp b/src/compiler.cpp index 499a71c380..0ad5d648d6 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -2465,10 +2465,25 @@ class CallEvent: public Event { assert(c, framePointerSurrogate == 0 or framePointerSurrogate->source->type(c) == RegisterOperand); - int ras = (returnAddressSurrogate ? static_cast - (returnAddressSurrogate->source)->number : NoRegister); - int fps = (framePointerSurrogate ? static_cast - (framePointerSurrogate->source)->number : NoRegister); + int ras; + if (returnAddressSurrogate) { + returnAddressSurrogate->source->freeze(c, returnAddressSurrogate); + + ras = static_cast + (returnAddressSurrogate->source)->number; + } else { + ras = NoRegister; + } + + int fps; + if (framePointerSurrogate) { + framePointerSurrogate->source->freeze(c, framePointerSurrogate); + + fps = static_cast + (framePointerSurrogate->source)->number; + } else { + fps = NoRegister; + } int offset = static_cast(c->arch->argumentFootprint(stackArgumentFootprint)) @@ -2488,7 +2503,15 @@ class CallEvent: public Event { padIndex, padding); } - if ((flags & Compiler::TailJump) == 0) { + if (flags & Compiler::TailJump) { + if (returnAddressSurrogate) { + returnAddressSurrogate->source->thaw(c, returnAddressSurrogate); + } + + if (framePointerSurrogate) { + framePointerSurrogate->source->thaw(c, framePointerSurrogate); + } + } else { unsigned footprint = c->arch->argumentFootprint(stackArgumentFootprint); if (footprint > c->arch->stackAlignmentInWords()) { Assembler::Register stack(c->arch->stack()); From 4091e871a79cd6b321304ffcb2af9d999509cc40 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 25 Apr 2009 20:14:29 -0600 Subject: [PATCH 014/172] tolerate null caller in Logger.log --- classpath/java/util/logging/Logger.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/classpath/java/util/logging/Logger.java b/classpath/java/util/logging/Logger.java index ab1a1bd28a..d06a7bb00a 100644 --- a/classpath/java/util/logging/Logger.java +++ b/classpath/java/util/logging/Logger.java @@ -113,8 +113,9 @@ public class Logger { if (level.intValue() < getEffectiveLevel().intValue()) { return; } - LogRecord r = new LogRecord(name, caller.getName(), level, message, - exception); + LogRecord r = new LogRecord + (name, caller == null ? "" : caller.getName(), level, message, + exception); publish(r); } From bf8fdb6316fc76ecebab120845f33d74c104aa9a Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 25 Apr 2009 20:24:04 -0600 Subject: [PATCH 015/172] visit MyProcessor::virtualThunks during GC --- src/compile.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/compile.cpp b/src/compile.cpp index b15c685291..ba35bd764e 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -5359,6 +5359,7 @@ class MyProcessor: public Processor { v->visit(&methodTreeSentinal); v->visit(&objectPools); v->visit(&staticTableArray); + v->visit(&virtualThunks); } for (MyThread::CallTrace* trace = t->trace; trace; trace = trace->next) { From 64b529c9154fee4046d1ab318ee984cd6bdf50a9 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 25 Apr 2009 20:54:36 -0600 Subject: [PATCH 016/172] avoid generating unreachable code after tail calls --- src/compile.cpp | 4 ++-- src/compiler.cpp | 28 +++++++++++++++++----------- src/compiler.h | 1 + 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index ba35bd764e..64ea0b0c18 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -1952,9 +1952,9 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target, bool tailCall, difference(&(t->tailAddress), t))); if (methodFlags(t, target) & ACC_NATIVE) { - c->jmp(c->constant(nativeThunk(t))); + c->exit(c->constant(nativeThunk(t))); } else { - c->jmp(c->constant(defaultThunk(t))); + c->exit(c->constant(defaultThunk(t))); } return result; diff --git a/src/compiler.cpp b/src/compiler.cpp index 0ad5d648d6..df0ac3a799 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -620,7 +620,7 @@ class Event { virtual bool isBranch() { return false; } - virtual bool allTailCalls() { return false; } + virtual bool allExits() { return false; } Event* next; Stack* stackBefore; @@ -2535,7 +2535,7 @@ class CallEvent: public Event { } } - virtual bool allTailCalls() { + virtual bool allExits() { return (flags & Compiler::TailJump) != 0; } @@ -2565,10 +2565,10 @@ appendCall(Context* c, Value* address, unsigned flags, } bool -followsOnlyTailCalls(Event* event) +unreachable(Event* event) { for (Link* p = event->predecessors; p; p = p->nextPredecessor) { - if (not p->predecessor->allTailCalls()) return false; + if (not p->predecessor->allExits()) return false; } return true; } @@ -2596,7 +2596,7 @@ class ReturnEvent: public Event { popRead(c, this, r->value); } - if (not followsOnlyTailCalls(this)) { + if (not unreachable(this)) { c->assembler->popFrameAndPopArgumentsAndReturn (c->arch->argumentFootprint(c->parameterFootprint)); } @@ -3692,8 +3692,8 @@ appendMemory(Context* c, Value* base, int displacement, Value* index, class BranchEvent: public Event { public: - BranchEvent(Context* c, UnaryOperation type, Value* address): - Event(c), type(type), address(address) + BranchEvent(Context* c, UnaryOperation type, Value* address, bool exit): + Event(c), type(type), address(address), exit(exit) { address->addPredecessor(c, this); @@ -3779,19 +3779,21 @@ class BranchEvent: public Event { virtual bool isBranch() { return true; } - virtual bool allTailCalls() { - return type == Jump and followsOnlyTailCalls(this); + virtual bool allExits() { + return type == Jump and (exit or unreachable(this)); } UnaryOperation type; Value* address; + bool exit; }; void -appendBranch(Context* c, UnaryOperation type, Value* address) +appendBranch(Context* c, UnaryOperation type, Value* address, + bool exit = false) { append(c, new (c->zone->allocate(sizeof(BranchEvent))) - BranchEvent(c, type, address)); + BranchEvent(c, type, address, exit)); } class BoundsCheckEvent: public Event { @@ -5465,6 +5467,10 @@ class MyCompiler: public Compiler { appendBranch(&c, Jump, static_cast(address)); } + virtual void exit(Operand* address) { + appendBranch(&c, Jump, static_cast(address), true); + } + virtual Operand* add(unsigned size, Operand* a, Operand* b) { Value* result = value(&c); appendCombine(&c, Add, size, static_cast(a), diff --git a/src/compiler.h b/src/compiler.h index 98c5dfb620..66c60e2276 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -116,6 +116,7 @@ class Compiler { virtual void je(Operand* address) = 0; virtual void jne(Operand* address) = 0; virtual void jmp(Operand* address) = 0; + virtual void exit(Operand* address) = 0; virtual Operand* add(unsigned size, Operand* a, Operand* b) = 0; virtual Operand* sub(unsigned size, Operand* a, Operand* b) = 0; virtual Operand* mul(unsigned size, Operand* a, Operand* b) = 0; From f80fb9b5369490ad529db3acdc39b693692fb37b Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 26 Apr 2009 12:19:16 -0600 Subject: [PATCH 017/172] refine code for picking target sites to avoid unecessary moves --- src/compiler.cpp | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/src/compiler.cpp b/src/compiler.cpp index df0ac3a799..19ea1e9627 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -1089,7 +1089,11 @@ FrameResource::thaw(Context* c, Value* v) class Target { public: - static const unsigned Penalty = 10; + static const unsigned MinimumRegisterCost = 0; + static const unsigned MinimumFrameCost = 1; + static const unsigned StealPenalty = 2; + static const unsigned StealUniquePenalty = 4; + static const unsigned LowRegisterPenalty = 10; static const unsigned Impossible = 20; Target(): cost(Impossible) { } @@ -1118,9 +1122,9 @@ resourceCost(Context* c UNUSED, Value* v, Resource* r) if (v and buddies(r->value, v)) { return 0; } else if (hasMoreThanOneSite(r->value)) { - return 2; + return Target::StealPenalty; } else { - return 4; + return Target::StealUniquePenalty; } } else { return 0; @@ -1135,7 +1139,7 @@ pickRegisterTarget(Context* c, Value* v, uint32_t mask, unsigned* cost) for (int i = c->arch->registerCount() - 1; i >= 0; --i) { if ((1 << i) & mask) { RegisterResource* r = c->registerResources + i; - unsigned myCost = resourceCost(c, v, r); + unsigned myCost = resourceCost(c, v, r) + Target::MinimumRegisterCost; if ((static_cast(1) << i) == mask) { *cost = myCost; return i; @@ -1161,7 +1165,8 @@ pickRegisterTarget(Context* c, Value* v, uint32_t mask) unsigned frameCost(Context* c, Value* v, int frameIndex) { - return resourceCost(c, v, c->frameResources + frameIndex) + 1; + return resourceCost(c, v, c->frameResources + frameIndex) + + Target::MinimumFrameCost; } Target @@ -1173,7 +1178,7 @@ pickFrameTarget(Context* c, Value* v) do { if (p->home >= 0) { Target mine(p->home, MemoryOperand, frameCost(c, v, p->home)); - if (mine.cost == 1) { + if (mine.cost == Target::MinimumFrameCost) { return mine; } else if (mine.cost < best.cost) { best = mine; @@ -1193,7 +1198,7 @@ pickAnyFrameTarget(Context* c, Value* v) unsigned count = totalFrameSize(c); for (unsigned i = 0; i < count; ++i) { Target mine(i, MemoryOperand, frameCost(c, v, i)); - if (mine.cost == 1) { + if (mine.cost == Target::MinimumFrameCost) { return mine; } else if (mine.cost < best.cost) { best = mine; @@ -1212,7 +1217,7 @@ pickTarget(Context* c, Value* value, const SiteMask& mask, mine.cost += registerPenalty; - if (mine.cost == 0) { + if (mine.cost == Target::MinimumRegisterCost) { return mine; } else if (mine.cost < best.cost) { best = mine; @@ -1222,7 +1227,7 @@ pickTarget(Context* c, Value* value, const SiteMask& mask, if ((mask.typeMask & (1 << MemoryOperand)) && mask.frameIndex >= 0) { Target mine(mask.frameIndex, MemoryOperand, frameCost(c, value, mask.frameIndex)); - if (mine.cost == 0) { + if (mine.cost == Target::MinimumFrameCost) { return mine; } else if (mine.cost < best.cost) { best = mine; @@ -1237,7 +1242,7 @@ pickTarget(Context* c, Read* read, bool intersectRead, unsigned registerReserveCount) { unsigned registerPenalty = (c->availableRegisterCount > registerReserveCount - ? 0 : Target::Penalty); + ? 0 : Target::LowRegisterPenalty); SiteMask mask; read->intersect(&mask); @@ -1250,8 +1255,8 @@ pickTarget(Context* c, Read* read, bool intersectRead, if (r) { SiteMask intersection = mask; if (r->intersect(&intersection)) { - best = pickTarget(c, read->value, mask, registerPenalty, best); - if (best.cost == 0) { + best = pickTarget(c, read->value, intersection, registerPenalty, best); + if (best.cost <= Target::MinimumFrameCost) { return best; } } @@ -1259,7 +1264,7 @@ pickTarget(Context* c, Read* read, bool intersectRead, } best = pickTarget(c, read->value, mask, registerPenalty, best); - if (best.cost == 0) { + if (best.cost <= Target::MinimumFrameCost) { return best; } @@ -1271,7 +1276,7 @@ pickTarget(Context* c, Read* read, bool intersectRead, mine.cost += registerPenalty; - if (mine.cost == 0) { + if (mine.cost == Target::MinimumRegisterCost) { return mine; } else if (mine.cost < best.cost) { best = mine; @@ -1279,14 +1284,16 @@ pickTarget(Context* c, Read* read, bool intersectRead, } { Target mine = pickFrameTarget(c, read->value); - if (mine.cost == 0) { + if (mine.cost == Target::MinimumFrameCost) { return mine; } else if (mine.cost < best.cost) { best = mine; } } - if (best.cost > 3 and c->availableRegisterCount == 0) { + if (best.cost >= Target::StealUniquePenalty + and c->availableRegisterCount == 0) + { // there are no free registers left, so moving from memory to // memory isn't an option - try harder to find an available frame // site: From 605ddffa31f8b8b7473f320d7f344f9c13a10fa5 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 26 Apr 2009 12:46:55 -0600 Subject: [PATCH 018/172] avoid unecessary array copy in Long.toString --- classpath/java/lang/Long.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/classpath/java/lang/Long.java b/classpath/java/lang/Long.java index 272c4365a9..279a8220ed 100644 --- a/classpath/java/lang/Long.java +++ b/classpath/java/lang/Long.java @@ -66,7 +66,7 @@ public final class Long extends Number implements Comparable { char[] array = new char[size]; - int i = array.length - 1; + int i = size - 1; for (long n = v; n != 0; n /= radix) { long digit = n % radix; if (negative) digit = -digit; @@ -83,7 +83,7 @@ public final class Long extends Number implements Comparable { array[i] = '-'; } - return new String(array); + return new String(array, 0, size, false); } public static String toString(long v) { From 03653d2dd82ca650a7c7d69128279daf45f65731 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 26 Apr 2009 15:55:35 -0600 Subject: [PATCH 019/172] fix stack unwinding and GC root scan for new calling convention --- src/compile.cpp | 49 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index 64ea0b0c18..95b8b424af 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -413,7 +413,7 @@ localOffset(MyThread* t, int v, object method) return offset; } -inline object* +object* localObject(MyThread* t, void* stack, object method, unsigned index) { return reinterpret_cast @@ -422,6 +422,14 @@ localObject(MyThread* t, void* stack, object method, unsigned index) + (t->arch->frameReturnAddressSize() * BytesPerWord)); } +void* +stackForFrame(MyThread* t, void* frame, object method) +{ + return static_cast(frame) + - alignedFrameSize(t, method) + - t->arch->frameHeaderSize(); +} + class PoolElement: public Promise { public: PoolElement(Thread* t, object target, PoolElement* next): @@ -1306,8 +1314,12 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, void* handler = findExceptionHandler(t, method, ip); + t->arch->nextFrame(&stack, &base); + + void* canonicalStack = stackForFrame(t, stack, method); + if (handler) { - void** sp = static_cast(stack) + void** sp = static_cast(canonicalStack) + t->arch->frameReturnAddressSize(); sp[localOffset(t, localSize(t, method), method) / BytesPerWord] @@ -1324,13 +1336,13 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, if (methodFlags(t, method) & ACC_STATIC) { lock = methodClass(t, method); } else { - lock = *localObject(t, stack, method, savedTargetIndex(t, method)); + lock = *localObject + (t, canonicalStack, method, savedTargetIndex(t, method)); } release(t, lock); } - t->arch->nextFrame(&stack, &base); ip = t->arch->frameIp(stack); } } else { @@ -4445,15 +4457,15 @@ finish(MyThread* t, Allocator* allocator, Context* context) (&byteArrayBody(t, methodSpec(t, context->method), 0))); // for debugging: - if (false and + if (//false and strcmp (reinterpret_cast (&byteArrayBody(t, className(t, methodClass(t, context->method)), 0)), - "java/lang/Throwable") == 0 and + "java/lang/Long") == 0 and strcmp (reinterpret_cast (&byteArrayBody(t, methodName(t, context->method), 0)), - "printStackTrace") == 0) + "toString") == 0) { trap(); } @@ -4937,22 +4949,24 @@ frameMapIndex(MyThread* t, object method, int32_t offset) } void -visitStackAndLocals(MyThread* t, Heap::Visitor* v, void* stack, object method, - void* ip, void* calleeStack, unsigned argumentFootprint) +visitStackAndLocals(MyThread* t, Heap::Visitor* v, void* frame, object method, + void* ip, bool skipArguments, unsigned argumentFootprint) { unsigned count; - if (calleeStack) { + if (skipArguments) { count = usableFrameSizeWithParameters(t, method) - argumentFootprint; } else { count = usableFrameSizeWithParameters(t, method); } - + if (count) { object map = codePool(t, methodCode(t, method)); int index = frameMapIndex (t, method, difference (ip, reinterpret_cast(methodAddress(t, method)))); + void* stack = stackForFrame(t, frame, method); + for (unsigned i = 0; i < count; ++i) { int j = index + i; if ((intArrayBody(t, map, j / 32) @@ -4975,7 +4989,7 @@ visitStack(MyThread* t, Heap::Visitor* v) } MyThread::CallTrace* trace = t->trace; - void* calleeStack = 0; + bool skipArguments = false; unsigned argumentFootprint = 0; while (stack) { @@ -4983,16 +4997,17 @@ visitStack(MyThread* t, Heap::Visitor* v) if (method) { PROTECT(t, method); - visitStackAndLocals - (t, v, stack, method, ip, calleeStack, argumentFootprint); + t->arch->nextFrame(&stack, &base); - calleeStack = stack; + visitStackAndLocals + (t, v, stack, method, ip, skipArguments, argumentFootprint); + + skipArguments = true; argumentFootprint = methodParameterFootprint(t, method); - t->arch->nextFrame(&stack, &base); ip = t->arch->frameIp(stack); } else if (trace) { - calleeStack = 0; + skipArguments = false; argumentFootprint = 0; stack = trace->stack; base = trace->base; From 299699f1ff5db3df34d109b00a04639df9a81c90 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 26 Apr 2009 16:06:15 -0600 Subject: [PATCH 020/172] fix stack unwinding for new calling convention (2nd try) --- src/compile.cpp | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index 95b8b424af..e5d71eaf10 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -1314,36 +1314,37 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, void* handler = findExceptionHandler(t, method, ip); - t->arch->nextFrame(&stack, &base); - - void* canonicalStack = stackForFrame(t, stack, method); - if (handler) { - void** sp = static_cast(canonicalStack) + *targetIp = handler; + *targetBase = base; + + t->arch->nextFrame(&stack, &base); + + void** sp = static_cast(stackForFrame(t, stack, method)) + t->arch->frameReturnAddressSize(); + *targetStack = sp; + sp[localOffset(t, localSize(t, method), method) / BytesPerWord] = t->exception; t->exception = 0; - - *targetIp = handler; - *targetBase = base; - *targetStack = sp; } else { + t->arch->nextFrame(&stack, &base); + ip = t->arch->frameIp(stack); + if (methodFlags(t, method) & ACC_SYNCHRONIZED) { object lock; if (methodFlags(t, method) & ACC_STATIC) { lock = methodClass(t, method); } else { lock = *localObject - (t, canonicalStack, method, savedTargetIndex(t, method)); + (t, stackForFrame(t, stack, method), method, + savedTargetIndex(t, method)); } release(t, lock); } - - ip = t->arch->frameIp(stack); } } else { *targetIp = ip; @@ -4457,15 +4458,15 @@ finish(MyThread* t, Allocator* allocator, Context* context) (&byteArrayBody(t, methodSpec(t, context->method), 0))); // for debugging: - if (//false and + if (false and strcmp (reinterpret_cast (&byteArrayBody(t, className(t, methodClass(t, context->method)), 0)), - "java/lang/Long") == 0 and + "java/lang/Throwable") == 0 and strcmp (reinterpret_cast (&byteArrayBody(t, methodName(t, context->method), 0)), - "toString") == 0) + "printStackTrace") == 0) { trap(); } From 50529969f9cb87072aa60be2ca4987f5699bb397 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 26 Apr 2009 19:53:42 -0600 Subject: [PATCH 021/172] fix code to visit GC roots on stack to be compatible with tail calls; avoid generating unreachable jumps --- src/assembler.h | 6 -- src/compile.cpp | 181 ++++++++++++++++++++++++----------------------- src/compiler.cpp | 23 +++--- src/compiler.h | 5 ++ 4 files changed, 109 insertions(+), 106 deletions(-) diff --git a/src/assembler.h b/src/assembler.h index 2ce04b44e7..0b39a9461c 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -198,12 +198,6 @@ class DelayedPromise: public ListenPromise { DelayedPromise* next; }; -class TraceHandler { - public: - virtual void handleTrace(Promise* address, unsigned padIndex, - unsigned padding) = 0; -}; - class Assembler { public: class Operand { }; diff --git a/src/compile.cpp b/src/compile.cpp index e5d71eaf10..b87fa6724e 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -50,6 +50,7 @@ class MyThread: public Thread { base(t->base), stack(t->stack), nativeMethod(0), + targetMethod(0), next(t->trace) { t->trace = this; @@ -68,6 +69,7 @@ class MyThread: public Thread { void* base; void* stack; object nativeMethod; + object targetMethod; CallTrace* next; }; @@ -464,18 +466,14 @@ class TraceElement: public TraceHandler { address(0), next(next), target(target), - padIndex(0), - padding(0), + argumentIndex(0), flags(flags) { } - virtual void handleTrace(Promise* address, unsigned padIndex, - unsigned padding) - { + virtual void handleTrace(Promise* address, unsigned argumentIndex) { if (this->address == 0) { this->address = address; - this->padIndex = padIndex; - this->padding = padding; + this->argumentIndex = argumentIndex; } } @@ -483,8 +481,7 @@ class TraceElement: public TraceHandler { Promise* address; TraceElement* next; object target; - unsigned padIndex; - unsigned padding; + unsigned argumentIndex; unsigned flags; uintptr_t map[0]; }; @@ -4092,31 +4089,9 @@ printSet(uintptr_t m, unsigned limit) } } -void -shiftLeftZeroPadded(void* data, int dataSizeInBytes, int shiftCountInBits) -{ - uint8_t* p = static_cast(data); - int shiftCountInBytes = shiftCountInBits / 8; - int shift = shiftCountInBits % 8; - - int count = dataSizeInBytes - shiftCountInBytes - 1; - for (int i = 0; i < count; ++i) { - int si = i + shiftCountInBytes; - p[i] = (p[si] >> shift) | ((p[si + 1] >> shift) << (8 - shift)); - } - - if (count >= 0) { - p[count] = (p[count + shiftCountInBytes] >> shift); - } - - for (int i = count + 1; i < dataSizeInBytes; ++i) { - p[i] = 0; - } -} - unsigned calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, - unsigned stackPadding, unsigned eventIndex) + unsigned eventIndex) { // for each instruction with more than one predecessor, and for each // stack position, determine if there exists a path to that @@ -4124,7 +4099,6 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, // stack position (i.e. it is uninitialized or contains primitive // data). - unsigned localSize = ::localSize(t, context->method); unsigned mapSize = frameMapSizeInWords(t, context->method); uintptr_t roots[mapSize]; @@ -4149,8 +4123,7 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, Event e = static_cast(context->eventLog.get(eventIndex++)); switch (e) { case PushContextEvent: { - eventIndex = calculateFrameMaps - (t, context, roots, stackPadding, eventIndex); + eventIndex = calculateFrameMaps(t, context, roots, eventIndex); } break; case PopContextEvent: @@ -4201,10 +4174,6 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, unsigned i = context->eventLog.get2(eventIndex); eventIndex += 2; - if (i >= localSize) { - i += stackPadding; - } - markBit(roots, i); } break; @@ -4212,10 +4181,6 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, unsigned i = context->eventLog.get2(eventIndex); eventIndex += 2; - if (i >= localSize) { - i += stackPadding; - } - clearBit(roots, i); } break; @@ -4229,12 +4194,6 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, memcpy(te->map, roots, mapSize * BytesPerWord); - if (te->flags & TraceElement::TailCall) { - shiftLeftZeroPadded - (te->map, mapSize * BytesPerWord, - usableFrameSize(t, context->method)); - } - eventIndex += BytesPerWord; } break; @@ -4412,22 +4371,8 @@ finish(MyThread* t, Allocator* allocator, Context* context) (p->address->value())); } - for (unsigned j = 0, k = 0; j < size; ++j, ++k) { - if (j == p->padIndex) { - unsigned limit = j + p->padding; - assert(t, limit <= size); - - for (; j < limit; ++j) { - if (DebugFrameMaps) { - fprintf(stderr, "_"); - } - clearBit(t, map, context->traceLogCount, size, i, j); - } - - if (j == size) break; - } - - if (getBit(p->map, k)) { + for (unsigned j = 0; j < p->argumentIndex; ++j) { + if (getBit(p->map, j)) { if (DebugFrameMaps) { fprintf(stderr, "1"); } @@ -4534,7 +4479,7 @@ compile(MyThread* t, Allocator* allocator, Context* context) if (UNLIKELY(t->exception)) return 0; context->dirtyRoots = false; - unsigned eventIndex = calculateFrameMaps(t, context, 0, 0, 0); + unsigned eventIndex = calculateFrameMaps(t, context, 0, 0); object eht = codeExceptionHandlerTable(t, methodCode(t, context->method)); if (eht) { @@ -4583,7 +4528,7 @@ compile(MyThread* t, Allocator* allocator, Context* context) compile(t, &frame2, exceptionHandlerIp(eh), start); if (UNLIKELY(t->exception)) return 0; - eventIndex = calculateFrameMaps(t, context, 0, 0, eventIndex); + eventIndex = calculateFrameMaps(t, context, 0, eventIndex); } } @@ -4593,7 +4538,7 @@ compile(MyThread* t, Allocator* allocator, Context* context) while (context->dirtyRoots) { context->dirtyRoots = false; - calculateFrameMaps(t, context, 0, 0, 0); + calculateFrameMaps(t, context, 0, 0); } return finish(t, allocator, context); @@ -4610,13 +4555,17 @@ void* compileMethod2(MyThread* t, void* ip) { object node = findCallNode(t, ip); - PROTECT(t, node); - object target = callNodeTarget(t, node); - PROTECT(t, target); if (LIKELY(t->exception == 0)) { + PROTECT(t, node); + PROTECT(t, target); + + t->trace->targetMethod = target; + compile(t, codeAllocator(t), 0, target); + + t->trace->targetMethod = 0; } if (UNLIKELY(t->exception)) { @@ -4655,6 +4604,18 @@ compileMethod(MyThread* t) void* compileVirtualMethod2(MyThread* t, object class_, unsigned index) { + // If class_ has BootstrapFlag set, that means its vtable is not yet + // available. However, we must set t->trace->targetMethod to an + // appropriate method to ensure we can accurately scan the stack for + // GC roots. We find such a method by looking for a superclass with + // a vtable and using it instead: + + object c = class_; + while (classVmFlags(t, c) & BootstrapFlag) { + c = classSuper(t, c); + } + t->trace->targetMethod = arrayBody(t, classVirtualTable(t, c), index); + PROTECT(t, class_); object target = resolveTarget(t, class_, index); @@ -4663,6 +4624,8 @@ compileVirtualMethod2(MyThread* t, object class_, unsigned index) compile(t, codeAllocator(t), 0, target); } + t->trace->targetMethod = 0; + if (UNLIKELY(t->exception)) { return 0; } else { @@ -4910,10 +4873,13 @@ invokeNative(MyThread* t) uint64_t result = 0; + t->trace->targetMethod = t->trace->nativeMethod; + if (LIKELY(t->exception == 0)) { result = invokeNative2(t, t->trace->nativeMethod); } + t->trace->targetMethod = 0; t->trace->nativeMethod = 0; if (UNLIKELY(t->exception)) { @@ -4951,14 +4917,9 @@ frameMapIndex(MyThread* t, object method, int32_t offset) void visitStackAndLocals(MyThread* t, Heap::Visitor* v, void* frame, object method, - void* ip, bool skipArguments, unsigned argumentFootprint) + void* ip) { - unsigned count; - if (skipArguments) { - count = usableFrameSizeWithParameters(t, method) - argumentFootprint; - } else { - count = usableFrameSizeWithParameters(t, method); - } + unsigned count = usableFrameSizeWithParameters(t, method); if (count) { object map = codePool(t, methodCode(t, method)); @@ -4979,6 +4940,49 @@ visitStackAndLocals(MyThread* t, Heap::Visitor* v, void* frame, object method, } } +void +visitArgument(MyThread* t, Heap::Visitor* v, void* stack, object method, + unsigned index) +{ + v->visit(static_cast(stack) + + (methodParameterFootprint(t, method) - index - 1) + + t->arch->frameReturnAddressSize() + + t->arch->frameFooterSize()); +} + +void +visitArguments(MyThread* t, Heap::Visitor* v, void* stack, object method) +{ + unsigned index = 0; + + if ((methodFlags(t, method) & ACC_STATIC) == 0) { + visitArgument(t, v, stack, method, index++); + } + + for (MethodSpecIterator it + (t, reinterpret_cast + (&byteArrayBody(t, methodSpec(t, method), 0))); + it.hasNext();) + { + switch (*it.next()) { + case 'L': + case '[': + visitArgument(t, v, stack, method, index++); + break; + + case 'J': + case 'D': + index += 2; + break; + + default: + ++ index; + break; + } + } + +} + void visitStack(MyThread* t, Heap::Visitor* v) { @@ -4990,30 +4994,32 @@ visitStack(MyThread* t, Heap::Visitor* v) } MyThread::CallTrace* trace = t->trace; - bool skipArguments = false; - unsigned argumentFootprint = 0; + object targetMethod = (trace ? trace->targetMethod : 0); while (stack) { object method = methodForIp(t, ip); if (method) { PROTECT(t, method); + if (targetMethod) { + visitArguments(t, v, stack, targetMethod); + targetMethod = 0; + } + t->arch->nextFrame(&stack, &base); - visitStackAndLocals - (t, v, stack, method, ip, skipArguments, argumentFootprint); - - skipArguments = true; - argumentFootprint = methodParameterFootprint(t, method); + visitStackAndLocals(t, v, stack, method, ip); ip = t->arch->frameIp(stack); } else if (trace) { - skipArguments = false; - argumentFootprint = 0; stack = trace->stack; base = trace->base; ip = t->arch->frameIp(stack); trace = trace->next; + + if (trace) { + targetMethod = trace->targetMethod; + } } else { break; } @@ -5380,6 +5386,7 @@ class MyProcessor: public Processor { for (MyThread::CallTrace* trace = t->trace; trace; trace = trace->next) { v->visit(&(trace->nativeMethod)); + v->visit(&(trace->targetMethod)); } for (Reference* r = t->reference; r; r = r->next) { diff --git a/src/compiler.cpp b/src/compiler.cpp index 19ea1e9627..9df66d4b41 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -2318,8 +2318,7 @@ class CallEvent: public Event { returnAddressSurrogate(0), framePointerSurrogate(0), popIndex(0), - padIndex(0), - padding(0), + stackArgumentIndex(0), flags(flags), resultSize(resultSize), stackArgumentFootprint(stackArgumentFootprint) @@ -2428,19 +2427,18 @@ class CallEvent: public Event { -- footprint; if (footprint == 0 and (flags & Compiler::TailJump) == 0) { - unsigned logicalIndex = ::frameIndex - (c, s->index + c->localFootprint); - - assert(c, logicalIndex >= frameIndex); - - padding = logicalIndex - frameIndex; - padIndex = s->index + c->localFootprint; + stackArgumentIndex = s->index + c->localFootprint; } ++ frameIndex; } if ((flags & Compiler::TailJump) == 0) { + if (stackArgumentFootprint == 0) { + stackArgumentIndex = (stackBefore ? stackBefore->index + 1 : 0) + + c->localFootprint; + } + popIndex = c->alignedFrameSize - c->arch->frameFooterSize() @@ -2507,7 +2505,7 @@ class CallEvent: public Event { if (traceHandler) { traceHandler->handleTrace(codePromise(c, c->assembler->offset()), - padIndex, padding); + stackArgumentIndex); } if (flags & Compiler::TailJump) { @@ -2552,8 +2550,7 @@ class CallEvent: public Event { Value* returnAddressSurrogate; Value* framePointerSurrogate; unsigned popIndex; - unsigned padIndex; - unsigned padding; + unsigned stackArgumentIndex; unsigned flags; unsigned resultSize; unsigned stackArgumentFootprint; @@ -3777,7 +3774,7 @@ class BranchEvent: public Event { jump = true; } - if (jump) { + if (jump and not unreachable(this)) { apply(c, type, BytesPerWord, address->source, 0); } diff --git a/src/compiler.h b/src/compiler.h index 66c60e2276..8e465e2857 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -17,6 +17,11 @@ namespace vm { +class TraceHandler { + public: + virtual void handleTrace(Promise* address, unsigned argumentIndex) = 0; +}; + class Compiler { public: class Client { From fd99691b009c76e814730f73ff66b07806079054 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 26 Apr 2009 21:59:22 -0600 Subject: [PATCH 022/172] fix CallEvent::popIndex calculation --- src/compiler.cpp | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/compiler.cpp b/src/compiler.cpp index 9df66d4b41..4e45b7e12a 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -2247,11 +2247,14 @@ clean(Context* c, Value* v, unsigned popIndex) (c, static_cast(s)->offset) >= popIndex)) { - if (false) { + if (false and + s->match(c, SiteMask(1 << MemoryOperand, 0, AnyFrameIndex))) + { char buffer[256]; s->toString(c, buffer, 256); - fprintf(stderr, "remove %s from %p at %d pop index %d\n", + fprintf(stderr, "remove %s from %p at %d pop offset 0x%x\n", buffer, v, offsetToFrameIndex - (c, static_cast(s)->offset), popIndex); + (c, static_cast(s)->offset), + frameIndexToOffset(c, popIndex)); } it.remove(c); } @@ -2425,25 +2428,20 @@ class CallEvent: public Event { } -- footprint; - - if (footprint == 0 and (flags & Compiler::TailJump) == 0) { - stackArgumentIndex = s->index + c->localFootprint; - } - ++ frameIndex; } if ((flags & Compiler::TailJump) == 0) { - if (stackArgumentFootprint == 0) { - stackArgumentIndex = (stackBefore ? stackBefore->index + 1 : 0) - + c->localFootprint; + stackArgumentIndex = c->localFootprint; + if (stackBefore) { + stackArgumentIndex += stackBefore->index + 1 - stackArgumentFootprint; } popIndex = c->alignedFrameSize + + c->parameterFootprint - c->arch->frameFooterSize() - - (stackBefore ? stackBefore->index + 1 - stackArgumentFootprint : 0) - - c->localFootprint; + - stackArgumentIndex; assert(c, static_cast(popIndex) >= 0); From 90dcf084a2445672788c21cb962bfb3f8af2580a Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 27 Apr 2009 14:46:43 +0000 Subject: [PATCH 023/172] protect object from GC in compileVirtualMethod2; condense frame GC root maps to minimum size needed --- src/compile.cpp | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index b87fa6724e..b2e5efccad 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -383,18 +383,6 @@ alignedFrameSize(MyThread* t, object method) + t->arch->frameFootprint(MaxNativeCallFootprint)); } -unsigned -usableFrameSize(MyThread* t, object method) -{ - return alignedFrameSize(t, method) - t->arch->frameFooterSize(); -} - -unsigned -usableFrameSizeWithParameters(MyThread* t, object method) -{ - return methodParameterFootprint(t, method) + usableFrameSize(t, method); -} - int localOffset(MyThread* t, int v, object method) { @@ -512,11 +500,16 @@ enum Event { TraceEvent }; +unsigned +frameMapSizeInBits(MyThread* t, object method) +{ + return localSize(t, method) + codeMaxStack(t, methodCode(t, method)); +} + unsigned frameMapSizeInWords(MyThread* t, object method) { - return ceiling(usableFrameSizeWithParameters(t, method), BitsPerWord) - * BytesPerWord; + return ceiling(frameMapSizeInBits(t, method), BitsPerWord) * BytesPerWord; } uint16_t* @@ -4221,7 +4214,7 @@ compareTraceElementPointers(const void* va, const void* vb) unsigned frameObjectMapSize(MyThread* t, object method, object map) { - int size = usableFrameSizeWithParameters(t, method); + int size = frameMapSizeInBits(t, method); return ceiling(intArrayLength(t, map) * size, 32 + size); } @@ -4347,7 +4340,7 @@ finish(MyThread* t, Allocator* allocator, Context* context) qsort(elements, context->traceLogCount, sizeof(TraceElement*), compareTraceElementPointers); - unsigned size = usableFrameSizeWithParameters(t, context->method); + unsigned size = frameMapSizeInBits(t, context->method); object map = makeIntArray (t, context->traceLogCount + ceiling(context->traceLogCount * size, 32)); @@ -4619,6 +4612,7 @@ compileVirtualMethod2(MyThread* t, object class_, unsigned index) PROTECT(t, class_); object target = resolveTarget(t, class_, index); + PROTECT(t, target); if (LIKELY(t->exception == 0)) { compile(t, codeAllocator(t), 0, target); @@ -4903,8 +4897,7 @@ frameMapIndex(MyThread* t, object method, int32_t offset) int32_t v = intArrayBody(t, map, middle); if (offset == v) { - return (indexSize * 32) - + (usableFrameSizeWithParameters(t, method) * middle); + return (indexSize * 32) + (frameMapSizeInBits(t, method) * middle); } else if (offset < v) { top = middle; } else { @@ -4919,7 +4912,7 @@ void visitStackAndLocals(MyThread* t, Heap::Visitor* v, void* frame, object method, void* ip) { - unsigned count = usableFrameSizeWithParameters(t, method); + unsigned count = frameMapSizeInBits(t, method); if (count) { object map = codePool(t, methodCode(t, method)); From 0cd4eb26553f7e3dbb424f1e9ce8d0247b9d91ad Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 3 May 2009 14:57:11 -0600 Subject: [PATCH 024/172] early sketch of continuation support --- src/assembler.h | 2 +- src/compile-x86.S | 74 ++++++- src/compile.cpp | 509 ++++++++++++++++++++++++++++++++++++---------- src/compiler.cpp | 226 +++++++++----------- src/compiler.h | 3 - src/interpret.cpp | 167 +++++++++------ src/machine.cpp | 21 +- src/machine.h | 18 +- src/process.cpp | 52 +++-- src/process.h | 30 ++- src/processor.h | 10 + src/types.def | 8 + src/x86.cpp | 2 +- 13 files changed, 765 insertions(+), 357 deletions(-) diff --git a/src/assembler.h b/src/assembler.h index 0b39a9461c..0bc97af8b8 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -258,7 +258,7 @@ class Assembler { virtual int thread() = 0; virtual int returnLow() = 0; virtual int returnHigh() = 0; - virtual int virtualCallClass() = 0; + virtual int virtualCallTarget() = 0; virtual int virtualCallIndex() = 0; virtual bool condensedAddressing() = 0; diff --git a/src/compile-x86.S b/src/compile-x86.S index e204a2ab51..58b370ae18 100644 --- a/src/compile-x86.S +++ b/src/compile-x86.S @@ -47,23 +47,70 @@ vmInvoke: // copy arguments into place movq $0,%r9 - jmp LOCAL(test) + jmp LOCAL(vmInvoke_argumentTest) -LOCAL(loop): +LOCAL(vmInvoke_argumentLoop): movq (%rdx,%r9,1),%r8 movq %r8,(%rsp,%r9,1) addq $8,%r9 -LOCAL(test): +LOCAL(vmInvoke_argumentTest): cmpq %rcx,%r9 - jb LOCAL(loop) + jb LOCAL(vmInvoke_argumentLoop) // call function call *%rsi +LOCAL(vmInvoke_returnAddress): // restore stack pointer movq %rbp,%rsp + + // call the next continuation frame, if any + movq THREAD_CONTINUATION(%rbx),%rcx + cmpq $0,%rcx + je LOCAL(vmInvoke_exit) + + movq CONTINUATION_SIZE(%rcx),%rsi + subq %rsi,%rsp + movq CONTINUATION_BODY(%rcx),%rdi + + movq $0,%r9 + jmp LOCAL(vmInvoke_continuationTest) + +LOCAL(vmInvoke_continuationLoop): + movq (%rdi,%r9,1),%r8 + movq %r8,(%rsp,%r9,1) + addq $8,%r9 + +LOCAL(vmInvoke_continuationTest): + cmpq %rsi,%r9 + jb LOCAL(vmInvoke_continuationLoop) + + movq CONTINUATION_RETURN_ADDRESS_OFFSET(%rcx),%rdi + movq LOCAL(vmInvoke_returnAddress),(%rsp,%rdi,1) + + movq CONTINUATION_FRAME_POINTER_OFFSET(%rcx),%rdi + movq %rbp,(%rsp,%rdi,1) + subq %rdi,%rbp + + movq CONTINUATION_NEXT(%rcx),%rdi + movq %rdi,THREAD_CONTINUATION(%rbx) + + // call the continuation unless we're handling an exception + movq THREAD_EXCEPTION(%rbx),%rsi + cmpq $0,%rsi + je *CONTINUATION_ADDRESS(%rcx) + + // we're handling an exception - call the exception handler instead + movq $0,THREAD_EXCEPTION(%rbx) + movq THREAD_EXCEPTION_STACK(%rbx),%rsp + movq THREAD_EXCEPTION_OFFSET(%rbx),%rdi + movq %rsi,(%rsp,%rdi,1) + + jmp *THREAD_EXCEPTION_HANDLER(%rbx) + +LOCAL(vmInvoke_exit): // restore callee-saved registers movq %rsp,%r9 subq $48,%r9 @@ -77,7 +124,24 @@ LOCAL(test): // return popq %rbp ret - + +.globl vmCallWithContinuation +vmCallWithContinuation: + // %rdi: thread + // %rsi: address + // %rdx: targetObject + // %rcx: continuation + // %r8 : base + // %r9 : stack + + movq %rdi,%rdx + movq %r8,%rbp + movq %r9,%rsp + movq LOCAL(vmInvoke_returnAddress),(%rsp) + movq %rcx,8(%rsp) + movq %rdx,16(%rsp) + jmp *%rsi + #elif defined __i386__ # if defined __APPLE__ || defined __MINGW32__ || defined __CYGWIN32__ diff --git a/src/compile.cpp b/src/compile.cpp index b2e5efccad..faa41d5fd5 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -27,7 +27,7 @@ vmCall(); namespace { -const bool DebugCompile = true; +const bool DebugCompile = false; const bool DebugNatives = false; const bool DebugCallTable = false; const bool DebugMethodTree = false; @@ -49,6 +49,7 @@ class MyThread: public Thread { t(t), base(t->base), stack(t->stack), + continuation(t->continuation), nativeMethod(0), targetMethod(0), next(t->trace) @@ -61,13 +62,14 @@ class MyThread: public Thread { ~CallTrace() { t->stack = stack; t->base = base; + t->continuation = continuation; t->trace = next; } MyThread* t; - void* ip; void* base; void* stack; + object continuation; object nativeMethod; object targetMethod; CallTrace* next; @@ -78,8 +80,12 @@ class MyThread: public Thread { ip(0), base(0), stack(0), + continuation(0), + exceptionStack(0), + exceptionOffset(0), + exceptionHandler(0), tailAddress(0), - virtualCallClass(0), + virtualCallTarget(0), virtualCallIndex(0), trace(0), reference(0), @@ -91,8 +97,12 @@ class MyThread: public Thread { void* ip; void* base; void* stack; + object continuation; + void* exceptionStack; + uintptr_t exceptionOffset; + void* exceptionHandler; void* tailAddress; - void* virtualCallClass; + void* virtualCallTarget; uintptr_t virtualCallIndex; CallTrace* trace; Reference* reference; @@ -110,7 +120,8 @@ parameterOffset(MyThread* t, object method) object resolveThisPointer(MyThread* t, void* stack, object method) { - return reinterpret_cast(stack)[parameterOffset(t, method)]; + return reinterpret_cast(stack) + [t->arch->frameFooterSize() + t->arch->frameReturnAddressSize()]; } object @@ -213,6 +224,7 @@ class MyStackWalker: public Processor::StackWalker { virtual void visit(Heap::Visitor* v) { v->visit(&(walker->method_)); + v->visit(&(walker->continuation)); } MyStackWalker* walker; @@ -226,6 +238,7 @@ class MyStackWalker: public Processor::StackWalker { stack(t->stack), trace(t->trace), method_(0), + continuation(t->continuation), protector(this) { } @@ -272,7 +285,10 @@ class MyStackWalker: public Processor::StackWalker { method_ = methodForIp(t, ip_); if (method_) { state = Method; + } else if (continuation) { + state = Continuation; } else if (trace) { + continuation = trace->continuation; stack = trace->stack; base = trace->base; ip_ = t->arch->frameIp(stack); @@ -290,6 +306,7 @@ class MyStackWalker: public Processor::StackWalker { } break; + case Continuation: case Method: case NativeMethod: return true; @@ -305,6 +322,10 @@ class MyStackWalker: public Processor::StackWalker { void next() { switch (state) { + case Continuation: + continuation = continuationNext(t, continuation); + break; + case Method: t->arch->nextFrame(&stack, &base); ip_ = t->arch->frameIp(stack); @@ -329,6 +350,10 @@ class MyStackWalker: public Processor::StackWalker { virtual int ip() { switch (state) { + case Continuation: + return continuationAddress(t, continuation) + - methodCompiled(t, continuationMethod(t, continuation)); + case Method: return reinterpret_cast(ip_) - methodCompiled(t, method_); @@ -358,6 +383,7 @@ class MyStackWalker: public Processor::StackWalker { void* stack; MyThread::CallTrace* trace; object method_; + object continuation; MyProtector protector; }; @@ -403,21 +429,30 @@ localOffset(MyThread* t, int v, object method) return offset; } +int +localOffsetFromStack(MyThread* t, int index, object method) +{ + return localOffset(t, index, method) + + (t->arch->frameReturnAddressSize() * BytesPerWord); +} + object* localObject(MyThread* t, void* stack, object method, unsigned index) { return reinterpret_cast - (static_cast(stack) - + localOffset(t, index, method) - + (t->arch->frameReturnAddressSize() * BytesPerWord)); + (static_cast(stack) + localOffsetFromStack(t, index, method)); +} + +int +stackOffsetFromFrame(MyThread* t, object method) +{ + return alignedFrameSize(t, method) + t->arch->frameHeaderSize(); } void* stackForFrame(MyThread* t, void* frame, object method) { - return static_cast(frame) - - alignedFrameSize(t, method) - - t->arch->frameHeaderSize(); + return static_cast(frame) - stackOffsetFromFrame(t, method); } class PoolElement: public Promise { @@ -684,6 +719,41 @@ class Context { MyProtector protector; }; +unsigned +translateLocalIndex(Context* context, unsigned footprint, unsigned index) +{ + unsigned parameterFootprint = methodParameterFootprint + (context->thread, context->method); + + if (index < parameterFootprint) { + return parameterFootprint - index - footprint; + } else { + return index; + } +} + +void +initLocal(Context* context, unsigned footprint, unsigned index) +{ + context->compiler->initLocal + (footprint, translateLocalIndex(context, footprint, index)); +} + +Compiler::Operand* +loadLocal(Context* context, unsigned footprint, unsigned index) +{ + return context->compiler->loadLocal + (footprint, translateLocalIndex(context, footprint, index)); +} + +void +storeLocal(Context* context, unsigned footprint, Compiler::Operand* value, + unsigned index) +{ + context->compiler->storeLocal + (footprint, value, translateLocalIndex(context, footprint, index)); +} + class Frame { public: enum StackType { @@ -1055,36 +1125,36 @@ class Frame { void loadInt(unsigned index) { assert(t, index < localSize()); - pushInt(c->loadLocal(1, index)); + pushInt(loadLocal(context, 1, index)); } void loadLong(unsigned index) { assert(t, index < static_cast(localSize() - 1)); - pushLong(c->loadLocal(2, index)); + pushLong(loadLocal(context, 2, index)); } void loadObject(unsigned index) { assert(t, index < localSize()); - pushObject(c->loadLocal(1, index)); + pushObject(loadLocal(context, 1, index)); } void storeInt(unsigned index) { - c->storeLocal(1, popInt(), index); + storeLocal(context, 1, popInt(), index); storedInt(index); } void storeLong(unsigned index) { - c->storeLocal(2, popLong(), index); + storeLocal(context, 2, popLong(), index); storedLong(index); } void storeObject(unsigned index) { - c->storeLocal(1, popObject(), index); + storeLocal(context, 1, popObject(), index); storedObject(index); } void storeObjectOrAddress(unsigned index) { - c->storeLocal(1, popQuiet(1), index); + storeLocal(context, 1, popQuiet(1), index); assert(t, sp >= 1); assert(t, sp - 1 >= localSize()); @@ -1261,22 +1331,25 @@ insertCallNode(MyThread* t, object node); void* findExceptionHandler(Thread* t, object method, void* ip) { - object table = codeExceptionHandlerTable(t, methodCode(t, method)); - if (table) { - object index = arrayBody(t, table, 0); + if (t->exception) { + object table = codeExceptionHandlerTable(t, methodCode(t, method)); + if (table) { + object index = arrayBody(t, table, 0); - uint8_t* compiled = reinterpret_cast(methodCompiled(t, method)); + uint8_t* compiled = reinterpret_cast + (methodCompiled(t, method)); - for (unsigned i = 0; i < arrayLength(t, table) - 1; ++i) { - unsigned start = intArrayBody(t, index, i * 3); - unsigned end = intArrayBody(t, index, (i * 3) + 1); - unsigned key = difference(ip, compiled) - 1; + for (unsigned i = 0; i < arrayLength(t, table) - 1; ++i) { + unsigned start = intArrayBody(t, index, i * 3); + unsigned end = intArrayBody(t, index, (i * 3) + 1); + unsigned key = difference(ip, compiled) - 1; - if (key >= start and key < end) { - object catchType = arrayBody(t, table, i + 1); + if (key >= start and key < end) { + object catchType = arrayBody(t, table, i + 1); - if (catchType == 0 or instanceOf(t, catchType, t->exception)) { - return compiled + intArrayBody(t, index, (i * 3) + 2); + if (catchType == 0 or instanceOf(t, catchType, t->exception)) { + return compiled + intArrayBody(t, index, (i * 3) + 2); + } } } } @@ -1285,6 +1358,23 @@ findExceptionHandler(Thread* t, object method, void* ip) return 0; } +void +releaseLock(MyThread* t, object method) +{ + if (methodFlags(t, method) & ACC_SYNCHRONIZED) { + object lock; + if (methodFlags(t, method) & ACC_STATIC) { + lock = methodClass(t, method); + } else { + lock = *localObject + (t, stackForFrame(t, stack, method), method, + savedTargetIndex(t, method)); + } + + release(t, lock); + } +} + void findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, void** targetStack) @@ -1323,19 +1413,98 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, t->arch->nextFrame(&stack, &base); ip = t->arch->frameIp(stack); - if (methodFlags(t, method) & ACC_SYNCHRONIZED) { - object lock; - if (methodFlags(t, method) & ACC_STATIC) { - lock = methodClass(t, method); - } else { - lock = *localObject - (t, stackForFrame(t, stack, method), method, - savedTargetIndex(t, method)); - } - - release(t, lock); - } + releaseLock(t, method); } + } else { + *targetIp = ip; + *targetBase = base; + *targetStack = static_cast(stack) + + t->arch->frameReturnAddressSize(); + + while (t->continuation) { + void* handler = findExceptionHandler + (t, continuationMethod(t, t->continuation), + continuationAddress(t, t->continuation)); + + if (handler) { + t->exceptionHandler = handler; + + t->exceptionStack = stackForFrame + (t, *targetStack, continuationMethod(t, t->continuation)); + + t->exceptionOffset = localOffset(t, localSize(t, method), method); + break; + } else { + releaseLock(t, continuationMethod(t, t->continuation)); + } + + t->continuation = continuationNext(t, t->continuation) + } + } + } +} + +object +makeCurrentContinuation(MyThread* t, void** targetIp, void** targetBase, + void** targetStack) +{ + void* ip = t->ip; + void* base = t->base; + void* stack = t->stack; + if (ip == 0) { + ip = t->arch->frameIp(stack); + } + + object target = t->trace->targetMethod; + PROTECT(t, target); + + object first = 0; + PROTECT(t, first); + + object last = 0; + PROTECT(t, last); + + *targetIp = 0; + while (*targetIp == 0) { + object method = methodForIp(t, ip); + if (method) { + PROTECT(t, method); + + void** top = static_cast(stack) - t->arch->frameHeader();; + unsigned argumentFootprint + = t->arch->argumentFootprint(methodParameterFootprint(t, target)); + unsigned alignment = t->arch->stackAlignmentInWords(); + if (argumentFootprint > alignment) { + top += argumentFootprint - alignment; + } + + t->arch->nextFrame(&stack, &base); + + void** bottom = static_cast(stack); + unsigned frameSize = bottom - top; + unsigned totalSize = frameSize + + t->arch->frameHeaderSize() + + t->arch->frameFooterSize() + + t->arch->argumentFootprint(methodParameterFootprint(t, method)); + + object c = makeContinuation + (t, 0, method, ip, + ((frameSize + t->arch->returnAddressOffset()) * BytesPerWord), + ((frameSize + t->arch->framePointerOffset()) * BytesPerWord), + totalSize); + + memcpy(&continuationBody(t, c, 0), top, totalSize * BytesPerWord); + + if (last) { + set(t, last, ContinuationNext, c); + } else { + first = c; + } + last = c; + + ip = t->arch->frameIp(stack); + + target = method; } else { *targetIp = ip; *targetBase = base; @@ -1343,6 +1512,11 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, + t->arch->frameReturnAddressSize(); } } + + expect(t, last); + set(t, last, ContinuationNext, t->continuation); + + return first; } void NO_RETURN @@ -2044,7 +2218,7 @@ handleMonitorEvent(MyThread* t, Frame* frame, intptr_t function) if (methodFlags(t, method) & ACC_STATIC) { lock = frame->append(methodClass(t, method)); } else { - lock = c->loadLocal(1, savedTargetIndex(t, method)); + lock = loadLocal(frame->context, 1, savedTargetIndex(t, method)); } c->call(c->constant(function), @@ -2063,11 +2237,9 @@ handleEntrance(MyThread* t, Frame* frame) if ((methodFlags(t, method) & (ACC_SYNCHRONIZED | ACC_STATIC)) == ACC_SYNCHRONIZED) { - Compiler* c = frame->c; - // save 'this' pointer in case it is overwritten. unsigned index = savedTargetIndex(t, method); - c->storeLocal(1, c->loadLocal(1, 0), index); + storeLocal(frame->context, 1, loadLocal(frame->context, 1, 0), index); frame->set(index, Frame::Object); } @@ -3080,7 +3252,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, int8_t count = codeBody(t, code, ip++); c->storeLocal - (1, c->add(4, c->constant(count), c->loadLocal(1, index)), index); + (1, c->add(4, c->constant(count), loadLocal(context, 1, index)), + index); } break; case iload: @@ -3217,21 +3390,16 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, bool tailCall = isTailCall(t, code, ip, context->method, target); - Compiler::Operand* classOperand = c->and_ - (BytesPerWord, c->constant(PointerMask), - c->memory(instance, 0, 0, 1)); - - c->freezeRegister(t->arch->virtualCallClass(), classOperand); - Compiler::Operand* result = c->stackCall - (c->memory(classOperand, offset, 0, 1), + (c->memory + (c->and_ + (BytesPerWord, c->constant(PointerMask), + c->memory(instance, 0, 0, 1)), offset, 0, 1), tailCall ? Compiler::TailJump : 0, frame->trace(0, 0), rSize, parameterFootprint); - c->thawRegister(t->arch->virtualCallClass()); - frame->pop(parameterFootprint); if (rSize) { @@ -3338,7 +3506,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, // wasn't already a live value there, which is something we // should verify once we have complete data flow information // (todo). - c->storeLocal(1, c->constant(0), index); + storeLocal(context, 1, c->constant(0), index); frame->storedObject(index); } @@ -3840,7 +4008,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } break; case ret: - c->jmp(c->loadLocal(1, codeBody(t, code, ip))); + c->jmp(loadLocal(context, 1, codeBody(t, code, ip))); c->endSubroutine(frame->subroutine); return; @@ -3940,7 +4108,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint16_t count = codeReadInt16(t, code, ip); c->storeLocal - (1, c->add(4, c->constant(count), c->loadLocal(1, index)), index); + (1, c->add(4, c->constant(count), loadLocal(context, 1, index)), + index); } break; case iload: { @@ -3960,7 +4129,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } break; case ret: - c->jmp(c->loadLocal(1, codeReadInt16(t, code, ip))); + c->jmp(loadLocal(context, 1, codeReadInt16(t, code, ip))); c->endSubroutine(frame->subroutine); return; @@ -4434,7 +4603,7 @@ compile(MyThread* t, Allocator* allocator, Context* context) unsigned index = 0; if ((methodFlags(t, context->method) & ACC_STATIC) == 0) { - c->initLocal(1, index); + initLocal(context, 1, index); frame.set(index++, Frame::Object); } @@ -4446,19 +4615,19 @@ compile(MyThread* t, Allocator* allocator, Context* context) switch (*it.next()) { case 'L': case '[': - c->initLocal(1, index); + initLocal(context, 1, index); frame.set(index++, Frame::Object); break; case 'J': case 'D': - c->initLocal(2, index); + initLocal(context, 2, index); frame.set(index++, Frame::Long); frame.set(index++, Frame::Long); break; default: - c->initLocal(1, index); + initLocal(context, 1, index); frame.set(index++, Frame::Integer); break; } @@ -4636,8 +4805,8 @@ compileVirtualMethod2(MyThread* t, object class_, unsigned index) uint64_t compileVirtualMethod(MyThread* t) { - object class_ = static_cast(t->virtualCallClass); - t->virtualCallClass = 0; + object class_ = objectClass(t, static_cast(t->virtualCallTarget)); + t->virtualCallTarget = 0; unsigned index = t->virtualCallIndex; t->virtualCallIndex = 0; @@ -4651,31 +4820,21 @@ compileVirtualMethod(MyThread* t) } } +inline uint64_t +invokeNativeFast(MyThread* t, object method) +{ + return reinterpret_cast(methodCompiled(t, method)) + (t, method, + static_cast(t->stack) + + t->arch->frameFooterSize() + + t->arch->frameReturnAddressSize()); +} + uint64_t -invokeNative2(MyThread* t, object method) +invokeNativeSlow(MyThread* t, object method) { PROTECT(t, method); - assert(t, methodFlags(t, method) & ACC_NATIVE); - - initClass(t, methodClass(t, method)); - if (UNLIKELY(t->exception)) return 0; - - if (methodCompiled(t, method) == defaultThunk(t)) { - void* function = resolveNativeMethod(t, method); - if (UNLIKELY(function == 0)) { - object message = makeString - (t, "%s.%s%s", - &byteArrayBody(t, className(t, methodClass(t, method)), 0), - &byteArrayBody(t, methodName(t, method), 0), - &byteArrayBody(t, methodSpec(t, method), 0)); - t->exception = makeUnsatisfiedLinkError(t, message); - return 0; - } - - methodCompiled(t, method) = reinterpret_cast(function); - } - object class_ = methodClass(t, method); PROTECT(t, class_); @@ -4694,12 +4853,13 @@ invokeNative2(MyThread* t, object method) types[typeOffset++] = POINTER_TYPE; uintptr_t* sp = static_cast(t->stack) - + parameterOffset(t, method); + + t->arch->frameFooterSize() + + t->arch->frameReturnAddressSize(); if (methodFlags(t, method) & ACC_STATIC) { args[argOffset++] = reinterpret_cast(&class_); } else { - args[argOffset++] = reinterpret_cast(sp--); + args[argOffset++] = reinterpret_cast(sp++); } types[typeOffset++] = POINTER_TYPE; @@ -4716,14 +4876,14 @@ invokeNative2(MyThread* t, object method) case INT16_TYPE: case INT32_TYPE: case FLOAT_TYPE: - args[argOffset++] = *(sp--); + args[argOffset++] = *(sp++); break; case INT64_TYPE: case DOUBLE_TYPE: { - memcpy(args + argOffset, sp - 1, 8); + memcpy(args + argOffset, sp, 8); argOffset += (8 / BytesPerWord); - sp -= 2; + sp += 2; } break; case POINTER_TYPE: { @@ -4732,7 +4892,7 @@ invokeNative2(MyThread* t, object method) } else { args[argOffset++] = 0; } - -- sp; + ++ sp; } break; default: abort(t); @@ -4842,6 +5002,16 @@ invokeNative2(MyThread* t, object method) return result; } + +uint64_t +invokeNative2(MyThread* t, object method) +{ + if (methodVmFlags(t, method) & FastNative) { + return invokeNativeFast(t, method); + } else { + return invokeNativeSlow(t, method); + } +} uint64_t invokeNative(MyThread* t) @@ -4870,7 +5040,11 @@ invokeNative(MyThread* t) t->trace->targetMethod = t->trace->nativeMethod; if (LIKELY(t->exception == 0)) { - result = invokeNative2(t, t->trace->nativeMethod); + resolveNative(t, t->trace->nativeMethod); + + if (LIKELY(t->exception == 0)) { + result = invokeNative2(t, t->trace->nativeMethod); + } } t->trace->targetMethod = 0; @@ -5019,6 +5193,61 @@ visitStack(MyThread* t, Heap::Visitor* v) } } +void +walkContinuationBody(MyThread* t, Heap::Walker* w, object c, int start) +{ + const int ContinuationReferenceCount = 3; + + int bodyStart = max(0, start - ContinuationReferenceCount); + + object method = t->m->heap->follow(continuationMethod(t, c)); + unsigned count = frameMapSizeInBits(t, method); + + if (count) { + object map = codePool(t, methodCode(t, method)); + int index = frameMapIndex + (t, method, difference + (continuationAddress(t, c), + reinterpret_cast(methodAddress(t, method)))); + + for (unsigned i = bodyStart; i < count; ++i) { + int j = index + i; + if ((intArrayBody(t, map, j / 32) + & (static_cast(1) << (j % 32)))) + { + if (not w->visit + ((continuationFramePointerOffset(t, c) / BytesPerWord) + - t->arch->framePointerOffset() + - stackOffsetFromFrame(t, method) + + localOffsetFromStack(c, i, method))) + { + return; + } + } + } + } +} + +void +callWithContinuation(MyThread* t, object method, object this_, + object continuation, void* base, void* stack) +{ + t->trace->targetMethod = 0; + + if (methodFlags(t, method) & ACC_NATIVE) { + t->trace->nativeMethod = method; + } else { + t->trace->nativeMethod = 0; + } + + vmCallWithContinuation + (t, methodAddress(t, method), this_, continuation, base, + static_cast(stack) + - t->arch->argumentFootprint(methodParameterFootprint(t, method)) + - t->arch->frameFooterSize() + - t->arch->returnAddressSize()); +} + class ArgumentList { public: ArgumentList(Thread* t, uintptr_t* array, unsigned size, bool* objectMask, @@ -5028,7 +5257,7 @@ class ArgumentList { array(array), objectMask(objectMask), size(size), - position(size), + position(0), protector(this) { if (this_) { @@ -5065,7 +5294,7 @@ class ArgumentList { array(array), objectMask(objectMask), size(size), - position(size), + position(0), protector(this) { if (this_) { @@ -5095,35 +5324,30 @@ class ArgumentList { } void addObject(object v) { - assert(t, position); + assert(t, position < size); - -- position; array[position] = reinterpret_cast(v); objectMask[position] = true; + ++ position; } void addInt(uintptr_t v) { - assert(t, position); + assert(t, position < size); - -- position; array[position] = v; objectMask[position] = false; + ++ position; } void addLong(uint64_t v) { - assert(t, position >= 2); + assert(t, position < size - 1); - position -= 2; - - if (BytesPerWord == 8) { - memcpy(array + position, &v, 8); - } else { - array[position] = v; - array[position + 1] = v >> 32; - } + memcpy(array + position, &v, 8); objectMask[position] = false; objectMask[position + 1] = false; + + position += 2; } MyThread* t; @@ -5378,10 +5602,13 @@ class MyProcessor: public Processor { } for (MyThread::CallTrace* trace = t->trace; trace; trace = trace->next) { + v->visit(&(trace->continuation)); v->visit(&(trace->nativeMethod)); v->visit(&(trace->targetMethod)); } + v->visit(&(t->continuation)); + for (Reference* r = t->reference; r; r = r->next) { v->visit(&(r->target)); } @@ -5677,6 +5904,53 @@ class MyProcessor: public Processor { expect(t, t->m->system->success (t->m->system->handleSegFault(&segFaultHandler))); } + + virtual void callWithCurrentContinuation(Thread* t, object method, + object this_) + { + object coninuation; + void* base; + void* stack; + + { PROTECT(t, method); + PROTECT(t, this_); + + compile(static_cast(t), + ::codeAllocator(static_cast(t)), 0, method); + + if (LIKELY(t->exception == 0)) { + void* ip; + continuation = makeCurrentContinuation + (static_cast(t), &ip, &base, &stack); + } + } + + if (LIKELY(t->exception == 0)) { + callWithContinuation(t, method, this_, continuation, base, stack); + } + } + + virtual void callContinuation(Thread* t, object continuation, object result) + { + assert(t, t->exception == 0); + + void* ip; + void* base; + void* stack; + findUnwindTarget(t, &ip, &base, &stack); + + t->trace->nativeMethod = 0; + t->trace->targetMethod = 0; + + t->continuation = continuation; + vmJump(ip, base, stack, t, result, 0); + } + + virtual void walkContinuationBody(Thread* t, Heap::Walker* w, object o, + unsigned start) + { + ::walkContinuationBody(static_cast(t), w, o, start); + } System* s; Allocator* allocator; @@ -6124,15 +6398,24 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, { Assembler* a = defaultVirtualContext.context.assembler; - Assembler::Register class_(t->arch->virtualCallClass()); - Assembler::Memory virtualCallClass - (t->arch->thread(), difference(&(t->virtualCallClass), t)); + Assembler::Register class_(t->arch->virtualCallTarget()); + Assembler::Memory virtualCallTargetSrc + (t->arch->stack(), + t->arch->frameFooterSize() + t->arch->returnAddressSize()); + + a->apply(Move, BytesPerWord, MemoryOperand, &virtualCallTargetSrc, + BytesPerWord, RegisterOperand, &class_); + + Assembler::Memory virtualCallTargetDst + (t->arch->thread(), difference(&(t->virtualCallTarget), t)); + a->apply(Move, BytesPerWord, RegisterOperand, &class_, - BytesPerWord, MemoryOperand, &virtualCallClass); + BytesPerWord, MemoryOperand, &virtualCallTargetDst); Assembler::Register index(t->arch->virtualCallIndex()); Assembler::Memory virtualCallIndex (t->arch->thread(), difference(&(t->virtualCallIndex), t)); + a->apply(Move, BytesPerWord, RegisterOperand, &index, BytesPerWord, MemoryOperand, &virtualCallIndex); diff --git a/src/compiler.cpp b/src/compiler.cpp index 4e45b7e12a..b65df7849a 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -2327,51 +2327,41 @@ class CallEvent: public Event { stackArgumentFootprint(stackArgumentFootprint) { uint32_t registerMask = ~0; - Stack* s = argumentStack; - unsigned index = 0; - unsigned frameIndex; - int returnAddressIndex = -1; - int framePointerIndex = -1; - if (flags & Compiler::TailJump) { - assert(c, argumentCount == 0); + if (argumentCount) { + assert(c, (flags & Compiler::TailJump) == 0); + assert(c, stackArgumentFootprint == 0); - int base = frameBase(c); - returnAddressIndex = base + c->arch->returnAddressOffset(); - framePointerIndex = base + c->arch->framePointerOffset(); + Stack* s = argumentStack; + unsigned frameIndex = 0; + unsigned index = 0; - frameIndex = totalFrameSize(c) - c->arch->argumentFootprint - (stackArgumentFootprint); - } else { - frameIndex = 0; - - if (argumentCount) { - while (true) { - Read* target; - if (index < c->arch->argumentRegisterCount()) { - int number = c->arch->argumentRegister(index); + while (true) { + Read* target; + if (index < c->arch->argumentRegisterCount()) { + int number = c->arch->argumentRegister(index); - if (DebugReads) { - fprintf(stderr, "reg %d arg read %p\n", number, s->value); - } - - target = fixedRegisterRead(c, number); - registerMask &= ~(1 << number); - } else { - if (DebugReads) { - fprintf(stderr, "stack %d arg read %p\n", frameIndex, s->value); - } - - target = read(c, SiteMask(1 << MemoryOperand, 0, frameIndex)); - ++ frameIndex; + if (DebugReads) { + fprintf(stderr, "reg %d arg read %p\n", number, s->value); } - addRead(c, this, s->value, target); - if ((++ index) < argumentCount) { - s = s->next; - } else { - break; + target = fixedRegisterRead(c, number); + registerMask &= ~(1 << number); + } else { + if (DebugReads) { + fprintf(stderr, "stack %d arg read %p\n", frameIndex, s->value); } + + target = read(c, SiteMask(1 << MemoryOperand, 0, frameIndex)); + ++ frameIndex; + } + + addRead(c, this, s->value, target); + + if ((++ index) < argumentCount) { + s = s->next; + } else { + break; } } } @@ -2394,41 +2384,53 @@ class CallEvent: public Event { (typeMask, registerMask & planRegisterMask, AnyFrameIndex))); } - int footprint = stackArgumentFootprint; - for (Stack* s = stackBefore; s; s = s->next) { - if (s->value) { - if (footprint > 0) { + Stack* stack = stackBefore; + + if (stackArgumentFootprint) { + int footprint = stackArgumentFootprint; + int returnAddressIndex; + int framePointerIndex; + int frameOffset; + + if (flags & Compiler::TailJump) { + assert(c, argumentCount == 0); + + int base = frameBase(c); + returnAddressIndex = base + c->arch->returnAddressOffset(); + framePointerIndex = base + c->arch->framePointerOffset(); + + frameOffset = totalFrameSize(c) + - c->arch->argumentFootprint(stackArgumentFootprint) - 1; + } else { + returnAddressIndex = -1; + framePointerIndex = -1; + frameOffset = -1; + } + + while (footprint > 0) { + if (stack->value) { + int frameIndex = footprint + frameOffset; + if (DebugReads) { fprintf(stderr, "stack arg read %p at %d of %d\n", - s->value, frameIndex, totalFrameSize(c)); + stack->value, frameIndex, totalFrameSize(c)); } if (static_cast(frameIndex) == returnAddressIndex) { - returnAddressSurrogate = s->value; - addRead(c, this, s->value, anyRegisterRead(c)); + returnAddressSurrogate = stack->value; + addRead(c, this, stack->value, anyRegisterRead(c)); } else if (static_cast(frameIndex) == framePointerIndex) { framePointerSurrogate = s->value; - addRead(c, this, s->value, anyRegisterRead(c)); + addRead(c, this, stack->value, anyRegisterRead(c)); } else { - addRead(c, this, s->value, read + addRead(c, this, stack->value, read (c, SiteMask(1 << MemoryOperand, 0, frameIndex))); } - } else if ((flags & Compiler::TailJump) == 0) { - unsigned logicalIndex = ::frameIndex - (c, s->index + c->localFootprint); - - if (DebugReads) { - fprintf(stderr, "stack save read %p at %d of %d\n", - s->value, logicalIndex, totalFrameSize(c)); - } - - addRead(c, this, s->value, read - (c, SiteMask(1 << MemoryOperand, 0, logicalIndex))); } - } - -- footprint; - ++ frameIndex; + stack = stack->next; + -- footprint; + } } if ((flags & Compiler::TailJump) == 0) { @@ -2445,6 +2447,23 @@ class CallEvent: public Event { assert(c, static_cast(popIndex) >= 0); + while (stack) { + if (stack->value) { + unsigned logicalIndex = ::frameIndex + (c, stack->index + c->localFootprint); + + if (DebugReads) { + fprintf(stderr, "stack save read %p at %d of %d\n", + stack->value, logicalIndex, totalFrameSize(c)); + } + + addRead(c, this, stack->value, read + (c, SiteMask(1 << MemoryOperand, 0, logicalIndex))); + } + + stack = stack->next; + } + saveLocals(c, this); } } @@ -3289,7 +3308,7 @@ push(Context* c, unsigned footprint, Value* v) Value* low = v; - if (bigEndian) { + if (not bigEndian) { v = pushWord(c, v); } @@ -3308,7 +3327,7 @@ push(Context* c, unsigned footprint, Value* v) high = 0; } - if (not bigEndian) { + if (bigEndian) { v = pushWord(c, v); } @@ -3341,7 +3360,7 @@ pop(Context* c, unsigned footprint) bool bigEndian = c->arch->bigEndian(); - if (not bigEndian) { + if (bigEndian) { s = c->stack; } @@ -3352,11 +3371,11 @@ pop(Context* c, unsigned footprint) Stack* low; Stack* high; if (bigEndian) { - high = c->stack; - low = high->next; - } else { low = c->stack; high = low->next; + } else { + high = c->stack; + low = high->next; } assert(c, low->value->high == high->value @@ -3366,7 +3385,7 @@ pop(Context* c, unsigned footprint) popWord(c); } - if (bigEndian) { + if (not bigEndian) { s = c->stack; } @@ -3997,61 +4016,6 @@ appendSaveLocals(Context* c) SaveLocalsEvent(c)); } -class FreezeRegisterEvent: public Event { - public: - FreezeRegisterEvent(Context* c, int number, Value* value): - Event(c), number(number), value(value) - { - addRead(c, this, value, fixedRegisterRead(c, number)); - } - - virtual const char* name() { - return "FreezeRegisterEvent"; - } - - virtual void compile(Context* c) { - c->registerResources[number].freeze(c, value); - - for (Read* r = reads; r; r = r->eventNext) { - popRead(c, this, r->value); - } - } - - int number; - Value* value; -}; - -void -appendFreezeRegister(Context* c, int number, Value* value) -{ - append(c, new (c->zone->allocate(sizeof(FreezeRegisterEvent))) - FreezeRegisterEvent(c, number, value)); -} - -class ThawRegisterEvent: public Event { - public: - ThawRegisterEvent(Context* c, int number): - Event(c), number(number) - { } - - virtual const char* name() { - return "ThawRegisterEvent"; - } - - virtual void compile(Context* c) { - c->registerResources[number].thaw(c, 0); - } - - int number; -}; - -void -appendThawRegister(Context* c, int number) -{ - append(c, new (c->zone->allocate(sizeof(ThawRegisterEvent))) - ThawRegisterEvent(c, number)); -} - class DummyEvent: public Event { public: DummyEvent(Context* c): @@ -5133,14 +5097,6 @@ class MyCompiler: public Compiler { return value(&c, s, s); } - virtual void freezeRegister(int number, Operand* value) { - appendFreezeRegister(&c, number, static_cast(value)); - } - - virtual void thawRegister(int number) { - appendThawRegister(&c, number); - } - Promise* machineIp() { return codePromise(&c, c.logicalCode[c.logicalIp]->lastEvent); } @@ -5230,18 +5186,18 @@ class MyCompiler: public Compiler { Stack* low; Stack* high; if (bigEndian) { - high = s; - low = s->next; - } else { low = s; high = s->next; + } else { + high = s; + low = s->next; } assert(&c, low->value->high == high->value and ((BytesPerWord == 8) xor (low->value->high != 0))); #endif // not NDEBUG - if (bigEndian) { + if (not bigEndian) { s = s->next; } } diff --git a/src/compiler.h b/src/compiler.h index 8e465e2857..2b60eb003b 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -67,9 +67,6 @@ class Compiler { virtual Operand* register_(int number) = 0; - virtual void freezeRegister(int number, Operand* value) = 0; - virtual void thawRegister(int number) = 0; - virtual void push(unsigned footprint) = 0; virtual void push(unsigned footprint, Operand* value) = 0; virtual void save(unsigned footprint, Operand* value) = 0; diff --git a/src/interpret.cpp b/src/interpret.cpp index f2e739fecf..e87b58beb8 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -460,7 +460,7 @@ makeNativeMethodData(Thread* t, object method, void* function) return data; } -inline object +inline void resolveNativeMethodData(Thread* t, object method) { if (methodCode(t, method) == 0) { @@ -479,9 +479,7 @@ resolveNativeMethodData(Thread* t, object method) t->exception = makeUnsatisfiedLinkError(t, message); return 0; } - } else { - return methodCode(t, method); - } + } } inline void @@ -498,16 +496,73 @@ checkStack(Thread* t, object method) } } +void +pushResult(Thread* t, unsigned returnCode, uint64_t result) +{ + switch (returnCode) { + case ByteField: + case BooleanField: + if (DebugRun) { + fprintf(stderr, "result: %d\n", static_cast(result)); + } + pushInt(t, static_cast(result)); + break; + + case CharField: + if (DebugRun) { + fprintf(stderr, "result: %d\n", static_cast(result)); + } + pushInt(t, static_cast(result)); + break; + + case ShortField: + if (DebugRun) { + fprintf(stderr, "result: %d\n", static_cast(result)); + } + pushInt(t, static_cast(result)); + break; + + case FloatField: + case IntField: + if (DebugRun) { + fprintf(stderr, "result: %d\n", static_cast(result)); + } + pushInt(t, result); + break; + + case LongField: + case DoubleField: + if (DebugRun) { + fprintf(stderr, "result: %"LLD"\n", result); + } + pushLong(t, result); + break; + + case ObjectField: + if (DebugRun) { + fprintf(stderr, "result: %p at %p\n", + static_cast(result) == 0 ? 0 : + *reinterpret_cast(static_cast(result)), + reinterpret_cast(static_cast(result))); + } + pushObject(t, static_cast(result) == 0 ? 0 : + *reinterpret_cast(static_cast(result))); + break; + + case VoidField: + break; + + default: + abort(t); + } +} + unsigned -invokeNative(Thread* t, object method) +invokeNativeSlow(Thread* t, object method) { PROTECT(t, method); - object data = resolveNativeMethodData(t, method); - if (UNLIKELY(t->exception)) { - return VoidField; - } - + object data = methodCode(t, method); PROTECT(t, data); pushFrame(t, method); @@ -609,66 +664,46 @@ invokeNative(Thread* t, object method) return VoidField; } - switch (returnCode) { - case ByteField: - case BooleanField: - if (DebugRun) { - fprintf(stderr, "result: %d\n", static_cast(result)); - } - pushInt(t, static_cast(result)); - break; - - case CharField: - if (DebugRun) { - fprintf(stderr, "result: %d\n", static_cast(result)); - } - pushInt(t, static_cast(result)); - break; - - case ShortField: - if (DebugRun) { - fprintf(stderr, "result: %d\n", static_cast(result)); - } - pushInt(t, static_cast(result)); - break; - - case FloatField: - case IntField: - if (DebugRun) { - fprintf(stderr, "result: %d\n", static_cast(result)); - } - pushInt(t, result); - break; - - case LongField: - case DoubleField: - if (DebugRun) { - fprintf(stderr, "result: %"LLD"\n", result); - } - pushLong(t, result); - break; - - case ObjectField: - if (DebugRun) { - fprintf(stderr, "result: %p at %p\n", - static_cast(result) == 0 ? 0 : - *reinterpret_cast(static_cast(result)), - reinterpret_cast(static_cast(result))); - } - pushObject(t, static_cast(result) == 0 ? 0 : - *reinterpret_cast(static_cast(result))); - break; - - case VoidField: - break; - - default: - abort(t); - } + pushResult(t, returnCode, result); return returnCode; } +unsigned +invokeNative(MyThread* t, object method) +{ + PROTECT(t, method); + + resolveNativeMethodData(t, method); + + if (UNLIKELY(t->exception)) { + return VoidField; + } + + if (methodVmFlags(t, method) & FastNative) { + pushFrame(t, method); + + uint64_t result = reinterpret_cast + (methodCompiled(t, method)) + (t, method, + static_cast(t->stack) + + t->arch->frameFooterSize() + + t->arch->frameReturnAddressSize()); + + popFrame(t); + + if (UNLIKELY(t->exception)) { + return VoidField; + } + + pushResult(t, methodReturnCode(t, method), result); + + return methodReturnCode(t, method); + } else { + return invokeNativeSlow(t, method); + } +} + bool classInit2(Thread* t, object class_, unsigned ipOffset) { diff --git a/src/machine.cpp b/src/machine.cpp index 353c78bcd6..98f8d484d1 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1544,9 +1544,12 @@ boot(Thread* t) m->unsafe = false; - classVmFlags(t, arrayBody(t, m->types, Machine::SingletonType)) + classFlags(t, arrayBody(t, m->types, Machine::SingletonType)) |= SingletonFlag; + classFlags(t, arrayBody(t, m->types, Machine::ContinuationType)) + |= ContinuationFlag; + classVmFlags(t, arrayBody(t, m->types, Machine::JreferenceType)) |= ReferenceFlag; classVmFlags(t, arrayBody(t, m->types, Machine::WeakReferenceType)) @@ -2754,6 +2757,8 @@ collect(Thread* t, Heap::CollectionType type) Machine* m = t->m; + m->continuationClass = arrayBody(t, t->m->types, Machine::ContinuationType); + m->unsafe = true; m->heap->collect(type, footprint(m->rootThread)); m->unsafe = false; @@ -2800,7 +2805,7 @@ walk(Thread* t, Heap::Walker* w, object o, unsigned start) intArrayLength(t, objectMask) * 4); ::walk(t, w, mask, fixedSize, arrayElementSize, arrayLength, start); - } else if (classVmFlags(t, class_) & SingletonFlag) { + } else if (classFlags(t, class_) & SingletonFlag) { unsigned length = singletonLength(t, o); if (length) { ::walk(t, w, singletonMask(t, o), @@ -2811,6 +2816,10 @@ walk(Thread* t, Heap::Walker* w, object o, unsigned start) } else if (start == 0) { w->visit(0); } + + if (classFlags(t, class_) & ContinuationFlag) { + t->m->processor->walkContinuationBody(t, w, o, start); + } } int @@ -2843,13 +2852,13 @@ visitRoots(Machine* m, Heap::Visitor* v) v->visit(&(m->types)); v->visit(&(m->jniMethodTable)); - for (Reference* r = m->jniReferences; r; r = r->next) { - v->visit(&(r->target)); - } - for (Thread* t = m->rootThread; t; t = t->peer) { ::visitRoots(t, v); } + + for (Reference* r = m->jniReferences; r; r = r->next) { + v->visit(&(r->target)); + } } void diff --git a/src/machine.h b/src/machine.h index 331c3bbc13..1018ae2aac 100644 --- a/src/machine.h +++ b/src/machine.h @@ -74,20 +74,26 @@ enum StackTag { const int NativeLine = -1; const int UnknownLine = -2; -// class flags: +// class flags (note that we must be careful not to overlap the +// standard ACC_* flags): +const unsigned SingletonFlag = 1 << 14; +const unsigned ContinuationFlag = 1 << 15; + +// class vmFlags: const unsigned ReferenceFlag = 1 << 0; const unsigned WeakReferenceFlag = 1 << 1; const unsigned NeedInitFlag = 1 << 2; const unsigned InitFlag = 1 << 3; const unsigned PrimitiveFlag = 1 << 4; -const unsigned SingletonFlag = 1 << 5; -const unsigned BootstrapFlag = 1 << 6; -const unsigned HasFinalMemberFlag = 1 << 7; +const unsigned BootstrapFlag = 1 << 5; +const unsigned HasFinalMemberFlag = 1 << 6; -// method flags: +// method vmFlags: const unsigned ClassInitFlag = 1 << 0; const unsigned CompiledFlag = 1 << 1; const unsigned ConstructorFlag = 1 << 2; +const unsigned NativeResolved = 1 << 3; +const unsigned FastNative = 1 << 4; typedef Machine JavaVM; typedef Thread JNIEnv; @@ -1320,6 +1326,8 @@ class Thread { #endif // VM_STRESS }; +typedef uint64_t (*FastNativeFunction)(Thread*, object, uintptr_t*) = 0; + inline object objectClass(Thread*, object o) { diff --git a/src/process.cpp b/src/process.cpp index c2693d0281..51bf3036bc 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -67,7 +67,7 @@ mangle(int8_t c, char* dst) unsigned jniNameLength(Thread* t, object method, bool decorate) { - unsigned size = 5; + unsigned size = 0; object className = ::className(t, methodClass(t, method)); for (unsigned i = 0; i < byteArrayLength(t, className) - 1; ++i) { @@ -96,10 +96,11 @@ jniNameLength(Thread* t, object method, bool decorate) } void -makeJNIName(Thread* t, char* name, object method, bool decorate) +makeJNIName(Thread* t, const char* prefix, unsigned prefixLength, char* name, + object method, bool decorate) { - memcpy(name, "Java_", 5); - name += 5; + memcpy(name, prefix, prefixLength); + name += prefixLength; object className = ::className(t, methodClass(t, method)); for (unsigned i = 0; i < byteArrayLength(t, className) - 1; ++i) { @@ -146,22 +147,19 @@ resolveNativeMethod(Thread* t, const char* undecorated, const char* decorated) return 0; } -} // namespace - -namespace vm { - void* -resolveNativeMethod2(Thread* t, object method) +resolveNativeMethod(Thread* t, object method, const char* prefix, + unsigned prefixLength) { - unsigned undecoratedSize = jniNameLength(t, method, false); + unsigned undecoratedSize = prefixLength + jniNameLength(t, method, false); char undecorated[undecoratedSize + 1 + 6]; // extra 6 is for code below - makeJNIName(t, undecorated + 1, method, false); + makeJNIName(t, prefix, prefixLength, undecorated + 1, method, false); - unsigned decoratedSize = jniNameLength(t, method, true); + unsigned decoratedSize = prefixLength + jniNameLength(t, method, true); char decorated[decoratedSize + 1 + 6]; // extra 6 is for code below - makeJNIName(t, decorated + 1, method, true); + makeJNIName(t, prefix, prefixLength, decorated + 1, method, true); - void* p = ::resolveNativeMethod(t, undecorated + 1, decorated + 1); + void* p = resolveNativeMethod(t, undecorated + 1, decorated + 1); if (p) { return p; } @@ -181,13 +179,13 @@ resolveNativeMethod2(Thread* t, object method) snprintf(decorated + decoratedSize + 1, 5, "@%d", footprint * BytesPerWord); - p = ::resolveNativeMethod(t, undecorated, decorated); + p = resolveNativeMethod(t, undecorated, decorated); if (p) { return p; } // one more try without the leading underscore - p = ::resolveNativeMethod(t, undecorated + 1, decorated + 1); + p = resolveNativeMethod(t, undecorated + 1, decorated + 1); if (p) { return p; } @@ -196,6 +194,28 @@ resolveNativeMethod2(Thread* t, object method) return 0; } +} // namespace + +namespace vm { + +void* +resolveNativeMethod2(Thread* t, object method) +{ + void* p = ::resolveNativeMethod(t, method, "Java_", 5); + if (p) { + methodVmFlags(t, method) |= NativeResolved; + return p; + } + + p = ::resolveNativeMethod(t, method, "Avian_", 6); + if (p) { + methodVmFlags(t, method) |= NativeResolved & FastNative; + return p; + } + + return 0; +} + int findLineNumber(Thread* t, object method, unsigned ip) { diff --git a/src/process.h b/src/process.h index 8cbacf48b5..ac7e052413 100644 --- a/src/process.h +++ b/src/process.h @@ -128,13 +128,31 @@ isSpecialMethod(Thread* t, object method, object class_) void* resolveNativeMethod2(Thread* t, object method); -inline void* -resolveNativeMethod(Thread* t, object method) +inline void +resolveNativeMethod(MyThread* t, object method) { - if (methodCode(t, method)) { - return pointerValue(t, methodCode(t, method)); - } else { - return resolveNativeMethod2(t, method); + PROTECT(t, method); + + assert(t, methodFlags(t, method) & ACC_NATIVE); + + initClass(t, methodClass(t, method)); + if (UNLIKELY(t->exception)) return 0; + + unsigned flags = methodVmFlags(t, method); + uintptr_t address = methodCompiled(t, method); + if ((flags & NativeResolved) == 0 or address == defaultThunk(t)) { + void* function = resolveNativeMethod2(t, method); + if (UNLIKELY(function == 0)) { + object message = makeString + (t, "%s.%s%s", + &byteArrayBody(t, className(t, methodClass(t, method)), 0), + &byteArrayBody(t, methodName(t, method), 0), + &byteArrayBody(t, methodSpec(t, method), 0)); + t->exception = makeUnsatisfiedLinkError(t, message); + return; + } + + methodCompiled(t, method) = reinterpret_cast(function); } } diff --git a/src/processor.h b/src/processor.h index 3724b2c96d..5f7b7ba00b 100644 --- a/src/processor.h +++ b/src/processor.h @@ -133,6 +133,16 @@ class Processor { virtual void boot(Thread* t, BootImage* image) = 0; + virtual void + callWithCurrentContinuation(Thread* t, object method, object this_) = 0; + + virtual void + callContinuation(Thread* t, object continuation, object result) = 0; + + virtual void + walkContiuationBody(Thread* t, Heap::Walker* w, object o, unsigned start) + = 0; + object invoke(Thread* t, object method, object this_, ...) { diff --git a/src/types.def b/src/types.def index 6dd1bc6092..c242a9b86c 100644 --- a/src/types.def +++ b/src/types.def @@ -103,6 +103,14 @@ (type array (noassert array object body)) +(type continuation + (object next) + (object method) + (void* address) + (uintptr_t returnAddressOffset) + (uintptr_t framePointerOffset) + (array uintptr_t body)) + (type string java/lang/String) (type thread java/lang/Thread) diff --git a/src/x86.cpp b/src/x86.cpp index 8bdd62e4e5..1e67528648 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -2034,7 +2034,7 @@ class MyArchitecture: public Assembler::Architecture { return (BytesPerWord == 4 ? rdx : NoRegister); } - virtual int virtualCallClass() { + virtual int virtualCallTarget() { return rax; } From eb3bd25aa19d793ab1636bce2c2b412feb315a03 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 4 May 2009 19:04:17 -0600 Subject: [PATCH 025/172] code cleanup and build fixes --- src/arch.h | 3 +- src/compile-x86.S | 28 +++++++++++--- src/compile.cpp | 99 +++++++++++++++++++++++++++++++++++------------ src/compiler.cpp | 2 +- src/interpret.cpp | 6 +++ src/machine.cpp | 2 - src/machine.h | 5 +-- src/posix.cpp | 2 +- src/process.cpp | 5 +-- src/process.h | 30 +------------- src/processor.h | 2 +- src/x86.S | 2 + 12 files changed, 116 insertions(+), 70 deletions(-) diff --git a/src/arch.h b/src/arch.h index ae613297b6..ae2039296f 100644 --- a/src/arch.h +++ b/src/arch.h @@ -14,7 +14,8 @@ #include "common.h" extern "C" void NO_RETURN -vmJump(void* address, void* base, void* stack, void* thread); +vmJump(void* address, void* base, void* stack, void* thread, + uintptr_t returnLow, uintptr_t returnHigh); #if (defined __i386__) || (defined __x86_64__) # include "x86.h" diff --git a/src/compile-x86.S b/src/compile-x86.S index 58b370ae18..456acc2228 100644 --- a/src/compile-x86.S +++ b/src/compile-x86.S @@ -15,6 +15,19 @@ .text #ifdef __x86_64__ + +#define THREAD_CONTINUATION 168 +#define THREAD_EXCEPTION 64 +#define THREAD_EXCEPTION_STACK 176 +#define THREAD_EXCEPTION_OFFSET 184 +#define THREAD_EXCEPTION_HANDLER 192 + +#define CONTINUATION_NEXT 8 +#define CONTINUATION_ADDRESS 24 +#define CONTINUATION_RETURN_ADDRESS_OFFSET 32 +#define CONTINUATION_FRAME_POINTER_OFFSET 40 +#define CONTINUATION_LENGTH 48 +#define CONTINUATION_BODY 56 .globl vmInvoke vmInvoke: @@ -65,12 +78,13 @@ LOCAL(vmInvoke_returnAddress): // restore stack pointer movq %rbp,%rsp - // call the next continuation frame, if any + // call the next continuation, if any movq THREAD_CONTINUATION(%rbx),%rcx cmpq $0,%rcx je LOCAL(vmInvoke_exit) - movq CONTINUATION_SIZE(%rcx),%rsi + movq CONTINUATION_LENGTH(%rcx),%rsi + shrq $3,%rsi subq %rsi,%rsp movq CONTINUATION_BODY(%rcx),%rdi @@ -88,7 +102,8 @@ LOCAL(vmInvoke_continuationTest): jb LOCAL(vmInvoke_continuationLoop) movq CONTINUATION_RETURN_ADDRESS_OFFSET(%rcx),%rdi - movq LOCAL(vmInvoke_returnAddress),(%rsp,%rdi,1) + movq LOCAL(vmInvoke_returnAddress)@GOTPCREL(%rip),%r10 + movq %r10,(%rsp,%rdi,1) movq CONTINUATION_FRAME_POINTER_OFFSET(%rcx),%rdi movq %rbp,(%rsp,%rdi,1) @@ -100,8 +115,10 @@ LOCAL(vmInvoke_continuationTest): // call the continuation unless we're handling an exception movq THREAD_EXCEPTION(%rbx),%rsi cmpq $0,%rsi - je *CONTINUATION_ADDRESS(%rcx) + jne LOCAL(vmInvoke_handleException) + jmp *CONTINUATION_ADDRESS(%rcx) +LOCAL(vmInvoke_handleException): // we're handling an exception - call the exception handler instead movq $0,THREAD_EXCEPTION(%rbx) movq THREAD_EXCEPTION_STACK(%rbx),%rsp @@ -137,7 +154,8 @@ vmCallWithContinuation: movq %rdi,%rdx movq %r8,%rbp movq %r9,%rsp - movq LOCAL(vmInvoke_returnAddress),(%rsp) + movq LOCAL(vmInvoke_returnAddress)@GOTPCREL(%rip),%r10 + movq %r10,(%rsp) movq %rcx,8(%rsp) movq %rdx,16(%rsp) jmp *%rsi diff --git a/src/compile.cpp b/src/compile.cpp index faa41d5fd5..13ad7ee73b 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -22,6 +22,10 @@ extern "C" uint64_t vmInvoke(void* thread, void* function, void* arguments, unsigned argumentFootprint, unsigned frameSize, unsigned returnType); +extern "C" uint64_t +vmCallWithContinuation(void* thread, void* function, void* targetObject, + object continuation, void* base, void* stack); + extern "C" void vmCall(); @@ -118,7 +122,7 @@ parameterOffset(MyThread* t, object method) } object -resolveThisPointer(MyThread* t, void* stack, object method) +resolveThisPointer(MyThread* t, void* stack) { return reinterpret_cast(stack) [t->arch->frameFooterSize() + t->arch->frameReturnAddressSize()]; @@ -127,7 +131,7 @@ resolveThisPointer(MyThread* t, void* stack, object method) object resolveTarget(MyThread* t, void* stack, object method) { - object class_ = objectClass(t, resolveThisPointer(t, stack, method)); + object class_ = objectClass(t, resolveThisPointer(t, stack)); if (classVmFlags(t, class_) & BootstrapFlag) { PROTECT(t, method); @@ -211,6 +215,7 @@ class MyStackWalker: public Processor::StackWalker { enum State { Start, Next, + Continuation, Method, NativeMethod, Finish @@ -351,7 +356,7 @@ class MyStackWalker: public Processor::StackWalker { virtual int ip() { switch (state) { case Continuation: - return continuationAddress(t, continuation) + return reinterpret_cast(continuationAddress(t, continuation)) - methodCompiled(t, continuationMethod(t, continuation)); case Method: @@ -1359,7 +1364,7 @@ findExceptionHandler(Thread* t, object method, void* ip) } void -releaseLock(MyThread* t, object method) +releaseLock(MyThread* t, object method, void* stack) { if (methodFlags(t, method) & ACC_SYNCHRONIZED) { object lock; @@ -1413,7 +1418,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, t->arch->nextFrame(&stack, &base); ip = t->arch->frameIp(stack); - releaseLock(t, method); + releaseLock(t, method, stack); } } else { *targetIp = ip; @@ -1430,15 +1435,19 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, t->exceptionHandler = handler; t->exceptionStack = stackForFrame - (t, *targetStack, continuationMethod(t, t->continuation)); + (t, stack, continuationMethod(t, t->continuation)); t->exceptionOffset = localOffset(t, localSize(t, method), method); break; } else { - releaseLock(t, continuationMethod(t, t->continuation)); + releaseLock(t, continuationMethod(t, t->continuation), + reinterpret_cast(t->continuation) + + ContinuationBody + + continuationReturnAddressOffset(t, t->continuation) + -t->arch->returnAddressOffset()); } - t->continuation = continuationNext(t, t->continuation) + t->continuation = continuationNext(t, t->continuation); } } } @@ -1470,7 +1479,7 @@ makeCurrentContinuation(MyThread* t, void** targetIp, void** targetBase, if (method) { PROTECT(t, method); - void** top = static_cast(stack) - t->arch->frameHeader();; + void** top = static_cast(stack) - t->arch->frameHeaderSize(); unsigned argumentFootprint = t->arch->argumentFootprint(methodParameterFootprint(t, target)); unsigned alignment = t->arch->stackAlignmentInWords(); @@ -1526,7 +1535,7 @@ unwind(MyThread* t) void* base; void* stack; findUnwindTarget(t, &ip, &base, &stack); - vmJump(ip, base, stack, t); + vmJump(ip, base, stack, t, 0, 0); } object& @@ -4820,7 +4829,40 @@ compileVirtualMethod(MyThread* t) } } -inline uint64_t +void +resolveNative(MyThread* t, object method) +{ + PROTECT(t, method); + + assert(t, methodFlags(t, method) & ACC_NATIVE); + + initClass(t, methodClass(t, method)); + + if (LIKELY(t->exception == 0) + and methodCompiled(t, method) == defaultThunk(t)) + { + void* function = resolveNativeMethod(t, method); + if (UNLIKELY(function == 0)) { + object message = makeString + (t, "%s.%s%s", + &byteArrayBody(t, className(t, methodClass(t, method)), 0), + &byteArrayBody(t, methodName(t, method), 0), + &byteArrayBody(t, methodSpec(t, method), 0)); + t->exception = makeUnsatisfiedLinkError(t, message); + return; + } + + // ensure other threads see updated methodVmFlags before + // methodCompiled, since we don't want them using the slow calling + // convention on a function that expects the fast calling + // convention: + memoryBarrier(); + + methodCompiled(t, method) = reinterpret_cast(function); + } +} + +uint64_t invokeNativeFast(MyThread* t, object method) { return reinterpret_cast(methodCompiled(t, method)) @@ -5200,7 +5242,8 @@ walkContinuationBody(MyThread* t, Heap::Walker* w, object c, int start) int bodyStart = max(0, start - ContinuationReferenceCount); - object method = t->m->heap->follow(continuationMethod(t, c)); + object method = static_cast + (t->m->heap->follow(continuationMethod(t, c))); unsigned count = frameMapSizeInBits(t, method); if (count) { @@ -5219,7 +5262,7 @@ walkContinuationBody(MyThread* t, Heap::Walker* w, object c, int start) ((continuationFramePointerOffset(t, c) / BytesPerWord) - t->arch->framePointerOffset() - stackOffsetFromFrame(t, method) - + localOffsetFromStack(c, i, method))) + + localOffsetFromStack(t, i, method))) { return; } @@ -5241,11 +5284,14 @@ callWithContinuation(MyThread* t, object method, object this_, } vmCallWithContinuation - (t, methodAddress(t, method), this_, continuation, base, + (t, reinterpret_cast(methodAddress(t, method)), + this_, + continuation, + base, static_cast(stack) - t->arch->argumentFootprint(methodParameterFootprint(t, method)) - t->arch->frameFooterSize() - - t->arch->returnAddressSize()); + - t->arch->frameReturnAddressSize()); } class ArgumentList { @@ -5516,6 +5562,7 @@ class MyProcessor: public Processor { MyThread* t = new (m->heap->allocate(sizeof(MyThread))) MyThread(m, javaThread, static_cast(parent)); t->init(); + return t; } @@ -5905,23 +5952,23 @@ class MyProcessor: public Processor { (t->m->system->handleSegFault(&segFaultHandler))); } - virtual void callWithCurrentContinuation(Thread* t, object method, + virtual void callWithCurrentContinuation(Thread* vmt, object method, object this_) { - object coninuation; + MyThread* t = static_cast(vmt); + + object continuation; void* base; void* stack; { PROTECT(t, method); PROTECT(t, this_); - compile(static_cast(t), - ::codeAllocator(static_cast(t)), 0, method); + compile(t, ::codeAllocator(t), 0, method); if (LIKELY(t->exception == 0)) { void* ip; - continuation = makeCurrentContinuation - (static_cast(t), &ip, &base, &stack); + continuation = makeCurrentContinuation(t, &ip, &base, &stack); } } @@ -5930,8 +5977,11 @@ class MyProcessor: public Processor { } } - virtual void callContinuation(Thread* t, object continuation, object result) + virtual void callContinuation(Thread* vmt, object continuation, + object result) { + MyThread* t = static_cast(vmt); + assert(t, t->exception == 0); void* ip; @@ -5943,7 +5993,8 @@ class MyProcessor: public Processor { t->trace->targetMethod = 0; t->continuation = continuation; - vmJump(ip, base, stack, t, result, 0); + + vmJump(ip, base, stack, t, reinterpret_cast(result), 0); } virtual void walkContinuationBody(Thread* t, Heap::Walker* w, object o, @@ -6401,7 +6452,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, Assembler::Register class_(t->arch->virtualCallTarget()); Assembler::Memory virtualCallTargetSrc (t->arch->stack(), - t->arch->frameFooterSize() + t->arch->returnAddressSize()); + t->arch->frameFooterSize() + t->arch->frameReturnAddressSize()); a->apply(Move, BytesPerWord, MemoryOperand, &virtualCallTargetSrc, BytesPerWord, RegisterOperand, &class_); diff --git a/src/compiler.cpp b/src/compiler.cpp index b65df7849a..249f247f2a 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -2420,7 +2420,7 @@ class CallEvent: public Event { returnAddressSurrogate = stack->value; addRead(c, this, stack->value, anyRegisterRead(c)); } else if (static_cast(frameIndex) == framePointerIndex) { - framePointerSurrogate = s->value; + framePointerSurrogate = stack->value; addRead(c, this, stack->value, anyRegisterRead(c)); } else { addRead(c, this, stack->value, read diff --git a/src/interpret.cpp b/src/interpret.cpp index e87b58beb8..fcc2621d90 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -468,6 +468,12 @@ resolveNativeMethodData(Thread* t, object method) if (LIKELY(p)) { PROTECT(t, method); object data = makeNativeMethodData(t, method, p); + + // ensure other threads see updated methodVmFlags before + // methodCode, and that the native method data is initialized + // before it is visible to those threads: + memoryBarrier(); + set(t, method, MethodCode, data); return data; } else { diff --git a/src/machine.cpp b/src/machine.cpp index 98f8d484d1..b4c877f4da 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -2757,8 +2757,6 @@ collect(Thread* t, Heap::CollectionType type) Machine* m = t->m; - m->continuationClass = arrayBody(t, t->m->types, Machine::ContinuationType); - m->unsafe = true; m->heap->collect(type, footprint(m->rootThread)); m->unsafe = false; diff --git a/src/machine.h b/src/machine.h index 1018ae2aac..c20ef8521e 100644 --- a/src/machine.h +++ b/src/machine.h @@ -92,8 +92,7 @@ const unsigned HasFinalMemberFlag = 1 << 6; const unsigned ClassInitFlag = 1 << 0; const unsigned CompiledFlag = 1 << 1; const unsigned ConstructorFlag = 1 << 2; -const unsigned NativeResolved = 1 << 3; -const unsigned FastNative = 1 << 4; +const unsigned FastNative = 1 << 3; typedef Machine JavaVM; typedef Thread JNIEnv; @@ -1326,7 +1325,7 @@ class Thread { #endif // VM_STRESS }; -typedef uint64_t (*FastNativeFunction)(Thread*, object, uintptr_t*) = 0; +typedef uint64_t (*FastNativeFunction)(Thread*, object, uintptr_t*); inline object objectClass(Thread*, object o) diff --git a/src/posix.cpp b/src/posix.cpp index 9d5e112773..b2b3800eee 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -831,7 +831,7 @@ handleSignal(int signal, siginfo_t* info, void* context) sigaddset(&set, SegFaultSignal); sigprocmask(SIG_UNBLOCK, &set, 0); - vmJump(ip, base, stack, thread); + vmJump(ip, base, stack, thread, 0, 0); } } break; diff --git a/src/process.cpp b/src/process.cpp index 51bf3036bc..83418a969c 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -199,17 +199,16 @@ resolveNativeMethod(Thread* t, object method, const char* prefix, namespace vm { void* -resolveNativeMethod2(Thread* t, object method) +resolveNativeMethod(Thread* t, object method) { void* p = ::resolveNativeMethod(t, method, "Java_", 5); if (p) { - methodVmFlags(t, method) |= NativeResolved; return p; } p = ::resolveNativeMethod(t, method, "Avian_", 6); if (p) { - methodVmFlags(t, method) |= NativeResolved & FastNative; + methodVmFlags(t, method) |= FastNative; return p; } diff --git a/src/process.h b/src/process.h index ac7e052413..ad58e22c67 100644 --- a/src/process.h +++ b/src/process.h @@ -126,35 +126,7 @@ isSpecialMethod(Thread* t, object method, object class_) } void* -resolveNativeMethod2(Thread* t, object method); - -inline void -resolveNativeMethod(MyThread* t, object method) -{ - PROTECT(t, method); - - assert(t, methodFlags(t, method) & ACC_NATIVE); - - initClass(t, methodClass(t, method)); - if (UNLIKELY(t->exception)) return 0; - - unsigned flags = methodVmFlags(t, method); - uintptr_t address = methodCompiled(t, method); - if ((flags & NativeResolved) == 0 or address == defaultThunk(t)) { - void* function = resolveNativeMethod2(t, method); - if (UNLIKELY(function == 0)) { - object message = makeString - (t, "%s.%s%s", - &byteArrayBody(t, className(t, methodClass(t, method)), 0), - &byteArrayBody(t, methodName(t, method), 0), - &byteArrayBody(t, methodSpec(t, method), 0)); - t->exception = makeUnsatisfiedLinkError(t, message); - return; - } - - methodCompiled(t, method) = reinterpret_cast(function); - } -} +resolveNativeMethod(Thread* t, object method); inline object findInterfaceMethod(Thread* t, object method, object class_) diff --git a/src/processor.h b/src/processor.h index 5f7b7ba00b..a24a6197d0 100644 --- a/src/processor.h +++ b/src/processor.h @@ -140,7 +140,7 @@ class Processor { callContinuation(Thread* t, object continuation, object result) = 0; virtual void - walkContiuationBody(Thread* t, Heap::Walker* w, object o, unsigned start) + walkContinuationBody(Thread* t, Heap::Walker* w, object o, unsigned start) = 0; object diff --git a/src/x86.S b/src/x86.S index a4f873f48d..3740a21f41 100644 --- a/src/x86.S +++ b/src/x86.S @@ -115,6 +115,8 @@ LOCAL(exit): .globl vmJump vmJump: + movq %r8,%rax + movq %r9,%rdx movq %rsi,%rbp movq %rdx,%rsp movq %rcx,%rbx From 66c4867f185148dc8eea7437a5cfec1fd6c1ad5a Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 5 May 2009 18:29:05 -0600 Subject: [PATCH 026/172] more work on continuation support --- classpath/avian/Callback.java | 16 +++++ classpath/avian/CallbackReceiver.java | 15 +++++ classpath/avian/Continuations.java | 27 ++++++++ classpath/java/util/concurrent/Callable.java | 15 +++++ src/builtin.cpp | 35 ++++++++++ src/compile.cpp | 67 ++++++++++++++++---- src/processor.h | 8 ++- src/type-generator.cpp | 32 ++++------ src/types.def | 7 +- 9 files changed, 189 insertions(+), 33 deletions(-) create mode 100644 classpath/avian/Callback.java create mode 100644 classpath/avian/CallbackReceiver.java create mode 100644 classpath/avian/Continuations.java create mode 100644 classpath/java/util/concurrent/Callable.java diff --git a/classpath/avian/Callback.java b/classpath/avian/Callback.java new file mode 100644 index 0000000000..25889f3b2c --- /dev/null +++ b/classpath/avian/Callback.java @@ -0,0 +1,16 @@ +/* Copyright (c) 2009, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package avian; + +public interface Callback { + public void handleResult(T result); + public void handleException(Throwable exception); +} diff --git a/classpath/avian/CallbackReceiver.java b/classpath/avian/CallbackReceiver.java new file mode 100644 index 0000000000..c36b1416bd --- /dev/null +++ b/classpath/avian/CallbackReceiver.java @@ -0,0 +1,15 @@ +/* Copyright (c) 2009, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package avian; + +public interface CallbackReceiver { + public T receive(Callback callback) throws Exception; +} diff --git a/classpath/avian/Continuations.java b/classpath/avian/Continuations.java new file mode 100644 index 0000000000..948b8b0bec --- /dev/null +++ b/classpath/avian/Continuations.java @@ -0,0 +1,27 @@ +/* Copyright (c) 2009, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package avian; + +import java.util.concurrent.Callable; + +public abstract class Continuations { + public static native T callWithCurrentContinuation + (CallbackReceiver receiver) throws Exception; + + public static native T dynamicWind(Runnable before, + Callable thunk, + Runnable after) throws Exception; + + private static class Continuation implements Callback { + public native void handleResult(T result); + public native void handleException(Throwable exception); + } +} diff --git a/classpath/java/util/concurrent/Callable.java b/classpath/java/util/concurrent/Callable.java new file mode 100644 index 0000000000..f0ad3be39e --- /dev/null +++ b/classpath/java/util/concurrent/Callable.java @@ -0,0 +1,15 @@ +/* Copyright (c) 2009, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.util.concurrent; + +public interface Callable { + public T call() throws Exception; +} diff --git a/src/builtin.cpp b/src/builtin.cpp index cf48ee58ef..9d45707a94 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -847,3 +847,38 @@ Java_java_net_URL_00024ResourceInputStream_close(Thread*, jclass, jlong peer) { reinterpret_cast(peer)->dispose(); } + +extern "C" JNIEXPORT void JNICALL +Avian_avian_Continuations_callWithCurrentContinuation(Thread* t, + object, + uintptr_t* arguments) +{ + t->m->processor->callWithCurrentContinuation + (t, reinterpret_cast(*arguments)); + + abort(t); +} + +extern "C" JNIEXPORT void JNICALL +Avian_avian_Continuation_handleResult(Thread* t, + object, + uintptr_t* arguments) +{ + t->m->processor->feedResultToContinuation + (t, reinterpret_cast(arguments[0]), + reinterpret_cast(arguments[1])); + + abort(t); +} + +extern "C" JNIEXPORT void JNICALL +Avian_avian_Continuation_handleException(Thread* t, + object, + uintptr_t* arguments) +{ + t->m->processor->feedExceptionToContinuation + (t, reinterpret_cast(arguments[0]), + reinterpret_cast(arguments[1])); + + abort(t); +} diff --git a/src/compile.cpp b/src/compile.cpp index 13ad7ee73b..b142d23bd3 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -5553,6 +5553,7 @@ class MyProcessor: public Processor { objectPools(0), staticTableArray(0), virtualThunks(0), + receiveMethod(0), codeAllocator(s, 0, 0) { } @@ -5952,33 +5953,52 @@ class MyProcessor: public Processor { (t->m->system->handleSegFault(&segFaultHandler))); } - virtual void callWithCurrentContinuation(Thread* vmt, object method, - object this_) - { + virtual void callWithCurrentContinuation(Thread* vmt, object receiver) { MyThread* t = static_cast(vmt); + object method; object continuation; void* base; void* stack; - { PROTECT(t, method); - PROTECT(t, this_); + { PROTECT(t, receiver); - compile(t, ::codeAllocator(t), 0, method); + if (receiveMethod == 0) { + const char* const className = "avian/CallbackReceiver"; + const char* const methodName = "receive"; + const char* const methodSpec = "(Lavian/Callback;)Ljava/lang/Object;"; + + receiveMethod = resolveMethod(t, className, methodName, methodSpec); + + if (receiveMethod == 0) { + object message = makeString + (t, "%s %s not found in %s", methodName, methodSpec, className); + t->exception = makeNoSuchMethodError(t, message); + } + } if (LIKELY(t->exception == 0)) { - void* ip; - continuation = makeCurrentContinuation(t, &ip, &base, &stack); + method = findInterfaceMethod + (t, receiveMethod, objectClass(t, receiver)); + PROTECT(t, method); + + compile(t, ::codeAllocator(t), 0, method); + if (LIKELY(t->exception == 0)) { + void* ip; + continuation = makeCurrentContinuation(t, &ip, &base, &stack); + } } } if (LIKELY(t->exception == 0)) { - callWithContinuation(t, method, this_, continuation, base, stack); + callWithContinuation(t, method, receiver, continuation, base, stack); + } else { + unwind(t); } } - virtual void callContinuation(Thread* vmt, object continuation, - object result) + virtual void feedResultToContinuation(Thread* vmt, object continuation, + object result) { MyThread* t = static_cast(vmt); @@ -5997,6 +6017,30 @@ class MyProcessor: public Processor { vmJump(ip, base, stack, t, reinterpret_cast(result), 0); } + virtual void feedExceptionToContinuation(Thread* vmt, object continuation, + object exception) + { + MyThread* t = static_cast(vmt); + + assert(t, t->exception == 0); + + void* ip; + void* base; + void* stack; + findUnwindTarget(t, &ip, &base, &stack); + + t->trace->nativeMethod = 0; + t->trace->targetMethod = 0; + + t->continuation = continuation; + + t->exception = exception; + + findUnwindTarget(t, &ip, &base, &stack); + + vmJump(ip, base, stack, t, 0, 0); + } + virtual void walkContinuationBody(Thread* t, Heap::Walker* w, object o, unsigned start) { @@ -6018,6 +6062,7 @@ class MyProcessor: public Processor { object objectPools; object staticTableArray; object virtualThunks; + object receiveMethod; SegFaultHandler segFaultHandler; FixedAllocator codeAllocator; }; diff --git a/src/processor.h b/src/processor.h index a24a6197d0..7777953580 100644 --- a/src/processor.h +++ b/src/processor.h @@ -134,10 +134,14 @@ class Processor { boot(Thread* t, BootImage* image) = 0; virtual void - callWithCurrentContinuation(Thread* t, object method, object this_) = 0; + callWithCurrentContinuation(Thread* t, object receiver) = 0; virtual void - callContinuation(Thread* t, object continuation, object result) = 0; + feedResultToContinuation(Thread* t, object continuation, object result) = 0; + + virtual void + feedExceptionToContinuation(Thread* t, object continuation, + object exception) = 0; virtual void walkContinuationBody(Thread* t, Heap::Walker* w, object o, unsigned start) diff --git a/src/type-generator.cpp b/src/type-generator.cpp index fbb0db7452..a98c046531 100644 --- a/src/type-generator.cpp +++ b/src/type-generator.cpp @@ -1323,12 +1323,6 @@ parseJavaClass(Object* type, Stream* s, Object* declarations) } } - if (equal(typeJavaName(type), "java/lang/Class")) { - // add inline vtable - addMember(type, Array::make - (type, 0, "void*", "vtable", sizeOf("void*", 0))); - } - if (typeSuper(type)) { for (Object* p = typeMethods(typeSuper(type)); p; p = cdr(p)) { addMethod(type, car(p)); @@ -1372,23 +1366,25 @@ parseType(Object::ObjectType type, Object* p, Object* declarations, Type* t = Type::make(type, name, javaName); - if (javaName and *javaName != '[') { - assert(cdr(p) == 0); + bool isJavaType = javaName and *javaName != '['; + if (isJavaType) { const char* file = append(javaClassDirectory, "/", javaName, ".class"); Stream s(fopen(file, "rb"), true); parseJavaClass(t, &s, declarations); - } else { - for (p = cdr(p); p; p = cdr(p)) { - if (type == Object::Type) { - parseSubdeclaration(t, car(p), declarations); - } else { - Object* member = parseMember(t, car(p), declarations); - assert(member->type == Object::Scalar); - addMember(t, member); - } - } + } + for (p = cdr(p); p; p = cdr(p)) { + if (type == Object::Type) { + parseSubdeclaration(t, car(p), declarations); + } else { + Object* member = parseMember(t, car(p), declarations); + assert(member->type == Object::Scalar); + addMember(t, member); + } + } + + if (not isJavaType) { if (type == Object::Type and typeSuper(t)) { for (Object* p = typeMethods(typeSuper(t)); p; p = cdr(p)) { addMethod(t, car(p)); diff --git a/src/types.def b/src/types.def index c242a9b86c..9039dde46f 100644 --- a/src/types.def +++ b/src/types.def @@ -1,6 +1,7 @@ (type jobject java/lang/Object) -(type class java/lang/Class) +(type class java/lang/Class + (array void* vtable)) (type singleton (array uintptr_t body)) @@ -103,7 +104,7 @@ (type array (noassert array object body)) -(type continuation +(type continuation avian/Continuations$Continuation (object next) (object method) (void* address) @@ -111,6 +112,8 @@ (uintptr_t framePointerOffset) (array uintptr_t body)) +(type callbackReceiver avian/CallbackReceiver) + (type string java/lang/String) (type thread java/lang/Thread) From 3d1ef6800146ab41548b5b9edba1f07ef535978c Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 12 May 2009 12:16:55 -0600 Subject: [PATCH 027/172] various bugfixes --- src/compile.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index b142d23bd3..02a18bb470 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -31,7 +31,7 @@ vmCall(); namespace { -const bool DebugCompile = false; +const bool DebugCompile = true; const bool DebugNatives = false; const bool DebugCallTable = false; const bool DebugMethodTree = false; @@ -255,6 +255,7 @@ class MyStackWalker: public Processor::StackWalker { stack(w->stack), trace(w->trace), method_(w->method_), + continuation(w->continuation), protector(this) { } @@ -6497,7 +6498,8 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, Assembler::Register class_(t->arch->virtualCallTarget()); Assembler::Memory virtualCallTargetSrc (t->arch->stack(), - t->arch->frameFooterSize() + t->arch->frameReturnAddressSize()); + (t->arch->frameFooterSize() + t->arch->frameReturnAddressSize()) + * BytesPerWord); a->apply(Move, BytesPerWord, MemoryOperand, &virtualCallTargetSrc, BytesPerWord, RegisterOperand, &class_); From 57cec2d0682d37ebd1c1f3ebbd941d0236da6efb Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 14 May 2009 20:08:01 -0600 Subject: [PATCH 028/172] various bugfixes --- src/compile.cpp | 65 ++++++++++++++++++++---------------------------- src/compiler.cpp | 36 ++++++++------------------- src/compiler.h | 5 +--- src/x86.S | 4 +-- 4 files changed, 40 insertions(+), 70 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index 02a18bb470..0610bfae32 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -738,13 +738,6 @@ translateLocalIndex(Context* context, unsigned footprint, unsigned index) } } -void -initLocal(Context* context, unsigned footprint, unsigned index) -{ - context->compiler->initLocal - (footprint, translateLocalIndex(context, footprint, index)); -} - Compiler::Operand* loadLocal(Context* context, unsigned footprint, unsigned index) { @@ -1105,13 +1098,7 @@ class Frame { void pop(unsigned count) { popped(count); - - for (unsigned i = count; i;) { - Compiler::StackElement* s = c->top(); - unsigned footprint = c->footprint(s); - c->popped(footprint); - i -= footprint; - } + c->popped(count); } Compiler::Operand* popInt() { @@ -3261,8 +3248,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint8_t index = codeBody(t, code, ip++); int8_t count = codeBody(t, code, ip++); - c->storeLocal - (1, c->add(4, c->constant(count), loadLocal(context, 1, index)), + storeLocal + (context, 1, + c->add(4, c->constant(count), loadLocal(context, 1, index)), index); } break; @@ -3810,7 +3798,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, unsigned offset = (localOffset - (t, localSize(t, context->method) + c->index(c->top()), + (t, localSize(t, context->method) + c->topOfStack(), context->method) / BytesPerWord) + t->arch->frameReturnAddressSize(); @@ -4117,8 +4105,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint16_t index = codeReadInt16(t, code, ip); uint16_t count = codeReadInt16(t, code, ip); - c->storeLocal - (1, c->add(4, c->constant(count), loadLocal(context, 1, index)), + storeLocal + (context, 1, + c->add(4, c->constant(count), loadLocal(context, 1, index)), index); } break; @@ -4611,10 +4600,10 @@ compile(MyThread* t, Allocator* allocator, Context* context) uint8_t stackMap[codeMaxStack(t, methodCode(t, context->method))]; Frame frame(context, stackMap); - unsigned index = 0; + unsigned index = methodParameterFootprint(t, context->method); if ((methodFlags(t, context->method) & ACC_STATIC) == 0) { - initLocal(context, 1, index); - frame.set(index++, Frame::Object); + frame.set(--index, Frame::Object); + c->initLocal(1, index); } for (MethodSpecIterator it @@ -4625,20 +4614,20 @@ compile(MyThread* t, Allocator* allocator, Context* context) switch (*it.next()) { case 'L': case '[': - initLocal(context, 1, index); - frame.set(index++, Frame::Object); + frame.set(--index, Frame::Object); + c->initLocal(1, index); break; case 'J': case 'D': - initLocal(context, 2, index); - frame.set(index++, Frame::Long); - frame.set(index++, Frame::Long); + frame.set(--index, Frame::Long); + frame.set(--index, Frame::Long); + c->initLocal(2, index); break; default: - initLocal(context, 1, index); - frame.set(index++, Frame::Integer); + frame.set(--index, Frame::Integer); + c->initLocal(1, index); break; } } @@ -5151,11 +5140,10 @@ visitStackAndLocals(MyThread* t, Heap::Visitor* v, void* frame, object method, } void -visitArgument(MyThread* t, Heap::Visitor* v, void* stack, object method, - unsigned index) +visitArgument(MyThread* t, Heap::Visitor* v, void* stack, unsigned index) { v->visit(static_cast(stack) - + (methodParameterFootprint(t, method) - index - 1) + + index + t->arch->frameReturnAddressSize() + t->arch->frameFooterSize()); } @@ -5166,7 +5154,7 @@ visitArguments(MyThread* t, Heap::Visitor* v, void* stack, object method) unsigned index = 0; if ((methodFlags(t, method) & ACC_STATIC) == 0) { - visitArgument(t, v, stack, method, index++); + visitArgument(t, v, stack, index++); } for (MethodSpecIterator it @@ -5177,7 +5165,7 @@ visitArguments(MyThread* t, Heap::Visitor* v, void* stack, object method) switch (*it.next()) { case 'L': case '[': - visitArgument(t, v, stack, method, index++); + visitArgument(t, v, stack, index++); break; case 'J': @@ -5435,13 +5423,14 @@ invoke(Thread* thread, object method, ArgumentList* arguments) trace.nativeMethod = method; } - unsigned count = arguments->size - arguments->position; + assert(t, arguments->position == arguments->size); result = vmInvoke (t, reinterpret_cast(methodAddress(t, method)), - arguments->array + arguments->position, - count * BytesPerWord, - t->arch->alignFrameSize(count + t->arch->frameFootprint(0)) + arguments->array, + arguments->position * BytesPerWord, + t->arch->alignFrameSize + (arguments->position + t->arch->frameFootprint(0)) * BytesPerWord, returnType); } diff --git a/src/compiler.cpp b/src/compiler.cpp index 249f247f2a..e4fe2aab1b 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -138,7 +138,7 @@ class SitePair { Site* high; }; -class Stack: public Compiler::StackElement { +class Stack { public: Stack(unsigned index, Value* value, Stack* next): index(index), value(value), next(next) @@ -5140,35 +5140,19 @@ class MyCompiler: public Compiler { } virtual void popped(unsigned footprint) { - assert(&c, c.stack->value->home >= 0); + for (; footprint; -- footprint) { + assert(&c, c.stack->value == 0 or c.stack->value->home >= 0); - if (footprint > 1) { - assert(&c, footprint == 2); - assert(&c, c.stack->value->high == c.stack->next->value - and ((BytesPerWord == 8) xor (c.stack->value->high != 0))); - - popped(1); + if (DebugFrame) { + fprintf(stderr, "popped %p\n", c.stack->value); + } + + c.stack = c.stack->next; } - - if (DebugFrame) { - fprintf(stderr, "popped %p\n", c.stack->value); - } - - c.stack = c.stack->next; } - virtual StackElement* top() { - return c.stack; - } - - virtual unsigned footprint(StackElement* e) { - return (static_cast(e)->next - and (static_cast(e)->next->value - == static_cast(e)->value->high)) ? 2 : 1; - } - - virtual unsigned index(StackElement* e) { - return static_cast(e)->index; + virtual unsigned topOfStack() { + return c.stack->index; } virtual Operand* peek(unsigned footprint, unsigned index) { diff --git a/src/compiler.h b/src/compiler.h index 2b60eb003b..9e28d57b5a 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -35,7 +35,6 @@ class Compiler { static const unsigned TailJump = 1 << 2; class Operand { }; - class StackElement { }; class State { }; class Subroutine { }; @@ -73,9 +72,7 @@ class Compiler { virtual Operand* pop(unsigned footprint) = 0; virtual void pushed() = 0; virtual void popped(unsigned footprint) = 0; - virtual StackElement* top() = 0; - virtual unsigned footprint(StackElement*) = 0; - virtual unsigned index(StackElement*) = 0; + virtual unsigned topOfStack() = 0; virtual Operand* peek(unsigned footprint, unsigned index) = 0; virtual Operand* call(Operand* address, diff --git a/src/x86.S b/src/x86.S index 3740a21f41..95889873bb 100644 --- a/src/x86.S +++ b/src/x86.S @@ -115,11 +115,11 @@ LOCAL(exit): .globl vmJump vmJump: - movq %r8,%rax - movq %r9,%rdx movq %rsi,%rbp movq %rdx,%rsp movq %rcx,%rbx + movq %r8,%rax + movq %r9,%rdx jmp *%rdi #elif defined __i386__ From 06fd492b1aba92cd0df20bea0d47da1e38b3a1fb Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 16 May 2009 02:01:07 -0600 Subject: [PATCH 029/172] add Continuations test --- test/extra/Continuations.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 test/extra/Continuations.java diff --git a/test/extra/Continuations.java b/test/extra/Continuations.java new file mode 100644 index 0000000000..47b0fff3bd --- /dev/null +++ b/test/extra/Continuations.java @@ -0,0 +1,19 @@ +package extra; + +import static avian.Continuations.callWithCurrentContinuation; + +import avian.CallbackReceiver; +import avian.Callback; + +public class Continuations { + public static void main(String[] args) throws Exception { + System.out.println + ("result: " + + callWithCurrentContinuation(new CallbackReceiver() { + public Integer receive(Callback continuation) { + continuation.handleResult(42); + throw new RuntimeException(); + } + })); + } +} From 6dc6f01359871356f4bc8b84ebcf1696febbd046 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 16 May 2009 02:01:32 -0600 Subject: [PATCH 030/172] move extra tests (not run as part of "make test") into "extra" package --- makefile | 2 +- test/extra/Memory.java | 2 ++ test/extra/RuntimeExec.java | 2 ++ test/extra/SendFile.java | 2 ++ test/extra/SendServer.java | 2 ++ 5 files changed, 9 insertions(+), 1 deletion(-) diff --git a/makefile b/makefile index 98694b3d1c..b0967894ad 100644 --- a/makefile +++ b/makefile @@ -299,7 +299,7 @@ classpath-classes = \ classpath-object = $(native-build)/classpath-jar.o classpath-dep = $(classpath-build)/dep -test-sources = $(wildcard $(test)/*.java) +test-sources = $(shell find $(test) -name '*.java') test-classes = $(call java-classes,$(test-sources),$(test),$(test-build)) test-dep = $(test-build)/dep diff --git a/test/extra/Memory.java b/test/extra/Memory.java index 24b837c716..b2e8cfbfea 100644 --- a/test/extra/Memory.java +++ b/test/extra/Memory.java @@ -1,3 +1,5 @@ +package extra; + import java.util.Collection; import java.util.Comparator; import java.util.HashMap; diff --git a/test/extra/RuntimeExec.java b/test/extra/RuntimeExec.java index 2895c61bf9..23adbb9105 100644 --- a/test/extra/RuntimeExec.java +++ b/test/extra/RuntimeExec.java @@ -1,3 +1,5 @@ +package extra; + import java.lang.Runtime; import java.lang.Process; diff --git a/test/extra/SendFile.java b/test/extra/SendFile.java index ad525a1e05..da77a33a21 100644 --- a/test/extra/SendFile.java +++ b/test/extra/SendFile.java @@ -1,3 +1,5 @@ +package extra; + import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.io.IOException; diff --git a/test/extra/SendServer.java b/test/extra/SendServer.java index e2877d3b22..5f60c962c1 100644 --- a/test/extra/SendServer.java +++ b/test/extra/SendServer.java @@ -1,3 +1,5 @@ +package extra; + import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; From 8cb59c9d4cbaa7bf095c263e4b9baf103f526f8a Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 16 May 2009 02:03:03 -0600 Subject: [PATCH 031/172] various bugfixes to get Continuations test working --- src/builtin.cpp | 10 ++++------ src/compile-x86.S | 22 ++++++++++++---------- src/compile.cpp | 29 +++++++++++++++++++++++------ src/machine.cpp | 11 ++--------- src/machine.h | 9 --------- 5 files changed, 41 insertions(+), 40 deletions(-) diff --git a/src/builtin.cpp b/src/builtin.cpp index 9d45707a94..6d3484bc68 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -860,9 +860,8 @@ Avian_avian_Continuations_callWithCurrentContinuation(Thread* t, } extern "C" JNIEXPORT void JNICALL -Avian_avian_Continuation_handleResult(Thread* t, - object, - uintptr_t* arguments) +Avian_avian_Continuations_00024Continuation_handleResult +(Thread* t, object, uintptr_t* arguments) { t->m->processor->feedResultToContinuation (t, reinterpret_cast(arguments[0]), @@ -872,9 +871,8 @@ Avian_avian_Continuation_handleResult(Thread* t, } extern "C" JNIEXPORT void JNICALL -Avian_avian_Continuation_handleException(Thread* t, - object, - uintptr_t* arguments) +Avian_avian_Continuations_00024Continuation_handleException +(Thread* t, object, uintptr_t* arguments) { t->m->processor->feedExceptionToContinuation (t, reinterpret_cast(arguments[0]), diff --git a/src/compile-x86.S b/src/compile-x86.S index 456acc2228..5010173125 100644 --- a/src/compile-x86.S +++ b/src/compile-x86.S @@ -74,7 +74,8 @@ LOCAL(vmInvoke_argumentTest): // call function call *%rsi -LOCAL(vmInvoke_returnAddress): +.globl vmInvoke_returnAddress +vmInvoke_returnAddress: // restore stack pointer movq %rbp,%rsp @@ -84,10 +85,10 @@ LOCAL(vmInvoke_returnAddress): je LOCAL(vmInvoke_exit) movq CONTINUATION_LENGTH(%rcx),%rsi - shrq $3,%rsi - subq %rsi,%rsp + shlq $3,%rsi + subq %rsi,%rsp - movq CONTINUATION_BODY(%rcx),%rdi + leaq CONTINUATION_BODY(%rcx),%rdi movq $0,%r9 jmp LOCAL(vmInvoke_continuationTest) @@ -102,12 +103,13 @@ LOCAL(vmInvoke_continuationTest): jb LOCAL(vmInvoke_continuationLoop) movq CONTINUATION_RETURN_ADDRESS_OFFSET(%rcx),%rdi - movq LOCAL(vmInvoke_returnAddress)@GOTPCREL(%rip),%r10 + movq vmInvoke_returnAddress@GOTPCREL(%rip),%r10 movq %r10,(%rsp,%rdi,1) movq CONTINUATION_FRAME_POINTER_OFFSET(%rcx),%rdi movq %rbp,(%rsp,%rdi,1) - subq %rdi,%rbp + addq %rsp,%rdi + movq %rdi,%rbp movq CONTINUATION_NEXT(%rcx),%rdi movq %rdi,THREAD_CONTINUATION(%rbx) @@ -151,13 +153,13 @@ vmCallWithContinuation: // %r8 : base // %r9 : stack - movq %rdi,%rdx + movq %rdi,%rbx movq %r8,%rbp movq %r9,%rsp - movq LOCAL(vmInvoke_returnAddress)@GOTPCREL(%rip),%r10 + movq vmInvoke_returnAddress@GOTPCREL(%rip),%r10 movq %r10,(%rsp) - movq %rcx,8(%rsp) - movq %rdx,16(%rsp) + movq %rdx,8(%rsp) + movq %rcx,16(%rsp) jmp *%rsi #elif defined __i386__ diff --git a/src/compile.cpp b/src/compile.cpp index 0610bfae32..447c00f133 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -1432,7 +1432,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, reinterpret_cast(t->continuation) + ContinuationBody + continuationReturnAddressOffset(t, t->continuation) - -t->arch->returnAddressOffset()); + - t->arch->returnAddressOffset()); } t->continuation = continuationNext(t, t->continuation); @@ -1467,7 +1467,8 @@ makeCurrentContinuation(MyThread* t, void** targetIp, void** targetBase, if (method) { PROTECT(t, method); - void** top = static_cast(stack) - t->arch->frameHeaderSize(); + void** top = static_cast(stack) + + t->arch->frameReturnAddressSize(); unsigned argumentFootprint = t->arch->argumentFootprint(methodParameterFootprint(t, target)); unsigned alignment = t->arch->stackAlignmentInWords(); @@ -1477,17 +1478,21 @@ makeCurrentContinuation(MyThread* t, void** targetIp, void** targetBase, t->arch->nextFrame(&stack, &base); - void** bottom = static_cast(stack); + void** bottom = static_cast(stack) + + t->arch->frameReturnAddressSize(); unsigned frameSize = bottom - top; unsigned totalSize = frameSize - + t->arch->frameHeaderSize() + t->arch->frameFooterSize() + t->arch->argumentFootprint(methodParameterFootprint(t, method)); object c = makeContinuation (t, 0, method, ip, - ((frameSize + t->arch->returnAddressOffset()) * BytesPerWord), - ((frameSize + t->arch->framePointerOffset()) * BytesPerWord), + ((frameSize + + t->arch->returnAddressOffset() + - t->arch->frameReturnAddressSize()) * BytesPerWord), + ((frameSize + + t->arch->framePointerOffset() + - t->arch->frameReturnAddressSize()) * BytesPerWord), totalSize); memcpy(&continuationBody(t, c, 0), top, totalSize * BytesPerWord); @@ -1580,6 +1585,9 @@ findInterfaceMethodFromInstance(MyThread* t, object method, object instance) if (UNLIKELY(t->exception)) { unwind(t); } else { + if (methodFlags(t, target) & ACC_NATIVE) { + t->trace->nativeMethod = target; + } return methodAddress(t, target); } } else { @@ -5965,6 +5973,15 @@ class MyProcessor: public Processor { (t, "%s %s not found in %s", methodName, methodSpec, className); t->exception = makeNoSuchMethodError(t, message); } + + if (LIKELY(t->exception == 0)) { + object continuationClass = arrayBody + (t, t->m->types, Machine::ContinuationType); + + if (classVmFlags(t, continuationClass) & BootstrapFlag) { + resolveClass(t, vm::className(t, continuationClass)); + } + } } if (LIKELY(t->exception == 0)) { diff --git a/src/machine.cpp b/src/machine.cpp index b4c877f4da..7c89ca91a7 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1313,14 +1313,7 @@ updateBootstrapClass(Thread* t, object bootstrapClass, object class_) expect(t, classSuper(t, bootstrapClass) == classSuper(t, class_)); expect(t, bootstrapClass == arrayBody(t, t->m->types, Machine::ClassType) - or classFixedSize(t, bootstrapClass) == classFixedSize(t, class_)); - - expect(t, - (classVmFlags(t, bootstrapClass) & ReferenceFlag) - or (classObjectMask(t, bootstrapClass) == 0 - and classObjectMask(t, class_) == 0) - or intArrayEqual(t, classObjectMask(t, bootstrapClass), - classObjectMask(t, class_))); + or classFixedSize(t, bootstrapClass) >= classFixedSize(t, class_)); PROTECT(t, bootstrapClass); PROTECT(t, class_); @@ -1329,7 +1322,7 @@ updateBootstrapClass(Thread* t, object bootstrapClass, object class_) classVmFlags(t, bootstrapClass) &= ~BootstrapFlag; classVmFlags(t, bootstrapClass) |= classVmFlags(t, class_); - classFlags(t, bootstrapClass) = classFlags(t, class_); + classFlags(t, bootstrapClass) |= classFlags(t, class_); set(t, bootstrapClass, ClassSuper, classSuper(t, class_)); set(t, bootstrapClass, ClassInterfaceTable, classInterfaceTable(t, class_)); diff --git a/src/machine.h b/src/machine.h index c20ef8521e..024ac84f12 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1943,15 +1943,6 @@ stringEqual(Thread* t, object a, object b) } } -inline bool -intArrayEqual(Thread* t, object a, object b) -{ - return a == b or - ((intArrayLength(t, a) == intArrayLength(t, b)) and - memcmp(&intArrayBody(t, a, 0), &intArrayBody(t, b, 0), - intArrayLength(t, a) * 4) == 0); -} - inline uint32_t methodHash(Thread* t, object method) { From 195d95d809c9dea8c170f67ab30e099816135cac Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 16 May 2009 18:39:08 -0600 Subject: [PATCH 032/172] continuation bugfixes --- src/compile-x86.S | 1 + src/compile.cpp | 67 ++++++++++++++++++++++------------- src/x86.cpp | 3 +- test/extra/Continuations.java | 35 +++++++++++++++++- 4 files changed, 78 insertions(+), 28 deletions(-) diff --git a/src/compile-x86.S b/src/compile-x86.S index 5010173125..22cfd0f9fa 100644 --- a/src/compile-x86.S +++ b/src/compile-x86.S @@ -87,6 +87,7 @@ vmInvoke_returnAddress: movq CONTINUATION_LENGTH(%rcx),%rsi shlq $3,%rsi subq %rsi,%rsp + subq $48,%rsp leaq CONTINUATION_BODY(%rcx),%rdi diff --git a/src/compile.cpp b/src/compile.cpp index 447c00f133..308b0161a5 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -61,6 +61,7 @@ class MyThread: public Thread { t->trace = this; t->base = 0; t->stack = 0; + t->continuation = 0; } ~CallTrace() { @@ -292,6 +293,7 @@ class MyStackWalker: public Processor::StackWalker { if (method_) { state = Method; } else if (continuation) { + method_ = continuationMethod(t, continuation); state = Continuation; } else if (trace) { continuation = trace->continuation; @@ -1379,12 +1381,12 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, ip = t->arch->frameIp(stack); } + object target = t->trace->targetMethod; + *targetIp = 0; while (*targetIp == 0) { object method = methodForIp(t, ip); if (method) { - PROTECT(t, method); - void* handler = findExceptionHandler(t, method, ip); if (handler) { @@ -1407,6 +1409,8 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, ip = t->arch->frameIp(stack); releaseLock(t, method, stack); + + target = method; } } else { *targetIp = ip; @@ -1415,20 +1419,23 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, + t->arch->frameReturnAddressSize(); while (t->continuation) { + object method = continuationMethod(t, t->continuation); + void* handler = findExceptionHandler - (t, continuationMethod(t, t->continuation), - continuationAddress(t, t->continuation)); + (t, method, continuationAddress(t, t->continuation)); if (handler) { t->exceptionHandler = handler; - t->exceptionStack = stackForFrame - (t, stack, continuationMethod(t, t->continuation)); + t->exceptionStack = static_cast(*targetStack) + + t->arch->argumentFootprint(methodParameterFootprint(t, target)) + - t->arch->argumentFootprint(methodParameterFootprint(t, method)) + - stackOffsetFromFrame(t, method); t->exceptionOffset = localOffset(t, localSize(t, method), method); break; } else { - releaseLock(t, continuationMethod(t, t->continuation), + releaseLock(t, method, reinterpret_cast(t->continuation) + ContinuationBody + continuationReturnAddressOffset(t, t->continuation) @@ -1443,7 +1450,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, object makeCurrentContinuation(MyThread* t, void** targetIp, void** targetBase, - void** targetStack) + void** targetStack, unsigned* oldArgumentFootprint) { void* ip = t->ip; void* base = t->base; @@ -1468,7 +1475,7 @@ makeCurrentContinuation(MyThread* t, void** targetIp, void** targetBase, PROTECT(t, method); void** top = static_cast(stack) - + t->arch->frameReturnAddressSize(); + + t->arch->frameReturnAddressSize(); unsigned argumentFootprint = t->arch->argumentFootprint(methodParameterFootprint(t, target)); unsigned alignment = t->arch->stackAlignmentInWords(); @@ -1512,6 +1519,8 @@ makeCurrentContinuation(MyThread* t, void** targetIp, void** targetBase, *targetBase = base; *targetStack = static_cast(stack) + t->arch->frameReturnAddressSize(); + *oldArgumentFootprint + = t->arch->argumentFootprint(methodParameterFootprint(t, target)); } } @@ -5020,18 +5029,6 @@ invokeNativeSlow(MyThread* t, object method) default: abort(t); } - - unsigned parameterFootprint = methodParameterFootprint(t, method); - if (t->arch->argumentFootprint(parameterFootprint) - > t->arch->stackAlignmentInWords()) - { - t->stack = static_cast(t->stack) - + (t->arch->argumentFootprint(parameterFootprint) - - t->arch->stackAlignmentInWords()); - } - - t->stack = static_cast(t->stack) - + t->arch->frameReturnAddressSize(); } else { result = 0; } @@ -5087,12 +5084,26 @@ invokeNative(MyThread* t) } } + unsigned parameterFootprint = methodParameterFootprint + (t, t->trace->targetMethod); + t->trace->targetMethod = 0; t->trace->nativeMethod = 0; if (UNLIKELY(t->exception)) { unwind(t); } else { + if (t->arch->argumentFootprint(parameterFootprint) + > t->arch->stackAlignmentInWords()) + { + t->stack = static_cast(t->stack) + + (t->arch->argumentFootprint(parameterFootprint) + - t->arch->stackAlignmentInWords()); + } + + t->stack = static_cast(t->stack) + + t->arch->frameReturnAddressSize(); + return result; } } @@ -5270,7 +5281,8 @@ walkContinuationBody(MyThread* t, Heap::Walker* w, object c, int start) void callWithContinuation(MyThread* t, object method, object this_, - object continuation, void* base, void* stack) + object continuation, void* base, void* stack, + unsigned oldArgumentFootprint) { t->trace->targetMethod = 0; @@ -5286,6 +5298,7 @@ callWithContinuation(MyThread* t, object method, object this_, continuation, base, static_cast(stack) + + oldArgumentFootprint - t->arch->argumentFootprint(methodParameterFootprint(t, method)) - t->arch->frameFooterSize() - t->arch->frameReturnAddressSize()); @@ -5438,7 +5451,7 @@ invoke(Thread* thread, object method, ArgumentList* arguments) arguments->array, arguments->position * BytesPerWord, t->arch->alignFrameSize - (arguments->position + t->arch->frameFootprint(0)) + (t->arch->argumentFootprint(arguments->position)) * BytesPerWord, returnType); } @@ -5958,6 +5971,7 @@ class MyProcessor: public Processor { object continuation; void* base; void* stack; + unsigned oldArgumentFootprint; { PROTECT(t, receiver); @@ -5992,13 +6006,16 @@ class MyProcessor: public Processor { compile(t, ::codeAllocator(t), 0, method); if (LIKELY(t->exception == 0)) { void* ip; - continuation = makeCurrentContinuation(t, &ip, &base, &stack); + continuation = makeCurrentContinuation + (t, &ip, &base, &stack, &oldArgumentFootprint); } } } if (LIKELY(t->exception == 0)) { - callWithContinuation(t, method, receiver, continuation, base, stack); + t->continuation = continuation; + callWithContinuation(t, method, receiver, continuation, base, stack, + oldArgumentFootprint); } else { unwind(t); } diff --git a/src/x86.cpp b/src/x86.cpp index 1e67528648..9d6f521b56 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -2150,8 +2150,7 @@ class MyArchitecture: public Assembler::Architecture { } virtual unsigned alignFrameSize(unsigned sizeInWords) { - const unsigned alignment = StackAlignmentInBytes / BytesPerWord; - return (ceiling(sizeInWords + FrameHeaderSize, alignment) * alignment) + return pad(sizeInWords + FrameHeaderSize, StackAlignmentInWords) - FrameHeaderSize; } diff --git a/test/extra/Continuations.java b/test/extra/Continuations.java index 47b0fff3bd..2c85ef2758 100644 --- a/test/extra/Continuations.java +++ b/test/extra/Continuations.java @@ -12,8 +12,41 @@ public class Continuations { callWithCurrentContinuation(new CallbackReceiver() { public Integer receive(Callback continuation) { continuation.handleResult(42); - throw new RuntimeException(); + throw new RuntimeException("unreachable"); } })); + + System.out.println + ("result: " + + callWithCurrentContinuation(new CallbackReceiver() { + public Integer receive(Callback continuation) { + return 43; + } + })); + + try { + callWithCurrentContinuation(new CallbackReceiver() { + public Integer receive(Callback continuation) { + continuation.handleException(new MyException()); + throw new RuntimeException("unreachable"); + } + }); + } catch (MyException e) { + e.printStackTrace(); + } + + try { + callWithCurrentContinuation(new CallbackReceiver() { + public Integer receive(Callback continuation) + throws MyException + { + throw new MyException(); + } + }); + } catch (MyException e) { + e.printStackTrace(); + } } + + private static class MyException extends Exception { } } From 857361972006f6fd335d4df10933b470899898e7 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 16 May 2009 21:15:41 -0600 Subject: [PATCH 033/172] refine Continuations.java and add Coroutines.java --- test/extra/Continuations.java | 34 ++++++++-------- test/extra/Coroutines.java | 77 +++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 16 deletions(-) create mode 100644 test/extra/Coroutines.java diff --git a/test/extra/Continuations.java b/test/extra/Continuations.java index 2c85ef2758..938ea0328c 100644 --- a/test/extra/Continuations.java +++ b/test/extra/Continuations.java @@ -6,23 +6,23 @@ import avian.CallbackReceiver; import avian.Callback; public class Continuations { - public static void main(String[] args) throws Exception { - System.out.println - ("result: " + - callWithCurrentContinuation(new CallbackReceiver() { - public Integer receive(Callback continuation) { - continuation.handleResult(42); - throw new RuntimeException("unreachable"); - } - })); + private static void expect(boolean v) { + if (! v) throw new RuntimeException(); + } - System.out.println - ("result: " + - callWithCurrentContinuation(new CallbackReceiver() { - public Integer receive(Callback continuation) { - return 43; - } - })); + public static void main(String[] args) throws Exception { + expect(callWithCurrentContinuation(new CallbackReceiver() { + public Integer receive(Callback continuation) { + continuation.handleResult(42); + throw new RuntimeException("unreachable"); + } + }) == 42); + + expect(callWithCurrentContinuation(new CallbackReceiver() { + public Integer receive(Callback continuation) { + return 43; + } + }) == 43); try { callWithCurrentContinuation(new CallbackReceiver() { @@ -31,6 +31,7 @@ public class Continuations { throw new RuntimeException("unreachable"); } }); + throw new RuntimeException("unreachable"); } catch (MyException e) { e.printStackTrace(); } @@ -43,6 +44,7 @@ public class Continuations { throw new MyException(); } }); + throw new RuntimeException("unreachable"); } catch (MyException e) { e.printStackTrace(); } diff --git a/test/extra/Coroutines.java b/test/extra/Coroutines.java new file mode 100644 index 0000000000..9623f37dd7 --- /dev/null +++ b/test/extra/Coroutines.java @@ -0,0 +1,77 @@ +package extra; + +import static avian.Continuations.callWithCurrentContinuation; + +import avian.CallbackReceiver; +import avian.Callback; + +public class Coroutines { + private static void expect(boolean v) { + if (! v) throw new RuntimeException(); + } + + private static void produce(Consumer consumer) throws Exception { + consumer.consume('a'); + consumer.consume('b'); + consumer.consume('c'); + } + + private static void consume(Producer producer) throws Exception { + expect(producer.produce() == 'a'); + expect(producer.produce() == 'b'); + expect(producer.produce() == 'c'); + } + + public static void main(String[] args) throws Exception { + final CoroutineState state = new CoroutineState(); + + final Consumer consumer = new Consumer() { + public void consume(final Character c) throws Exception { + callWithCurrentContinuation(new CallbackReceiver() { + public Object receive(Callback continuation) { + state.produceNext = continuation; + + state.consumeNext.handleResult(c); + + throw new RuntimeException("unreachable"); + } + }); + } + }; + + Producer producer = new Producer() { + public Character produce() throws Exception { + return callWithCurrentContinuation(new CallbackReceiver() { + public Character receive(Callback continuation) + throws Exception + { + state.consumeNext = continuation; + + if (state.produceNext == null) { + Coroutines.produce(consumer); + } else { + state.produceNext.handleResult(null); + } + + throw new RuntimeException("unreachable"); + } + }); + } + }; + + consume(producer); + } + + private static class CoroutineState { + public Callback produceNext; + public Callback consumeNext; + } + + private interface Producer { + public T produce() throws Exception; + } + + private interface Consumer { + public void consume(T value) throws Exception; + } +} From 8463bb4056e4cc57e39acd24919e36d6e2d9935c Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 16 May 2009 21:41:27 -0600 Subject: [PATCH 034/172] minor tweaks to test classes --- test/extra/Continuations.java | 8 ++++---- test/extra/Coroutines.java | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/extra/Continuations.java b/test/extra/Continuations.java index 938ea0328c..a439d8a58d 100644 --- a/test/extra/Continuations.java +++ b/test/extra/Continuations.java @@ -14,7 +14,7 @@ public class Continuations { expect(callWithCurrentContinuation(new CallbackReceiver() { public Integer receive(Callback continuation) { continuation.handleResult(42); - throw new RuntimeException("unreachable"); + throw new AssertionError(); } }) == 42); @@ -28,10 +28,10 @@ public class Continuations { callWithCurrentContinuation(new CallbackReceiver() { public Integer receive(Callback continuation) { continuation.handleException(new MyException()); - throw new RuntimeException("unreachable"); + throw new AssertionError(); } }); - throw new RuntimeException("unreachable"); + throw new AssertionError(); } catch (MyException e) { e.printStackTrace(); } @@ -44,7 +44,7 @@ public class Continuations { throw new MyException(); } }); - throw new RuntimeException("unreachable"); + throw new AssertionError(); } catch (MyException e) { e.printStackTrace(); } diff --git a/test/extra/Coroutines.java b/test/extra/Coroutines.java index 9623f37dd7..bacbe99563 100644 --- a/test/extra/Coroutines.java +++ b/test/extra/Coroutines.java @@ -33,13 +33,13 @@ public class Coroutines { state.consumeNext.handleResult(c); - throw new RuntimeException("unreachable"); + throw new AssertionError(); } }); } }; - Producer producer = new Producer() { + final Producer producer = new Producer() { public Character produce() throws Exception { return callWithCurrentContinuation(new CallbackReceiver() { public Character receive(Callback continuation) @@ -53,7 +53,7 @@ public class Coroutines { state.produceNext.handleResult(null); } - throw new RuntimeException("unreachable"); + throw new AssertionError(); } }); } @@ -63,7 +63,7 @@ public class Coroutines { } private static class CoroutineState { - public Callback produceNext; + public Callback produceNext; public Callback consumeNext; } From 398dec58bbe5f7bf400020b9544061352484c85d Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 17 May 2009 17:43:48 -0600 Subject: [PATCH 035/172] GC bugfixes --- src/compile.cpp | 59 +++++++++++++++++++++++++------------------------ src/machine.cpp | 22 ++++++++++-------- 2 files changed, 43 insertions(+), 38 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index 308b0161a5..b54209d29f 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -431,7 +431,7 @@ localOffset(MyThread* t, int v, object method) - v - 1) : (frameSize + parameterFootprint - - v - 1)) * BytesPerWord; + - v - 1)); assert(t, offset >= 0); return offset; @@ -441,14 +441,13 @@ int localOffsetFromStack(MyThread* t, int index, object method) { return localOffset(t, index, method) - + (t->arch->frameReturnAddressSize() * BytesPerWord); + + t->arch->frameReturnAddressSize(); } object* localObject(MyThread* t, void* stack, object method, unsigned index) { - return reinterpret_cast - (static_cast(stack) + localOffsetFromStack(t, index, method)); + return static_cast(stack) + localOffsetFromStack(t, index, method); } int @@ -1400,8 +1399,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, *targetStack = sp; - sp[localOffset(t, localSize(t, method), method) / BytesPerWord] - = t->exception; + sp[localOffset(t, localSize(t, method), method)] = t->exception; t->exception = 0; } else { @@ -1432,7 +1430,8 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, - t->arch->argumentFootprint(methodParameterFootprint(t, method)) - stackOffsetFromFrame(t, method); - t->exceptionOffset = localOffset(t, localSize(t, method), method); + t->exceptionOffset + = localOffset(t, localSize(t, method), method) * BytesPerWord; break; } else { releaseLock(t, method, @@ -3814,9 +3813,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, PROTECT(t, class_); unsigned offset - = (localOffset - (t, localSize(t, context->method) + c->topOfStack(), - context->method) / BytesPerWord) + = localOffset + (t, localSize(t, context->method) + c->topOfStack(), context->method) + t->arch->frameReturnAddressSize(); Compiler::Operand* result = c->call @@ -5197,7 +5195,6 @@ visitArguments(MyThread* t, Heap::Visitor* v, void* stack, object method) break; } } - } void @@ -5214,15 +5211,15 @@ visitStack(MyThread* t, Heap::Visitor* v) object targetMethod = (trace ? trace->targetMethod : 0); while (stack) { + if (targetMethod) { + visitArguments(t, v, stack, targetMethod); + targetMethod = 0; + } + object method = methodForIp(t, ip); if (method) { PROTECT(t, method); - if (targetMethod) { - visitArguments(t, v, stack, targetMethod); - targetMethod = 0; - } - t->arch->nextFrame(&stack, &base); visitStackAndLocals(t, v, stack, method, ip); @@ -5246,34 +5243,37 @@ visitStack(MyThread* t, Heap::Visitor* v) void walkContinuationBody(MyThread* t, Heap::Walker* w, object c, int start) { - const int ContinuationReferenceCount = 3; - - int bodyStart = max(0, start - ContinuationReferenceCount); + const int BodyOffset = ContinuationBody / BytesPerWord; object method = static_cast (t->m->heap->follow(continuationMethod(t, c))); - unsigned count = frameMapSizeInBits(t, method); + int count = frameMapSizeInBits(t, method); if (count) { + int stack = BodyOffset + + (continuationFramePointerOffset(t, c) / BytesPerWord) + - t->arch->framePointerOffset() + - stackOffsetFromFrame(t, method); + + int first = stack + localOffsetFromStack(t, count - 1, method); + if (start > first) { + count -= start - first; + } + object map = codePool(t, methodCode(t, method)); int index = frameMapIndex (t, method, difference (continuationAddress(t, c), reinterpret_cast(methodAddress(t, method)))); - for (unsigned i = bodyStart; i < count; ++i) { + for (int i = count - 1; i >= 0; --i) { int j = index + i; if ((intArrayBody(t, map, j / 32) & (static_cast(1) << (j % 32)))) { - if (not w->visit - ((continuationFramePointerOffset(t, c) / BytesPerWord) - - t->arch->framePointerOffset() - - stackOffsetFromFrame(t, method) - + localOffsetFromStack(t, i, method))) - { + if (not w->visit(stack + localOffsetFromStack(t, i, method))) { return; - } + } } } } @@ -5417,7 +5417,7 @@ class ArgumentList { MyProtector(ArgumentList* list): Protector(list->t), list(list) { } virtual void visit(Heap::Visitor* v) { - for (unsigned i = list->position; i < list->size; ++i) { + for (unsigned i = 0; i < list->position; ++i) { if (list->objectMask[i]) { v->visit(reinterpret_cast(list->array + i)); } @@ -5658,6 +5658,7 @@ class MyProcessor: public Processor { v->visit(&objectPools); v->visit(&staticTableArray); v->visit(&virtualThunks); + v->visit(&receiveMethod); } for (MyThread::CallTrace* trace = t->trace; trace; trace = trace->next) { diff --git a/src/machine.cpp b/src/machine.cpp index 7c89ca91a7..c0ee2be304 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -196,7 +196,7 @@ visitRoots(Thread* t, Heap::Visitor* v) } } -void +bool walk(Thread*, Heap::Walker* w, uint32_t* mask, unsigned fixedSize, unsigned arrayElementSize, unsigned arrayLength, unsigned start) { @@ -207,7 +207,7 @@ walk(Thread*, Heap::Walker* w, uint32_t* mask, unsigned fixedSize, for (unsigned i = start; i < fixedSizeInWords; ++i) { if (mask[i / 32] & (static_cast(1) << (i % 32))) { if (not w->visit(i)) { - return; + return false; } } } @@ -240,12 +240,14 @@ walk(Thread*, Heap::Walker* w, uint32_t* mask, unsigned fixedSize, if (not w->visit (fixedSizeInWords + (i * arrayElementSizeInWords) + j)) { - return; + return false; } } } } } + + return true; } void @@ -2784,6 +2786,8 @@ walk(Thread* t, Heap::Walker* w, object o, unsigned start) object objectMask = static_cast (t->m->heap->follow(classObjectMask(t, class_))); + bool more = true; + if (objectMask) { unsigned fixedSize = classFixedSize(t, class_); unsigned arrayElementSize = classArrayElementSize(t, class_); @@ -2795,20 +2799,20 @@ walk(Thread* t, Heap::Walker* w, object o, unsigned start) memcpy(mask, &intArrayBody(t, objectMask, 0), intArrayLength(t, objectMask) * 4); - ::walk(t, w, mask, fixedSize, arrayElementSize, arrayLength, start); + more = ::walk(t, w, mask, fixedSize, arrayElementSize, arrayLength, start); } else if (classFlags(t, class_) & SingletonFlag) { unsigned length = singletonLength(t, o); if (length) { - ::walk(t, w, singletonMask(t, o), - (singletonCount(t, o) + 2) * BytesPerWord, 0, 0, start); + more = ::walk(t, w, singletonMask(t, o), + (singletonCount(t, o) + 2) * BytesPerWord, 0, 0, start); } else if (start == 0) { - w->visit(0); + more = w->visit(0); } } else if (start == 0) { - w->visit(0); + more = w->visit(0); } - if (classFlags(t, class_) & ContinuationFlag) { + if (more and classFlags(t, class_) & ContinuationFlag) { t->m->processor->walkContinuationBody(t, w, o, start); } } From ecfecf2006ac2b2476d5c5f0e754e80e8e8f81ce Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 18 May 2009 09:16:17 -0600 Subject: [PATCH 036/172] translate local indexes before passing to Frame.stored{Int,Long,Object} --- src/compile.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index b54209d29f..424b5fdd9e 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -31,7 +31,7 @@ vmCall(); namespace { -const bool DebugCompile = true; +const bool DebugCompile = false; const bool DebugNatives = false; const bool DebugCallTable = false; const bool DebugMethodTree = false; @@ -1134,17 +1134,17 @@ class Frame { void storeInt(unsigned index) { storeLocal(context, 1, popInt(), index); - storedInt(index); + storedInt(translateLocalIndex(context, 1, index)); } void storeLong(unsigned index) { storeLocal(context, 2, popLong(), index); - storedLong(index); + storedLong(translateLocalIndex(context, 2, index)); } void storeObject(unsigned index) { storeLocal(context, 1, popObject(), index); - storedObject(index); + storedObject(translateLocalIndex(context, 1, index)); } void storeObjectOrAddress(unsigned index) { @@ -1153,9 +1153,9 @@ class Frame { assert(t, sp >= 1); assert(t, sp - 1 >= localSize()); if (get(sp - 1) == Object) { - storedObject(index); + storedObject(translateLocalIndex(context, 1, index)); } else { - storedInt(index); + storedInt(translateLocalIndex(context, 1, index)); } popped(1); @@ -3521,7 +3521,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, // should verify once we have complete data flow information // (todo). storeLocal(context, 1, c->constant(0), index); - frame->storedObject(index); + frame->storedObject(translateLocalIndex(context, 1, index)); } frame->pushAddress(frame->addressOperand(c->machineIp(ip))); From e35047b0561b39bccf2c7622d5d62dd1e6b6374e Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 18 May 2009 09:17:09 -0600 Subject: [PATCH 037/172] build but don't run extra tests in makefile --- makefile | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/makefile b/makefile index b0967894ad..077222a5cf 100644 --- a/makefile +++ b/makefile @@ -299,10 +299,15 @@ classpath-classes = \ classpath-object = $(native-build)/classpath-jar.o classpath-dep = $(classpath-build)/dep -test-sources = $(shell find $(test) -name '*.java') +test-sources = $(wildcard $(test)/*.java) test-classes = $(call java-classes,$(test-sources),$(test),$(test-build)) test-dep = $(test-build)/dep +test-extra-sources = $(wildcard $(test)/extra/*.java) +test-extra-classes = \ + $(call java-classes,$(test-extra-sources),$(test),$(test-build)) +test-extra-dep = $(test-build)/extra/dep + class-name = $(patsubst $(1)/%.class,%,$(2)) class-names = $(foreach x,$(2),$(call class-name,$(1),$(x))) @@ -312,7 +317,7 @@ args = $(flags) $(input) .PHONY: build build: $(static-library) $(executable) $(dynamic-library) \ - $(executable-dynamic) $(classpath-dep) $(test-dep) + $(executable-dynamic) $(classpath-dep) $(test-dep) $(test-extra-dep) $(test-classes): $(classpath-dep) @@ -390,6 +395,13 @@ $(test-dep): $(test-sources) test/Subroutine.java @touch $(@) +$(test-extra-dep): $(test-extra-sources) + @echo "compiling extra test classes" + @mkdir -p $(dir $(@)) + $(javac) -d $(test) -bootclasspath $(classpath-build) \ + $(shell $(MAKE) -s --no-print-directory $(test-extra-classes)) + @touch $(@) + define compile-object @echo "compiling $(@)" @mkdir -p $(dir $(@)) From db91c27441fa384a97bc0a13e38483b120cd2fab Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 18 May 2009 09:17:49 -0600 Subject: [PATCH 038/172] move Continuations and Coroutines tests to top-level test directory --- test/{extra => }/Continuations.java | 2 - test/{extra => }/Coroutines.java | 70 +++++++++++++++++------------ 2 files changed, 42 insertions(+), 30 deletions(-) rename test/{extra => }/Continuations.java (98%) rename test/{extra => }/Coroutines.java (54%) diff --git a/test/extra/Continuations.java b/test/Continuations.java similarity index 98% rename from test/extra/Continuations.java rename to test/Continuations.java index a439d8a58d..3ee444b02a 100644 --- a/test/extra/Continuations.java +++ b/test/Continuations.java @@ -1,5 +1,3 @@ -package extra; - import static avian.Continuations.callWithCurrentContinuation; import avian.CallbackReceiver; diff --git a/test/extra/Coroutines.java b/test/Coroutines.java similarity index 54% rename from test/extra/Coroutines.java rename to test/Coroutines.java index bacbe99563..62cea719ec 100644 --- a/test/extra/Coroutines.java +++ b/test/Coroutines.java @@ -1,5 +1,3 @@ -package extra; - import static avian.Continuations.callWithCurrentContinuation; import avian.CallbackReceiver; @@ -11,15 +9,28 @@ public class Coroutines { } private static void produce(Consumer consumer) throws Exception { + System.out.println("produce \"a\""); consumer.consume('a'); + + System.out.println("produce \"b\""); consumer.consume('b'); + + System.out.println("produce \"c\""); consumer.consume('c'); } private static void consume(Producer producer) throws Exception { - expect(producer.produce() == 'a'); - expect(producer.produce() == 'b'); - expect(producer.produce() == 'c'); + char v = producer.produce(); + System.out.println("consume \"" + v + "\""); + expect(v == 'a'); + + v = producer.produce(); + System.out.println("consume \"" + v + "\""); + expect(v == 'b'); + + v = producer.produce(); + System.out.println("consume \"" + v + "\""); + expect(v == 'c'); } public static void main(String[] args) throws Exception { @@ -28,30 +39,10 @@ public class Coroutines { final Consumer consumer = new Consumer() { public void consume(final Character c) throws Exception { callWithCurrentContinuation(new CallbackReceiver() { - public Object receive(Callback continuation) { - state.produceNext = continuation; + public Object receive(Callback continuation) { + state.produceNext = continuation; - state.consumeNext.handleResult(c); - - throw new AssertionError(); - } - }); - } - }; - - final Producer producer = new Producer() { - public Character produce() throws Exception { - return callWithCurrentContinuation(new CallbackReceiver() { - public Character receive(Callback continuation) - throws Exception - { - state.consumeNext = continuation; - - if (state.produceNext == null) { - Coroutines.produce(consumer); - } else { - state.produceNext.handleResult(null); - } + state.consumeNext.handleResult(c); throw new AssertionError(); } @@ -59,6 +50,29 @@ public class Coroutines { } }; + final Producer producer = new Producer() { + final CallbackReceiver receiver + = new CallbackReceiver() { + public Character receive(Callback continuation) + throws Exception + { + state.consumeNext = continuation; + + if (state.produceNext == null) { + Coroutines.produce(consumer); + } else { + state.produceNext.handleResult(null); + } + + throw new AssertionError(); + } + }; + + public Character produce() throws Exception { + return callWithCurrentContinuation(receiver); + } + }; + consume(producer); } From e165d5f3fd7ddad312faa397f34d58056417d23d Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 19 May 2009 18:28:43 -0600 Subject: [PATCH 039/172] avoid uninitialized variable warnings in MyProcessor::callWithCurrentContinuation --- src/compile.cpp | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index 424b5fdd9e..3dfa33f232 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -5968,12 +5968,6 @@ class MyProcessor: public Processor { virtual void callWithCurrentContinuation(Thread* vmt, object receiver) { MyThread* t = static_cast(vmt); - object method; - object continuation; - void* base; - void* stack; - unsigned oldArgumentFootprint; - { PROTECT(t, receiver); if (receiveMethod == 0) { @@ -6000,26 +5994,27 @@ class MyProcessor: public Processor { } if (LIKELY(t->exception == 0)) { - method = findInterfaceMethod + object method = findInterfaceMethod (t, receiveMethod, objectClass(t, receiver)); PROTECT(t, method); compile(t, ::codeAllocator(t), 0, method); if (LIKELY(t->exception == 0)) { void* ip; - continuation = makeCurrentContinuation + void* base; + void* stack; + unsigned oldArgumentFootprint; + t->continuation = makeCurrentContinuation (t, &ip, &base, &stack, &oldArgumentFootprint); + + callWithContinuation + (t, method, receiver, t->continuation, base, stack, + oldArgumentFootprint); } } } - if (LIKELY(t->exception == 0)) { - t->continuation = continuation; - callWithContinuation(t, method, receiver, continuation, base, stack, - oldArgumentFootprint); - } else { - unwind(t); - } + unwind(t); } virtual void feedResultToContinuation(Thread* vmt, object continuation, From 4305fdc7f34b8406fb228e0b9cff159f31330e58 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 23 May 2009 16:15:06 -0600 Subject: [PATCH 040/172] begin dynamicWind implementation --- classpath/avian/Continuations.java | 71 +++++- src/builtin.cpp | 17 +- src/compile-x86.S | 46 ++-- src/compile.cpp | 339 +++++++++++++++++++++++------ src/types.def | 10 + 5 files changed, 398 insertions(+), 85 deletions(-) diff --git a/classpath/avian/Continuations.java b/classpath/avian/Continuations.java index 948b8b0bec..4074b28897 100644 --- a/classpath/avian/Continuations.java +++ b/classpath/avian/Continuations.java @@ -16,12 +16,77 @@ public abstract class Continuations { public static native T callWithCurrentContinuation (CallbackReceiver receiver) throws Exception; - public static native T dynamicWind(Runnable before, - Callable thunk, - Runnable after) throws Exception; + public static T dynamicWind(Runnable before, + Callable thunk, + Runnable after) + throws Exception + { + UnwindResult result = dynamicWind2(buffer, thunk, after); + if (result.continuation != null) { + after.run(); + if (result.exception != null) { + result.continuation.handleException(result.exception); + } else { + result.continuation.handleResult(result.value); + } + throw new AssertionError(); + } else { + return (T) result.value; + } + } + + private static native UnwindResult dynamicWind2(Runnable before, + Callable thunk, + Runnable after) + throws Exception; + + private static UnwindResult wind(Runnable before, + Callable thunk, + Runnable after) + throws Exception + { + before.run(); + + try { + return new UnwindResult(null, thunk.call(), null); + } finally { + after.run(); + } + } + + private static void rewind(Runnable before, + Callback continuation, + Object result, + Throwable exception) + throws Exception + { + before.run(); + + if (exception != null) { + continuation.handleException(exception); + } else { + continuation.handleResult(value); + } + + throw new AssertionError(); + } private static class Continuation implements Callback { public native void handleResult(T result); public native void handleException(Throwable exception); } + + private static class UnwindResult { + public final Callback continuation; + public final Object result; + public final Throwable exception; + + public UnwindResult(Callback continuation, Object result, + Throwable exception) + { + this.continuation = continuation; + this.result = result; + this.exception = exception; + } + } } diff --git a/src/builtin.cpp b/src/builtin.cpp index 6d3484bc68..33e5a489b5 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -849,9 +849,8 @@ Java_java_net_URL_00024ResourceInputStream_close(Thread*, jclass, jlong peer) } extern "C" JNIEXPORT void JNICALL -Avian_avian_Continuations_callWithCurrentContinuation(Thread* t, - object, - uintptr_t* arguments) +Avian_avian_Continuations_callWithCurrentContinuation +(Thread* t, object, uintptr_t* arguments) { t->m->processor->callWithCurrentContinuation (t, reinterpret_cast(*arguments)); @@ -859,6 +858,18 @@ Avian_avian_Continuations_callWithCurrentContinuation(Thread* t, abort(t); } +extern "C" JNIEXPORT void JNICALL +Avian_avian_Continuations_dynamicWind2 +(Thread* t, object, uintptr_t* arguments) +{ + t->m->processor->dynamicWind + (t, reinterpret_cast(arguments[0]), + reinterpret_cast(arguments[1]), + reinterpret_cast(arguments[2])); + + abort(t); +} + extern "C" JNIEXPORT void JNICALL Avian_avian_Continuations_00024Continuation_handleResult (Thread* t, object, uintptr_t* arguments) diff --git a/src/compile-x86.S b/src/compile-x86.S index 22cfd0f9fa..fb84ef37c3 100644 --- a/src/compile-x86.S +++ b/src/compile-x86.S @@ -23,11 +23,11 @@ #define THREAD_EXCEPTION_HANDLER 192 #define CONTINUATION_NEXT 8 -#define CONTINUATION_ADDRESS 24 -#define CONTINUATION_RETURN_ADDRESS_OFFSET 32 -#define CONTINUATION_FRAME_POINTER_OFFSET 40 -#define CONTINUATION_LENGTH 48 -#define CONTINUATION_BODY 56 +#define CONTINUATION_ADDRESS 32 +#define CONTINUATION_RETURN_ADDRESS_OFFSET 40 +#define CONTINUATION_FRAME_POINTER_OFFSET 48 +#define CONTINUATION_LENGTH 56 +#define CONTINUATION_BODY 64 .globl vmInvoke vmInvoke: @@ -145,22 +145,36 @@ LOCAL(vmInvoke_exit): popq %rbp ret -.globl vmCallWithContinuation -vmCallWithContinuation: +.globl vmJumpAndInvoke +vmJumpAndInvoke: // %rdi: thread // %rsi: address - // %rdx: targetObject - // %rcx: continuation - // %r8 : base - // %r9 : stack + // %rdx: base + // %rcx: stack + // %r8 : argumentFootprint + // %r9 : arguments - movq %rdi,%rbx - movq %r8,%rbp - movq %r9,%rsp + // set return address movq vmInvoke_returnAddress@GOTPCREL(%rip),%r10 movq %r10,(%rsp) - movq %rdx,8(%rsp) - movq %rcx,16(%rsp) + + // copy arguments into place + movq $0,%r11 + jmp LOCAL(vmJumpAndInvoke_argumentTest) + +LOCAL(vmJumpAndInvoke_argumentLoop): + movq (%r8,%r11,1),%r10 + movq %r10,8(%rsp,%r11,1) + addq $8,%r11 + +LOCAL(vmJumpAndInvoke_argumentTest): + cmpq %r8,%r11 + jb LOCAL(vmJumpAndInvoke_argumentLoop) + + movq %rdi,%rbx + movq %rdx,%rbp + movq %rcx,%rsp + jmp *%rsi #elif defined __i386__ diff --git a/src/compile.cpp b/src/compile.cpp index 3dfa33f232..9018808673 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -22,9 +22,9 @@ extern "C" uint64_t vmInvoke(void* thread, void* function, void* arguments, unsigned argumentFootprint, unsigned frameSize, unsigned returnType); -extern "C" uint64_t -vmCallWithContinuation(void* thread, void* function, void* targetObject, - object continuation, void* base, void* stack); +extern "C" void +vmJumpAndInvoke(void* thread, void* function, void* base, void* stack, + unsigned argumentFootprint, uintptr_t* arguments); extern "C" void vmCall(); @@ -1386,7 +1386,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, while (*targetIp == 0) { object method = methodForIp(t, ip); if (method) { - void* handler = findExceptionHandler(t, method, ip); + void* handler = findExceptionHandler(t, method, ip, forContinuation); if (handler) { *targetIp = handler; @@ -1406,7 +1406,9 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, t->arch->nextFrame(&stack, &base); ip = t->arch->frameIp(stack); - releaseLock(t, method, stack); + if (t->exception) { + releaseLock(t, method, stack); + } target = method; } @@ -1420,7 +1422,8 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, object method = continuationMethod(t, t->continuation); void* handler = findExceptionHandler - (t, method, continuationAddress(t, t->continuation)); + (t, method, continuationAddress(t, t->continuation), + forContinuation); if (handler) { t->exceptionHandler = handler; @@ -1433,7 +1436,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, t->exceptionOffset = localOffset(t, localSize(t, method), method) * BytesPerWord; break; - } else { + } else if (t->exception) { releaseLock(t, method, reinterpret_cast(t->continuation) + ContinuationBody @@ -1448,9 +1451,12 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, } object -makeCurrentContinuation(MyThread* t, void** targetIp, void** targetBase, - void** targetStack, unsigned* oldArgumentFootprint) +makeCurrentContinuation(MyThread* t, object context, void** targetIp, + void** targetBase, void** targetStack, + unsigned* oldArgumentFootprint) { + PROTECT(t, context); + void* ip = t->ip; void* base = t->base; void* stack = t->stack; @@ -1492,7 +1498,7 @@ makeCurrentContinuation(MyThread* t, void** targetIp, void** targetBase, + t->arch->argumentFootprint(methodParameterFootprint(t, method)); object c = makeContinuation - (t, 0, method, ip, + (t, 0, context, method, ip, ((frameSize + t->arch->returnAddressOffset() - t->arch->frameReturnAddressSize()) * BytesPerWord), @@ -5280,9 +5286,176 @@ walkContinuationBody(MyThread* t, Heap::Walker* w, object c, int start) } void -callWithContinuation(MyThread* t, object method, object this_, - object continuation, void* base, void* stack, - unsigned oldArgumentFootprint) +callContinuation(MyThread* t, object continuation, object result, + object exception, void* ip, void* base, void* stack) +{ + assert(t, t->exception == 0); + + t->trace->nativeMethod = 0; + t->trace->targetMethod = 0; + + t->continuation = continuation; + + if (exception) { + t->exception = exception; + + t->ip = ip; + t->base = base; + t->stack = stack; + + findUnwindTarget(t, &ip, &base, &stack); + } + + vmJump(ip, base, stack, t, reinterpret_cast(result), 0); +} + +uint8_t* +returnSpec(MyThread* t, object method) +{ + uint8_t* s = &byteArrayBody(t, methodSpec(t, method)); + while (*s and *s != ')') ++ s; + expect(t, *s == ')'); + return s + 1; +} + +bool +compatibleReturnType(MyThread* t, object oldMethod, object newMethod) +{ + if (oldMethod == newMethod) { + return true; + } else if (methodReturnCode(t, oldMethod) == methodReturnCode(t, newMethod)) + { + if (methodReturnCode(t, oldMethod) == ObjectField) { + uint8_t* oldSpec = returnSpec(t, oldMethod); + uint8_t* newSpec = returnSpec(t, newMethod); + + + } else { + return true; + } + } else { + return methodReturnCode(t, oldMethod) == VoidField; + } +} + +object +findUnwindContinuation(MyThread* t, object oldContinuation, + object newContinuation) +{ + +} + +object +findRewindContinuation(MyThread* t, object oldContinuation, + object newContinuation) +{ + +} + +void +callContinuation(MyThread* t, object continuation, object result, + object exception) +{ + enum { + Call, + Unwind, + Rewind, + Throw + } action; + + object nextContinuation = 0; + + if (t->continuation == null + or continuationContext(t, t->continuation) + != continuationContext(t, continuation)) + { + PROTECT(t, continuation); + PROTECT(t, result); + PROTECT(t, exception); + + if (not compatibleReturnType + (t, t->trace->originalMethod, continuationContextMethod + (t, continuationContext(t, t->continuation)))) + { + t->exception = makeIncompatibleContinuationException(t); + action = Throw; + } else { + nextContinuation = findUnwindContinuation + (t, t->continuation, continuation); + + if (nextContinuation) { + result = makeUnwindResult(t, continuation, result, exception); + action = Unwind; + } else { + nextContinuation = findRewindContinuation + (t, t->continuation, continuation); + + if (nextContinuation) { + action = Rewind; + + if (rewindMethod(t) == 0) { + const char* const className = "avian/Continuations"; + const char* const methodName = "rewind"; + const char* const methodSpec + = "(Ljava/lang/Runnable;Lavian/Callback;Ljava/lang/Object;" + "Ljava/lang/Throwable;)V"; + + object method = resolveMethod + (t, className, methodName, methodSpec); + + if (method) { + rewindMethod(t) == 0; + } else { + object message = makeString + (t, "%s %s not found in %s", + methodName, methodSpec, className); + + t->exception = makeNoSuchMethodError(t, message); + action = Throw; + } + } + } + } + } + } else { + action = Call; + } + + void* ip; + void* base; + void* stack; + findUnwindTarget(t, &ip, &base, &stack); + + switch (action) { + case Call: { + callContinuation + (t, unwindContinuation, result, exception, ip, base, stack); + } break; + + case Unwind: { + callContinuation(t, nextContinuation, result, 0, ip, base, stack); + } break; + + case Rewind: { + jumpAndInvoke + (t, rewindMethod(t), base, stack, oldArgumentFootprint, 3, + continuationContextBefore(t, nextContinuation), nextContinuation, + result, exception); + } break; + + case Throw: { + vmJump(ip, base, stack, t, 0, 0); + } break; + + default: + abort(t); + } +} + +void +jumpAndInvoke(MyThread* t, object method, void* base, void* stack, + unsigned oldArgumentFootprint, unsigned argumentCount, + ...) { t->trace->targetMethod = 0; @@ -5291,17 +5464,24 @@ callWithContinuation(MyThread* t, object method, object this_, } else { t->trace->nativeMethod = 0; } + + uintptr_t arguments[argumentCount]; + va_list a; va_start(a, argumentCount); + for (unsigned i = 0; i < argumentCount; ++i) { + arguments[i] = va_arg(a, uintptr_t); + } + va_end(a); - vmCallWithContinuation + vmJumpAndInvoke (t, reinterpret_cast(methodAddress(t, method)), - this_, - continuation, base, static_cast(stack) + oldArgumentFootprint - t->arch->argumentFootprint(methodParameterFootprint(t, method)) - t->arch->frameFooterSize() - - t->arch->frameReturnAddressSize()); + - t->arch->frameReturnAddressSize(), + argumentCount * BytesPerWord, + arguments); } class ArgumentList { @@ -5968,6 +6148,12 @@ class MyProcessor: public Processor { virtual void callWithCurrentContinuation(Thread* vmt, object receiver) { MyThread* t = static_cast(vmt); + object method = 0; + void* ip = 0; + void* base = 0; + void* stack = 0; + unsigned oldArgumentFootprint = 0; + { PROTECT(t, receiver); if (receiveMethod == 0) { @@ -5994,71 +6180,98 @@ class MyProcessor: public Processor { } if (LIKELY(t->exception == 0)) { - object method = findInterfaceMethod + method = findInterfaceMethod (t, receiveMethod, objectClass(t, receiver)); PROTECT(t, method); compile(t, ::codeAllocator(t), 0, method); - if (LIKELY(t->exception == 0)) { - void* ip; - void* base; - void* stack; - unsigned oldArgumentFootprint; - t->continuation = makeCurrentContinuation - (t, &ip, &base, &stack, &oldArgumentFootprint); - callWithContinuation - (t, method, receiver, t->continuation, base, stack, - oldArgumentFootprint); + if (LIKELY(t->exception == 0)) { + t->continuation = makeCurrentContinuation + (t, t->continuation + ? continuationContext(t, t->continuation) + : makeContinuationContext + (t, 0, 0, 0, 0, t->trace->originalMethod), + &ip, &base, &stack, &oldArgumentFootprint); } } } - unwind(t); + if (LIKELY(t->exception == 0)) { + jumpAndInvoke + (t, method, base, stack, oldArgumentFootprint, 2, receiver, + t->continuation); + } else { + unwind(t); + } + } + + virtual void dynamicWind(Thread* vmt, object before, object thunk, + object after) + { + MyThread* t = static_cast(vmt); + + void* ip = 0; + void* base = 0; + void* stack = 0; + unsigned oldArgumentFootprint = 0; + + { PROTECT(t, before); + PROTECT(t, thunk); + PROTECT(t, after); + + if (windMethod == 0) { + const char* const className = "avian/Continuations"; + const char* const methodName = "wind"; + const char* const methodSpec + = "(Ljava/lang/Runnable;Ljava/util/concurrent/Callable;" + "Ljava/lang/Runnable;)Ljava/lang/Object;"; + + windMethod = resolveMethod(t, className, methodName, methodSpec); + + if (windMethod == 0) { + object message = makeString + (t, "%s %s not found in %s", methodName, methodSpec, className); + t->exception = makeNoSuchMethodError(t, message); + } + } + + if (LIKELY(t->exception == 0)) { + object oldContext + = (t->continuation ? continuationContext(t, t->continuation) : 0); + + object context = makeContinuationContext + (t, oldContext, before, after, 0, t->trace->originalMethod); + + object continuation = makeCurrentContinuation + (t, context, &ip, &base, &stack, &oldArgumentFootprint); + + set(t, continuationContext(t, continuation), + ContinuationContextContinuation, continuation); + + t->continuation = continuation; + } + } + + if (LIKELY(t->exception == 0)) { + jumpAndInvoke + (t, method, base, stack, oldArgumentFootprint, 3, before, thunk, + after); + } else { + unwind(t); + } } virtual void feedResultToContinuation(Thread* vmt, object continuation, object result) { - MyThread* t = static_cast(vmt); - - assert(t, t->exception == 0); - - void* ip; - void* base; - void* stack; - findUnwindTarget(t, &ip, &base, &stack); - - t->trace->nativeMethod = 0; - t->trace->targetMethod = 0; - - t->continuation = continuation; - - vmJump(ip, base, stack, t, reinterpret_cast(result), 0); + callContinuation(static_cast(vmt), continuation, result, 0); } virtual void feedExceptionToContinuation(Thread* vmt, object continuation, object exception) { - MyThread* t = static_cast(vmt); - - assert(t, t->exception == 0); - - void* ip; - void* base; - void* stack; - findUnwindTarget(t, &ip, &base, &stack); - - t->trace->nativeMethod = 0; - t->trace->targetMethod = 0; - - t->continuation = continuation; - - t->exception = exception; - - findUnwindTarget(t, &ip, &base, &stack); - - vmJump(ip, base, stack, t, 0, 0); + callContinuation(static_cast(vmt), continuation, 0, exception); } virtual void walkContinuationBody(Thread* t, Heap::Walker* w, object o, diff --git a/src/types.def b/src/types.def index 9039dde46f..34fd77a985 100644 --- a/src/types.def +++ b/src/types.def @@ -104,14 +104,24 @@ (type array (noassert array object body)) +(type continuationContext + (object next) + (object before) + (object after) + (object continuation) + (object method)) + (type continuation avian/Continuations$Continuation (object next) + (object context) (object method) (void* address) (uintptr_t returnAddressOffset) (uintptr_t framePointerOffset) (array uintptr_t body)) +(type unwindResult avian/Continuations$UnwindResult) + (type callbackReceiver avian/CallbackReceiver) (type string java/lang/String) From 364f31b7852d19d8d6b7c09b07c2cad7b462458a Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 23 May 2009 19:49:14 -0600 Subject: [PATCH 041/172] finish initial sketch of dynamicWind implementation --- classpath/avian/Continuations.java | 12 +- src/compile.cpp | 313 +++++++++++++++++------------ src/machine.h | 6 + src/processor.h | 3 + src/types.def | 3 + 5 files changed, 200 insertions(+), 137 deletions(-) diff --git a/classpath/avian/Continuations.java b/classpath/avian/Continuations.java index 4074b28897..0953995320 100644 --- a/classpath/avian/Continuations.java +++ b/classpath/avian/Continuations.java @@ -21,27 +21,27 @@ public abstract class Continuations { Runnable after) throws Exception { - UnwindResult result = dynamicWind2(buffer, thunk, after); + UnwindResult result = dynamicWind2(before, thunk, after); if (result.continuation != null) { after.run(); if (result.exception != null) { result.continuation.handleException(result.exception); } else { - result.continuation.handleResult(result.value); + result.continuation.handleResult(result.result); } throw new AssertionError(); } else { - return (T) result.value; + return (T) result.result; } } private static native UnwindResult dynamicWind2(Runnable before, - Callable thunk, + Callable thunk, Runnable after) throws Exception; private static UnwindResult wind(Runnable before, - Callable thunk, + Callable thunk, Runnable after) throws Exception { @@ -65,7 +65,7 @@ public abstract class Continuations { if (exception != null) { continuation.handleException(exception); } else { - continuation.handleResult(value); + continuation.handleResult(result); } throw new AssertionError(); diff --git a/src/compile.cpp b/src/compile.cpp index 9018808673..8ae1b2c020 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -49,13 +49,14 @@ class MyThread: public Thread { public: class CallTrace { public: - CallTrace(MyThread* t): + CallTrace(MyThread* t, object method): t(t), base(t->base), stack(t->stack), continuation(t->continuation), - nativeMethod(0), + nativeMethod((methodFlags(t, method) & ACC_NATIVE) ? method : 0), targetMethod(0), + originalMethod(method), next(t->trace) { t->trace = this; @@ -77,6 +78,7 @@ class MyThread: public Thread { object continuation; object nativeMethod; object targetMethod; + object originalMethod; CallTrace* next; }; @@ -1371,7 +1373,7 @@ releaseLock(MyThread* t, object method, void* stack) void findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, - void** targetStack) + void** targetStack, unsigned* oldArgumentFootprint = 0) { void* ip = t->ip; void* base = t->base; @@ -1386,7 +1388,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, while (*targetIp == 0) { object method = methodForIp(t, ip); if (method) { - void* handler = findExceptionHandler(t, method, ip, forContinuation); + void* handler = findExceptionHandler(t, method, ip); if (handler) { *targetIp = handler; @@ -1418,12 +1420,16 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, *targetStack = static_cast(stack) + t->arch->frameReturnAddressSize(); + if (oldArgumentFootprint) { + *oldArgumentFootprint + = t->arch->argumentFootprint(methodParameterFootprint(t, target)); + } + while (t->continuation) { object method = continuationMethod(t, t->continuation); void* handler = findExceptionHandler - (t, method, continuationAddress(t, t->continuation), - forContinuation); + (t, method, continuationAddress(t, t->continuation)); if (handler) { t->exceptionHandler = handler; @@ -1548,6 +1554,9 @@ unwind(MyThread* t) object& objectPools(MyThread* t); +object& +rewindMethod(MyThread* t); + uintptr_t defaultThunk(MyThread* t); @@ -5309,15 +5318,33 @@ callContinuation(MyThread* t, object continuation, object result, vmJump(ip, base, stack, t, reinterpret_cast(result), 0); } -uint8_t* +int8_t* returnSpec(MyThread* t, object method) { - uint8_t* s = &byteArrayBody(t, methodSpec(t, method)); + int8_t* s = &byteArrayBody(t, methodSpec(t, method), 0); while (*s and *s != ')') ++ s; expect(t, *s == ')'); return s + 1; } +object +returnClass(MyThread* t, object method) +{ + int8_t* spec = returnSpec(t, method); + unsigned length = strlen(reinterpret_cast(spec)); + object name; + if (*spec == '[') { + name = makeByteArray(t, length + 1); + memcpy(&byteArrayBody(t, name, 0), spec, length); + } else { + assert(t, *spec == 'L'); + assert(t, spec[length - 1] == ';'); + name = makeByteArray(t, length - 1); + memcpy(&byteArrayBody(t, name, 0), spec + 1, length - 2); + } + return resolveClass(t, name); +} + bool compatibleReturnType(MyThread* t, object oldMethod, object newMethod) { @@ -5326,10 +5353,14 @@ compatibleReturnType(MyThread* t, object oldMethod, object newMethod) } else if (methodReturnCode(t, oldMethod) == methodReturnCode(t, newMethod)) { if (methodReturnCode(t, oldMethod) == ObjectField) { - uint8_t* oldSpec = returnSpec(t, oldMethod); - uint8_t* newSpec = returnSpec(t, newMethod); + PROTECT(t, newMethod); - + object oldClass = returnClass(t, oldMethod); + PROTECT(t, oldClass); + + object newClass = returnClass(t, newMethod); + + return isAssignableFrom(t, oldClass, newClass); } else { return true; } @@ -5338,120 +5369,6 @@ compatibleReturnType(MyThread* t, object oldMethod, object newMethod) } } -object -findUnwindContinuation(MyThread* t, object oldContinuation, - object newContinuation) -{ - -} - -object -findRewindContinuation(MyThread* t, object oldContinuation, - object newContinuation) -{ - -} - -void -callContinuation(MyThread* t, object continuation, object result, - object exception) -{ - enum { - Call, - Unwind, - Rewind, - Throw - } action; - - object nextContinuation = 0; - - if (t->continuation == null - or continuationContext(t, t->continuation) - != continuationContext(t, continuation)) - { - PROTECT(t, continuation); - PROTECT(t, result); - PROTECT(t, exception); - - if (not compatibleReturnType - (t, t->trace->originalMethod, continuationContextMethod - (t, continuationContext(t, t->continuation)))) - { - t->exception = makeIncompatibleContinuationException(t); - action = Throw; - } else { - nextContinuation = findUnwindContinuation - (t, t->continuation, continuation); - - if (nextContinuation) { - result = makeUnwindResult(t, continuation, result, exception); - action = Unwind; - } else { - nextContinuation = findRewindContinuation - (t, t->continuation, continuation); - - if (nextContinuation) { - action = Rewind; - - if (rewindMethod(t) == 0) { - const char* const className = "avian/Continuations"; - const char* const methodName = "rewind"; - const char* const methodSpec - = "(Ljava/lang/Runnable;Lavian/Callback;Ljava/lang/Object;" - "Ljava/lang/Throwable;)V"; - - object method = resolveMethod - (t, className, methodName, methodSpec); - - if (method) { - rewindMethod(t) == 0; - } else { - object message = makeString - (t, "%s %s not found in %s", - methodName, methodSpec, className); - - t->exception = makeNoSuchMethodError(t, message); - action = Throw; - } - } - } - } - } - } else { - action = Call; - } - - void* ip; - void* base; - void* stack; - findUnwindTarget(t, &ip, &base, &stack); - - switch (action) { - case Call: { - callContinuation - (t, unwindContinuation, result, exception, ip, base, stack); - } break; - - case Unwind: { - callContinuation(t, nextContinuation, result, 0, ip, base, stack); - } break; - - case Rewind: { - jumpAndInvoke - (t, rewindMethod(t), base, stack, oldArgumentFootprint, 3, - continuationContextBefore(t, nextContinuation), nextContinuation, - result, exception); - } break; - - case Throw: { - vmJump(ip, base, stack, t, 0, 0); - } break; - - default: - abort(t); - } -} - void jumpAndInvoke(MyThread* t, object method, void* base, void* stack, unsigned oldArgumentFootprint, unsigned argumentCount, @@ -5484,6 +5401,131 @@ jumpAndInvoke(MyThread* t, object method, void* base, void* stack, arguments); } +void +callContinuation(MyThread* t, object continuation, object result, + object exception) +{ + enum { + Call, + Unwind, + Rewind, + Throw + } action; + + object nextContinuation = 0; + + if (t->continuation == 0 + or continuationContext(t, t->continuation) + != continuationContext(t, continuation)) + { + PROTECT(t, continuation); + PROTECT(t, result); + PROTECT(t, exception); + + if (compatibleReturnType + (t, t->trace->originalMethod, continuationContextMethod + (t, continuationContext(t, t->continuation)))) + { + object oldContext; + object unwindContext; + + if (t->continuation) { + oldContext = continuationContext(t, t->continuation); + unwindContext = oldContext; + } else { + oldContext = 0; + unwindContext = 0; + } + + object rewindContext = 0; + + for (object newContext = continuationContext(t, continuation); + newContext; newContext = continuationContextNext(t, newContext)) + { + if (newContext == oldContext) { + unwindContext = 0; + break; + } else { + rewindContext = newContext; + } + } + + if (unwindContext + and continuationContextContinuation(t, unwindContext)) + { + nextContinuation = continuationContextContinuation(t, unwindContext); + result = makeUnwindResult(t, continuation, result, exception); + action = Unwind; + } else if (rewindContext + and continuationContextContinuation(t, rewindContext)) + { + nextContinuation = continuationContextContinuation(t, rewindContext); + action = Rewind; + + if (rewindMethod(t) == 0) { + PROTECT(t, nextContinuation); + + const char* const className = "avian/Continuations"; + const char* const methodName = "rewind"; + const char* const methodSpec + = "(Ljava/lang/Runnable;Lavian/Callback;Ljava/lang/Object;" + "Ljava/lang/Throwable;)V"; + + object method = resolveMethod + (t, className, methodName, methodSpec); + + if (method) { + rewindMethod(t) = method; + } else { + object message = makeString + (t, "%s %s not found in %s", + methodName, methodSpec, className); + + t->exception = makeNoSuchMethodError(t, message); + action = Throw; + } + } + } + } else { + t->exception = makeIncompatibleContinuationException(t); + action = Throw; + } + } else { + action = Call; + } + + void* ip; + void* base; + void* stack; + unsigned oldArgumentFootprint; + findUnwindTarget(t, &ip, &base, &stack, &oldArgumentFootprint); + + switch (action) { + case Call: { + callContinuation + (t, nextContinuation, result, exception, ip, base, stack); + } break; + + case Unwind: { + callContinuation(t, nextContinuation, result, 0, ip, base, stack); + } break; + + case Rewind: { + jumpAndInvoke + (t, rewindMethod(t), base, stack, oldArgumentFootprint, 3, + continuationContextBefore(t, nextContinuation), nextContinuation, + result, exception); + } break; + + case Throw: { + vmJump(ip, base, stack, t, 0, 0); + } break; + + default: + abort(t); + } +} + class ArgumentList { public: ArgumentList(Thread* t, uintptr_t* array, unsigned size, bool* objectMask, @@ -5618,11 +5660,7 @@ invoke(Thread* thread, object method, ArgumentList* arguments) uint64_t result; - { MyThread::CallTrace trace(t); - - if (methodFlags(t, method) & ACC_NATIVE) { - trace.nativeMethod = method; - } + { MyThread::CallTrace trace(t, method); assert(t, arguments->position == arguments->size); @@ -5745,6 +5783,8 @@ class MyProcessor: public Processor { staticTableArray(0), virtualThunks(0), receiveMethod(0), + windMethod(0), + rewindMethod(0), codeAllocator(s, 0, 0) { } @@ -5839,12 +5879,15 @@ class MyProcessor: public Processor { v->visit(&staticTableArray); v->visit(&virtualThunks); v->visit(&receiveMethod); + v->visit(&windMethod); + v->visit(&rewindMethod); } for (MyThread::CallTrace* trace = t->trace; trace; trace = trace->next) { v->visit(&(trace->continuation)); v->visit(&(trace->nativeMethod)); v->visit(&(trace->targetMethod)); + v->visit(&(trace->originalMethod)); } v->visit(&(t->continuation)); @@ -6255,7 +6298,7 @@ class MyProcessor: public Processor { if (LIKELY(t->exception == 0)) { jumpAndInvoke - (t, method, base, stack, oldArgumentFootprint, 3, before, thunk, + (t, windMethod, base, stack, oldArgumentFootprint, 3, before, thunk, after); } else { unwind(t); @@ -6296,6 +6339,8 @@ class MyProcessor: public Processor { object staticTableArray; object virtualThunks; object receiveMethod; + object windMethod; + object rewindMethod; SegFaultHandler segFaultHandler; FixedAllocator codeAllocator; }; @@ -6906,6 +6951,12 @@ objectPools(MyThread* t) return processor(t)->objectPools; } +object& +rewindMethod(MyThread* t) +{ + return processor(t)->rewindMethod; +} + uintptr_t defaultThunk(MyThread* t) { diff --git a/src/machine.h b/src/machine.h index 024ac84f12..67e2dbf071 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1726,6 +1726,12 @@ makeInterruptedException(Thread* t) return makeInterruptedException(t, 0, makeTrace(t), 0); } +inline object +makeIncompatibleContinuationException(Thread* t) +{ + return makeIncompatibleContinuationException(t, 0, makeTrace(t), 0); +} + inline object makeStackOverflowError(Thread* t) { diff --git a/src/processor.h b/src/processor.h index 7777953580..13d4328d5f 100644 --- a/src/processor.h +++ b/src/processor.h @@ -136,6 +136,9 @@ class Processor { virtual void callWithCurrentContinuation(Thread* t, object receiver) = 0; + virtual void + dynamicWind(Thread* t, object before, object thunk, object after) = 0; + virtual void feedResultToContinuation(Thread* t, object continuation, object result) = 0; diff --git a/src/types.def b/src/types.def index 34fd77a985..c3d711c18a 100644 --- a/src/types.def +++ b/src/types.def @@ -175,6 +175,9 @@ (type exceptionInInitializerError java/lang/ExceptionInInitializerError) +(type incompatibleContinuationException + avian/IncompatibleContinuationException) + (type number java/lang/Number) (type byte java/lang/Byte) From 18ec68c7b74d7cf651b237196ba17d4cdb1b4d5e Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 24 May 2009 00:31:53 -0600 Subject: [PATCH 042/172] fix word order when pushing 64-bit values as arguments to helper thunks in appendCombine --- src/compiler.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/compiler.cpp b/src/compiler.cpp index e4fe2aab1b..e8cd1e0b40 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -2377,7 +2377,7 @@ class CallEvent: public Event { ((flags & Compiler::Aligned) ? AlignedCall : Call, BytesPerWord, &typeMask, &planRegisterMask, &thunk); - assert(c, thunk == 0); + assert(c, not thunk); addRead(c, this, address, read (c, SiteMask @@ -3300,15 +3300,15 @@ pushWord(Context* c, Value* v) } Value* -push(Context* c, unsigned footprint, Value* v) +push(Context* c, unsigned footprint, Value* v, bool reverse) { assert(c, footprint); - bool bigEndian = c->arch->bigEndian(); + bool lowFirst = reverse xor c->arch->bigEndian(); Value* low = v; - if (not bigEndian) { + if (lowFirst) { v = pushWord(c, v); } @@ -3327,7 +3327,7 @@ push(Context* c, unsigned footprint, Value* v) high = 0; } - if (bigEndian) { + if (not lowFirst) { v = pushWord(c, v); } @@ -3493,8 +3493,8 @@ appendCombine(Context* c, TernaryOperation type, if (thunk) { Stack* oldStack = c->stack; - ::push(c, ceiling(secondSize, BytesPerWord), second); - ::push(c, ceiling(firstSize, BytesPerWord), first); + ::push(c, ceiling(secondSize, BytesPerWord), second, false); + ::push(c, ceiling(firstSize, BytesPerWord), first, false); Stack* argumentStack = c->stack; c->stack = oldStack; @@ -3724,7 +3724,7 @@ class BranchEvent: public Event { c->arch->plan(type, BytesPerWord, &typeMask, ®isterMask, &thunk); - assert(c, thunk == 0); + assert(c, not thunk); addRead(c, this, address, read (c, SiteMask(typeMask, registerMask, AnyFrameIndex))); @@ -5111,7 +5111,7 @@ class MyCompiler: public Compiler { } virtual void push(unsigned footprint, Operand* value) { - ::push(&c, footprint, static_cast(value)); + ::push(&c, footprint, static_cast(value), true); } virtual void save(unsigned footprint, Operand* value) { From 9dbea21ec40ea279145fbaaa1846f30c3ad6da0c Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 24 May 2009 00:32:49 -0600 Subject: [PATCH 043/172] add continuation support to 32-bit section of compile-x86.S --- src/compile-x86.S | 161 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 140 insertions(+), 21 deletions(-) diff --git a/src/compile-x86.S b/src/compile-x86.S index fb84ef37c3..befa836881 100644 --- a/src/compile-x86.S +++ b/src/compile-x86.S @@ -153,6 +153,10 @@ vmJumpAndInvoke: // %rcx: stack // %r8 : argumentFootprint // %r9 : arguments + + movq %rdi,%rbx + movq %rdx,%rbp + movq %rcx,%rsp // set return address movq vmInvoke_returnAddress@GOTPCREL(%rip),%r10 @@ -163,29 +167,38 @@ vmJumpAndInvoke: jmp LOCAL(vmJumpAndInvoke_argumentTest) LOCAL(vmJumpAndInvoke_argumentLoop): - movq (%r8,%r11,1),%r10 + movq (%r9,%r11,1),%r10 movq %r10,8(%rsp,%r11,1) addq $8,%r11 LOCAL(vmJumpAndInvoke_argumentTest): cmpq %r8,%r11 jb LOCAL(vmJumpAndInvoke_argumentLoop) - - movq %rdi,%rbx - movq %rdx,%rbp - movq %rcx,%rsp jmp *%rsi #elif defined __i386__ + +#define THREAD_CONTINUATION 96 +#define THREAD_EXCEPTION 36 +#define THREAD_EXCEPTION_STACK 100 +#define THREAD_EXCEPTION_OFFSET 104 +#define THREAD_EXCEPTION_HANDLER 108 -# if defined __APPLE__ || defined __MINGW32__ || defined __CYGWIN32__ +#define CONTINUATION_NEXT 4 +#define CONTINUATION_ADDRESS 16 +#define CONTINUATION_RETURN_ADDRESS_OFFSET 20 +#define CONTINUATION_FRAME_POINTER_OFFSET 24 +#define CONTINUATION_LENGTH 28 +#define CONTINUATION_BODY 32 + +#if defined __APPLE__ || defined __MINGW32__ || defined __CYGWIN32__ .globl _vmInvoke _vmInvoke: -# else +#else .globl vmInvoke vmInvoke: -# endif +#endif pushl %ebp movl %esp,%ebp @@ -214,25 +227,89 @@ vmInvoke: // copy arguments into place movl $0,%ecx movl 16(%ebp),%edx - jmp LOCAL(test) + jmp LOCAL(vmInvoke_argumentTest) -LOCAL(loop): +LOCAL(vmInvoke_argumentLoop): movl (%edx,%ecx,1),%eax movl %eax,(%esp,%ecx,1) addl $4,%ecx -LOCAL(test): +LOCAL(vmInvoke_argumentTest): cmpl 20(%ebp),%ecx - jb LOCAL(loop) + jb LOCAL(vmInvoke_argumentLoop) // call function call *12(%ebp) - + +.globl vmInvoke_returnAddress +vmInvoke_returnAddress: // restore stack pointer and callee-saved registers movl %ebp,%ecx subl $16,%ecx movl %ecx,%esp + // call the next continuation, if any + movl THREAD_CONTINUATION(%ebx),%ecx + cmpl $0,%ecx + je LOCAL(vmInvoke_exit) + + movl CONTINUATION_LENGTH(%ecx),%esi + shll $3,%esi + subl %esi,%esp + subl $48,%esp + + leal CONTINUATION_BODY(%ecx),%edi + + push %eax + push %edx + + movl $0,%edx + jmp LOCAL(vmInvoke_continuationTest) + +LOCAL(vmInvoke_continuationLoop): + movl (%edi,%edx,1),%eax + movl %eax,(%esp,%edx,1) + addl $8,%edx + +LOCAL(vmInvoke_continuationTest): + cmpl %esi,%edx + jb LOCAL(vmInvoke_continuationLoop) + + pop %edx + pop %eax + + movl CONTINUATION_RETURN_ADDRESS_OFFSET(%ecx),%edi + call LOCAL(getPC) + addl $_GLOBAL_OFFSET_TABLE_,%esi + movl vmInvoke_returnAddress@GOT(%esi),%esi + movl %esi,(%esp,%edi,1) + + movl CONTINUATION_FRAME_POINTER_OFFSET(%ecx),%edi + movl %ebp,(%esp,%edi,1) + addl %esp,%edi + movl %edi,%ebp + + movl CONTINUATION_NEXT(%ecx),%edi + movl %edi,THREAD_CONTINUATION(%ebx) + + // call the continuation unless we're handling an exception + movl THREAD_EXCEPTION(%ebx),%esi + cmpl $0,%esi + jne LOCAL(vmInvoke_handleException) + + jmp *CONTINUATION_ADDRESS(%ecx) + +LOCAL(vmInvoke_handleException): + // we're handling an exception - call the exception handler instead + movl $0,THREAD_EXCEPTION(%ebx) + movl THREAD_EXCEPTION_STACK(%ebx),%esp + movl THREAD_EXCEPTION_OFFSET(%ebx),%edi + movl %esi,(%esp,%edi,1) + + jmp *THREAD_EXCEPTION_HANDLER(%ebx) + +LOCAL(vmInvoke_exit): + // restore callee-saved registers movl 0(%esp),%ebx movl 4(%esp),%esi movl 8(%esp),%edi @@ -242,22 +319,64 @@ LOCAL(test): addl $16,%esp -LOCAL(void): +LOCAL(vmInvoke_void): cmpl $VOID_TYPE,%ecx - jne LOCAL(int64) - jmp LOCAL(exit) + jne LOCAL(vmInvoke_int64) + jmp LOCAL(vmInvoke_return) -LOCAL(int64): +LOCAL(vmInvoke_int64): cmpl $INT64_TYPE,%ecx - jne LOCAL(int32) - jmp LOCAL(exit) + jne LOCAL(vmInvoke_int32) + jmp LOCAL(vmInvoke_return) -LOCAL(int32): +LOCAL(vmInvoke_int32): movl $0,%edx -LOCAL(exit): +LOCAL(vmInvoke_return): popl %ebp ret + +LOCAL(getPC): + movl (%esp),%esi + ret + +.globl vmJumpAndInvoke +vmJumpAndInvoke: + // 8(%ebp): thread + // 12(%ebp): address + // 16(%ebp): base + // 20(%ebp): stack + // 24(%ebp): argumentFootprint + // 28(%ebp): arguments + + movl 8(%ebp),%ebx + movl 20(%ebp),%esp + + // set return address + call LOCAL(getPC) + addl $_GLOBAL_OFFSET_TABLE_,%esi + movl vmInvoke_returnAddress@GOT(%esi),%esi + movl %esi,(%esp) + + // copy arguments into place + movl $0,%ecx + movl 24(%ebp),%esi + movl 28(%ebp),%eax + jmp LOCAL(vmJumpAndInvoke_argumentTest) + +LOCAL(vmJumpAndInvoke_argumentLoop): + movl (%eax,%ecx,1),%edx + movl %edx,8(%esp,%ecx,1) + addl $8,%ecx + +LOCAL(vmJumpAndInvoke_argumentTest): + cmpl %esi,%ecx + jb LOCAL(vmJumpAndInvoke_argumentLoop) + + movl 12(%ebp),%esi + movl 16(%ebp),%ebp + + jmp *%esi #else # error unsupported platform From e80401ed102e0520951548c848aa493e95d4f259 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 24 May 2009 11:18:17 -0600 Subject: [PATCH 044/172] vmJumpAndInvoke bugfixes --- src/compile-x86.S | 48 ++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/src/compile-x86.S b/src/compile-x86.S index befa836881..a16753d007 100644 --- a/src/compile-x86.S +++ b/src/compile-x86.S @@ -155,12 +155,10 @@ vmJumpAndInvoke: // %r9 : arguments movq %rdi,%rbx - movq %rdx,%rbp - movq %rcx,%rsp // set return address movq vmInvoke_returnAddress@GOTPCREL(%rip),%r10 - movq %r10,(%rsp) + movq %r10,(%rcx) // copy arguments into place movq $0,%r11 @@ -168,12 +166,15 @@ vmJumpAndInvoke: LOCAL(vmJumpAndInvoke_argumentLoop): movq (%r9,%r11,1),%r10 - movq %r10,8(%rsp,%r11,1) + movq %r10,8(%rcx,%r11,1) addq $8,%r11 LOCAL(vmJumpAndInvoke_argumentTest): cmpq %r8,%r11 jb LOCAL(vmJumpAndInvoke_argumentLoop) + + movq %rdx,%rbp + movq %rcx,%rsp jmp *%rsi @@ -342,40 +343,41 @@ LOCAL(getPC): .globl vmJumpAndInvoke vmJumpAndInvoke: - // 8(%ebp): thread - // 12(%ebp): address - // 16(%ebp): base - // 20(%ebp): stack - // 24(%ebp): argumentFootprint - // 28(%ebp): arguments + // 4(%esp): thread + // 8(%esp): address + // 12(%esp): base + // 16(%esp): stack + // 20(%esp): argumentFootprint + // 24(%esp): arguments - movl 8(%ebp),%ebx - movl 20(%ebp),%esp + movl 16(%esp),%ecx // set return address call LOCAL(getPC) addl $_GLOBAL_OFFSET_TABLE_,%esi movl vmInvoke_returnAddress@GOT(%esi),%esi - movl %esi,(%esp) + movl %esi,(%ecx) // copy arguments into place - movl $0,%ecx - movl 24(%ebp),%esi - movl 28(%ebp),%eax + movl $0,%esi + movl 20(%esp),%edx + movl 24(%esp),%eax jmp LOCAL(vmJumpAndInvoke_argumentTest) LOCAL(vmJumpAndInvoke_argumentLoop): - movl (%eax,%ecx,1),%edx - movl %edx,8(%esp,%ecx,1) - addl $8,%ecx + movl (%eax,%esi,1),%edi + movl %edi,4(%ecx,%esi,1) + addl $4,%esi LOCAL(vmJumpAndInvoke_argumentTest): - cmpl %esi,%ecx + cmpl %edx,%esi jb LOCAL(vmJumpAndInvoke_argumentLoop) - movl 12(%ebp),%esi - movl 16(%ebp),%ebp - + movl 4(%esp),%ebx + movl 8(%esp),%esi + movl 12(%esp),%ebp + movl %ecx,%esp + jmp *%esi #else From 03e7a61bfdcfdc7115e61eba6740051d3dd83549 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 24 May 2009 18:20:50 -0600 Subject: [PATCH 045/172] add test/DynamicWind.java --- test/DynamicWind.java | 305 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 test/DynamicWind.java diff --git a/test/DynamicWind.java b/test/DynamicWind.java new file mode 100644 index 0000000000..81838f0630 --- /dev/null +++ b/test/DynamicWind.java @@ -0,0 +1,305 @@ +import static avian.Continuations.callWithCurrentContinuation; +import static avian.Continuations.dynamicWind; + +import avian.CallbackReceiver; +import avian.Callback; + +import java.util.concurrent.Callable; + +public class DynamicWind { + private int before; + private int task; + private int after; + private int continuationCount; + private Callback continuationReference; + + private static void expect(boolean v) { + if (! v) throw new RuntimeException(); + } + + private void unwindTest(final Callable unwind) throws Exception { + try { + expect(dynamicWind(new Runnable() { + public void run() { + System.out.println("unwindTest before"); + + expect(before == 0); + expect(task == 0); + expect(after == 0); + + before = 1; + } + }, new Callable() { + public Integer call() throws Exception { + System.out.println("unwindTest thunk"); + + expect(before == 1); + expect(task == 0); + expect(after == 0); + + task = 1; + + return unwind.call(); + } + }, + new Runnable() { + public void run() { + System.out.println("unwindTest after"); + + expect(before == 1); + expect(task == 1); + expect(after == 0); + + after = 1; + } + }) == 42); + } catch (MyException e) { + e.printStackTrace(); + } + + expect(before == 1); + expect(task == 1); + expect(after == 1); + } + + private void normalUnwind() throws Exception { + unwindTest(new Callable() { + public Integer call() { + return 42; + } + }); + } + + private void exceptionUnwind() throws Exception { + unwindTest(new Callable() { + public Integer call() throws Exception { + throw new MyException(); + } + }); + } + + private void continuationUnwindTest(final CallbackReceiver receiver) + throws Exception + { + try { + expect(callWithCurrentContinuation(new CallbackReceiver() { + public Integer receive(final Callback continuation) + throws Exception + { + unwindTest(new Callable() { + public Integer call() throws Exception { + return receiver.receive(continuation); + } + }); + throw new AssertionError(); + } + }) == 42); + } catch (MyException e) { + e.printStackTrace(); + } + + expect(before == 1); + expect(task == 1); + expect(after == 1); + } + + private void continuationResultUnwind() throws Exception { + continuationUnwindTest(new CallbackReceiver() { + public Integer receive(final Callback continuation) { + continuation.handleResult(42); + throw new AssertionError(); + } + }); + } + + private void continuationExceptionUnwind() throws Exception { + continuationUnwindTest(new CallbackReceiver() { + public Integer receive(final Callback continuation) { + continuation.handleException(new MyException()); + throw new AssertionError(); + } + }); + } + + private void rewindTest(final Callable unwind, Runnable rewind) + throws Exception + { + int value; + try { + value = dynamicWind(new Runnable() { + public void run() { + expect(before == continuationCount); + expect(task == 0); + expect(after == 0); + + ++ before; + } + }, new Callable() { + public Integer call() throws Exception { + expect(before == 1); + expect(task == 0); + expect(after == 0); + + task = 1; + + return callWithCurrentContinuation + (new CallbackReceiver() { + public Integer receive(final Callback continuation) + throws Exception + { + continuationReference = continuation; + return unwind.call(); + } + }); + } + }, new Runnable() { + public void run() { + expect(before == continuationCount + 1); + expect(task == 1); + expect(after == continuationCount); + + ++ after; + } + }); + } catch (MyException e) { + value = e.value; + } + + expect(value == continuationCount); + + if (value == 0) { + expect(before == 1); + expect(task == 1); + expect(after == 1); + + continuationCount = 1; + rewind.run(); + throw new AssertionError(); + } else { + expect(value == 1); + expect(before == 2); + expect(task == 1); + expect(after == 2); + } + } + + private void continuationResultRewind() throws Exception { + rewindTest(new Callable() { + public Integer call() { + return 0; + } + }, new Runnable() { + public void run() { + continuationReference.handleResult(1); + } + }); + } + + private void continuationExceptionRewind() throws Exception { + rewindTest(new Callable() { + public Integer call() throws Exception { + throw new MyException(0); + } + }, new Runnable() { + public void run() { + continuationReference.handleException(new MyException(1)); + } + }); + } + + private void continuationResultUnwindAndRewind() throws Exception { + rewindTest(new Callable() { + public Integer call() { + return 0; + } + }, new Runnable() { + public void run() { + try { + new DynamicWind().unwindTest(new Callable() { + public Integer call() { + continuationReference.handleResult(1); + throw new AssertionError(); + } + }); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }); + } + + private void continuationExceptionUnwindAndRewind() throws Exception { + rewindTest(new Callable() { + public Integer call() throws Exception { + throw new MyException(0); + } + }, new Runnable() { + public void run() { + try { + new DynamicWind().unwindTest(new Callable() { + public Integer call() { + continuationReference.handleException(new MyException(1)); + throw new AssertionError(); + } + }); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }); + } + + private void continuationResultUnwindAndRewindWithShared() throws Exception { + unwindTest(new Callable() { + public Integer call() throws Exception { + new DynamicWind().continuationResultUnwindAndRewind(); + return 42; + } + }); + } + + private void continuationExceptionUnwindAndRewindWithShared() + throws Exception + { + unwindTest(new Callable() { + public Integer call() throws Exception { + new DynamicWind().continuationExceptionUnwindAndRewind(); + return 42; + } + }); + } + + public static void main(String[] args) throws Exception { + new DynamicWind().normalUnwind(); + + new DynamicWind().exceptionUnwind(); + + new DynamicWind().continuationResultUnwind(); + + new DynamicWind().continuationExceptionUnwind(); + + new DynamicWind().continuationResultRewind(); + + new DynamicWind().continuationExceptionRewind(); + + new DynamicWind().continuationResultUnwindAndRewind(); + + new DynamicWind().continuationExceptionUnwindAndRewind(); + + new DynamicWind().continuationResultUnwindAndRewindWithShared(); + + new DynamicWind().continuationExceptionUnwindAndRewindWithShared(); + } + + private static class MyException extends Exception { + public final int value; + + public MyException() { + this(0); + } + + public MyException(int value) { + this.value = value; + } + } +} From d11af47dca0b07bd7649b8caa23fa17153883277 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 24 May 2009 18:21:19 -0600 Subject: [PATCH 046/172] add classpath/avian/IncompatibleContinuationException.java --- .../IncompatibleContinuationException.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 classpath/avian/IncompatibleContinuationException.java diff --git a/classpath/avian/IncompatibleContinuationException.java b/classpath/avian/IncompatibleContinuationException.java new file mode 100644 index 0000000000..49641c0f27 --- /dev/null +++ b/classpath/avian/IncompatibleContinuationException.java @@ -0,0 +1,21 @@ +/* Copyright (c) 2009, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package avian; + +public class IncompatibleContinuationException extends Exception { + public IncompatibleContinuationException(String message) { + super(message); + } + + public IncompatibleContinuationException() { + super(); + } +} From af59c85deb02a6554cfa2114573f5edb207fdc4a Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 24 May 2009 18:22:36 -0600 Subject: [PATCH 047/172] various bugfixes --- src/compile-x86.S | 8 ++++---- src/compile.cpp | 21 +++++++++++++++++++-- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/compile-x86.S b/src/compile-x86.S index a16753d007..d52d3ac68f 100644 --- a/src/compile-x86.S +++ b/src/compile-x86.S @@ -255,9 +255,9 @@ vmInvoke_returnAddress: je LOCAL(vmInvoke_exit) movl CONTINUATION_LENGTH(%ecx),%esi - shll $3,%esi + shll $2,%esi subl %esi,%esp - subl $48,%esp + subl $16,%esp leal CONTINUATION_BODY(%ecx),%edi @@ -269,8 +269,8 @@ vmInvoke_returnAddress: LOCAL(vmInvoke_continuationLoop): movl (%edi,%edx,1),%eax - movl %eax,(%esp,%edx,1) - addl $8,%edx + movl %eax,8(%esp,%edx,1) + addl $4,%edx LOCAL(vmInvoke_continuationTest): cmpl %esi,%edx diff --git a/src/compile.cpp b/src/compile.cpp index 8ae1b2c020..29eaac78c1 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -5476,6 +5476,12 @@ callContinuation(MyThread* t, object continuation, object result, if (method) { rewindMethod(t) = method; + + compile(t, ::codeAllocator(t), 0, method); + + if (UNLIKELY(t->exception)) { + action = Throw; + } } else { object message = makeString (t, "%s %s not found in %s", @@ -5795,6 +5801,15 @@ class MyProcessor: public Processor { MyThread(m, javaThread, static_cast(parent)); t->init(); + if (false) { + fprintf(stderr, "%d\n", difference(&(t->continuation), t)); + fprintf(stderr, "%d\n", difference(&(t->exception), t)); + fprintf(stderr, "%d\n", difference(&(t->exceptionStack), t)); + fprintf(stderr, "%d\n", difference(&(t->exceptionOffset), t)); + fprintf(stderr, "%d\n", difference(&(t->exceptionHandler), t)); + exit(0); + } + return t; } @@ -6268,11 +6283,13 @@ class MyProcessor: public Processor { const char* const methodName = "wind"; const char* const methodSpec = "(Ljava/lang/Runnable;Ljava/util/concurrent/Callable;" - "Ljava/lang/Runnable;)Ljava/lang/Object;"; + "Ljava/lang/Runnable;)Lavian/Continuations$UnwindResult;"; windMethod = resolveMethod(t, className, methodName, methodSpec); - if (windMethod == 0) { + if (windMethod) { + compile(t, ::codeAllocator(t), 0, windMethod); + } else { object message = makeString (t, "%s %s not found in %s", methodName, methodSpec, className); t->exception = makeNoSuchMethodError(t, message); From dc523fe6eb383ef2c5b5e57cf175e87fc5741d19 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 24 May 2009 18:57:59 -0600 Subject: [PATCH 048/172] load eax and edx in 32-bit vmJump --- src/x86.S | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/x86.S b/src/x86.S index 95889873bb..67b31f872e 100644 --- a/src/x86.S +++ b/src/x86.S @@ -208,11 +208,13 @@ _vmJump: .globl vmJump vmJump: # endif - movl 4(%esp),%eax + movl 4(%esp),%esi movl 8(%esp),%ebp movl 16(%esp),%ebx + movl 20(%esp),%eax + movl 24(%esp),%edx movl 12(%esp),%esp - jmp *%eax + jmp *%esi #else # error unsupported platform From c2bd828cc187afde3d2ba0f8969b58f2d3660186 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 24 May 2009 18:58:45 -0600 Subject: [PATCH 049/172] call the right continuation in callContinuation --- src/compile.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index 29eaac78c1..10623c53ac 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -5508,8 +5508,7 @@ callContinuation(MyThread* t, object continuation, object result, switch (action) { case Call: { - callContinuation - (t, nextContinuation, result, exception, ip, base, stack); + callContinuation(t, continuation, result, exception, ip, base, stack); } break; case Unwind: { From 92aea95b36f42977b480076bd057c5b03d97b5ea Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 24 May 2009 22:27:50 -0600 Subject: [PATCH 050/172] continuation bugfixes --- src/compile-x86.S | 10 +++--- src/compile.cpp | 88 +++++++++++++++++++++++------------------------ 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/src/compile-x86.S b/src/compile-x86.S index d52d3ac68f..74381bf061 100644 --- a/src/compile-x86.S +++ b/src/compile-x86.S @@ -18,7 +18,7 @@ #define THREAD_CONTINUATION 168 #define THREAD_EXCEPTION 64 -#define THREAD_EXCEPTION_STACK 176 +#define THREAD_EXCEPTION_STACK_ADJUSTMENT 176 #define THREAD_EXCEPTION_OFFSET 184 #define THREAD_EXCEPTION_HANDLER 192 @@ -124,7 +124,8 @@ LOCAL(vmInvoke_continuationTest): LOCAL(vmInvoke_handleException): // we're handling an exception - call the exception handler instead movq $0,THREAD_EXCEPTION(%rbx) - movq THREAD_EXCEPTION_STACK(%rbx),%rsp + movq THREAD_EXCEPTION_STACK_ADJUSTMENT(%rbx),%rdi + subq %rdi,%rsp movq THREAD_EXCEPTION_OFFSET(%rbx),%rdi movq %rsi,(%rsp,%rdi,1) @@ -182,7 +183,7 @@ LOCAL(vmJumpAndInvoke_argumentTest): #define THREAD_CONTINUATION 96 #define THREAD_EXCEPTION 36 -#define THREAD_EXCEPTION_STACK 100 +#define THREAD_EXCEPTION_STACK_ADJUSTMENT 100 #define THREAD_EXCEPTION_OFFSET 104 #define THREAD_EXCEPTION_HANDLER 108 @@ -303,7 +304,8 @@ LOCAL(vmInvoke_continuationTest): LOCAL(vmInvoke_handleException): // we're handling an exception - call the exception handler instead movl $0,THREAD_EXCEPTION(%ebx) - movl THREAD_EXCEPTION_STACK(%ebx),%esp + movl THREAD_EXCEPTION_STACK_ADJUSTMENT(%ebx),%edi + subl %edi,%esp movl THREAD_EXCEPTION_OFFSET(%ebx),%edi movl %esi,(%esp,%edi,1) diff --git a/src/compile.cpp b/src/compile.cpp index 10623c53ac..f954b76143 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -88,7 +88,7 @@ class MyThread: public Thread { base(0), stack(0), continuation(0), - exceptionStack(0), + exceptionStackAdjustment(0), exceptionOffset(0), exceptionHandler(0), tailAddress(0), @@ -105,7 +105,7 @@ class MyThread: public Thread { void* base; void* stack; object continuation; - void* exceptionStack; + uintptr_t exceptionStackAdjustment; uintptr_t exceptionOffset; void* exceptionHandler; void* tailAddress; @@ -1426,43 +1426,43 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, } while (t->continuation) { - object method = continuationMethod(t, t->continuation); + object c = t->continuation; + + object method = continuationMethod(t, c); void* handler = findExceptionHandler - (t, method, continuationAddress(t, t->continuation)); + (t, method, continuationAddress(t, c)); if (handler) { t->exceptionHandler = handler; - t->exceptionStack = static_cast(*targetStack) - + t->arch->argumentFootprint(methodParameterFootprint(t, target)) - - t->arch->argumentFootprint(methodParameterFootprint(t, method)) - - stackOffsetFromFrame(t, method); + t->exceptionStackAdjustment + = (stackOffsetFromFrame(t, method) + - ((continuationFramePointerOffset(t, c) / BytesPerWord) + - t->arch->framePointerOffset() + + t->arch->frameReturnAddressSize())) * BytesPerWord; t->exceptionOffset = localOffset(t, localSize(t, method), method) * BytesPerWord; break; } else if (t->exception) { releaseLock(t, method, - reinterpret_cast(t->continuation) + reinterpret_cast(c) + ContinuationBody - + continuationReturnAddressOffset(t, t->continuation) + + continuationReturnAddressOffset(t, c) - t->arch->returnAddressOffset()); } - t->continuation = continuationNext(t, t->continuation); + t->continuation = continuationNext(t, c); } } } } object -makeCurrentContinuation(MyThread* t, object context, void** targetIp, - void** targetBase, void** targetStack, - unsigned* oldArgumentFootprint) +makeCurrentContinuation(MyThread* t, void** targetIp, void** targetBase, + void** targetStack, unsigned* oldArgumentFootprint) { - PROTECT(t, context); - void* ip = t->ip; void* base = t->base; void* stack = t->stack; @@ -1470,6 +1470,11 @@ makeCurrentContinuation(MyThread* t, object context, void** targetIp, ip = t->arch->frameIp(stack); } + object context = t->continuation + ? continuationContext(t, t->continuation) + : makeContinuationContext(t, 0, 0, 0, 0, t->trace->originalMethod); + PROTECT(t, context); + object target = t->trace->targetMethod; PROTECT(t, target); @@ -5300,9 +5305,6 @@ callContinuation(MyThread* t, object continuation, object result, { assert(t, t->exception == 0); - t->trace->nativeMethod = 0; - t->trace->targetMethod = 0; - t->continuation = continuation; if (exception) { @@ -5313,8 +5315,13 @@ callContinuation(MyThread* t, object continuation, object result, t->stack = stack; findUnwindTarget(t, &ip, &base, &stack); + + t->ip = 0; } + t->trace->nativeMethod = 0; + t->trace->targetMethod = 0; + vmJump(ip, base, stack, t, reinterpret_cast(result), 0); } @@ -5371,8 +5378,7 @@ compatibleReturnType(MyThread* t, object oldMethod, object newMethod) void jumpAndInvoke(MyThread* t, object method, void* base, void* stack, - unsigned oldArgumentFootprint, unsigned argumentCount, - ...) + unsigned oldArgumentFootprint, ...) { t->trace->targetMethod = 0; @@ -5382,8 +5388,9 @@ jumpAndInvoke(MyThread* t, object method, void* base, void* stack, t->trace->nativeMethod = 0; } + unsigned argumentCount = methodParameterFootprint(t, method); uintptr_t arguments[argumentCount]; - va_list a; va_start(a, argumentCount); + va_list a; va_start(a, oldArgumentFootprint); for (unsigned i = 0; i < argumentCount; ++i) { arguments[i] = va_arg(a, uintptr_t); } @@ -5394,7 +5401,7 @@ jumpAndInvoke(MyThread* t, object method, void* base, void* stack, base, static_cast(stack) + oldArgumentFootprint - - t->arch->argumentFootprint(methodParameterFootprint(t, method)) + - t->arch->argumentFootprint(argumentCount) - t->arch->frameFooterSize() - t->arch->frameReturnAddressSize(), argumentCount * BytesPerWord, @@ -5517,9 +5524,9 @@ callContinuation(MyThread* t, object continuation, object result, case Rewind: { jumpAndInvoke - (t, rewindMethod(t), base, stack, oldArgumentFootprint, 3, - continuationContextBefore(t, nextContinuation), nextContinuation, - result, exception); + (t, rewindMethod(t), base, stack, oldArgumentFootprint, + continuationContextBefore(t, continuationContext(t, nextContinuation)), + nextContinuation, result, exception); } break; case Throw: { @@ -5803,7 +5810,7 @@ class MyProcessor: public Processor { if (false) { fprintf(stderr, "%d\n", difference(&(t->continuation), t)); fprintf(stderr, "%d\n", difference(&(t->exception), t)); - fprintf(stderr, "%d\n", difference(&(t->exceptionStack), t)); + fprintf(stderr, "%d\n", difference(&(t->exceptionStackAdjustment), t)); fprintf(stderr, "%d\n", difference(&(t->exceptionOffset), t)); fprintf(stderr, "%d\n", difference(&(t->exceptionHandler), t)); exit(0); @@ -6245,18 +6252,14 @@ class MyProcessor: public Processor { if (LIKELY(t->exception == 0)) { t->continuation = makeCurrentContinuation - (t, t->continuation - ? continuationContext(t, t->continuation) - : makeContinuationContext - (t, 0, 0, 0, 0, t->trace->originalMethod), - &ip, &base, &stack, &oldArgumentFootprint); + (t, &ip, &base, &stack, &oldArgumentFootprint); } } } if (LIKELY(t->exception == 0)) { jumpAndInvoke - (t, method, base, stack, oldArgumentFootprint, 2, receiver, + (t, method, base, stack, oldArgumentFootprint, receiver, t->continuation); } else { unwind(t); @@ -6296,25 +6299,20 @@ class MyProcessor: public Processor { } if (LIKELY(t->exception == 0)) { - object oldContext - = (t->continuation ? continuationContext(t, t->continuation) : 0); + t->continuation = makeCurrentContinuation + (t, &ip, &base, &stack, &oldArgumentFootprint); - object context = makeContinuationContext - (t, oldContext, before, after, 0, t->trace->originalMethod); + object newContext = makeContinuationContext + (t, continuationContext(t, t->continuation), before, after, + t->continuation, t->trace->originalMethod); - object continuation = makeCurrentContinuation - (t, context, &ip, &base, &stack, &oldArgumentFootprint); - - set(t, continuationContext(t, continuation), - ContinuationContextContinuation, continuation); - - t->continuation = continuation; + set(t, t->continuation, ContinuationContext, newContext); } } if (LIKELY(t->exception == 0)) { jumpAndInvoke - (t, windMethod, base, stack, oldArgumentFootprint, 3, before, thunk, + (t, windMethod, base, stack, oldArgumentFootprint, before, thunk, after); } else { unwind(t); From 0a4e77ffa7b4cefaa8fb5106aac4a65edd8cd2be Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 24 May 2009 22:36:16 -0600 Subject: [PATCH 051/172] fix thinko in callContinuation --- src/compile.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index f954b76143..d73d761be9 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -31,7 +31,7 @@ vmCall(); namespace { -const bool DebugCompile = false; +const bool DebugCompile = true; const bool DebugNatives = false; const bool DebugCallTable = false; const bool DebugMethodTree = false; @@ -5431,7 +5431,7 @@ callContinuation(MyThread* t, object continuation, object result, if (compatibleReturnType (t, t->trace->originalMethod, continuationContextMethod - (t, continuationContext(t, t->continuation)))) + (t, continuationContext(t, continuation)))) { object oldContext; object unwindContext; From 9837528a3ef1ff5f3e81e5064e6a6cc51fc764fe Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 24 May 2009 22:49:39 -0600 Subject: [PATCH 052/172] set Thread::continuation before calling jumpAndInvoke in Rewind case of callContinuation --- src/compile.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index d73d761be9..ff0a83fd7c 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -31,7 +31,7 @@ vmCall(); namespace { -const bool DebugCompile = true; +const bool DebugCompile = false; const bool DebugNatives = false; const bool DebugCallTable = false; const bool DebugMethodTree = false; @@ -5498,7 +5498,9 @@ callContinuation(MyThread* t, object continuation, object result, action = Throw; } } - } + } else { + action = Call; + } } else { t->exception = makeIncompatibleContinuationException(t); action = Throw; @@ -5523,10 +5525,12 @@ callContinuation(MyThread* t, object continuation, object result, } break; case Rewind: { + t->continuation = nextContinuation; + jumpAndInvoke (t, rewindMethod(t), base, stack, oldArgumentFootprint, continuationContextBefore(t, continuationContext(t, nextContinuation)), - nextContinuation, result, exception); + continuation, result, exception); } break; case Throw: { From cc6bf3f42b7a4eed7471b7de299038252e052526 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 24 May 2009 22:50:11 -0600 Subject: [PATCH 053/172] bugfixes and print statements in DynamicWind --- test/DynamicWind.java | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/test/DynamicWind.java b/test/DynamicWind.java index 81838f0630..18419b335c 100644 --- a/test/DynamicWind.java +++ b/test/DynamicWind.java @@ -18,8 +18,10 @@ public class DynamicWind { } private void unwindTest(final Callable unwind) throws Exception { + System.out.println("unwindTest enter"); + try { - expect(dynamicWind(new Runnable() { + expect(dynamicWind(new Runnable() { public void run() { System.out.println("unwindTest before"); @@ -57,9 +59,13 @@ public class DynamicWind { e.printStackTrace(); } + System.out.println("unwindTest expect"); + expect(before == 1); expect(task == 1); expect(after == 1); + + System.out.println("unwindTest exit"); } private void normalUnwind() throws Exception { @@ -81,6 +87,8 @@ public class DynamicWind { private void continuationUnwindTest(final CallbackReceiver receiver) throws Exception { + System.out.println("continuationUnwindTest enter"); + try { expect(callWithCurrentContinuation(new CallbackReceiver() { public Integer receive(final Callback continuation) @@ -98,9 +106,13 @@ public class DynamicWind { e.printStackTrace(); } + System.out.println("continuationUnwindTest expect"); + expect(before == 1); expect(task == 1); expect(after == 1); + + System.out.println("continuationUnwindTest exit"); } private void continuationResultUnwind() throws Exception { @@ -124,18 +136,24 @@ public class DynamicWind { private void rewindTest(final Callable unwind, Runnable rewind) throws Exception { + System.out.println("rewindTest enter"); + int value; try { value = dynamicWind(new Runnable() { public void run() { + System.out.println("rewindTest before"); + expect(before == continuationCount); - expect(task == 0); - expect(after == 0); + expect(task == continuationCount); + expect(after == continuationCount); ++ before; } }, new Callable() { public Integer call() throws Exception { + System.out.println("rewindTest thunk"); + expect(before == 1); expect(task == 0); expect(after == 0); @@ -154,6 +172,8 @@ public class DynamicWind { } }, new Runnable() { public void run() { + System.out.println("rewindTest after"); + expect(before == continuationCount + 1); expect(task == 1); expect(after == continuationCount); @@ -165,9 +185,13 @@ public class DynamicWind { value = e.value; } + System.out.println("rewindTest expect"); + expect(value == continuationCount); if (value == 0) { + System.out.println("rewindTest expect 0"); + expect(before == 1); expect(task == 1); expect(after == 1); @@ -176,11 +200,15 @@ public class DynamicWind { rewind.run(); throw new AssertionError(); } else { + System.out.println("rewindTest expect 1"); + expect(value == 1); expect(before == 2); expect(task == 1); expect(after == 2); } + + System.out.println("rewindTest exit"); } private void continuationResultRewind() throws Exception { From ea5fea48023575dfd59b81c37e56ff4ef48e8378 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 25 May 2009 14:59:36 -0600 Subject: [PATCH 054/172] fix printf format for 64-bit build --- src/compile.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index ff0a83fd7c..9b5e6da60c 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -5812,11 +5812,11 @@ class MyProcessor: public Processor { t->init(); if (false) { - fprintf(stderr, "%d\n", difference(&(t->continuation), t)); - fprintf(stderr, "%d\n", difference(&(t->exception), t)); - fprintf(stderr, "%d\n", difference(&(t->exceptionStackAdjustment), t)); - fprintf(stderr, "%d\n", difference(&(t->exceptionOffset), t)); - fprintf(stderr, "%d\n", difference(&(t->exceptionHandler), t)); + fprintf(stderr, "%"LD"\n", difference(&(t->continuation), t)); + fprintf(stderr, "%"LD"\n", difference(&(t->exception), t)); + fprintf(stderr, "%"LD"\n", difference(&(t->exceptionStackAdjustment), t)); + fprintf(stderr, "%"LD"\n", difference(&(t->exceptionOffset), t)); + fprintf(stderr, "%"LD"\n", difference(&(t->exceptionHandler), t)); exit(0); } From 758325ae2777273986b8639c001179757db1fc2b Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 25 May 2009 20:02:25 -0600 Subject: [PATCH 055/172] convert methods in builtin.cpp to use fast native calling convention --- src/builtin.cpp | 592 +++++++++++++++++++++++++++--------------------- 1 file changed, 331 insertions(+), 261 deletions(-) diff --git a/src/builtin.cpp b/src/builtin.cpp index 33e5a489b5..f9bf0a8dd1 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -22,14 +22,14 @@ replace(char a, char b, char* c) for (; *c; ++c) if (*c == a) *c = b; } -jclass -search(Thread* t, jstring name, object (*op)(Thread*, object), +int64_t +search(Thread* t, object name, object (*op)(Thread*, object), bool replaceDots) { if (LIKELY(name)) { - object n = makeByteArray(t, stringLength(t, *name) + 1); + object n = makeByteArray(t, stringLength(t, name) + 1); char* s = reinterpret_cast(&byteArrayBody(t, n, 0)); - stringChars(t, *name, s); + stringChars(t, name, s); if (replaceDots) { replace('.', '/', s); @@ -40,7 +40,7 @@ search(Thread* t, jstring name, object (*op)(Thread*, object), return 0; } - return makeLocalReference(t, r); + return reinterpret_cast(r); } else { t->exception = makeNullPointerException(t); return 0; @@ -63,124 +63,136 @@ enumerateThreads(Thread* t, Thread* x, object array, unsigned* index, } // namespace -extern "C" JNIEXPORT jstring JNICALL -Java_java_lang_Object_toString(Thread* t, jobject this_) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Object_toString +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object this_ = reinterpret_cast(arguments[0]); - unsigned hash = objectHash(t, *this_); + unsigned hash = objectHash(t, this_); object s = makeString (t, "%s@0x%x", - &byteArrayBody(t, className(t, objectClass(t, *this_)), 0), + &byteArrayBody(t, className(t, objectClass(t, this_)), 0), hash); - return makeLocalReference(t, s); + return reinterpret_cast(s); } -extern "C" JNIEXPORT jclass JNICALL -Java_java_lang_Object_getClass(Thread* t, jobject this_) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Object_getClass +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object this_ = reinterpret_cast(arguments[0]); - return makeLocalReference(t, objectClass(t, *this_)); + return reinterpret_cast(objectClass(t, this_)); } extern "C" JNIEXPORT void JNICALL -Java_java_lang_Object_wait(Thread* t, jobject this_, jlong milliseconds) +Avian_java_lang_Object_wait +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object this_ = reinterpret_cast(arguments[0]); + int64_t milliseconds; memcpy(&milliseconds, arguments + 1, 8); - vm::wait(t, *this_, milliseconds); + vm::wait(t, this_, milliseconds); } extern "C" JNIEXPORT void JNICALL -Java_java_lang_Object_notify(Thread* t, jobject this_) +Avian_java_lang_Object_notify +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object this_ = reinterpret_cast(arguments[0]); - notify(t, *this_); + notify(t, this_); } extern "C" JNIEXPORT void JNICALL -Java_java_lang_Object_notifyAll(Thread* t, jobject this_) +Avian_java_lang_Object_notifyAll +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object this_ = reinterpret_cast(arguments[0]); - notifyAll(t, *this_); + notifyAll(t, this_); } extern "C" JNIEXPORT jint JNICALL -Java_java_lang_Object_hashCode(Thread* t, jobject this_) +Avian_java_lang_Object_hashCode +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object this_ = reinterpret_cast(arguments[0]); - return objectHash(t, *this_); + return objectHash(t, this_); } -extern "C" JNIEXPORT jobject JNICALL -Java_java_lang_Object_clone(Thread* t, jclass, jobject o) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Object_clone +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object o = reinterpret_cast(arguments[0]); + PROTECT(t, o); - object class_ = objectClass(t, *o); - unsigned size = baseSize(t, *o, class_) * BytesPerWord; + object class_ = objectClass(t, o); + unsigned size = baseSize(t, o, class_) * BytesPerWord; object clone; if (classArrayElementSize(t, class_)) { clone = static_cast(allocate(t, size, classObjectMask(t, class_))); - memcpy(clone, *o, size); + memcpy(clone, o, size); // clear any object header flags: - setObjectClass(t, *o, objectClass(t, *o)); + setObjectClass(t, o, objectClass(t, o)); } else { clone = make(t, class_); memcpy(reinterpret_cast(clone) + 1, - reinterpret_cast(*o) + 1, + reinterpret_cast(o) + 1, size - BytesPerWord); } - return makeLocalReference(t, clone); + return reinterpret_cast(clone); } -extern "C" JNIEXPORT jclass JNICALL -Java_java_lang_ClassLoader_defineClass -(Thread* t, jclass, jbyteArray b, jint offset, jint length) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_ClassLoader_defineClass +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object b = reinterpret_cast(arguments[0]); + int offset = arguments[1]; + int length = arguments[2]; uint8_t* buffer = static_cast (t->m->heap->allocate(length)); - memcpy(buffer, &byteArrayBody(t, *b, offset), length); + memcpy(buffer, &byteArrayBody(t, b, offset), length); object c = parseClass(t, buffer, length); t->m->heap->free(buffer, length); - return makeLocalReference(t, c); + return reinterpret_cast(c); } -extern "C" JNIEXPORT jclass JNICALL -Java_java_lang_SystemClassLoader_findLoadedClass -(Thread* t, jclass, jstring name) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_SystemClassLoader_findLoadedClass +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object name = reinterpret_cast(arguments[1]); return search(t, name, findLoadedClass, true); } -extern "C" JNIEXPORT jclass JNICALL -Java_java_lang_SystemClassLoader_findClass(Thread* t, jclass, jstring name) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_SystemClassLoader_findClass +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object name = reinterpret_cast(arguments[1]); return search(t, name, resolveClass, true); } -extern "C" JNIEXPORT jboolean JNICALL -Java_java_lang_SystemClassLoader_resourceExists -(Thread* t, jclass, jstring name) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_SystemClassLoader_resourceExists +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object name = reinterpret_cast(arguments[1]); if (LIKELY(name)) { - char n[stringLength(t, *name) + 1]; - stringChars(t, *name, n); + char n[stringLength(t, name) + 1]; + stringChars(t, name, n); return t->m->finder->exists(n); } else { t->exception = makeNullPointerException(t); @@ -188,38 +200,49 @@ Java_java_lang_SystemClassLoader_resourceExists } } -extern "C" JNIEXPORT jobject JNICALL -Java_java_io_ObjectInputStream_makeInstance(Thread* t, jclass, jclass c) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_io_ObjectInputStream_makeInstance +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object c = reinterpret_cast(arguments[0]); - return makeLocalReference(t, make(t, *c)); + return reinterpret_cast(make(t, c)); } -extern "C" JNIEXPORT jclass JNICALL -Java_java_lang_Class_primitiveClass(Thread* t, jclass, jchar name) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Class_primitiveClass +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + char name = arguments[0]; switch (name) { case 'B': - return makeLocalReference(t, arrayBody(t, t->m->types, Machine::JbyteType)); + return reinterpret_cast + (arrayBody(t, t->m->types, Machine::JbyteType)); case 'C': - return makeLocalReference(t, arrayBody(t, t->m->types, Machine::JcharType)); + return reinterpret_cast + (arrayBody(t, t->m->types, Machine::JcharType)); case 'D': - return makeLocalReference(t, arrayBody(t, t->m->types, Machine::JdoubleType)); + return reinterpret_cast + (arrayBody(t, t->m->types, Machine::JdoubleType)); case 'F': - return makeLocalReference(t, arrayBody(t, t->m->types, Machine::JfloatType)); + return reinterpret_cast + (arrayBody(t, t->m->types, Machine::JfloatType)); case 'I': - return makeLocalReference(t, arrayBody(t, t->m->types, Machine::JintType)); + return reinterpret_cast + (arrayBody(t, t->m->types, Machine::JintType)); case 'J': - return makeLocalReference(t, arrayBody(t, t->m->types, Machine::JlongType)); + return reinterpret_cast + (arrayBody(t, t->m->types, Machine::JlongType)); case 'S': - return makeLocalReference(t, arrayBody(t, t->m->types, Machine::JshortType)); + return reinterpret_cast + (arrayBody(t, t->m->types, Machine::JshortType)); case 'V': - return makeLocalReference(t, arrayBody(t, t->m->types, Machine::JvoidType)); + return reinterpret_cast + (arrayBody(t, t->m->types, Machine::JvoidType)); case 'Z': - return makeLocalReference(t, arrayBody(t, t->m->types, Machine::JbooleanType)); + return reinterpret_cast + (arrayBody(t, t->m->types, Machine::JbooleanType)); default: t->exception = makeIllegalArgumentException(t); return 0; @@ -227,93 +250,102 @@ Java_java_lang_Class_primitiveClass(Thread* t, jclass, jchar name) } extern "C" JNIEXPORT void JNICALL -Java_java_lang_Class_initialize(Thread* t, jobject this_) +Avian_java_lang_Class_initialize +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object this_ = reinterpret_cast(arguments[0]); - initClass(t, *this_); + initClass(t, this_); } -extern "C" JNIEXPORT jboolean JNICALL -Java_java_lang_Class_isAssignableFrom(Thread* t, jobject this_, jclass that) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Class_isAssignableFrom +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object this_ = reinterpret_cast(arguments[0]); + object that = reinterpret_cast(arguments[1]); if (LIKELY(that)) { - return vm::isAssignableFrom(t, *this_, *that); + return vm::isAssignableFrom(t, this_, that); } else { t->exception = makeNullPointerException(t); return 0; } } -extern "C" JNIEXPORT jlong JNICALL -Java_java_lang_reflect_Field_getPrimitive -(Thread* t, jclass, jobject instance, jint code, jint offset) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Field_getPrimitive +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object instance = reinterpret_cast(arguments[0]); + int code = arguments[1]; + int offset = arguments[2]; switch (code) { case ByteField: - return cast(*instance, offset); + return cast(instance, offset); case BooleanField: - return cast(*instance, offset); + return cast(instance, offset); case CharField: - return cast(*instance, offset); + return cast(instance, offset); case ShortField: - return cast(*instance, offset); + return cast(instance, offset); case IntField: - return cast(*instance, offset); + return cast(instance, offset); case LongField: - return cast(*instance, offset); + return cast(instance, offset); case FloatField: - return cast(*instance, offset); + return cast(instance, offset); case DoubleField: - return cast(*instance, offset); + return cast(instance, offset); default: abort(t); } } -extern "C" JNIEXPORT jobject JNICALL -Java_java_lang_reflect_Field_getObject -(Thread* t, jclass, jobject instance, jint offset) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Field_getObject +(Thread*, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object instance = reinterpret_cast(arguments[0]); + int offset = arguments[1]; - return makeLocalReference(t, cast(*instance, offset)); + return reinterpret_cast(cast(instance, offset)); } extern "C" JNIEXPORT void JNICALL -Java_java_lang_reflect_Field_setPrimitive -(Thread* t, jclass, jobject instance, jint code, jint offset, jlong value) +Avian_java_lang_reflect_Field_setPrimitive +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object instance = reinterpret_cast(arguments[0]); + int code = arguments[1]; + int offset = arguments[2]; + int64_t value; memcpy(&value, arguments + 3, 8); switch (code) { case ByteField: - cast(*instance, offset) = static_cast(value); + cast(instance, offset) = static_cast(value); break; case BooleanField: - cast(*instance, offset) = static_cast(value); + cast(instance, offset) = static_cast(value); break; case CharField: - cast(*instance, offset) = static_cast(value); + cast(instance, offset) = static_cast(value); break; case ShortField: - cast(*instance, offset) = static_cast(value); + cast(instance, offset) = static_cast(value); break; case IntField: - cast(*instance, offset) = static_cast(value); + cast(instance, offset) = static_cast(value); break; case LongField: - cast(*instance, offset) = static_cast(value); + cast(instance, offset) = static_cast(value); break; case FloatField: - cast(*instance, offset) = static_cast(value); + cast(instance, offset) = static_cast(value); break; case DoubleField: - cast(*instance, offset) = static_cast(value); + cast(instance, offset) = static_cast(value); break; default: abort(t); @@ -321,27 +353,29 @@ Java_java_lang_reflect_Field_setPrimitive } extern "C" JNIEXPORT void JNICALL -Java_java_lang_reflect_Field_setObject -(Thread* t, jclass, jobject instance, jint offset, jobject value) +Avian_java_lang_reflect_Field_setObject +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object instance = reinterpret_cast(arguments[0]); + int offset = arguments[1]; + object value = reinterpret_cast(arguments[2]); - set(t, *instance, offset, (value ? *value : 0)); + set(t, instance, offset, value); } -extern "C" JNIEXPORT jobject JNICALL -Java_java_lang_reflect_Constructor_make(Thread* t, jclass, jclass c) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Constructor_make +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object c = reinterpret_cast(arguments[0]); - return makeLocalReference(t, make(t, *c)); + return reinterpret_cast(make(t, c)); } -extern "C" JNIEXPORT jobject JNICALL -Java_java_lang_reflect_Method_getCaller(Thread* t, jclass) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Method_getCaller +(Thread* t, object, uintptr_t*) { - ENTER(t, Thread::ActiveState); - class Visitor: public Processor::StackVisitor { public: Visitor(Thread* t): t(t), method(0), count(0) { } @@ -363,34 +397,35 @@ Java_java_lang_reflect_Method_getCaller(Thread* t, jclass) t->m->processor->walkStack(t, &v); - return makeLocalReference(t, v.method); + return reinterpret_cast(v.method); } -extern "C" JNIEXPORT jobject JNICALL -Java_java_lang_reflect_Method_invoke -(Thread* t, jclass, jobject method, jobject instance, jobjectArray arguments) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Method_invoke +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object method = reinterpret_cast(arguments[0]); + object instance = reinterpret_cast(arguments[1]); + object args = reinterpret_cast(arguments[2]); - object v = t->m->processor->invokeArray - (t, *method, (instance ? *instance : 0), *arguments); + object v = t->m->processor->invokeArray(t, method, instance, args); if (t->exception) { t->exception = makeInvocationTargetException(t, t->exception); } - return makeLocalReference(t, v); + return reinterpret_cast(v); } -extern "C" JNIEXPORT jint JNICALL -Java_java_lang_reflect_Array_getLength(Thread* t, jclass, jobject array) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Array_getLength +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object array = reinterpret_cast(arguments[0]); if (LIKELY(array)) { - object a = *array; - unsigned elementSize = classArrayElementSize(t, objectClass(t, a)); + unsigned elementSize = classArrayElementSize(t, objectClass(t, array)); if (LIKELY(elementSize)) { - return cast(a, BytesPerWord); + return cast(array, BytesPerWord); } else { t->exception = makeIllegalArgumentException(t); } @@ -400,101 +435,111 @@ Java_java_lang_reflect_Array_getLength(Thread* t, jclass, jobject array) return 0; } -extern "C" JNIEXPORT jobject JNICALL -Java_java_lang_reflect_Array_makeObjectArray -(Thread* t, jclass, jclass elementType, jint length) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Array_makeObjectArray +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object elementType = reinterpret_cast(arguments[0]); + int length = arguments[1]; - return makeLocalReference(t, makeObjectArray(t, *elementType, length)); + return reinterpret_cast(makeObjectArray(t, elementType, length)); } -extern "C" JNIEXPORT jint JNICALL -Java_java_lang_Float_floatToRawIntBits(Thread*, jclass, jfloat v) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Float_floatToRawIntBits +(Thread*, object, uintptr_t* arguments) { - return floatToBits(v); + return static_cast(*arguments); } -extern "C" JNIEXPORT jfloat JNICALL -Java_java_lang_Float_intBitsToFloat(Thread*, jclass, jint v) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Float_intBitsToFloat +(Thread*, object, uintptr_t* arguments) { - return bitsToFloat(v); + return static_cast(*arguments); } -extern "C" JNIEXPORT jlong JNICALL -Java_java_lang_Double_doubleToRawLongBits(Thread*, jclass, jdouble v) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Double_doubleToRawLongBits +(Thread*, object, uintptr_t* arguments) { - return doubleToBits(v); + int64_t v; memcpy(&v, arguments, 8); + return v; } -extern "C" JNIEXPORT jdouble JNICALL -Java_java_lang_Double_longBitsToDouble(Thread*, jclass, jlong v) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Double_longBitsToDouble +(Thread*, object, uintptr_t* arguments) { - return bitsToDouble(v); + int64_t v; memcpy(&v, arguments, 8); + return v; } -extern "C" JNIEXPORT jobject JNICALL -Java_java_lang_String_intern(Thread* t, jobject this_) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_String_intern +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object this_ = reinterpret_cast(arguments[0]); - return makeLocalReference(t, intern(t, *this_)); + return reinterpret_cast(intern(t, this_)); } -extern "C" JNIEXPORT jstring JNICALL -Java_java_lang_System_getVMProperty(Thread* t, jclass, jstring name, - jbooleanArray found) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_System_getVMProperty +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object name = reinterpret_cast(arguments[0]); + object found = reinterpret_cast(arguments[1]); + PROTECT(t, found); - unsigned length = stringLength(t, *name); + unsigned length = stringLength(t, name); char n[length + 1]; - stringChars(t, *name, n); + stringChars(t, name, n); - jstring r = 0; + int64_t r = 0; if (strcmp(n, "java.lang.classpath") == 0) { - r = makeLocalReference(t, makeString(t, "%s", t->m->finder->path())); + r = reinterpret_cast(makeString(t, "%s", t->m->finder->path())); } else if (strcmp(n, "avian.version") == 0) { - r = makeLocalReference(t, makeString(t, AVIAN_VERSION)); + r = reinterpret_cast(makeString(t, AVIAN_VERSION)); } else if (strcmp(n, "file.encoding") == 0) { - r = makeLocalReference(t, makeString(t, "ASCII")); + r = reinterpret_cast(makeString(t, "ASCII")); } else { const char* v = findProperty(t, n); if (v) { - r = makeLocalReference(t, makeString(t, v)); + r = reinterpret_cast(makeString(t, v)); } } if (r) { - booleanArrayBody(t, *found, 0) = true; + booleanArrayBody(t, found, 0) = true; } return r; } extern "C" JNIEXPORT void JNICALL -Java_java_lang_System_arraycopy -(Thread* t, jclass, jobject src, jint srcOffset, - jobject dst, jint dstOffset, jint length) +Avian_java_lang_System_arraycopy +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object src = reinterpret_cast(arguments[0]); + int32_t srcOffset = arguments[1]; + object dst = reinterpret_cast(arguments[2]); + int32_t dstOffset = arguments[3]; + int32_t length = arguments[4]; if (LIKELY(src and dst)) { - object s = *src; - object d = *dst; - - if (LIKELY(objectClass(t, s) == objectClass(t, d))) { - unsigned elementSize = classArrayElementSize(t, objectClass(t, s)); + if (LIKELY(objectClass(t, src) == objectClass(t, dst))) { + unsigned elementSize = classArrayElementSize(t, objectClass(t, src)); if (LIKELY(elementSize)) { - intptr_t sl = cast(s, BytesPerWord); - intptr_t dl = cast(d, BytesPerWord); + intptr_t sl = cast(src, BytesPerWord); + intptr_t dl = cast(dst, BytesPerWord); if (LIKELY(srcOffset >= 0 and srcOffset + length <= sl and dstOffset >= 0 and dstOffset + length <= dl)) { - uint8_t* sbody = &cast(s, ArrayBody); - uint8_t* dbody = &cast(d, ArrayBody); - if (s == d) { + uint8_t* sbody = &cast(src, ArrayBody); + uint8_t* dbody = &cast(dst, ArrayBody); + if (src == dst) { memmove(dbody + (dstOffset * elementSize), sbody + (srcOffset * elementSize), length * elementSize); @@ -504,8 +549,8 @@ Java_java_lang_System_arraycopy length * elementSize); } - if (classObjectMask(t, objectClass(t, d))) { - mark(t, d, ArrayBody + (dstOffset * BytesPerWord), length); + if (classObjectMask(t, objectClass(t, dst))) { + mark(t, dst, ArrayBody + (dstOffset * BytesPerWord), length); } return; @@ -520,13 +565,14 @@ Java_java_lang_System_arraycopy t->exception = makeArrayStoreException(t); } -extern "C" JNIEXPORT jint JNICALL -Java_java_lang_System_identityHashCode(Thread* t, jclass, jobject o) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_System_identityHashCode +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object o = reinterpret_cast(arguments[0]); if (LIKELY(o)) { - return objectHash(t, *o); + return objectHash(t, o); } else { t->exception = makeNullPointerException(t); return 0; @@ -534,14 +580,17 @@ Java_java_lang_System_identityHashCode(Thread* t, jclass, jobject o) } extern "C" JNIEXPORT void JNICALL -Java_java_lang_Runtime_load(Thread* t, jclass, jstring name, jboolean mapName) +Avian_java_lang_Runtime_load +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); - ACQUIRE(t, t->m->classLock); + object name = reinterpret_cast(arguments[0]); + bool mapName = arguments[1]; - unsigned length = stringLength(t, *name); + unsigned length = stringLength(t, name); char n[length + 1]; - stringChars(t, *name, n); + stringChars(t, name, n); + + ACQUIRE(t, t->m->classLock); const char* builtins = findProperty(t, "avian.builtins"); if (mapName and builtins) { @@ -581,7 +630,8 @@ Java_java_lang_Runtime_load(Thread* t, jclass, jstring name, jboolean mapName) } extern "C" JNIEXPORT void JNICALL -Java_java_lang_Runtime_gc(Thread* t, jobject) +Avian_java_lang_Runtime_gc +(Thread* t, object, uintptr_t*) { collect(t, Heap::MajorCollection); } @@ -589,13 +639,14 @@ Java_java_lang_Runtime_gc(Thread* t, jobject) #ifdef AVIAN_HEAPDUMP extern "C" JNIEXPORT void JNICALL -Java_java_lang_Runtime_dumpHeap(Thread* t, jclass, jstring outputFile) +Avian_java_lang_Runtime_dumpHeap +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object outputFile = reinterpret_cast(*arguments); - unsigned length = stringLength(t, *outputFile); + unsigned length = stringLength(t, outputFile); char n[length + 1]; - stringChars(t, *outputFile, n); + stringChars(t, outputFile, n); FILE* out = fopen(n, "wb"); if (out) { { ENTER(t, Thread::ExclusiveState); @@ -611,31 +662,33 @@ Java_java_lang_Runtime_dumpHeap(Thread* t, jclass, jstring outputFile) #endif//AVIAN_HEAPDUMP extern "C" JNIEXPORT void JNICALL -Java_java_lang_Runtime_exit(Thread* t, jobject, jint code) +Avian_java_lang_Runtime_exit +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); - - t->m->system->exit(code); + t->m->system->exit(*arguments); } -extern "C" JNIEXPORT jlong JNICALL -Java_java_lang_Runtime_freeMemory(Thread*, jobject) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Runtime_freeMemory +(Thread*, object, uintptr_t*) { // todo return 0; } -extern "C" JNIEXPORT jlong JNICALL -Java_java_lang_Runtime_totalMemory(Thread*, jobject) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Runtime_totalMemory +(Thread*, object, uintptr_t*) { // todo return 0; } -extern "C" JNIEXPORT jobject JNICALL -Java_java_lang_Throwable_trace(Thread* t, jclass, jint skipCount) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Throwable_trace +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + int32_t skipCount = arguments[0]; class Visitor: public Processor::StackVisitor { public: @@ -673,15 +726,17 @@ Java_java_lang_Throwable_trace(Thread* t, jclass, jint skipCount) if (v.trace == 0) v.trace = makeArray(t, 0); - return makeLocalReference(t, v.trace); + return reinterpret_cast(v.trace); } -extern "C" JNIEXPORT jarray JNICALL -Java_java_lang_Throwable_resolveTrace(Thread* t, jclass, jobject trace) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Throwable_resolveTrace +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object trace = reinterpret_cast(*arguments); + PROTECT(t, trace); - unsigned length = arrayLength(t, *trace); + unsigned length = arrayLength(t, trace); object array = makeObjectArray (t, arrayBody(t, t->m->types, Machine::StackTraceElementType), length); PROTECT(t, array); @@ -693,7 +748,7 @@ Java_java_lang_Throwable_resolveTrace(Thread* t, jclass, jobject trace) PROTECT(t, class_); for (unsigned i = 0; i < length; ++i) { - e = arrayBody(t, *trace, i); + e = arrayBody(t, trace, i); class_ = className(t, methodClass(t, traceElementMethod(t, e))); class_ = makeString(t, class_, 0, byteArrayLength(t, class_) - 1, 0); @@ -708,26 +763,26 @@ Java_java_lang_Throwable_resolveTrace(Thread* t, jclass, jobject trace) set(t, array, ArrayBody + (i * BytesPerWord), ste); } - return makeLocalReference(t, array); + return reinterpret_cast(array); } -extern "C" JNIEXPORT jobject JNICALL -Java_java_lang_Thread_currentThread(Thread* t, jclass) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Thread_currentThread +(Thread* t, object, uintptr_t*) { - ENTER(t, Thread::ActiveState); - - return makeLocalReference(t, t->javaThread); + return reinterpret_cast(t->javaThread); } -extern "C" JNIEXPORT jlong JNICALL -Java_java_lang_Thread_doStart(Thread* t, jobject this_) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Thread_doStart +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object this_ = reinterpret_cast(*arguments); - Thread* p = t->m->processor->makeThread(t->m, *this_, t); + Thread* p = t->m->processor->makeThread(t->m, this_, t); if (t->m->system->success(t->m->system->start(&(p->runnable)))) { - return reinterpret_cast(p); + return reinterpret_cast(p); } else { p->exit(); return 0; @@ -735,52 +790,58 @@ Java_java_lang_Thread_doStart(Thread* t, jobject this_) } extern "C" JNIEXPORT void JNICALL -Java_java_lang_Thread_interrupt(Thread* t, jclass, jlong peer) +Avian_java_lang_Thread_interrupt +(Thread* t, object, uintptr_t* arguments) { + int64_t peer; memcpy(&peer, arguments, 8); + interrupt(t, reinterpret_cast(peer)); } -extern "C" JNIEXPORT jobject JNICALL -Java_java_lang_Thread_getStackTrace(Thread* t, jclass, jlong peer) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Thread_getStackTrace +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + int64_t peer; memcpy(&peer, arguments, 8); if (reinterpret_cast(peer) == t) { - return makeLocalReference(t, makeTrace(t)); + return reinterpret_cast(makeTrace(t)); } else { - return makeLocalReference - (t, t->m->processor->getStackTrace(t, reinterpret_cast(peer))); + return reinterpret_cast + (t->m->processor->getStackTrace(t, reinterpret_cast(peer))); } } -extern "C" JNIEXPORT jint JNICALL -Java_java_lang_Thread_activeCount(Thread* t, jclass) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Thread_activeCount +(Thread* t, object, uintptr_t*) { return t->m->liveCount; } -extern "C" JNIEXPORT jint JNICALL -Java_java_lang_Thread_enumerate(Thread* t, jclass, jobjectArray array) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Thread_enumerate +(Thread* t, object, uintptr_t* arguments) { + object array = reinterpret_cast(*arguments); + ACQUIRE_RAW(t, t->m->stateLock); - ENTER(t, Thread::ActiveState); - - unsigned count = min(t->m->liveCount, objectArrayLength(t, *array)); + unsigned count = min(t->m->liveCount, objectArrayLength(t, array)); unsigned index = 0; - enumerateThreads(t, t->m->rootThread, *array, &index, count); + enumerateThreads(t, t->m->rootThread, array, &index, count); return count; } -extern "C" JNIEXPORT jint JNICALL -Java_java_net_URL_00024ResourceInputStream_getContentLength -(Thread* t, jclass, jstring path) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_net_URL_00024ResourceInputStream_getContentLength +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object path = reinterpret_cast(*arguments); if (LIKELY(path)) { - char p[stringLength(t, *path) + 1]; - stringChars(t, *path, p); + char p[stringLength(t, path) + 1]; + stringChars(t, path, p); System::Region* r = t->m->finder->find(p); if (r) { @@ -792,27 +853,30 @@ Java_java_net_URL_00024ResourceInputStream_getContentLength return -1; } -extern "C" JNIEXPORT jlong JNICALL -Java_java_net_URL_00024ResourceInputStream_open -(Thread* t, jclass, jstring path) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_net_URL_00024ResourceInputStream_open +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + object path = reinterpret_cast(*arguments); if (LIKELY(path)) { - char p[stringLength(t, *path) + 1]; - stringChars(t, *path, p); + char p[stringLength(t, path) + 1]; + stringChars(t, path, p); - return reinterpret_cast(t->m->finder->find(p)); + return reinterpret_cast(t->m->finder->find(p)); } else { t->exception = makeNullPointerException(t); return 0; } } -extern "C" JNIEXPORT jint JNICALL -Java_java_net_URL_00024ResourceInputStream_read__JI -(Thread*, jclass, jlong peer, jint position) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_net_URL_00024ResourceInputStream_read__JI +(Thread*, object, uintptr_t* arguments) { + int64_t peer; memcpy(&peer, arguments, 8); + int32_t position = arguments[2]; + System::Region* region = reinterpret_cast(peer); if (position >= static_cast(region->length())) { return -1; @@ -821,12 +885,15 @@ Java_java_net_URL_00024ResourceInputStream_read__JI } } -extern "C" JNIEXPORT jint JNICALL -Java_java_net_URL_00024ResourceInputStream_read__JI_3BII -(Thread* t, jclass, jlong peer, jint position, - jbyteArray b, jint offset, jint length) +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_net_URL_00024ResourceInputStream_read__JI_3BII +(Thread* t, object, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + int64_t peer; memcpy(&peer, arguments, 8); + int32_t position = arguments[2]; + object buffer = reinterpret_cast(arguments[3]); + int32_t offset = arguments[4]; + int32_t length = arguments[5]; if (length == 0) return 0; @@ -837,14 +904,17 @@ Java_java_net_URL_00024ResourceInputStream_read__JI_3BII if (length <= 0) { return -1; } else { - memcpy(&byteArrayBody(t, *b, offset), region->start() + position, length); + memcpy(&byteArrayBody(t, buffer, offset), region->start() + position, + length); return length; } } extern "C" JNIEXPORT void JNICALL -Java_java_net_URL_00024ResourceInputStream_close(Thread*, jclass, jlong peer) +Avian_java_net_URL_00024ResourceInputStream_close +(Thread*, object, uintptr_t* arguments) { + int64_t peer; memcpy(&peer, arguments, 8); reinterpret_cast(peer)->dispose(); } From 43f5c3f382cfa34fec4926d92b5ea4415ef5df48 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 25 May 2009 21:05:49 -0600 Subject: [PATCH 056/172] fix process=interpret build --- src/interpret.cpp | 103 +++++++++++++++++++++++++++++----------------- 1 file changed, 66 insertions(+), 37 deletions(-) diff --git a/src/interpret.cpp b/src/interpret.cpp index fcc2621d90..c77e150a87 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -410,8 +410,7 @@ makeNativeMethodData(Thread* t, object method, void* function) object data = makeNativeMethodData(t, function, 0, // argument table size - count, - false); + count); unsigned argumentTableSize = BytesPerWord * 2; unsigned index = 0; @@ -475,7 +474,6 @@ resolveNativeMethodData(Thread* t, object method) memoryBarrier(); set(t, method, MethodCode, data); - return data; } else { object message = makeString (t, "%s.%s%s", @@ -483,7 +481,6 @@ resolveNativeMethodData(Thread* t, object method) &byteArrayBody(t, methodName(t, method), 0), &byteArrayBody(t, methodSpec(t, method), 0)); t->exception = makeUnsatisfiedLinkError(t, message); - return 0; } } } @@ -503,7 +500,7 @@ checkStack(Thread* t, object method) } void -pushResult(Thread* t, unsigned returnCode, uint64_t result) +pushResult(Thread* t, unsigned returnCode, uint64_t result, bool indirect) { switch (returnCode) { case ByteField: @@ -545,14 +542,21 @@ pushResult(Thread* t, unsigned returnCode, uint64_t result) break; case ObjectField: - if (DebugRun) { - fprintf(stderr, "result: %p at %p\n", - static_cast(result) == 0 ? 0 : - *reinterpret_cast(static_cast(result)), - reinterpret_cast(static_cast(result))); + if (indirect) { + if (DebugRun) { + fprintf(stderr, "result: %p at %p\n", + static_cast(result) == 0 ? 0 : + *reinterpret_cast(static_cast(result)), + reinterpret_cast(static_cast(result))); + } + pushObject(t, static_cast(result) == 0 ? 0 : + *reinterpret_cast(static_cast(result))); + } else { + if (DebugRun) { + fprintf(stderr, "result: %p\n", reinterpret_cast(result)); + } + pushObject(t, reinterpret_cast(result)); } - pushObject(t, static_cast(result) == 0 ? 0 : - *reinterpret_cast(static_cast(result))); break; case VoidField: @@ -670,13 +674,13 @@ invokeNativeSlow(Thread* t, object method) return VoidField; } - pushResult(t, returnCode, result); + pushResult(t, returnCode, result, true); return returnCode; } unsigned -invokeNative(MyThread* t, object method) +invokeNative(Thread* t, object method) { PROTECT(t, method); @@ -689,20 +693,24 @@ invokeNative(MyThread* t, object method) if (methodVmFlags(t, method) & FastNative) { pushFrame(t, method); - uint64_t result = reinterpret_cast - (methodCompiled(t, method)) - (t, method, - static_cast(t->stack) - + t->arch->frameFooterSize() - + t->arch->frameReturnAddressSize()); + unsigned footprint = methodParameterFootprint(t, method); + uintptr_t arguments[footprint]; + unsigned sp = frameBase(t, t->frame); + for (unsigned i = 0; i < footprint; ++i) { + arguments[i] = t->stack[((sp + i) * 2) + 1]; + } + uint64_t result = reinterpret_cast + (nativeMethodDataFunction(t, methodCode(t, method))) + (t, method, arguments); + popFrame(t); if (UNLIKELY(t->exception)) { return VoidField; } - pushResult(t, methodReturnCode(t, method), result); + pushResult(t, methodReturnCode(t, method), result, false); return methodReturnCode(t, method); } else { @@ -952,7 +960,7 @@ interpret(Thread* t) object class_ = resolveClassInPool(t, codePool(t, code), index - 1); if (UNLIKELY(exception)) goto throw_; - pushObject(t, makeObjectArray(t, class_, count, true)); + pushObject(t, makeObjectArray(t, class_, count)); } else { object message = makeString(t, "%d", count); exception = makeNegativeArraySizeException(t, message); @@ -2393,7 +2401,7 @@ interpret(Thread* t) } } - object array = makeArray(t, counts[0], true); + object array = makeArray(t, counts[0]); setObjectClass(t, array, class_); PROTECT(t, array); @@ -2424,35 +2432,35 @@ interpret(Thread* t) switch (type) { case T_BOOLEAN: - array = makeBooleanArray(t, count, true); + array = makeBooleanArray(t, count); break; case T_CHAR: - array = makeCharArray(t, count, true); + array = makeCharArray(t, count); break; case T_FLOAT: - array = makeFloatArray(t, count, true); + array = makeFloatArray(t, count); break; case T_DOUBLE: - array = makeDoubleArray(t, count, true); + array = makeDoubleArray(t, count); break; case T_BYTE: - array = makeByteArray(t, count, true); + array = makeByteArray(t, count); break; case T_SHORT: - array = makeShortArray(t, count, true); + array = makeShortArray(t, count); break; case T_INT: - array = makeIntArray(t, count, true); + array = makeIntArray(t, count); break; case T_LONG: - array = makeLongArray(t, count, true); + array = makeLongArray(t, count); break; default: abort(t); @@ -3042,7 +3050,7 @@ class MyProcessor: public Processor { return vm::makeClass (t, flags, vmFlags, arrayDimensions, fixedSize, arrayElementSize, objectMask, name, super, interfaceTable, virtualTable, fieldTable, - methodTable, staticTable, loader, 0, false); + methodTable, staticTable, loader, 0); } virtual void @@ -3198,14 +3206,12 @@ class MyProcessor: public Processor { return 0; } - virtual void compileThunks(vm::Thread*, BootImage*, uint8_t*, unsigned*, - unsigned) - { + virtual void initialize(vm::Thread*, BootImage*, uint8_t*, unsigned) { abort(s); } - virtual void compileMethod(vm::Thread*, Zone*, uint8_t*, unsigned*, unsigned, - object*, object*, DelayedPromise**, object) + virtual void compileMethod(vm::Thread*, Zone*, object*, object*, + DelayedPromise**, object) { abort(s); } @@ -3224,6 +3230,29 @@ class MyProcessor: public Processor { expect(s, image == 0); } + + virtual void callWithCurrentContinuation(vm::Thread*, object) { + abort(s); + } + + virtual void dynamicWind(vm::Thread*, object, object, object) { + abort(s); + } + + virtual void feedResultToContinuation(vm::Thread*, object, object){ + abort(s); + } + + virtual void feedExceptionToContinuation(vm::Thread*, object, object) { + abort(s); + } + + virtual void walkContinuationBody(vm::Thread*, Heap::Walker*, object, + unsigned) + { + abort(s); + } + virtual void dispose(vm::Thread* t) { t->m->heap->free(t, sizeof(Thread)); } From 9682d63b84812554c78133f234fcd69e6401dc37 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 25 May 2009 21:20:29 -0600 Subject: [PATCH 057/172] fix marshalling of 64-bit arguments in interpret.cpp --- src/interpret.cpp | 85 ++++++++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 37 deletions(-) diff --git a/src/interpret.cpp b/src/interpret.cpp index c77e150a87..a85ecdc056 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -567,6 +567,48 @@ pushResult(Thread* t, unsigned returnCode, uint64_t result, bool indirect) } } +void +marshalArguments(Thread* t, uintptr_t* args, unsigned i, unsigned count, + object data, bool indirect) +{ + unsigned offset = 0; + unsigned sp = frameBase(t, t->frame); + for (; i < count; ++i) { + unsigned type = nativeMethodDataParameterTypes(t, data, i + 1); + + switch (type) { + case INT8_TYPE: + case INT16_TYPE: + case INT32_TYPE: + case FLOAT_TYPE: + args[offset++] = peekInt(t, sp++); + break; + + case INT64_TYPE: + case DOUBLE_TYPE: { + uint64_t v = peekLong(t, sp); + memcpy(args + offset, &v, 8); + offset += (8 / BytesPerWord); + sp += 2; + } break; + + case POINTER_TYPE: { + if (indirect) { + object* v = reinterpret_cast(t->stack + ((sp++) * 2) + 1); + if (*v == 0) { + v = 0; + } + args[offset++] = reinterpret_cast(v); + } else { + args[offset++] = reinterpret_cast(peekObject(t, sp++)); + } + } break; + + default: abort(t); + } + } +} + unsigned invokeNativeSlow(Thread* t, object method) { @@ -592,37 +634,7 @@ invokeNativeSlow(Thread* t, object method) (pushReference(t, methodClass(t, method))); } - unsigned sp = frameBase(t, t->frame); - for (; i < count; ++i) { - unsigned type = nativeMethodDataParameterTypes(t, data, i + 1); - - switch (type) { - case INT8_TYPE: - case INT16_TYPE: - case INT32_TYPE: - case FLOAT_TYPE: - args[offset++] = peekInt(t, sp++); - break; - - case INT64_TYPE: - case DOUBLE_TYPE: { - uint64_t v = peekLong(t, sp); - memcpy(args + offset, &v, 8); - offset += (8 / BytesPerWord); - sp += 2; - } break; - - case POINTER_TYPE: { - object* v = reinterpret_cast(t->stack + ((sp++) * 2) + 1); - if (*v == 0) { - v = 0; - } - args[offset++] = reinterpret_cast(v); - } break; - - default: abort(t); - } - } + marshalArguments(t, args + offset, i, count, data, true); unsigned returnCode = methodReturnCode(t, method); unsigned returnType = fieldType(t, returnCode); @@ -693,12 +705,11 @@ invokeNative(Thread* t, object method) if (methodVmFlags(t, method) & FastNative) { pushFrame(t, method); - unsigned footprint = methodParameterFootprint(t, method); - uintptr_t arguments[footprint]; - unsigned sp = frameBase(t, t->frame); - for (unsigned i = 0; i < footprint; ++i) { - arguments[i] = t->stack[((sp + i) * 2) + 1]; - } + object data = methodCode(t, method); + uintptr_t arguments[methodParameterFootprint(t, method)]; + marshalArguments + (t, arguments, (methodFlags(t, method) & ACC_STATIC) ? 1 : 0, + nativeMethodDataLength(t, data) - 1, data, false); uint64_t result = reinterpret_cast (nativeMethodDataFunction(t, methodCode(t, method))) From 31d9700c9bc4a8698d3522a86295bbf9221a4490 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 25 May 2009 21:36:29 -0600 Subject: [PATCH 058/172] move SystemClassLoader and Runtime.dumpHeap to avian package --- classpath/{java/lang => avian}/SystemClassLoader.java | 2 +- classpath/java/lang/Runtime.java | 2 -- src/builtin.cpp | 8 ++++---- src/types.def | 2 +- 4 files changed, 6 insertions(+), 8 deletions(-) rename classpath/{java/lang => avian}/SystemClassLoader.java (97%) diff --git a/classpath/java/lang/SystemClassLoader.java b/classpath/avian/SystemClassLoader.java similarity index 97% rename from classpath/java/lang/SystemClassLoader.java rename to classpath/avian/SystemClassLoader.java index 723651ca10..e85d240a85 100644 --- a/classpath/java/lang/SystemClassLoader.java +++ b/classpath/avian/SystemClassLoader.java @@ -8,7 +8,7 @@ There is NO WARRANTY for this software. See license.txt for details. */ -package java.lang; +package avian; import java.net.URL; import java.net.MalformedURLException; diff --git a/classpath/java/lang/Runtime.java b/classpath/java/lang/Runtime.java index 63a029301a..51f15006c7 100644 --- a/classpath/java/lang/Runtime.java +++ b/classpath/java/lang/Runtime.java @@ -75,8 +75,6 @@ public class Runtime { public native long totalMemory(); - public static native void dumpHeap(String outputFile); - private static class MyProcess extends Process { private long pid; private final int in; diff --git a/src/builtin.cpp b/src/builtin.cpp index f9bf0a8dd1..25a428b0a4 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -167,7 +167,7 @@ Avian_java_lang_ClassLoader_defineClass } extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_SystemClassLoader_findLoadedClass +Avian_avian_SystemClassLoader_findLoadedClass (Thread* t, object, uintptr_t* arguments) { object name = reinterpret_cast(arguments[1]); @@ -176,7 +176,7 @@ Avian_java_lang_SystemClassLoader_findLoadedClass } extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_SystemClassLoader_findClass +Avian_avian_SystemClassLoader_findClass (Thread* t, object, uintptr_t* arguments) { object name = reinterpret_cast(arguments[1]); @@ -185,7 +185,7 @@ Avian_java_lang_SystemClassLoader_findClass } extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_SystemClassLoader_resourceExists +Avian_avian_SystemClassLoader_resourceExists (Thread* t, object, uintptr_t* arguments) { object name = reinterpret_cast(arguments[1]); @@ -639,7 +639,7 @@ Avian_java_lang_Runtime_gc #ifdef AVIAN_HEAPDUMP extern "C" JNIEXPORT void JNICALL -Avian_java_lang_Runtime_dumpHeap +Avian_avian_Machine_dumpHeap (Thread* t, object, uintptr_t* arguments) { object outputFile = reinterpret_cast(*arguments); diff --git a/src/types.def b/src/types.def index c3d711c18a..98ad156f23 100644 --- a/src/types.def +++ b/src/types.def @@ -8,7 +8,7 @@ (type classLoader java/lang/ClassLoader) -(type systemClassLoader java/lang/SystemClassLoader) +(type systemClassLoader avian/SystemClassLoader) (type accessibleObject java/lang/reflect/AccessibleObject) From deefc47b1afd4fc5943ae1e3070c011484d220be Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 25 May 2009 21:39:17 -0600 Subject: [PATCH 059/172] correct comment in vmInvoke --- src/compile-x86.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compile-x86.S b/src/compile-x86.S index 74381bf061..ccd402d3b8 100644 --- a/src/compile-x86.S +++ b/src/compile-x86.S @@ -245,7 +245,7 @@ LOCAL(vmInvoke_argumentTest): .globl vmInvoke_returnAddress vmInvoke_returnAddress: - // restore stack pointer and callee-saved registers + // restore stack pointer movl %ebp,%ecx subl $16,%ecx movl %ecx,%esp From 31eb75a73674a4cff719401eb5cc5b064f7e9ce8 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 25 May 2009 23:27:10 -0600 Subject: [PATCH 060/172] support tail calls and continuations as build options --- makefile | 14 +++ src/assembler.h | 6 + src/compile.cpp | 289 ++++++++++++++++++++++++++++------------------- src/compiler.cpp | 46 ++++---- src/x86.cpp | 60 +++++----- 5 files changed, 250 insertions(+), 165 deletions(-) diff --git a/makefile b/makefile index 077222a5cf..a6341c1630 100644 --- a/makefile +++ b/makefile @@ -35,6 +35,12 @@ endif ifeq ($(heapdump),true) options := $(options)-heapdump endif +ifeq ($(tails),true) + options := $(options)-tails +endif +ifeq ($(continuations),true) + options := $(options)-continuations +endif root = $(shell (cd .. && pwd)) build = build @@ -254,6 +260,14 @@ ifeq ($(heapdump),true) cflags += -DAVIAN_HEAPDUMP endif +ifeq ($(tails),true) + cflags += -DAVIAN_TAILS +endif + +ifeq ($(continuations),true) + cflags += -DAVIAN_CONTINUATIONS +endif + bootimage-generator-sources = $(src)/bootimage.cpp bootimage-generator-objects = \ $(call cpp-objects,$(bootimage-generator-sources),$(src),$(native-build)) diff --git a/src/assembler.h b/src/assembler.h index 0bc97af8b8..c89aee8f67 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -16,6 +16,12 @@ namespace vm { +#ifdef AVIAN_TAILS +const bool TailCalls = true; +#else +const bool TailCalls = false; +#endif + enum Operation { Return, LoadBarrier, diff --git a/src/compile.cpp b/src/compile.cpp index 9b5e6da60c..5496779fb8 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -39,6 +39,12 @@ const bool DebugFrameMaps = false; const bool CheckArrayBounds = true; +#ifdef AVIAN_CONTINUATIONS +const bool Continuations = true; +#else +const bool Continuations = false; +#endif + const unsigned MaxNativeCallFootprint = 4; const unsigned InitialZoneCapacityInBytes = 64 * 1024; @@ -1425,7 +1431,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, = t->arch->argumentFootprint(methodParameterFootprint(t, target)); } - while (t->continuation) { + while (Continuations and t->continuation) { object c = t->continuation; object method = continuationMethod(t, c); @@ -1495,7 +1501,7 @@ makeCurrentContinuation(MyThread* t, void** targetIp, void** targetBase, unsigned argumentFootprint = t->arch->argumentFootprint(methodParameterFootprint(t, target)); unsigned alignment = t->arch->stackAlignmentInWords(); - if (argumentFootprint > alignment) { + if (TailCalls and argumentFootprint > alignment) { top += argumentFootprint - alignment; } @@ -1559,9 +1565,15 @@ unwind(MyThread* t) object& objectPools(MyThread* t); +object& +windMethod(MyThread* t); + object& rewindMethod(MyThread* t); +object& +receiveMethod(MyThread* t); + uintptr_t defaultThunk(MyThread* t); @@ -2144,7 +2156,7 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target, bool tailCall, unsigned flags = (tailCall ? Compiler::TailJump : 0); if (useThunk or (tailCall and (methodFlags(t, target) & ACC_NATIVE))) { - if (tailCall) { + if (TailCalls and tailCall) { TraceElement* trace = frame->trace(target, TraceElement::TailCall); Compiler::Operand* returnAddress = c->promiseConstant (new (frame->context->zone.allocate(sizeof(TraceElementPromise))) @@ -2409,12 +2421,13 @@ returnsNext(MyThread* t, object code, unsigned ip) bool isTailCall(MyThread* t, object code, unsigned ip, object caller, object callee) { - return (((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)) - and returnsNext(t, code, ip)); + 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)) + and returnsNext(t, code, ip); } void @@ -5111,7 +5124,8 @@ invokeNative(MyThread* t) if (UNLIKELY(t->exception)) { unwind(t); } else { - if (t->arch->argumentFootprint(parameterFootprint) + if (TailCalls + and t->arch->argumentFootprint(parameterFootprint) > t->arch->stackAlignmentInWords()) { t->stack = static_cast(t->stack) @@ -5542,6 +5556,117 @@ callContinuation(MyThread* t, object continuation, object result, } } +void +callWithCurrentContinuation(MyThread* t, object receiver) +{ + object method = 0; + void* ip = 0; + void* base = 0; + void* stack = 0; + unsigned oldArgumentFootprint = 0; + + { PROTECT(t, receiver); + + if (receiveMethod(t) == 0) { + const char* const className = "avian/CallbackReceiver"; + const char* const methodName = "receive"; + const char* const methodSpec = "(Lavian/Callback;)Ljava/lang/Object;"; + + object m = resolveMethod(t, className, methodName, methodSpec); + + if (m) { + receiveMethod(t) = m; + } else { + object message = makeString + (t, "%s %s not found in %s", methodName, methodSpec, className); + t->exception = makeNoSuchMethodError(t, message); + } + + if (LIKELY(t->exception == 0)) { + object continuationClass = arrayBody + (t, t->m->types, Machine::ContinuationType); + + if (classVmFlags(t, continuationClass) & BootstrapFlag) { + resolveClass(t, vm::className(t, continuationClass)); + } + } + } + + if (LIKELY(t->exception == 0)) { + method = findInterfaceMethod + (t, receiveMethod(t), objectClass(t, receiver)); + PROTECT(t, method); + + compile(t, ::codeAllocator(t), 0, method); + + if (LIKELY(t->exception == 0)) { + t->continuation = makeCurrentContinuation + (t, &ip, &base, &stack, &oldArgumentFootprint); + } + } + } + + if (LIKELY(t->exception == 0)) { + jumpAndInvoke + (t, method, base, stack, oldArgumentFootprint, receiver, + t->continuation); + } else { + unwind(t); + } +} + +void +dynamicWind(MyThread* t, object before, object thunk, object after) +{ + void* ip = 0; + void* base = 0; + void* stack = 0; + unsigned oldArgumentFootprint = 0; + + { PROTECT(t, before); + PROTECT(t, thunk); + PROTECT(t, after); + + if (windMethod(t) == 0) { + const char* const className = "avian/Continuations"; + const char* const methodName = "wind"; + const char* const methodSpec + = "(Ljava/lang/Runnable;Ljava/util/concurrent/Callable;" + "Ljava/lang/Runnable;)Lavian/Continuations$UnwindResult;"; + + object method = resolveMethod(t, className, methodName, methodSpec); + + if (method) { + windMethod(t) = method; + compile(t, ::codeAllocator(t), 0, method); + } else { + object message = makeString + (t, "%s %s not found in %s", methodName, methodSpec, className); + t->exception = makeNoSuchMethodError(t, message); + } + } + + if (LIKELY(t->exception == 0)) { + t->continuation = makeCurrentContinuation + (t, &ip, &base, &stack, &oldArgumentFootprint); + + object newContext = makeContinuationContext + (t, continuationContext(t, t->continuation), before, after, + t->continuation, t->trace->originalMethod); + + set(t, t->continuation, ContinuationContext, newContext); + } + } + + if (LIKELY(t->exception == 0)) { + jumpAndInvoke + (t, windMethod(t), base, stack, oldArgumentFootprint, before, thunk, + after); + } else { + unwind(t); + } +} + class ArgumentList { public: ArgumentList(Thread* t, uintptr_t* array, unsigned size, bool* objectMask, @@ -6213,132 +6338,52 @@ class MyProcessor: public Processor { (t->m->system->handleSegFault(&segFaultHandler))); } - virtual void callWithCurrentContinuation(Thread* vmt, object receiver) { - MyThread* t = static_cast(vmt); - - object method = 0; - void* ip = 0; - void* base = 0; - void* stack = 0; - unsigned oldArgumentFootprint = 0; - - { PROTECT(t, receiver); - - if (receiveMethod == 0) { - const char* const className = "avian/CallbackReceiver"; - const char* const methodName = "receive"; - const char* const methodSpec = "(Lavian/Callback;)Ljava/lang/Object;"; - - receiveMethod = resolveMethod(t, className, methodName, methodSpec); - - if (receiveMethod == 0) { - object message = makeString - (t, "%s %s not found in %s", methodName, methodSpec, className); - t->exception = makeNoSuchMethodError(t, message); - } - - if (LIKELY(t->exception == 0)) { - object continuationClass = arrayBody - (t, t->m->types, Machine::ContinuationType); - - if (classVmFlags(t, continuationClass) & BootstrapFlag) { - resolveClass(t, vm::className(t, continuationClass)); - } - } - } - - if (LIKELY(t->exception == 0)) { - method = findInterfaceMethod - (t, receiveMethod, objectClass(t, receiver)); - PROTECT(t, method); - - compile(t, ::codeAllocator(t), 0, method); - - if (LIKELY(t->exception == 0)) { - t->continuation = makeCurrentContinuation - (t, &ip, &base, &stack, &oldArgumentFootprint); - } - } - } - - if (LIKELY(t->exception == 0)) { - jumpAndInvoke - (t, method, base, stack, oldArgumentFootprint, receiver, - t->continuation); + virtual void callWithCurrentContinuation(Thread* t, object receiver) { + if (Continuations) { + ::callWithCurrentContinuation(static_cast(t), receiver); } else { - unwind(t); + abort(t); } } - virtual void dynamicWind(Thread* vmt, object before, object thunk, + virtual void dynamicWind(Thread* t, object before, object thunk, object after) { - MyThread* t = static_cast(vmt); - - void* ip = 0; - void* base = 0; - void* stack = 0; - unsigned oldArgumentFootprint = 0; - - { PROTECT(t, before); - PROTECT(t, thunk); - PROTECT(t, after); - - if (windMethod == 0) { - const char* const className = "avian/Continuations"; - const char* const methodName = "wind"; - const char* const methodSpec - = "(Ljava/lang/Runnable;Ljava/util/concurrent/Callable;" - "Ljava/lang/Runnable;)Lavian/Continuations$UnwindResult;"; - - windMethod = resolveMethod(t, className, methodName, methodSpec); - - if (windMethod) { - compile(t, ::codeAllocator(t), 0, windMethod); - } else { - object message = makeString - (t, "%s %s not found in %s", methodName, methodSpec, className); - t->exception = makeNoSuchMethodError(t, message); - } - } - - if (LIKELY(t->exception == 0)) { - t->continuation = makeCurrentContinuation - (t, &ip, &base, &stack, &oldArgumentFootprint); - - object newContext = makeContinuationContext - (t, continuationContext(t, t->continuation), before, after, - t->continuation, t->trace->originalMethod); - - set(t, t->continuation, ContinuationContext, newContext); - } - } - - if (LIKELY(t->exception == 0)) { - jumpAndInvoke - (t, windMethod, base, stack, oldArgumentFootprint, before, thunk, - after); + if (Continuations) { + ::dynamicWind(static_cast(t), before, thunk, after); } else { - unwind(t); - } + abort(t); + } } - virtual void feedResultToContinuation(Thread* vmt, object continuation, + virtual void feedResultToContinuation(Thread* t, object continuation, object result) { - callContinuation(static_cast(vmt), continuation, result, 0); + if (Continuations) { + callContinuation(static_cast(t), continuation, result, 0); + } else { + abort(t); + } } - virtual void feedExceptionToContinuation(Thread* vmt, object continuation, + virtual void feedExceptionToContinuation(Thread* t, object continuation, object exception) { - callContinuation(static_cast(vmt), continuation, 0, exception); + if (Continuations) { + callContinuation(static_cast(t), continuation, 0, exception); + } else { + abort(t); + } } virtual void walkContinuationBody(Thread* t, Heap::Walker* w, object o, unsigned start) { - ::walkContinuationBody(static_cast(t), w, o, start); + if (Continuations) { + ::walkContinuationBody(static_cast(t), w, o, start); + } else { + abort(t); + } } System* s; @@ -6969,12 +7014,24 @@ objectPools(MyThread* t) return processor(t)->objectPools; } +object& +windMethod(MyThread* t) +{ + return processor(t)->windMethod; +} + object& rewindMethod(MyThread* t) { return processor(t)->rewindMethod; } +object& +receiveMethod(MyThread* t) +{ + return processor(t)->receiveMethod; +} + uintptr_t defaultThunk(MyThread* t) { diff --git a/src/compiler.cpp b/src/compiler.cpp index e8cd1e0b40..6742dbb459 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -2392,7 +2392,7 @@ class CallEvent: public Event { int framePointerIndex; int frameOffset; - if (flags & Compiler::TailJump) { + if (TailCalls and (flags & Compiler::TailJump)) { assert(c, argumentCount == 0); int base = frameBase(c); @@ -2433,7 +2433,7 @@ class CallEvent: public Event { } } - if ((flags & Compiler::TailJump) == 0) { + if ((not TailCalls) or (flags & Compiler::TailJump) == 0) { stackArgumentIndex = c->localFootprint; if (stackBefore) { stackArgumentIndex += stackBefore->index + 1 - stackArgumentFootprint; @@ -2475,7 +2475,7 @@ class CallEvent: public Event { virtual void compile(Context* c) { UnaryOperation op; - if (flags & Compiler::TailJump) { + if (TailCalls and (flags & Compiler::TailJump)) { if (flags & Compiler::Aligned) { op = AlignedJump; } else { @@ -2525,25 +2525,29 @@ class CallEvent: public Event { stackArgumentIndex); } - if (flags & Compiler::TailJump) { - if (returnAddressSurrogate) { - returnAddressSurrogate->source->thaw(c, returnAddressSurrogate); - } + if (TailCalls) { + if (flags & Compiler::TailJump) { + if (returnAddressSurrogate) { + returnAddressSurrogate->source->thaw(c, returnAddressSurrogate); + } - if (framePointerSurrogate) { - framePointerSurrogate->source->thaw(c, framePointerSurrogate); - } - } else { - unsigned footprint = c->arch->argumentFootprint(stackArgumentFootprint); - if (footprint > c->arch->stackAlignmentInWords()) { - Assembler::Register stack(c->arch->stack()); - ResolvedPromise adjustmentPromise - ((footprint - c->arch->stackAlignmentInWords()) * BytesPerWord); - Assembler::Constant adjustmentConstant(&adjustmentPromise); - c->assembler->apply - (Subtract, BytesPerWord, ConstantOperand, &adjustmentConstant, - BytesPerWord, RegisterOperand, &stack, - BytesPerWord, RegisterOperand, &stack); + if (framePointerSurrogate) { + framePointerSurrogate->source->thaw(c, framePointerSurrogate); + } + } else { + unsigned footprint = c->arch->argumentFootprint + (stackArgumentFootprint); + + if (footprint > c->arch->stackAlignmentInWords()) { + Assembler::Register stack(c->arch->stack()); + ResolvedPromise adjustmentPromise + ((footprint - c->arch->stackAlignmentInWords()) * BytesPerWord); + Assembler::Constant adjustmentConstant(&adjustmentPromise); + c->assembler->apply + (Subtract, BytesPerWord, ConstantOperand, &adjustmentConstant, + BytesPerWord, RegisterOperand, &stack, + BytesPerWord, RegisterOperand, &stack); + } } } diff --git a/src/x86.cpp b/src/x86.cpp index 9d6f521b56..3fd93af296 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -2412,44 +2412,48 @@ class MyAssembler: public Assembler { int returnAddressSurrogate, int framePointerSurrogate) { - if (offset) { - Register tmp(c.client->acquireTemporary()); + if (TailCalls) { + if (offset) { + Register tmp(c.client->acquireTemporary()); - Memory returnAddressSrc(rsp, (footprint + 1) * BytesPerWord); - moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &tmp); + Memory returnAddressSrc(rsp, (footprint + 1) * BytesPerWord); + moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &tmp); - Memory returnAddressDst(rsp, (footprint - offset + 1) * BytesPerWord); - moveRM(&c, BytesPerWord, &tmp, BytesPerWord, &returnAddressDst); + Memory returnAddressDst(rsp, (footprint - offset + 1) * BytesPerWord); + moveRM(&c, BytesPerWord, &tmp, BytesPerWord, &returnAddressDst); - c.client->releaseTemporary(tmp.low); + c.client->releaseTemporary(tmp.low); - Memory baseSrc(rsp, footprint * BytesPerWord); - Register base(rbp); - moveMR(&c, BytesPerWord, &baseSrc, BytesPerWord, &base); + Memory baseSrc(rsp, footprint * BytesPerWord); + Register base(rbp); + moveMR(&c, BytesPerWord, &baseSrc, BytesPerWord, &base); - Register stack(rsp); - Constant footprintConstant - (resolved(&c, (footprint - offset + 1) * BytesPerWord)); - addCR(&c, BytesPerWord, &footprintConstant, BytesPerWord, &stack); + Register stack(rsp); + Constant footprintConstant + (resolved(&c, (footprint - offset + 1) * BytesPerWord)); + addCR(&c, BytesPerWord, &footprintConstant, BytesPerWord, &stack); - if (returnAddressSurrogate != NoRegister) { - assert(&c, offset > 0); + if (returnAddressSurrogate != NoRegister) { + assert(&c, offset > 0); - Register ras(returnAddressSurrogate); - Memory dst(rsp, offset * BytesPerWord); - moveRM(&c, BytesPerWord, &ras, BytesPerWord, &dst); - } + Register ras(returnAddressSurrogate); + Memory dst(rsp, offset * BytesPerWord); + moveRM(&c, BytesPerWord, &ras, BytesPerWord, &dst); + } - if (framePointerSurrogate != NoRegister) { - assert(&c, offset > 0); + if (framePointerSurrogate != NoRegister) { + assert(&c, offset > 0); - Register fps(framePointerSurrogate); - Memory dst(rsp, (offset - 1) * BytesPerWord); - moveRM(&c, BytesPerWord, &fps, BytesPerWord, &dst); + Register fps(framePointerSurrogate); + Memory dst(rsp, (offset - 1) * BytesPerWord); + moveRM(&c, BytesPerWord, &fps, BytesPerWord, &dst); + } + } else { + popFrame(); } } else { - popFrame(); - } + abort(&c); + } } virtual void popFrameAndPopArgumentsAndReturn(unsigned argumentFootprint) { @@ -2458,7 +2462,7 @@ class MyAssembler: public Assembler { assert(&c, argumentFootprint >= StackAlignmentInWords); assert(&c, (argumentFootprint % StackAlignmentInWords) == 0); - if (argumentFootprint > StackAlignmentInWords) { + if (TailCalls and argumentFootprint > StackAlignmentInWords) { Register returnAddress(rcx); popR(&c, BytesPerWord, &returnAddress); From 4eeabbeec3b4f452b240fe277ce5ef01b397bece Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 25 May 2009 23:27:47 -0600 Subject: [PATCH 061/172] point javac to the right output directory when building extra tests --- makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefile b/makefile index a6341c1630..b9a8f15078 100644 --- a/makefile +++ b/makefile @@ -412,7 +412,7 @@ $(test-dep): $(test-sources) $(test-extra-dep): $(test-extra-sources) @echo "compiling extra test classes" @mkdir -p $(dir $(@)) - $(javac) -d $(test) -bootclasspath $(classpath-build) \ + $(javac) -d $(test-build) -bootclasspath $(classpath-build) \ $(shell $(MAKE) -s --no-print-directory $(test-extra-classes)) @touch $(@) From a8c836d2cb444559ca0d8e0905f79e09fbf5735b Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 25 May 2009 23:30:40 -0600 Subject: [PATCH 062/172] move continuations tests into test/extra --- test/{ => extra}/Continuations.java | 2 ++ test/{ => extra}/Coroutines.java | 2 ++ test/{ => extra}/DynamicWind.java | 2 ++ 3 files changed, 6 insertions(+) rename test/{ => extra}/Continuations.java (98%) rename test/{ => extra}/Coroutines.java (99%) rename test/{ => extra}/DynamicWind.java (99%) diff --git a/test/Continuations.java b/test/extra/Continuations.java similarity index 98% rename from test/Continuations.java rename to test/extra/Continuations.java index 3ee444b02a..a439d8a58d 100644 --- a/test/Continuations.java +++ b/test/extra/Continuations.java @@ -1,3 +1,5 @@ +package extra; + import static avian.Continuations.callWithCurrentContinuation; import avian.CallbackReceiver; diff --git a/test/Coroutines.java b/test/extra/Coroutines.java similarity index 99% rename from test/Coroutines.java rename to test/extra/Coroutines.java index 62cea719ec..7d4ee9c5a5 100644 --- a/test/Coroutines.java +++ b/test/extra/Coroutines.java @@ -1,3 +1,5 @@ +package extra; + import static avian.Continuations.callWithCurrentContinuation; import avian.CallbackReceiver; diff --git a/test/DynamicWind.java b/test/extra/DynamicWind.java similarity index 99% rename from test/DynamicWind.java rename to test/extra/DynamicWind.java index 18419b335c..aa617ddc9c 100644 --- a/test/DynamicWind.java +++ b/test/extra/DynamicWind.java @@ -1,3 +1,5 @@ +package extra; + import static avian.Continuations.callWithCurrentContinuation; import static avian.Continuations.dynamicWind; From 9ddbf14b6cf9a9a8589a98d5ce1d590236745e0e Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 25 May 2009 23:31:13 -0600 Subject: [PATCH 063/172] add classpath/avian/Machine.java --- classpath/avian/Machine.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 classpath/avian/Machine.java diff --git a/classpath/avian/Machine.java b/classpath/avian/Machine.java new file mode 100644 index 0000000000..cbc62efae6 --- /dev/null +++ b/classpath/avian/Machine.java @@ -0,0 +1,17 @@ +/* Copyright (c) 2009, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package avian; + +public abstract class Machine { + + public static native void dumpHeap(String outputFile); + +} From 2608a2ee433a993ee634dddf14bdef2a0dd2aa88 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 26 May 2009 19:02:39 -0600 Subject: [PATCH 064/172] progress towards powerpc continuation and tail call support --- src/assembler.h | 3 +- src/common.h | 2 +- src/compile-powerpc.S | 163 +++++++++++++++++++++++++++++++++++++----- src/compile-x86.S | 23 +++--- src/compile.cpp | 17 ++--- src/compiler.cpp | 22 +++--- src/powerpc.S | 2 + src/powerpc.cpp | 49 ++++++++++--- src/x86.cpp | 8 +++ 9 files changed, 231 insertions(+), 58 deletions(-) diff --git a/src/assembler.h b/src/assembler.h index c89aee8f67..26b1f9b509 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -232,7 +232,7 @@ class Assembler { class Memory: public Operand { public: - Memory(int base, int offset, int index = NoRegister, unsigned scale = 0): + Memory(int base, int offset, int index = NoRegister, unsigned scale = 1): base(base), offset(offset), index(index), scale(scale) { } @@ -327,6 +327,7 @@ class Assembler { virtual void saveFrame(unsigned stackOffset, unsigned baseOffset) = 0; virtual void pushFrame(unsigned argumentCount, ...) = 0; virtual void allocateFrame(unsigned footprint) = 0; + virtual void adjustFrame(unsigned footprint) = 0; virtual void popFrame() = 0; virtual void popFrameForTailCall(unsigned footprint, int offset, int returnAddressSurrogate, diff --git a/src/common.h b/src/common.h index 8ab02e4041..94d351d5d3 100644 --- a/src/common.h +++ b/src/common.h @@ -30,7 +30,7 @@ #endif #if (defined __i386__) || (defined __POWERPC__) -# define LD "d" +# define LD "ld" # define LLD "lld" #ifdef __APPLE__ # define ULD "lu" diff --git a/src/compile-powerpc.S b/src/compile-powerpc.S index 3a72334fcf..034ca9321e 100644 --- a/src/compile-powerpc.S +++ b/src/compile-powerpc.S @@ -17,14 +17,28 @@ #define ARGUMENT_BASE BYTES_PER_WORD * LINKAGE_AREA #define LOCAL(x) L##x - + #ifdef __APPLE__ -.globl _vmInvoke -_vmInvoke: +# define GLOBAL(x) _##x #else -.globl vmInvoke -vmInvoke: +# define GLOBAL(x) x #endif + +#define THREAD_CONTINUATION 96 +#define THREAD_EXCEPTION 36 +#define THREAD_EXCEPTION_STACK_ADJUSTMENT 100 +#define THREAD_EXCEPTION_OFFSET 104 +#define THREAD_EXCEPTION_HANDLER 108 + +#define CONTINUATION_NEXT 4 +#define CONTINUATION_ADDRESS 16 +#define CONTINUATION_RETURN_ADDRESS_OFFSET 20 +#define CONTINUATION_FRAME_POINTER_OFFSET 24 +#define CONTINUATION_LENGTH 28 +#define CONTINUATION_BODY 32 + +.globl GLOBAL(vmInvoke) +GLOBAL(vmInvoke): // save return address mflr r0 stw r0,8(r1) @@ -73,24 +87,95 @@ vmInvoke: // copy arguments into place li r16,0 - b LOCAL(test) + b LOCAL(vmInvoke_argumentTest) -LOCAL(loop): +LOCAL(vmInvoke_argumentLoop): lwzx r17,r16,r5 addi r18,r16,ARGUMENT_BASE stwx r17,r18,r1 addi r16,r16,BYTES_PER_WORD -LOCAL(test): +LOCAL(vmInvoke_argumentTest): cmplw r16,r6 - blt LOCAL(loop) + blt LOCAL(vmInvoke_argumentLoop) // load and call function address mtctr r4 bctrl +.globl GLOBAL(vmInvoke_returnAddress) +GLOBAL(vmInvoke_returnAddress): // restore stack pointer lwz r1,0(r1) + +#ifdef AVIAN_CONTINUATIONS + // call the next continuation, if any + lwz r5,THREAD_CONTINUATION(r13) + cmplwi r5,0 + beq LOCAL(vmInvoke_exit) + + lwz r6,CONTINUATION_LENGTH(r5) + slwi r6,r6,2 + subfic r6,r6,-80 + stwux r1,r1,r6 + + addi r7,r5,CONTINUATION_BODY + + li r8,0 + b LOCAL(vmInvoke_continuationTest) + +LOCAL(vmInvoke_continuationLoop): + lwzx r9,r7,r8 + stwx r9,r1,r8 + addi r8,r8,4 + +LOCAL(vmInvoke_continuationTest): + cmplw r8,r6 + ble LOCAL(vmInvoke_continuationLoop) + + lwz r7,CONTINUATION_RETURN_ADDRESS_OFFSET(r5) + bl LOCAL(vmInvoke_getPC) + +LOCAL(vmInvoke_getPC): + mflr r10 + addis r10,r10,ha16(GLOBAL(vmInvoke_returnAddress)-LOCAL(vmInvoke_getPC)) + la r10,lo16(GLOBAL(vmInvoke_returnAddress)-LOCAL(vmInvoke_getPC))(r10) + stwx r10,r1,r7 + + lwz r7,CONTINUATION_FRAME_POINTER_OFFSET(r5) + lwz r8,0(r1) + add r7,r7,r1 + stw r8,0(r7) + stw r7,0(r1) + + lwz r7,CONTINUATION_NEXT(r5) + stw r7,THREAD_CONTINUATION(r13) + + // call the continuation unless we're handling an exception + lwz r7,THREAD_EXCEPTION(r13) + cmpwi r7,0 + bne LOCAL(vmInvoke_handleException) + addi r7,r5,CONTINUATION_ADDRESS + mtctr r7 + bctr + +LOCAL(vmInvoke_handleException): + // we're handling an exception - call the exception handler instead + li r8,0 + stw r8,THREAD_EXCEPTION(r13) + lwz r8,THREAD_EXCEPTION_STACK_ADJUSTMENT(r13) + lwz r9,0(r1) + subfic r8,r8,0 + stwux r9,r1,r8 + lwz r8,THREAD_EXCEPTION_OFFSET(r13) + stwx r7,r1,r8 + + addi r7,r13,THREAD_EXCEPTION_HANDLER + mtctr r7 + bctr + +LOCAL(vmInvoke_exit): +#endif // AVIAN_CONTINUATIONS // restore callee-saved registers subi r9,r1,80 @@ -118,23 +203,67 @@ LOCAL(test): // handle return value based on expected type lwz r8,44(r1) -LOCAL(void): +LOCAL(vmInvoke_void): cmplwi r8,VOID_TYPE - bne LOCAL(int64) - b LOCAL(exit) + bne LOCAL(vmInvoke_int64) + b LOCAL(vmInvoke_return) -LOCAL(int64): +LOCAL(vmInvoke_int64): cmplwi r8,INT64_TYPE - bne LOCAL(int32) - b LOCAL(exit) + bne LOCAL(vmInvoke_int32) + b LOCAL(vmInvoke_return) -LOCAL(int32): +LOCAL(vmInvoke_int32): li r3,0 -LOCAL(exit): +LOCAL(vmInvoke_return): // load return address lwz r0,8(r1) mtlr r0 // return blr + +.globl GLOBAL(vmJumpAndInvoke) +GLOBAL(vmJumpAndInvoke): + // r3: thread + // r4: address + // r5: (unused) + // r6: stack + // r7: argumentFootprint + // r8: arguments + // r9: frameSize + + stw r6,0(r1) + + mr r13,r3 + + // copy arguments into place + li r9,0 + addi r10,r6,ARGUMENT_BASE + b LOCAL(vmJumpAndInvoke_argumentTest) + +LOCAL(vmJumpAndInvoke_argumentLoop): + lwzx r11,r8,r9 + stwx r11,r10,r9 + addi r9,r9,4 + +LOCAL(vmJumpAndInvoke_argumentTest): + cmplw r9,r7 + ble LOCAL(vmJumpAndInvoke_argumentLoop) + + subf r7,r6,r9 + stw r6,0(r7) + mr r1,r7 + + // set return address + bl LOCAL(vmJumpAndInvoke_getPC) + +LOCAL(vmJumpAndInvoke_getPC): + mflr r10 + addis r10,r10,ha16(GLOBAL(vmInvoke_returnAddress)-LOCAL(vmJumpAndInvoke_getPC)) + la r10,lo16(GLOBAL(vmInvoke_returnAddress)-LOCAL(vmJumpAndInvoke_getPC))(r10) + mtlr r10 + + mtctr r4 + bctr diff --git a/src/compile-x86.S b/src/compile-x86.S index ccd402d3b8..cfc104c463 100644 --- a/src/compile-x86.S +++ b/src/compile-x86.S @@ -148,15 +148,20 @@ LOCAL(vmInvoke_exit): .globl vmJumpAndInvoke vmJumpAndInvoke: - // %rdi: thread - // %rsi: address - // %rdx: base - // %rcx: stack - // %r8 : argumentFootprint - // %r9 : arguments + // %rdi: thread + // %rsi: address + // %rdx: base + // %rcx: stack + // %r8 : argumentFootprint + // %r9 : arguments + // 8(%rsp): frameSize + movq %rdx,%rbp + movq %rdi,%rbx + subq 8(%rsp),%rcx + // set return address movq vmInvoke_returnAddress@GOTPCREL(%rip),%r10 movq %r10,(%rcx) @@ -174,7 +179,6 @@ LOCAL(vmJumpAndInvoke_argumentTest): cmpq %r8,%r11 jb LOCAL(vmJumpAndInvoke_argumentLoop) - movq %rdx,%rbp movq %rcx,%rsp jmp *%rsi @@ -351,8 +355,12 @@ vmJumpAndInvoke: // 16(%esp): stack // 20(%esp): argumentFootprint // 24(%esp): arguments + // 28(%esp): frameSize + movl 12(%esp),%ebp + movl 16(%esp),%ecx + subl 28(%esp),%ecx // set return address call LOCAL(getPC) @@ -377,7 +385,6 @@ LOCAL(vmJumpAndInvoke_argumentTest): movl 4(%esp),%ebx movl 8(%esp),%esi - movl 12(%esp),%ebp movl %ecx,%esp jmp *%esi diff --git a/src/compile.cpp b/src/compile.cpp index 5496779fb8..fe5a05d3ea 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -24,14 +24,15 @@ vmInvoke(void* thread, void* function, void* arguments, extern "C" void vmJumpAndInvoke(void* thread, void* function, void* base, void* stack, - unsigned argumentFootprint, uintptr_t* arguments); + unsigned argumentFootprint, uintptr_t* arguments, + unsigned frameSize); extern "C" void vmCall(); namespace { -const bool DebugCompile = false; +const bool DebugCompile = true; const bool DebugNatives = false; const bool DebugCallTable = false; const bool DebugMethodTree = false; @@ -5413,13 +5414,13 @@ jumpAndInvoke(MyThread* t, object method, void* base, void* stack, vmJumpAndInvoke (t, reinterpret_cast(methodAddress(t, method)), base, - static_cast(stack) - + oldArgumentFootprint - - t->arch->argumentFootprint(argumentCount) - - t->arch->frameFooterSize() - - t->arch->frameReturnAddressSize(), + stack, argumentCount * BytesPerWord, - arguments); + arguments, + (oldArgumentFootprint + - t->arch->argumentFootprint(argumentCount) + - t->arch->frameFooterSize() + - t->arch->frameReturnAddressSize()) * BytesPerWord); } void diff --git a/src/compiler.cpp b/src/compiler.cpp index 6742dbb459..e594e64717 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -384,13 +384,13 @@ unsigned RegisterResource::toString(Context* c, char* buffer, unsigned bufferSize) { return snprintf - (buffer, bufferSize, "register %"LD, this - c->registerResources); + (buffer, bufferSize, "register %d", this - c->registerResources); } unsigned FrameResource::toString(Context* c, char* buffer, unsigned bufferSize) { - return snprintf(buffer, bufferSize, "frame %"LD, this - c->frameResources); + return snprintf(buffer, bufferSize, "frame %d", this - c->frameResources); } class PoolPromise: public Promise { @@ -679,8 +679,7 @@ offsetToFrameIndex(Context* c, unsigned offset) { assert(c, static_cast ((offset / BytesPerWord) - c->arch->frameFooterSize()) >= 0); - - assert(c, (offset / BytesPerWord) - c->arch->frameFooterSize() + assert(c, ((offset / BytesPerWord) - c->arch->frameFooterSize()) < totalFrameSize(c)); return (offset / BytesPerWord) - c->arch->frameFooterSize(); @@ -689,7 +688,8 @@ offsetToFrameIndex(Context* c, unsigned offset) unsigned frameBase(Context* c) { - return c->alignedFrameSize - 1 + return c->alignedFrameSize + - c->arch->frameReturnAddressSize() - c->arch->frameFooterSize() + c->arch->frameHeaderSize(); } @@ -1262,7 +1262,7 @@ pickTarget(Context* c, Read* read, bool intersectRead, } } } - + best = pickTarget(c, read->value, mask, registerPenalty, best); if (best.cost <= Target::MinimumFrameCost) { return best; @@ -2539,14 +2539,8 @@ class CallEvent: public Event { (stackArgumentFootprint); if (footprint > c->arch->stackAlignmentInWords()) { - Assembler::Register stack(c->arch->stack()); - ResolvedPromise adjustmentPromise - ((footprint - c->arch->stackAlignmentInWords()) * BytesPerWord); - Assembler::Constant adjustmentConstant(&adjustmentPromise); - c->assembler->apply - (Subtract, BytesPerWord, ConstantOperand, &adjustmentConstant, - BytesPerWord, RegisterOperand, &stack, - BytesPerWord, RegisterOperand, &stack); + c->assembler->adjustFrame + (footprint - c->arch->stackAlignmentInWords()); } } } diff --git a/src/powerpc.S b/src/powerpc.S index fba6f52ec0..fce2079af7 100644 --- a/src/powerpc.S +++ b/src/powerpc.S @@ -161,4 +161,6 @@ vmJump: mtlr r3 mr r1,r5 mr r13,r6 + mr r4,r7 + mr r3,r8 blr diff --git a/src/powerpc.cpp b/src/powerpc.cpp index dc1e315ebb..2477cc5af0 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -65,7 +65,7 @@ inline int sth(int rs, int ra, int i) { return D(44, rs, ra, i); } inline int sthx(int rs, int ra, int rb) { return X(31, rs, ra, rb, 407, 0); } inline int stw(int rs, int ra, int i) { return D(36, rs, ra, i); } inline int stwu(int rs, int ra, int i) { return D(37, rs, ra, i); } -inline int stwux(int rs, int ra, int i) { return X(31, rs, ra, rb, 183, 0); } +inline int stwux(int rs, int ra, int rb) { return X(31, rs, ra, rb, 183, 0); } inline int stwx(int rs, int ra, int rb) { return X(31, rs, ra, rb, 151, 0); } inline int add(int rt, int ra, int rb) { return XO(31, rt, ra, rb, 0, 266, 0); } inline int addc(int rt, int ra, int rb) { return XO(31, rt, ra, rb, 0, 10, 0); } @@ -137,7 +137,7 @@ inline int blt(int i) { return bc(12, 0, i, 0); } inline int bgt(int i) { return bc(12, 1, i, 0); } inline int bge(int i) { return bc(4, 0, i, 0); } inline int ble(int i) { return bc(4, 1, i, 0); } -inline int be(int i) { return bc(12, 2, i, 0); } +inline int beq(int i) { return bc(12, 2, i, 0); } inline int bne(int i) { return bc(4, 2, i, 0); } inline int cmpw(int ra, int rb) { return cmp(0, ra, rb); } inline int cmplw(int ra, int rb) { return cmpl(0, ra, rb); } @@ -160,6 +160,7 @@ carry16(intptr_t v) const unsigned FrameFooterSize = 6; const unsigned StackAlignmentInBytes = 16; +const unsigned StackAlignmentInWords = StackAlignmentInBytes / BytesPerWord; const int StackRegister = 1; const int ThreadRegister = 13; @@ -1507,7 +1508,7 @@ jumpIfEqualC(Context* c, unsigned size UNUSED, Assembler::Constant* target) assert(c, size == BytesPerWord); appendOffsetTask(c, target->value, offset(c), true); - issue(c, be(0)); + issue(c, beq(0)); } void @@ -1688,6 +1689,14 @@ class MyArchitecture: public Assembler::Architecture { return (BytesPerWord == 4 ? 3 : NoRegister); } + virtual int virtualCallTarget() { + return 4; + } + + virtual int virtualCallIndex() { + return 3; + } + virtual bool condensedAddressing() { return false; } @@ -1708,7 +1717,7 @@ class MyArchitecture: public Assembler::Architecture { } } - virtual unsigned stackPadding(unsigned footprint) { + virtual unsigned frameFootprint(unsigned footprint) { return max(footprint, StackAlignmentInWords); } @@ -1726,11 +1735,16 @@ class MyArchitecture: public Assembler::Architecture { return index + 3; } + virtual unsigned stackAlignmentInWords() { + return StackAlignmentInWords; + } + virtual bool matchCall(void* returnAddress, void* target) { uint32_t* instruction = static_cast(returnAddress) - 1; - return *instruction == bl(static_cast(target) - - reinterpret_cast(instruction)); + return *instruction == static_cast + (bl(static_cast(target) + - reinterpret_cast(instruction))); } virtual void updateCall(UnaryOperation op UNUSED, @@ -1788,6 +1802,14 @@ class MyArchitecture: public Assembler::Architecture { return FrameFooterSize; } + virtual int returnAddressOffset() { + return 8 / BytesPerWord; + } + + virtual int framePointerOffset() { + return 0; + } + virtual void nextFrame(void** stack, void**) { assert(&c, *static_cast(*stack) != *stack); @@ -1971,6 +1993,15 @@ class MyAssembler: public Assembler { moveAndUpdateRM(&c, BytesPerWord, &stack, BytesPerWord, &stackDst); } + virtual void adjustFrame(unsigned footprint) { + Register nextStack(0); + Memory stackSrc(StackRegister, 0); + moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &nextStack); + + Memory stackDst(StackRegister, -footprint * BytesPerWord); + moveAndUpdateRM(&c, BytesPerWord, &nextStack, BytesPerWord, &stackDst); + } + virtual void popFrame() { Register stack(StackRegister); Memory stackSrc(StackRegister, 0); @@ -2024,8 +2055,8 @@ class MyAssembler: public Assembler { virtual void popFrameAndPopArgumentsAndReturn(unsigned argumentFootprint) { popFrame(); - assert(c, argumentFootprint >= StackAlignmentInWords); - assert(c, (argumentFootprint % StackAlignmentInWords) == 0); + assert(&c, argumentFootprint >= StackAlignmentInWords); + assert(&c, (argumentFootprint % StackAlignmentInWords) == 0); if (argumentFootprint > StackAlignmentInWords) { Register tmp(0); @@ -2049,7 +2080,7 @@ class MyAssembler: public Assembler { moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &tmp1); Register tmp2(arch_->returnLow()); - Memory newStackSrc(ThreadRegister, stackOffsetFromThread); + Memory newStackSrc(ThreadRegister, stackOffset); moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &tmp2); Register stack(StackRegister); diff --git a/src/x86.cpp b/src/x86.cpp index 3fd93af296..50c8383862 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -2398,6 +2398,14 @@ class MyAssembler: public Assembler { BytesPerWord, RegisterOperand, &stack); } + virtual void adjustFrame(unsigned footprint) { + Register stack(rsp); + Constant footprintConstant(resolved(&c, footprint * BytesPerWord)); + apply(Subtract, BytesPerWord, ConstantOperand, &footprintConstant, + BytesPerWord, RegisterOperand, &stack, + BytesPerWord, RegisterOperand, &stack); + } + virtual void popFrame() { Register base(rbp); Register stack(rsp); From 49a2c1846d485c75bcb075651c92c075e850b3a9 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 26 May 2009 19:30:11 -0600 Subject: [PATCH 065/172] powerpc bugfixes --- src/powerpc.cpp | 57 +++++++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/src/powerpc.cpp b/src/powerpc.cpp index 2477cc5af0..12d66ea8af 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -2019,36 +2019,40 @@ class MyAssembler: public Assembler { int returnAddressSurrogate, int framePointerSurrogate) { - if (offset) { - Register tmp(0); - Memory returnAddressSrc(StackRegister, 8 + (footprint * BytesPerWord)); - moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &tmp); + if (TailCalls) { + if (offset) { + Register tmp(0); + Memory returnAddressSrc(StackRegister, 8 + (footprint * BytesPerWord)); + moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &tmp); - issue(&c, mtlr(tmp.low)); + issue(&c, mtlr(tmp.low)); - Memory stackSrc(StackRegister, footprint * BytesPerWord); - moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &tmp); + Memory stackSrc(StackRegister, footprint * BytesPerWord); + moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &tmp); - Memory stackDst(StackRegister, (footprint - offset) * BytesPerWord); - moveAndUpdateRM(&c, BytesPerWord, &tmp, BytesPerWord, &stackDst); + Memory stackDst(StackRegister, (footprint - offset) * BytesPerWord); + moveAndUpdateRM(&c, BytesPerWord, &tmp, BytesPerWord, &stackDst); - if (returnAddressSurrogate != NoRegister) { - assert(&c, offset > 0); + if (returnAddressSurrogate != NoRegister) { + assert(&c, offset > 0); - Register ras(returnAddressSurrogate); - Memory dst(StackRegister, 8 + (offset * BytesPerWord)); - moveRM(&c, BytesPerWord, &ras, BytesPerWord, &dst); - } + Register ras(returnAddressSurrogate); + Memory dst(StackRegister, 8 + (offset * BytesPerWord)); + moveRM(&c, BytesPerWord, &ras, BytesPerWord, &dst); + } - if (framePointerSurrogate != NoRegister) { - assert(&c, offset > 0); + if (framePointerSurrogate != NoRegister) { + assert(&c, offset > 0); - Register fps(framePointerSurrogate); - Memory dst(StackRegister, offset * BytesPerWord); - moveRM(&c, BytesPerWord, &fps, BytesPerWord, &dst); + Register fps(framePointerSurrogate); + Memory dst(StackRegister, offset * BytesPerWord); + moveRM(&c, BytesPerWord, &fps, BytesPerWord, &dst); + } + } else { + popFrame(); } } else { - popFrame(); + abort(&c); } } @@ -2058,7 +2062,7 @@ class MyAssembler: public Assembler { assert(&c, argumentFootprint >= StackAlignmentInWords); assert(&c, (argumentFootprint % StackAlignmentInWords) == 0); - if (argumentFootprint > StackAlignmentInWords) { + if (TailCalls and argumentFootprint > StackAlignmentInWords) { Register tmp(0); Memory stackSrc(StackRegister, 0); moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &tmp); @@ -2072,16 +2076,17 @@ class MyAssembler: public Assembler { return_(&c); } - virtual void popFrameAndUpdateStackAndReturn(unsigned stackOffset) { + virtual void popFrameAndUpdateStackAndReturn(unsigned stackOffsetFromThread) + { popFrame(); Register tmp1(0); Memory stackSrc(StackRegister, 0); moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &tmp1); - Register tmp2(arch_->returnLow()); - Memory newStackSrc(ThreadRegister, stackOffset); - moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &tmp2); + Register tmp2(5); + Memory newStackSrc(ThreadRegister, stackOffsetFromThread); + moveMR(&c, BytesPerWord, &newStackSrc, BytesPerWord, &tmp2); Register stack(StackRegister); subR(&c, BytesPerWord, &tmp2, &stack, &tmp2); From ec60b844d4a434d1f8b68e6cbbd4bb26374fe2cf Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 27 May 2009 18:15:39 -0600 Subject: [PATCH 066/172] fix powerpc tail calls --- src/powerpc.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/powerpc.cpp b/src/powerpc.cpp index 12d66ea8af..64e95df96d 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -1598,6 +1598,9 @@ populateTables(ArchitectureContext* c) uo[index(Jump, R)] = CAST1(jumpR); uo[index(Jump, C)] = CAST1(jumpC); + uo[index(AlignedJump, R)] = CAST1(jumpR); + uo[index(AlignedJump, C)] = CAST1(jumpC); + uo[index(JumpIfEqual, C)] = CAST1(jumpIfEqualC); uo[index(JumpIfNotEqual, C)] = CAST1(jumpIfNotEqualC); uo[index(JumpIfGreater, C)] = CAST1(jumpIfGreaterC); @@ -2089,7 +2092,7 @@ class MyAssembler: public Assembler { moveMR(&c, BytesPerWord, &newStackSrc, BytesPerWord, &tmp2); Register stack(StackRegister); - subR(&c, BytesPerWord, &tmp2, &stack, &tmp2); + subR(&c, BytesPerWord, &stack, &tmp2, &tmp2); Memory stackDst(StackRegister, 0, tmp2.low); moveAndUpdateRM(&c, BytesPerWord, &tmp1, BytesPerWord, &stackDst); From ca4e62cdb785904243509098a1549a7575a1a5b8 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 28 May 2009 18:51:53 -0600 Subject: [PATCH 067/172] pass -DAVIAN_CONTINUATIONS to assembler when continuations enabled --- makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/makefile b/makefile index b9a8f15078..a6845d4abb 100644 --- a/makefile +++ b/makefile @@ -266,6 +266,7 @@ endif ifeq ($(continuations),true) cflags += -DAVIAN_CONTINUATIONS + asmflags += -DAVIAN_CONTINUATIONS endif bootimage-generator-sources = $(src)/bootimage.cpp @@ -425,7 +426,7 @@ endef define compile-asm-object @echo "compiling $(@)" @mkdir -p $(dir $(@)) - $(cc) -I$(src) -c $(<) -o $(@) + $(cc) -I$(src) $(asmflags) -c $(<) -o $(@) endef $(vm-cpp-objects): $(native-build)/%.o: $(src)/%.cpp $(vm-depends) From d99f8df6e65b3928c95d48a48e68b376ec582cc2 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 28 May 2009 18:56:05 -0600 Subject: [PATCH 068/172] several bugfixes for powerpc continuations --- src/compile-powerpc.S | 56 +++++++++++++++++++++++++++---------------- src/compile.cpp | 50 +++++++++++++------------------------- 2 files changed, 52 insertions(+), 54 deletions(-) diff --git a/src/compile-powerpc.S b/src/compile-powerpc.S index 034ca9321e..03e85b1ff9 100644 --- a/src/compile-powerpc.S +++ b/src/compile-powerpc.S @@ -87,12 +87,12 @@ GLOBAL(vmInvoke): // copy arguments into place li r16,0 + addi r18,r1,ARGUMENT_BASE b LOCAL(vmInvoke_argumentTest) LOCAL(vmInvoke_argumentLoop): lwzx r17,r16,r5 - addi r18,r16,ARGUMENT_BASE - stwx r17,r18,r1 + stwx r17,r16,r18 addi r16,r16,BYTES_PER_WORD LOCAL(vmInvoke_argumentTest): @@ -102,9 +102,8 @@ LOCAL(vmInvoke_argumentTest): // load and call function address mtctr r4 bctrl - -.globl GLOBAL(vmInvoke_returnAddress) -GLOBAL(vmInvoke_returnAddress): + +LOCAL(vmInvoke_returnAddress): // restore stack pointer lwz r1,0(r1) @@ -116,17 +115,18 @@ GLOBAL(vmInvoke_returnAddress): lwz r6,CONTINUATION_LENGTH(r5) slwi r6,r6,2 - subfic r6,r6,-80 - stwux r1,r1,r6 + subfic r7,r6,-80 + stwux r1,r1,r7 addi r7,r5,CONTINUATION_BODY li r8,0 + addi r10,r1,ARGUMENT_BASE b LOCAL(vmInvoke_continuationTest) LOCAL(vmInvoke_continuationLoop): lwzx r9,r7,r8 - stwx r9,r1,r8 + stwx r9,r10,r8 addi r8,r8,4 LOCAL(vmInvoke_continuationTest): @@ -138,8 +138,7 @@ LOCAL(vmInvoke_continuationTest): LOCAL(vmInvoke_getPC): mflr r10 - addis r10,r10,ha16(GLOBAL(vmInvoke_returnAddress)-LOCAL(vmInvoke_getPC)) - la r10,lo16(GLOBAL(vmInvoke_returnAddress)-LOCAL(vmInvoke_getPC))(r10) + la r10,lo16(LOCAL(vmInvoke_returnAddress)-LOCAL(vmInvoke_getPC))(r10) stwx r10,r1,r7 lwz r7,CONTINUATION_FRAME_POINTER_OFFSET(r5) @@ -155,7 +154,7 @@ LOCAL(vmInvoke_getPC): lwz r7,THREAD_EXCEPTION(r13) cmpwi r7,0 bne LOCAL(vmInvoke_handleException) - addi r7,r5,CONTINUATION_ADDRESS + lwz r7,CONTINUATION_ADDRESS(r5) mtctr r7 bctr @@ -170,7 +169,7 @@ LOCAL(vmInvoke_handleException): lwz r8,THREAD_EXCEPTION_OFFSET(r13) stwx r7,r1,r8 - addi r7,r13,THREAD_EXCEPTION_HANDLER + lwz r7,THREAD_EXCEPTION_HANDLER(r13) mtctr r7 bctr @@ -226,6 +225,7 @@ LOCAL(vmInvoke_return): .globl GLOBAL(vmJumpAndInvoke) GLOBAL(vmJumpAndInvoke): +#ifdef AVIAN_CONTINUATIONS // r3: thread // r4: address // r5: (unused) @@ -234,36 +234,50 @@ GLOBAL(vmJumpAndInvoke): // r8: arguments // r9: frameSize + // restore (pseudo)-stack pointer (we don't want to touch the real + // stack pointer, since we haven't copied the arguments yet) + lwz r6,0(r6) + + // make everything between r1 and r6 one big stack frame while we + // shuffle things around stw r6,0(r1) + + // allocate new frame, adding room for callee-saved registers + subfic r10,r9,-80 + stwux r6,r6,r10 mr r13,r3 // copy arguments into place li r9,0 - addi r10,r6,ARGUMENT_BASE + addi r11,r6,ARGUMENT_BASE b LOCAL(vmJumpAndInvoke_argumentTest) LOCAL(vmJumpAndInvoke_argumentLoop): - lwzx r11,r8,r9 - stwx r11,r10,r9 + lwzx r12,r8,r9 + stwx r12,r11,r9 addi r9,r9,4 LOCAL(vmJumpAndInvoke_argumentTest): cmplw r9,r7 ble LOCAL(vmJumpAndInvoke_argumentLoop) - subf r7,r6,r9 - stw r6,0(r7) - mr r1,r7 + // the arguments have been copied, so we can set the real stack + // pointer now + mr r1,r6 - // set return address + // set return address to vmInvoke_returnAddress bl LOCAL(vmJumpAndInvoke_getPC) LOCAL(vmJumpAndInvoke_getPC): mflr r10 - addis r10,r10,ha16(GLOBAL(vmInvoke_returnAddress)-LOCAL(vmJumpAndInvoke_getPC)) - la r10,lo16(GLOBAL(vmInvoke_returnAddress)-LOCAL(vmJumpAndInvoke_getPC))(r10) + la r10,lo16(LOCAL(vmInvoke_returnAddress)-LOCAL(vmJumpAndInvoke_getPC))(r10) mtlr r10 mtctr r4 bctr +#else // not AVIAN_CONTINUATIONS + // vmJumpAndInvoke should only be called when continuations are + // enabled + trap +#endif // not AVIAN_CONTINUATIONS diff --git a/src/compile.cpp b/src/compile.cpp index fe5a05d3ea..8d51a80b5c 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -1380,7 +1380,7 @@ releaseLock(MyThread* t, object method, void* stack) void findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, - void** targetStack, unsigned* oldArgumentFootprint = 0) + void** targetStack) { void* ip = t->ip; void* base = t->base; @@ -1427,11 +1427,6 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, *targetStack = static_cast(stack) + t->arch->frameReturnAddressSize(); - if (oldArgumentFootprint) { - *oldArgumentFootprint - = t->arch->argumentFootprint(methodParameterFootprint(t, target)); - } - while (Continuations and t->continuation) { object c = t->continuation; @@ -1468,7 +1463,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, object makeCurrentContinuation(MyThread* t, void** targetIp, void** targetBase, - void** targetStack, unsigned* oldArgumentFootprint) + void** targetStack) { void* ip = t->ip; void* base = t->base; @@ -1498,7 +1493,8 @@ makeCurrentContinuation(MyThread* t, void** targetIp, void** targetBase, PROTECT(t, method); void** top = static_cast(stack) - + t->arch->frameReturnAddressSize(); + + t->arch->frameReturnAddressSize() + + t->arch->frameFooterSize(); unsigned argumentFootprint = t->arch->argumentFootprint(methodParameterFootprint(t, target)); unsigned alignment = t->arch->stackAlignmentInWords(); @@ -1518,9 +1514,11 @@ makeCurrentContinuation(MyThread* t, void** targetIp, void** targetBase, object c = makeContinuation (t, 0, context, method, ip, ((frameSize + + t->arch->frameFooterSize() + t->arch->returnAddressOffset() - t->arch->frameReturnAddressSize()) * BytesPerWord), ((frameSize + + t->arch->frameFooterSize() + t->arch->framePointerOffset() - t->arch->frameReturnAddressSize()) * BytesPerWord), totalSize); @@ -1541,9 +1539,7 @@ makeCurrentContinuation(MyThread* t, void** targetIp, void** targetBase, *targetIp = ip; *targetBase = base; *targetStack = static_cast(stack) - + t->arch->frameReturnAddressSize(); - *oldArgumentFootprint - = t->arch->argumentFootprint(methodParameterFootprint(t, target)); + + t->arch->frameReturnAddressSize();; } } @@ -5392,8 +5388,7 @@ compatibleReturnType(MyThread* t, object oldMethod, object newMethod) } void -jumpAndInvoke(MyThread* t, object method, void* base, void* stack, - unsigned oldArgumentFootprint, ...) +jumpAndInvoke(MyThread* t, object method, void* base, void* stack, ...) { t->trace->targetMethod = 0; @@ -5405,7 +5400,7 @@ jumpAndInvoke(MyThread* t, object method, void* base, void* stack, unsigned argumentCount = methodParameterFootprint(t, method); uintptr_t arguments[argumentCount]; - va_list a; va_start(a, oldArgumentFootprint); + va_list a; va_start(a, stack); for (unsigned i = 0; i < argumentCount; ++i) { arguments[i] = va_arg(a, uintptr_t); } @@ -5417,10 +5412,8 @@ jumpAndInvoke(MyThread* t, object method, void* base, void* stack, stack, argumentCount * BytesPerWord, arguments, - (oldArgumentFootprint - - t->arch->argumentFootprint(argumentCount) - - t->arch->frameFooterSize() - - t->arch->frameReturnAddressSize()) * BytesPerWord); + t->arch->alignFrameSize(t->arch->argumentFootprint(argumentCount)) + * BytesPerWord); } void @@ -5527,8 +5520,7 @@ callContinuation(MyThread* t, object continuation, object result, void* ip; void* base; void* stack; - unsigned oldArgumentFootprint; - findUnwindTarget(t, &ip, &base, &stack, &oldArgumentFootprint); + findUnwindTarget(t, &ip, &base, &stack); switch (action) { case Call: { @@ -5543,7 +5535,7 @@ callContinuation(MyThread* t, object continuation, object result, t->continuation = nextContinuation; jumpAndInvoke - (t, rewindMethod(t), base, stack, oldArgumentFootprint, + (t, rewindMethod(t), base, stack, continuationContextBefore(t, continuationContext(t, nextContinuation)), continuation, result, exception); } break; @@ -5564,7 +5556,6 @@ callWithCurrentContinuation(MyThread* t, object receiver) void* ip = 0; void* base = 0; void* stack = 0; - unsigned oldArgumentFootprint = 0; { PROTECT(t, receiver); @@ -5601,16 +5592,13 @@ callWithCurrentContinuation(MyThread* t, object receiver) compile(t, ::codeAllocator(t), 0, method); if (LIKELY(t->exception == 0)) { - t->continuation = makeCurrentContinuation - (t, &ip, &base, &stack, &oldArgumentFootprint); + t->continuation = makeCurrentContinuation(t, &ip, &base, &stack); } } } if (LIKELY(t->exception == 0)) { - jumpAndInvoke - (t, method, base, stack, oldArgumentFootprint, receiver, - t->continuation); + jumpAndInvoke(t, method, base, stack, receiver, t->continuation); } else { unwind(t); } @@ -5622,7 +5610,6 @@ dynamicWind(MyThread* t, object before, object thunk, object after) void* ip = 0; void* base = 0; void* stack = 0; - unsigned oldArgumentFootprint = 0; { PROTECT(t, before); PROTECT(t, thunk); @@ -5648,8 +5635,7 @@ dynamicWind(MyThread* t, object before, object thunk, object after) } if (LIKELY(t->exception == 0)) { - t->continuation = makeCurrentContinuation - (t, &ip, &base, &stack, &oldArgumentFootprint); + t->continuation = makeCurrentContinuation(t, &ip, &base, &stack); object newContext = makeContinuationContext (t, continuationContext(t, t->continuation), before, after, @@ -5660,9 +5646,7 @@ dynamicWind(MyThread* t, object before, object thunk, object after) } if (LIKELY(t->exception == 0)) { - jumpAndInvoke - (t, windMethod(t), base, stack, oldArgumentFootprint, before, thunk, - after); + jumpAndInvoke(t, windMethod(t), base, stack, before, thunk, after); } else { unwind(t); } From b4dea1f71cab703bf41eb2af3c70ce15b85595d6 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 28 May 2009 19:12:26 -0600 Subject: [PATCH 069/172] fix printf warnings in compiler.cpp --- src/compiler.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/compiler.cpp b/src/compiler.cpp index e594e64717..1b9b95ca44 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -384,13 +384,15 @@ unsigned RegisterResource::toString(Context* c, char* buffer, unsigned bufferSize) { return snprintf - (buffer, bufferSize, "register %d", this - c->registerResources); + (buffer, bufferSize, "register %d", static_cast + (this - c->registerResources)); } unsigned FrameResource::toString(Context* c, char* buffer, unsigned bufferSize) { - return snprintf(buffer, bufferSize, "frame %d", this - c->frameResources); + return snprintf(buffer, bufferSize, "frame %d", static_cast + (this - c->frameResources)); } class PoolPromise: public Promise { From 2478d4fc7f8692abc357f69540769e1500af7608 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 28 May 2009 19:13:15 -0600 Subject: [PATCH 070/172] conditionally include continuation code in compile-x86.S --- src/compile-x86.S | 49 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/src/compile-x86.S b/src/compile-x86.S index cfc104c463..e2ef5dd433 100644 --- a/src/compile-x86.S +++ b/src/compile-x86.S @@ -12,6 +12,12 @@ #define LOCAL(x) .L##x +#if defined __APPLE__ || defined __MINGW32__ || defined __CYGWIN32__ +# define GLOBAL(x) _##x +#else +# define GLOBAL(x) x +#endif + .text #ifdef __x86_64__ @@ -29,8 +35,8 @@ #define CONTINUATION_LENGTH 56 #define CONTINUATION_BODY 64 -.globl vmInvoke -vmInvoke: +.globl GLOBAL(vmInvoke) +GLOBAL(vmInvoke): pushq %rbp movq %rsp,%rbp @@ -74,11 +80,12 @@ LOCAL(vmInvoke_argumentTest): // call function call *%rsi -.globl vmInvoke_returnAddress -vmInvoke_returnAddress: +.globl GLOBAL(vmInvoke_returnAddress) +GLOBAL(vmInvoke_returnAddress): // restore stack pointer movq %rbp,%rsp +#ifdef AVIAN_CONTINUATIONS // call the next continuation, if any movq THREAD_CONTINUATION(%rbx),%rcx cmpq $0,%rcx @@ -132,6 +139,8 @@ LOCAL(vmInvoke_handleException): jmp *THREAD_EXCEPTION_HANDLER(%rbx) LOCAL(vmInvoke_exit): +#endif // AVIAN_CONTINUATIONS + // restore callee-saved registers movq %rsp,%r9 subq $48,%r9 @@ -146,8 +155,9 @@ LOCAL(vmInvoke_exit): popq %rbp ret -.globl vmJumpAndInvoke -vmJumpAndInvoke: +.globl GLOBAL(vmJumpAndInvoke) +GLOBAL(vmJumpAndInvoke): +#ifdef AVIAN_CONTINUATIONS // %rdi: thread // %rsi: address // %rdx: base @@ -182,6 +192,11 @@ LOCAL(vmJumpAndInvoke_argumentTest): movq %rcx,%rsp jmp *%rsi +#else // not AVIAN_CONTINUATIONS + // vmJumpAndInvoke should only be called when continuations are + // enabled + int3 +#endif // not AVIAN_CONTINUATIONS #elif defined __i386__ @@ -198,13 +213,8 @@ LOCAL(vmJumpAndInvoke_argumentTest): #define CONTINUATION_LENGTH 28 #define CONTINUATION_BODY 32 -#if defined __APPLE__ || defined __MINGW32__ || defined __CYGWIN32__ -.globl _vmInvoke -_vmInvoke: -#else -.globl vmInvoke -vmInvoke: -#endif +.globl GLOBAL(vmInvoke) +GLOBAL(vmInvoke): pushl %ebp movl %esp,%ebp @@ -254,6 +264,7 @@ vmInvoke_returnAddress: subl $16,%ecx movl %ecx,%esp +#ifdef AVIAN_CONTINUATIONS // call the next continuation, if any movl THREAD_CONTINUATION(%ebx),%ecx cmpl $0,%ecx @@ -316,6 +327,8 @@ LOCAL(vmInvoke_handleException): jmp *THREAD_EXCEPTION_HANDLER(%ebx) LOCAL(vmInvoke_exit): +#endif // AVIAN_CONTINUATIONS + // restore callee-saved registers movl 0(%esp),%ebx movl 4(%esp),%esi @@ -347,8 +360,9 @@ LOCAL(getPC): movl (%esp),%esi ret -.globl vmJumpAndInvoke -vmJumpAndInvoke: +.globl GLOBAL(vmJumpAndInvoke) +GLOBAL(vmJumpAndInvoke): +#ifdef AVIAN_CONTINUATIONS // 4(%esp): thread // 8(%esp): address // 12(%esp): base @@ -388,6 +402,11 @@ LOCAL(vmJumpAndInvoke_argumentTest): movl %ecx,%esp jmp *%esi +#else // not AVIAN_CONTINUATIONS + // vmJumpAndInvoke should only be called when continuations are + // enabled + int3 +#endif // AVIAN_CONTINUATIONS #else # error unsupported platform From 14613193fa5a8b0887f771003638d90f86bd9d8c Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 28 May 2009 19:50:44 -0600 Subject: [PATCH 071/172] include return address size in frameSize passed to vmInvoke; fix printf warnings --- src/common.h | 2 +- src/compile.cpp | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/common.h b/src/common.h index 94d351d5d3..c3c03e89c4 100644 --- a/src/common.h +++ b/src/common.h @@ -288,7 +288,7 @@ bitsToFloat(uint32_t bits) return f; } -inline intptr_t +inline int difference(void* a, void* b) { return reinterpret_cast(a) - reinterpret_cast(b); diff --git a/src/compile.cpp b/src/compile.cpp index 8d51a80b5c..f43f2f5623 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -5412,7 +5412,8 @@ jumpAndInvoke(MyThread* t, object method, void* base, void* stack, ...) stack, argumentCount * BytesPerWord, arguments, - t->arch->alignFrameSize(t->arch->argumentFootprint(argumentCount)) + (t->arch->alignFrameSize(t->arch->argumentFootprint(argumentCount)) + + t->arch->frameReturnAddressSize()) * BytesPerWord); } @@ -5922,11 +5923,11 @@ class MyProcessor: public Processor { t->init(); if (false) { - fprintf(stderr, "%"LD"\n", difference(&(t->continuation), t)); - fprintf(stderr, "%"LD"\n", difference(&(t->exception), t)); - fprintf(stderr, "%"LD"\n", difference(&(t->exceptionStackAdjustment), t)); - fprintf(stderr, "%"LD"\n", difference(&(t->exceptionOffset), t)); - fprintf(stderr, "%"LD"\n", difference(&(t->exceptionHandler), t)); + fprintf(stderr, "%d\n", difference(&(t->continuation), t)); + fprintf(stderr, "%d\n", difference(&(t->exception), t)); + fprintf(stderr, "%d\n", difference(&(t->exceptionStackAdjustment), t)); + fprintf(stderr, "%d\n", difference(&(t->exceptionOffset), t)); + fprintf(stderr, "%d\n", difference(&(t->exceptionHandler), t)); exit(0); } From f30e31e5f6fad815c3690ec95dad1a343a28d6a5 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 28 May 2009 19:54:32 -0600 Subject: [PATCH 072/172] compile-x86.S bugfixes and cleanups --- src/compile-x86.S | 74 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 20 deletions(-) diff --git a/src/compile-x86.S b/src/compile-x86.S index e2ef5dd433..cab2e20089 100644 --- a/src/compile-x86.S +++ b/src/compile-x86.S @@ -35,6 +35,8 @@ #define CONTINUATION_LENGTH 56 #define CONTINUATION_BODY 64 +#define CALLEE_SAVED_REGISTER_FOOTPRINT 48 + .globl GLOBAL(vmInvoke) GLOBAL(vmInvoke): pushq %rbp @@ -48,8 +50,8 @@ GLOBAL(vmInvoke): // %r9 : returnType (ignored) // allocate stack space, adding room for callee-saved registers - subq %r8,%rsp - subq $48,%rsp + subq %r8,%rsp + subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rsp // save callee-saved registers movq %rsp,%r9 @@ -91,11 +93,14 @@ GLOBAL(vmInvoke_returnAddress): cmpq $0,%rcx je LOCAL(vmInvoke_exit) + // allocate a frame of size (continuation.length * BYTES_PER_WORD) + // + CALLEE_SAVED_REGISTER_FOOTPRINT movq CONTINUATION_LENGTH(%rcx),%rsi shlq $3,%rsi subq %rsi,%rsp - subq $48,%rsp - + subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rsp + + // copy the continuation body into the frame leaq CONTINUATION_BODY(%rcx),%rdi movq $0,%r9 @@ -109,16 +114,19 @@ LOCAL(vmInvoke_continuationLoop): LOCAL(vmInvoke_continuationTest): cmpq %rsi,%r9 jb LOCAL(vmInvoke_continuationLoop) - + + // set the return address to vmInvoke_returnAddress movq CONTINUATION_RETURN_ADDRESS_OFFSET(%rcx),%rdi movq vmInvoke_returnAddress@GOTPCREL(%rip),%r10 movq %r10,(%rsp,%rdi,1) - + + // save the current base pointer in the frame and update it movq CONTINUATION_FRAME_POINTER_OFFSET(%rcx),%rdi movq %rbp,(%rsp,%rdi,1) addq %rsp,%rdi movq %rdi,%rbp - + + // consume the continuation movq CONTINUATION_NEXT(%rcx),%rdi movq %rdi,THREAD_CONTINUATION(%rbx) @@ -141,9 +149,10 @@ LOCAL(vmInvoke_handleException): LOCAL(vmInvoke_exit): #endif // AVIAN_CONTINUATIONS - // restore callee-saved registers + // restore callee-saved registers (below the stack pointer, but in + // the red zone) movq %rsp,%r9 - subq $48,%r9 + subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%r9 movq 0(%r9),%rbx movq 8(%r9),%r12 @@ -161,16 +170,23 @@ GLOBAL(vmJumpAndInvoke): // %rdi: thread // %rsi: address // %rdx: base - // %rcx: stack + // %rcx: (unused) // %r8 : argumentFootprint // %r9 : arguments // 8(%rsp): frameSize movq %rdx,%rbp - movq %rdi,%rbx + // restore (pseudo)-stack pointer (we don't want to touch the real + // stack pointer, since we haven't copied the arguments yet) + movq %rbp,%rcx + + // allocate new frame, adding room for callee-saved registers + movl 8(%rsp),%eax + subq %rax,%rcx + subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rcx - subq 8(%rsp),%rcx + movq %rdi,%rbx // set return address movq vmInvoke_returnAddress@GOTPCREL(%rip),%r10 @@ -189,6 +205,8 @@ LOCAL(vmJumpAndInvoke_argumentTest): cmpq %r8,%r11 jb LOCAL(vmJumpAndInvoke_argumentLoop) + // the arguments have been copied, so we can set the real stack + // pointer now movq %rcx,%rsp jmp *%rsi @@ -213,6 +231,8 @@ LOCAL(vmJumpAndInvoke_argumentTest): #define CONTINUATION_LENGTH 28 #define CONTINUATION_BODY 32 +#define CALLEE_SAVED_REGISTER_FOOTPRINT 16 + .globl GLOBAL(vmInvoke) GLOBAL(vmInvoke): pushl %ebp @@ -227,7 +247,7 @@ GLOBAL(vmInvoke): // allocate stack space, adding room for callee-saved registers subl 24(%ebp),%esp - subl $16,%esp + subl $CALLEE_SAVED_REGISTER_FOOTPRINT,%esp // save callee-saved registers movl %esp,%ecx @@ -259,9 +279,10 @@ LOCAL(vmInvoke_argumentTest): .globl vmInvoke_returnAddress vmInvoke_returnAddress: - // restore stack pointer + // restore stack pointer, preserving the area containing saved + // registers movl %ebp,%ecx - subl $16,%ecx + subl $CALLEE_SAVED_REGISTER_FOOTPRINT,%ecx movl %ecx,%esp #ifdef AVIAN_CONTINUATIONS @@ -270,11 +291,12 @@ vmInvoke_returnAddress: cmpl $0,%ecx je LOCAL(vmInvoke_exit) + // allocate a frame of size (continuation.length * BYTES_PER_WORD) movl CONTINUATION_LENGTH(%ecx),%esi shll $2,%esi subl %esi,%esp - subl $16,%esp + // copy the continuation body into the frame leal CONTINUATION_BODY(%ecx),%edi push %eax @@ -295,17 +317,20 @@ LOCAL(vmInvoke_continuationTest): pop %edx pop %eax + // set the return address to vmInvoke_returnAddress movl CONTINUATION_RETURN_ADDRESS_OFFSET(%ecx),%edi call LOCAL(getPC) addl $_GLOBAL_OFFSET_TABLE_,%esi movl vmInvoke_returnAddress@GOT(%esi),%esi movl %esi,(%esp,%edi,1) + // save the current base pointer in the frame and update it movl CONTINUATION_FRAME_POINTER_OFFSET(%ecx),%edi movl %ebp,(%esp,%edi,1) addl %esp,%edi movl %edi,%ebp + // consume the continuation movl CONTINUATION_NEXT(%ecx),%edi movl %edi,THREAD_CONTINUATION(%ebx) @@ -337,7 +362,7 @@ LOCAL(vmInvoke_exit): // handle return value based on expected type movl 28(%ebp),%ecx - addl $16,%esp + addl $CALLEE_SAVED_REGISTER_FOOTPRINT,%esp LOCAL(vmInvoke_void): cmpl $VOID_TYPE,%ecx @@ -366,15 +391,22 @@ GLOBAL(vmJumpAndInvoke): // 4(%esp): thread // 8(%esp): address // 12(%esp): base - // 16(%esp): stack + // 16(%esp): (unused) // 20(%esp): argumentFootprint // 24(%esp): arguments // 28(%esp): frameSize movl 12(%esp),%ebp - movl 16(%esp),%ecx + // restore (pseudo)-stack pointer (we don't want to touch the real + // stack pointer, since we haven't copied the arguments yet) + movl %ebp,%ecx + + // allocate new frame, adding room for callee-saved registers subl 28(%esp),%ecx + subl $CALLEE_SAVED_REGISTER_FOOTPRINT,%ecx + + movl 4(%esp),%ebx // set return address call LOCAL(getPC) @@ -397,8 +429,10 @@ LOCAL(vmJumpAndInvoke_argumentTest): cmpl %edx,%esi jb LOCAL(vmJumpAndInvoke_argumentLoop) - movl 4(%esp),%ebx movl 8(%esp),%esi + + // the arguments have been copied, so we can set the real stack + // pointer now movl %ecx,%esp jmp *%esi From 02fba106148bbb786afa2b9a31c6060388079c34 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 28 May 2009 19:56:15 -0600 Subject: [PATCH 073/172] set DebugCompile to false --- src/compile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compile.cpp b/src/compile.cpp index f43f2f5623..3317756106 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -32,7 +32,7 @@ vmCall(); namespace { -const bool DebugCompile = true; +const bool DebugCompile = false; const bool DebugNatives = false; const bool DebugCallTable = false; const bool DebugMethodTree = false; From b5cb1692fb9862fb4dc97d1efcfa1921cc59d6b6 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 29 May 2009 18:32:16 -0600 Subject: [PATCH 074/172] document avian.Continuations --- classpath/avian/Continuations.java | 149 +++++++++++++++++++++++++++++ makefile | 2 +- 2 files changed, 150 insertions(+), 1 deletion(-) diff --git a/classpath/avian/Continuations.java b/classpath/avian/Continuations.java index 0953995320..3aaf9c17c1 100644 --- a/classpath/avian/Continuations.java +++ b/classpath/avian/Continuations.java @@ -12,10 +12,159 @@ package avian; import java.util.concurrent.Callable; +/** + * This class provides access to the Avian VM's continuation support. + * + *

A continuation is a snapshot of a thread's call stack which can + * be captured via callWithCurrentContinuation and later + * restored any number of times. We restore this snapshot by either + * feeding it a result (to be returned by + * callWithCurrentContinuation) or feeding it an + * exception (to be thrown by + * callWithCurrentContinuation). Continuations may be + * used to implement features such as coroutines, generators, and + * cooperative multitasking. + * + *

This class provides two static methods - + * callWithCurrentContinuation and + * dynamicWind - with similar semantics to the Scheme + * methods call-with-current-continuation and + * dynamic-wind, respectively. Additionally, we define + * how continuations work with respect to native code, exceptions, + * try/finally blocks, synchronized blocks, and multithreading. + * + *

Continuations and Continuation Contexts

+ * + *

A continuation can be thought of as a singly-linked list of + * stack frames representing the call trace, where the head of the + * list is the frame of the method most recently called (i.e. the top + * of the stack). However, this trace only extends as far as the most + * recent chain of Java frames - it ends just prior to the most recent + * native frame in the stack. The reason for this is that the VM + * cannot, in general, safely capture and restore native frames. + * Therefore, each call from native code to Java (including the + * original invocation of main or + * Thread.run) represents a new continuation context in + * which continuations may be captured, and these will only contain + * frames from within that context. + * + *

Calling a continuation (i.e. feeding it a result or exception) + * causes the current continuation to be replaced with the calling + * continuation. When the last method in this new continuation + * returns, it returns to the native frame which created the current + * context, which may not be the same as the context in which that + * continuation was created. + * + *

We define the return type of a continuation context as the + * return type of the least-recently called method in the call trace + * (i.e. the end of the list). A continuation may be called from a + * different continuation context than the one in which it was created + * provided the return type of the new context is compatible with the + * original context. + * + *

Given a thread executing in continuation context "A" which wants + * to call a continuation created in context "B", the following rules + * apply: + * + *

    + * + *
  • If the return type of "A" is void, the return + * type of "B" may be anything, including void
  • + * + *
  • If the return type of "A" is a primitive type, the return + * type of "B" must match exactly
  • + * + *
  • If the return type of "A" is an object type, that type must + * assignable from the return type of "B" (i.e. the latter must + * either be the same as the former or a superclass or + * superinterface of it)
  • + * + *
+ * + *

A thread may call a continuation created by a different thread + * provided the return types are compatible. Multiple threads may + * safely call the same continuation simultaneously without + * synchronization. Any attempt to call a continuation from a context + * with an incompatible return type will result in an + * avian/IncompatibleContinuationException being thrown. + * + *

Winding, Unwinding, and Rewinding

+ * + *

Traditionally, Java provides one way to wind the execution stack + * (recursive method calls) and two ways to unwind it (normal returns + * and exception unwinding). With continuations, we add a new way to + * (re)wind the stack and a new way to unwind it. + * + *

The call stack of a continuation may share frames with other + * continuations - in which case they share a common history. When + * calling a continuation "B" from the current continuation "A", we + * must unwind past any frames which are in "A" but not in "B" and + * rewind past any frames in "B" but not in "A". During this + * unwinding and rewinding, we may pass through synchronized and + * try/finally blocks while going down the old stack and up the new + * stack. + * + *

However, unlike the traditional processes of winding and + * unwinding, the VM will ignore these blocks - monitors will not be + * released or acquired and finally blocks will not execute. This is + * by design. The purpose of such a block is to acquire a resource + * before executing a task and release when that task is done. With + * continuations, we may wish to yield control temporarily to another + * continuation while executing such a task, and we might do so + * several times. In such a case we would only want to acquire the + * resource when we start the task and only release it when we're + * finished, regardless of how often we unwound to reach other + * continuations or rewound to return to the next step. + * + *

Conversely, we may wish to acquire and release a resource each + * time we (re)wind to or unwind from a continuation, respectively. + * In this case, we use dynamicWind to register functions + * which will run every time that frame is passed, regardless of how + * the stack is wound or unwound. + */ public abstract class Continuations { + /** + * Captures the current continuation, passing a reference to the + * specified receiver. + * + *

This method will either return the result returned by + * receiver.receive(Callback), propagate the exception + * thrown by that method, return the result passed to the + * handleResult(T) method of the continuation, or throw the + * exception passed to the handleException(Throwable) of the + * continuation. + */ public static native T callWithCurrentContinuation (CallbackReceiver receiver) throws Exception; + /** + * Calls the specified "before" and "after" tasks each time a + * continuation containing the call is wound or unwound, + * respectively. + * + *

This method first calls before.run(), then + * thunk.call(), and finally after.run(), + * returning the result of the second call. If + * before.run() does not return normally, the second + * and third calls will not happen. If thunk.call() + * throws an exception, after.run(), will be called + * before the exception is propagated. + * + *

If thunk.call() calls a continuation (directly or + * via a subroutine) which does not include the current call to + * dynamicWind, after.run() will be called + * before control passes to that continuation. If this call throws + * an exception, the exception will propagate to the current caller + * of dynamicWind. + * + *

If thunk.call() creates a continuation which is + * later called from a continuation which does not include the + * current call to dynamicWind, + * before.run() will be called before control passes to + * that continuation. As above, if this call throws an exception, + * the exception will propagate to the current caller of + * dynamicWind. + */ public static T dynamicWind(Runnable before, Callable thunk, Runnable after) diff --git a/makefile b/makefile index a6845d4abb..c4710d5511 100644 --- a/makefile +++ b/makefile @@ -363,7 +363,7 @@ tarball: .PHONY: javadoc javadoc: - javadoc -sourcepath classpath -d build/javadoc -subpackages java \ + javadoc -sourcepath classpath -d build/javadoc -subpackages avian:java \ -windowtitle "Avian v$(version) Class Library API" \ -doctitle "Avian v$(version) Class Library API" \ -header "Avian v$(version)" \ From f1ff0d75bff9a8cd1f7ec9c983cbc33efa8ed973 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 29 May 2009 19:09:32 -0600 Subject: [PATCH 075/172] avian.Continuations documentation tweaks --- classpath/avian/Continuations.java | 41 +++++++++++++++--------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/classpath/avian/Continuations.java b/classpath/avian/Continuations.java index 3aaf9c17c1..1375cd97a9 100644 --- a/classpath/avian/Continuations.java +++ b/classpath/avian/Continuations.java @@ -13,23 +13,24 @@ package avian; import java.util.concurrent.Callable; /** - * This class provides access to the Avian VM's continuation support. + * This class provides methods to capture continuations and manage + * control flow when calling continuations. * *

A continuation is a snapshot of a thread's call stack which can * be captured via callWithCurrentContinuation and later - * restored any number of times. We restore this snapshot by either - * feeding it a result (to be returned by + * restored any number of times. The program may restore this + * snapshot by either feeding it a result (to be returned by * callWithCurrentContinuation) or feeding it an * exception (to be thrown by * callWithCurrentContinuation). Continuations may be * used to implement features such as coroutines, generators, and * cooperative multitasking. * - *

This class provides two static methods - + *

This class provides two static methods, * callWithCurrentContinuation and - * dynamicWind - with similar semantics to the Scheme + * dynamicWind, with similar semantics to the Scheme * methods call-with-current-continuation and - * dynamic-wind, respectively. Additionally, we define + * dynamic-wind, respectively. In addition, we define * how continuations work with respect to native code, exceptions, * try/finally blocks, synchronized blocks, and multithreading. * @@ -43,8 +44,8 @@ import java.util.concurrent.Callable; * native frame in the stack. The reason for this is that the VM * cannot, in general, safely capture and restore native frames. * Therefore, each call from native code to Java (including the - * original invocation of main or - * Thread.run) represents a new continuation context in + * original invocation of main(String[]) or + * Thread.run()) represents a new continuation context in * which continuations may be captured, and these will only contain * frames from within that context. * @@ -56,15 +57,13 @@ import java.util.concurrent.Callable; * continuation was created. * *

We define the return type of a continuation context as the - * return type of the least-recently called method in the call trace - * (i.e. the end of the list). A continuation may be called from a - * different continuation context than the one in which it was created - * provided the return type of the new context is compatible with the - * original context. + * return type of the first method called in that context. A + * continuation may be called from a different context than the one in + * which it was created, provided the return type of the latter is + * compatible with the current context. * - *

Given a thread executing in continuation context "A" which wants - * to call a continuation created in context "B", the following rules - * apply: + *

Given a thread executing in context "A" which wants to call a + * continuation created in context "B", the following rules apply: * *