Restore the args in the invoke trampoline slow paths.

Previously, there were errors caused by not restoring the args for
the slow path in artInvokeInterfaceTrampoline and artInvokeCommon. The
slow path in artInvokeInterfaceTrampoline occurs when you attempt
to do an interface dispatch of a method in another dex file. The slow
path in artInvokeCommon occurs when the method in dex cache is not
already resolved.

Since FindMethodFromCode may resolve a method, it can occasionally
cause thread suspension/GC. If a moving GC occurred at this point it
resulted in this_object being invalid after the trampoline returned
the code pointer. This caused a native crash in one of the money runs
since there was an unbundeled app which did a List.iterator call.

Bug: 12934910
Change-Id: Ib454faad14bef0d7732a6d7f1ca5803472d502a6
diff --git a/runtime/Android.mk b/runtime/Android.mk
index cf7f895..9df69f0 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -182,7 +182,6 @@
 	entrypoints/quick/quick_field_entrypoints.cc \
 	entrypoints/quick/quick_fillarray_entrypoints.cc \
 	entrypoints/quick/quick_instrumentation_entrypoints.cc \
-	entrypoints/quick/quick_invoke_entrypoints.cc \
 	entrypoints/quick/quick_jni_entrypoints.cc \
 	entrypoints/quick/quick_lock_entrypoints.cc \
 	entrypoints/quick/quick_math_entrypoints.cc \
diff --git a/runtime/entrypoints/quick/quick_invoke_entrypoints.cc b/runtime/entrypoints/quick/quick_invoke_entrypoints.cc
deleted file mode 100644
index e024a90..0000000
--- a/runtime/entrypoints/quick/quick_invoke_entrypoints.cc
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "callee_save_frame.h"
-#include "dex_instruction-inl.h"
-#include "entrypoints/entrypoint_utils.h"
-#include "mirror/art_method-inl.h"
-#include "mirror/class-inl.h"
-#include "mirror/dex_cache-inl.h"
-#include "mirror/object-inl.h"
-#include "mirror/object_array-inl.h"
-
-namespace art {
-
-// Determine target of interface dispatch. This object is known non-null.
-extern "C" uint64_t artInvokeInterfaceTrampoline(mirror::ArtMethod* interface_method,
-                                                 mirror::Object* this_object,
-                                                 mirror::ArtMethod* caller_method,
-                                                 Thread* self, mirror::ArtMethod** sp)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::ArtMethod* method;
-  if (LIKELY(interface_method->GetDexMethodIndex() != DexFile::kDexNoIndex)) {
-    method = this_object->GetClass()->FindVirtualMethodForInterface(interface_method);
-    if (UNLIKELY(method == NULL)) {
-      FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs);
-      ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(interface_method, this_object,
-                                                                 caller_method);
-      return 0;  // Failure.
-    }
-  } else {
-    FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs);
-    DCHECK(interface_method == Runtime::Current()->GetResolutionMethod());
-    // Determine method index from calling dex instruction.
-#if defined(__arm__)
-    // On entry the stack pointed by sp is:
-    // | argN       |  |
-    // | ...        |  |
-    // | arg4       |  |
-    // | arg3 spill |  |  Caller's frame
-    // | arg2 spill |  |
-    // | arg1 spill |  |
-    // | Method*    | ---
-    // | LR         |
-    // | ...        |    callee saves
-    // | R3         |    arg3
-    // | R2         |    arg2
-    // | R1         |    arg1
-    // | R0         |
-    // | Method*    |  <- sp
-    DCHECK_EQ(48U, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes());
-    uintptr_t* regs = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp) + kPointerSize);
-    uintptr_t caller_pc = regs[10];
-#elif defined(__i386__)
-    // On entry the stack pointed by sp is:
-    // | argN        |  |
-    // | ...         |  |
-    // | arg4        |  |
-    // | arg3 spill  |  |  Caller's frame
-    // | arg2 spill  |  |
-    // | arg1 spill  |  |
-    // | Method*     | ---
-    // | Return      |
-    // | EBP,ESI,EDI |    callee saves
-    // | EBX         |    arg3
-    // | EDX         |    arg2
-    // | ECX         |    arg1
-    // | EAX/Method* |  <- sp
-    DCHECK_EQ(32U, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes());
-    uintptr_t* regs = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp));
-    uintptr_t caller_pc = regs[7];
-#elif defined(__mips__)
-    // On entry the stack pointed by sp is:
-    // | argN       |  |
-    // | ...        |  |
-    // | arg4       |  |
-    // | arg3 spill |  |  Caller's frame
-    // | arg2 spill |  |
-    // | arg1 spill |  |
-    // | Method*    | ---
-    // | RA         |
-    // | ...        |    callee saves
-    // | A3         |    arg3
-    // | A2         |    arg2
-    // | A1         |    arg1
-    // | A0/Method* |  <- sp
-    DCHECK_EQ(64U, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes());
-    uintptr_t* regs = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp));
-    uintptr_t caller_pc = regs[15];
-#else
-    UNIMPLEMENTED(FATAL);
-    uintptr_t caller_pc = 0;
-#endif
-    uint32_t dex_pc = caller_method->ToDexPc(caller_pc);
-    const DexFile::CodeItem* code = MethodHelper(caller_method).GetCodeItem();
-    CHECK_LT(dex_pc, code->insns_size_in_code_units_);
-    const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
-    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);
-    uint32_t dex_method_idx;
-    if (instr_code == Instruction::INVOKE_INTERFACE) {
-      dex_method_idx = instr->VRegB_35c();
-    } else {
-      DCHECK_EQ(instr_code, Instruction::INVOKE_INTERFACE_RANGE);
-      dex_method_idx = instr->VRegB_3rc();
-    }
-    method = FindMethodFromCode<kInterface, false>(dex_method_idx, this_object, caller_method, self);
-    if (UNLIKELY(method == NULL)) {
-      CHECK(self->IsExceptionPending());
-      return 0;  // Failure.
-    }
-  }
-  const void* code = method->GetEntryPointFromQuickCompiledCode();
-
-  // When we return, the caller will branch to this address, so it had better not be 0!
-  if (kIsDebugBuild && UNLIKELY(code == nullptr)) {
-      MethodHelper mh(method);
-      LOG(FATAL) << "Code was NULL in method: " << PrettyMethod(method)
-                 << " location: " << mh.GetDexFile().GetLocation();
-  }
-#ifdef __LP64__
-  UNIMPLEMENTED(FATAL);
-  return 0;
-#else
-  uint32_t method_uint = reinterpret_cast<uint32_t>(method);
-  uint64_t code_uint = reinterpret_cast<uint32_t>(code);
-  uint64_t result = ((code_uint << 32) | method_uint);
-  return result;
-#endif
-}
-
-template<InvokeType type, bool access_check>
-uint64_t artInvokeCommon(uint32_t method_idx, mirror::Object* this_object,
-                         mirror::ArtMethod* caller_method,
-                         Thread* self, mirror::ArtMethod** sp) {
-  mirror::ArtMethod* method = FindMethodFast(method_idx, this_object, caller_method, access_check,
-                                             type);
-  if (UNLIKELY(method == NULL)) {
-    FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs);
-    method = FindMethodFromCode<type, access_check>(method_idx, this_object, caller_method, self);
-    if (UNLIKELY(method == NULL)) {
-      CHECK(self->IsExceptionPending());
-      return 0;  // failure
-    }
-  }
-  DCHECK(!self->IsExceptionPending());
-  const void* code = method->GetEntryPointFromQuickCompiledCode();
-
-  // When we return, the caller will branch to this address, so it had better not be 0!
-  if (kIsDebugBuild && UNLIKELY(code == NULL)) {
-      MethodHelper mh(method);
-      LOG(FATAL) << "Code was NULL in method: " << PrettyMethod(method)
-                 << " location: " << mh.GetDexFile().GetLocation();
-  }
-#ifdef __LP64__
-  UNIMPLEMENTED(FATAL);
-  return 0;
-#else
-  uint32_t method_uint = reinterpret_cast<uint32_t>(method);
-  uint64_t code_uint = reinterpret_cast<uint32_t>(code);
-  uint64_t result = ((code_uint << 32) | method_uint);
-  return result;
-#endif
-}
-
-// Explicit template declarations of artInvokeCommon for all invoke types.
-#define EXPLICIT_ART_INVOKE_COMMON_TEMPLATE_DECL(_type, _access_check)                 \
-  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)                                 \
-  uint64_t artInvokeCommon<_type, _access_check>(uint32_t method_idx,                  \
-                                                 mirror::Object* this_object,          \
-                                                 mirror::ArtMethod* caller_method,     \
-                                                 Thread* self, mirror::ArtMethod** sp)
-
-#define EXPLICIT_ART_INVOKE_COMMON_TYPED_TEMPLATE_DECL(_type) \
-    EXPLICIT_ART_INVOKE_COMMON_TEMPLATE_DECL(_type, false);   \
-    EXPLICIT_ART_INVOKE_COMMON_TEMPLATE_DECL(_type, true)
-
-EXPLICIT_ART_INVOKE_COMMON_TYPED_TEMPLATE_DECL(kStatic);
-EXPLICIT_ART_INVOKE_COMMON_TYPED_TEMPLATE_DECL(kDirect);
-EXPLICIT_ART_INVOKE_COMMON_TYPED_TEMPLATE_DECL(kVirtual);
-EXPLICIT_ART_INVOKE_COMMON_TYPED_TEMPLATE_DECL(kSuper);
-EXPLICIT_ART_INVOKE_COMMON_TYPED_TEMPLATE_DECL(kInterface);
-
-#undef EXPLICIT_ART_INVOKE_COMMON_TYPED_TEMPLATE_DECL
-#undef EXPLICIT_ART_INVOKE_COMMON_TEMPLATE_DECL
-
-// See comments in runtime_support_asm.S
-extern "C" uint64_t artInvokeInterfaceTrampolineWithAccessCheck(uint32_t method_idx,
-                                                                mirror::Object* this_object,
-                                                                mirror::ArtMethod* caller_method,
-                                                                Thread* self,
-                                                                mirror::ArtMethod** sp)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return artInvokeCommon<kInterface, true>(method_idx, this_object, caller_method, self, sp);
-}
-
-
-extern "C" uint64_t artInvokeDirectTrampolineWithAccessCheck(uint32_t method_idx,
-                                                             mirror::Object* this_object,
-                                                             mirror::ArtMethod* caller_method,
-                                                             Thread* self,
-                                                             mirror::ArtMethod** sp)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return artInvokeCommon<kDirect, true>(method_idx, this_object, caller_method, self, sp);
-}
-
-extern "C" uint64_t artInvokeStaticTrampolineWithAccessCheck(uint32_t method_idx,
-                                                             mirror::Object* this_object,
-                                                             mirror::ArtMethod* caller_method,
-                                                             Thread* self,
-                                                             mirror::ArtMethod** sp)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return artInvokeCommon<kStatic, true>(method_idx, this_object, caller_method, self, sp);
-}
-
-extern "C" uint64_t artInvokeSuperTrampolineWithAccessCheck(uint32_t method_idx,
-                                                            mirror::Object* this_object,
-                                                            mirror::ArtMethod* caller_method,
-                                                            Thread* self,
-                                                            mirror::ArtMethod** sp)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return artInvokeCommon<kSuper, true>(method_idx, this_object, caller_method, self, sp);
-}
-
-extern "C" uint64_t artInvokeVirtualTrampolineWithAccessCheck(uint32_t method_idx,
-                                                              mirror::Object* this_object,
-                                                              mirror::ArtMethod* caller_method,
-                                                              Thread* self,
-                                                              mirror::ArtMethod** sp)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return artInvokeCommon<kVirtual, true>(method_idx, this_object, caller_method, self, sp);
-}
-
-}  // namespace art
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 20432c6..9fc173a 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -23,6 +23,7 @@
 #include "interpreter/interpreter.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/class-inl.h"
+#include "mirror/dex_cache-inl.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
 #include "object_utils.h"
@@ -618,6 +619,7 @@
   // Fixup any references which may have changed.
   for (const auto& pair : references_) {
     pair.second->Assign(soa_->Decode<mirror::Object*>(pair.first));
+    soa_->Env()->DeleteLocalRef(pair.first);
   }
 }
 
@@ -708,6 +710,7 @@
   // Fixup any references which may have changed.
   for (const auto& pair : references_) {
     pair.second->Assign(soa_->Decode<mirror::Object*>(pair.first));
+    soa_->Env()->DeleteLocalRef(pair.first);
   }
 }
 
@@ -1630,4 +1633,230 @@
   }
 }
 
+template<InvokeType type, bool access_check>
+uint64_t artInvokeCommon(uint32_t method_idx, mirror::Object* this_object,
+                         mirror::ArtMethod* caller_method,
+                         Thread* self, mirror::ArtMethod** sp)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+template<InvokeType type, bool access_check>
+uint64_t artInvokeCommon(uint32_t method_idx, mirror::Object* this_object,
+                         mirror::ArtMethod* caller_method,
+                         Thread* self, mirror::ArtMethod** sp) {
+  mirror::ArtMethod* method = FindMethodFast(method_idx, this_object, caller_method, access_check,
+                                             type);
+  if (UNLIKELY(method == nullptr)) {
+    FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs);
+    const DexFile* dex_file = caller_method->GetDeclaringClass()->GetDexCache()->GetDexFile();
+    uint32_t shorty_len;
+    const char* shorty =
+        dex_file->GetMethodShorty(dex_file->GetMethodId(method_idx), &shorty_len);
+    {
+      // Remember the args in case a GC happens in FindMethodFromCode.
+      ScopedObjectAccessUnchecked soa(self->GetJniEnv());
+      RememberForGcArgumentVisitor visitor(sp, type == kStatic, shorty, shorty_len, &soa);
+      visitor.VisitArguments();
+      method = FindMethodFromCode<type, access_check>(method_idx, this_object, caller_method, self);
+      visitor.FixupReferences();
+    }
+
+    if (UNLIKELY(method == NULL)) {
+      CHECK(self->IsExceptionPending());
+      return 0;  // failure
+    }
+  }
+  DCHECK(!self->IsExceptionPending());
+  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) << " location: "
+      << MethodHelper(method).GetDexFile().GetLocation();
+#ifdef __LP64__
+  UNIMPLEMENTED(FATAL);
+  return 0;
+#else
+  uint32_t method_uint = reinterpret_cast<uint32_t>(method);
+  uint64_t code_uint = reinterpret_cast<uint32_t>(code);
+  uint64_t result = ((code_uint << 32) | method_uint);
+  return result;
+#endif
+}
+
+
+// See comments in runtime_support_asm.S
+extern "C" uint64_t artInvokeInterfaceTrampolineWithAccessCheck(uint32_t method_idx,
+                                                                mirror::Object* this_object,
+                                                                mirror::ArtMethod* caller_method,
+                                                                Thread* self,
+                                                                mirror::ArtMethod** sp)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  return artInvokeCommon<kInterface, true>(method_idx, this_object, caller_method, self, sp);
+}
+
+
+extern "C" uint64_t artInvokeDirectTrampolineWithAccessCheck(uint32_t method_idx,
+                                                             mirror::Object* this_object,
+                                                             mirror::ArtMethod* caller_method,
+                                                             Thread* self,
+                                                             mirror::ArtMethod** sp)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  return artInvokeCommon<kDirect, true>(method_idx, this_object, caller_method, self, sp);
+}
+
+extern "C" uint64_t artInvokeStaticTrampolineWithAccessCheck(uint32_t method_idx,
+                                                             mirror::Object* this_object,
+                                                             mirror::ArtMethod* caller_method,
+                                                             Thread* self,
+                                                             mirror::ArtMethod** sp)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  return artInvokeCommon<kStatic, true>(method_idx, this_object, caller_method, self, sp);
+}
+
+extern "C" uint64_t artInvokeSuperTrampolineWithAccessCheck(uint32_t method_idx,
+                                                            mirror::Object* this_object,
+                                                            mirror::ArtMethod* caller_method,
+                                                            Thread* self,
+                                                            mirror::ArtMethod** sp)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  return artInvokeCommon<kSuper, true>(method_idx, this_object, caller_method, self, sp);
+}
+
+extern "C" uint64_t artInvokeVirtualTrampolineWithAccessCheck(uint32_t method_idx,
+                                                              mirror::Object* this_object,
+                                                              mirror::ArtMethod* caller_method,
+                                                              Thread* self,
+                                                              mirror::ArtMethod** sp)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  return artInvokeCommon<kVirtual, true>(method_idx, this_object, caller_method, self, sp);
+}
+
+// Determine target of interface dispatch. This object is known non-null.
+extern "C" uint64_t artInvokeInterfaceTrampoline(mirror::ArtMethod* interface_method,
+                                                 mirror::Object* this_object,
+                                                 mirror::ArtMethod* caller_method,
+                                                 Thread* self, mirror::ArtMethod** sp)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  mirror::ArtMethod* method;
+  if (LIKELY(interface_method->GetDexMethodIndex() != DexFile::kDexNoIndex)) {
+    method = this_object->GetClass()->FindVirtualMethodForInterface(interface_method);
+    if (UNLIKELY(method == NULL)) {
+      FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs);
+      ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(interface_method, this_object,
+                                                                 caller_method);
+      return 0;  // Failure.
+    }
+  } else {
+    FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs);
+    DCHECK(interface_method == Runtime::Current()->GetResolutionMethod());
+    // Determine method index from calling dex instruction.
+#if defined(__arm__)
+    // On entry the stack pointed by sp is:
+    // | argN       |  |
+    // | ...        |  |
+    // | arg4       |  |
+    // | arg3 spill |  |  Caller's frame
+    // | arg2 spill |  |
+    // | arg1 spill |  |
+    // | Method*    | ---
+    // | LR         |
+    // | ...        |    callee saves
+    // | R3         |    arg3
+    // | R2         |    arg2
+    // | R1         |    arg1
+    // | R0         |
+    // | Method*    |  <- sp
+    DCHECK_EQ(48U, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes());
+    uintptr_t* regs = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp) + kPointerSize);
+    uintptr_t caller_pc = regs[10];
+#elif defined(__i386__)
+    // On entry the stack pointed by sp is:
+    // | argN        |  |
+    // | ...         |  |
+    // | arg4        |  |
+    // | arg3 spill  |  |  Caller's frame
+    // | arg2 spill  |  |
+    // | arg1 spill  |  |
+    // | Method*     | ---
+    // | Return      |
+    // | EBP,ESI,EDI |    callee saves
+    // | EBX         |    arg3
+    // | EDX         |    arg2
+    // | ECX         |    arg1
+    // | EAX/Method* |  <- sp
+    DCHECK_EQ(32U, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes());
+    uintptr_t* regs = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp));
+    uintptr_t caller_pc = regs[7];
+#elif defined(__mips__)
+    // On entry the stack pointed by sp is:
+    // | argN       |  |
+    // | ...        |  |
+    // | arg4       |  |
+    // | arg3 spill |  |  Caller's frame
+    // | arg2 spill |  |
+    // | arg1 spill |  |
+    // | Method*    | ---
+    // | RA         |
+    // | ...        |    callee saves
+    // | A3         |    arg3
+    // | A2         |    arg2
+    // | A1         |    arg1
+    // | A0/Method* |  <- sp
+    DCHECK_EQ(64U, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes());
+    uintptr_t* regs = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp));
+    uintptr_t caller_pc = regs[15];
+#else
+    UNIMPLEMENTED(FATAL);
+    uintptr_t caller_pc = 0;
+#endif
+    uint32_t dex_pc = caller_method->ToDexPc(caller_pc);
+    const DexFile::CodeItem* code = MethodHelper(caller_method).GetCodeItem();
+    CHECK_LT(dex_pc, code->insns_size_in_code_units_);
+    const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
+    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);
+    uint32_t dex_method_idx;
+    if (instr_code == Instruction::INVOKE_INTERFACE) {
+      dex_method_idx = instr->VRegB_35c();
+    } else {
+      DCHECK_EQ(instr_code, Instruction::INVOKE_INTERFACE_RANGE);
+      dex_method_idx = instr->VRegB_3rc();
+    }
+
+    const DexFile* dex_file = caller_method->GetDeclaringClass()->GetDexCache()->GetDexFile();
+    uint32_t shorty_len;
+    const char* shorty =
+        dex_file->GetMethodShorty(dex_file->GetMethodId(dex_method_idx), &shorty_len);
+    {
+      // Remember the args in case a GC happens in FindMethodFromCode.
+      ScopedObjectAccessUnchecked soa(self->GetJniEnv());
+      RememberForGcArgumentVisitor visitor(sp, false, shorty, shorty_len, &soa);
+      visitor.VisitArguments();
+      method = FindMethodFromCode<kInterface, false>(dex_method_idx, this_object, caller_method,
+                                                     self);
+      visitor.FixupReferences();
+    }
+
+    if (UNLIKELY(method == nullptr)) {
+      CHECK(self->IsExceptionPending());
+      return 0;  // Failure.
+    }
+  }
+  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) << " location: "
+      << MethodHelper(method).GetDexFile().GetLocation();
+#ifdef __LP64__
+  UNIMPLEMENTED(FATAL);
+  return 0;
+#else
+  uint32_t method_uint = reinterpret_cast<uint32_t>(method);
+  uint64_t code_uint = reinterpret_cast<uint32_t>(code);
+  uint64_t result = ((code_uint << 32) | method_uint);
+  return result;
+#endif
+}
+
 }  // namespace art