diff options
| author | 2011-09-22 20:06:48 -0700 | |
|---|---|---|
| committer | 2011-09-22 20:06:48 -0700 | |
| commit | d8b877a20c87e3c7ebef4a3ddd1d8896b2a5b822 (patch) | |
| tree | 92aeaf574b00a8177eba50d6408b5dbc183bc28d | |
| parent | 8fe11f02fdf16ad03d91a891c1a4570b85a82c83 (diff) | |
| parent | 932746a4f22951abcba7b7c4c94c27b1bf164272 (diff) | |
Merge "Stack overflow error and unit test." into dalvik-dev
| -rw-r--r-- | src/asm_support.h | 6 | ||||
| -rw-r--r-- | src/compiler/codegen/arm/MethodCodegenDriver.cc | 2 | ||||
| -rw-r--r-- | src/runtime_support.S | 9 | ||||
| -rw-r--r-- | src/runtime_support.h | 1 | ||||
| -rw-r--r-- | src/thread.cc | 36 | ||||
| -rw-r--r-- | src/thread.h | 31 | ||||
| -rw-r--r-- | test/IntMath/IntMath.java | 27 |
7 files changed, 90 insertions, 22 deletions
diff --git a/src/asm_support.h b/src/asm_support.h index 17a29cf67b..3a8a8ce350 100644 --- a/src/asm_support.h +++ b/src/asm_support.h @@ -9,13 +9,13 @@ #define rLR r14 #define SUSPEND_CHECK_INTERVAL (1000) // Offset of field Thread::top_of_managed_stack_ verified in InitCpu -#define THREAD_TOP_OF_MANAGED_STACK_OFFSET 333 +#define THREAD_TOP_OF_MANAGED_STACK_OFFSET 341 // Offset of field Thread::top_of_managed_stack_pc_ verified in InitCpu -#define THREAD_TOP_OF_MANAGED_STACK_PC_OFFSET 337 +#define THREAD_TOP_OF_MANAGED_STACK_PC_OFFSET 345 #elif defined(__i386__) // Offset of field Thread::self_ verified in InitCpu -#define THREAD_SELF_OFFSET 0x165 +#define THREAD_SELF_OFFSET 365 #endif #endif // ART_SRC_ASM_SUPPORT_H_ diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc index 58cd53bc48..595bc986b5 100644 --- a/src/compiler/codegen/arm/MethodCodegenDriver.cc +++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc @@ -2084,7 +2084,7 @@ static void handleThrowLaunchpads(CompilationUnit *cUnit) break; case kArmThrowStackOverflow: funcOffset = - OFFSETOF_MEMBER(Thread, pStackOverflowFromCode); + OFFSETOF_MEMBER(Thread, pThrowStackOverflowFromCode); // Restore stack alignment opRegImm(cUnit, kOpAdd, rSP, cUnit->numSpills * 4); break; diff --git a/src/runtime_support.S b/src/runtime_support.S index 0e575923ac..185cdc2acc 100644 --- a/src/runtime_support.S +++ b/src/runtime_support.S @@ -58,6 +58,15 @@ art_throw_array_bounds_from_code: mov r3, sp @ pass SP b artThrowArrayBoundsFromCode @ artThrowArrayBoundsFromCode(index, limit, Thread*, SP) + .global art_throw_stack_overflow_from_code + .extern artThrowStackOverflowFromCode +art_throw_stack_overflow_from_code: + stmdb sp!, {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, lr} + sub sp, #16 @ 4 words of space, bottom word will hold Method* + mov r1, r9 @ pass Thread::Current + mov r2, sp @ pass SP + b artThrowStackOverflowFromCode @ artThrowStackOverflowFromCode(method, Thread*, SP) + .global art_invoke_interface_trampoline .extern artFindInterfaceMethodInCacheFromCode /* diff --git a/src/runtime_support.h b/src/runtime_support.h index 734ba0b9eb..de2a975b27 100644 --- a/src/runtime_support.h +++ b/src/runtime_support.h @@ -16,6 +16,7 @@ extern "C" void art_deliver_exception_from_code(void*); extern "C" void art_throw_array_bounds_from_code(int32_t index, int32_t limit); extern "C" void art_throw_div_zero_from_code(); extern "C" void art_throw_null_pointer_exception_from_code(); + extern "C" void art_throw_stack_overflow_from_code(void*); extern "C" void art_unlock_object_from_code(void*, void*); /* Conversions */ diff --git a/src/thread.cc b/src/thread.cc index 989f56d169..57bc09b156 100644 --- a/src/thread.cc +++ b/src/thread.cc @@ -128,12 +128,17 @@ void ThrowAbstractMethodErrorFromCode(Method* method, Thread* thread, Method** s thread->DeliverException(); } -// TODO: placeholder -void StackOverflowFromCode(Method* method) { - Thread::Current()->SetTopOfStackPC(reinterpret_cast<uintptr_t>(__builtin_return_address(0))); - Thread::Current()->Dump(std::cerr); - //NOTE: to save code space, this handler needs to look up its own Thread* - UNIMPLEMENTED(FATAL) << "Stack overflow: " << PrettyMethod(method); +extern "C" void artThrowStackOverflowFromCode(Method* method, Thread* thread, Method** sp) { + // Place a special frame at the TOS that will save all callee saves + Runtime* runtime = Runtime::Current(); + *sp = runtime->GetCalleeSaveMethod(); + thread->SetTopOfStack(sp, 0); + thread->SetStackEndForStackOverflow(); + thread->ThrowNewException("Ljava/lang/StackOverflowError;", + "stack size %zdkb; default stack size: %zdkb", + thread->GetStackSize() / KB, runtime->GetDefaultStackSize() / KB); + thread->ResetDefaultStackEnd(); + thread->DeliverException(); } // TODO: placeholder @@ -359,6 +364,7 @@ void Thread::InitFunctionPointers() { pThrowArrayBoundsFromCode = art_throw_array_bounds_from_code; pThrowDivZeroFromCode = art_throw_div_zero_from_code; pThrowNullPointerFromCode = art_throw_null_pointer_exception_from_code; + pThrowStackOverflowFromCode = art_throw_stack_overflow_from_code; pUnlockObjectFromCode = art_unlock_object_from_code; #endif pDeliverException = art_deliver_exception_from_code; @@ -381,7 +387,6 @@ void Thread::InitFunctionPointers() { pLockObjectFromCode = LockObjectFromCode; pFindInstanceFieldFromCode = Field::FindInstanceFieldFromCode; pCheckSuspendFromCode = artCheckSuspendFromCode; - pStackOverflowFromCode = StackOverflowFromCode; pThrowVerificationErrorFromCode = ThrowVerificationErrorFromCode; pThrowNegArraySizeFromCode = ThrowNegArraySizeFromCode; pThrowRuntimeExceptionFromCode = ThrowRuntimeExceptionFromCode; @@ -573,18 +578,17 @@ void Thread::InitStackHwm() { pthread_attr_t attributes; CHECK_PTHREAD_CALL(pthread_getattr_np, (pthread_, &attributes), __FUNCTION__); - void* stack_base; - size_t stack_size; - CHECK_PTHREAD_CALL(pthread_attr_getstack, (&attributes, &stack_base, &stack_size), __FUNCTION__); + void* temp_stack_base; + CHECK_PTHREAD_CALL(pthread_attr_getstack, (&attributes, &temp_stack_base, &stack_size_), + __FUNCTION__); + stack_base_ = reinterpret_cast<byte*>(temp_stack_base); - if (stack_size <= kStackOverflowReservedBytes) { - LOG(FATAL) << "attempt to attach a thread with a too-small stack (" << stack_size << " bytes)"; + if (stack_size_ <= kStackOverflowReservedBytes) { + LOG(FATAL) << "attempt to attach a thread with a too-small stack (" << stack_size_ << " bytes)"; } - // stack_base is the "lowest addressable byte" of the stack. - // Our stacks grow down, so we want stack_end_ to be near there, but reserving enough room - // to throw a StackOverflowError. - stack_end_ = reinterpret_cast<byte*>(stack_base) + kStackOverflowReservedBytes; + // Set stack_end_ to the bottom of the stack saving space of stack overflows + ResetDefaultStackEnd(); // Sanity check. int stack_variable; diff --git a/src/thread.h b/src/thread.h index a33d36153f..39d984bed3 100644 --- a/src/thread.h +++ b/src/thread.h @@ -167,7 +167,8 @@ class PACKED Thread { kSuspended = 9, // suspended, usually by GC or debugger }; - static const size_t kStackOverflowReservedBytes = 1024; // Space to throw a StackOverflowError in. + // Space to throw a StackOverflowError in. + static const size_t kStackOverflowReservedBytes = 3 * KB; static const size_t kDefaultStackSize = 64 * KB; @@ -225,7 +226,7 @@ class PACKED Thread { Field* (*pFindInstanceFieldFromCode)(uint32_t, const Method*); void (*pCheckSuspendFromCode)(Thread*); void (*pTestSuspendFromCode)(); - void (*pStackOverflowFromCode)(Method*); + void (*pThrowStackOverflowFromCode)(void*); void (*pThrowNullPointerFromCode)(); void (*pThrowArrayBoundsFromCode)(int32_t, int32_t); void (*pThrowDivZeroFromCode)(); @@ -489,6 +490,26 @@ class PACKED Thread { return ThreadOffset(OFFSETOF_VOLATILE_MEMBER(Thread, state_)); } + // Size of stack less any space reserved for stack overflow + size_t GetStackSize() { + return stack_size_ - (stack_end_ - stack_base_); + } + + // Set the stack end to that to be used during a stack overflow + void SetStackEndForStackOverflow() { + // During stack overflow we allow use of the full stack + CHECK(stack_end_ != stack_base_) << "Need to increase: kStackOverflowReservedBytes (" + << kStackOverflowReservedBytes << ")"; + stack_end_ = stack_base_; + } + + // Set the stack end to that to be used during regular execution + void ResetDefaultStackEnd() { + // Our stacks grow down, so we want stack_end_ to be near there, but reserving enough room + // to throw a StackOverflowError. + stack_end_ = stack_base_ + kStackOverflowReservedBytes; + } + static ThreadOffset StackEndOffset() { return ThreadOffset(OFFSETOF_MEMBER(Thread, stack_end_)); } @@ -577,6 +598,12 @@ class PACKED Thread { // We leave extra space so there's room for the code that throws StackOverflowError. byte* stack_end_; + // Size of the stack + size_t stack_size_; + + // The "lowest addressable byte" of the stack + byte* stack_base_; + // Top of the managed stack, written out prior to the state transition from // kRunnable to kNative. Uses include to give the starting point for scanning // a managed stack when a thread is in native code. diff --git a/test/IntMath/IntMath.java b/test/IntMath/IntMath.java index c43d09eafc..e5fa806ca4 100644 --- a/test/IntMath/IntMath.java +++ b/test/IntMath/IntMath.java @@ -786,6 +786,25 @@ class IntMath extends IntMathBase { return res; } + static long recursion_count_; + static void throwStackOverflow(long l) { + recursion_count_++; + throwStackOverflow(recursion_count_); + } + + static long testStackOverflow() { + try { + throwStackOverflow(0); + if (recursion_count_ != 0) { + return recursion_count_; + } else { + return -1; + } + } catch(StackOverflowError soe) { + return 0; + } + } + public static void main(String[] args) { boolean failure = false; int res; @@ -947,6 +966,14 @@ class IntMath extends IntMathBase { failure = true; } + lres= testStackOverflow(); + if (lres == 0) { + System.out.println("testStackOverflow PASSED"); + } else { + System.out.println("testStackOverflow FAILED: " + lres); + failure = true; + } + res = manyArgs(0, 1L, 2, 3L, 4, 5L, 6, 7, 8.0, 9.0f, 10.0, (short)11, 12, (char)13, 14, 15, (byte)-16, true, 18, 19, 20L, 21L, 22, 23, 24, 25, 26); |