summaryrefslogtreecommitdiff
path: root/src/compiler_llvm/method_compiler.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler_llvm/method_compiler.cc')
-rw-r--r--src/compiler_llvm/method_compiler.cc167
1 files changed, 88 insertions, 79 deletions
diff --git a/src/compiler_llvm/method_compiler.cc b/src/compiler_llvm/method_compiler.cc
index 52b7b5f39b..06128551f2 100644
--- a/src/compiler_llvm/method_compiler.cc
+++ b/src/compiler_llvm/method_compiler.cc
@@ -67,7 +67,6 @@ MethodCompiler::MethodCompiler(CompilationUnit* cunit,
shadow_frame_entries_(code_item_->registers_size_),
reg_to_shadow_frame_index_(code_item_->registers_size_, -1),
retval_reg_(NULL),
- basic_block_stack_overflow_(NULL),
basic_block_alloca_(NULL), basic_block_shadow_frame_(NULL),
basic_block_reg_arg_init_(NULL),
basic_blocks_(code_item_->insns_size_in_code_units_),
@@ -156,9 +155,6 @@ void MethodCompiler::EmitPrologue() {
basic_block_alloca_ =
llvm::BasicBlock::Create(*context_, "prologue.alloca", func_);
- basic_block_stack_overflow_ =
- llvm::BasicBlock::Create(*context_, "prologue.stack_overflow_check", func_);
-
basic_block_shadow_frame_ =
llvm::BasicBlock::Create(*context_, "prologue.shadowframe", func_);
@@ -206,8 +202,6 @@ void MethodCompiler::EmitPrologue() {
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);
@@ -251,14 +245,18 @@ void MethodCompiler::EmitStackOverflowCheck() {
irb_.CreateRet(irb_.getJZero(ret_shorty));
}
- basic_block_stack_overflow_ = block_continue;
+ irb_.SetInsertPoint(block_continue);
}
void MethodCompiler::EmitPrologueLastBranch() {
+ llvm::BasicBlock* basic_block_stack_overflow =
+ llvm::BasicBlock::Create(*context_, "prologue.stack_overflow_check", func_);
+
irb_.SetInsertPoint(basic_block_alloca_);
- irb_.CreateBr(basic_block_stack_overflow_);
+ irb_.CreateBr(basic_block_stack_overflow);
+ irb_.SetInsertPoint(basic_block_stack_overflow);
// If a method will not call to other method, and the method is small, we can avoid stack overflow
// check.
if (method_info_.has_invoke ||
@@ -266,8 +264,8 @@ void MethodCompiler::EmitPrologueLastBranch() {
// the 8KB reserved at Stack End
EmitStackOverflowCheck();
}
-
- irb_.SetInsertPoint(basic_block_stack_overflow_);
+ // Garbage collection safe-point
+ EmitGuard_GarbageCollectionSuspend();
irb_.CreateBr(basic_block_shadow_frame_);
irb_.SetInsertPoint(basic_block_shadow_frame_);
@@ -1331,9 +1329,6 @@ void MethodCompiler::EmitInsn_ThrowVerificationError(uint32_t dex_pc,
void MethodCompiler::EmitInsn_ReturnVoid(uint32_t dex_pc,
Instruction const* insn) {
- // Garbage collection safe-point
- EmitGuard_GarbageCollectionSuspend(dex_pc);
-
// Pop the shadow frame
EmitPopShadowFrame();
@@ -1347,9 +1342,6 @@ void MethodCompiler::EmitInsn_Return(uint32_t dex_pc,
DecodedInstruction dec_insn(insn);
- // Garbage collection safe-point
- EmitGuard_GarbageCollectionSuspend(dex_pc);
-
// Pop the shadow frame
EmitPopShadowFrame();
// NOTE: It is important to keep this AFTER the GC safe-point. Otherwise,
@@ -1460,7 +1452,7 @@ void MethodCompiler::EmitInsn_LoadConstantString(uint32_t dex_pc,
string_addr = irb_.CreateCall2(runtime_func, method_object_addr,
string_idx_value);
- EmitGuard_ExceptionLandingPad(dex_pc);
+ EmitGuard_ExceptionLandingPad(dex_pc, true);
}
// Store the string object to the Dalvik register
@@ -1488,7 +1480,7 @@ llvm::Value* MethodCompiler::EmitLoadConstantClass(uint32_t dex_pc,
llvm::Value* type_object_addr =
irb_.CreateCall3(runtime_func, type_idx_value, method_object_addr, thread_object_addr);
- EmitGuard_ExceptionLandingPad(dex_pc);
+ EmitGuard_ExceptionLandingPad(dex_pc, false);
return type_object_addr;
@@ -1533,7 +1525,7 @@ llvm::Value* MethodCompiler::EmitLoadConstantClass(uint32_t dex_pc,
llvm::Value* loaded_type_object_addr =
irb_.CreateCall3(runtime_func, type_idx_value, method_object_addr, thread_object_addr);
- EmitGuard_ExceptionLandingPad(dex_pc);
+ EmitGuard_ExceptionLandingPad(dex_pc, false);
llvm::BasicBlock* block_after_load_class = irb_.GetInsertBlock();
@@ -1601,7 +1593,8 @@ void MethodCompiler::EmitInsn_MonitorExit(uint32_t dex_pc,
llvm::Value* thread_object_addr = irb_.CreateCall(irb_.GetRuntime(GetCurrentThread));
irb_.CreateCall2(irb_.GetRuntime(UnlockObject), object_addr, thread_object_addr);
- EmitGuard_ExceptionLandingPad(dex_pc);
+
+ EmitGuard_ExceptionLandingPad(dex_pc, true);
irb_.CreateBr(GetNextBasicBlock(dex_pc));
}
@@ -1656,7 +1649,7 @@ void MethodCompiler::EmitInsn_CheckCast(uint32_t dex_pc,
irb_.CreateCall2(irb_.GetRuntime(CheckCast),
type_object_addr, object_type_object_addr);
- EmitGuard_ExceptionLandingPad(dex_pc);
+ EmitGuard_ExceptionLandingPad(dex_pc, true);
irb_.CreateBr(GetNextBasicBlock(dex_pc));
}
@@ -1782,7 +1775,7 @@ void MethodCompiler::EmitInsn_NewInstance(uint32_t dex_pc,
llvm::Value* object_addr =
irb_.CreateCall3(runtime_func, type_index_value, method_object_addr, thread_object_addr);
- EmitGuard_ExceptionLandingPad(dex_pc);
+ EmitGuard_ExceptionLandingPad(dex_pc, true);
EmitStoreDalvikReg(dec_insn.vA, kObject, kAccurate, object_addr);
@@ -1826,7 +1819,7 @@ llvm::Value* MethodCompiler::EmitAllocNewArray(uint32_t dex_pc,
irb_.CreateCall4(runtime_func, type_index_value, method_object_addr,
array_length_value, thread_object_addr);
- EmitGuard_ExceptionLandingPad(dex_pc);
+ EmitGuard_ExceptionLandingPad(dex_pc, false);
return object_addr;
}
@@ -1957,7 +1950,7 @@ void MethodCompiler::EmitInsn_FillArrayData(uint32_t dex_pc,
method_object_addr, irb_.getInt32(dex_pc),
array_addr, irb_.getInt32(payload_offset));
- EmitGuard_ExceptionLandingPad(dex_pc);
+ EmitGuard_ExceptionLandingPad(dex_pc, true);
}
irb_.CreateBr(GetNextBasicBlock(dex_pc));
@@ -2345,7 +2338,7 @@ void MethodCompiler::EmitInsn_APut(uint32_t dex_pc,
irb_.CreateCall2(runtime_func, new_value, array_addr);
- EmitGuard_ExceptionLandingPad(dex_pc);
+ EmitGuard_ExceptionLandingPad(dex_pc, false);
EmitMarkGCCard(new_value, array_addr);
}
@@ -2398,7 +2391,7 @@ void MethodCompiler::EmitInsn_IGet(uint32_t dex_pc,
field_value = irb_.CreateCall3(runtime_func, field_idx_value,
method_object_addr, object_addr);
- EmitGuard_ExceptionLandingPad(dex_pc);
+ EmitGuard_ExceptionLandingPad(dex_pc, true);
} else {
DCHECK_GE(field_offset, 0);
@@ -2464,7 +2457,7 @@ void MethodCompiler::EmitInsn_IPut(uint32_t dex_pc,
irb_.CreateCall4(runtime_func, field_idx_value,
method_object_addr, object_addr, new_value);
- EmitGuard_ExceptionLandingPad(dex_pc);
+ EmitGuard_ExceptionLandingPad(dex_pc, true);
} else {
DCHECK_GE(field_offset, 0);
@@ -2528,7 +2521,7 @@ llvm::Value* MethodCompiler::EmitLoadStaticStorage(uint32_t dex_pc,
llvm::Value* loaded_storage_object_addr =
irb_.CreateCall3(runtime_func, type_idx_value, method_object_addr, thread_object_addr);
- EmitGuard_ExceptionLandingPad(dex_pc);
+ EmitGuard_ExceptionLandingPad(dex_pc, false);
llvm::BasicBlock* block_after_load_static = irb_.GetInsertBlock();
@@ -2585,7 +2578,7 @@ void MethodCompiler::EmitInsn_SGet(uint32_t dex_pc,
static_field_value =
irb_.CreateCall2(runtime_func, field_idx_value, method_object_addr);
- EmitGuard_ExceptionLandingPad(dex_pc);
+ EmitGuard_ExceptionLandingPad(dex_pc, true);
} else {
DCHECK_GE(field_offset, 0);
@@ -2664,7 +2657,7 @@ void MethodCompiler::EmitInsn_SPut(uint32_t dex_pc,
irb_.CreateCall3(runtime_func, field_idx_value,
method_object_addr, new_value);
- EmitGuard_ExceptionLandingPad(dex_pc);
+ EmitGuard_ExceptionLandingPad(dex_pc, true);
} else {
DCHECK_GE(field_offset, 0);
@@ -2878,7 +2871,7 @@ void MethodCompiler::EmitInsn_Invoke(uint32_t dex_pc,
// Invoke callee
EmitUpdateDexPC(dex_pc);
llvm::Value* retval = irb_.CreateCall(code_addr, args);
- EmitGuard_ExceptionLandingPad(dex_pc);
+ EmitGuard_ExceptionLandingPad(dex_pc, true);
uint32_t callee_access_flags = is_static ? kAccStatic : 0;
UniquePtr<OatCompilationUnit> callee_oat_compilation_unit(
@@ -2933,7 +2926,7 @@ void MethodCompiler::EmitInsn_Invoke(uint32_t dex_pc,
irb_.SetInsertPoint(block_link);
code_addr = EmitFixStub(callee_method_object_addr, callee_method_idx, is_static);
- EmitGuard_ExceptionLandingPad(dex_pc);
+ EmitGuard_ExceptionLandingPad(dex_pc, false);
llvm::Value* retval = irb_.CreateCall(code_addr, args);
if (ret_shorty != 'V') {
@@ -2964,7 +2957,7 @@ void MethodCompiler::EmitInsn_Invoke(uint32_t dex_pc,
irb_.SetInsertPoint(block_continue);
- EmitGuard_ExceptionLandingPad(dex_pc);
+ EmitGuard_ExceptionLandingPad(dex_pc, true);
#endif
irb_.CreateBr(GetNextBasicBlock(dex_pc));
@@ -3063,7 +3056,7 @@ EmitCallRuntimeForCalleeMethodObjectAddr(uint32_t callee_method_idx,
caller_method_object_addr,
thread_object_addr);
- EmitGuard_ExceptionLandingPad(dex_pc);
+ EmitGuard_ExceptionLandingPad(dex_pc, false);
return callee_method_object_addr;
}
@@ -3699,13 +3692,20 @@ void MethodCompiler::EmitBranchExceptionLandingPad(uint32_t dex_pc) {
}
-void MethodCompiler::EmitGuard_ExceptionLandingPad(uint32_t dex_pc) {
+void MethodCompiler::EmitGuard_ExceptionLandingPad(uint32_t dex_pc, bool can_skip_unwind) {
+ llvm::BasicBlock* lpad = GetLandingPadBasicBlock(dex_pc);
+ Instruction const* insn = Instruction::At(code_item_->insns_ + dex_pc);
+ if (lpad == NULL && can_skip_unwind &&
+ IsInstructionDirectToReturn(dex_pc + insn->SizeInCodeUnits())) {
+ return;
+ }
+
llvm::Value* exception_pending =
irb_.CreateCall(irb_.GetRuntime(IsExceptionPending));
llvm::BasicBlock* block_cont = CreateBasicBlockWithDexPC(dex_pc, "cont");
- if (llvm::BasicBlock* lpad = GetLandingPadBasicBlock(dex_pc)) {
+ if (lpad) {
irb_.CreateCondBr(exception_pending, lpad, block_cont, kUnlikely);
} else {
irb_.CreateCondBr(exception_pending, GetUnwindBasicBlock(), block_cont, kUnlikely);
@@ -3715,8 +3715,9 @@ void MethodCompiler::EmitGuard_ExceptionLandingPad(uint32_t dex_pc) {
}
-void MethodCompiler::EmitGuard_GarbageCollectionSuspend(uint32_t dex_pc) {
- if (!method_info_.need_shadow_frame_entry) {
+void MethodCompiler::EmitGuard_GarbageCollectionSuspend() {
+ // Loop suspend will be added by our llvm pass.
+ if (!method_info_.has_invoke) {
return;
}
@@ -4086,6 +4087,49 @@ bool MethodCompiler::EmitInlinedStringLength(const std::vector<llvm::Value*>& ar
}
+bool MethodCompiler::IsInstructionDirectToReturn(uint32_t dex_pc) {
+ for (int i = 0; i < 8; ++i) { // Trace at most 8 instructions.
+ if (dex_pc >= code_item_->insns_size_in_code_units_) {
+ return false;
+ }
+
+ Instruction const* insn = Instruction::At(code_item_->insns_ + dex_pc);
+
+ if (insn->IsReturn()) {
+ return true;
+ }
+
+ // Is throw, switch, invoke or conditional branch.
+ if (insn->IsThrow() || insn->IsSwitch() || insn->IsInvoke() ||
+ (insn->IsBranch() && !insn->IsUnconditional())) {
+ return false;
+ }
+
+ switch (insn->Opcode()) {
+ default:
+ dex_pc += insn->SizeInCodeUnits();
+ break;
+
+ // This instruction will remove the exception. Consider as a side effect.
+ case Instruction::MOVE_EXCEPTION:
+ return false;
+ break;
+
+ case Instruction::GOTO:
+ case Instruction::GOTO_16:
+ case Instruction::GOTO_32:
+ {
+ DecodedInstruction dec_insn(insn);
+ int32_t branch_offset = dec_insn.vA;
+ dex_pc += branch_offset;
+ }
+ break;
+ }
+ }
+ return false;
+}
+
+
// TODO: Use high-level IR to do this
void MethodCompiler::ComputeMethodInfo() {
// If this method is static, we set the "this" register index to -1. So we don't worry about this
@@ -4192,23 +4236,8 @@ void MethodCompiler::ComputeMethodInfo() {
case Instruction::GOTO_32:
{
int32_t branch_offset = dec_insn.vA;
- if (branch_offset <= 0) {
- Instruction const* target = Instruction::At(code_item_->insns_ + dex_pc + branch_offset);
- // According to the statistics, there are a few methods have "fake" back edge, which means
- // the backedge is not for a loop.
- // The most "fake" edges in the small methods are just branches to a return instruction. So
- // we can do an simple check to avoid false loop detection. After we have a high-level IR
- // before IRBuilder, we should remove this trick.
- switch (target->Opcode()) {
- default:
- may_have_loop = true;
- break;
- case Instruction::RETURN_VOID:
- case Instruction::RETURN:
- case Instruction::RETURN_WIDE:
- case Instruction::RETURN_OBJECT:
- break;
- }
+ if (branch_offset <= 0 && !IsInstructionDirectToReturn(dex_pc + branch_offset)) {
+ may_have_loop = true;
}
}
break;
@@ -4235,18 +4264,8 @@ void MethodCompiler::ComputeMethodInfo() {
case Instruction::IF_LE:
{
int32_t branch_offset = dec_insn.vC;
- if (branch_offset <= 0) {
- Instruction const* target = Instruction::At(code_item_->insns_ + dex_pc + branch_offset);
- switch (target->Opcode()) {
- default:
- may_have_loop = true;
- break;
- case Instruction::RETURN_VOID:
- case Instruction::RETURN:
- case Instruction::RETURN_WIDE:
- case Instruction::RETURN_OBJECT:
- break;
- }
+ if (branch_offset <= 0 && !IsInstructionDirectToReturn(dex_pc + branch_offset)) {
+ may_have_loop = true;
}
}
break;
@@ -4259,18 +4278,8 @@ void MethodCompiler::ComputeMethodInfo() {
case Instruction::IF_LEZ:
{
int32_t branch_offset = dec_insn.vB;
- if (branch_offset <= 0) {
- Instruction const* target = Instruction::At(code_item_->insns_ + dex_pc + branch_offset);
- switch (target->Opcode()) {
- default:
- may_have_loop = true;
- break;
- case Instruction::RETURN_VOID:
- case Instruction::RETURN:
- case Instruction::RETURN_WIDE:
- case Instruction::RETURN_OBJECT:
- break;
- }
+ if (branch_offset <= 0 && !IsInstructionDirectToReturn(dex_pc + branch_offset)) {
+ may_have_loop = true;
}
}
break;