Enable devirtualization for abstract and sub-class methods.

If we know the type of a receiver in the verifier we record devirtualization
data. Currently we only use this data to avoid virtual method dispatch when
we know the receiver of a method isn't a sub-class. This change allows
devirtualization of virtual and interface methods when we know the receiver's
type and the method the we'd find via dispatch is either known within boot or
has a reference from the current dex file.

Pass the receiver through to the method resolution trampoline as
devirtualization may mean the dex method index needs to be made more accurate
for the receiver.

Tidy up method devirtualization and related statistics.

Push the devirtualization map lookup into a less common case to avoid
taking its lock.

Make MethodReference a struct rather than a typedef of a pair, so the members
can have more meaningful names than first and second.

Rough statistics show that we devirtualize using this change around 2.5% of
the time, whilst some apps like GMS core devirtualize over 3.4% of the time.

Change-Id: Ieed3471dbedfc4cc881d652631b67176bb37d394
diff --git a/src/compiler/dex/mir_dataflow.cc b/src/compiler/dex/mir_dataflow.cc
index 9f61d73..f65c9ae 100644
--- a/src/compiler/dex/mir_dataflow.cc
+++ b/src/compiler/dex/mir_dataflow.cc
@@ -1237,17 +1237,17 @@
       return false;
   }
   DexCompilationUnit m_unit(cu_);
-  // TODO: add a flag so we don't counts the stats for this twice
-  uint32_t dex_method_idx = mir->dalvikInsn.vB;
+  CompilerDriver::MethodReference target_method(cu_->dex_file, mir->dalvikInsn.vB);
   int vtable_idx;
   uintptr_t direct_code;
   uintptr_t direct_method;
   uint32_t current_offset = static_cast<uint32_t>(current_offset_);
   bool fast_path =
-      cu_->compiler_driver->ComputeInvokeInfo(dex_method_idx, current_offset,
-                                              &m_unit, type,
-                                              vtable_idx, direct_code,
-                                              direct_method) &&
+      cu_->compiler_driver->ComputeInvokeInfo(&m_unit, current_offset,
+                                              type, target_method,
+                                              vtable_idx,
+                                              direct_code, direct_method,
+                                              false) &&
                                               !(cu_->enable_debug & (1 << kDebugSlowInvokePath));
   return (((type == kDirect) || (type == kStatic)) &&
           fast_path && ((direct_code == 0) || (direct_method == 0)));
diff --git a/src/compiler/dex/quick/gen_invoke.cc b/src/compiler/dex/quick/gen_invoke.cc
index afcd9ef..f44272a 100644
--- a/src/compiler/dex/quick/gen_invoke.cc
+++ b/src/compiler/dex/quick/gen_invoke.cc
@@ -311,7 +311,8 @@
  * emit the next instruction in static & direct invoke sequences.
  */
 static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info,
-                          int state, uint32_t dex_idx, uint32_t unused,
+                          int state, const CompilerDriver::MethodReference& target_method,
+                          uint32_t unused,
                           uintptr_t direct_code, uintptr_t direct_method,
                           InvokeType type)
 {
@@ -327,9 +328,11 @@
       if (direct_code != static_cast<unsigned int>(-1)) {
         cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code);
       } else {
-        LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_, dex_idx, 0);
+        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_, dex_idx);
+          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);
@@ -339,9 +342,11 @@
       if (direct_method != static_cast<unsigned int>(-1)) {
         cg->LoadConstant(cg->TargetReg(kArg0), direct_method);
       } else {
-        LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_, dex_idx, 0);
+        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_, dex_idx);
+          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);
@@ -366,9 +371,11 @@
         if (direct_code != static_cast<unsigned int>(-1)) {
           cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code);
         } else {
-          LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_, dex_idx, 0);
+          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_, dex_idx);
+            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);
@@ -378,8 +385,10 @@
       }
       break;
     case 2:  // Grab target method*
+      CHECK_EQ(cu->dex_file, target_method.dex_file);
       cg->LoadWordDisp(cg->TargetReg(kArg0),
-                       mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() + dex_idx * 4,
+                       mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
+                           (target_method.dex_method_index * 4),
                        cg-> TargetReg(kArg0));
       break;
     case 3:  // Grab the code from the method*
@@ -407,8 +416,9 @@
  * kArg1 here rather than the standard LoadArgRegs.
  */
 static int NextVCallInsn(CompilationUnit* cu, CallInfo* info,
-                         int state, uint32_t dex_idx, uint32_t method_idx,
-                         uintptr_t unused, uintptr_t unused2, InvokeType unused3)
+                         int state, const CompilerDriver::MethodReference& target_method,
+                         uint32_t method_idx, uintptr_t unused, uintptr_t unused2,
+                         InvokeType unused3)
 {
   Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
   /*
@@ -455,7 +465,8 @@
  * which will locate the target and continue on via a tail call.
  */
 static int NextInterfaceCallInsn(CompilationUnit* cu, CallInfo* info, int state,
-                                 uint32_t dex_idx, uint32_t unused, uintptr_t unused2,
+                                 const CompilerDriver::MethodReference& target_method,
+                                 uint32_t unused, uintptr_t unused2,
                                  uintptr_t direct_method, InvokeType unused4)
 {
   Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
@@ -476,9 +487,12 @@
         if (direct_method != static_cast<unsigned int>(-1)) {
           cg->LoadConstant(cg->TargetReg(kArg0), direct_method);
         } else {
-          LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_, dex_idx, 0);
+          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_, dex_idx);
+            data_target = cg->AddWordData(&cg->method_literal_list_,
+                                          target_method.dex_method_index);
             data_target->operands[1] = kInterface;
           }
           LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kArg0), data_target);
@@ -505,8 +519,10 @@
                        cg->TargetReg(kArg0));
       break;
     case 2:  // Grab target method* [set/use kArg0]
+      CHECK_EQ(cu->dex_file, target_method.dex_file);
       cg->LoadWordDisp(cg->TargetReg(kArg0),
-                       mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() + dex_idx * 4,
+                       mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
+                           (target_method.dex_method_index * 4),
                        cg->TargetReg(kArg0));
       break;
     default:
@@ -517,7 +533,8 @@
 }
 
 static int NextInvokeInsnSP(CompilationUnit* cu, CallInfo* info, int trampoline,
-                            int state, uint32_t dex_idx, uint32_t method_idx)
+                            int state, const CompilerDriver::MethodReference& target_method,
+                            uint32_t method_idx)
 {
   Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
   /*
@@ -530,58 +547,66 @@
       cg->LoadWordDisp(cg->TargetReg(kSelf), trampoline, cg->TargetReg(kInvokeTgt));
     }
     // Load kArg0 with method index
-    cg->LoadConstant(cg->TargetReg(kArg0), dex_idx);
+    CHECK_EQ(cu->dex_file, target_method.dex_file);
+    cg->LoadConstant(cg->TargetReg(kArg0), target_method.dex_method_index);
     return 1;
   }
   return -1;
 }
 
 static int NextStaticCallInsnSP(CompilationUnit* cu, CallInfo* info,
-                                int state, uint32_t dex_idx, uint32_t method_idx,
+                                int state,
+                                const CompilerDriver::MethodReference& target_method,
+                                uint32_t method_idx,
                                 uintptr_t unused, uintptr_t unused2,
-                         InvokeType unused3)
+                                InvokeType unused3)
 {
   int trampoline = ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck);
-  return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
+  return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
 }
 
 static int NextDirectCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
-                                uint32_t dex_idx, uint32_t method_idx, uintptr_t unused,
+                                const CompilerDriver::MethodReference& target_method,
+                                uint32_t method_idx, uintptr_t unused,
                                 uintptr_t unused2, InvokeType unused3)
 {
   int trampoline = ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck);
-  return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
+  return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
 }
 
 static int NextSuperCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
-                               uint32_t dex_idx, uint32_t method_idx, uintptr_t unused,
-                        uintptr_t unused2, InvokeType unused3)
+                               const CompilerDriver::MethodReference& target_method,
+                               uint32_t method_idx, uintptr_t unused,
+                               uintptr_t unused2, InvokeType unused3)
 {
   int trampoline = ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck);
-  return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
+  return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
 }
 
 static int NextVCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
-                           uint32_t dex_idx, uint32_t method_idx, uintptr_t unused,
+                           const CompilerDriver::MethodReference& target_method,
+                           uint32_t method_idx, uintptr_t unused,
                            uintptr_t unused2, InvokeType unused3)
 {
   int trampoline = ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck);
-  return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
+  return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
 }
 
 static int NextInterfaceCallInsnWithAccessCheck(CompilationUnit* cu,
                                                 CallInfo* info, int state,
-                                         uint32_t dex_idx, uint32_t unused,
-                                         uintptr_t unused2, uintptr_t unused3,
-                                         InvokeType unused4)
+                                                const CompilerDriver::MethodReference& target_method,
+                                                uint32_t unused,
+                                                uintptr_t unused2, uintptr_t unused3,
+                                                InvokeType unused4)
 {
   int trampoline = ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck);
-  return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
+  return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
 }
 
 int Mir2Lir::LoadArgRegs(CallInfo* info, int call_state,
-                         NextCallInsn next_call_insn, uint32_t dex_idx,
-                         uint32_t method_idx, uintptr_t direct_code,
+                         NextCallInsn next_call_insn,
+                         const CompilerDriver::MethodReference& target_method,
+                         uint32_t vtable_idx, uintptr_t direct_code,
                          uintptr_t direct_method, InvokeType type, bool skip_this)
 {
   int last_arg_reg = TargetReg(kArg3);
@@ -605,8 +630,8 @@
       }
       LoadValueDirectFixed(rl_arg, next_reg);
     }
-    call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
-                 direct_code, direct_method, type);
+    call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
+                                direct_code, direct_method, type);
   }
   return call_state;
 }
@@ -620,7 +645,8 @@
  */
 int Mir2Lir::GenDalvikArgsNoRange(CallInfo* info,
                                   int call_state, LIR** pcrLabel, NextCallInsn next_call_insn,
-                                  uint32_t dex_idx, uint32_t method_idx, uintptr_t direct_code,
+                                  const CompilerDriver::MethodReference& target_method,
+                                  uint32_t vtable_idx, uintptr_t direct_code,
                                   uintptr_t direct_method, InvokeType type, bool skip_this)
 {
   RegLocation rl_arg;
@@ -629,8 +655,8 @@
   if (info->num_arg_words == 0)
     return call_state;
 
-  call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
-                           direct_code, direct_method, type);
+  call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
+                              direct_code, direct_method, type);
 
   DCHECK_LE(info->num_arg_words, 5);
   if (info->num_arg_words > 3) {
@@ -650,13 +676,13 @@
         // kArg2 & rArg3 can safely be used here
         reg = TargetReg(kArg3);
         LoadWordDisp(TargetReg(kSp), SRegOffset(rl_arg.s_reg_low) + 4, reg);
-        call_state = next_call_insn(cu_, info, call_state, dex_idx,
-                                 method_idx, direct_code, direct_method, type);
+        call_state = next_call_insn(cu_, info, call_state, target_method,
+                                    vtable_idx, direct_code, direct_method, type);
       }
       StoreBaseDisp(TargetReg(kSp), (next_use + 1) * 4, reg, kWord);
       StoreBaseDisp(TargetReg(kSp), 16 /* (3+1)*4 */, reg, kWord);
-      call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
-                               direct_code, direct_method, type);
+      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
+                                  direct_code, direct_method, type);
       next_use++;
     }
     // Loop through the rest
@@ -676,8 +702,8 @@
         } else {
           LoadValueDirectFixed(rl_arg, low_reg);
         }
-        call_state = next_call_insn(cu_, info, call_state, dex_idx,
-                                 method_idx, direct_code, direct_method, type);
+        call_state = next_call_insn(cu_, info, call_state, target_method,
+                                    vtable_idx, direct_code, direct_method, type);
       }
       int outs_offset = (next_use + 1) * 4;
       if (rl_arg.wide) {
@@ -687,14 +713,14 @@
         StoreWordDisp(TargetReg(kSp), outs_offset, low_reg);
         next_use++;
       }
-      call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
+      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
                                direct_code, direct_method, type);
     }
   }
 
   call_state = LoadArgRegs(info, call_state, next_call_insn,
-                          dex_idx, method_idx, direct_code, direct_method,
-                          type, skip_this);
+                           target_method, vtable_idx, direct_code, direct_method,
+                           type, skip_this);
 
   if (pcrLabel) {
     *pcrLabel = GenNullCheck(info->args[0].s_reg_low, TargetReg(kArg1), info->opt_flags);
@@ -718,15 +744,16 @@
  *
  */
 int Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state,
-                                LIR** pcrLabel, NextCallInsn next_call_insn, uint32_t dex_idx,
-                                uint32_t method_idx, uintptr_t direct_code, uintptr_t direct_method,
+                                LIR** pcrLabel, NextCallInsn next_call_insn,
+                                const CompilerDriver::MethodReference& target_method,
+                                uint32_t vtable_idx, uintptr_t direct_code, uintptr_t direct_method,
                                 InvokeType type, bool skip_this)
 {
 
   // If we can treat it as non-range (Jumbo ops will use range form)
   if (info->num_arg_words <= 5)
     return GenDalvikArgsNoRange(info, call_state, pcrLabel,
-                                next_call_insn, dex_idx, method_idx,
+                                next_call_insn, target_method, vtable_idx,
                                 direct_code, direct_method, type, skip_this);
   /*
    * First load the non-register arguments.  Both forms expect all
@@ -772,31 +799,31 @@
     } else {
       // Use vldm/vstm pair using kArg3 as a temp
       int regs_left = std::min(info->num_arg_words - 3, 16);
-      call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
+      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
                                direct_code, direct_method, type);
       OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), start_offset);
       LIR* ld = OpVldm(TargetReg(kArg3), regs_left);
       //TUNING: loosen barrier
       ld->def_mask = ENCODE_ALL;
       SetMemRefType(ld, true /* is_load */, kDalvikReg);
-      call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
+      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
                                direct_code, direct_method, type);
       OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), 4 /* Method* */ + (3 * 4));
-      call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
+      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
                                direct_code, direct_method, type);
       LIR* st = OpVstm(TargetReg(kArg3), regs_left);
       SetMemRefType(st, false /* is_load */, kDalvikReg);
       st->def_mask = ENCODE_ALL;
-      call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
+      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
                                direct_code, direct_method, type);
     }
   }
 
   call_state = LoadArgRegs(info, call_state, next_call_insn,
-                          dex_idx, method_idx, direct_code, direct_method,
-                          type, skip_this);
+                           target_method, vtable_idx, direct_code, direct_method,
+                           type, skip_this);
 
-  call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
+  call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
                            direct_code, direct_method, type);
   if (pcrLabel) {
     *pcrLabel = GenNullCheck(info->args[0].s_reg_low, TargetReg(kArg1), info->opt_flags);
@@ -1327,20 +1354,24 @@
   // Explicit register usage
   LockCallTemps();
 
-  uint32_t dex_method_idx = info->index;
+  DexCompilationUnit* cUnit = mir_graph_->GetCurrentDexCompilationUnit();
+  CompilerDriver::MethodReference target_method(cUnit->GetDexFile(), info->index);
   int vtable_idx;
   uintptr_t direct_code;
   uintptr_t direct_method;
   bool skip_this;
-  bool fast_path = cu_->compiler_driver->ComputeInvokeInfo(
-      dex_method_idx, current_dalvik_offset_, mir_graph_->GetCurrentDexCompilationUnit(), info->type, vtable_idx,
-      direct_code, direct_method) && !SLOW_INVOKE_PATH;
+  bool fast_path =
+      cu_->compiler_driver->ComputeInvokeInfo(mir_graph_->GetCurrentDexCompilationUnit(),
+                                              current_dalvik_offset_,
+                                              info->type, target_method,
+                                              vtable_idx,
+                                              direct_code, direct_method,
+                                              true) && !SLOW_INVOKE_PATH;
   if (info->type == kInterface) {
     if (fast_path) {
       p_null_ck = &null_ck;
     }
-    next_call_insn = fast_path ? NextInterfaceCallInsn
-                            : NextInterfaceCallInsnWithAccessCheck;
+    next_call_insn = fast_path ? NextInterfaceCallInsn : NextInterfaceCallInsnWithAccessCheck;
     skip_this = false;
   } else if (info->type == kDirect) {
     if (fast_path) {
@@ -1362,20 +1393,20 @@
   }
   if (!info->is_range) {
     call_state = GenDalvikArgsNoRange(info, call_state, p_null_ck,
-                                     next_call_insn, dex_method_idx,
-                                     vtable_idx, direct_code, direct_method,
-                                     original_type, skip_this);
+                                      next_call_insn, target_method,
+                                      vtable_idx, direct_code, direct_method,
+                                      original_type, skip_this);
   } else {
     call_state = GenDalvikArgsRange(info, call_state, p_null_ck,
-                                   next_call_insn, dex_method_idx, vtable_idx,
-                                   direct_code, direct_method, original_type,
-                                   skip_this);
+                                    next_call_insn, target_method, vtable_idx,
+                                    direct_code, direct_method, original_type,
+                                    skip_this);
   }
   // Finish up any of the call sequence not interleaved in arg loading
   while (call_state >= 0) {
-    call_state = next_call_insn(cu_, info, call_state, dex_method_idx,
-                             vtable_idx, direct_code, direct_method,
-                             original_type);
+    call_state = next_call_insn(cu_, info, call_state, target_method,
+                                vtable_idx, direct_code, direct_method,
+                                original_type);
   }
   LIR* call_inst;
   if (cu_->instruction_set != kX86) {
diff --git a/src/compiler/dex/quick/mir_to_lir.h b/src/compiler/dex/quick/mir_to_lir.h
index 21a0aac..9a4f5d0 100644
--- a/src/compiler/dex/quick/mir_to_lir.h
+++ b/src/compiler/dex/quick/mir_to_lir.h
@@ -24,6 +24,7 @@
 #include "compiler/dex/backend.h"
 #include "compiler/dex/growable_array.h"
 #include "compiler/dex/arena_allocator.h"
+#include "compiler/driver/compiler_driver.h"
 #include "safe_map.h"
 
 namespace art {
@@ -98,7 +99,8 @@
 class MIRGraph;
 class Mir2Lir;
 
-typedef int (*NextCallInsn)(CompilationUnit*, CallInfo*, int, uint32_t dex_idx,
+typedef int (*NextCallInsn)(CompilationUnit*, CallInfo*, int,
+                            const CompilerDriver::MethodReference& target_method,
                             uint32_t method_idx, uintptr_t direct_code,
                             uintptr_t direct_method, InvokeType type);
 
@@ -462,11 +464,15 @@
     void GenInvoke(CallInfo* info);
     void FlushIns(RegLocation* ArgLocs, RegLocation rl_method);
     int GenDalvikArgsNoRange(CallInfo* info, int call_state, LIR** pcrLabel,
-                             NextCallInsn next_call_insn, uint32_t dex_idx, uint32_t method_idx,
+                             NextCallInsn next_call_insn,
+                             const CompilerDriver::MethodReference& target_method,
+                             uint32_t vtable_idx,
                              uintptr_t direct_code, uintptr_t direct_method, InvokeType type,
                              bool skip_this);
     int GenDalvikArgsRange(CallInfo* info, int call_state, LIR** pcrLabel,
-                           NextCallInsn next_call_insn, uint32_t dex_idx, uint32_t method_idx,
+                           NextCallInsn next_call_insn,
+                           const CompilerDriver::MethodReference& target_method,
+                           uint32_t vtable_idx,
                            uintptr_t direct_code, uintptr_t direct_method, InvokeType type,
                            bool skip_this);
     RegLocation InlineTarget(CallInfo* info);
@@ -486,7 +492,9 @@
                              bool is_volatile, bool is_ordered);
     bool GenIntrinsic(CallInfo* info);
     int LoadArgRegs(CallInfo* info, int call_state,
-                    NextCallInsn next_call_insn, uint32_t dex_idx, uint32_t method_idx,
+                    NextCallInsn next_call_insn,
+                    const CompilerDriver::MethodReference& target_method,
+                    uint32_t vtable_idx,
                     uintptr_t direct_code, uintptr_t direct_method, InvokeType type,
                     bool skip_this);
 
diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc
index 6985172..bf8bb8a 100644
--- a/src/compiler/driver/compiler_driver.cc
+++ b/src/compiler/driver/compiler_driver.cc
@@ -184,34 +184,43 @@
     unresolved_static_fields_++;
   }
 
+  // Indicate that type information from the verifier led to devirtualization.
   void PreciseTypeDevirtualization() {
     STATS_LOCK();
     type_based_devirtualization_++;
   }
+
+  // Indicate that a method of the given type was resolved at compile time.
   void ResolvedMethod(InvokeType type) {
     DCHECK_LE(type, kMaxInvokeType);
     STATS_LOCK();
     resolved_methods_[type]++;
   }
 
+  // Indicate that a method of the given type was unresolved at compile time as it was in an
+  // unknown dex file.
   void UnresolvedMethod(InvokeType type) {
     DCHECK_LE(type, kMaxInvokeType);
     STATS_LOCK();
     unresolved_methods_[type]++;
   }
 
+  // Indicate that a type of virtual method dispatch has been converted into a direct method
+  // dispatch.
   void VirtualMadeDirect(InvokeType type) {
-    DCHECK_LE(type, kMaxInvokeType);
+    DCHECK(type == kVirtual || type == kInterface || type == kSuper);
     STATS_LOCK();
     virtual_made_direct_[type]++;
   }
 
+  // Indicate that a method of the given type was able to call directly into boot.
   void DirectCallsToBoot(InvokeType type) {
     DCHECK_LE(type, kMaxInvokeType);
     STATS_LOCK();
     direct_calls_to_boot_[type]++;
   }
 
+  // Indicate that a method of the given type was able to be resolved directly from boot.
   void DirectMethodsToBoot(InvokeType type) {
     DCHECK_LE(type, kMaxInvokeType);
     STATS_LOCK();
@@ -312,6 +321,7 @@
       compiler_(NULL),
       compiler_context_(NULL),
       jni_compiler_(NULL),
+      compiler_enable_auto_elf_loading_(NULL),
       compiler_get_method_code_addr_(NULL)
 {
   std::string compiler_so_name(MakeCompilerSoName(compiler_backend_));
@@ -764,7 +774,8 @@
                                                    mirror::Class* referrer_class,
                                                    mirror::AbstractMethod* method,
                                                    uintptr_t& direct_code,
-                                                   uintptr_t& direct_method) {
+                                                   uintptr_t& direct_method,
+                                                   bool update_stats) {
   // For direct and static methods compute possible direct_code and direct_method values, ie
   // an address for the Method* being invoked and an address of the code for that Method*.
   // For interface calls compute a value for direct_method that is the interface method being
@@ -789,10 +800,12 @@
     // Ensure we run the clinit trampoline unless we are invoking a static method in the same class.
     return;
   }
-  if (sharp_type != kInterface) {  // Interfaces always go via a trampoline.
-    stats_->DirectCallsToBoot(type);
+  if (update_stats) {
+    if (sharp_type != kInterface) {  // Interfaces always go via a trampoline.
+      stats_->DirectCallsToBoot(type);
+    }
+    stats_->DirectMethodsToBoot(type);
   }
-  stats_->DirectMethodsToBoot(type);
   bool compiling_boot = Runtime::Current()->GetHeap()->GetSpaces().size() == 1;
   if (compiling_boot) {
     const bool kSupportBootImageFixup = true;
@@ -813,26 +826,24 @@
   }
 }
 
-bool CompilerDriver::ComputeInvokeInfo(uint32_t method_idx,const uint32_t dex_pc,
-                                       const DexCompilationUnit* mUnit, InvokeType& type,
-                                       int& vtable_idx, uintptr_t& direct_code,
-                                       uintptr_t& direct_method) {
+bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const uint32_t dex_pc,
+                                       InvokeType& invoke_type,
+                                       MethodReference& target_method,
+                                       int& vtable_idx,
+                                       uintptr_t& direct_code, uintptr_t& direct_method,
+                                       bool update_stats) {
   ScopedObjectAccess soa(Thread::Current());
-
-  const bool kEnableVerifierBasedSharpening = true;
-  const CompilerDriver::MethodReference ref_caller(mUnit->GetDexFile(), mUnit->GetDexMethodIndex());
-  const CompilerDriver::MethodReference* ref_sharpen = verifier::MethodVerifier::GetDevirtMap(ref_caller, dex_pc);
-  bool can_devirtualize = (dex_pc != art::kDexPCNotReady) && (ref_sharpen != NULL);
   vtable_idx = -1;
   direct_code = 0;
   direct_method = 0;
   mirror::AbstractMethod* resolved_method =
-      ComputeMethodReferencedFromCompilingMethod(soa, mUnit, method_idx, type);
+      ComputeMethodReferencedFromCompilingMethod(soa, mUnit, target_method.dex_method_index,
+                                                 invoke_type);
   if (resolved_method != NULL) {
     // Don't try to fast-path if we don't understand the caller's class or this appears to be an
     // Incompatible Class Change Error.
     mirror::Class* referrer_class = ComputeCompilingMethodsClass(soa, mUnit);
-    bool icce = resolved_method->CheckIncompatibleClassChange(type);
+    bool icce = resolved_method->CheckIncompatibleClassChange(invoke_type);
     if (referrer_class != NULL && !icce) {
       mirror::Class* methods_class = resolved_method->GetDeclaringClass();
       if (!referrer_class->CanAccess(methods_class) ||
@@ -842,71 +853,151 @@
         // protected method being made public by implementing an interface that re-declares the
         // method public. Resort to the dex file to determine the correct class for the access
         // check.
-        const DexFile& dex_file = *referrer_class->GetDexCache()->GetDexFile();
-        methods_class =
-            mUnit->GetClassLinker()->ResolveType(dex_file,
-                                                 dex_file.GetMethodId(method_idx).class_idx_,
-                                                 referrer_class);
+        uint16_t class_idx =
+            target_method.dex_file->GetMethodId(target_method.dex_method_index).class_idx_;
+        methods_class = mUnit->GetClassLinker()->ResolveType(*target_method.dex_file,
+                                                             class_idx, referrer_class);
       }
       if (referrer_class->CanAccess(methods_class) &&
           referrer_class->CanAccessMember(methods_class, resolved_method->GetAccessFlags())) {
-        vtable_idx = resolved_method->GetMethodIndex();
-        const bool kEnableSharpening = true;
-        // Sharpen a virtual call into a direct call when the target is known.
-        bool can_sharpen = type == kVirtual && (resolved_method->IsFinal() ||
-            methods_class->IsFinal());
-        // Ensure the vtable index will be correct to dispatch in the vtable of the super class.
-        can_sharpen = can_sharpen || (type == kSuper && referrer_class != methods_class &&
-            referrer_class->IsSubClass(methods_class) &&
-            vtable_idx < methods_class->GetVTable()->GetLength() &&
-            methods_class->GetVTable()->Get(vtable_idx) == resolved_method);
+        const bool kEnableFinalBasedSharpening = true;
+        // Sharpen a virtual call into a direct call when the target is known not to have been
+        // overridden (ie is final).
+        bool can_sharpen_virtual_based_on_type =
+            (invoke_type == kVirtual) && (resolved_method->IsFinal() || methods_class->IsFinal());
+        // For invoke-super, ensure the vtable index will be correct to dispatch in the vtable of
+        // the super class.
+        bool can_sharpen_super_based_on_type = (invoke_type == kSuper) &&
+            (referrer_class != methods_class) && referrer_class->IsSubClass(methods_class) &&
+            resolved_method->GetMethodIndex() < methods_class->GetVTable()->GetLength() &&
+            (methods_class->GetVTable()->Get(resolved_method->GetMethodIndex()) == resolved_method);
 
-        if (kEnableSharpening && can_sharpen) {
-          stats_->ResolvedMethod(type);
+        if (kEnableFinalBasedSharpening && (can_sharpen_virtual_based_on_type ||
+                                            can_sharpen_super_based_on_type)) {
           // Sharpen a virtual call into a direct call. The method_idx is into referrer's
           // dex cache, check that this resolved method is where we expect it.
-          CHECK(referrer_class->GetDexCache()->GetResolvedMethod(method_idx) == resolved_method)
-              << PrettyMethod(resolved_method);
-          stats_->VirtualMadeDirect(type);
-          GetCodeAndMethodForDirectCall(type, kDirect, referrer_class, resolved_method,
-                                        direct_code, direct_method);
-          type = kDirect;
+          CHECK(referrer_class->GetDexCache()->GetResolvedMethod(target_method.dex_method_index) ==
+                resolved_method) << PrettyMethod(resolved_method);
+          if (update_stats) {
+            stats_->ResolvedMethod(invoke_type);
+            stats_->VirtualMadeDirect(invoke_type);
+          }
+          GetCodeAndMethodForDirectCall(invoke_type, kDirect, referrer_class, resolved_method,
+                                        direct_code, direct_method, update_stats);
+          invoke_type = kDirect;
           return true;
-        } else if(can_devirtualize && kEnableSharpening && kEnableVerifierBasedSharpening) {
-            // If traditional sharpening fails, try the sharpening based on type information (Devirtualization)
-            mirror::DexCache* dex_cache = mUnit->GetClassLinker()->FindDexCache(*ref_sharpen->first);
-            mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader());
-            mirror::AbstractMethod* concrete_method = mUnit->GetClassLinker()->ResolveMethod(
-                *ref_sharpen->first, ref_sharpen->second, dex_cache, class_loader, NULL, kVirtual);
-            CHECK(concrete_method != NULL);
-            CHECK(!concrete_method->IsAbstract());
-            // TODO: fix breakage in image patching to be able to devirtualize cases with different
-            // resolved and concrete methods.
-            if(resolved_method == concrete_method) {
-              GetCodeAndMethodForDirectCall(type, kDirect, referrer_class, concrete_method, direct_code, direct_method);
-              stats_->VirtualMadeDirect(type);
-              type = kDirect;
-              stats_->PreciseTypeDevirtualization();
-            }
-            stats_->ResolvedMethod(type);
-            return true;
         }
-        else if (type == kSuper) {
+        const bool kEnableVerifierBasedSharpening = true;
+        if (kEnableVerifierBasedSharpening && (invoke_type == kVirtual ||
+                                               invoke_type == kInterface)) {
+          // Did the verifier record a more precise invoke target based on its type information?
+          const CompilerDriver::MethodReference caller_method(mUnit->GetDexFile(),
+                                                              mUnit->GetDexMethodIndex());
+          const CompilerDriver::MethodReference* devirt_map_target =
+              verifier::MethodVerifier::GetDevirtMap(caller_method, dex_pc);
+          if (devirt_map_target != NULL) {
+            mirror::DexCache* target_dex_cache =
+                mUnit->GetClassLinker()->FindDexCache(*devirt_map_target->dex_file);
+            mirror::ClassLoader* class_loader =
+                soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader());
+            mirror::AbstractMethod* called_method =
+                mUnit->GetClassLinker()->ResolveMethod(*devirt_map_target->dex_file,
+                                                       devirt_map_target->dex_method_index,
+                                                       target_dex_cache, class_loader, NULL,
+                                                       kVirtual);
+            CHECK(called_method != NULL);
+            CHECK(!called_method->IsAbstract());
+            GetCodeAndMethodForDirectCall(invoke_type, kDirect, referrer_class, called_method,
+                                          direct_code, direct_method, update_stats);
+            bool compiler_needs_dex_cache =
+                (GetCompilerBackend() == kQuick && instruction_set_ != kThumb2) ||
+                (direct_code == 0) || (direct_code == static_cast<unsigned int>(-1)) ||
+                (direct_method == 0) || (direct_method == static_cast<unsigned int>(-1));
+            if ((devirt_map_target->dex_file != target_method.dex_file) &&
+                compiler_needs_dex_cache) {
+              // We need to use the dex cache to find either the method or code, and the dex file
+              // containing the method isn't the one expected for the target method. Try to find
+              // the method within the expected target dex file.
+              // TODO: the -1 could be handled as direct code if the patching new the target dex
+              //       file.
+              // TODO: quick only supports direct pointers with Thumb2.
+              // TODO: the following should be factored into a common helper routine to find
+              //       one dex file's method within another.
+              const DexFile* dexfile = target_method.dex_file;
+              const DexFile* cm_dexfile =
+                  called_method->GetDeclaringClass()->GetDexCache()->GetDexFile();
+              const DexFile::MethodId& cm_method_id =
+                  cm_dexfile->GetMethodId(called_method->GetDexMethodIndex());
+              const char* cm_descriptor = cm_dexfile->StringByTypeIdx(cm_method_id.class_idx_);
+              const DexFile::StringId* descriptor = dexfile->FindStringId(cm_descriptor);
+              if (descriptor != NULL) {
+                const DexFile::TypeId* type_id =
+                    dexfile->FindTypeId(dexfile->GetIndexForStringId(*descriptor));
+                if (type_id != NULL) {
+                  const char* cm_name = cm_dexfile->GetMethodName(cm_method_id);
+                  const DexFile::StringId* name = dexfile->FindStringId(cm_name);
+                  if (name != NULL) {
+                    uint16_t return_type_idx;
+                    std::vector<uint16_t> param_type_idxs;
+                    bool success = dexfile->CreateTypeList(&return_type_idx, &param_type_idxs,
+                                                           cm_dexfile->GetMethodSignature(cm_method_id));
+                    if (success) {
+                      const DexFile::ProtoId* sig =
+                          dexfile->FindProtoId(return_type_idx, param_type_idxs);
+                      if (sig != NULL) {
+                        const  DexFile::MethodId* method_id = dexfile->FindMethodId(*type_id,
+                                                                                    *name, *sig);
+                        if (method_id != NULL) {
+                          if (update_stats) {
+                            stats_->ResolvedMethod(invoke_type);
+                            stats_->VirtualMadeDirect(invoke_type);
+                            stats_->PreciseTypeDevirtualization();
+                          }
+                          target_method.dex_method_index = dexfile->GetIndexForMethodId(*method_id);
+                          invoke_type = kDirect;
+                          return true;
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            } else {
+              if (update_stats) {
+                stats_->ResolvedMethod(invoke_type);
+                stats_->VirtualMadeDirect(invoke_type);
+                stats_->PreciseTypeDevirtualization();
+              }
+              target_method = *devirt_map_target;
+              invoke_type = kDirect;
+              return true;
+            }
+          }
+        }
+        if (invoke_type == kSuper) {
           // Unsharpened super calls are suspicious so go slow-path.
         } else {
-          stats_->ResolvedMethod(type);
-          GetCodeAndMethodForDirectCall(type, type, referrer_class, resolved_method,
-                                        direct_code, direct_method);
+          // Sharpening failed so generate a regular resolved method dispatch.
+          if (update_stats) {
+            stats_->ResolvedMethod(invoke_type);
+          }
+          if (invoke_type == kVirtual || invoke_type == kSuper) {
+            vtable_idx = resolved_method->GetMethodIndex();
+          }
+          GetCodeAndMethodForDirectCall(invoke_type, invoke_type, referrer_class, resolved_method,
+                                        direct_code, direct_method, update_stats);
           return true;
         }
       }
     }
   }
-  // Clean up any exception left by method/type resolution
+  // Clean up any exception left by method/invoke_type resolution
   if (soa.Self()->IsExceptionPending()) {
       soa.Self()->ClearException();
   }
-  stats_->UnresolvedMethod(type);
+  if (update_stats) {
+    stats_->UnresolvedMethod(invoke_type);
+  }
   return false;  // Incomplete knowledge needs slow path.
 }
 
diff --git a/src/compiler/driver/compiler_driver.h b/src/compiler/driver/compiler_driver.h
index 75d276d..250532b 100644
--- a/src/compiler/driver/compiler_driver.h
+++ b/src/compiler/driver/compiler_driver.h
@@ -39,7 +39,6 @@
 class DexCompilationUnit;
 class TimingLogger;
 
-const uint32_t kDexPCNotReady = 0xFFFFFF;
 enum CompilerBackend {
   kQuick,
   kPortable,
@@ -106,7 +105,22 @@
       LOCKS_EXCLUDED(compiled_classes_lock_);
 
   // A method is uniquely located by its DexFile and the method_ids_ table index into that DexFile
-  typedef std::pair<const DexFile*, uint32_t> MethodReference;
+  struct MethodReference {
+    MethodReference(const DexFile* file, uint32_t index) : dex_file(file), dex_method_index(index) {
+    }
+    const DexFile* dex_file;
+    uint32_t dex_method_index;
+  };
+
+  struct MethodReferenceComparator {
+    bool operator()(MethodReference mr1, MethodReference mr2) const {
+      if (mr1.dex_file == mr2.dex_file) {
+        return mr1.dex_method_index < mr2.dex_method_index;
+      } else {
+        return mr1.dex_file < mr2.dex_file;
+      }
+    }
+  };
 
   CompiledMethod* GetCompiledMethod(MethodReference ref) const
       LOCKS_EXCLUDED(compiled_methods_lock_);
@@ -146,9 +160,9 @@
 
   // Can we fastpath a interface, super class or virtual method call? Computes method's vtable
   // index.
-  bool ComputeInvokeInfo(uint32_t method_idx, uint32_t dex_pc,
-                         const DexCompilationUnit* mUnit, InvokeType& type, int& vtable_idx,
-                         uintptr_t& direct_code, uintptr_t& direct_method)
+  bool ComputeInvokeInfo(const DexCompilationUnit* mUnit, const uint32_t dex_pc,
+                         InvokeType& type, MethodReference& target_method, int& vtable_idx,
+                         uintptr_t& direct_code, uintptr_t& direct_method, bool update_stats)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
   // Record patch information for later fix up.
@@ -262,7 +276,8 @@
   void GetCodeAndMethodForDirectCall(InvokeType type, InvokeType sharp_type,
                                      mirror::Class* referrer_class,
                                      mirror::AbstractMethod* method,
-                                     uintptr_t& direct_code, uintptr_t& direct_method)
+                                     uintptr_t& direct_code, uintptr_t& direct_method,
+                                     bool update_stats)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
@@ -321,7 +336,7 @@
   mutable Mutex compiled_classes_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   ClassTable compiled_classes_ GUARDED_BY(compiled_classes_lock_);
 
-  typedef SafeMap<const MethodReference, CompiledMethod*> MethodTable;
+  typedef SafeMap<const MethodReference, CompiledMethod*, MethodReferenceComparator> MethodTable;
   // All method references that this compiler has compiled.
   mutable Mutex compiled_methods_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   MethodTable compiled_methods_ GUARDED_BY(compiled_methods_lock_);
diff --git a/src/compiler/llvm/gbc_expander.cc b/src/compiler/llvm/gbc_expander.cc
index 99c8fd5..bdf9aca 100644
--- a/src/compiler/llvm/gbc_expander.cc
+++ b/src/compiler/llvm/gbc_expander.cc
@@ -776,7 +776,8 @@
   art::InvokeType invoke_type =
       static_cast<art::InvokeType>(LV2UInt(call_inst.getArgOperand(0)));
   bool is_static = (invoke_type == art::kStatic);
-  uint32_t callee_method_idx = LV2UInt(call_inst.getArgOperand(1));
+  art::CompilerDriver::MethodReference target_method(dex_compilation_unit_->GetDexFile(),
+                                                     LV2UInt(call_inst.getArgOperand(1)));
 
   // Load *this* actual parameter
   llvm::Value* this_addr = (!is_static) ? call_inst.getArgOperand(3) : NULL;
@@ -785,18 +786,17 @@
   int vtable_idx = -1;
   uintptr_t direct_code = 0;
   uintptr_t direct_method = 0;
-  // TODO: pass actual value of dex PC (instead of kDexPCNotready) needed by verifier based
-  // sharpening after LLVM re-factoring is finished.
-  bool is_fast_path = driver_->
-      ComputeInvokeInfo(callee_method_idx, art::kDexPCNotReady, dex_compilation_unit_,
-                        invoke_type, vtable_idx, direct_code, direct_method);
-
+  bool is_fast_path = driver_->ComputeInvokeInfo(dex_compilation_unit_, dex_pc,
+                                                 invoke_type, target_method,
+                                                 vtable_idx,
+                                                 direct_code, direct_method,
+                                                 true);
   // Load the method object
   llvm::Value* callee_method_object_addr = NULL;
 
   if (!is_fast_path) {
     callee_method_object_addr =
-        EmitCallRuntimeForCalleeMethodObjectAddr(callee_method_idx, invoke_type,
+        EmitCallRuntimeForCalleeMethodObjectAddr(target_method.dex_method_index, invoke_type,
                                                  this_addr, dex_pc, is_fast_path);
   } else {
     switch (invoke_type) {
@@ -809,7 +809,7 @@
                                   irb_.getJObjectTy());
         } else {
           callee_method_object_addr =
-              EmitLoadSDCalleeMethodObjectAddr(callee_method_idx);
+              EmitLoadSDCalleeMethodObjectAddr(target_method.dex_method_index);
         }
         break;
 
@@ -826,7 +826,7 @@
 
       case art::kInterface:
         callee_method_object_addr =
-            EmitCallRuntimeForCalleeMethodObjectAddr(callee_method_idx,
+            EmitCallRuntimeForCalleeMethodObjectAddr(target_method.dex_method_index,
                                                      invoke_type, this_addr,
                                                      dex_pc, is_fast_path);
         break;
@@ -844,7 +844,7 @@
 
   llvm::Value* code_addr;
   llvm::Type* func_type = GetFunctionType(call_inst.getType(),
-                                          callee_method_idx, is_static);
+                                          target_method.dex_method_index, is_static);
   if (direct_code != 0u && direct_code != static_cast<uintptr_t>(-1)) {
     code_addr =
         irb_.CreateIntToPtr(irb_.getPtrEquivInt(direct_code),
diff --git a/src/oat/runtime/arm/runtime_support_arm.S b/src/oat/runtime/arm/runtime_support_arm.S
index 3578ba0..b8d2265 100644
--- a/src/oat/runtime/arm/runtime_support_arm.S
+++ b/src/oat/runtime/arm/runtime_support_arm.S
@@ -258,9 +258,9 @@
     sub    sp, #12                        @ pad stack pointer to align frame
     .pad #12
     .cfi_adjust_cfa_offset 12
-    mov    r2, r9                         @ pass Thread::Current
-    mov    r1, sp                         @ pass stack pointer
-    blx    artPortableResolutionTrampoline   @ (method_idx, sp, Thread*)
+    mov    r3, r9                         @ pass Thread::Current
+    mov    r2, sp                         @ pass stack pointer
+    blx    artPortableResolutionTrampoline   @ (method, receiver, sp, Thread*)
     mov    r12, r0                        @ save method code pointer result
     add    sp, #12                        @ remove padding from stack pointer
     .cfi_adjust_cfa_offset -12
@@ -277,9 +277,9 @@
      .extern artQuickResolutionTrampoline
 ENTRY art_quick_resolution_trampoline
     SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME  @ save callee saves in case allocation triggers GC
-    mov    r2, r9                         @ pass Thread::Current
-    mov    r1, sp                         @ pass stack pointer
-    blx    artQuickResolutionTrampoline   @ (method_idx, sp, Thread*)
+    mov    r3, r9                         @ pass Thread::Current
+    mov    r2, sp                         @ pass stack pointer
+    blx    artQuickResolutionTrampoline   @ (called method, receiver, sp, Thread*)
     mov    r12, r0                        @ save method code pointer result
     add    sp, #4                         @ set up stack pointer
     .cfi_adjust_cfa_offset -4
diff --git a/src/oat/runtime/mips/runtime_support_mips.S b/src/oat/runtime/mips/runtime_support_mips.S
index 2144e34..2eeb662 100644
--- a/src/oat/runtime/mips/runtime_support_mips.S
+++ b/src/oat/runtime/mips/runtime_support_mips.S
@@ -430,9 +430,9 @@
     .cfi_rel_offset 5, 4
     sw     $a0, 0($sp)
     .cfi_rel_offset 4, 0
-    move  $a2, $s1              # pass Thread::Current()
-    jal   artPortableResolutionTrampoline  # (method_idx, sp, Thread*)
-    move  $a1, $sp              # pass stack pointer
+    move  $a3, $s1              # pass Thread::Current()
+    jal   artPortableResolutionTrampoline  # (method, receiver, sp, Thread*)
+    move  $a2, $sp              # pass stack pointer
     lw    $a0, 0($sp)           # restore registers from stack
     lw    $a1, 4($sp)
     lw    $a2, 8($sp)
@@ -455,9 +455,9 @@
 ENTRY art_quick_resolution_trampoline
     GENERATE_GLOBAL_POINTER
     SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
-    move  $a2, $s1              # pass Thread::Current()
-    jal   artQuickResolutionTrampoline  # (method_idx, sp, Thread*)
-    move  $a1, $sp              # pass stack pointer
+    move  $a3, $s1              # pass Thread::Current()
+    jal   artQuickResolutionTrampoline  # (method, receiver, sp, Thread*)
+    move  $a2, $sp              # pass stack pointer
     move  $t9, $v0              # put method code result in $t9
     lw    $a0, 0($sp)           # restore registers from stack
     lw    $a1, 4($sp)
diff --git a/src/oat/runtime/support_stubs.cc b/src/oat/runtime/support_stubs.cc
index df2dda2..97d5f66 100644
--- a/src/oat/runtime/support_stubs.cc
+++ b/src/oat/runtime/support_stubs.cc
@@ -32,6 +32,7 @@
 
 // Lazily resolve a method for portable. Called by stub code.
 extern "C" const void* artPortableResolutionTrampoline(mirror::AbstractMethod* called,
+                                                       mirror::Object* receiver,
                                                        mirror::AbstractMethod** called_addr,
                                                        Thread* thread)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -79,6 +80,14 @@
         invoke_type = kVirtual;
         is_range = true;
         break;
+      case Instruction::INVOKE_INTERFACE:
+        invoke_type = kInterface;
+        is_range = false;
+        break;
+      case Instruction::INVOKE_INTERFACE_RANGE:
+        invoke_type = kInterface;
+        is_range = true;
+        break;
       default:
         LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(NULL);
         // Avoid used uninitialized warnings.
@@ -87,6 +96,12 @@
     }
     uint32_t dex_method_idx = (is_range) ? instr->VRegB_3rc() : instr->VRegB_35c();
     called = linker->ResolveMethod(dex_method_idx, caller, invoke_type);
+    // Refine called method based on receiver.
+    if (invoke_type == kVirtual) {
+      called = receiver->GetClass()->FindVirtualMethodForVirtual(called);
+    } else if (invoke_type == kInterface) {
+      called = receiver->GetClass()->FindVirtualMethodForInterface(called);
+    }
   } else {
     CHECK(called->IsStatic()) << PrettyMethod(called);
     invoke_type = kStatic;
@@ -138,6 +153,7 @@
 
 // Lazily resolve a method for quick. Called by stub code.
 extern "C" const void* artQuickResolutionTrampoline(mirror::AbstractMethod* called,
+                                                    mirror::Object* receiver,
                                                     mirror::AbstractMethod** sp, Thread* thread)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
 #if defined(__arm__)
@@ -261,6 +277,14 @@
         invoke_type = kVirtual;
         is_range = true;
         break;
+      case Instruction::INVOKE_INTERFACE:
+        invoke_type = kInterface;
+        is_range = false;
+        break;
+      case Instruction::INVOKE_INTERFACE_RANGE:
+        invoke_type = kInterface;
+        is_range = true;
+        break;
       default:
         LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(NULL);
         // Avoid used uninitialized warnings.
@@ -334,6 +358,12 @@
   if (LIKELY(!thread->IsExceptionPending())) {
     // Incompatible class change should have been handled in resolve method.
     CHECK(!called->CheckIncompatibleClassChange(invoke_type));
+    // Refine called method based on receiver.
+    if (invoke_type == kVirtual) {
+      called = receiver->GetClass()->FindVirtualMethodForVirtual(called);
+    } else if (invoke_type == kInterface) {
+      called = receiver->GetClass()->FindVirtualMethodForInterface(called);
+    }
     // Ensure that the called method's class is initialized.
     mirror::Class* called_class = called->GetDeclaringClass();
     linker->EnsureInitialized(called_class, true, true);
diff --git a/src/oat/runtime/x86/runtime_support_x86.S b/src/oat/runtime/x86/runtime_support_x86.S
index d3a1fb7..734aad1 100644
--- a/src/oat/runtime/x86/runtime_support_x86.S
+++ b/src/oat/runtime/x86/runtime_support_x86.S
@@ -312,9 +312,10 @@
     movl 8(%ebp), %eax            // load the called method* into %eax
     leal 8(%ebp), %edx            // put the called method* address in %edx
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
-    PUSH edx                      // pass called method* address
-    PUSH eax                      // pass method*
-    call SYMBOL(artPortableResolutionTrampoline)  // (method_idx, sp, Thread*)
+    pushl %edx                    // pass called method* address
+    pushl 12(%ebp)                // pass receiver
+    pushl 8(%ebp)                 // pass method*
+    call SYMBOL(artPortableResolutionTrampoline)  // (method, receiver, sp, Thread*)
     leave                         // restore the stack and %ebp
     .cfi_def_cfa esp, 4
     .cfi_restore ebp
@@ -330,11 +331,11 @@
      */
 DEFINE_FUNCTION art_quick_resolution_trampoline
     SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
-    movl %esp, %ecx               // save stack pointer
-    PUSH eax                      // align stack
+    movl %esp, %edx               // save stack pointer
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
     .cfi_adjust_cfa_offset 4
-    PUSH ecx                      // pass stack pointer
+    PUSH edx                      // pass stack pointer
+    PUSH ecx                      // pass receiver
     PUSH eax                      // pass method*
     call SYMBOL(artQuickResolutionTrampoline)  // (method_idx, sp, Thread*)
     movl %eax, %edi               // save returned code pointer in %edi
diff --git a/src/verifier/method_verifier.cc b/src/verifier/method_verifier.cc
index 90f5b41..1b2d9f3 100644
--- a/src/verifier/method_verifier.cc
+++ b/src/verifier/method_verifier.cc
@@ -3355,14 +3355,15 @@
   MutexLock mu(Thread::Current(), *dex_gc_maps_lock_);
   DexGcMapTable::const_iterator it = dex_gc_maps_->find(ref);
   if (it == dex_gc_maps_->end()) {
-    LOG(WARNING) << "Didn't find GC map for: " << PrettyMethod(ref.second, *ref.first);
+    LOG(WARNING) << "Didn't find GC map for: " << PrettyMethod(ref.dex_method_index, *ref.dex_file);
     return NULL;
   }
   CHECK(it->second != NULL);
   return it->second;
 }
 
-const CompilerDriver::MethodReference* MethodVerifier::GetDevirtMap(CompilerDriver::MethodReference ref, uint32_t pc) {
+const CompilerDriver::MethodReference* MethodVerifier::GetDevirtMap(const CompilerDriver::MethodReference& ref,
+                                                                    uint32_t dex_pc) {
   MutexLock mu(Thread::Current(), *devirt_maps_lock_);
   DevirtualizationMapTable::const_iterator it = devirt_maps_->find(ref);
   if (it == devirt_maps_->end()) {
@@ -3370,7 +3371,7 @@
   }
 
   // Look up the PC in the map, get the concrete method to execute and return its reference.
-  MethodVerifier::PcToConreteMethod::const_iterator pc_to_concrete_method = it->second->find(pc);
+  MethodVerifier::PcToConreteMethod::const_iterator pc_to_concrete_method = it->second->find(dex_pc);
   if(pc_to_concrete_method != it->second->end()) {
     return &(pc_to_concrete_method->second);
   } else {
diff --git a/src/verifier/method_verifier.h b/src/verifier/method_verifier.h
index ab7e3cc..755d089 100644
--- a/src/verifier/method_verifier.h
+++ b/src/verifier/method_verifier.h
@@ -187,7 +187,8 @@
   static const std::vector<uint8_t>* GetDexGcMap(CompilerDriver::MethodReference ref)
       LOCKS_EXCLUDED(dex_gc_maps_lock_);
 
-  static const CompilerDriver::MethodReference* GetDevirtMap(CompilerDriver::MethodReference ref, uint32_t pc)
+  static const CompilerDriver::MethodReference* GetDevirtMap(const CompilerDriver::MethodReference& ref,
+                                                             uint32_t dex_pc)
       LOCKS_EXCLUDED(devirt_maps_lock_);
 
   // Fills 'monitor_enter_dex_pcs' with the dex pcs of the monitor-enter instructions corresponding
@@ -574,7 +575,8 @@
   InstructionFlags* CurrentInsnFlags();
 
   // All the GC maps that the verifier has created
-  typedef SafeMap<const CompilerDriver::MethodReference, const std::vector<uint8_t>*> DexGcMapTable;
+  typedef SafeMap<const CompilerDriver::MethodReference, const std::vector<uint8_t>*,
+      CompilerDriver::MethodReferenceComparator> DexGcMapTable;
   static Mutex* dex_gc_maps_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   static DexGcMapTable* dex_gc_maps_ GUARDED_BY(dex_gc_maps_lock_);
   static void SetDexGcMap(CompilerDriver::MethodReference ref, const std::vector<uint8_t>& dex_gc_map)
@@ -583,8 +585,8 @@
 
   // Devirtualization map.
   typedef SafeMap<const uint32_t, CompilerDriver::MethodReference> PcToConreteMethod;
-  typedef SafeMap<const CompilerDriver::MethodReference, const PcToConreteMethod*>
-      DevirtualizationMapTable;
+  typedef SafeMap<const CompilerDriver::MethodReference, const PcToConreteMethod*,
+      CompilerDriver::MethodReferenceComparator> DevirtualizationMapTable;
   MethodVerifier::PcToConreteMethod* GenerateDevirtMap()
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);