mirror of
https://github.com/corda/corda.git
synced 2025-01-01 02:36:44 +00:00
support tail calls and continuations as build options
This commit is contained in:
parent
deefc47b1a
commit
31eb75a736
14
makefile
14
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))
|
||||
|
@ -16,6 +16,12 @@
|
||||
|
||||
namespace vm {
|
||||
|
||||
#ifdef AVIAN_TAILS
|
||||
const bool TailCalls = true;
|
||||
#else
|
||||
const bool TailCalls = false;
|
||||
#endif
|
||||
|
||||
enum Operation {
|
||||
Return,
|
||||
LoadBarrier,
|
||||
|
289
src/compile.cpp
289
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<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)
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
60
src/x86.cpp
60
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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user