Stack overflow error and unit test.

Change-Id: Ie7198569207b1b87c50d986df002c551ad5d7d3a
diff --git a/src/asm_support.h b/src/asm_support.h
index 17a29cf..3a8a8ce 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 58cd53b..595bc98 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -2084,7 +2084,7 @@
                 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 0e57592..185cdc2 100644
--- a/src/runtime_support.S
+++ b/src/runtime_support.S
@@ -58,6 +58,15 @@
     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 734ba0b..de2a975 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -16,6 +16,7 @@
   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 989f56d..57bc09b 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -128,12 +128,17 @@
   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 @@
   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 @@
   pLockObjectFromCode = LockObjectFromCode;
   pFindInstanceFieldFromCode = Field::FindInstanceFieldFromCode;
   pCheckSuspendFromCode = artCheckSuspendFromCode;
-  pStackOverflowFromCode = StackOverflowFromCode;
   pThrowVerificationErrorFromCode = ThrowVerificationErrorFromCode;
   pThrowNegArraySizeFromCode = ThrowNegArraySizeFromCode;
   pThrowRuntimeExceptionFromCode = ThrowRuntimeExceptionFromCode;
@@ -573,18 +578,17 @@
   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 a33d361..39d984b 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -167,7 +167,8 @@
     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 @@
   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 @@
     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 @@
   // 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.