From 31eb75a73674a4cff719401eb5cc5b064f7e9ce8 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 25 May 2009 23:27:10 -0600 Subject: [PATCH] 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);