Move FindDexMethodIndexInOtherDexFile into ArtMethod.

Move FindDexMethodIndexInOtherDexFile out of MethodHelper into ArtMethod in
preparation for the removal of MethodHelper.
Tidy ClassLinker::ResolveMethod so that all exception paths flow through the
exception pending assertion.
Tidy artQuickResolutionTrampoline to be more explicit about variable names and
only update the dex cache if necessary.

Change-Id: I3e48eb4f6c1291533067c1b53efe90c53bfcaea8
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 6d7713f..1993c23 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -35,7 +35,6 @@
 #include "dex/quick/dex_file_method_inliner.h"
 #include "driver/compiler_options.h"
 #include "jni_internal.h"
-#include "method_helper.h"
 #include "object_lock.h"
 #include "profiler.h"
 #include "runtime.h"
@@ -1195,11 +1194,10 @@
     target_method->dex_method_index = method->GetDexMethodIndex();
   } else {
     if (no_guarantee_of_dex_cache_entry) {
-      StackHandleScope<1> hs(Thread::Current());
-      MethodHelper mh(hs.NewHandle(method));
       // See if the method is also declared in this dex cache.
-      uint32_t dex_method_idx = mh.FindDexMethodIndexInOtherDexFile(
-          *target_method->dex_file, target_method->dex_method_index);
+      uint32_t dex_method_idx =
+          method->FindDexMethodIndexInOtherDexFile(*target_method->dex_file,
+                                                   target_method->dex_method_index);
       if (dex_method_idx != DexFile::kDexNoIndex) {
         target_method->dex_method_index = dex_method_idx;
       } else {
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 4bd702d..52e6662 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1671,6 +1671,7 @@
       LOG(FATAL) << "Failed to open dex file " << dex_file_location
                  << " from within oat file " << oat_file.GetLocation()
                  << " error '" << error_msg << "'";
+      UNREACHABLE();
     }
 
     CHECK_EQ(dex_file->GetLocationChecksum(), oat_dex_file->GetDexFileLocationChecksum());
@@ -2393,6 +2394,7 @@
           break;
         default:
           LOG(FATAL) << "Unknown descriptor: " << c;
+          UNREACHABLE();
       }
     }
   }
@@ -2442,7 +2444,7 @@
   }
   DCHECK(!it.HasNext());
   LOG(FATAL) << "Failed to find method index " << method_idx << " in " << dex_file.GetLocation();
-  return 0;
+  UNREACHABLE();
 }
 
 const OatFile::OatMethod ClassLinker::FindOatMethodFor(mirror::ArtMethod* method, bool* found) {
@@ -3078,7 +3080,7 @@
     LOG(ERROR) << "Registered dex file " << i << " = " << dex_cache->GetDexFile()->GetLocation();
   }
   LOG(FATAL) << "Failed to find DexCache for DexFile " << location;
-  return nullptr;
+  UNREACHABLE();
 }
 
 void ClassLinker::FixupDexCaches(mirror::ArtMethod* resolution_method) {
@@ -3749,8 +3751,7 @@
   LOG(FATAL) << "Unexpected class status: " << oat_file_class_status
              << " " << dex_file.GetLocation() << " " << PrettyClass(klass) << " "
              << klass->GetDescriptor(&temp);
-
-  return false;
+  UNREACHABLE();
 }
 
 void ClassLinker::ResolveClassExceptionHandlerTypes(const DexFile& dex_file,
@@ -5566,71 +5567,73 @@
       }
 
       // If we found something, check that it can be accessed by the referrer.
+      bool exception_generated = false;
       if (resolved != nullptr && referrer.Get() != nullptr) {
         mirror::Class* methods_class = resolved->GetDeclaringClass();
         mirror::Class* referring_class = referrer->GetDeclaringClass();
         if (!referring_class->CanAccess(methods_class)) {
           ThrowIllegalAccessErrorClassForMethodDispatch(referring_class, methods_class,
                                                         resolved, type);
-          return nullptr;
+          exception_generated = true;
         } else if (!referring_class->CanAccessMember(methods_class,
                                                      resolved->GetAccessFlags())) {
           ThrowIllegalAccessErrorMethod(referring_class, resolved);
-          return nullptr;
+          exception_generated = true;
         }
       }
-
-      // Otherwise, throw an IncompatibleClassChangeError if we found something, and check interface
-      // methods and throw if we find the method there. If we find nothing, throw a
-      // NoSuchMethodError.
-      switch (type) {
-        case kDirect:
-        case kStatic:
-          if (resolved != nullptr) {
-            ThrowIncompatibleClassChangeError(type, kVirtual, resolved, referrer.Get());
-          } else {
-            resolved = klass->FindInterfaceMethod(name, signature);
-            if (resolved != nullptr) {
-              ThrowIncompatibleClassChangeError(type, kInterface, resolved, referrer.Get());
-            } else {
-              ThrowNoSuchMethodError(type, klass, name, signature);
-            }
-          }
-          break;
-        case kInterface:
-          if (resolved != nullptr) {
-            ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer.Get());
-          } else {
-            resolved = klass->FindVirtualMethod(name, signature);
+      if (!exception_generated) {
+        // Otherwise, throw an IncompatibleClassChangeError if we found something, and check
+        // interface methods and throw if we find the method there. If we find nothing, throw a
+        // NoSuchMethodError.
+        switch (type) {
+          case kDirect:
+          case kStatic:
             if (resolved != nullptr) {
               ThrowIncompatibleClassChangeError(type, kVirtual, resolved, referrer.Get());
             } else {
-              ThrowNoSuchMethodError(type, klass, name, signature);
+              resolved = klass->FindInterfaceMethod(name, signature);
+              if (resolved != nullptr) {
+                ThrowIncompatibleClassChangeError(type, kInterface, resolved, referrer.Get());
+              } else {
+                ThrowNoSuchMethodError(type, klass, name, signature);
+              }
             }
-          }
-          break;
-        case kSuper:
-          if (resolved != nullptr) {
-            ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer.Get());
-          } else {
-            ThrowNoSuchMethodError(type, klass, name, signature);
-          }
-          break;
-        case kVirtual:
-          if (resolved != nullptr) {
-            ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer.Get());
-          } else {
-            resolved = klass->FindInterfaceMethod(name, signature);
+            break;
+          case kInterface:
             if (resolved != nullptr) {
-              ThrowIncompatibleClassChangeError(type, kInterface, resolved, referrer.Get());
+              ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer.Get());
+            } else {
+              resolved = klass->FindVirtualMethod(name, signature);
+              if (resolved != nullptr) {
+                ThrowIncompatibleClassChangeError(type, kVirtual, resolved, referrer.Get());
+              } else {
+                ThrowNoSuchMethodError(type, klass, name, signature);
+              }
+            }
+            break;
+          case kSuper:
+            if (resolved != nullptr) {
+              ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer.Get());
             } else {
               ThrowNoSuchMethodError(type, klass, name, signature);
             }
-          }
-          break;
+            break;
+          case kVirtual:
+            if (resolved != nullptr) {
+              ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer.Get());
+            } else {
+              resolved = klass->FindInterfaceMethod(name, signature);
+              if (resolved != nullptr) {
+                ThrowIncompatibleClassChangeError(type, kInterface, resolved, referrer.Get());
+              } else {
+                ThrowNoSuchMethodError(type, klass, name, signature);
+              }
+            }
+            break;
+        }
       }
     }
-    DCHECK(Thread::Current()->IsExceptionPending());
+    Thread::Current()->AssertPendingException();
     return nullptr;
   }
 }
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index e3eb707..a176a87 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -22,7 +22,7 @@
 #include "entrypoints/runtime_asm_entrypoints.h"
 #include "gc/accounting/card_table-inl.h"
 #include "interpreter/interpreter.h"
-#include "method_helper.h"
+#include "method_reference.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/dex_cache-inl.h"
@@ -642,7 +642,7 @@
 
   // Convert proxy method into expected interface method.
   mirror::ArtMethod* interface_method = proxy_method->FindOverriddenMethod();
-  DCHECK(interface_method != NULL) << PrettyMethod(proxy_method);
+  DCHECK(interface_method != nullptr) << PrettyMethod(proxy_method);
   DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method);
   jobject interface_method_jobj = soa.AddLocalReference<jobject>(interface_method);
 
@@ -711,12 +711,12 @@
   ClassLinker* linker = Runtime::Current()->GetClassLinker();
   mirror::ArtMethod* caller = QuickArgumentVisitor::GetCallingMethod(sp);
   InvokeType invoke_type;
-  const DexFile* dex_file;
-  uint32_t dex_method_idx;
-  if (called->IsRuntimeMethod()) {
+  MethodReference called_method(nullptr, 0);
+  const bool called_method_known_on_entry = !called->IsRuntimeMethod();
+  if (!called_method_known_on_entry) {
     uint32_t dex_pc = caller->ToDexPc(QuickArgumentVisitor::GetCallingPc(sp));
     const DexFile::CodeItem* code;
-    dex_file = caller->GetDexFile();
+    called_method.dex_file = caller->GetDexFile();
     code = caller->GetCodeItem();
     CHECK_LT(dex_pc, code->insns_size_in_code_units_);
     const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
@@ -764,33 +764,33 @@
         is_range = true;
         break;
       default:
-        LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(NULL);
-        // Avoid used uninitialized warnings.
-        invoke_type = kDirect;
-        is_range = false;
+        LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(nullptr);
+        UNREACHABLE();
     }
-    dex_method_idx = (is_range) ? instr->VRegB_3rc() : instr->VRegB_35c();
+    called_method.dex_method_index = (is_range) ? instr->VRegB_3rc() : instr->VRegB_35c();
   } else {
     invoke_type = kStatic;
-    dex_file = called->GetDexFile();
-    dex_method_idx = called->GetDexMethodIndex();
+    called_method.dex_file = called->GetDexFile();
+    called_method.dex_method_index = called->GetDexMethodIndex();
   }
   uint32_t shorty_len;
   const char* shorty =
-      dex_file->GetMethodShorty(dex_file->GetMethodId(dex_method_idx), &shorty_len);
+      called_method.dex_file->GetMethodShorty(
+          called_method.dex_file->GetMethodId(called_method.dex_method_index), &shorty_len);
   RememberForGcArgumentVisitor visitor(sp, invoke_type == kStatic, shorty, shorty_len, &soa);
   visitor.VisitArguments();
   self->EndAssertNoThreadSuspension(old_cause);
-  bool virtual_or_interface = invoke_type == kVirtual || invoke_type == kInterface;
+  const bool virtual_or_interface = invoke_type == kVirtual || invoke_type == kInterface;
   // Resolve method filling in dex cache.
-  if (UNLIKELY(called->IsRuntimeMethod())) {
+  if (!called_method_known_on_entry) {
     StackHandleScope<1> hs(self);
     mirror::Object* dummy = nullptr;
     HandleWrapper<mirror::Object> h_receiver(
         hs.NewHandleWrapper(virtual_or_interface ? &receiver : &dummy));
-    called = linker->ResolveMethod(self, dex_method_idx, &caller, invoke_type);
+    DCHECK_EQ(caller->GetDexFile(), called_method.dex_file);
+    called = linker->ResolveMethod(self, called_method.dex_method_index, &caller, invoke_type);
   }
-  const void* code = NULL;
+  const void* code = nullptr;
   if (LIKELY(!self->IsExceptionPending())) {
     // Incompatible class change should have been handled in resolve method.
     CHECK(!called->CheckIncompatibleClassChange(invoke_type))
@@ -811,20 +811,23 @@
                                << invoke_type << " " << orig_called->GetVtableIndex();
 
       // We came here because of sharpening. Ensure the dex cache is up-to-date on the method index
-      // of the sharpened method.
-      if (called->HasSameDexCacheResolvedMethods(caller)) {
-        caller->SetDexCacheResolvedMethod(called->GetDexMethodIndex(), called);
-      } else {
+      // of the sharpened method avoiding dirtying the dex cache if possible.
+      uint32_t update_dex_cache_method_index = called_method.dex_method_index;
+      if (!called->HasSameDexCacheResolvedMethods(caller)) {
         // Calling from one dex file to another, need to compute the method index appropriate to
         // the caller's dex file. Since we get here only if the original called was a runtime
         // method, we've got the correct dex_file and a dex_method_idx from above.
-        DCHECK_EQ(caller->GetDexFile(), dex_file);
-        StackHandleScope<1> hs(self);
-        MethodHelper mh(hs.NewHandle(called));
-        uint32_t method_index = mh.FindDexMethodIndexInOtherDexFile(*dex_file, dex_method_idx);
-        if (method_index != DexFile::kDexNoIndex) {
-          caller->SetDexCacheResolvedMethod(method_index, called);
-        }
+        DCHECK(!called_method_known_on_entry);
+        DCHECK_EQ(caller->GetDexFile(), called_method.dex_file);
+        const DexFile* caller_dex_file = called_method.dex_file;
+        uint32_t caller_method_name_and_sig_index = called_method.dex_method_index;
+        update_dex_cache_method_index =
+            called->FindDexMethodIndexInOtherDexFile(*caller_dex_file,
+                                                     caller_method_name_and_sig_index);
+      }
+      if ((update_dex_cache_method_index != DexFile::kDexNoIndex) &&
+          (caller->GetDexCacheResolvedMethod(update_dex_cache_method_index) != called)) {
+        caller->SetDexCacheResolvedMethod(update_dex_cache_method_index, called);
       }
     }
     // Ensure that the called method's class is initialized.
@@ -846,7 +849,7 @@
       DCHECK(called_class->IsErroneous());
     }
   }
-  CHECK_EQ(code == NULL, self->IsExceptionPending());
+  CHECK_EQ(code == nullptr, self->IsExceptionPending());
   // Fixup any locally saved objects may have moved during a GC.
   visitor.FixupReferences();
   // Place called method in callee-save frame to be placed as first argument to quick method.
@@ -1263,6 +1266,7 @@
           break;
         default:
           LOG(FATAL) << "Unexpected type: " << cur_type_ << " in " << shorty;
+          UNREACHABLE();
       }
     }
 
@@ -1786,7 +1790,7 @@
       visitor.FixupReferences();
     }
 
-    if (UNLIKELY(method == NULL)) {
+    if (UNLIKELY(method == nullptr)) {
       CHECK(self->IsExceptionPending());
       return GetTwoWordFailureValue();  // Failure.
     }
@@ -1795,7 +1799,7 @@
   const void* code = method->GetEntryPointFromQuickCompiledCode();
 
   // When we return, the caller will branch to this address, so it had better not be 0!
-  DCHECK(code != nullptr) << "Code was NULL in method: " << PrettyMethod(method)
+  DCHECK(code != nullptr) << "Code was null in method: " << PrettyMethod(method)
                           << " location: "
                           << method->GetDexFile()->GetLocation();
 
@@ -1881,7 +1885,7 @@
   mirror::ArtMethod* method;
   if (LIKELY(interface_method->GetDexMethodIndex() != DexFile::kDexNoIndex)) {
     method = this_object->GetClass()->FindVirtualMethodForInterface(interface_method);
-    if (UNLIKELY(method == NULL)) {
+    if (UNLIKELY(method == nullptr)) {
       ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(interface_method, this_object,
                                                                  caller_method);
       return GetTwoWordFailureValue();  // Failure.
@@ -1901,7 +1905,7 @@
     Instruction::Code instr_code = instr->Opcode();
     CHECK(instr_code == Instruction::INVOKE_INTERFACE ||
           instr_code == Instruction::INVOKE_INTERFACE_RANGE)
-        << "Unexpected call into interface trampoline: " << instr->DumpString(NULL);
+        << "Unexpected call into interface trampoline: " << instr->DumpString(nullptr);
     uint32_t dex_method_idx;
     if (instr_code == Instruction::INVOKE_INTERFACE) {
       dex_method_idx = instr->VRegB_35c();
@@ -1933,7 +1937,7 @@
   const void* code = method->GetEntryPointFromQuickCompiledCode();
 
   // When we return, the caller will branch to this address, so it had better not be 0!
-  DCHECK(code != nullptr) << "Code was NULL in method: " << PrettyMethod(method)
+  DCHECK(code != nullptr) << "Code was null in method: " << PrettyMethod(method)
                           << " location: " << method->GetDexFile()->GetLocation();
 
   return GetTwoWordSuccessValue(reinterpret_cast<uintptr_t>(code),
diff --git a/runtime/method_helper.cc b/runtime/method_helper.cc
index 81e1794..683d1bd 100644
--- a/runtime/method_helper.cc
+++ b/runtime/method_helper.cc
@@ -58,94 +58,8 @@
   return true;
 }
 
-template <template <class T> class HandleKind>
-uint32_t MethodHelperT<HandleKind>::FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::ArtMethod* method = GetMethod();
-  const DexFile* dexfile = method->GetDexFile();
-  if (dexfile == &other_dexfile) {
-    return method->GetDexMethodIndex();
-  }
-  const DexFile::MethodId& mid = dexfile->GetMethodId(method->GetDexMethodIndex());
-  const char* mid_declaring_class_descriptor = dexfile->StringByTypeIdx(mid.class_idx_);
-  const DexFile::StringId* other_descriptor =
-      other_dexfile.FindStringId(mid_declaring_class_descriptor);
-  if (other_descriptor != nullptr) {
-    const DexFile::TypeId* other_type_id =
-        other_dexfile.FindTypeId(other_dexfile.GetIndexForStringId(*other_descriptor));
-    if (other_type_id != nullptr) {
-      const char* mid_name = dexfile->GetMethodName(mid);
-      const DexFile::StringId* other_name = other_dexfile.FindStringId(mid_name);
-      if (other_name != nullptr) {
-        uint16_t other_return_type_idx;
-        std::vector<uint16_t> other_param_type_idxs;
-        bool success = other_dexfile.CreateTypeList(
-            dexfile->GetMethodSignature(mid).ToString(), &other_return_type_idx,
-            &other_param_type_idxs);
-        if (success) {
-          const DexFile::ProtoId* other_sig =
-              other_dexfile.FindProtoId(other_return_type_idx, other_param_type_idxs);
-          if (other_sig != nullptr) {
-            const  DexFile::MethodId* other_mid = other_dexfile.FindMethodId(
-                *other_type_id, *other_name, *other_sig);
-            if (other_mid != nullptr) {
-              return other_dexfile.GetIndexForMethodId(*other_mid);
-            }
-          }
-        }
-      }
-    }
-  }
-  return DexFile::kDexNoIndex;
-}
-
-template <template <typename> class HandleKind>
-uint32_t MethodHelperT<HandleKind>::FindDexMethodIndexInOtherDexFile(
-    const DexFile& other_dexfile, uint32_t name_and_signature_idx)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::ArtMethod* method = GetMethod();
-  const DexFile* dexfile = method->GetDexFile();
-  const uint32_t dex_method_idx = method->GetDexMethodIndex();
-  const DexFile::MethodId& mid = dexfile->GetMethodId(dex_method_idx);
-  const DexFile::MethodId& name_and_sig_mid = other_dexfile.GetMethodId(name_and_signature_idx);
-  DCHECK_STREQ(dexfile->GetMethodName(mid), other_dexfile.GetMethodName(name_and_sig_mid));
-  DCHECK_EQ(dexfile->GetMethodSignature(mid), other_dexfile.GetMethodSignature(name_and_sig_mid));
-  if (dexfile == &other_dexfile) {
-    return dex_method_idx;
-  }
-  const char* mid_declaring_class_descriptor = dexfile->StringByTypeIdx(mid.class_idx_);
-  const DexFile::StringId* other_descriptor =
-      other_dexfile.FindStringId(mid_declaring_class_descriptor);
-  if (other_descriptor != nullptr) {
-    const DexFile::TypeId* other_type_id =
-        other_dexfile.FindTypeId(other_dexfile.GetIndexForStringId(*other_descriptor));
-    if (other_type_id != nullptr) {
-      const DexFile::MethodId* other_mid = other_dexfile.FindMethodId(
-          *other_type_id, other_dexfile.GetStringId(name_and_sig_mid.name_idx_),
-          other_dexfile.GetProtoId(name_and_sig_mid.proto_idx_));
-      if (other_mid != nullptr) {
-        return other_dexfile.GetIndexForMethodId(*other_mid);
-      }
-    }
-  }
-  return DexFile::kDexNoIndex;
-}
-
 // Instantiate methods.
 template
-uint32_t MethodHelperT<Handle>::FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile);
-template
-uint32_t MethodHelperT<MutableHandle>::FindDexMethodIndexInOtherDexFile(
-    const DexFile& other_dexfile);
-
-template
-uint32_t MethodHelperT<Handle>::FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile,
-                                                                 uint32_t name_and_signature_idx);
-template
-uint32_t MethodHelperT<MutableHandle>::FindDexMethodIndexInOtherDexFile(
-    const DexFile& other_dexfile, uint32_t name_and_signature_idx);
-
-template
 bool MethodHelperT<Handle>::HasSameSignatureWithDifferentClassLoaders<Handle>(Thread* self,
     MethodHelperT<Handle>* other);
 
diff --git a/runtime/method_helper.h b/runtime/method_helper.h
index dc305d5..2630608 100644
--- a/runtime/method_helper.h
+++ b/runtime/method_helper.h
@@ -109,15 +109,6 @@
   mirror::Class* GetClassFromTypeIdx(uint16_t type_idx, bool resolve = true)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  uint32_t FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  // The name_and_signature_idx MUST point to a MethodId with the same name and signature in the
-  // other_dexfile, such as the method index used to resolve this method in the other_dexfile.
-  uint32_t FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile,
-                                            uint32_t name_and_signature_idx)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
  protected:
   HandleKind<mirror::ArtMethod> method_;
 
diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc
index 4f5ca3f..40c2b2c 100644
--- a/runtime/mirror/art_method.cc
+++ b/runtime/mirror/art_method.cc
@@ -160,6 +160,35 @@
   return result;
 }
 
+uint32_t ArtMethod::FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile,
+                                                     uint32_t name_and_signature_idx) {
+  const DexFile* dexfile = GetDexFile();
+  const uint32_t dex_method_idx = GetDexMethodIndex();
+  const DexFile::MethodId& mid = dexfile->GetMethodId(dex_method_idx);
+  const DexFile::MethodId& name_and_sig_mid = other_dexfile.GetMethodId(name_and_signature_idx);
+  DCHECK_STREQ(dexfile->GetMethodName(mid), other_dexfile.GetMethodName(name_and_sig_mid));
+  DCHECK_EQ(dexfile->GetMethodSignature(mid), other_dexfile.GetMethodSignature(name_and_sig_mid));
+  if (dexfile == &other_dexfile) {
+    return dex_method_idx;
+  }
+  const char* mid_declaring_class_descriptor = dexfile->StringByTypeIdx(mid.class_idx_);
+  const DexFile::StringId* other_descriptor =
+      other_dexfile.FindStringId(mid_declaring_class_descriptor);
+  if (other_descriptor != nullptr) {
+    const DexFile::TypeId* other_type_id =
+        other_dexfile.FindTypeId(other_dexfile.GetIndexForStringId(*other_descriptor));
+    if (other_type_id != nullptr) {
+      const DexFile::MethodId* other_mid = other_dexfile.FindMethodId(
+          *other_type_id, other_dexfile.GetStringId(name_and_sig_mid.name_idx_),
+          other_dexfile.GetProtoId(name_and_sig_mid.proto_idx_));
+      if (other_mid != nullptr) {
+        return other_dexfile.GetIndexForMethodId(*other_mid);
+      }
+    }
+  }
+  return DexFile::kDexNoIndex;
+}
+
 uint32_t ArtMethod::ToDexPc(const uintptr_t pc, bool abort_on_failure) {
   if (IsPortableCompiled()) {
     // Portable doesn't use the machine pc, we just use dex pc instead.
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index 0466fe3..04f8efc 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -237,9 +237,17 @@
   bool HasSameDexCacheResolvedTypes(ObjectArray<Class>* other_cache)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  // Find the method that this method overrides
+  // Find the method that this method overrides.
   ArtMethod* FindOverriddenMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // Find the method index for this method within other_dexfile. If this method isn't present then
+  // return DexFile::kDexNoIndex. The name_and_signature_idx MUST refer to a MethodId with the same
+  // name and signature in the other_dexfile, such as the method index used to resolve this method
+  // in the other_dexfile.
+  uint32_t FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile,
+                                            uint32_t name_and_signature_idx)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   void Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result, const char* shorty)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);