Support Direct Method/Type access for X86

Thumb generates code to optimize calls to methods within core.oat.
Implement this for X86 as well, but take advantage of mov with 32 bit
immediate and call relative with 32 bit immediate.

Fix some incorrect return locations for long inlines.

Change-Id: I1907bdfc7574f3d0aa76c7fad13dc537acdf1ed3
Signed-off-by: Mark Mendell <mark.p.mendell@intel.com>
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/gen_common.cc b/compiler/dex/quick/gen_common.cc
index c59f3b8..901d722 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);
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index 6aaad66..4e18278 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;
@@ -1094,7 +1070,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);
@@ -1308,7 +1284,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 +1412,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..22d4385 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();
@@ -737,6 +737,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.
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..59f07e1 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -245,6 +245,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 +327,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 +368,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 +491,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..c657fda 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) {
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..74c4c2f 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -365,7 +365,7 @@
       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 +1396,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..e9b695b 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -238,6 +238,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,
@@ -362,8 +371,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 +393,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 +402,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 {
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();