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;