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 &registry = *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,