Remove unnecessary checks for small methods.
Remove unnecessary shadow frames, suspend checks, stack overflow checks,
null pointer checks for small methods.
Change-Id: I4e67e2d38a398ff62b84a74265efb26ce054fab3
diff --git a/src/compiler_llvm/method_compiler.cc b/src/compiler_llvm/method_compiler.cc
index 3f640ee..4070791 100644
--- a/src/compiler_llvm/method_compiler.cc
+++ b/src/compiler_llvm/method_compiler.cc
@@ -175,7 +175,9 @@
retval_reg_.reset(DalvikReg::CreateRetValReg(*this));
// Create Shadow Frame
- EmitPrologueAllocShadowFrame();
+ if (method_info_.need_shadow_frame) {
+ EmitPrologueAllocShadowFrame();
+ }
// Store argument to dalvik register
irb_.SetInsertPoint(basic_block_reg_arg_init_);
@@ -240,7 +242,13 @@
irb_.SetInsertPoint(basic_block_reg_alloca_);
irb_.CreateBr(basic_block_stack_overflow_);
- EmitStackOverflowCheck();
+ // 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 ||
+ code_item_->registers_size_ > 32) { // Small leaf function is OK given
+ // the 8KB reserved at Stack End
+ EmitStackOverflowCheck();
+ }
irb_.SetInsertPoint(basic_block_stack_overflow_);
irb_.CreateBr(basic_block_shadow_frame_alloca_);
@@ -1540,8 +1548,9 @@
llvm::Value* object_addr =
EmitLoadDalvikReg(dec_insn.vA, kObject, kAccurate);
- // TODO: Slow path always. May not need NullPointerException check.
- EmitGuard_NullPointerException(dex_pc, object_addr);
+ if (!(method_info_.this_will_not_be_null && dec_insn.vA == method_info_.this_reg_idx)) {
+ EmitGuard_NullPointerException(dex_pc, object_addr);
+ }
llvm::Value* thread_object_addr = irb_.CreateCall(irb_.GetRuntime(GetCurrentThread));
@@ -1559,7 +1568,9 @@
llvm::Value* object_addr =
EmitLoadDalvikReg(dec_insn.vA, kObject, kAccurate);
- EmitGuard_NullPointerException(dex_pc, object_addr);
+ if (!(method_info_.this_will_not_be_null && dec_insn.vA == method_info_.this_reg_idx)) {
+ EmitGuard_NullPointerException(dex_pc, object_addr);
+ }
EmitUpdateDexPC(dex_pc);
@@ -2335,7 +2346,9 @@
llvm::Value* object_addr = EmitLoadDalvikReg(reg_idx, kObject, kAccurate);
- EmitGuard_NullPointerException(dex_pc, object_addr);
+ if (!(method_info_.this_will_not_be_null && reg_idx == method_info_.this_reg_idx)) {
+ EmitGuard_NullPointerException(dex_pc, object_addr);
+ }
llvm::Value* field_value;
@@ -2399,7 +2412,9 @@
llvm::Value* object_addr = EmitLoadDalvikReg(reg_idx, kObject, kAccurate);
- EmitGuard_NullPointerException(dex_pc, object_addr);
+ if (!(method_info_.this_will_not_be_null && reg_idx == method_info_.this_reg_idx)) {
+ EmitGuard_NullPointerException(dex_pc, object_addr);
+ }
llvm::Value* new_value = EmitLoadDalvikReg(dec_insn.vA, field_jty, kField);
@@ -2747,11 +2762,12 @@
if (!is_static) {
// Test: Is *this* parameter equal to null?
- this_addr = (arg_fmt == kArgReg) ?
- EmitLoadDalvikReg(dec_insn.arg[0], kObject, kAccurate):
- EmitLoadDalvikReg(dec_insn.vC + 0, kObject, kAccurate);
+ uint32_t reg_idx = (arg_fmt == kArgReg) ? dec_insn.arg[0] : (dec_insn.vC + 0);
+ this_addr = EmitLoadDalvikReg(reg_idx, kObject, kAccurate);
- EmitGuard_NullPointerException(dex_pc, this_addr);
+ if (!(method_info_.this_will_not_be_null && reg_idx == method_info_.this_reg_idx)) {
+ EmitGuard_NullPointerException(dex_pc, this_addr);
+ }
}
// Load the method object
@@ -3601,6 +3617,10 @@
CompiledMethod *MethodCompiler::Compile() {
+ // TODO: Use high-level IR to do this
+ // Compute method info
+ ComputeMethodInfo();
+
// Code generation
CreateFunction();
@@ -3613,7 +3633,7 @@
// Add the memory usage approximation of the compilation unit
cunit_->AddMemUsageApproximation(code_item_->insns_size_in_code_units_ * 900);
- // NOTE: From statistic, the bitcode size is 4.5 times bigger than the
+ // NOTE: From statistics, the bitcode size is 4.5 times bigger than the
// Dex file. Besides, we have to convert the code unit into bytes.
// Thus, we got our magic number 9.
@@ -3659,6 +3679,10 @@
void MethodCompiler::EmitGuard_GarbageCollectionSuspend(uint32_t dex_pc) {
+ if (!method_info_.need_shadow_frame_entry) {
+ return;
+ }
+
llvm::Value* runtime_func = irb_.GetRuntime(TestSuspend);
llvm::Value* thread_object_addr = irb_.CreateCall(irb_.GetRuntime(GetCurrentThread));
@@ -3860,6 +3884,10 @@
return NULL;
}
+ if (!method_info_.need_shadow_frame_entry) {
+ return NULL;
+ }
+
std::string reg_name;
#if !defined(NDEBUG)
@@ -3912,11 +3940,17 @@
void MethodCompiler::EmitPopShadowFrame() {
+ if (!method_info_.need_shadow_frame) {
+ return;
+ }
irb_.CreateCall(irb_.GetRuntime(PopShadowFrame));
}
void MethodCompiler::EmitUpdateDexPC(uint32_t dex_pc) {
+ if (!method_info_.need_shadow_frame) {
+ return;
+ }
irb_.StoreToObjectOffset(shadow_frame_,
ShadowFrame::DexPCOffset(),
irb_.getInt32(dex_pc),
@@ -3924,5 +3958,536 @@
}
+// 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
+ // method is static or not in the following comparison.
+ int64_t this_reg_idx = (oat_compilation_unit_->IsStatic()) ?
+ (-1) :
+ (code_item_->registers_size_ - code_item_->ins_size_);
+ bool has_invoke = false;
+ bool may_have_loop = false;
+ bool modify_this = false;
+ bool may_throw_exception = false;
+
+ Instruction const* insn;
+ for (uint32_t dex_pc = 0;
+ dex_pc < code_item_->insns_size_in_code_units_;
+ dex_pc += insn->SizeInCodeUnits()) {
+ insn = Instruction::At(code_item_->insns_ + dex_pc);
+ DecodedInstruction dec_insn(insn);
+
+ switch (insn->Opcode()) {
+ case Instruction::NOP:
+ break;
+
+ case Instruction::MOVE:
+ case Instruction::MOVE_FROM16:
+ case Instruction::MOVE_16:
+ case Instruction::MOVE_WIDE:
+ case Instruction::MOVE_WIDE_FROM16:
+ case Instruction::MOVE_WIDE_16:
+ case Instruction::MOVE_OBJECT:
+ case Instruction::MOVE_OBJECT_FROM16:
+ case Instruction::MOVE_OBJECT_16:
+ case Instruction::MOVE_RESULT:
+ case Instruction::MOVE_RESULT_WIDE:
+ case Instruction::MOVE_RESULT_OBJECT:
+ case Instruction::MOVE_EXCEPTION:
+ if (dec_insn.vA == this_reg_idx) {
+ modify_this = true;
+ }
+ break;
+
+ case Instruction::RETURN_VOID:
+ case Instruction::RETURN:
+ case Instruction::RETURN_WIDE:
+ case Instruction::RETURN_OBJECT:
+ break;
+
+ case Instruction::CONST_4:
+ case Instruction::CONST_16:
+ case Instruction::CONST:
+ case Instruction::CONST_HIGH16:
+ case Instruction::CONST_WIDE_16:
+ case Instruction::CONST_WIDE_32:
+ case Instruction::CONST_WIDE:
+ case Instruction::CONST_WIDE_HIGH16:
+ if (dec_insn.vA == this_reg_idx) {
+ modify_this = true;
+ }
+ break;
+
+ case Instruction::CONST_STRING:
+ case Instruction::CONST_STRING_JUMBO:
+ // TODO: Will the ResolveString throw exception?
+ if (!compiler_->CanAssumeStringIsPresentInDexCache(dex_cache_, dec_insn.vB)) {
+ may_throw_exception = true;
+ }
+ if (dec_insn.vA == this_reg_idx) {
+ modify_this = true;
+ }
+ break;
+
+ case Instruction::CONST_CLASS:
+ may_throw_exception = true;
+ if (dec_insn.vA == this_reg_idx) {
+ modify_this = true;
+ }
+ break;
+
+ case Instruction::MONITOR_ENTER:
+ case Instruction::MONITOR_EXIT:
+ case Instruction::CHECK_CAST:
+ may_throw_exception = true;
+ break;
+
+ case Instruction::INSTANCE_OF:
+ may_throw_exception = true;
+ if (dec_insn.vA == this_reg_idx) {
+ modify_this = true;
+ }
+ break;
+
+ case Instruction::ARRAY_LENGTH:
+ if (dec_insn.vA == this_reg_idx) {
+ modify_this = true;
+ }
+ break;
+
+ case Instruction::NEW_INSTANCE:
+ case Instruction::NEW_ARRAY:
+ may_throw_exception = true;
+ if (dec_insn.vA == this_reg_idx) {
+ modify_this = true;
+ }
+ break;
+
+ case Instruction::FILLED_NEW_ARRAY:
+ case Instruction::FILLED_NEW_ARRAY_RANGE:
+ case Instruction::FILL_ARRAY_DATA:
+ case Instruction::THROW:
+ may_throw_exception = true;
+ break;
+
+ case Instruction::GOTO:
+ case Instruction::GOTO_16:
+ 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;
+ }
+ }
+ }
+ break;
+
+ case Instruction::PACKED_SWITCH:
+ case Instruction::SPARSE_SWITCH:
+ break;
+
+ case Instruction::CMPL_FLOAT:
+ case Instruction::CMPG_FLOAT:
+ case Instruction::CMPL_DOUBLE:
+ case Instruction::CMPG_DOUBLE:
+ case Instruction::CMP_LONG:
+ if (dec_insn.vA == this_reg_idx) {
+ modify_this = true;
+ }
+ break;
+
+ case Instruction::IF_EQ:
+ case Instruction::IF_NE:
+ case Instruction::IF_LT:
+ case Instruction::IF_GE:
+ case Instruction::IF_GT:
+ 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;
+ }
+ }
+ }
+ break;
+
+ case Instruction::IF_EQZ:
+ case Instruction::IF_NEZ:
+ case Instruction::IF_LTZ:
+ case Instruction::IF_GEZ:
+ case Instruction::IF_GTZ:
+ 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;
+ }
+ }
+ }
+ break;
+
+ case Instruction::AGET:
+ case Instruction::AGET_WIDE:
+ case Instruction::AGET_OBJECT:
+ case Instruction::AGET_BOOLEAN:
+ case Instruction::AGET_BYTE:
+ case Instruction::AGET_CHAR:
+ case Instruction::AGET_SHORT:
+ may_throw_exception = true;
+ if (dec_insn.vA == this_reg_idx) {
+ modify_this = true;
+ }
+ break;
+
+ case Instruction::APUT:
+ case Instruction::APUT_WIDE:
+ case Instruction::APUT_OBJECT:
+ case Instruction::APUT_BOOLEAN:
+ case Instruction::APUT_BYTE:
+ case Instruction::APUT_CHAR:
+ case Instruction::APUT_SHORT:
+ may_throw_exception = true;
+ break;
+
+ case Instruction::IGET:
+ case Instruction::IGET_WIDE:
+ case Instruction::IGET_OBJECT:
+ case Instruction::IGET_BOOLEAN:
+ case Instruction::IGET_BYTE:
+ case Instruction::IGET_CHAR:
+ case Instruction::IGET_SHORT:
+ {
+ if (dec_insn.vA == this_reg_idx) {
+ modify_this = true;
+ }
+ uint32_t reg_idx = dec_insn.vB;
+ uint32_t field_idx = dec_insn.vC;
+ int field_offset;
+ bool is_volatile;
+ bool is_fast_path = compiler_->ComputeInstanceFieldInfo(
+ field_idx, oat_compilation_unit_, field_offset, is_volatile, false);
+ if (!is_fast_path) {
+ may_throw_exception = true;
+ } else if (reg_idx != this_reg_idx) {
+ // NullPointerException
+ may_throw_exception = true;
+ }
+ }
+ break;
+
+ case Instruction::IPUT:
+ case Instruction::IPUT_WIDE:
+ case Instruction::IPUT_OBJECT:
+ case Instruction::IPUT_BOOLEAN:
+ case Instruction::IPUT_BYTE:
+ case Instruction::IPUT_CHAR:
+ case Instruction::IPUT_SHORT:
+ {
+ uint32_t reg_idx = dec_insn.vB;
+ uint32_t field_idx = dec_insn.vC;
+ int field_offset;
+ bool is_volatile;
+ bool is_fast_path = compiler_->ComputeInstanceFieldInfo(
+ field_idx, oat_compilation_unit_, field_offset, is_volatile, true);
+ if (!is_fast_path) {
+ may_throw_exception = true;
+ } else if (reg_idx != this_reg_idx) {
+ // NullPointerException
+ may_throw_exception = true;
+ }
+ }
+ break;
+
+ case Instruction::SGET:
+ case Instruction::SGET_WIDE:
+ case Instruction::SGET_OBJECT:
+ case Instruction::SGET_BOOLEAN:
+ case Instruction::SGET_BYTE:
+ case Instruction::SGET_CHAR:
+ case Instruction::SGET_SHORT:
+ {
+ if (dec_insn.vA == this_reg_idx) {
+ modify_this = true;
+ }
+ uint32_t field_idx = dec_insn.vB;
+
+ int field_offset;
+ int ssb_index;
+ bool is_referrers_class;
+ bool is_volatile;
+
+ bool is_fast_path = compiler_->ComputeStaticFieldInfo(
+ field_idx, oat_compilation_unit_, field_offset, ssb_index,
+ is_referrers_class, is_volatile, false);
+ if (!is_fast_path || !is_referrers_class) {
+ may_throw_exception = true;
+ }
+ }
+ break;
+
+ case Instruction::SPUT:
+ case Instruction::SPUT_WIDE:
+ case Instruction::SPUT_OBJECT:
+ case Instruction::SPUT_BOOLEAN:
+ case Instruction::SPUT_BYTE:
+ case Instruction::SPUT_CHAR:
+ case Instruction::SPUT_SHORT:
+ {
+ uint32_t field_idx = dec_insn.vB;
+
+ int field_offset;
+ int ssb_index;
+ bool is_referrers_class;
+ bool is_volatile;
+
+ bool is_fast_path = compiler_->ComputeStaticFieldInfo(
+ field_idx, oat_compilation_unit_, field_offset, ssb_index,
+ is_referrers_class, is_volatile, true);
+ if (!is_fast_path || !is_referrers_class) {
+ may_throw_exception = true;
+ }
+ }
+ break;
+
+
+ case Instruction::INVOKE_VIRTUAL:
+ case Instruction::INVOKE_SUPER:
+ case Instruction::INVOKE_DIRECT:
+ case Instruction::INVOKE_STATIC:
+ case Instruction::INVOKE_INTERFACE:
+ case Instruction::INVOKE_VIRTUAL_RANGE:
+ case Instruction::INVOKE_SUPER_RANGE:
+ case Instruction::INVOKE_DIRECT_RANGE:
+ case Instruction::INVOKE_STATIC_RANGE:
+ case Instruction::INVOKE_INTERFACE_RANGE:
+ has_invoke = true;
+ may_throw_exception = true;
+ break;
+
+ case Instruction::NEG_INT:
+ case Instruction::NOT_INT:
+ case Instruction::NEG_LONG:
+ case Instruction::NOT_LONG:
+ case Instruction::NEG_FLOAT:
+ case Instruction::NEG_DOUBLE:
+ case Instruction::INT_TO_LONG:
+ case Instruction::INT_TO_FLOAT:
+ case Instruction::INT_TO_DOUBLE:
+ case Instruction::LONG_TO_INT:
+ case Instruction::LONG_TO_FLOAT:
+ case Instruction::LONG_TO_DOUBLE:
+ case Instruction::FLOAT_TO_INT:
+ case Instruction::FLOAT_TO_LONG:
+ case Instruction::FLOAT_TO_DOUBLE:
+ case Instruction::DOUBLE_TO_INT:
+ case Instruction::DOUBLE_TO_LONG:
+ case Instruction::DOUBLE_TO_FLOAT:
+ case Instruction::INT_TO_BYTE:
+ case Instruction::INT_TO_CHAR:
+ case Instruction::INT_TO_SHORT:
+ case Instruction::ADD_INT:
+ case Instruction::SUB_INT:
+ case Instruction::MUL_INT:
+ case Instruction::AND_INT:
+ case Instruction::OR_INT:
+ case Instruction::XOR_INT:
+ case Instruction::SHL_INT:
+ case Instruction::SHR_INT:
+ case Instruction::USHR_INT:
+ case Instruction::ADD_LONG:
+ case Instruction::SUB_LONG:
+ case Instruction::MUL_LONG:
+ case Instruction::AND_LONG:
+ case Instruction::OR_LONG:
+ case Instruction::XOR_LONG:
+ case Instruction::SHL_LONG:
+ case Instruction::SHR_LONG:
+ case Instruction::USHR_LONG:
+ case Instruction::ADD_INT_2ADDR:
+ case Instruction::SUB_INT_2ADDR:
+ case Instruction::MUL_INT_2ADDR:
+ case Instruction::AND_INT_2ADDR:
+ case Instruction::OR_INT_2ADDR:
+ case Instruction::XOR_INT_2ADDR:
+ case Instruction::SHL_INT_2ADDR:
+ case Instruction::SHR_INT_2ADDR:
+ case Instruction::USHR_INT_2ADDR:
+ case Instruction::ADD_LONG_2ADDR:
+ case Instruction::SUB_LONG_2ADDR:
+ case Instruction::MUL_LONG_2ADDR:
+ case Instruction::AND_LONG_2ADDR:
+ case Instruction::OR_LONG_2ADDR:
+ case Instruction::XOR_LONG_2ADDR:
+ case Instruction::SHL_LONG_2ADDR:
+ case Instruction::SHR_LONG_2ADDR:
+ case Instruction::USHR_LONG_2ADDR:
+ if (dec_insn.vA == this_reg_idx) {
+ modify_this = true;
+ }
+ break;
+
+ case Instruction::DIV_INT:
+ case Instruction::REM_INT:
+ case Instruction::DIV_LONG:
+ case Instruction::REM_LONG:
+ case Instruction::DIV_INT_2ADDR:
+ case Instruction::REM_INT_2ADDR:
+ case Instruction::DIV_LONG_2ADDR:
+ case Instruction::REM_LONG_2ADDR:
+ may_throw_exception = true;
+ if (dec_insn.vA == this_reg_idx) {
+ modify_this = true;
+ }
+ break;
+
+ case Instruction::ADD_FLOAT:
+ case Instruction::SUB_FLOAT:
+ case Instruction::MUL_FLOAT:
+ case Instruction::DIV_FLOAT:
+ case Instruction::REM_FLOAT:
+ case Instruction::ADD_DOUBLE:
+ case Instruction::SUB_DOUBLE:
+ case Instruction::MUL_DOUBLE:
+ case Instruction::DIV_DOUBLE:
+ case Instruction::REM_DOUBLE:
+ case Instruction::ADD_FLOAT_2ADDR:
+ case Instruction::SUB_FLOAT_2ADDR:
+ case Instruction::MUL_FLOAT_2ADDR:
+ case Instruction::DIV_FLOAT_2ADDR:
+ case Instruction::REM_FLOAT_2ADDR:
+ case Instruction::ADD_DOUBLE_2ADDR:
+ case Instruction::SUB_DOUBLE_2ADDR:
+ case Instruction::MUL_DOUBLE_2ADDR:
+ case Instruction::DIV_DOUBLE_2ADDR:
+ case Instruction::REM_DOUBLE_2ADDR:
+ if (dec_insn.vA == this_reg_idx) {
+ modify_this = true;
+ }
+ break;
+
+ case Instruction::ADD_INT_LIT16:
+ case Instruction::ADD_INT_LIT8:
+ case Instruction::RSUB_INT:
+ case Instruction::RSUB_INT_LIT8:
+ case Instruction::MUL_INT_LIT16:
+ case Instruction::MUL_INT_LIT8:
+ case Instruction::AND_INT_LIT16:
+ case Instruction::AND_INT_LIT8:
+ case Instruction::OR_INT_LIT16:
+ case Instruction::OR_INT_LIT8:
+ case Instruction::XOR_INT_LIT16:
+ case Instruction::XOR_INT_LIT8:
+ case Instruction::SHL_INT_LIT8:
+ case Instruction::SHR_INT_LIT8:
+ case Instruction::USHR_INT_LIT8:
+ if (dec_insn.vA == this_reg_idx) {
+ modify_this = true;
+ }
+ break;
+ case Instruction::DIV_INT_LIT16:
+ case Instruction::DIV_INT_LIT8:
+ case Instruction::REM_INT_LIT16:
+ case Instruction::REM_INT_LIT8:
+ if (dec_insn.vC == 0) {
+ may_throw_exception = true;
+ }
+ if (dec_insn.vA == this_reg_idx) {
+ modify_this = true;
+ }
+ break;
+
+ case Instruction::THROW_VERIFICATION_ERROR:
+ may_throw_exception = true;
+ break;
+
+ case Instruction::UNUSED_3E:
+ case Instruction::UNUSED_3F:
+ case Instruction::UNUSED_40:
+ case Instruction::UNUSED_41:
+ case Instruction::UNUSED_42:
+ case Instruction::UNUSED_43:
+ case Instruction::UNUSED_73:
+ case Instruction::UNUSED_79:
+ case Instruction::UNUSED_7A:
+ case Instruction::UNUSED_E3:
+ case Instruction::UNUSED_E4:
+ case Instruction::UNUSED_E5:
+ case Instruction::UNUSED_E6:
+ case Instruction::UNUSED_E7:
+ case Instruction::UNUSED_E8:
+ case Instruction::UNUSED_E9:
+ case Instruction::UNUSED_EA:
+ case Instruction::UNUSED_EB:
+ case Instruction::UNUSED_EC:
+ case Instruction::UNUSED_EE:
+ case Instruction::UNUSED_EF:
+ case Instruction::UNUSED_F0:
+ case Instruction::UNUSED_F1:
+ case Instruction::UNUSED_F2:
+ case Instruction::UNUSED_F3:
+ case Instruction::UNUSED_F4:
+ case Instruction::UNUSED_F5:
+ case Instruction::UNUSED_F6:
+ case Instruction::UNUSED_F7:
+ case Instruction::UNUSED_F8:
+ case Instruction::UNUSED_F9:
+ case Instruction::UNUSED_FA:
+ case Instruction::UNUSED_FB:
+ case Instruction::UNUSED_FC:
+ case Instruction::UNUSED_FD:
+ case Instruction::UNUSED_FE:
+ case Instruction::UNUSED_FF:
+ LOG(FATAL) << "Dex file contains UNUSED bytecode: " << insn->Opcode();
+ break;
+ }
+ }
+
+ method_info_.this_reg_idx = this_reg_idx;
+ // According to the statistics, there are few methods that modify the "this" pointer. So this is a
+ // simple way to avoid data flow analysis. After we have a high-level IR before IRBuilder, we
+ // should remove this trick.
+ method_info_.this_will_not_be_null = !modify_this;
+ method_info_.has_invoke = has_invoke;
+ // If this method has loop or invoke instruction, it may suspend. Thus we need a shadow frame entry
+ // for GC.
+ method_info_.need_shadow_frame_entry = has_invoke || may_have_loop;
+ // If this method may throw an exception, we need a shadow frame for stack trace (dexpc).
+ method_info_.need_shadow_frame = method_info_.need_shadow_frame_entry || may_throw_exception;
+}
+
+
+
} // namespace compiler_llvm
} // namespace art
diff --git a/src/compiler_llvm/method_compiler.h b/src/compiler_llvm/method_compiler.h
index e815e3b..598a337 100644
--- a/src/compiler_llvm/method_compiler.h
+++ b/src/compiler_llvm/method_compiler.h
@@ -434,6 +434,18 @@
EmitStoreDalvikRetValReg(GetJTypeFromShorty(shorty), space, new_value);
}
+ // TODO: Use high-level IR to do this
+
+ struct MethodInfo {
+ int64_t this_reg_idx;
+ bool this_will_not_be_null;
+ bool has_invoke;
+ bool need_shadow_frame_entry;
+ bool need_shadow_frame;
+ };
+ MethodInfo method_info_;
+
+ void ComputeMethodInfo();
private:
CompilationUnit* cunit_;