more work on frame-pointer-less unwinding

This fixes the tails=true build (at least for x86_64) and eliminates
the need for a frame table in the tails=false build.  In the
tails=true build, we still need a frame table on x86(_64) to help
determine whether we've caught a thread executing code to do a tail
call or pop arguments off the stack.  However, I've not yet written
the code to actually use this table, and it is only needed to handle
asynchronous unwinds via Thread.getStackTrace.
This commit is contained in:
Joel Dice 2011-01-25 17:22:43 -07:00
parent 966650f105
commit c1a0d8b6fc
9 changed files with 327 additions and 232 deletions

View File

@ -164,13 +164,13 @@ inline int carry16(intptr_t v) { return static_cast<int16_t>(v) < 0 ? 1 : 0; }
inline bool isOfWidth(long long i, int size) { return static_cast<unsigned long long>(i) >> size == 0; }
inline bool isOfWidth(int i, int size) { return static_cast<unsigned>(i) >> size == 0; }
const unsigned FrameFooterSize = 2;
const unsigned FrameHeaderSize = 0;
const unsigned FrameHeaderSize = (UseFramePointer ? 2 : 1);
const unsigned StackAlignmentInBytes = 8;
const unsigned StackAlignmentInWords = StackAlignmentInBytes / BytesPerWord;
const int ThreadRegister = 8;
const int FrameRegister = 12;
const int StackRegister = 13;
const int LinkRegister = 14;
const int ProgramCounter = 15;
@ -1701,6 +1701,9 @@ class MyArchitecture: public Assembler::Architecture {
virtual bool reserved(int register_) {
switch (register_) {
case FrameRegister:
return UseFramePointer;
case LinkRegister:
case StackRegister:
case ThreadRegister:
@ -1781,8 +1784,8 @@ class MyArchitecture: public Assembler::Architecture {
}
virtual unsigned alignFrameSize(unsigned sizeInWords) {
const unsigned alignment = StackAlignmentInBytes / BytesPerWord;
return (ceiling(sizeInWords + FrameFooterSize, alignment) * alignment);
return pad(sizeInWords + FrameHeaderSize, StackAlignmentInWords)
- FrameHeaderSize;
}
virtual void* frameIp(void* stack) {
@ -1798,15 +1801,15 @@ class MyArchitecture: public Assembler::Architecture {
}
virtual unsigned frameFooterSize() {
return FrameFooterSize;
return 0;
}
virtual int returnAddressOffset() {
return 1;
return -1;
}
virtual int framePointerOffset() {
return 0;
return -2;
}
virtual void nextFrame(void** stack, void**) {
@ -2006,11 +2009,14 @@ class MyAssembler: public Assembler {
return arch_;
}
virtual void saveFrame(unsigned stackOffset, unsigned) {
virtual void saveFrame(unsigned stackOffset) {
appendFrameSizeEvent(&c, FrameSizePoison);
// ???
Register returnAddress(LinkRegister);
Memory returnAddressDst
(StackRegister, arch_->returnAddressOffset() * BytesPerWord);
moveRM(&c, BytesPerWord, &returnAddress, BytesPerWord, &returnAddressDst);
Memory returnAddressDst(StackRegister, - BytesPerWord);
moveAndUpdateRM(&c, BytesPerWord, &returnAddress, BytesPerWord,
&returnAddressDst);
Register stack(StackRegister);
Memory stackDst(ThreadRegister, stackOffset);
@ -2059,33 +2065,53 @@ class MyAssembler: public Assembler {
}
virtual void allocateFrame(unsigned footprint) {
Register returnAddress(LinkRegister);
Register stack(StackRegister);
Constant footprintConstant(resolved(&c, footprint * BytesPerWord));
subCR(&c, BytesPerWord, &footprintConstant, BytesPerWord, &stack,
BytesPerWord, &stack);
Memory returnAddressDst(StackRegister, arch_->returnAddressOffset() * BytesPerWord);
appendFrameSizeEvent(&c, footprint);
Register returnAddress(LinkRegister);
Memory returnAddressDst(StackRegister, (footprint - 1) * BytesPerWord);
moveRM(&c, BytesPerWord, &returnAddress, BytesPerWord, &returnAddressDst);
Register stack(StackRegister);
Memory stackDst(StackRegister, -footprint * BytesPerWord);
moveAndUpdateRM(&c, BytesPerWord, &stack, BytesPerWord, &stackDst);
if (UseFramePointer) {
Register frame(FrameRegister);
Memory frameDst(StackRegister, (footprint - 2) * BytesPerWord);
moveRM(&c, BytesPerWord, &frame, BytesPerWord, &frameDst);
}
}
virtual void adjustFrame(unsigned footprint) {
Register nextStack(5);
Memory stackSrc(StackRegister, 0);
moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &nextStack);
virtual void adjustFrame(unsigned difference) {
appendFrameSizeEvent(&c, - difference);
Memory stackDst(StackRegister, -footprint * BytesPerWord);
moveAndUpdateRM(&c, BytesPerWord, &nextStack, BytesPerWord, &stackDst);
Register stack(StackRegister);
Constant differenceConstant(resolved(&c, difference * BytesPerWord));
subCR(&c, BytesPerWord, &differenceConstant, BytesPerWord, &stack,
BytesPerWord, &stack);
appendFrameSizeEvent(&c, difference);
}
virtual void popFrame() {
Register stack(StackRegister);
Memory stackSrc(StackRegister, arch_->framePointerOffset() * BytesPerWord);
moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &stack);
virtual void popFrame(unsigned frameFootprint) {
if (UseFramePointer) {
Register frame(FrameRegister);
Memory frameSrc(StackRegister, (frameFootprint - 1) * BytesPerWord);
moveMR(&c, BytesPerWord, &frameSrc, BytesPerWord, &frame);
}
Register returnAddress(LinkRegister);
Memory returnAddressSrc(StackRegister, arch_->returnAddressOffset() * BytesPerWord);
Memory returnAddressSrc
(StackRegister, (frameFootprint - 1) * BytesPerWord);
moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &returnAddress);
Register stack(StackRegister);
Constant differenceConstant(resolved(&c, frameFootprint * BytesPerWord));
addCR(&c, BytesPerWord, &differenceConstant, BytesPerWord, &stack,
BytesPerWord, &stack);
appendFrameSizeEvent(&c, - frameFootprint);
}
virtual void popFrameForTailCall(unsigned footprint,
@ -2095,80 +2121,85 @@ class MyAssembler: public Assembler {
{
if (TailCalls) {
if (offset) {
if (UseFramePointer) {
Register frame(FrameRegister);
Memory frameSrc(StackRegister, (footprint - 1) * BytesPerWord);
moveMR(&c, BytesPerWord, &frameSrc, BytesPerWord, &frame);
}
Register link(LinkRegister);
Memory returnAddressSrc
(StackRegister, BytesPerWord + (footprint * BytesPerWord));
(StackRegister, (footprint - 1) * BytesPerWord);
moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &link);
Register tmp(c.client->acquireTemporary());
Memory stackSrc(StackRegister, footprint * BytesPerWord);
moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &tmp);
Register stack(StackRegister);
Constant footprintConstant
(resolved(&c, (footprint - offset + 1) * BytesPerWord));
addCR(&c, BytesPerWord, &footprintConstant, BytesPerWord, &stack);
Memory stackDst(StackRegister, (footprint - offset) * BytesPerWord);
moveAndUpdateRM(&c, BytesPerWord, &tmp, BytesPerWord, &stackDst);
c.client->releaseTemporary(tmp.low);
appendFrameSizeEvent(&c, - (frameFootprint - offset + 1));
if (returnAddressSurrogate != NoRegister) {
assert(&c, offset > 0);
Register ras(returnAddressSurrogate);
Memory dst(StackRegister, BytesPerWord + (offset * BytesPerWord));
Memory dst(StackRegister, (offset - 1) * 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);
Register las(framePointerSurrogate);
Memory dst(StackRegister, (offset - 2) * BytesPerWord);
moveRM(&c, BytesPerWord, &las, BytesPerWord, &dst);
}
} else {
popFrame();
popFrame(footprint);
}
} else {
abort(&c);
}
}
virtual void popFrameAndPopArgumentsAndReturn(unsigned argumentFootprint) {
popFrame();
virtual void popFrameAndPopArgumentsAndReturn(unsigned frameFootprint,
unsigned argumentFootprint)
{
popFrame(frameFootprint);
assert(&c, argumentFootprint >= StackAlignmentInWords);
assert(&c, (argumentFootprint % StackAlignmentInWords) == 0);
unsigned offset;
if (TailCalls and argumentFootprint > StackAlignmentInWords) {
Register tmp(5);
Memory stackSrc(StackRegister, 0);
moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &tmp);
offset = argumentFootprint - StackAlignmentInWords;
Memory stackDst(StackRegister,
(argumentFootprint - StackAlignmentInWords)
* BytesPerWord);
moveAndUpdateRM(&c, BytesPerWord, &tmp, BytesPerWord, &stackDst);
Register stack(StackRegister);
Constant adjustment(resolved(&c, offset * BytesPerWord));
addCR(&c, BytesPerWord, &adjustment, BytesPerWord, &stack);
appendFrameSizeEvent(&c, - offset);
} else {
offset = 0;
}
return_(&c);
// todo: this is not necessary if there are no instructions to
// follow:
appendFrameSizeEvent(&c, frameFootprint + offset);
}
virtual void popFrameAndUpdateStackAndReturn(unsigned stackOffsetFromThread)
virtual void popFrameAndUpdateStackAndReturn(unsigned frameFootprint,
unsigned stackOffsetFromThread)
{
popFrame();
appendFrameSizeEvent(&c, FrameSizePoison);
Register tmp1(6);
Memory stackSrc(StackRegister, 0);
moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &tmp1);
Register tmp2(5);
Memory newStackSrc(ThreadRegister, stackOffsetFromThread);
moveMR(&c, BytesPerWord, &newStackSrc, BytesPerWord, &tmp2);
popFrame(frameFootprint);
Register stack(StackRegister);
subR(&c, BytesPerWord, &stack, &tmp2, &tmp2);
Memory stackDst(StackRegister, 0, tmp2.low);
moveAndUpdateRM(&c, BytesPerWord, &tmp1, BytesPerWord, &stackDst);
Memory newStackSrc(ThreadRegister, stackOffsetFromThread);
moveMR(&c, BytesPerWord, &newStackSrc, BytesPerWord, &stack);
return_(&c);
}

View File

@ -304,11 +304,10 @@ class Assembler {
virtual unsigned resolve(unsigned start, Block* next) = 0;
};
class FrameSizeEvent {
class FrameEvent {
public:
virtual unsigned offset() = 0;
virtual int change() = 0;
virtual FrameSizeEvent* next() = 0;
virtual FrameEvent* next() = 0;
};
class Architecture {
@ -351,6 +350,10 @@ class Assembler {
virtual unsigned alignFrameSize(unsigned sizeInWords) = 0;
virtual void nextFrame(void* start, unsigned size, unsigned footprint,
int32_t* frameTable, void* link, void* stackLimit,
unsigned targetParameterFootprint, void** ip,
void** stack) = 0;
virtual void* frameIp(void* stack) = 0;
virtual unsigned frameHeaderSize() = 0;
virtual unsigned frameReturnAddressSize() = 0;
@ -437,9 +440,9 @@ class Assembler {
virtual unsigned length() = 0;
virtual unsigned frameSizeEventCount() = 0;
virtual unsigned frameEventCount() = 0;
virtual FrameSizeEvent* firstFrameSizeEvent() = 0;
virtual FrameEvent* firstFrameEvent() = 0;
virtual void dispose() = 0;
};

View File

@ -295,9 +295,9 @@ LOCAL(vmJumpAndInvoke_argumentTest):
#define THREAD_STACK 2148
#define THREAD_SCRATCH 2152
#define CALLEE_SAVED_REGISTER_FOOTPRINT 16
.globl GLOBAL(vmInvoke)
GLOBAL(vmInvoke):
pushl %ebp

View File

@ -153,14 +153,18 @@ class MyThread: public Thread {
CallTrace* trace):
Context(t, ip, stack, continuation, trace),
t(t),
link(0),
javaStackLimit(0),
next(t->traceContext)
{
t->traceContext = this;
}
TraceContext(MyThread* t):
TraceContext(MyThread* t, void* link):
Context(t, t->ip, t->stack, t->continuation, t->trace),
t(t),
link(link),
javaStackLimit(0),
next(t->traceContext)
{
t->traceContext = this;
@ -171,6 +175,8 @@ class MyThread: public Thread {
}
MyThread* t;
void* link;
void* javaStackLimit;
TraceContext* next;
};
@ -414,56 +420,42 @@ getTableValue(Thread* t, object table, unsigned base, unsigned max,
(&intArrayBody(t, table, base), bits, index * bits);
}
unsigned
frameSize(MyThread* t, intptr_t ip, object method)
void
nextFrame(MyThread* t, void** ip, void** sp, object method, object target)
{
object code = methodCode(t, method);
object table = codeFrameSizeTable(t, code);
unsigned count = intArrayBody(t, table, 0);
unsigned max = alignedFrameSize(t, method);
object table = codeFrameTable(t, code);
intptr_t start = codeCompiled(t, code);
int codeSize = compiledSize(start);
unsigned indexSize = ceiling(count * bitsNeeded(codeSize), 32);
assert(t, ip >= start);
assert(t, ip <= start + codeSize);
void* link;
void* javaStackLimit;
unsigned offset = ip - start;
unsigned bottom = 0;
unsigned top = count;
for (unsigned span = top - bottom; span; span = top - bottom) {
unsigned middle = bottom + (span / 2);
unsigned candidate = getTableValue(t, table, 1, codeSize, middle);
if (offset >= candidate
and (middle + 1 == count
or offset < getTableValue(t, table, 1, codeSize, middle + 1)))
{
return getTableValue(t, table, 1 + indexSize, max, middle);
} else if (offset < candidate) {
top = middle;
} else if (offset > candidate) {
bottom = middle + 1;
}
}
if (top == 0) {
return 0;
} else if (top < count) {
return getTableValue(t, table, 1 + indexSize, max, top);
} else if (top == count && count > 0) {
return getTableValue(t, table, 1 + indexSize, max, top - 1);
if (t->traceContext) {
link = t->traceContext->link;
javaStackLimit = t->traceContext->javaStackLimit;
} else {
abort(t);
link = 0;
javaStackLimit = 0;
}
}
void*
nextFrame(MyThread* t, void* ip, void* sp, object method)
{
return reinterpret_cast<void**>(sp) + local::frameSize
(t, reinterpret_cast<intptr_t>(ip), method)
+ t->arch->frameReturnAddressSize();
// fprintf(stderr, "nextFrame %s.%s%s target %s.%s%s\n",
// &byteArrayBody(t, className(t, methodClass(t, method)), 0),
// &byteArrayBody(t, methodName(t, method), 0),
// &byteArrayBody(t, methodSpec(t, method), 0),
// target
// ? &byteArrayBody(t, className(t, methodClass(t, target)), 0)
// : 0,
// target
// ? &byteArrayBody(t, methodName(t, target), 0)
// : 0,
// target
// ? &byteArrayBody(t, methodSpec(t, target), 0)
// : 0);
t->arch->nextFrame
(reinterpret_cast<void*>(start), compiledSize(start),
alignedFrameSize(t, method), table ? &intArrayBody(t, table, 0) : 0,
link, javaStackLimit, target ? methodParameterFootprint(t, target) : -1,
ip, sp);
}
class MyStackWalker: public Processor::StackWalker {
@ -486,6 +478,7 @@ class MyStackWalker: public Processor::StackWalker {
virtual void visit(Heap::Visitor* v) {
v->visit(&(walker->method_));
v->visit(&(walker->target));
v->visit(&(walker->continuation));
}
@ -496,6 +489,7 @@ class MyStackWalker: public Processor::StackWalker {
t(t),
state(Start),
method_(0),
target(0),
protector(this)
{
if (t->traceContext) {
@ -518,6 +512,7 @@ class MyStackWalker: public Processor::StackWalker {
stack(w->stack),
trace(w->trace),
method_(w->method_),
target(w->target),
continuation(w->continuation),
protector(this)
{ }
@ -551,6 +546,7 @@ class MyStackWalker: public Processor::StackWalker {
case Next:
if (stack) {
target = method_;
method_ = methodForIp(t, ip_);
if (method_) {
state = Method;
@ -599,8 +595,7 @@ class MyStackWalker: public Processor::StackWalker {
break;
case Method:
stack = nextFrame(t, ip_, stack, method_);
ip_ = t->arch->frameIp(stack);
nextFrame(t, &ip_, &stack, method_, target);
break;
case NativeMethod:
@ -654,6 +649,7 @@ class MyStackWalker: public Processor::StackWalker {
void* stack;
MyThread::CallTrace* trace;
object method_;
object target;
object continuation;
MyProtector protector;
};
@ -2028,7 +2024,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetStack,
if (handler) {
*targetIp = handler;
stack = nextFrame(t, ip, stack, method);
nextFrame(t, &ip, &stack, method, target);
void** sp = static_cast<void**>(stackForFrame(t, stack, method))
+ t->arch->frameReturnAddressSize();
@ -2040,8 +2036,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetStack,
t->exception = 0;
} else {
stack = nextFrame(t, ip, stack, method);
ip = t->arch->frameIp(stack);
nextFrame(t, &ip, &stack, method, target);
if (t->exception) {
releaseLock(t, method, stack);
@ -2126,7 +2121,8 @@ makeCurrentContinuation(MyThread* t, void** targetIp, void** targetStack)
top += argumentFootprint - alignment;
}
stack = nextFrame(t, ip, stack, method);
void* nextIp = ip;
nextFrame(t, &nextIp, &stack, method, target);
void** bottom = static_cast<void**>(stack)
+ t->arch->frameReturnAddressSize();
@ -2156,7 +2152,7 @@ makeCurrentContinuation(MyThread* t, void** targetIp, void** targetStack)
}
last = c;
ip = t->arch->frameIp(stack);
ip = nextIp;
target = method;
} else {
@ -5224,20 +5220,21 @@ translateLineNumberTable(MyThread* t, Compiler* c, object code, intptr_t start)
}
object
makeFrameSizeTable(MyThread* t, Context* c, unsigned codeSize)
makeFrameTable(MyThread* t, Context* c, unsigned codeSize)
{
Assembler* a = c->assembler;
unsigned count = a->frameSizeEventCount();
int max = alignedFrameSize(t, c->method);
unsigned indexSize = ceiling(count * bitsNeeded(codeSize), 32);
unsigned tableSize = ceiling(count * bitsNeeded(max), 32);
object table = makeIntArray(t, 1 + indexSize + tableSize);
unsigned count = a->frameEventCount();
if (count == 0) {
return 0;
}
unsigned size = ceiling(count * bitsNeeded(codeSize), 32);
object table = makeIntArray(t, 1 + size);
intArrayBody(t, table, 0) = count;
unsigned index = 0;
int value = 0;
for (Assembler::FrameSizeEvent* e = a->firstFrameSizeEvent();
for (Assembler::FrameEvent* e = a->firstFrameEvent();
e; e = e->next())
{
assert(t, index < count);
@ -5245,17 +5242,8 @@ makeFrameSizeTable(MyThread* t, Context* c, unsigned codeSize)
unsigned offset = e->offset();
assert(t, offset <= codeSize);
value += e->change();
fprintf(stderr, "offset %d change %d value %d\n",
offset, e->change(), value);
assert(t, value >= 0);
assert(t, value <= max);
setTableValue(t, table, 1, codeSize, index, offset);
setTableValue(t, table, 1 + indexSize, max, index, value);
++ index;
}
@ -5950,12 +5938,12 @@ finish(MyThread* t, Allocator* allocator, Context* context)
PROTECT(t, newLineNumberTable);
object frameSizeTable = makeFrameSizeTable(t, context, codeSize);
object frameTable = makeFrameTable(t, context, codeSize);
object code = methodCode(t, context->method);
code = makeCode
(t, 0, newExceptionHandlerTable, newLineNumberTable, frameSizeTable,
(t, 0, newExceptionHandlerTable, newLineNumberTable, frameTable,
reinterpret_cast<uintptr_t>(start), codeMaxStack(t, code),
codeMaxLocals(t, code), 0);
@ -6700,6 +6688,7 @@ visitStack(MyThread* t, Heap::Visitor* v)
MyThread::CallTrace* trace = t->trace;
object targetMethod = (trace ? trace->targetMethod : 0);
object target = targetMethod;
while (stack) {
if (targetMethod) {
@ -6711,11 +6700,14 @@ visitStack(MyThread* t, Heap::Visitor* v)
if (method) {
PROTECT(t, method);
stack = nextFrame(t, ip, stack, method);
void* nextIp = ip;
nextFrame(t, &nextIp, &stack, method, target);
visitStackAndLocals(t, v, stack, method, ip);
ip = t->arch->frameIp(stack);
ip = nextIp;
target = method;
} else if (trace) {
stack = trace->stack;
ip = t->arch->frameIp(stack);
@ -6723,6 +6715,9 @@ visitStack(MyThread* t, Heap::Visitor* v)
if (trace) {
targetMethod = trace->targetMethod;
target = targetMethod;
} else {
target = 0;
}
} else {
break;
@ -7665,13 +7660,14 @@ class MyProcessor: public Processor {
t(t), p(p), target(target), trace(0)
{ }
virtual void visit(void* ip, void* stack) {
MyThread::TraceContext c(target);
virtual void visit(void* ip, void* stack, void* link) {
MyThread::TraceContext c(target, link);
if (methodForIp(t, ip)) {
// we caught the thread in Java code - use the register values
c.ip = ip;
c.stack = stack;
c.javaStackLimit = stack;
} else if (target->transition) {
// we caught the thread in native code while in the middle
// of updating the context fields (MyThread::stack, etc.)

View File

@ -834,6 +834,7 @@ handleSignal(int signal, siginfo_t* info, void* context)
void* ip = reinterpret_cast<void*>(IP_REGISTER(c));
void* stack = reinterpret_cast<void*>(STACK_REGISTER(c));
void* thread = reinterpret_cast<void*>(THREAD_REGISTER(c));
void* link = reinterpret_cast<void*>(LINK_REGISTER(c));
unsigned index;
@ -841,7 +842,7 @@ handleSignal(int signal, siginfo_t* info, void* context)
case VisitSignal: {
index = VisitSignalIndex;
system->threadVisitor->visit(ip, stack);
system->threadVisitor->visit(ip, stack, link);
System::Thread* t = system->visitTarget;
system->visitTarget = 0;

View File

@ -35,7 +35,7 @@ class System {
class ThreadVisitor {
public:
virtual void visit(void* ip, void* stack) = 0;
virtual void visit(void* ip, void* stack, void* link) = 0;
};
class Runnable {

View File

@ -86,7 +86,7 @@
(object pool)
(object exceptionHandlerTable)
(object lineNumberTable)
(object frameSizeTable)
(object frameTable)
(intptr_t compiled)
(uint16_t maxStack)
(uint16_t maxLocals)

View File

@ -72,8 +72,6 @@ const int LongJumpRegister = r10;
const unsigned StackAlignmentInBytes = 16;
const unsigned StackAlignmentInWords = StackAlignmentInBytes / BytesPerWord;
const int FrameSizePoison = -2147483647;
bool
isInt8(intptr_t v)
{
@ -88,7 +86,7 @@ isInt32(intptr_t v)
class Task;
class AlignmentPadding;
class MyFrameSizeEvent;
class MyFrameEvent;
unsigned
padding(AlignmentPadding* p, unsigned index, unsigned offset,
@ -97,17 +95,14 @@ padding(AlignmentPadding* p, unsigned index, unsigned offset,
class Context;
class MyBlock;
void
appendFrameSizeEvent(Context* c, MyBlock* b, Promise* offset, int change);
ResolvedPromise*
resolved(Context* c, int64_t value);
resolved(Context* c, int64_t value);
class MyBlock: public Assembler::Block {
public:
MyBlock(unsigned offset):
next(0), firstPadding(0), lastPadding(0), firstFrameSizeEvent(0),
lastFrameSizeEvent(0), offset(offset), start(~0), size(0)
next(0), firstPadding(0), lastPadding(0), firstFrameEvent(0),
lastFrameEvent(0), offset(offset), start(~0), size(0)
{ }
virtual unsigned resolve(unsigned start, Assembler::Block* next) {
@ -120,8 +115,8 @@ class MyBlock: public Assembler::Block {
MyBlock* next;
AlignmentPadding* firstPadding;
AlignmentPadding* lastPadding;
MyFrameSizeEvent* firstFrameSizeEvent;
MyFrameSizeEvent* lastFrameSizeEvent;
MyFrameEvent* firstFrameEvent;
MyFrameEvent* lastFrameEvent;
unsigned offset;
unsigned start;
unsigned size;
@ -164,8 +159,8 @@ class Context {
Context(System* s, Allocator* a, Zone* zone, ArchitectureContext* ac):
s(s), zone(zone), client(0), code(s, a, 1024), tasks(0), result(0),
firstBlock(new (zone->allocate(sizeof(MyBlock))) MyBlock(0)),
lastBlock(firstBlock), firstFrameSizeEvent(0), lastFrameSizeEvent(0),
ac(ac), frameSizeEventCount(0)
lastBlock(firstBlock), firstFrameEvent(0), lastFrameEvent(0),
ac(ac), frameEventCount(0)
{ }
System* s;
@ -176,10 +171,10 @@ class Context {
uint8_t* result;
MyBlock* firstBlock;
MyBlock* lastBlock;
MyFrameSizeEvent* firstFrameSizeEvent;
MyFrameSizeEvent* lastFrameSizeEvent;
MyFrameEvent* firstFrameEvent;
MyFrameEvent* lastFrameEvent;
ArchitectureContext* ac;
unsigned frameSizeEventCount;
unsigned frameEventCount;
};
void NO_RETURN
@ -466,52 +461,45 @@ padding(AlignmentPadding* p, unsigned start, unsigned offset,
return padding;
}
class MyFrameSizeEvent: public Assembler::FrameSizeEvent {
class MyFrameEvent: public Assembler::FrameEvent {
public:
MyFrameSizeEvent(Context* c, Promise* offset, int change):
c(c), next_(0), offset_(offset), change_(change)
MyFrameEvent(Context* c, Promise* offset):
c(c), next_(0), offset_(offset)
{ }
virtual unsigned offset() {
return offset_->value();
}
virtual int change() {
expect(c, change_ != FrameSizePoison);
return change_;
}
virtual Assembler::FrameSizeEvent* next() {
virtual Assembler::FrameEvent* next() {
return next_;
}
Context* c;
MyFrameSizeEvent* next_;
MyFrameEvent* next_;
Promise* offset_;
int change_;
};
void
appendFrameSizeEvent(Context* c, MyBlock* b, Promise* offset, int change)
appendFrameEvent(Context* c, MyBlock* b, Promise* offset)
{
MyFrameSizeEvent* e = new (c->zone->allocate(sizeof(MyFrameSizeEvent)))
MyFrameSizeEvent(c, offset, change);
MyFrameEvent* e = new (c->zone->allocate(sizeof(MyFrameEvent)))
MyFrameEvent(c, offset);
if (b->firstFrameSizeEvent) {
b->lastFrameSizeEvent->next_ = e;
if (b->firstFrameEvent) {
b->lastFrameEvent->next_ = e;
} else {
b->firstFrameSizeEvent = e;
b->firstFrameEvent = e;
}
b->lastFrameSizeEvent = e;
b->lastFrameEvent = e;
++ c->frameSizeEventCount;
++ c->frameEventCount;
}
void
appendFrameSizeEvent(Context* c, int change)
appendFrameEvent(Context* c)
{
appendFrameSizeEvent(c, c->lastBlock, offset(c), change);
appendFrameEvent(c, c->lastBlock, offset(c));
}
extern "C" bool
@ -2574,6 +2562,93 @@ absoluteRR(Context* c, unsigned aSize, Assembler::Register* a,
c->client->releaseTemporary(rdx);
}
unsigned
argumentFootprint(unsigned footprint)
{
return max(pad(footprint, StackAlignmentInWords), StackAlignmentInWords);
}
uint32_t
read4(uint8_t* p)
{
uint32_t v; memcpy(&v, p, 4);
return v;
}
void
nextFrame(ArchitectureContext* c, uint8_t* start, unsigned size,
unsigned footprint, int32_t*, void*, void* stackLimit,
unsigned targetParameterFootprint, void** ip, void** stack)
{
assert(c, *ip >= start);
assert(c, *ip <= start + size);
uint8_t* instruction = static_cast<uint8_t*>(*ip);
if (BytesPerWord == 4) {
if (*start == 0x39) {
// skip stack overflow check
start += 11;
}
} else if (*start == 0x48 and start[1] == 0x39) {
// skip stack overflow check
start += 12;
}
if (instruction <= start) {
*ip = reinterpret_cast<void**>(*stack)[0];
return;
}
if (UseFramePointer) {
// skip preamble
start += (BytesPerWord == 4 ? 3 : 4);
if (instruction <= start or *instruction == 0x5d) {
*ip = reinterpret_cast<void**>(*stack)[1];
*stack = reinterpret_cast<void**>(*stack) + 1;
return;
}
}
if (*instruction == 0xc3) {
*ip = reinterpret_cast<void**>(*stack)[0];
return;
}
unsigned offset = footprint + FrameHeaderSize
- (stackLimit == *stack ? 1 : 0);
if (TailCalls) {
if (argumentFootprint(targetParameterFootprint) > StackAlignmentInWords) {
offset += argumentFootprint(targetParameterFootprint)
- StackAlignmentInWords;
}
if (BytesPerWord == 4) {
if ((*instruction == 0x83 or *instruction == 0x81)
and instruction[1] == 0xec)
{
offset
-= (*instruction == 0x83 ? instruction[2] : read4(instruction + 2))
/ BytesPerWord;
}
} else if (*instruction == 0x48
and (instruction[1] == 0x83 or instruction[1] == 0x81)
and instruction[2] == 0xec)
{
offset
-= (instruction[1] == 0x83 ? instruction[3] : read4(instruction + 3))
/ BytesPerWord;
}
// todo: use frameTable to check for and handle tail calls
}
*ip = reinterpret_cast<void**>(*stack)[offset];
*stack = reinterpret_cast<void**>(*stack) + offset;
}
void
populateTables(ArchitectureContext* c)
{
@ -2771,7 +2846,7 @@ class MyArchitecture: public Assembler::Architecture {
}
virtual unsigned argumentFootprint(unsigned footprint) {
return max(pad(footprint, StackAlignmentInWords), StackAlignmentInWords);
return local::argumentFootprint(footprint);
}
virtual bool argumentAlignment() {
@ -2900,6 +2975,16 @@ class MyArchitecture: public Assembler::Architecture {
- FrameHeaderSize;
}
virtual void nextFrame(void* start, unsigned size, unsigned footprint,
int32_t* frameTable, void* link, void* stackLimit,
unsigned targetParameterFootprint, void** ip,
void** stack)
{
local::nextFrame(&c, static_cast<uint8_t*>(start), size, footprint,
frameTable, link, stackLimit, targetParameterFootprint,
ip, stack);
}
virtual void* frameIp(void* stack) {
return stack ? *static_cast<void**>(stack) : 0;
}
@ -3397,28 +3482,20 @@ class MyAssembler: public Assembler {
apply(Move, BytesPerWord, RegisterOperand, &stack,
BytesPerWord, RegisterOperand, &base);
appendFrameSizeEvent(&c, 1);
}
Constant footprintConstant(resolved(&c, footprint * BytesPerWord));
apply(Subtract, BytesPerWord, ConstantOperand, &footprintConstant,
BytesPerWord, RegisterOperand, &stack,
BytesPerWord, RegisterOperand, &stack);
appendFrameSizeEvent(&c, footprint);
}
virtual void adjustFrame(unsigned difference) {
appendFrameSizeEvent(&c, - difference);
Register stack(rsp);
Constant differenceConstant(resolved(&c, difference * BytesPerWord));
apply(Subtract, BytesPerWord, ConstantOperand, &differenceConstant,
BytesPerWord, RegisterOperand, &stack,
BytesPerWord, RegisterOperand, &stack);
appendFrameSizeEvent(&c, difference);
}
virtual void popFrame(unsigned frameFootprint) {
@ -3428,19 +3505,13 @@ class MyAssembler: public Assembler {
apply(Move, BytesPerWord, RegisterOperand, &base,
BytesPerWord, RegisterOperand, &stack);
appendFrameSizeEvent(&c, - frameFootprint);
popR(&c, BytesPerWord, &base);
appendFrameSizeEvent(&c, - 1);
} else {
Register stack(rsp);
Constant footprint(resolved(&c, frameFootprint * BytesPerWord));
apply(Add, BytesPerWord, ConstantOperand, &footprint,
BytesPerWord, RegisterOperand, &stack,
BytesPerWord, RegisterOperand, &stack);
appendFrameSizeEvent(&c, - frameFootprint);
}
}
@ -3451,13 +3522,18 @@ class MyAssembler: public Assembler {
{
if (TailCalls) {
if (offset) {
appendFrameEvent(&c);
Register tmp(c.client->acquireTemporary());
Memory returnAddressSrc(rsp, (frameFootprint + 1) * BytesPerWord);
unsigned baseSize = UseFramePointer ? 1 : 0;
Memory returnAddressSrc
(rsp, (frameFootprint + baseSize) * BytesPerWord);
moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &tmp);
Memory returnAddressDst
(rsp, (frameFootprint - offset + 1) * BytesPerWord);
(rsp, (frameFootprint - offset + baseSize) * BytesPerWord);
moveRM(&c, BytesPerWord, &tmp, BytesPerWord, &returnAddressDst);
c.client->releaseTemporary(tmp.low);
@ -3470,11 +3546,9 @@ class MyAssembler: public Assembler {
Register stack(rsp);
Constant footprint
(resolved(&c, (frameFootprint - offset + 1) * BytesPerWord));
(resolved(&c, (frameFootprint - offset + baseSize) * BytesPerWord));
addCR(&c, BytesPerWord, &footprint, BytesPerWord, &stack);
appendFrameSizeEvent(&c, - (frameFootprint - offset + 1));
if (returnAddressSurrogate != NoRegister) {
assert(&c, offset > 0);
@ -3507,6 +3581,8 @@ class MyAssembler: public Assembler {
assert(&c, (argumentFootprint % StackAlignmentInWords) == 0);
if (TailCalls and argumentFootprint > StackAlignmentInWords) {
appendFrameEvent(&c);
Register returnAddress(rcx);
popR(&c, BytesPerWord, &returnAddress);
@ -3516,16 +3592,10 @@ class MyAssembler: public Assembler {
* BytesPerWord));
addCR(&c, BytesPerWord, &adjustment, BytesPerWord, &stack);
appendFrameSizeEvent(&c, - (argumentFootprint - StackAlignmentInWords));
jumpR(&c, BytesPerWord, &returnAddress);
} else {
return_(&c);
}
// todo: this is not necessary if there are no instructions to
// follow:
appendFrameSizeEvent(&c, frameFootprint);
}
virtual void popFrameAndUpdateStackAndReturn(unsigned frameFootprint,
@ -3536,16 +3606,10 @@ class MyAssembler: public Assembler {
Register returnAddress(rcx);
popR(&c, BytesPerWord, &returnAddress);
appendFrameSizeEvent(&c, -1);
Register stack(rsp);
Memory stackSrc(rbx, stackOffsetFromThread);
moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &stack);
// we can't statically determine the frame size at this point, so
// we poison any attempt to query for it:
appendFrameSizeEvent(&c, FrameSizePoison);
jumpR(&c, BytesPerWord, &returnAddress);
}
@ -3594,13 +3658,13 @@ class MyAssembler: public Assembler {
c.result = dst;
for (MyBlock* b = c.firstBlock; b; b = b->next) {
if (b->firstFrameSizeEvent) {
if (c.firstFrameSizeEvent) {
c.lastFrameSizeEvent->next_ = b->firstFrameSizeEvent;
if (b->firstFrameEvent) {
if (c.firstFrameEvent) {
c.lastFrameEvent->next_ = b->firstFrameEvent;
} else {
c.firstFrameSizeEvent = b->firstFrameSizeEvent;
c.firstFrameEvent = b->firstFrameEvent;
}
c.lastFrameSizeEvent = b->lastFrameSizeEvent;
c.lastFrameEvent = b->lastFrameEvent;
}
unsigned index = 0;
@ -3656,12 +3720,12 @@ class MyAssembler: public Assembler {
return c.code.length();
}
virtual unsigned frameSizeEventCount() {
return c.frameSizeEventCount;
virtual unsigned frameEventCount() {
return c.frameEventCount;
}
virtual FrameSizeEvent* firstFrameSizeEvent() {
return c.firstFrameSizeEvent;
virtual FrameEvent* firstFrameEvent() {
return c.firstFrameEvent;
}
virtual void dispose() {

View File

@ -29,20 +29,20 @@
# ifdef __APPLE__
# if __DARWIN_UNIX03 && defined(_STRUCT_X86_EXCEPTION_STATE32)
# define IP_REGISTER(context) (context->uc_mcontext->__ss.__eip)
# define BASE_REGISTER(context) (context->uc_mcontext->__ss.__ebp)
# define STACK_REGISTER(context) (context->uc_mcontext->__ss.__esp)
# define THREAD_REGISTER(context) (context->uc_mcontext->__ss.__ebx)
# define LINK_REGISTER(context) (context->uc_mcontext->__ss.__ecx)
# else
# define IP_REGISTER(context) (context->uc_mcontext->ss.eip)
# define BASE_REGISTER(context) (context->uc_mcontext->ss.ebp)
# define STACK_REGISTER(context) (context->uc_mcontext->ss.esp)
# define THREAD_REGISTER(context) (context->uc_mcontext->ss.ebx)
# define LINK_REGISTER(context) (context->uc_mcontext->ss.ecx)
# endif
# else
# define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_EIP])
# define BASE_REGISTER(context) (context->uc_mcontext.gregs[REG_EBP])
# define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_ESP])
# define THREAD_REGISTER(context) (context->uc_mcontext.gregs[REG_EBX])
# define LINK_REGISTER(context) (context->uc_mcontext.gregs[REG_ECX])
# endif
extern "C" uint64_t
@ -65,20 +65,20 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t*,
# ifdef __APPLE__
# if __DARWIN_UNIX03 && defined(_STRUCT_X86_EXCEPTION_STATE32)
# define IP_REGISTER(context) (context->uc_mcontext->__ss.__rip)
# define BASE_REGISTER(context) (context->uc_mcontext->__ss.__rbp)
# define STACK_REGISTER(context) (context->uc_mcontext->__ss.__rsp)
# define THREAD_REGISTER(context) (context->uc_mcontext->__ss.__rbx)
# define LINK_REGISTER(context) (context->uc_mcontext->__ss.__rcx)
# else
# define IP_REGISTER(context) (context->uc_mcontext->ss.rip)
# define BASE_REGISTER(context) (context->uc_mcontext->ss.rbp)
# define STACK_REGISTER(context) (context->uc_mcontext->ss.rsp)
# define THREAD_REGISTER(context) (context->uc_mcontext->ss.rbx)
# define LINK_REGISTER(context) (context->uc_mcontext->ss.rcx)
# endif
# else
# define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_RIP])
# define BASE_REGISTER(context) (context->uc_mcontext.gregs[REG_RBP])
# define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_RSP])
# define THREAD_REGISTER(context) (context->uc_mcontext.gregs[REG_RBX])
# define LINK_REGISTER(context) (context->uc_mcontext.gregs[REG_RCX])
# endif
extern "C" uint64_t