Merge "Add root types and thread id to root visiting."
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc
index c2016d0..8f83cd0 100644
--- a/compiler/dex/frontend.cc
+++ b/compiler/dex/frontend.cc
@@ -140,24 +140,25 @@
 CompilationUnit::~CompilationUnit() {
 }
 
-// TODO: Add a cumulative version of logging, and combine with dex2oat --dump-timing
 void CompilationUnit::StartTimingSplit(const char* label) {
-  if (enable_debug & (1 << kDebugTimings)) {
+  if (compiler_driver->GetDumpPasses()) {
     timings.StartSplit(label);
   }
 }
 
 void CompilationUnit::NewTimingSplit(const char* label) {
-  if (enable_debug & (1 << kDebugTimings)) {
+  if (compiler_driver->GetDumpPasses()) {
     timings.NewSplit(label);
   }
 }
 
 void CompilationUnit::EndTiming() {
-  if (enable_debug & (1 << kDebugTimings)) {
+  if (compiler_driver->GetDumpPasses()) {
     timings.EndSplit();
-    LOG(INFO) << "TIMINGS " << PrettyMethod(method_idx, *dex_file);
-    LOG(INFO) << Dumpable<TimingLogger>(timings);
+    if (enable_debug & (1 << kDebugTimings)) {
+      LOG(INFO) << "TIMINGS " << PrettyMethod(method_idx, *dex_file);
+      LOG(INFO) << Dumpable<TimingLogger>(timings);
+    }
   }
 }
 
@@ -330,6 +331,9 @@
   }
 
   cu.EndTiming();
+  compiler.GetTimingsLogger().Start();
+  compiler.GetTimingsLogger().AddLogger(cu.timings);
+  compiler.GetTimingsLogger().End();
   return result;
 }
 
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index 5e0fed7..05eb360 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -1186,4 +1186,37 @@
 void Mir2Lir::AddSlowPath(LIRSlowPath* slowpath) {
   slow_paths_.Insert(slowpath);
 }
+
+void Mir2Lir::LoadCodeAddress(int dex_method_index, InvokeType type, SpecialTargetRegister symbolic_reg) {
+  LIR* data_target = ScanLiteralPool(code_literal_list_, dex_method_index, 0);
+  if (data_target == NULL) {
+    data_target = AddWordData(&code_literal_list_, dex_method_index);
+    data_target->operands[1] = type;
+  }
+  LIR* load_pc_rel = OpPcRelLoad(TargetReg(symbolic_reg), data_target);
+  AppendLIR(load_pc_rel);
+  DCHECK_NE(cu_->instruction_set, kMips) << reinterpret_cast<void*>(data_target);
+}
+
+void Mir2Lir::LoadMethodAddress(int dex_method_index, InvokeType type, SpecialTargetRegister symbolic_reg) {
+  LIR* data_target = ScanLiteralPool(method_literal_list_, dex_method_index, 0);
+  if (data_target == NULL) {
+    data_target = AddWordData(&method_literal_list_, dex_method_index);
+    data_target->operands[1] = type;
+  }
+  LIR* load_pc_rel = OpPcRelLoad(TargetReg(symbolic_reg), data_target);
+  AppendLIR(load_pc_rel);
+  DCHECK_NE(cu_->instruction_set, kMips) << reinterpret_cast<void*>(data_target);
+}
+
+void Mir2Lir::LoadClassType(uint32_t type_idx, SpecialTargetRegister symbolic_reg) {
+  // Use the literal pool and a PC-relative load from a data word.
+  LIR* data_target = ScanLiteralPool(class_literal_list_, type_idx, 0);
+  if (data_target == nullptr) {
+    data_target = AddWordData(&class_literal_list_, type_idx);
+  }
+  LIR* load_pc_rel = OpPcRelLoad(TargetReg(symbolic_reg), data_target);
+  AppendLIR(load_pc_rel);
+}
+
 }  // namespace art
diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc
index 0ad8abf..389dd9a 100644
--- a/compiler/dex/quick/dex_file_method_inliner.cc
+++ b/compiler/dex/quick/dex_file_method_inliner.cc
@@ -123,6 +123,8 @@
     { kClassCacheShort, 1, { kClassCacheShort } },
     // kProtoCacheD_D
     { kClassCacheDouble, 1, { kClassCacheDouble } },
+    // kProtoCacheF_F
+    { kClassCacheFloat, 1, { kClassCacheFloat } },
     // kProtoCacheD_J
     { kClassCacheLong, 1, { kClassCacheDouble } },
     // kProtoCacheJ_D
@@ -198,6 +200,10 @@
     INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0),
     INTRINSIC(JavaLangMath,       Abs, J_J, kIntrinsicAbsLong, 0),
     INTRINSIC(JavaLangStrictMath, Abs, J_J, kIntrinsicAbsLong, 0),
+    INTRINSIC(JavaLangMath,       Abs, F_F, kIntrinsicAbsFloat, 0),
+    INTRINSIC(JavaLangStrictMath, Abs, F_F, kIntrinsicAbsFloat, 0),
+    INTRINSIC(JavaLangMath,       Abs, D_D, kIntrinsicAbsDouble, 0),
+    INTRINSIC(JavaLangStrictMath, Abs, D_D, kIntrinsicAbsDouble, 0),
     INTRINSIC(JavaLangMath,       Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
     INTRINSIC(JavaLangStrictMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
     INTRINSIC(JavaLangMath,       Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
@@ -345,6 +351,10 @@
       return backend->GenInlinedAbsInt(info);
     case kIntrinsicAbsLong:
       return backend->GenInlinedAbsLong(info);
+    case kIntrinsicAbsFloat:
+      return backend->GenInlinedAbsFloat(info);
+    case kIntrinsicAbsDouble:
+      return backend->GenInlinedAbsDouble(info);
     case kIntrinsicMinMaxInt:
       return backend->GenInlinedMinMaxInt(info, intrinsic.d.data & kIntrinsicFlagMin);
     case kIntrinsicSqrt:
diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h
index fe0824c..fb7528e 100644
--- a/compiler/dex/quick/dex_file_method_inliner.h
+++ b/compiler/dex/quick/dex_file_method_inliner.h
@@ -40,6 +40,8 @@
   kIntrinsicReverseBytes,
   kIntrinsicAbsInt,
   kIntrinsicAbsLong,
+  kIntrinsicAbsFloat,
+  kIntrinsicAbsDouble,
   kIntrinsicMinMaxInt,
   kIntrinsicSqrt,
   kIntrinsicCharAt,
@@ -268,6 +270,7 @@
       kProtoCacheJ_J,
       kProtoCacheS_S,
       kProtoCacheD_D,
+      kProtoCacheF_F,
       kProtoCacheD_J,
       kProtoCacheJ_D,
       kProtoCacheF_I,
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index c59f3b8..0533fbf 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -220,13 +220,7 @@
                                    &is_type_initialized, &use_direct_type_ptr, &direct_type_ptr)) {
       // The fast path.
       if (!use_direct_type_ptr) {
-        // Use the literal pool and a PC-relative load from a data word.
-        LIR* data_target = ScanLiteralPool(class_literal_list_, type_idx, 0);
-        if (data_target == nullptr) {
-          data_target = AddWordData(&class_literal_list_, type_idx);
-        }
-        LIR* load_pc_rel = OpPcRelLoad(TargetReg(kArg0), data_target);
-        AppendLIR(load_pc_rel);
+        LoadClassType(type_idx, kArg0);
         func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocArrayResolved);
         CallRuntimeHelperRegMethodRegLocation(func_offset, TargetReg(kArg0), rl_src, true);
       } else {
@@ -994,13 +988,7 @@
                                    &is_type_initialized, &use_direct_type_ptr, &direct_type_ptr)) {
       // The fast path.
       if (!use_direct_type_ptr) {
-        // Use the literal pool and a PC-relative load from a data word.
-        LIR* data_target = ScanLiteralPool(class_literal_list_, type_idx, 0);
-        if (data_target == nullptr) {
-          data_target = AddWordData(&class_literal_list_, type_idx);
-        }
-        LIR* load_pc_rel = OpPcRelLoad(TargetReg(kArg0), data_target);
-        AppendLIR(load_pc_rel);
+        LoadClassType(type_idx, kArg0);
         if (!is_type_initialized) {
           func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocObjectResolved);
           CallRuntimeHelperRegMethod(func_offset, TargetReg(kArg0), true);
@@ -1100,6 +1088,9 @@
                                          bool can_assume_type_is_in_dex_cache,
                                          uint32_t type_idx, RegLocation rl_dest,
                                          RegLocation rl_src) {
+  // X86 has its own implementation.
+  DCHECK_NE(cu_->instruction_set, kX86);
+
   FlushAllRegs();
   // May generate a call - use explicit registers
   LockCallTemps();
@@ -1181,15 +1172,10 @@
         LoadConstant(rl_result.low_reg, 1);     // assume true
         branchover = OpCmpBranch(kCondEq, TargetReg(kArg1), TargetReg(kArg2), NULL);
       }
-      if (cu_->instruction_set != kX86) {
-        int r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(pInstanceofNonTrivial));
-        OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));    // .ne case - arg0 <= class
-        OpReg(kOpBlx, r_tgt);    // .ne case: helper(class, ref->class)
-        FreeTemp(r_tgt);
-      } else {
-        OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));
-        OpThreadMem(kOpBlx, QUICK_ENTRYPOINT_OFFSET(pInstanceofNonTrivial));
-      }
+      int r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(pInstanceofNonTrivial));
+      OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));    // .ne case - arg0 <= class
+      OpReg(kOpBlx, r_tgt);    // .ne case: helper(class, ref->class)
+      FreeTemp(r_tgt);
     }
   }
   // TODO: only clobber when type isn't final?
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index 6aaad66..ee61c8b 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -384,31 +384,15 @@
         if (cu->instruction_set != kX86) {
           cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code);
         }
-      } else {
+      } else if (cu->instruction_set != kX86) {
         CHECK_EQ(cu->dex_file, target_method.dex_file);
-        LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_,
-                                               target_method.dex_method_index, 0);
-        if (data_target == NULL) {
-          data_target = cg->AddWordData(&cg->code_literal_list_, target_method.dex_method_index);
-          data_target->operands[1] = type;
-        }
-        LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kInvokeTgt), data_target);
-        cg->AppendLIR(load_pc_rel);
-        DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
+        cg->LoadCodeAddress(target_method.dex_method_index, type, kInvokeTgt);
       }
       if (direct_method != static_cast<unsigned int>(-1)) {
         cg->LoadConstant(cg->TargetReg(kArg0), direct_method);
       } else {
         CHECK_EQ(cu->dex_file, target_method.dex_file);
-        LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_,
-                                               target_method.dex_method_index, 0);
-        if (data_target == NULL) {
-          data_target = cg->AddWordData(&cg->method_literal_list_, target_method.dex_method_index);
-          data_target->operands[1] = type;
-        }
-        LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kArg0), data_target);
-        cg->AppendLIR(load_pc_rel);
-        DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
+        cg->LoadMethodAddress(target_method.dex_method_index, type, kArg0);
       }
       break;
     default:
@@ -427,18 +411,10 @@
       if (direct_code != 0) {
         if (direct_code != static_cast<unsigned int>(-1)) {
           cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code);
-        } else {
+        } else if (cu->instruction_set != kX86) {
           CHECK_EQ(cu->dex_file, target_method.dex_file);
           CHECK_LT(target_method.dex_method_index, target_method.dex_file->NumMethodIds());
-          LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_,
-                                                 target_method.dex_method_index, 0);
-          if (data_target == NULL) {
-            data_target = cg->AddWordData(&cg->code_literal_list_, target_method.dex_method_index);
-            data_target->operands[1] = type;
-          }
-          LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kInvokeTgt), data_target);
-          cg->AppendLIR(load_pc_rel);
-          DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
+          cg->LoadCodeAddress(target_method.dex_method_index, type, kInvokeTgt);
         }
       }
       break;
@@ -1001,7 +977,10 @@
   RegLocation rl_obj = info->args[0];
   RegLocation rl_idx = info->args[1];
   rl_obj = LoadValue(rl_obj, kCoreReg);
-  rl_idx = LoadValue(rl_idx, kCoreReg);
+  // X86 wants to avoid putting a constant index into a register.
+  if (!(cu_->instruction_set == kX86 && rl_idx.is_const)) {
+    rl_idx = LoadValue(rl_idx, kCoreReg);
+  }
   int reg_max;
   GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, info->opt_flags);
   bool range_check = (!(info->opt_flags & MIR_IGNORE_RANGE_CHECK));
@@ -1025,29 +1004,43 @@
       FreeTemp(reg_max);
       OpCondBranch(kCondUge, launch_pad);
     }
+    OpRegImm(kOpAdd, reg_ptr, data_offset);
   } else {
     if (range_check) {
-      reg_max = AllocTemp();
-      LoadWordDisp(rl_obj.low_reg, count_offset, reg_max);
+      // On x86, we can compare to memory directly
       // Set up a launch pad to allow retry in case of bounds violation */
       launch_pad = RawLIR(0, kPseudoIntrinsicRetry, WrapPointer(info));
       intrinsic_launchpads_.Insert(launch_pad);
-      OpRegReg(kOpCmp, rl_idx.low_reg, reg_max);
-      FreeTemp(reg_max);
-      OpCondBranch(kCondUge, launch_pad);
+      if (rl_idx.is_const) {
+        OpCmpMemImmBranch(kCondUlt, INVALID_REG, rl_obj.low_reg, count_offset,
+                          mir_graph_->ConstantValue(rl_idx.orig_sreg), launch_pad);
+      } else {
+        OpRegMem(kOpCmp, rl_idx.low_reg, rl_obj.low_reg, count_offset);
+        OpCondBranch(kCondUge, launch_pad);
+      }
     }
     reg_off = AllocTemp();
     reg_ptr = AllocTemp();
     LoadWordDisp(rl_obj.low_reg, offset_offset, reg_off);
     LoadWordDisp(rl_obj.low_reg, value_offset, reg_ptr);
   }
-  OpRegImm(kOpAdd, reg_ptr, data_offset);
-  OpRegReg(kOpAdd, reg_off, rl_idx.low_reg);
+  if (rl_idx.is_const) {
+    OpRegImm(kOpAdd, reg_off, mir_graph_->ConstantValue(rl_idx.orig_sreg));
+  } else {
+    OpRegReg(kOpAdd, reg_off, rl_idx.low_reg);
+  }
   FreeTemp(rl_obj.low_reg);
-  FreeTemp(rl_idx.low_reg);
+  if (rl_idx.low_reg != INVALID_REG) {
+    FreeTemp(rl_idx.low_reg);
+  }
   RegLocation rl_dest = InlineTarget(info);
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
-  LoadBaseIndexed(reg_ptr, reg_off, rl_result.low_reg, 1, kUnsignedHalf);
+  if (cu_->instruction_set != kX86) {
+    LoadBaseIndexed(reg_ptr, reg_off, rl_result.low_reg, 1, kUnsignedHalf);
+  } else {
+    LoadBaseIndexedDisp(reg_ptr, reg_off, 1, data_offset, rl_result.low_reg,
+                        INVALID_REG, kUnsignedHalf, INVALID_SREG);
+  }
   FreeTemp(reg_off);
   FreeTemp(reg_ptr);
   StoreValue(rl_dest, rl_result);
@@ -1094,7 +1087,7 @@
     return false;
   }
   RegLocation rl_src_i = info->args[0];
-  RegLocation rl_dest = InlineTarget(info);  // result reg
+  RegLocation rl_dest = (size == kLong) ? InlineTargetWide(info) : InlineTarget(info);  // result reg
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
   if (size == kLong) {
     RegLocation rl_i = LoadValueWide(rl_src_i, kCoreReg);
@@ -1179,6 +1172,43 @@
   }
 }
 
+bool Mir2Lir::GenInlinedAbsFloat(CallInfo* info) {
+  if (cu_->instruction_set == kMips) {
+    // TODO - add Mips implementation
+    return false;
+  }
+  RegLocation rl_src = info->args[0];
+  rl_src = LoadValue(rl_src, kCoreReg);
+  RegLocation rl_dest = InlineTarget(info);
+  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
+  int signMask = AllocTemp();
+  LoadConstant(signMask, 0x7fffffff);
+  OpRegRegReg(kOpAnd, rl_result.low_reg, rl_src.low_reg, signMask);
+  FreeTemp(signMask);
+  StoreValue(rl_dest, rl_result);
+  return true;
+}
+
+bool Mir2Lir::GenInlinedAbsDouble(CallInfo* info) {
+  if (cu_->instruction_set == kMips) {
+    // TODO - add Mips implementation
+    return false;
+  }
+  RegLocation rl_src = info->args[0];
+  rl_src = LoadValueWide(rl_src, kCoreReg);
+  RegLocation rl_dest = InlineTargetWide(info);
+  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
+  OpRegCopyWide(rl_result.low_reg, rl_result.high_reg, rl_src.low_reg, rl_src.high_reg);
+  FreeTemp(rl_src.low_reg);
+  FreeTemp(rl_src.high_reg);
+  int signMask = AllocTemp();
+  LoadConstant(signMask, 0x7fffffff);
+  OpRegReg(kOpAnd, rl_result.high_reg, signMask);
+  FreeTemp(signMask);
+  StoreValueWide(rl_dest, rl_result);
+  return true;
+}
+
 bool Mir2Lir::GenInlinedFloatCvt(CallInfo* info) {
   if (cu_->instruction_set == kMips) {
     // TODO - add Mips implementation
@@ -1308,7 +1338,7 @@
   RegLocation rl_src_obj = info->args[1];  // Object
   RegLocation rl_src_offset = info->args[2];  // long low
   rl_src_offset.wide = 0;  // ignore high half in info->args[3]
-  RegLocation rl_dest = InlineTarget(info);  // result reg
+  RegLocation rl_dest = is_long ? InlineTargetWide(info) : InlineTarget(info);  // result reg
   if (is_volatile) {
     GenMemBarrier(kLoadLoad);
   }
@@ -1436,8 +1466,15 @@
     call_inst = OpReg(kOpBlx, TargetReg(kInvokeTgt));
   } else {
     if (fast_path) {
-      call_inst = OpMem(kOpBlx, TargetReg(kArg0),
-                        mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value());
+      if (direct_code == static_cast<unsigned int>(-1)) {
+        // We can have the linker fixup a call relative.
+        call_inst =
+          reinterpret_cast<X86Mir2Lir*>(this)->CallWithLinkerFixup(
+              target_method.dex_method_index, info->type);
+      } else {
+        call_inst = OpMem(kOpBlx, TargetReg(kArg0),
+                          mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value());
+      }
     } else {
       ThreadOffset trampoline(-1);
       switch (info->type) {
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 3a68044..6115953 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -417,7 +417,7 @@
     bool EvaluateBranch(Instruction::Code opcode, int src1, int src2);
     bool IsInexpensiveConstant(RegLocation rl_src);
     ConditionCode FlipComparisonOrder(ConditionCode before);
-    void InstallLiteralPools();
+    virtual void InstallLiteralPools();
     void InstallSwitchTables();
     void InstallFillArrayData();
     bool VerifyCatchEntries();
@@ -663,6 +663,8 @@
     bool GenInlinedReverseBytes(CallInfo* info, OpSize size);
     bool GenInlinedAbsInt(CallInfo* info);
     bool GenInlinedAbsLong(CallInfo* info);
+    bool GenInlinedAbsFloat(CallInfo* info);
+    bool GenInlinedAbsDouble(CallInfo* info);
     bool GenInlinedFloatCvt(CallInfo* info);
     bool GenInlinedDoubleCvt(CallInfo* info);
     bool GenInlinedIndexOf(CallInfo* info, bool zero_based);
@@ -737,6 +739,34 @@
     void SpecialMIR2LIR(const InlineMethod& special);
     void MethodMIR2LIR();
 
+    /*
+     * @brief Load the address of the dex method into the register.
+     * @param dex_method_index The index of the method to be invoked.
+     * @param type How the method will be invoked.
+     * @param register that will contain the code address.
+     * @note register will be passed to TargetReg to get physical register.
+     */
+    void LoadCodeAddress(int dex_method_index, InvokeType type,
+                         SpecialTargetRegister symbolic_reg);
+
+    /*
+     * @brief Load the Method* of a dex method into the register.
+     * @param dex_method_index The index of the method to be invoked.
+     * @param type How the method will be invoked.
+     * @param register that will contain the code address.
+     * @note register will be passed to TargetReg to get physical register.
+     */
+    virtual void LoadMethodAddress(int dex_method_index, InvokeType type,
+                                   SpecialTargetRegister symbolic_reg);
+
+    /*
+     * @brief Load the Class* of a Dex Class type into the register.
+     * @param type How the method will be invoked.
+     * @param register that will contain the code address.
+     * @note register will be passed to TargetReg to get physical register.
+     */
+    virtual void LoadClassType(uint32_t type_idx, SpecialTargetRegister symbolic_reg);
+
     // Routines that work for the generic case, but may be overriden by target.
     /*
      * @brief Compare memory to immediate, and branch if condition true.
@@ -1046,13 +1076,13 @@
 
     void AddSlowPath(LIRSlowPath* slowpath);
 
-  private:
-    void GenInstanceofCallingHelper(bool needs_access_check, bool type_known_final,
-                                    bool type_known_abstract, bool use_declaring_class,
-                                    bool can_assume_type_is_in_dex_cache,
-                                    uint32_t type_idx, RegLocation rl_dest,
-                                    RegLocation rl_src);
+    virtual void GenInstanceofCallingHelper(bool needs_access_check, bool type_known_final,
+                                            bool type_known_abstract, bool use_declaring_class,
+                                            bool can_assume_type_is_in_dex_cache,
+                                            uint32_t type_idx, RegLocation rl_dest,
+                                            RegLocation rl_src);
 
+  private:
     void ClobberBody(RegisterInfo* p);
     void ResetDefBody(RegisterInfo* p) {
       p->def_start = NULL;
diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc
index ae53ddb..321c6a7 100644
--- a/compiler/dex/quick/x86/assemble_x86.cc
+++ b/compiler/dex/quick/x86/assemble_x86.cc
@@ -354,6 +354,7 @@
   { kX86CallM, kCall, IS_BINARY_OP | IS_BRANCH | IS_LOAD | REG_USE0,        { 0,             0, 0xFF, 0,    0, 2, 0, 0 }, "CallM", "[!0r+!1d]" },
   { kX86CallA, kCall, IS_QUAD_OP   | IS_BRANCH | IS_LOAD | REG_USE01,       { 0,             0, 0xFF, 0,    0, 2, 0, 0 }, "CallA", "[!0r+!1r<<!2d+!3d]" },
   { kX86CallT, kCall, IS_UNARY_OP  | IS_BRANCH | IS_LOAD,                   { THREAD_PREFIX, 0, 0xFF, 0,    0, 2, 0, 0 }, "CallT", "fs:[!0d]" },
+  { kX86CallI, kCall, IS_UNARY_OP  | IS_BRANCH,                             { 0,             0, 0xE8, 0,    0, 0, 0, 4 }, "CallI", "!0d" },
   { kX86Ret,   kNullary, NO_OPERAND | IS_BRANCH,                            { 0,             0, 0xC3, 0,    0, 0, 0, 0 }, "Ret", "" },
 
   { kX86StartOfMethod, kMacro,  IS_UNARY_OP | SETS_CCODES,             { 0, 0, 0,    0, 0, 0, 0, 0 }, "StartOfMethod", "!0r" },
@@ -494,6 +495,7 @@
       }
     case kCall:
       switch (lir->opcode) {
+        case kX86CallI: return 5;  // opcode 0:disp
         case kX86CallR: return 2;  // opcode modrm
         case kX86CallM:  // lir operands - 0: base, 1: disp
           return ComputeSize(entry, lir->operands[0], lir->operands[1], false);
@@ -985,6 +987,16 @@
   DCHECK_EQ(0, entry->skeleton.immediate_bytes);
 }
 
+void X86Mir2Lir::EmitCallImmediate(const X86EncodingMap* entry, int disp) {
+  EmitPrefixAndOpcode(entry);
+  DCHECK_EQ(4, entry->skeleton.immediate_bytes);
+  code_buffer_.push_back(disp & 0xFF);
+  code_buffer_.push_back((disp >> 8) & 0xFF);
+  code_buffer_.push_back((disp >> 16) & 0xFF);
+  code_buffer_.push_back((disp >> 24) & 0xFF);
+  DCHECK_EQ(0, entry->skeleton.ax_opcode);
+}
+
 void X86Mir2Lir::EmitCallThread(const X86EncodingMap* entry, int disp) {
   DCHECK_NE(entry->skeleton.prefix1, 0);
   EmitPrefixAndOpcode(entry);
@@ -1290,6 +1302,9 @@
         break;
       case kCall:
         switch (entry->opcode) {
+          case kX86CallI:  // lir operands - 0: disp
+            EmitCallImmediate(entry, lir->operands[0]);
+            break;
           case kX86CallM:  // lir operands - 0: base, 1: disp
             EmitCallMem(entry, lir->operands[0], lir->operands[1]);
             break;
@@ -1375,6 +1390,13 @@
  */
 void X86Mir2Lir::AssembleLIR() {
   cu_->NewTimingSplit("Assemble");
+
+  // We will remove the method address if we never ended up using it
+  if (store_method_addr_ && !store_method_addr_used_) {
+    setup_method_address_[0]->flags.is_nop = true;
+    setup_method_address_[1]->flags.is_nop = true;
+  }
+
   AssignOffsets();
   int assembler_retries = 0;
   /*
diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc
index 93875c9..7f646e0 100644
--- a/compiler/dex/quick/x86/call_x86.cc
+++ b/compiler/dex/quick/x86/call_x86.cc
@@ -93,6 +93,7 @@
     RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low);
     rl_method = LoadValue(rl_method, kCoreReg);
     start_of_method_reg = rl_method.low_reg;
+    store_method_addr_used_ = true;
   } else {
     start_of_method_reg = AllocTemp();
     NewLIR1(kX86StartOfMethod, start_of_method_reg);
@@ -155,6 +156,7 @@
     // We can use the saved value.
     RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low);
     LoadValueDirect(rl_method, rX86_ARG2);
+    store_method_addr_used_ = true;
   } else {
     NewLIR1(kX86StartOfMethod, rX86_ARG2);
   }
@@ -228,9 +230,9 @@
 
   if (base_of_code_ != nullptr) {
     // We have been asked to save the address of the method start for later use.
-    NewLIR1(kX86StartOfMethod, rX86_ARG0);
+    setup_method_address_[0] = NewLIR1(kX86StartOfMethod, rX86_ARG0);
     int displacement = SRegOffset(base_of_code_->s_reg_low);
-    StoreBaseDisp(rX86_SP, displacement, rX86_ARG0, kWord);
+    setup_method_address_[1] = StoreBaseDisp(rX86_SP, displacement, rX86_ARG0, kWord);
   }
 
   FreeTemp(rX86_ARG0);
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index 4c1c171..22e36d5 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -189,6 +189,24 @@
      */
     void GenInstanceofFinal(bool use_declaring_class, uint32_t type_idx,
                             RegLocation rl_dest, RegLocation rl_src);
+    /*
+     *
+     * @brief Implement Set up instanceof a class with x86 specific code.
+     * @param needs_access_check 'true' if we must check the access.
+     * @param type_known_final 'true' if the type is known to be a final class.
+     * @param type_known_abstract 'true' if the type is known to be an abstract class.
+     * @param use_declaring_class 'true' if the type can be loaded off the current Method*.
+     * @param can_assume_type_is_in_dex_cache 'true' if the type is known to be in the cache.
+     * @param type_idx Type index to use if use_declaring_class is 'false'.
+     * @param rl_dest Result to be set to 0 or 1.
+     * @param rl_src Object to be tested.
+     */
+    void GenInstanceofCallingHelper(bool needs_access_check, bool type_known_final,
+                                    bool type_known_abstract, bool use_declaring_class,
+                                    bool can_assume_type_is_in_dex_cache,
+                                    uint32_t type_idx, RegLocation rl_dest,
+                                    RegLocation rl_src);
+
     // Single operation generators.
     LIR* OpUnconditionalBranch(LIR* target);
     LIR* OpCmpBranch(ConditionCode cond, int src1, int src2, LIR* target);
@@ -245,6 +263,43 @@
     void GenArithOpInt(Instruction::Code opcode, RegLocation rl_dest,
                        RegLocation rl_lhs, RegLocation rl_rhs);
 
+    /*
+     * @brief Dump a RegLocation using printf
+     * @param loc Register location to dump
+     */
+    static void DumpRegLocation(RegLocation loc);
+
+    /*
+     * @brief Load the Method* of a dex method into the register.
+     * @param dex_method_index The index of the method to be invoked.
+     * @param type How the method will be invoked.
+     * @param register that will contain the code address.
+     * @note register will be passed to TargetReg to get physical register.
+     */
+    void LoadMethodAddress(int dex_method_index, InvokeType type,
+                           SpecialTargetRegister symbolic_reg);
+
+    /*
+     * @brief Load the Class* of a Dex Class type into the register.
+     * @param type How the method will be invoked.
+     * @param register that will contain the code address.
+     * @note register will be passed to TargetReg to get physical register.
+     */
+    void LoadClassType(uint32_t type_idx, SpecialTargetRegister symbolic_reg);
+
+    /*
+     * @brief Generate a relative call to the method that will be patched at link time.
+     * @param dex_method_index The index of the method to be invoked.
+     * @param type How the method will be invoked.
+     * @returns Call instruction
+     */
+    LIR * CallWithLinkerFixup(int dex_method_index, InvokeType type);
+
+    /*
+     * @brief Handle x86 specific literals
+     */
+    void InstallLiteralPools();
+
   private:
     void EmitPrefix(const X86EncodingMap* entry);
     void EmitOpcode(const X86EncodingMap* entry);
@@ -290,6 +345,7 @@
     void EmitJmp(const X86EncodingMap* entry, int rel);
     void EmitJcc(const X86EncodingMap* entry, int rel, uint8_t cc);
     void EmitCallMem(const X86EncodingMap* entry, uint8_t base, int disp);
+    void EmitCallImmediate(const X86EncodingMap* entry, int disp);
     void EmitCallThread(const X86EncodingMap* entry, int disp);
     void EmitPcRel(const X86EncodingMap* entry, uint8_t reg, int base_or_table, uint8_t index,
                    int scale, int table_or_disp);
@@ -330,12 +386,6 @@
      */
     bool IsNoOp(Instruction::Code op, int32_t value);
 
-    /*
-     * @brief Dump a RegLocation using printf
-     * @param loc Register location to dump
-     */
-    static void DumpRegLocation(RegLocation loc);
-
     /**
      * @brief Calculate magic number and shift for a given divisor
      * @param divisor divisor number for calculation
@@ -459,11 +509,26 @@
 
     // Information derived from analysis of MIR
 
+    // The compiler temporary for the code address of the method.
+    CompilerTemp *base_of_code_;
+
     // Have we decided to compute a ptr to code and store in temporary VR?
     bool store_method_addr_;
 
-    // The compiler temporary for the code address of the method.
-    CompilerTemp *base_of_code_;
+    // Have we used the stored method address?
+    bool store_method_addr_used_;
+
+    // Instructions to remove if we didn't use the stored method address.
+    LIR* setup_method_address_[2];
+
+    // Instructions needing patching with Method* values.
+    GrowableArray<LIR*> method_address_insns_;
+
+    // Instructions needing patching with Class Type* values.
+    GrowableArray<LIR*> class_type_address_insns_;
+
+    // Instructions needing patching with PC relative code addresses.
+    GrowableArray<LIR*> call_method_insns_;
 };
 
 }  // namespace art
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index a567a8a..9dd6116 100644
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -670,7 +670,7 @@
 bool X86Mir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) {
   RegLocation rl_src_address = info->args[0];  // long address
   rl_src_address.wide = 0;  // ignore high half in info->args[1]
-  RegLocation rl_dest = InlineTarget(info);
+  RegLocation rl_dest = size == kLong ? InlineTargetWide(info) : InlineTarget(info);
   RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
   if (size == kLong) {
@@ -780,8 +780,23 @@
 }
 
 LIR* X86Mir2Lir::OpPcRelLoad(int reg, LIR* target) {
-  LOG(FATAL) << "Unexpected use of OpPcRelLoad for x86";
-  return NULL;
+  CHECK(base_of_code_ != nullptr);
+
+  // Address the start of the method
+  RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low);
+  LoadValueDirectFixed(rl_method, reg);
+  store_method_addr_used_ = true;
+
+  // Load the proper value from the literal area.
+  // We don't know the proper offset for the value, so pick one that will force
+  // 4 byte offset.  We will fix this up in the assembler later to have the right
+  // value.
+  LIR *res = RawLIR(current_dalvik_offset_, kX86Mov32RM, reg, reg, 256, 0, 0, target);
+  res->target = target;
+  res->flags.fixup = kFixupLoad;
+  SetMemRefType(res, true, kLiteral);
+  store_method_addr_used_ = true;
+  return res;
 }
 
 LIR* X86Mir2Lir::OpVldm(int rBase, int count) {
@@ -1717,6 +1732,88 @@
   StoreValue(rl_dest, rl_result);
 }
 
+void X86Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_known_final,
+                                            bool type_known_abstract, bool use_declaring_class,
+                                            bool can_assume_type_is_in_dex_cache,
+                                            uint32_t type_idx, RegLocation rl_dest,
+                                            RegLocation rl_src) {
+  FlushAllRegs();
+  // May generate a call - use explicit registers.
+  LockCallTemps();
+  LoadCurrMethodDirect(TargetReg(kArg1));  // kArg1 gets current Method*.
+  int class_reg = TargetReg(kArg2);  // kArg2 will hold the Class*.
+  // Reference must end up in kArg0.
+  if (needs_access_check) {
+    // Check we have access to type_idx and if not throw IllegalAccessError,
+    // Caller function returns Class* in kArg0.
+    CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccess),
+                         type_idx, true);
+    OpRegCopy(class_reg, TargetReg(kRet0));
+    LoadValueDirectFixed(rl_src, TargetReg(kArg0));
+  } else if (use_declaring_class) {
+    LoadValueDirectFixed(rl_src, TargetReg(kArg0));
+    LoadWordDisp(TargetReg(kArg1),
+                 mirror::ArtMethod::DeclaringClassOffset().Int32Value(), class_reg);
+  } else {
+    // Load dex cache entry into class_reg (kArg2).
+    LoadValueDirectFixed(rl_src, TargetReg(kArg0));
+    LoadWordDisp(TargetReg(kArg1),
+                 mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), class_reg);
+    int32_t offset_of_type =
+        mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() + (sizeof(mirror::Class*)
+        * type_idx);
+    LoadWordDisp(class_reg, offset_of_type, class_reg);
+    if (!can_assume_type_is_in_dex_cache) {
+      // Need to test presence of type in dex cache at runtime.
+      LIR* hop_branch = OpCmpImmBranch(kCondNe, class_reg, 0, NULL);
+      // Type is not resolved. Call out to helper, which will return resolved type in kRet0/kArg0.
+      CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(pInitializeType), type_idx, true);
+      OpRegCopy(TargetReg(kArg2), TargetReg(kRet0));  // Align usage with fast path.
+      LoadValueDirectFixed(rl_src, TargetReg(kArg0));  /* Reload Ref. */
+      // Rejoin code paths
+      LIR* hop_target = NewLIR0(kPseudoTargetLabel);
+      hop_branch->target = hop_target;
+    }
+  }
+  /* kArg0 is ref, kArg2 is class. If ref==null, use directly as bool result. */
+  RegLocation rl_result = GetReturn(false);
+
+  // SETcc only works with EAX..EDX.
+  DCHECK_LT(rl_result.low_reg, 4);
+
+  // Is the class NULL?
+  LIR* branch1 = OpCmpImmBranch(kCondEq, TargetReg(kArg0), 0, NULL);
+
+  /* Load object->klass_. */
+  DCHECK_EQ(mirror::Object::ClassOffset().Int32Value(), 0);
+  LoadWordDisp(TargetReg(kArg0),  mirror::Object::ClassOffset().Int32Value(), TargetReg(kArg1));
+  /* kArg0 is ref, kArg1 is ref->klass_, kArg2 is class. */
+  LIR* branchover = nullptr;
+  if (type_known_final) {
+    // Ensure top 3 bytes of result are 0.
+    LoadConstant(rl_result.low_reg, 0);
+    OpRegReg(kOpCmp, TargetReg(kArg1), TargetReg(kArg2));
+    // Set the low byte of the result to 0 or 1 from the compare condition code.
+    NewLIR2(kX86Set8R, rl_result.low_reg, kX86CondEq);
+  } else {
+    if (!type_known_abstract) {
+      LoadConstant(rl_result.low_reg, 1);     // Assume result succeeds.
+      branchover = OpCmpBranch(kCondEq, TargetReg(kArg1), TargetReg(kArg2), NULL);
+    }
+    OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));
+    OpThreadMem(kOpBlx, QUICK_ENTRYPOINT_OFFSET(pInstanceofNonTrivial));
+  }
+  // TODO: only clobber when type isn't final?
+  ClobberCallerSave();
+  /* Branch targets here. */
+  LIR* target = NewLIR0(kPseudoTargetLabel);
+  StoreValue(rl_dest, rl_result);
+  branch1->target = target;
+  if (branchover != nullptr) {
+    branchover->target = target;
+  }
+}
+
 void X86Mir2Lir::GenArithOpInt(Instruction::Code opcode, RegLocation rl_dest,
                             RegLocation rl_lhs, RegLocation rl_rhs) {
   OpKind op = kOpBkpt;
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index a347d8b..1893ffc 100644
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -510,7 +510,11 @@
 }
 
 X86Mir2Lir::X86Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
-    : Mir2Lir(cu, mir_graph, arena) {
+    : Mir2Lir(cu, mir_graph, arena),
+      method_address_insns_(arena, 100, kGrowableArrayMisc),
+      class_type_address_insns_(arena, 100, kGrowableArrayMisc),
+      call_method_insns_(arena, 100, kGrowableArrayMisc) {
+  store_method_addr_used_ = false;
   for (int i = 0; i < kX86Last; i++) {
     if (X86Mir2Lir::EncodingMap[i].opcode != i) {
       LOG(FATAL) << "Encoding order for " << X86Mir2Lir::EncodingMap[i].name
@@ -816,4 +820,104 @@
   Mir2Lir::Materialize();
 }
 
+void X86Mir2Lir::LoadMethodAddress(int dex_method_index, InvokeType type,
+                                   SpecialTargetRegister symbolic_reg) {
+  /*
+   * For x86, just generate a 32 bit move immediate instruction, that will be filled
+   * in at 'link time'.  For now, put a unique value based on target to ensure that
+   * code deduplication works.
+   */
+  const DexFile::MethodId& id = cu_->dex_file->GetMethodId(dex_method_index);
+  uintptr_t ptr = reinterpret_cast<uintptr_t>(&id);
+
+  // Generate the move instruction with the unique pointer and save index and type.
+  LIR *move = RawLIR(current_dalvik_offset_, kX86Mov32RI, TargetReg(symbolic_reg),
+                     static_cast<int>(ptr), dex_method_index, type);
+  AppendLIR(move);
+  method_address_insns_.Insert(move);
+}
+
+void X86Mir2Lir::LoadClassType(uint32_t type_idx, SpecialTargetRegister symbolic_reg) {
+  /*
+   * For x86, just generate a 32 bit move immediate instruction, that will be filled
+   * in at 'link time'.  For now, put a unique value based on target to ensure that
+   * code deduplication works.
+   */
+  const DexFile::TypeId& id = cu_->dex_file->GetTypeId(type_idx);
+  uintptr_t ptr = reinterpret_cast<uintptr_t>(&id);
+
+  // Generate the move instruction with the unique pointer and save index and type.
+  LIR *move = RawLIR(current_dalvik_offset_, kX86Mov32RI, TargetReg(symbolic_reg),
+                     static_cast<int>(ptr), type_idx);
+  AppendLIR(move);
+  class_type_address_insns_.Insert(move);
+}
+
+LIR *X86Mir2Lir::CallWithLinkerFixup(int dex_method_index, InvokeType type) {
+  /*
+   * For x86, just generate a 32 bit call relative instruction, that will be filled
+   * in at 'link time'.  For now, put a unique value based on target to ensure that
+   * code deduplication works.
+   */
+  const DexFile::MethodId& id = cu_->dex_file->GetMethodId(dex_method_index);
+  uintptr_t ptr = reinterpret_cast<uintptr_t>(&id);
+
+  // Generate the call instruction with the unique pointer and save index and type.
+  LIR *call = RawLIR(current_dalvik_offset_, kX86CallI, static_cast<int>(ptr), dex_method_index,
+                     type);
+  AppendLIR(call);
+  call_method_insns_.Insert(call);
+  return call;
+}
+
+void X86Mir2Lir::InstallLiteralPools() {
+  // These are handled differently for x86.
+  DCHECK(code_literal_list_ == nullptr);
+  DCHECK(method_literal_list_ == nullptr);
+  DCHECK(class_literal_list_ == nullptr);
+
+  // Handle the fixups for methods.
+  for (uint32_t i = 0; i < method_address_insns_.Size(); i++) {
+      LIR* p = method_address_insns_.Get(i);
+      DCHECK_EQ(p->opcode, kX86Mov32RI);
+      uint32_t target = p->operands[2];
+
+      // The offset to patch is the last 4 bytes of the instruction.
+      int patch_offset = p->offset + p->flags.size - 4;
+      cu_->compiler_driver->AddMethodPatch(cu_->dex_file, cu_->class_def_idx,
+                                           cu_->method_idx, cu_->invoke_type,
+                                           target, static_cast<InvokeType>(p->operands[3]),
+                                           patch_offset);
+  }
+
+  // Handle the fixups for class types.
+  for (uint32_t i = 0; i < class_type_address_insns_.Size(); i++) {
+      LIR* p = class_type_address_insns_.Get(i);
+      DCHECK_EQ(p->opcode, kX86Mov32RI);
+      uint32_t target = p->operands[2];
+
+      // The offset to patch is the last 4 bytes of the instruction.
+      int patch_offset = p->offset + p->flags.size - 4;
+      cu_->compiler_driver->AddClassPatch(cu_->dex_file, cu_->class_def_idx,
+                                          cu_->method_idx, target, patch_offset);
+  }
+
+  // And now the PC-relative calls to methods.
+  for (uint32_t i = 0; i < call_method_insns_.Size(); i++) {
+      LIR* p = call_method_insns_.Get(i);
+      DCHECK_EQ(p->opcode, kX86CallI);
+      uint32_t target = p->operands[1];
+
+      // The offset to patch is the last 4 bytes of the instruction.
+      int patch_offset = p->offset + p->flags.size - 4;
+      cu_->compiler_driver->AddRelativeCodePatch(cu_->dex_file, cu_->class_def_idx,
+                                                 cu_->method_idx, cu_->invoke_type, target,
+                                                 static_cast<InvokeType>(p->operands[2]),
+                                                 patch_offset, -4 /* offset */);
+  }
+
+  // And do the normal processing.
+  Mir2Lir::InstallLiteralPools();
+}
+
 }  // namespace art
diff --git a/compiler/dex/quick/x86/utility_x86.cc b/compiler/dex/quick/x86/utility_x86.cc
index e2744d0..48a39bb 100644
--- a/compiler/dex/quick/x86/utility_x86.cc
+++ b/compiler/dex/quick/x86/utility_x86.cc
@@ -518,8 +518,7 @@
         res->target = data_target;
         res->flags.fixup = kFixupLoad;
         SetMemRefType(res, true, kLiteral);
-        // Redo after we assign target to ensure size is correct.
-        SetupResourceMasks(res);
+        store_method_addr_used_ = true;
       } else {
         if (val_lo == 0) {
           res = NewLIR2(kX86XorpsRR, r_dest_lo, r_dest_lo);
@@ -860,6 +859,7 @@
     case Instruction::REM_DOUBLE_2ADDR:
       AnalyzeFPInstruction(opcode, bb, mir);
       break;
+
     // Packed switches and array fills need a pointer to the base of the method.
     case Instruction::FILL_ARRAY_DATA:
     case Instruction::PACKED_SWITCH:
diff --git a/compiler/dex/quick/x86/x86_lir.h b/compiler/dex/quick/x86/x86_lir.h
index 6962ff7..c49f627 100644
--- a/compiler/dex/quick/x86/x86_lir.h
+++ b/compiler/dex/quick/x86/x86_lir.h
@@ -387,6 +387,7 @@
   kX86CallA,            // call [base + index * scale + disp]
                         // lir operands - 0: base, 1: index, 2: scale, 3: disp
   kX86CallT,            // call fs:[disp]; fs: is equal to Thread::Current(); lir operands - 0: disp
+  kX86CallI,            // call <relative> - 0: disp; Used for core.oat linking only
   kX86Ret,              // ret; no lir operands
   kX86StartOfMethod,    // call 0; pop reg; sub reg, # - generate start of method into reg
                         // lir operands - 0: reg
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 5b9d66c..402d4f4 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -344,7 +344,7 @@
                                CompilerBackend compiler_backend, InstructionSet instruction_set,
                                InstructionSetFeatures instruction_set_features,
                                bool image, DescriptorSet* image_classes, size_t thread_count,
-                               bool dump_stats)
+                               bool dump_stats, bool dump_passes, CumulativeLogger* timer)
     : verification_results_(verification_results),
       method_inliner_map_(method_inliner_map),
       compiler_backend_(compiler_backend),
@@ -359,13 +359,15 @@
       start_ns_(0),
       stats_(new AOTCompilationStats),
       dump_stats_(dump_stats),
+      dump_passes_(dump_passes),
+      timings_logger_(timer),
       compiler_library_(NULL),
       compiler_(NULL),
       compiler_context_(NULL),
       jni_compiler_(NULL),
       compiler_enable_auto_elf_loading_(NULL),
       compiler_get_method_code_addr_(NULL),
-      support_boot_image_fixup_(instruction_set == kThumb2),
+      support_boot_image_fixup_(instruction_set != kMips),
       dedupe_code_("dedupe code"),
       dedupe_mapping_table_("dedupe mapping table"),
       dedupe_vmap_table_("dedupe vmap table"),
@@ -1396,6 +1398,24 @@
                                                     target_invoke_type,
                                                     literal_offset));
 }
+void CompilerDriver::AddRelativeCodePatch(const DexFile* dex_file,
+                                          uint16_t referrer_class_def_idx,
+                                          uint32_t referrer_method_idx,
+                                          InvokeType referrer_invoke_type,
+                                          uint32_t target_method_idx,
+                                          InvokeType target_invoke_type,
+                                          size_t literal_offset,
+                                          int32_t pc_relative_offset) {
+  MutexLock mu(Thread::Current(), compiled_methods_lock_);
+  code_to_patch_.push_back(new RelativeCallPatchInformation(dex_file,
+                                                            referrer_class_def_idx,
+                                                            referrer_method_idx,
+                                                            referrer_invoke_type,
+                                                            target_method_idx,
+                                                            target_invoke_type,
+                                                            literal_offset,
+                                                            pc_relative_offset));
+}
 void CompilerDriver::AddMethodPatch(const DexFile* dex_file,
                                     uint16_t referrer_class_def_idx,
                                     uint32_t referrer_method_idx,
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index ea43e4f..c4ac9db 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -22,6 +22,7 @@
 #include <vector>
 
 #include "base/mutex.h"
+#include "base/timing_logger.h"
 #include "class_reference.h"
 #include "compiled_class.h"
 #include "compiled_method.h"
@@ -103,7 +104,8 @@
                           CompilerBackend compiler_backend, InstructionSet instruction_set,
                           InstructionSetFeatures instruction_set_features,
                           bool image, DescriptorSet* image_classes,
-                          size_t thread_count, bool dump_stats);
+                          size_t thread_count, bool dump_stats, bool dump_passes,
+                          CumulativeLogger* timer);
 
   ~CompilerDriver();
 
@@ -238,6 +240,15 @@
                     InvokeType target_invoke_type,
                     size_t literal_offset)
       LOCKS_EXCLUDED(compiled_methods_lock_);
+  void AddRelativeCodePatch(const DexFile* dex_file,
+                            uint16_t referrer_class_def_idx,
+                            uint32_t referrer_method_idx,
+                            InvokeType referrer_invoke_type,
+                            uint32_t target_method_idx,
+                            InvokeType target_invoke_type,
+                            size_t literal_offset,
+                            int32_t pc_relative_offset)
+      LOCKS_EXCLUDED(compiled_methods_lock_);
   void AddMethodPatch(const DexFile* dex_file,
                       uint16_t referrer_class_def_idx,
                       uint32_t referrer_method_idx,
@@ -293,6 +304,15 @@
 
   class CallPatchInformation;
   class TypePatchInformation;
+
+  bool GetDumpPasses() const {
+    return dump_passes_;
+  }
+
+  CumulativeLogger& GetTimingsLogger() const {
+    return *timings_logger_;
+  }
+
   class PatchInformation {
    public:
     const DexFile& GetDexFile() const {
@@ -362,8 +382,14 @@
     bool IsCall() const {
       return true;
     }
+    virtual bool IsRelative() const {
+      return false;
+    }
+    virtual int RelativeOffset() const {
+      return 0;
+    }
 
-   private:
+   protected:
     CallPatchInformation(const DexFile* dex_file,
                          uint16_t referrer_class_def_idx,
                          uint32_t referrer_method_idx,
@@ -378,6 +404,7 @@
           target_invoke_type_(target_invoke_type) {
     }
 
+   private:
     const InvokeType referrer_invoke_type_;
     const uint32_t target_method_idx_;
     const InvokeType target_invoke_type_;
@@ -386,6 +413,36 @@
     DISALLOW_COPY_AND_ASSIGN(CallPatchInformation);
   };
 
+  class RelativeCallPatchInformation : public CallPatchInformation {
+   public:
+    bool IsRelative() const {
+      return true;
+    }
+    int RelativeOffset() const {
+      return offset_;
+    }
+
+   private:
+    RelativeCallPatchInformation(const DexFile* dex_file,
+                                 uint16_t referrer_class_def_idx,
+                                 uint32_t referrer_method_idx,
+                                 InvokeType referrer_invoke_type,
+                                 uint32_t target_method_idx,
+                                 InvokeType target_invoke_type,
+                                 size_t literal_offset,
+                                 int32_t pc_relative_offset)
+        : CallPatchInformation(dex_file, referrer_class_def_idx,
+                           referrer_method_idx, referrer_invoke_type,
+                           target_method_idx, target_invoke_type, literal_offset),
+          offset_(pc_relative_offset) {
+    }
+
+    const int offset_;
+
+    friend class CompilerDriver;
+    DISALLOW_COPY_AND_ASSIGN(RelativeCallPatchInformation);
+  };
+
   class TypePatchInformation : public PatchInformation {
    public:
     uint32_t GetTargetTypeIdx() const {
@@ -535,6 +592,9 @@
   UniquePtr<AOTCompilationStats> stats_;
 
   bool dump_stats_;
+  const bool dump_passes_;
+
+  CumulativeLogger* const timings_logger_;
 
   typedef void (*CompilerCallbackFn)(CompilerDriver& driver);
   typedef MutexLock* (*CompilerMutexLockFn)(CompilerDriver& driver);
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 67cd51b..e5dfb9d 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -785,7 +785,19 @@
     uintptr_t quick_code = reinterpret_cast<uintptr_t>(class_linker->GetQuickOatCodeFor(target));
     uintptr_t code_base = reinterpret_cast<uintptr_t>(&oat_file_->GetOatHeader());
     uintptr_t code_offset = quick_code - code_base;
-    SetPatchLocation(patch, PointerToLowMemUInt32(GetOatAddress(code_offset)));
+    if (patch->IsRelative()) {
+      // value to patch is relative to the location being patched
+      const void* quick_oat_code =
+        class_linker->GetQuickOatCodeFor(patch->GetDexFile(),
+                                         patch->GetReferrerClassDefIdx(),
+                                         patch->GetReferrerMethodIdx());
+      uintptr_t base = reinterpret_cast<uintptr_t>(quick_oat_code);
+      uintptr_t patch_location = base + patch->GetLiteralOffset();
+      uintptr_t value = quick_code - patch_location + patch->RelativeOffset();
+      SetPatchLocation(patch, value);
+    } else {
+      SetPatchLocation(patch, PointerToLowMemUInt32(GetOatAddress(code_offset)));
+    }
   }
 
   const CallPatches& methods_to_patch = compiler_driver_.GetMethodsToPatch();
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index b3070b6..f6b511c 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -91,10 +91,12 @@
   verification_results_.reset(new VerificationResults);
   method_inliner_map_.reset(compiler_backend == kQuick ? new DexFileToMethodInlinerMap : nullptr);
   callbacks_.Reset(verification_results_.get(), method_inliner_map_.get());
+  timer_.reset(new CumulativeLogger("Compilation times"));
   compiler_driver_.reset(new CompilerDriver(verification_results_.get(),
                                             method_inliner_map_.get(),
                                             compiler_backend, insn_set,
-                                            insn_features, false, NULL, 2, true));
+                                            insn_features, false, NULL, 2, true, true,
+                                            timer_.get()));
   jobject class_loader = NULL;
   if (kCompile) {
     TimingLogger timings("OatTest::WriteRead", false, false);
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 90eea5e..98c64aa 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -253,7 +253,9 @@
                                       bool image,
                                       UniquePtr<CompilerDriver::DescriptorSet>& image_classes,
                                       bool dump_stats,
-                                      TimingLogger& timings) {
+                                      bool dump_passes,
+                                      TimingLogger& timings,
+                                      CumulativeLogger& compiler_phases_timings) {
     // SirtRef and ClassLoader creation needs to come after Runtime::Create
     jobject class_loader = NULL;
     Thread* self = Thread::Current();
@@ -280,7 +282,9 @@
                                                         image,
                                                         image_classes.release(),
                                                         thread_count_,
-                                                        dump_stats));
+                                                        dump_stats,
+                                                        dump_passes,
+                                                        &compiler_phases_timings));
 
     if (compiler_backend_ == kPortable) {
       driver->SetBitcodeFileName(bitcode_filename);
@@ -654,6 +658,7 @@
 
 static int dex2oat(int argc, char** argv) {
   TimingLogger timings("compiler", false, false);
+  CumulativeLogger compiler_phases_timings("compilation times");
 
   InitLogging(argv);
 
@@ -703,6 +708,7 @@
   bool is_host = false;
   bool dump_stats = false;
   bool dump_timing = false;
+  bool dump_passes = false;
   bool dump_slow_timing = kIsDebugBuild;
   bool watch_dog_enabled = !kIsTargetBuild;
 
@@ -798,6 +804,8 @@
       runtime_args.push_back(argv[i]);
     } else if (option == "--dump-timing") {
       dump_timing = true;
+    } else if (option == "--dump-passes") {
+      dump_passes = true;
     } else if (option == "--dump-stats") {
       dump_stats = true;
     } else {
@@ -1069,7 +1077,9 @@
                                                                   image,
                                                                   image_classes,
                                                                   dump_stats,
-                                                                  timings));
+                                                                  dump_passes,
+                                                                  timings,
+                                                                  compiler_phases_timings));
 
   if (compiler.get() == NULL) {
     LOG(ERROR) << "Failed to create oat file: " << oat_location;
@@ -1145,6 +1155,9 @@
     if (dump_timing || (dump_slow_timing && timings.GetTotalNs() > MsToNs(1000))) {
       LOG(INFO) << Dumpable<TimingLogger>(timings);
     }
+    if (dump_passes) {
+      LOG(INFO) << Dumpable<CumulativeLogger>(compiler.get()->GetTimingsLogger());
+    }
     return EXIT_SUCCESS;
   }
 
@@ -1187,6 +1200,9 @@
   if (dump_timing || (dump_slow_timing && timings.GetTotalNs() > MsToNs(1000))) {
     LOG(INFO) << Dumpable<TimingLogger>(timings);
   }
+  if (dump_passes) {
+    LOG(INFO) << Dumpable<CumulativeLogger>(compiler_phases_timings);
+  }
 
   // Everything was successfully written, do an explicit exit here to avoid running Runtime
   // destructors that take time (bug 10645725) unless we're a debug build or running on valgrind.
diff --git a/runtime/common_test.h b/runtime/common_test.h
index daa2ff1..af7e8ae 100644
--- a/runtime/common_test.h
+++ b/runtime/common_test.h
@@ -480,12 +480,13 @@
         }
       }
       class_linker_->FixupDexCaches(runtime_->GetResolutionMethod());
+      timer_.reset(new CumulativeLogger("Compilation times"));
       compiler_driver_.reset(new CompilerDriver(verification_results_.get(),
                                                 method_inliner_map_.get(),
                                                 compiler_backend, instruction_set,
                                                 instruction_set_features,
                                                 true, new CompilerDriver::DescriptorSet,
-                                                2, true));
+                                                2, true, true, timer_.get()));
     }
     // We typically don't generate an image in unit tests, disable this optimization by default.
     compiler_driver_->SetSupportBootImageFixup(false);
@@ -530,6 +531,7 @@
     (*icu_cleanup_fn)();
 
     compiler_driver_.reset();
+    timer_.reset();
     callbacks_.Reset(nullptr, nullptr);
     method_inliner_map_.reset();
     verification_results_.reset();
@@ -662,7 +664,7 @@
 
   class TestCompilerCallbacks : public CompilerCallbacks {
    public:
-    TestCompilerCallbacks() : verification_results_(nullptr), method_inliner_map_(nullptr) { }
+    TestCompilerCallbacks() : verification_results_(nullptr), method_inliner_map_(nullptr) {}
 
     void Reset(VerificationResults* verification_results,
                DexFileToMethodInlinerMap* method_inliner_map) {
@@ -701,6 +703,7 @@
   UniquePtr<DexFileToMethodInlinerMap> method_inliner_map_;
   TestCompilerCallbacks callbacks_;
   UniquePtr<CompilerDriver> compiler_driver_;
+  UniquePtr<CumulativeLogger> timer_;
 
  private:
   std::vector<const DexFile*> opened_dex_files_;
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 0f380ad..00a8506 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -226,7 +226,7 @@
   }
 
   for (size_t i = 0; i < GetOatHeader().GetDexFileCount(); i++) {
-    size_t dex_file_location_size = *reinterpret_cast<const uint32_t*>(oat);
+    uint32_t dex_file_location_size = *reinterpret_cast<const uint32_t*>(oat);
     if (UNLIKELY(dex_file_location_size == 0U)) {
       *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd with empty location name",
                                 GetLocation().c_str(), i);
diff --git a/runtime/runtime_linux.cc b/runtime/runtime_linux.cc
index d8f408a..73ac034 100644
--- a/runtime/runtime_linux.cc
+++ b/runtime/runtime_linux.cc
@@ -19,6 +19,7 @@
 #include <signal.h>
 #include <string.h>
 #include <sys/utsname.h>
+#include <inttypes.h>
 
 #include "base/logging.h"
 #include "base/mutex.h"
@@ -185,6 +186,41 @@
     os << '\n';
     DumpRegister32(os, "gs",  context.gregs[REG_GS]);
     DumpRegister32(os, "ss",  context.gregs[REG_SS]);
+#elif defined(__linux__) && defined(__x86_64__)
+    DumpRegister64(os, "rax", context.gregs[REG_RAX]);
+    DumpRegister64(os, "rbx", context.gregs[REG_RBX]);
+    DumpRegister64(os, "rcx", context.gregs[REG_RCX]);
+    DumpRegister64(os, "rdx", context.gregs[REG_RDX]);
+    os << '\n';
+
+    DumpRegister64(os, "rdi", context.gregs[REG_RDI]);
+    DumpRegister64(os, "rsi", context.gregs[REG_RSI]);
+    DumpRegister64(os, "rbp", context.gregs[REG_RBP]);
+    DumpRegister64(os, "rsp", context.gregs[REG_RSP]);
+    os << '\n';
+
+    DumpRegister64(os, "r8 ", context.gregs[REG_R8]);
+    DumpRegister64(os, "r9 ", context.gregs[REG_R9]);
+    DumpRegister64(os, "r10", context.gregs[REG_R10]);
+    DumpRegister64(os, "r11", context.gregs[REG_R11]);
+    os << '\n';
+
+    DumpRegister64(os, "r12", context.gregs[REG_R12]);
+    DumpRegister64(os, "r13", context.gregs[REG_R13]);
+    DumpRegister64(os, "r14", context.gregs[REG_R14]);
+    DumpRegister64(os, "r15", context.gregs[REG_R15]);
+    os << '\n';
+
+    DumpRegister64(os, "rip", context.gregs[REG_RIP]);
+    os << "   ";
+    DumpRegister32(os, "eflags", context.gregs[REG_EFL]);
+    DumpX86Flags(os, context.gregs[REG_EFL]);
+    os << '\n';
+
+    DumpRegister32(os, "cs",  (context.gregs[REG_CSGSFS]) & 0x0FFFF);
+    DumpRegister32(os, "gs",  (context.gregs[REG_CSGSFS] >> 16) & 0x0FFFF);
+    DumpRegister32(os, "fs",  (context.gregs[REG_CSGSFS] >> 32) & 0x0FFFF);
+    os << '\n';
 #else
     os << "Unknown architecture/word size/OS in ucontext dump";
 #endif
@@ -194,6 +230,10 @@
     os << StringPrintf(" %6s: 0x%08x", name, value);
   }
 
+  void DumpRegister64(std::ostream& os, const char* name, uint64_t value) {
+    os << StringPrintf(" %6s: 0x%016" PRIx64, name, value);
+  }
+
   void DumpX86Flags(std::ostream& os, uint32_t flags) {
     os << " [";
     if ((flags & (1 << 0)) != 0) {
diff --git a/test/051-thread/expected.txt b/test/051-thread/expected.txt
index 8e6b153..7139b7f 100644
--- a/test/051-thread/expected.txt
+++ b/test/051-thread/expected.txt
@@ -1,8 +1,9 @@
-Initializing System.out...
-Thread count: 512
-Starting thread 'Thready'
-@ Thread running
-@ Got expected setDaemon exception
-@ Thread bailing
-Thread starter returning
+thread test starting
+testThreadCapacity thread count: 512
+testThreadDaemons starting thread 'TestDaemonThread'
+testThreadDaemons @ Thread running
+testThreadDaemons @ Got expected setDaemon exception
+testThreadDaemons @ Thread bailing
+testThreadDaemons finished
+testSleepZero finished
 thread test done
diff --git a/test/051-thread/src/Main.java b/test/051-thread/src/Main.java
index 911c739..608b7e0 100644
--- a/test/051-thread/src/Main.java
+++ b/test/051-thread/src/Main.java
@@ -21,50 +21,36 @@
  */
 public class Main {
     public static void main(String[] args) throws Exception {
-        System.out.println("Initializing System.out...");
-
-        MyThread[] threads = new MyThread[512];
-        for (int i = 0; i < 512; i++) {
-            threads[i] = new MyThread();
-        }
-
-        for (MyThread thread : threads) {
-            thread.start();
-        }
-        for (MyThread thread : threads) {
-            thread.join();
-        }
-
-        System.out.println("Thread count: " + MyThread.mCount);
-
-        go();
+        System.out.println("thread test starting");
+        testThreadCapacity();
+        testThreadDaemons();
+        testSleepZero();
         System.out.println("thread test done");
     }
 
-    public static void go() {
-        Thread t = new Thread(null, new ThreadTestSub(), "Thready", 7168);
-
-        t.setDaemon(false);
-
-        System.out.print("Starting thread '" + t.getName() + "'\n");
-        t.start();
-
-        try {
-            t.join();
-        } catch (InterruptedException ex) {
-            ex.printStackTrace();
-        }
-
-        System.out.print("Thread starter returning\n");
-    }
-
     /*
      * Simple thread capacity test.
      */
-    static class MyThread extends Thread {
+    private static void testThreadCapacity() throws Exception {
+        TestCapacityThread[] threads = new TestCapacityThread[512];
+        for (int i = 0; i < 512; i++) {
+            threads[i] = new TestCapacityThread();
+        }
+
+        for (TestCapacityThread thread : threads) {
+            thread.start();
+        }
+        for (TestCapacityThread thread : threads) {
+            thread.join();
+        }
+
+        System.out.println("testThreadCapacity thread count: " + TestCapacityThread.mCount);
+    }
+
+    private static class TestCapacityThread extends Thread {
         static int mCount = 0;
         public void run() {
-            synchronized (MyThread.class) {
+            synchronized (TestCapacityThread.class) {
                 ++mCount;
             }
             try {
@@ -73,29 +59,57 @@
             }
         }
     }
-}
 
-class ThreadTestSub implements Runnable {
-    public void run() {
-        System.out.print("@ Thread running\n");
+    private static void testThreadDaemons() {
+        Thread t = new Thread(null, new TestDaemonThread(), "TestDaemonThread", 7168);
+
+        t.setDaemon(false);
+
+        System.out.print("testThreadDaemons starting thread '" + t.getName() + "'\n");
+        t.start();
 
         try {
-            Thread.currentThread().setDaemon(true);
-            System.out.print("@ FAILED: setDaemon() succeeded\n");
-        } catch (IllegalThreadStateException itse) {
-            System.out.print("@ Got expected setDaemon exception\n");
+            t.join();
+        } catch (InterruptedException ex) {
+            ex.printStackTrace();
         }
 
-        //if (true)
-        //    throw new NullPointerException();
+        System.out.print("testThreadDaemons finished\n");
+    }
+
+    private static class TestDaemonThread implements Runnable {
+        public void run() {
+            System.out.print("testThreadDaemons @ Thread running\n");
+
+            try {
+                Thread.currentThread().setDaemon(true);
+                System.out.print("testThreadDaemons @ FAILED: setDaemon() succeeded\n");
+            } catch (IllegalThreadStateException itse) {
+                System.out.print("testThreadDaemons @ Got expected setDaemon exception\n");
+            }
+
+            try {
+                Thread.sleep(2000);
+            }
+            catch (InterruptedException ie) {
+                System.out.print("testThreadDaemons @ Interrupted!\n");
+            }
+            finally {
+                System.out.print("testThreadDaemons @ Thread bailing\n");
+            }
+        }
+    }
+
+    private static void testSleepZero() throws Exception {
+        Thread.currentThread().interrupt();
         try {
-            Thread.sleep(2000);
+            Thread.sleep(0);
+            throw new AssertionError("unreachable");
+        } catch (InterruptedException e) {
+            if (Thread.currentThread().isInterrupted()) {
+                throw new AssertionError("thread is interrupted");
+            }
         }
-        catch (InterruptedException ie) {
-            System.out.print("@ Interrupted!\n");
-        }
-        finally {
-            System.out.print("@ Thread bailing\n");
-        }
+        System.out.print("testSleepZero finished\n");
     }
 }