fix ARM stack unwinding

We can't rely on the C++ compiler to save the return address in a
known location on entry to each function we might call from Java
(although GCC 4.5 seems to do so consistently, which is why I hadn't
realized the unwinding code was relying on that assumption), so we
must store it explicitly in MyThread::ip in each thunk.  For PowerPC
and x86, we continue saving it on the stack as always, since the
calling convention guarantees its location relative to the stack
pointer.
This commit is contained in:
Joel Dice 2011-02-19 20:33:26 -07:00
parent b2268143f5
commit 8a88c6ee3c
5 changed files with 29 additions and 13 deletions

View File

@ -2126,7 +2126,11 @@ class MyAssembler: public Assembler {
&handlerConstant);
}
virtual void saveFrame(unsigned stackOffset) {
virtual void saveFrame(unsigned stackOffset, unsigned ipOffset) {
Register link(LinkRegister);
Memory linkDst(ThreadRegister, ipOffset);
moveRM(&c, BytesPerWord, &link, BytesPerWord, &linkDst);
Register stack(StackRegister);
Memory stackDst(ThreadRegister, stackOffset);
moveRM(&c, BytesPerWord, &stack, BytesPerWord, &stackDst);

View File

@ -397,7 +397,7 @@ class Assembler {
virtual void checkStackOverflow(uintptr_t handler,
unsigned stackLimitOffsetFromThread) = 0;
virtual void saveFrame(unsigned stackOffset) = 0;
virtual void saveFrame(unsigned stackOffset, unsigned ipOffset) = 0;
virtual void pushFrame(unsigned argumentCount, ...) = 0;
virtual void allocateFrame(unsigned footprint) = 0;
virtual void adjustFrame(unsigned difference) = 0;

View File

@ -435,6 +435,18 @@ nextFrame(MyThread* t, void** ip, void** sp, object method, object target)
// fprintf(stderr, "next frame ip %p sp %p\n", *ip, *sp);
}
void*
getIp(MyThread* t)
{
// Here we use the convention that, if the return address is neither
// pushed on to the stack automatically as part of the call nor
// stored in the caller's frame, it will be saved in MyThread::ip
// instead of on the stack. See the various implementations of
// Assembler::saveFrame for details on how this is done.
return t->arch->returnAddressOffset() < 0
? t->ip : t->arch->frameIp(t->stack);
}
class MyStackWalker: public Processor::StackWalker {
public:
enum State {
@ -475,7 +487,7 @@ class MyStackWalker: public Processor::StackWalker {
trace = t->traceContext->trace;
continuation = t->traceContext->continuation;
} else {
ip_ = 0;
ip_ = getIp(t);
stack = t->stack;
trace = t->trace;
continuation = t->continuation;
@ -1981,7 +1993,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetFrame,
stack = t->traceContext->stack;
continuation = t->traceContext->continuation;
} else {
ip = 0;
ip = getIp(t);
stack = t->stack;
continuation = t->continuation;
}
@ -6669,7 +6681,7 @@ visitArguments(MyThread* t, Heap::Visitor* v, void* stack, object method)
void
visitStack(MyThread* t, Heap::Visitor* v)
{
void* ip = t->arch->frameIp(t->stack);
void* ip = getIp(t);
void* stack = t->stack;
MyThread::CallTrace* trace = t->trace;
@ -8398,7 +8410,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p)
{ Assembler* a = defaultContext.context.assembler;
a->saveFrame(difference(&(t->stack), t));
a->saveFrame(difference(&(t->stack), t), difference(&(t->ip), t));
p->thunks.default_.frameSavedOffset = a->length();
@ -8442,7 +8454,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p)
a->apply(Move, BytesPerWord, RegisterOperand, &index,
BytesPerWord, MemoryOperand, &virtualCallIndex);
a->saveFrame(difference(&(t->stack), t));
a->saveFrame(difference(&(t->stack), t), difference(&(t->ip), t));
p->thunks.defaultVirtual.frameSavedOffset = a->length();
@ -8464,7 +8476,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p)
{ Assembler* a = nativeContext.context.assembler;
a->saveFrame(difference(&(t->stack), t));
a->saveFrame(difference(&(t->stack), t), difference(&(t->ip), t));
p->thunks.native.frameSavedOffset = a->length();
@ -8484,7 +8496,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p)
{ Assembler* a = aioobContext.context.assembler;
a->saveFrame(difference(&(t->stack), t));
a->saveFrame(difference(&(t->stack), t), difference(&(t->ip), t));
p->thunks.aioob.frameSavedOffset = a->length();
@ -8501,7 +8513,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p)
{ Assembler* a = stackOverflowContext.context.assembler;
a->saveFrame(difference(&(t->stack), t));
a->saveFrame(difference(&(t->stack), t), difference(&(t->ip), t));
p->thunks.stackOverflow.frameSavedOffset = a->length();
@ -8518,7 +8530,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p)
{ Assembler* a = tableContext.context.assembler;
a->saveFrame(difference(&(t->stack), t));
a->saveFrame(difference(&(t->stack), t), difference(&(t->ip), t));
p->thunks.table.frameSavedOffset = a->length();

View File

@ -2253,7 +2253,7 @@ class MyAssembler: public Assembler {
&handlerConstant);
}
virtual void saveFrame(unsigned stackOffset) {
virtual void saveFrame(unsigned stackOffset, unsigned) {
Register returnAddress(0);
emit(&c, mflr(returnAddress.low));

View File

@ -3382,7 +3382,7 @@ class MyAssembler: public Assembler {
&handlerConstant);
}
virtual void saveFrame(unsigned stackOffset) {
virtual void saveFrame(unsigned stackOffset, unsigned) {
Register stack(rsp);
Memory stackDst(rbx, stackOffset);
apply(Move, BytesPerWord, RegisterOperand, &stack,