fix StackOverflowError stack walking in tails=true builds

The various Architecture::nextFrame implementations were not walking
the stack correctly when a StackOverflowError was thrown.  The
throwStackOverflow thunk is called before the frame of the most
recently called method has been fully created, and because tails=true
builds use a different calling convention, we need to treat this
situation carefully when building a stack trace or unwinding.
Otherwise, we will skip past all the java frames to the next native
frame, which is what was happening.
This commit is contained in:
Joel Dice 2014-03-14 09:59:04 -06:00
parent 73e60adeab
commit 918b7828f1
5 changed files with 33 additions and 13 deletions

View File

@ -88,7 +88,7 @@ virtual unsigned alignFrameSize(unsigned sizeInWords) = 0;
virtual void nextFrame(void* start, unsigned size, unsigned footprint, virtual void nextFrame(void* start, unsigned size, unsigned footprint,
void* link, bool mostRecent, void* link, bool mostRecent,
unsigned targetParameterFootprint, void** ip, int targetParameterFootprint, void** ip,
void** stack) = 0; void** stack) = 0;
virtual void* frameIp(void* stack) = 0; virtual void* frameIp(void* stack) = 0;
virtual unsigned frameHeaderSize() = 0; virtual unsigned frameHeaderSize() = 0;
@ -138,4 +138,4 @@ virtual void release() = 0;
} // namespace codegen } // namespace codegen
} // namespace avian } // namespace avian
#endif // AVIAN_CODEGEN_ARCHITECTURE_H #endif // AVIAN_CODEGEN_ARCHITECTURE_H

View File

@ -83,7 +83,7 @@ argumentFootprint(unsigned footprint)
void void
nextFrame(ArchitectureContext* con, uint32_t* start, unsigned size UNUSED, nextFrame(ArchitectureContext* con, uint32_t* start, unsigned size UNUSED,
unsigned footprint, void* link, bool, unsigned footprint, void* link, bool,
unsigned targetParameterFootprint UNUSED, void** ip, void** stack) int targetParameterFootprint UNUSED, void** ip, void** stack)
{ {
assert(con, *ip >= start); assert(con, *ip >= start);
assert(con, *ip <= start + (size / TargetBytesPerWord)); assert(con, *ip <= start + (size / TargetBytesPerWord));
@ -113,13 +113,13 @@ nextFrame(ArchitectureContext* con, uint32_t* start, unsigned size UNUSED,
return; return;
} }
if (TailCalls) { if (TailCalls and targetParameterFootprint >= 0) {
if (argumentFootprint(targetParameterFootprint) > StackAlignmentInWords) { if (argumentFootprint(targetParameterFootprint) > StackAlignmentInWords) {
offset += argumentFootprint(targetParameterFootprint) offset += argumentFootprint(targetParameterFootprint)
- StackAlignmentInWords; - StackAlignmentInWords;
} }
// check for post-non-tail-call stack adjustment of the form "add // check for post-non-tail-call stack adjustment of the form "sub
// sp, sp, #offset": // sp, sp, #offset":
if ((*instruction >> 12) == 0xe24dd) { if ((*instruction >> 12) == 0xe24dd) {
unsigned value = *instruction & 0xff; unsigned value = *instruction & 0xff;
@ -292,7 +292,7 @@ class MyArchitecture: public Architecture {
virtual void nextFrame(void* start, unsigned size, unsigned footprint, virtual void nextFrame(void* start, unsigned size, unsigned footprint,
void* link, bool mostRecent, void* link, bool mostRecent,
unsigned targetParameterFootprint, void** ip, int targetParameterFootprint, void** ip,
void** stack) void** stack)
{ {
arm::nextFrame(&con, static_cast<uint32_t*>(start), size, footprint, link, arm::nextFrame(&con, static_cast<uint32_t*>(start), size, footprint, link,

View File

@ -191,7 +191,7 @@ argumentFootprint(unsigned footprint)
void void
nextFrame(ArchitectureContext* c UNUSED, int32_t* start, unsigned size, nextFrame(ArchitectureContext* c UNUSED, int32_t* start, unsigned size,
unsigned footprint, void* link, bool, unsigned footprint, void* link, bool,
unsigned targetParameterFootprint, void** ip, void** stack) int targetParameterFootprint, void** ip, void** stack)
{ {
assert(c, *ip >= start); assert(c, *ip >= start);
assert(c, *ip <= start + (size / BytesPerWord)); assert(c, *ip <= start + (size / BytesPerWord));
@ -214,7 +214,7 @@ nextFrame(ArchitectureContext* c UNUSED, int32_t* start, unsigned size,
unsigned offset = footprint; unsigned offset = footprint;
if (TailCalls) { if (TailCalls and targetParameterFootprint >= 0) {
if (argumentFootprint(targetParameterFootprint) > StackAlignmentInWords) { if (argumentFootprint(targetParameterFootprint) > StackAlignmentInWords) {
offset += argumentFootprint(targetParameterFootprint) offset += argumentFootprint(targetParameterFootprint)
- StackAlignmentInWords; - StackAlignmentInWords;
@ -391,7 +391,7 @@ class MyArchitecture: public Architecture {
virtual void nextFrame(void* start, unsigned size, unsigned footprint, virtual void nextFrame(void* start, unsigned size, unsigned footprint,
void* link, bool mostRecent, void* link, bool mostRecent,
unsigned targetParameterFootprint, void** ip, int targetParameterFootprint, void** ip,
void** stack) void** stack)
{ {
powerpc::nextFrame(&c, static_cast<int32_t*>(start), size, footprint, link, powerpc::nextFrame(&c, static_cast<int32_t*>(start), size, footprint, link,

View File

@ -72,7 +72,7 @@ read4(uint8_t* p)
void void
nextFrame(ArchitectureContext* c UNUSED, uint8_t* start, unsigned size UNUSED, nextFrame(ArchitectureContext* c UNUSED, uint8_t* start, unsigned size UNUSED,
unsigned footprint, void*, bool mostRecent, unsigned footprint, void*, bool mostRecent,
unsigned targetParameterFootprint, void** ip, void** stack) int targetParameterFootprint, void** ip, void** stack)
{ {
assert(c, *ip >= start); assert(c, *ip >= start);
assert(c, *ip <= start + size); assert(c, *ip <= start + size);
@ -114,13 +114,13 @@ nextFrame(ArchitectureContext* c UNUSED, uint8_t* start, unsigned size UNUSED,
unsigned offset = footprint + FrameHeaderSize - (mostRecent ? 1 : 0); unsigned offset = footprint + FrameHeaderSize - (mostRecent ? 1 : 0);
if (TailCalls) { if (TailCalls and targetParameterFootprint >= 0) {
if (argumentFootprint(targetParameterFootprint) > StackAlignmentInWords) { if (argumentFootprint(targetParameterFootprint) > StackAlignmentInWords) {
offset += argumentFootprint(targetParameterFootprint) offset += argumentFootprint(targetParameterFootprint)
- StackAlignmentInWords; - StackAlignmentInWords;
} }
// check for post-non-tail-call stack adjustment of the form "add // check for post-non-tail-call stack adjustment of the form "sub
// $offset,%rsp": // $offset,%rsp":
if (TargetBytesPerWord == 4) { if (TargetBytesPerWord == 4) {
if ((*instruction == 0x83 or *instruction == 0x81) if ((*instruction == 0x83 or *instruction == 0x81)
@ -141,6 +141,14 @@ nextFrame(ArchitectureContext* c UNUSED, uint8_t* start, unsigned size UNUSED,
// todo: check for and handle tail calls // todo: check for and handle tail calls
} }
if (UseFramePointer and not mostRecent) {
assert(c, static_cast<void***>(*stack)[-1] + 1
== static_cast<void**>(*stack) + offset);
assert(c, static_cast<void***>(*stack)[-1][1]
== static_cast<void**>(*stack)[offset]);
}
*ip = static_cast<void**>(*stack)[offset]; *ip = static_cast<void**>(*stack)[offset];
*stack = static_cast<void**>(*stack) + offset; *stack = static_cast<void**>(*stack) + offset;
@ -369,7 +377,7 @@ class MyArchitecture: public Architecture {
virtual void nextFrame(void* start, unsigned size, unsigned footprint, virtual void nextFrame(void* start, unsigned size, unsigned footprint,
void* link, bool mostRecent, void* link, bool mostRecent,
unsigned targetParameterFootprint, void** ip, int targetParameterFootprint, void** ip,
void** stack) void** stack)
{ {
x86::nextFrame(&c, static_cast<uint8_t*>(start), size, footprint, x86::nextFrame(&c, static_cast<uint8_t*>(start), size, footprint,

View File

@ -1,5 +1,17 @@
public class StackOverflow { public class StackOverflow {
private static int add(int[] numbers, int offset, int length) {
if (length == 0) {
return 0;
} else {
return numbers[offset] + add(numbers, offset + 1, length - 1);
}
}
private static int add(int ... numbers) {
return add(numbers, 0, numbers.length);
}
private static int test1() { private static int test1() {
add(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
return test1() + 1; return test1() + 1;
} }