support tail calls and continuations as build options

This commit is contained in:
Joel Dice 2009-05-25 23:27:10 -06:00
parent deefc47b1a
commit 31eb75a736
5 changed files with 250 additions and 165 deletions

View File

@ -35,6 +35,12 @@ endif
ifeq ($(heapdump),true) ifeq ($(heapdump),true)
options := $(options)-heapdump options := $(options)-heapdump
endif endif
ifeq ($(tails),true)
options := $(options)-tails
endif
ifeq ($(continuations),true)
options := $(options)-continuations
endif
root = $(shell (cd .. && pwd)) root = $(shell (cd .. && pwd))
build = build build = build
@ -254,6 +260,14 @@ ifeq ($(heapdump),true)
cflags += -DAVIAN_HEAPDUMP cflags += -DAVIAN_HEAPDUMP
endif endif
ifeq ($(tails),true)
cflags += -DAVIAN_TAILS
endif
ifeq ($(continuations),true)
cflags += -DAVIAN_CONTINUATIONS
endif
bootimage-generator-sources = $(src)/bootimage.cpp bootimage-generator-sources = $(src)/bootimage.cpp
bootimage-generator-objects = \ bootimage-generator-objects = \
$(call cpp-objects,$(bootimage-generator-sources),$(src),$(native-build)) $(call cpp-objects,$(bootimage-generator-sources),$(src),$(native-build))

View File

@ -16,6 +16,12 @@
namespace vm { namespace vm {
#ifdef AVIAN_TAILS
const bool TailCalls = true;
#else
const bool TailCalls = false;
#endif
enum Operation { enum Operation {
Return, Return,
LoadBarrier, LoadBarrier,

View File

@ -39,6 +39,12 @@ const bool DebugFrameMaps = false;
const bool CheckArrayBounds = true; const bool CheckArrayBounds = true;
#ifdef AVIAN_CONTINUATIONS
const bool Continuations = true;
#else
const bool Continuations = false;
#endif
const unsigned MaxNativeCallFootprint = 4; const unsigned MaxNativeCallFootprint = 4;
const unsigned InitialZoneCapacityInBytes = 64 * 1024; const unsigned InitialZoneCapacityInBytes = 64 * 1024;
@ -1425,7 +1431,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase,
= t->arch->argumentFootprint(methodParameterFootprint(t, target)); = t->arch->argumentFootprint(methodParameterFootprint(t, target));
} }
while (t->continuation) { while (Continuations and t->continuation) {
object c = t->continuation; object c = t->continuation;
object method = continuationMethod(t, c); object method = continuationMethod(t, c);
@ -1495,7 +1501,7 @@ makeCurrentContinuation(MyThread* t, void** targetIp, void** targetBase,
unsigned argumentFootprint unsigned argumentFootprint
= t->arch->argumentFootprint(methodParameterFootprint(t, target)); = t->arch->argumentFootprint(methodParameterFootprint(t, target));
unsigned alignment = t->arch->stackAlignmentInWords(); unsigned alignment = t->arch->stackAlignmentInWords();
if (argumentFootprint > alignment) { if (TailCalls and argumentFootprint > alignment) {
top += argumentFootprint - alignment; top += argumentFootprint - alignment;
} }
@ -1559,9 +1565,15 @@ unwind(MyThread* t)
object& object&
objectPools(MyThread* t); objectPools(MyThread* t);
object&
windMethod(MyThread* t);
object& object&
rewindMethod(MyThread* t); rewindMethod(MyThread* t);
object&
receiveMethod(MyThread* t);
uintptr_t uintptr_t
defaultThunk(MyThread* t); defaultThunk(MyThread* t);
@ -2144,7 +2156,7 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target, bool tailCall,
unsigned flags = (tailCall ? Compiler::TailJump : 0); unsigned flags = (tailCall ? Compiler::TailJump : 0);
if (useThunk or (tailCall and (methodFlags(t, target) & ACC_NATIVE))) { if (useThunk or (tailCall and (methodFlags(t, target) & ACC_NATIVE))) {
if (tailCall) { if (TailCalls and tailCall) {
TraceElement* trace = frame->trace(target, TraceElement::TailCall); TraceElement* trace = frame->trace(target, TraceElement::TailCall);
Compiler::Operand* returnAddress = c->promiseConstant Compiler::Operand* returnAddress = c->promiseConstant
(new (frame->context->zone.allocate(sizeof(TraceElementPromise))) (new (frame->context->zone.allocate(sizeof(TraceElementPromise)))
@ -2409,12 +2421,13 @@ returnsNext(MyThread* t, object code, unsigned ip)
bool bool
isTailCall(MyThread* t, object code, unsigned ip, object caller, object callee) isTailCall(MyThread* t, object code, unsigned ip, object caller, object callee)
{ {
return (((methodFlags(t, caller) & ACC_SYNCHRONIZED) == 0) return TailCalls
and ((methodFlags(t, caller) & ACC_SYNCHRONIZED) == 0)
and (not inTryBlock(t, code, ip - 1)) and (not inTryBlock(t, code, ip - 1))
and (not needsReturnBarrier(t, caller)) and (not needsReturnBarrier(t, caller))
and (methodReturnCode(t, caller) == VoidField and (methodReturnCode(t, caller) == VoidField
or methodReturnCode(t, caller) == methodReturnCode(t, callee)) or methodReturnCode(t, caller) == methodReturnCode(t, callee))
and returnsNext(t, code, ip)); and returnsNext(t, code, ip);
} }
void void
@ -5111,7 +5124,8 @@ invokeNative(MyThread* t)
if (UNLIKELY(t->exception)) { if (UNLIKELY(t->exception)) {
unwind(t); unwind(t);
} else { } else {
if (t->arch->argumentFootprint(parameterFootprint) if (TailCalls
and t->arch->argumentFootprint(parameterFootprint)
> t->arch->stackAlignmentInWords()) > t->arch->stackAlignmentInWords())
{ {
t->stack = static_cast<uintptr_t*>(t->stack) t->stack = static_cast<uintptr_t*>(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 { class ArgumentList {
public: public:
ArgumentList(Thread* t, uintptr_t* array, unsigned size, bool* objectMask, ArgumentList(Thread* t, uintptr_t* array, unsigned size, bool* objectMask,
@ -6213,132 +6338,52 @@ class MyProcessor: public Processor {
(t->m->system->handleSegFault(&segFaultHandler))); (t->m->system->handleSegFault(&segFaultHandler)));
} }
virtual void callWithCurrentContinuation(Thread* vmt, object receiver) { virtual void callWithCurrentContinuation(Thread* t, object receiver) {
MyThread* t = static_cast<MyThread*>(vmt); if (Continuations) {
::callWithCurrentContinuation(static_cast<MyThread*>(t), receiver);
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);
} else { } 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) object after)
{ {
MyThread* t = static_cast<MyThread*>(vmt); if (Continuations) {
::dynamicWind(static_cast<MyThread*>(t), before, thunk, after);
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 { } else {
object message = makeString abort(t);
(t, "%s %s not found in %s", methodName, methodSpec, className);
t->exception = makeNoSuchMethodError(t, message);
} }
} }
if (LIKELY(t->exception == 0)) { virtual void feedResultToContinuation(Thread* t, object continuation,
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);
} else {
unwind(t);
}
}
virtual void feedResultToContinuation(Thread* vmt, object continuation,
object result) object result)
{ {
callContinuation(static_cast<MyThread*>(vmt), continuation, result, 0); if (Continuations) {
callContinuation(static_cast<MyThread*>(t), continuation, result, 0);
} else {
abort(t);
}
} }
virtual void feedExceptionToContinuation(Thread* vmt, object continuation, virtual void feedExceptionToContinuation(Thread* t, object continuation,
object exception) object exception)
{ {
callContinuation(static_cast<MyThread*>(vmt), continuation, 0, exception); if (Continuations) {
callContinuation(static_cast<MyThread*>(t), continuation, 0, exception);
} else {
abort(t);
}
} }
virtual void walkContinuationBody(Thread* t, Heap::Walker* w, object o, virtual void walkContinuationBody(Thread* t, Heap::Walker* w, object o,
unsigned start) unsigned start)
{ {
if (Continuations) {
::walkContinuationBody(static_cast<MyThread*>(t), w, o, start); ::walkContinuationBody(static_cast<MyThread*>(t), w, o, start);
} else {
abort(t);
}
} }
System* s; System* s;
@ -6969,12 +7014,24 @@ objectPools(MyThread* t)
return processor(t)->objectPools; return processor(t)->objectPools;
} }
object&
windMethod(MyThread* t)
{
return processor(t)->windMethod;
}
object& object&
rewindMethod(MyThread* t) rewindMethod(MyThread* t)
{ {
return processor(t)->rewindMethod; return processor(t)->rewindMethod;
} }
object&
receiveMethod(MyThread* t)
{
return processor(t)->receiveMethod;
}
uintptr_t uintptr_t
defaultThunk(MyThread* t) defaultThunk(MyThread* t)
{ {

View File

@ -2392,7 +2392,7 @@ class CallEvent: public Event {
int framePointerIndex; int framePointerIndex;
int frameOffset; int frameOffset;
if (flags & Compiler::TailJump) { if (TailCalls and (flags & Compiler::TailJump)) {
assert(c, argumentCount == 0); assert(c, argumentCount == 0);
int base = frameBase(c); 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; stackArgumentIndex = c->localFootprint;
if (stackBefore) { if (stackBefore) {
stackArgumentIndex += stackBefore->index + 1 - stackArgumentFootprint; stackArgumentIndex += stackBefore->index + 1 - stackArgumentFootprint;
@ -2475,7 +2475,7 @@ class CallEvent: public Event {
virtual void compile(Context* c) { virtual void compile(Context* c) {
UnaryOperation op; UnaryOperation op;
if (flags & Compiler::TailJump) { if (TailCalls and (flags & Compiler::TailJump)) {
if (flags & Compiler::Aligned) { if (flags & Compiler::Aligned) {
op = AlignedJump; op = AlignedJump;
} else { } else {
@ -2525,6 +2525,7 @@ class CallEvent: public Event {
stackArgumentIndex); stackArgumentIndex);
} }
if (TailCalls) {
if (flags & Compiler::TailJump) { if (flags & Compiler::TailJump) {
if (returnAddressSurrogate) { if (returnAddressSurrogate) {
returnAddressSurrogate->source->thaw(c, returnAddressSurrogate); returnAddressSurrogate->source->thaw(c, returnAddressSurrogate);
@ -2534,7 +2535,9 @@ class CallEvent: public Event {
framePointerSurrogate->source->thaw(c, framePointerSurrogate); framePointerSurrogate->source->thaw(c, framePointerSurrogate);
} }
} else { } else {
unsigned footprint = c->arch->argumentFootprint(stackArgumentFootprint); unsigned footprint = c->arch->argumentFootprint
(stackArgumentFootprint);
if (footprint > c->arch->stackAlignmentInWords()) { if (footprint > c->arch->stackAlignmentInWords()) {
Assembler::Register stack(c->arch->stack()); Assembler::Register stack(c->arch->stack());
ResolvedPromise adjustmentPromise ResolvedPromise adjustmentPromise
@ -2546,6 +2549,7 @@ class CallEvent: public Event {
BytesPerWord, RegisterOperand, &stack); BytesPerWord, RegisterOperand, &stack);
} }
} }
}
clean(c, this, stackBefore, localsBefore, reads, popIndex); clean(c, this, stackBefore, localsBefore, reads, popIndex);

View File

@ -2412,6 +2412,7 @@ class MyAssembler: public Assembler {
int returnAddressSurrogate, int returnAddressSurrogate,
int framePointerSurrogate) int framePointerSurrogate)
{ {
if (TailCalls) {
if (offset) { if (offset) {
Register tmp(c.client->acquireTemporary()); Register tmp(c.client->acquireTemporary());
@ -2450,6 +2451,9 @@ class MyAssembler: public Assembler {
} else { } else {
popFrame(); popFrame();
} }
} else {
abort(&c);
}
} }
virtual void popFrameAndPopArgumentsAndReturn(unsigned argumentFootprint) { virtual void popFrameAndPopArgumentsAndReturn(unsigned argumentFootprint) {
@ -2458,7 +2462,7 @@ class MyAssembler: public Assembler {
assert(&c, argumentFootprint >= StackAlignmentInWords); assert(&c, argumentFootprint >= StackAlignmentInWords);
assert(&c, (argumentFootprint % StackAlignmentInWords) == 0); assert(&c, (argumentFootprint % StackAlignmentInWords) == 0);
if (argumentFootprint > StackAlignmentInWords) { if (TailCalls and argumentFootprint > StackAlignmentInWords) {
Register returnAddress(rcx); Register returnAddress(rcx);
popR(&c, BytesPerWord, &returnAddress); popR(&c, BytesPerWord, &returnAddress);