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)
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))

View File

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

View File

@ -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<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 {
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<MyThread*>(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<MyThread*>(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<MyThread*>(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<MyThread*>(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<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)
{
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,
unsigned start)
{
::walkContinuationBody(static_cast<MyThread*>(t), w, o, start);
if (Continuations) {
::walkContinuationBody(static_cast<MyThread*>(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)
{

View File

@ -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);
}
}
}

View File

@ -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);