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);