From 526643e38c344701d96068f351548a393c67b6be Mon Sep 17 00:00:00 2001 From: TDYa127 Date: Sat, 26 May 2012 01:01:48 -0700 Subject: Remove unnecessary exception and suspend checks. 1. Post exception check, when 2 consecutive branches are return and exception unwind, respectively, merge these 2 branches as the caller doesn't care the return value when an exception is pending.. 2. If the method is leaf, we can elide the suspend check. 3. Also, move suspend checks to be before pushing shadow frame for the sake of "1" and for reducing code size (Multiple returns). Change-Id: I18f38f97f4e7714eadab4a1d6a568aa6e2c982ae --- src/compiler_llvm/method_compiler.cc | 167 ++++++++++++++++++----------------- 1 file changed, 88 insertions(+), 79 deletions(-) (limited to 'src/compiler_llvm/method_compiler.cc') 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 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& 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; -- cgit v1.2.3-59-g8ed1b