Merge "Make the epoch-related "can't happen" situation easier to spot." into ics-mr1-plus-art
diff --git a/Android.mk b/Android.mk
index cd96c52..6eb4299 100644
--- a/Android.mk
+++ b/Android.mk
@@ -76,7 +76,7 @@
@echo test-art-gtest PASSED
.PHONY: test-art-oat
-test-art-oat: test-art-target-oat # test-art-host-oat
+test-art-oat: test-art-target-oat test-art-host-oat
@echo test-art-oat PASSED
########################################################################
@@ -84,7 +84,7 @@
# "mm test-art-host" to build and run all host tests
.PHONY: test-art-host
-test-art-host: test-art-host-gtest # test-art-host-oat # test-art-host-run-test
+test-art-host: test-art-host-gtest test-art-host-oat # test-art-host-run-test
@echo test-art-host PASSED
.PHONY: test-art-host-dependencies
@@ -243,6 +243,8 @@
rm -f $(TARGET_OUT_JAVA_LIBRARIES)/*.oat
rm -f $(TARGET_OUT_JAVA_LIBRARIES)/*.art
rm -f $(TARGET_OUT_APPS)/*.oat
+ rm -f $(TARGET_OUT_INTERMEDIATES)/JAVA_LIBRARIES/*_intermediates/javalib.jar.oat
+ rm -f $(TARGET_OUT_INTERMEDIATES)/APPS/*_intermediates/package.apk.oat
adb remount
adb shell rm $(ART_NATIVETEST_DIR)/*.oat
adb shell rm $(ART_NATIVETEST_DIR)/*.art
diff --git a/src/compiler/codegen/GenCommon.cc b/src/compiler/codegen/GenCommon.cc
index 14eaf1d..c9ba285 100644
--- a/src/compiler/codegen/GenCommon.cc
+++ b/src/compiler/codegen/GenCommon.cc
@@ -1060,7 +1060,7 @@
if (isVolatile) {
oatGenMemBarrier(cUnit, kST);
}
- storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
+ storeBaseDispWide(cUnit, regPtr, 0, rlSrc.lowReg, rlSrc.highReg);
if (isVolatile) {
oatGenMemBarrier(cUnit, kSY);
}
@@ -1642,7 +1642,7 @@
oatFreeTemp(cUnit, regLen);
}
- storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
+ storeBaseDispWide(cUnit, regPtr, 0, rlSrc.lowReg, rlSrc.highReg);
oatFreeTemp(cUnit, regPtr);
} else {
diff --git a/src/compiler/codegen/MethodCodegenDriver.cc b/src/compiler/codegen/MethodCodegenDriver.cc
index b75b9a8..01ac436 100644
--- a/src/compiler/codegen/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/MethodCodegenDriver.cc
@@ -225,9 +225,9 @@
loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
loadConstant(cUnit, resetReg, 0);
storeWordDisp(cUnit, rSELF, exOffset, resetReg);
- storeValue(cUnit, rlDest, rlResult);
oatFreeTemp(cUnit, resetReg);
#endif
+ storeValue(cUnit, rlDest, rlResult);
break;
}
case Instruction::RETURN_VOID:
diff --git a/src/compiler/codegen/arm/Thumb2/Factory.cc b/src/compiler/codegen/arm/Thumb2/Factory.cc
index 533f8b4..67f7938 100644
--- a/src/compiler/codegen/arm/Thumb2/Factory.cc
+++ b/src/compiler/codegen/arm/Thumb2/Factory.cc
@@ -1009,11 +1009,6 @@
return storeBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong);
}
-void storePair(CompilationUnit* cUnit, int base, int lowReg, int highReg)
-{
- storeBaseDispWide(cUnit, base, 0, lowReg, highReg);
-}
-
void loadPair(CompilationUnit* cUnit, int base, int lowReg, int highReg)
{
loadBaseDispWide(cUnit, NULL, base, 0, lowReg, highReg, INVALID_SREG);
diff --git a/src/compiler/codegen/mips/Mips32/Factory.cc b/src/compiler/codegen/mips/Mips32/Factory.cc
index 0a7dd9d..8b6f185 100644
--- a/src/compiler/codegen/mips/Mips32/Factory.cc
+++ b/src/compiler/codegen/mips/Mips32/Factory.cc
@@ -40,8 +40,6 @@
#endif
void genBarrier(CompilationUnit *cUnit);
-void storePair(CompilationUnit *cUnit, int base, int lowReg,
- int highReg);
void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg);
LIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
int rDest);
@@ -742,12 +740,6 @@
return storeBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong);
}
-void storePair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
-{
- storeWordDisp(cUnit, base, LOWORD_OFFSET, lowReg);
- storeWordDisp(cUnit, base, HIWORD_OFFSET, highReg);
-}
-
void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
{
loadWordDisp(cUnit, base, LOWORD_OFFSET , lowReg);
diff --git a/src/compiler/codegen/x86/FP/X86FP.cc b/src/compiler/codegen/x86/FP/X86FP.cc
index 7c27eae..24cd7d3 100644
--- a/src/compiler/codegen/x86/FP/X86FP.cc
+++ b/src/compiler/codegen/x86/FP/X86FP.cc
@@ -124,7 +124,9 @@
RegLocation rlDest;
X86OpCode op = kX86Nop;
int srcReg;
+ int tempReg;
RegLocation rlResult;
+ LIR* branch = NULL;
switch (opcode) {
case Instruction::INT_TO_FLOAT:
longSrc = false;
@@ -151,14 +153,45 @@
op = kX86Cvtsi2sdRR;
break;
case Instruction::FLOAT_TO_INT:
+ rlSrc = oatGetSrc(cUnit, mir, 0);
+ rlSrc = loadValue(cUnit, rlSrc, kFPReg);
+ srcReg = rlSrc.lowReg;
+ rlDest = oatGetDest(cUnit, mir, 0);
+ oatClobberSReg(cUnit, rlDest.sRegLow);
+ rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+ tempReg = oatAllocTempFloat(cUnit);
+
+ loadConstant(cUnit, rlResult.lowReg, 0x7fffffff);
+ newLIR2(cUnit, kX86Cvtsi2ssRR, tempReg, rlResult.lowReg);
+ newLIR2(cUnit, kX86ComissRR, srcReg, tempReg);
+ branch = newLIR2(cUnit, kX86Jcc8, 0, kX86CondA);
+ newLIR2(cUnit, kX86Cvtss2siRR, rlResult.lowReg, srcReg);
+ branch->target = newLIR0(cUnit, kPseudoTargetLabel);
+ storeValue(cUnit, rlDest, rlResult);
+ return false;
case Instruction::DOUBLE_TO_INT:
- // These are easy to implement inline except when the src is > MAX_INT/LONG the result
- // needs to be changed from 0x80000000 to 0x7FFFFFF (requires an in memory float/double
- // literal constant to compare against).
- UNIMPLEMENTED(WARNING) << "inline [df]2i " << PrettyMethod(cUnit->method_idx, *cUnit->dex_file);
+ rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
+ rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
+ srcReg = rlSrc.lowReg;
+ rlDest = oatGetDest(cUnit, mir, 0);
+ oatClobberSReg(cUnit, rlDest.sRegLow);
+ rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+ tempReg = oatAllocTempDouble(cUnit);
+
+ loadConstant(cUnit, rlResult.lowReg, 0x7fffffff);
+ newLIR2(cUnit, kX86Cvtsi2sdRR, tempReg, rlResult.lowReg);
+ newLIR2(cUnit, kX86ComisdRR, srcReg, tempReg);
+ branch = newLIR2(cUnit, kX86Jcc8, 0, kX86CondA);
+ newLIR2(cUnit, kX86Cvtsd2siRR, rlResult.lowReg, srcReg);
+ branch->target = newLIR0(cUnit, kPseudoTargetLabel);
+ storeValue(cUnit, rlDest, rlResult);
+ return false;
case Instruction::LONG_TO_DOUBLE:
- case Instruction::FLOAT_TO_LONG:
case Instruction::LONG_TO_FLOAT:
+ // These can be implemented inline by using memory as a 64-bit source.
+ // However, this can't be done easily if the register has been promoted.
+ UNIMPLEMENTED(WARNING) << "inline l2[df] " << PrettyMethod(cUnit->method_idx, *cUnit->dex_file);
+ case Instruction::FLOAT_TO_LONG:
case Instruction::DOUBLE_TO_LONG:
return genConversionPortable(cUnit, mir);
default:
@@ -205,6 +238,7 @@
rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
srcReg2 = S2D(rlSrc2.lowReg, rlSrc2.highReg);
}
+ oatClobberSReg(cUnit, rlDest.sRegLow);
RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
loadConstantNoClobber(cUnit, rlResult.lowReg, unorderedGt ? 1 : 0);
if (single) {
diff --git a/src/compiler/codegen/x86/X86/Factory.cc b/src/compiler/codegen/x86/X86/Factory.cc
index c3fb6a6..3698d2d 100644
--- a/src/compiler/codegen/x86/X86/Factory.cc
+++ b/src/compiler/codegen/x86/X86/Factory.cc
@@ -47,8 +47,6 @@
};
void genBarrier(CompilationUnit *cUnit);
-void storePair(CompilationUnit *cUnit, int base, int lowReg,
- int highReg);
void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg);
LIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
int rDest);
@@ -676,12 +674,6 @@
rSrcLo, rSrcHi, kLong, INVALID_SREG);
}
-void storePair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
-{
- storeWordDisp(cUnit, base, 0, lowReg);
- storeWordDisp(cUnit, base, 4, highReg);
-}
-
void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
{
loadWordDisp(cUnit, base, 0, lowReg);
diff --git a/src/compiler_llvm/art_module.ll b/src/compiler_llvm/art_module.ll
index a2da2b6..caef683 100644
--- a/src/compiler_llvm/art_module.ll
+++ b/src/compiler_llvm/art_module.ll
@@ -160,10 +160,10 @@
; Math
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-declare i64 @D2L(double)
-declare i32 @D2I(double)
-declare i64 @F2L(float)
-declare i32 @F2I(float)
+declare i64 @art_d2l(double)
+declare i32 @art_d2i(double)
+declare i64 @art_f2l(float)
+declare i32 @art_f2i(float)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Temporary runtime support, will be removed in the future
diff --git a/src/compiler_llvm/compilation_unit.cc b/src/compiler_llvm/compilation_unit.cc
index fbd2f05..598a8b3 100644
--- a/src/compiler_llvm/compilation_unit.cc
+++ b/src/compiler_llvm/compilation_unit.cc
@@ -141,7 +141,8 @@
irb_->SetInsertPoint(bb->getTerminator());
- using namespace art::compiler_llvm::runtime_support;
+ using art::compiler_llvm::runtime_support::TestSuspend;
+ using art::compiler_llvm::runtime_support::GetCurrentThread;
llvm::Value* runtime_func = irb_->GetRuntime(TestSuspend);
llvm::Value* thread_object_addr = irb_->CreateCall(irb_->GetRuntime(GetCurrentThread));
irb_->CreateCall(runtime_func, thread_object_addr);
@@ -207,7 +208,7 @@
if (thread_count == 1) {
llvm::raw_string_ostream str_os(elf_image_);
- bool success = MaterializeToFile(str_os, insn_set_);
+ bool success = MaterializeToFile(str_os);
LOG(INFO) << "Compilation Unit: " << elf_idx_ << (success ? " (done)" : " (failed)");
// Free the resources
@@ -244,7 +245,7 @@
// TODO: Should use exec* family instead of invoking a function.
// Forward our compilation request to bcc.
- exit(static_cast<int>(!MaterializeToFile(fd_os, insn_set_)));
+ exit(static_cast<int>(!MaterializeToFile(fd_os)));
} else { // Parent process
// Close the unused pipe write end
@@ -325,19 +326,12 @@
}
}
-bool CompilationUnit::MaterializeToFile(llvm::raw_ostream& out_stream,
- InstructionSet insn_set) {
- // Initialize the LLVM first
- llvm::InitializeAllTargets();
- llvm::InitializeAllTargetMCs();
- llvm::InitializeAllAsmPrinters();
- llvm::InitializeAllAsmParsers();
-
+bool CompilationUnit::MaterializeToFile(llvm::raw_ostream& out_stream) {
// Lookup the LLVM target
char const* target_triple = NULL;
char const* target_attr = NULL;
- switch (insn_set) {
+ switch (insn_set_) {
case kThumb2:
target_triple = "thumb-none-linux-gnueabi";
target_attr = "+thumb2,+neon,+neonfp,+vfp3";
@@ -360,7 +354,7 @@
break;
default:
- LOG(FATAL) << "Unknown instruction set: " << insn_set;
+ LOG(FATAL) << "Unknown instruction set: " << insn_set_;
}
std::string errmsg;
@@ -437,8 +431,9 @@
pm_builder.OptLevel = 3;
pm_builder.DisableSimplifyLibCalls = 1;
pm_builder.DisableUnitAtATime = 1;
- pm_builder.populateModulePassManager(pm);
pm_builder.populateFunctionPassManager(fpm);
+ pm_builder.populateModulePassManager(pm);
+ pm.add(llvm::createStripDeadPrototypesPass());
// Add passes to emit ELF image
{
diff --git a/src/compiler_llvm/compilation_unit.h b/src/compiler_llvm/compilation_unit.h
index 40a4c73..52e4ae6 100644
--- a/src/compiler_llvm/compilation_unit.h
+++ b/src/compiler_llvm/compilation_unit.h
@@ -133,8 +133,7 @@
size_t mem_usage_;
uint16_t num_elf_funcs_;
- bool MaterializeToFile(llvm::raw_ostream& out_stream,
- InstructionSet insn_set);
+ bool MaterializeToFile(llvm::raw_ostream& out_stream);
};
} // namespace compiler_llvm
diff --git a/src/compiler_llvm/compiler_llvm.cc b/src/compiler_llvm/compiler_llvm.cc
index dce7f91..b517d47 100644
--- a/src/compiler_llvm/compiler_llvm.cc
+++ b/src/compiler_llvm/compiler_llvm.cc
@@ -55,12 +55,18 @@
pthread_once_t llvm_initialized = PTHREAD_ONCE_INIT;
void InitializeLLVM() {
+ // Initialize LLVM internal data structure for multithreading
+ llvm::llvm_start_multithreaded();
+
// NOTE: Uncomment following line to show the time consumption of LLVM passes
//llvm::TimePassesIsEnabled = true;
// Enable -arm-reserve-r9
ReserveR9 = true;
+ // Enable -arm-long-calls
+ EnableARMLongCalls = false;
+
// Initialize LLVM target, MC subsystem, asm printer, and asm parser
llvm::InitializeAllTargets();
llvm::InitializeAllTargetMCs();
@@ -68,9 +74,6 @@
llvm::InitializeAllAsmParsers();
// TODO: Maybe we don't have to initialize "all" targets.
- // Enable -arm-long-calls
- EnableARMLongCalls = false;
-
// Initialize LLVM optimization passes
llvm::PassRegistry ®istry = *llvm::PassRegistry::getPassRegistry();
@@ -83,9 +86,6 @@
llvm::initializeInstCombine(registry);
llvm::initializeInstrumentation(registry);
llvm::initializeTarget(registry);
-
- // Initialize LLVM internal data structure for multithreading
- llvm::llvm_start_multithreaded();
}
// The Guard to Shutdown LLVM
diff --git a/src/compiler_llvm/generated/art_module.cc b/src/compiler_llvm/generated/art_module.cc
index b3963ef..cd93542 100644
--- a/src/compiler_llvm/generated/art_module.cc
+++ b/src/compiler_llvm/generated/art_module.cc
@@ -911,49 +911,49 @@
AttrListPtr func_art_check_put_array_element_from_code_PAL;
func_art_check_put_array_element_from_code->setAttributes(func_art_check_put_array_element_from_code_PAL);
-Function* func_D2L = mod->getFunction("D2L");
-if (!func_D2L) {
-func_D2L = Function::Create(
+Function* func_art_d2l = mod->getFunction("art_d2l");
+if (!func_art_d2l) {
+func_art_d2l = Function::Create(
/*Type=*/FuncTy_31,
/*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"D2L", mod); // (external, no body)
-func_D2L->setCallingConv(CallingConv::C);
+ /*Name=*/"art_d2l", mod); // (external, no body)
+func_art_d2l->setCallingConv(CallingConv::C);
}
-AttrListPtr func_D2L_PAL;
-func_D2L->setAttributes(func_D2L_PAL);
+AttrListPtr func_art_d2l_PAL;
+func_art_d2l->setAttributes(func_art_d2l_PAL);
-Function* func_D2I = mod->getFunction("D2I");
-if (!func_D2I) {
-func_D2I = Function::Create(
+Function* func_art_d2i = mod->getFunction("art_d2i");
+if (!func_art_d2i) {
+func_art_d2i = Function::Create(
/*Type=*/FuncTy_32,
/*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"D2I", mod); // (external, no body)
-func_D2I->setCallingConv(CallingConv::C);
+ /*Name=*/"art_d2i", mod); // (external, no body)
+func_art_d2i->setCallingConv(CallingConv::C);
}
-AttrListPtr func_D2I_PAL;
-func_D2I->setAttributes(func_D2I_PAL);
+AttrListPtr func_art_d2i_PAL;
+func_art_d2i->setAttributes(func_art_d2i_PAL);
-Function* func_F2L = mod->getFunction("F2L");
-if (!func_F2L) {
-func_F2L = Function::Create(
+Function* func_art_f2l = mod->getFunction("art_f2l");
+if (!func_art_f2l) {
+func_art_f2l = Function::Create(
/*Type=*/FuncTy_33,
/*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"F2L", mod); // (external, no body)
-func_F2L->setCallingConv(CallingConv::C);
+ /*Name=*/"art_f2l", mod); // (external, no body)
+func_art_f2l->setCallingConv(CallingConv::C);
}
-AttrListPtr func_F2L_PAL;
-func_F2L->setAttributes(func_F2L_PAL);
+AttrListPtr func_art_f2l_PAL;
+func_art_f2l->setAttributes(func_art_f2l_PAL);
-Function* func_F2I = mod->getFunction("F2I");
-if (!func_F2I) {
-func_F2I = Function::Create(
+Function* func_art_f2i = mod->getFunction("art_f2i");
+if (!func_art_f2i) {
+func_art_f2i = Function::Create(
/*Type=*/FuncTy_34,
/*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"F2I", mod); // (external, no body)
-func_F2I->setCallingConv(CallingConv::C);
+ /*Name=*/"art_f2i", mod); // (external, no body)
+func_art_f2i->setCallingConv(CallingConv::C);
}
-AttrListPtr func_F2I_PAL;
-func_F2I->setAttributes(func_F2I_PAL);
+AttrListPtr func_art_f2i_PAL;
+func_art_f2i->setAttributes(func_art_f2i_PAL);
Function* func_art_mark_gc_card_from_code = mod->getFunction("art_mark_gc_card_from_code");
if (!func_art_mark_gc_card_from_code) {
diff --git a/src/compiler_llvm/ir_builder.h b/src/compiler_llvm/ir_builder.h
index aa261c3..24a594d 100644
--- a/src/compiler_llvm/ir_builder.h
+++ b/src/compiler_llvm/ir_builder.h
@@ -120,7 +120,7 @@
llvm::BasicBlock* true_bb,
llvm::BasicBlock* false_bb,
ExpectCond expect) {
- DCHECK_NE(expect, MAX_EXPECT) << "MAX_EXPECT is not for branch weight";
+ DCHECK_LT(expect, MAX_EXPECT) << "MAX_EXPECT is not for branch weight";
llvm::BranchInst* branch_inst = LLVMIRBuilder::CreateCondBr(cond, true_bb, false_bb);
branch_inst->setMetadata(llvm::LLVMContext::MD_prof, expect_cond_[expect]);
diff --git a/src/compiler_llvm/method_compiler.cc b/src/compiler_llvm/method_compiler.cc
index 3f3e0ad..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_);
@@ -801,11 +809,11 @@
break;
case Instruction::FLOAT_TO_INT:
- EmitInsn_FPToInt(ARGS, kFloat, kInt, F2I);
+ EmitInsn_FPToInt(ARGS, kFloat, kInt, art_f2i);
break;
case Instruction::FLOAT_TO_LONG:
- EmitInsn_FPToInt(ARGS, kFloat, kLong, F2L);
+ EmitInsn_FPToInt(ARGS, kFloat, kLong, art_f2l);
break;
case Instruction::FLOAT_TO_DOUBLE:
@@ -813,11 +821,11 @@
break;
case Instruction::DOUBLE_TO_INT:
- EmitInsn_FPToInt(ARGS, kDouble, kInt, D2I);
+ EmitInsn_FPToInt(ARGS, kDouble, kInt, art_d2i);
break;
case Instruction::DOUBLE_TO_LONG:
- EmitInsn_FPToInt(ARGS, kDouble, kLong, D2L);
+ EmitInsn_FPToInt(ARGS, kDouble, kLong, art_d2l);
break;
case Instruction::DOUBLE_TO_FLOAT:
@@ -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_;
diff --git a/src/compiler_llvm/runtime_support_func_list.h b/src/compiler_llvm/runtime_support_func_list.h
index 5cf2374..62729c6 100644
--- a/src/compiler_llvm/runtime_support_func_list.h
+++ b/src/compiler_llvm/runtime_support_func_list.h
@@ -66,7 +66,7 @@
V(FixStub, art_fix_stub_from_code) \
V(ProxyInvokeHandler, art_proxy_invoke_handler_from_code) \
V(DecodeJObjectInThread, art_decode_jobject_in_thread) \
- V(D2L, D2L) \
- V(D2I, D2I) \
- V(F2L, F2L) \
- V(F2I, F2I)
+ V(art_d2l, art_d2l) \
+ V(art_d2i, art_d2i) \
+ V(art_f2l, art_f2l) \
+ V(art_f2i, art_f2i)
diff --git a/src/compiler_llvm/runtime_support_llvm.cc b/src/compiler_llvm/runtime_support_llvm.cc
index b0d59ea..a31c27e 100644
--- a/src/compiler_llvm/runtime_support_llvm.cc
+++ b/src/compiler_llvm/runtime_support_llvm.cc
@@ -595,7 +595,7 @@
#undef EXTERNAL_LINKAGE
static void* art_find_compiler_runtime_func(char const* name) {
-// TODO: If target support some math func, use the target's version. (e.g. D2I -> __aeabi_d2iz)
+// TODO: If target support some math func, use the target's version. (e.g. art_d2i -> __aeabi_d2iz)
static const char* const names[] = {
#define DEFINE_ENTRY(NAME) #NAME ,
#include "compiler_runtime_func_list.h"
diff --git a/src/oat/runtime/arm/oat_support_entrypoints_arm.cc b/src/oat/runtime/arm/oat_support_entrypoints_arm.cc
index be390e9..d26a11d 100644
--- a/src/oat/runtime/arm/oat_support_entrypoints_arm.cc
+++ b/src/oat/runtime/arm/oat_support_entrypoints_arm.cc
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "runtime_support.h"
#include "oat/runtime/oat_support_entrypoints.h"
namespace art {
@@ -81,8 +82,6 @@
extern "C" int32_t __aeabi_d2iz(double op1); // DOUBLE_TO_INT
extern "C" float __aeabi_l2f(int64_t op1); // LONG_TO_FLOAT
extern "C" double __aeabi_l2d(int64_t op1); // LONG_TO_DOUBLE
-extern int64_t D2L(double d);
-extern int64_t F2L(float f);
// Single-precision FP arithmetics.
extern "C" float __aeabi_fadd(float a, float b); // ADD_FLOAT[_2ADDR]
@@ -214,8 +213,8 @@
points->pD2iz = __aeabi_d2iz;
points->pF2iz = __aeabi_f2iz;
points->pIdivmod = __aeabi_idivmod;
- points->pD2l = D2L;
- points->pF2l = F2L;
+ points->pD2l = art_d2l;
+ points->pF2l = art_f2l;
points->pLdiv = __aeabi_ldivmod;
points->pLdivmod = __aeabi_ldivmod; // result returned in r2:r3
points->pLmul = __aeabi_lmul;
diff --git a/src/oat/runtime/mips/oat_support_entrypoints_mips.cc b/src/oat/runtime/mips/oat_support_entrypoints_mips.cc
index d791632..9b4a46f 100644
--- a/src/oat/runtime/mips/oat_support_entrypoints_mips.cc
+++ b/src/oat/runtime/mips/oat_support_entrypoints_mips.cc
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "runtime_support.h"
#include "oat/runtime/oat_support_entrypoints.h"
namespace art {
@@ -83,8 +84,6 @@
extern "C" double __floatdidf(int64_t op1); // LONG_TO_DOUBLE
extern "C" int64_t __fixsfdi(float op1); // FLOAT_TO_LONG
extern "C" int64_t __fixdfdi(double op1); // DOUBLE_TO_LONG
-extern int64_t D2L(double d);
-extern int64_t F2L(float f);
// Single-precision FP arithmetics.
extern "C" float __addsf3(float a, float b); // ADD_FLOAT[_2ADDR]
@@ -213,8 +212,8 @@
points->pD2iz = __fixdfsi;
points->pF2iz = __fixsfi;
points->pIdivmod = NULL;
- points->pD2l = D2L;
- points->pF2l = F2L;
+ points->pD2l = art_d2l;
+ points->pF2l = art_f2l;
points->pLdiv = NULL;
points->pLdivmod = NULL;
points->pLmul = NULL;
diff --git a/src/oat/runtime/x86/oat_support_entrypoints_x86.cc b/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
index 95b479b..605024e 100644
--- a/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
+++ b/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
@@ -67,10 +67,10 @@
extern "C" void art_unlock_object_from_code(void*);
// Math entrypoints.
-extern int32_t CmpgDouble(double a, double b);
-extern int32_t CmplDouble(double a, double b);
-extern int32_t CmpgFloat(float a, float b);
-extern int32_t CmplFloat(float a, float b);
+extern "C" double art_l2d_from_code(int64_t);
+extern "C" float art_l2f_from_code(int64_t);
+extern "C" int64_t art_d2l_from_code(double);
+extern "C" int64_t art_f2l_from_code(float);
extern "C" int32_t art_idivmod_from_code(int32_t, int32_t);
extern "C" int64_t art_ldiv_from_code(int64_t, int64_t);
extern "C" int64_t art_ldivmod_from_code(int64_t, int64_t);
@@ -159,10 +159,10 @@
points->pUnlockObjectFromCode = art_unlock_object_from_code;
// Math
- points->pCmpgDouble = CmpgDouble;
- points->pCmpgFloat = CmpgFloat;
- points->pCmplDouble = CmplDouble;
- points->pCmplFloat = CmplFloat;
+ //points->pCmpgDouble = NULL; // Not needed on x86.
+ //points->pCmpgFloat = NULL; // Not needed on x86.
+ //points->pCmplDouble = NULL; // Not needed on x86.
+ //points->pCmplFloat = NULL; // Not needed on x86.
//points->pDadd = NULL; // Not needed on x86.
//points->pDdiv = NULL; // Not needed on x86.
//points->pDmul = NULL; // Not needed on x86.
@@ -170,7 +170,7 @@
//points->pF2d = NULL;
//points->pFmod = NULL;
//points->pI2d = NULL;
- //points->pL2d = NULL;
+ points->pL2d = art_l2d_from_code;
//points->pD2f = NULL;
//points->pFadd = NULL; // Not needed on x86.
//points->pFdiv = NULL; // Not needed on x86.
@@ -178,12 +178,12 @@
//points->pFmul = NULL; // Not needed on x86.
//points->pFsub = NULL; // Not needed on x86.
//points->pI2f = NULL;
- //points->pL2f = NULL;
- points->pD2iz = D2I;
- points->pF2iz = F2I;
+ points->pL2f = art_l2f_from_code;
+ //points->pD2iz = NULL; // Not needed on x86.
+ //points->pF2iz = NULL; // Not needed on x86.
points->pIdivmod = art_idivmod_from_code;
- points->pD2l = D2L;
- points->pF2l = F2L;
+ points->pD2l = art_d2l_from_code;
+ points->pF2l = art_f2l_from_code;
points->pLdiv = art_ldiv_from_code;
points->pLdivmod = art_ldivmod_from_code;
points->pLmul = art_lmul_from_code;
diff --git a/src/oat/runtime/x86/runtime_support_x86.S b/src/oat/runtime/x86/runtime_support_x86.S
index 9164800..028d7ec 100644
--- a/src/oat/runtime/x86/runtime_support_x86.S
+++ b/src/oat/runtime/x86/runtime_support_x86.S
@@ -395,6 +395,41 @@
NO_ARG_DOWNCALL art_test_suspend, artTestSuspendFromCode, ret
+DEFINE_FUNCTION art_l2d_from_code
+ pushl %eax // alignment padding
+ pushl %ecx // pass arg2
+ pushl %eax // pass arg1
+ call SYMBOL(art_l2d) // (jlong a, Thread*, SP)
+ fstpl (%esp) // get return value
+ movsd (%esp), %xmm0 // place into %xmm0
+ addl LITERAL(12), %esp // pop arguments
+ ret
+
+DEFINE_FUNCTION art_l2f_from_code
+ pushl %eax // alignment padding
+ pushl %ecx // pass arg2
+ pushl %eax // pass arg1
+ call SYMBOL(art_l2f) // (jlong a, Thread*, SP)
+ fstp (%esp) // get return value
+ movss (%esp), %xmm0 // place into %xmm0
+ addl LITERAL(12), %esp // pop arguments
+ ret
+
+DEFINE_FUNCTION art_d2l_from_code
+ pushl %eax // alignment padding
+ pushl %ecx // pass arg2
+ pushl %eax // pass arg1
+ call SYMBOL(art_d2l) // (jdouble a, Thread*, SP)
+ addl LITERAL(12), %esp // pop arguments
+ ret
+
+DEFINE_FUNCTION art_f2l_from_code
+ subl LITERAL(8), %esp // alignment padding
+ pushl %eax // pass arg1
+ call SYMBOL(art_f2l) // (jfloat a, Thread*, SP)
+ addl LITERAL(12), %esp // pop arguments
+ ret
+
DEFINE_FUNCTION art_idivmod_from_code
cmpl LITERAL(0x80000000), %eax
je check_arg2 // special case
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 1152c79..f8b40a2 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -18,13 +18,19 @@
#include "ScopedLocalRef.h"
-namespace art {
+double art_l2d(int64_t l) {
+ return (double) l;
+}
+
+float art_l2f(int64_t l) {
+ return (float) l;
+}
/*
* Float/double conversion requires clamping to min and max of integer form. If
* target doesn't support this normally, use these.
*/
-int64_t D2L(double d) {
+int64_t art_d2l(double d) {
static const double kMaxLong = (double) (int64_t) 0x7fffffffffffffffULL;
static const double kMinLong = (double) (int64_t) 0x8000000000000000ULL;
if (d >= kMaxLong) {
@@ -38,7 +44,7 @@
}
}
-int64_t F2L(float f) {
+int64_t art_f2l(float f) {
static const float kMaxLong = (float) (int64_t) 0x7fffffffffffffffULL;
static const float kMinLong = (float) (int64_t) 0x8000000000000000ULL;
if (f >= kMaxLong) {
@@ -52,7 +58,7 @@
}
}
-int32_t D2I(double d) {
+int32_t art_d2i(double d) {
static const double kMaxInt = (double) (int32_t) 0x7fffffffUL;
static const double kMinInt = (double) (int32_t) 0x80000000UL;
if (d >= kMaxInt) {
@@ -66,7 +72,7 @@
}
}
-int32_t F2I(float f) {
+int32_t art_f2i(float f) {
static const float kMaxInt = (float) (int32_t) 0x7fffffffUL;
static const float kMinInt = (float) (int32_t) 0x80000000UL;
if (f >= kMaxInt) {
@@ -80,6 +86,8 @@
}
}
+namespace art {
+
void ThrowNewIllegalAccessErrorClass(Thread* self,
Class* referrer,
Class* accessed) {
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 0fb1b2b..50b6735 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -28,6 +28,13 @@
extern "C" void art_proxy_invoke_handler();
extern "C" void art_work_around_app_jni_bugs();
+extern "C" double art_l2d(int64_t l);
+extern "C" float art_l2f(int64_t l);
+extern "C" int64_t art_d2l(double d);
+extern "C" int32_t art_d2i(double d);
+extern "C" int64_t art_f2l(float f);
+extern "C" int32_t art_f2i(float f);
+
namespace art {
class Array;
@@ -36,11 +43,6 @@
class Method;
class Object;
-int64_t D2L(double d);
-int32_t D2I(double d);
-int64_t F2L(float f);
-int32_t F2I(float f);
-
// Helpers to give consistent descriptive exception messages
void ThrowNewIllegalAccessErrorClass(Thread* self, Class* referrer, Class* accessed);
void ThrowNewIllegalAccessErrorClassForMethodDispatch(Thread* self, Class* referrer,