Implement StackOverflow check.

Change-Id: I981afe85ace84749f2e194e6df902c8ede947828
diff --git a/src/compiler_llvm/art_module.ll b/src/compiler_llvm/art_module.ll
index 8eb1783..b85ba7c 100644
--- a/src/compiler_llvm/art_module.ll
+++ b/src/compiler_llvm/art_module.ll
@@ -58,7 +58,7 @@
 declare void @art_throw_array_bounds_from_code(i32, i32)
 declare void @art_throw_no_such_method_from_code(i32)
 declare void @art_throw_null_pointer_exception_from_code()
-declare void @art_throw_stack_overflow_from_code(%JavaObject*)
+declare void @art_throw_stack_overflow_from_code()
 declare void @art_throw_exception_from_code(%JavaObject*)
 
 declare i32 @art_find_catch_block_from_code(%JavaObject*, i32)
diff --git a/src/compiler_llvm/generated/art_module.cc b/src/compiler_llvm/generated/art_module.cc
index 18432d5..973ef06 100644
--- a/src/compiler_llvm/generated/art_module.cc
+++ b/src/compiler_llvm/generated/art_module.cc
@@ -413,7 +413,7 @@
 Function* func_art_throw_stack_overflow_from_code = mod->getFunction("art_throw_stack_overflow_from_code");
 if (!func_art_throw_stack_overflow_from_code) {
 func_art_throw_stack_overflow_from_code = Function::Create(
- /*Type=*/FuncTy_4,
+ /*Type=*/FuncTy_5,
  /*Linkage=*/GlobalValue::ExternalLinkage,
  /*Name=*/"art_throw_stack_overflow_from_code", mod); // (external, no body)
 func_art_throw_stack_overflow_from_code->setCallingConv(CallingConv::C);
diff --git a/src/compiler_llvm/method_compiler.cc b/src/compiler_llvm/method_compiler.cc
index 0ab8871..bcd40de 100644
--- a/src/compiler_llvm/method_compiler.cc
+++ b/src/compiler_llvm/method_compiler.cc
@@ -139,6 +139,9 @@
 
 void MethodCompiler::EmitPrologue() {
   // Create basic blocks for prologue
+  basic_block_stack_overflow_ =
+    llvm::BasicBlock::Create(*context_, "prologue.stack_overflow_check", func_);
+
   basic_block_reg_alloca_ =
     llvm::BasicBlock::Create(*context_, "prologue.alloca", func_);
 
@@ -151,6 +154,9 @@
   basic_block_reg_arg_init_ =
     llvm::BasicBlock::Create(*context_, "prologue.arginit", func_);
 
+  // Before alloca, check stack overflow.
+  EmitStackOverflowCheck();
+
   // Create register array
   for (uint16_t r = 0; r < code_item_->registers_size_; ++r) {
     regs_.push_back(DalvikReg::CreateLocalVarReg(*this, r));
@@ -170,7 +176,61 @@
 }
 
 
+void MethodCompiler::EmitStackOverflowCheck() {
+  irb_.SetInsertPoint(basic_block_stack_overflow_);
+
+  // Call llvm intrinsic function to get frame address.
+  llvm::Function* frameaddress =
+      llvm::Intrinsic::getDeclaration(module_, llvm::Intrinsic::frameaddress);
+
+  // The type of llvm::frameaddress is: i8* @llvm.frameaddress(i32)
+  llvm::Value* frame_address = irb_.CreateCall(frameaddress, irb_.getInt32(0));
+
+  // Cast i8* to int
+  frame_address = irb_.CreatePtrToInt(frame_address, irb_.getPtrEquivIntTy());
+
+  // Get thread.stack_end_
+  llvm::Value* thread_object_addr =
+    irb_.CreateCall(irb_.GetRuntime(GetCurrentThread));
+
+  llvm::Value* stack_end_addr =
+    irb_.CreatePtrDisp(thread_object_addr,
+                       irb_.getPtrEquivInt(Thread::StackEndOffset().Int32Value()),
+                       irb_.getPtrEquivIntTy()->getPointerTo());
+
+  llvm::Value* stack_end = irb_.CreateLoad(stack_end_addr);
+
+  // Check the frame address < thread.stack_end_ ?
+  llvm::Value* is_stack_overflow = irb_.CreateICmpULT(frame_address, stack_end);
+
+  llvm::BasicBlock* block_exception =
+      llvm::BasicBlock::Create(*context_, "stack_overflow", func_);
+
+  llvm::BasicBlock* block_continue =
+      llvm::BasicBlock::Create(*context_, "stack_overflow_cont", func_);
+
+  irb_.CreateCondBr(is_stack_overflow, block_exception, block_continue);
+
+  // If stack overflow, throw exception.
+  irb_.SetInsertPoint(block_exception);
+  irb_.CreateCall(irb_.GetRuntime(ThrowStackOverflowException));
+
+  // Unwind.
+  char ret_shorty = method_helper_.GetShorty()[0];
+  if (ret_shorty == 'V') {
+    irb_.CreateRetVoid();
+  } else {
+    irb_.CreateRet(irb_.getJZero(ret_shorty));
+  }
+
+  basic_block_stack_overflow_ = block_continue;
+}
+
+
 void MethodCompiler::EmitPrologueLastBranch() {
+  irb_.SetInsertPoint(basic_block_stack_overflow_);
+  irb_.CreateBr(basic_block_reg_alloca_);
+
   irb_.SetInsertPoint(basic_block_reg_alloca_);
   irb_.CreateBr(basic_block_shadow_frame_alloca_);
 
diff --git a/src/compiler_llvm/method_compiler.h b/src/compiler_llvm/method_compiler.h
index 6f24799..006f763 100644
--- a/src/compiler_llvm/method_compiler.h
+++ b/src/compiler_llvm/method_compiler.h
@@ -88,6 +88,7 @@
  private:
   void CreateFunction();
   void EmitPrologue();
+  void EmitStackOverflowCheck();
   void EmitPrologueLastBranch();
   void EmitPrologueAllocShadowFrame();
   void EmitPrologueAssignArgRegister();
@@ -447,6 +448,7 @@
   std::vector<DalvikReg*> regs_;
   UniquePtr<DalvikReg> retval_reg_;
 
+  llvm::BasicBlock* basic_block_stack_overflow_;
   llvm::BasicBlock* basic_block_reg_alloca_;
   llvm::BasicBlock* basic_block_shadow_frame_alloca_;
   llvm::BasicBlock* basic_block_reg_zero_init_;
diff --git a/src/compiler_llvm/runtime_support_func_list.h b/src/compiler_llvm/runtime_support_func_list.h
index 38d7a89..1c21d48 100644
--- a/src/compiler_llvm/runtime_support_func_list.h
+++ b/src/compiler_llvm/runtime_support_func_list.h
@@ -23,6 +23,7 @@
   V(PopShadowFrame, art_pop_shadow_frame_from_code) \
   V(TestSuspend, art_test_suspend_from_code) \
   V(ThrowException, art_throw_exception_from_code) \
+  V(ThrowStackOverflowException, art_throw_stack_overflow_from_code) \
   V(ThrowNullPointerException, art_throw_null_pointer_exception_from_code) \
   V(ThrowDivZeroException, art_throw_div_zero_from_code) \
   V(ThrowIndexOutOfBounds, art_throw_array_bounds_from_code) \
diff --git a/src/compiler_llvm/runtime_support_llvm.cc b/src/compiler_llvm/runtime_support_llvm.cc
index 7349647..ccc8639 100644
--- a/src/compiler_llvm/runtime_support_llvm.cc
+++ b/src/compiler_llvm/runtime_support_llvm.cc
@@ -113,12 +113,17 @@
   thread->ThrowNewException("Ljava/lang/NullPointerException;", NULL);
 }
 
-void art_throw_stack_overflow_from_code(void*) {
+void art_throw_stack_overflow_from_code() {
   Thread* thread = Thread::Current();
+  if (Runtime::Current()->IsMethodTracingActive()) {
+    TraceMethodUnwindFromCode(thread);
+  }
+  thread->SetStackEndForStackOverflow();  // Allow space on the stack for constructor to execute
   thread->ThrowNewExceptionF("Ljava/lang/StackOverflowError;",
       "stack size %zdkb; default stack size: %zdkb",
       thread->GetStackSize() / KB,
       Runtime::Current()->GetDefaultStackSize() / KB);
+  thread->ResetDefaultStackEnd();  // Return to default stack size
 }
 
 void art_throw_exception_from_code(Object* exception) {
diff --git a/src/compiler_llvm/runtime_support_llvm.h b/src/compiler_llvm/runtime_support_llvm.h
index f0e0a58..51d238b 100644
--- a/src/compiler_llvm/runtime_support_llvm.h
+++ b/src/compiler_llvm/runtime_support_llvm.h
@@ -42,7 +42,7 @@
 
 void art_throw_null_pointer_exception_from_code();
 
-void art_throw_stack_overflow_from_code(void*);
+void art_throw_stack_overflow_from_code();
 
 void art_throw_exception_from_code(Object* exception);
 
diff --git a/src/thread.h b/src/thread.h
index 40409b6..a6459c6 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -87,7 +87,11 @@
   };
 
   // Space to throw a StackOverflowError in.
+#if !defined(ART_USE_LLVM_COMPILER)
   static const size_t kStackOverflowReservedBytes = 4 * KB;
+#else  // LLVM_x86 requires more memory to throw stack overflow exception.
+  static const size_t kStackOverflowReservedBytes = 8 * KB;
+#endif
 
   static const size_t kDefaultStackSize = 96 * KB;