Add landing pad support.
Change-Id: I38fef34f625e739cf716c071c179a2eb0728279d
diff --git a/src/compiler_llvm/method_compiler.cc b/src/compiler_llvm/method_compiler.cc
index 65d6412..ca1eba5 100644
--- a/src/compiler_llvm/method_compiler.cc
+++ b/src/compiler_llvm/method_compiler.cc
@@ -59,7 +59,9 @@
irb_(*compiler_llvm_->GetIRBuilder()), func_(NULL), retval_reg_(NULL),
basic_block_reg_alloca_(NULL),
basic_block_reg_zero_init_(NULL), basic_block_reg_arg_init_(NULL),
- basic_blocks_(code_item->insns_size_in_code_units_) {
+ basic_blocks_(code_item->insns_size_in_code_units_),
+ basic_block_landing_pads_(code_item->tries_size_, NULL),
+ basic_block_unwind_(NULL), basic_block_unreachable_(NULL) {
}
@@ -242,6 +244,31 @@
}
+void MethodCompiler::EmitBranchExceptionLandingPad(uint32_t dex_pc) {
+ if (llvm::BasicBlock* lpad = GetLandingPadBasicBlock(dex_pc)) {
+ irb_.CreateBr(lpad);
+ } else {
+ irb_.CreateBr(GetUnwindBasicBlock());
+ }
+}
+
+
+void MethodCompiler::EmitGuard_ExceptionLandingPad(uint32_t dex_pc) {
+ llvm::Value* exception_pending =
+ irb_.CreateCall(irb_.GetRuntime(IsExceptionPending));
+
+ llvm::BasicBlock* block_cont = CreateBasicBlockWithDexPC(dex_pc, "cont");
+
+ if (llvm::BasicBlock* lpad = GetLandingPadBasicBlock(dex_pc)) {
+ irb_.CreateCondBr(exception_pending, lpad, block_cont);
+ } else {
+ irb_.CreateCondBr(exception_pending, GetUnwindBasicBlock(), block_cont);
+ }
+
+ irb_.SetInsertPoint(block_cont);
+}
+
+
llvm::BasicBlock* MethodCompiler::
CreateBasicBlockWithDexPC(uint32_t dex_pc, char const* postfix) {
std::string name;
@@ -277,6 +304,129 @@
}
+int32_t MethodCompiler::GetTryItemOffset(uint32_t dex_pc) {
+ // TODO: Since we are emitting the dex instructions in ascending order
+ // w.r.t. address, we can cache the lastest try item offset so that we
+ // don't have to do binary search for every query.
+
+ int32_t min = 0;
+ int32_t max = code_item_->tries_size_ - 1;
+
+ while (min <= max) {
+ int32_t mid = min + (max - min) / 2;
+
+ DexFile::TryItem const* ti = DexFile::GetTryItems(*code_item_, mid);
+ uint32_t start = ti->start_addr_;
+ uint32_t end = start + ti->insn_count_;
+
+ if (dex_pc < start) {
+ max = mid - 1;
+ } else if (dex_pc >= end) {
+ min = mid + 1;
+ } else {
+ return mid; // found
+ }
+ }
+
+ return -1; // not found
+}
+
+
+llvm::BasicBlock* MethodCompiler::GetLandingPadBasicBlock(uint32_t dex_pc) {
+ // Find the try item for this address in this method
+ int32_t ti_offset = GetTryItemOffset(dex_pc);
+
+ if (ti_offset == -1) {
+ return NULL; // No landing pad is available for this address.
+ }
+
+ // Check for the existing landing pad basic block
+ DCHECK_GT(basic_block_landing_pads_.size(), static_cast<size_t>(ti_offset));
+ llvm::BasicBlock* block_lpad = basic_block_landing_pads_[ti_offset];
+
+ if (block_lpad) {
+ // We have generated landing pad for this try item already. Return the
+ // same basic block.
+ return block_lpad;
+ }
+
+ // Get try item from code item
+ DexFile::TryItem const* ti = DexFile::GetTryItems(*code_item_, ti_offset);
+
+ // Create landing pad basic block
+ block_lpad = llvm::BasicBlock::Create(*context_,
+ StringPrintf("lpad%d", ti_offset),
+ func_);
+
+ // Change IRBuilder insert point
+ llvm::IRBuilderBase::InsertPoint irb_ip_original = irb_.saveIP();
+ irb_.SetInsertPoint(block_lpad);
+
+ // Find catch block with matching type
+ llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
+
+ // TODO: Maybe passing try item offset will be a better idea? For now,
+ // we are passing dex_pc, so that we can use existing runtime support
+ // function directly. However, in the runtime supporting function we
+ // have to search for try item with binary search which can be
+ // eliminated.
+ llvm::Value* dex_pc_value = irb_.getInt32(ti->start_addr_);
+
+ llvm::Value* catch_handler_index_value =
+ irb_.CreateCall2(irb_.GetRuntime(FindCatchBlock),
+ method_object_addr, dex_pc_value);
+
+ // Switch instruction (Go to unwind basic block by default)
+ llvm::SwitchInst* sw =
+ irb_.CreateSwitch(catch_handler_index_value, GetUnwindBasicBlock());
+
+ // Cases with matched catch block
+ CatchHandlerIterator iter(*code_item_, ti->start_addr_);
+
+ for (uint32_t c = 0; iter.HasNext(); iter.Next(), ++c) {
+ sw->addCase(irb_.getInt32(c), GetBasicBlock(iter.GetHandlerAddress()));
+ }
+
+ // Restore the orignal insert point for IRBuilder
+ irb_.restoreIP(irb_ip_original);
+
+ // Cache this landing pad
+ DCHECK_GT(basic_block_landing_pads_.size(), static_cast<size_t>(ti_offset));
+ basic_block_landing_pads_[ti_offset] = block_lpad;
+
+ return block_lpad;
+}
+
+
+llvm::BasicBlock* MethodCompiler::GetUnwindBasicBlock() {
+ // Check the existing unwinding baisc block block
+ if (basic_block_unwind_ != NULL) {
+ return basic_block_unwind_;
+ }
+
+ // Create new basic block for unwinding
+ basic_block_unwind_ =
+ llvm::BasicBlock::Create(*context_, "exception_unwind", func_);
+
+ // Change IRBuilder insert point
+ llvm::IRBuilderBase::InsertPoint irb_ip_original = irb_.saveIP();
+ irb_.SetInsertPoint(basic_block_unwind_);
+
+ // Emit the code to return default value (zero) for the given return type.
+ char ret_shorty = method_helper_.GetShorty()[0];
+ if (ret_shorty == 'V') {
+ irb_.CreateRetVoid();
+ } else {
+ irb_.CreateRet(irb_.getJZero(ret_shorty));
+ }
+
+ // Restore the orignal insert point for IRBuilder
+ irb_.restoreIP(irb_ip_original);
+
+ return basic_block_unwind_;
+}
+
+
llvm::Value* MethodCompiler::AllocDalvikLocalVarReg(RegCategory cat,
uint32_t reg_idx) {
diff --git a/src/compiler_llvm/method_compiler.h b/src/compiler_llvm/method_compiler.h
index 5918107..491ced3 100644
--- a/src/compiler_llvm/method_compiler.h
+++ b/src/compiler_llvm/method_compiler.h
@@ -89,6 +89,10 @@
llvm::BasicBlock* basic_block_reg_arg_init_;
std::vector<llvm::BasicBlock*> basic_blocks_;
+ std::vector<llvm::BasicBlock*> basic_block_landing_pads_;
+ llvm::BasicBlock* basic_block_unwind_;
+ llvm::BasicBlock* basic_block_unreachable_;
+
public:
MethodCompiler(InstructionSet insn_set,
@@ -137,6 +141,10 @@
llvm::FunctionType* GetFunctionType(uint32_t method_idx, bool is_static);
+ void EmitGuard_ExceptionLandingPad(uint32_t dex_pc);
+
+ void EmitBranchExceptionLandingPad(uint32_t dex_pc);
+
// Basic block helper functions
llvm::BasicBlock* GetBasicBlock(uint32_t dex_pc);
@@ -146,6 +154,12 @@
llvm::BasicBlock* CreateBasicBlockWithDexPC(uint32_t dex_pc,
char const* postfix = NULL);
+ int32_t GetTryItemOffset(uint32_t dex_pc);
+
+ llvm::BasicBlock* GetLandingPadBasicBlock(uint32_t dex_pc);
+
+ llvm::BasicBlock* GetUnwindBasicBlock();
+
// Register helper function