ART: Implement missing mterp handlers

Adds mterp handlers for const-method-{handle,type}, invoke-custom, and
invoke-polymorphic.

Minor refactoring starting from interpreter_common.{h,cc} for consistency.

Test: m test-art-host
Bug: 65872996
Change-Id: I95cda758d1ce2fb52e3b1c6211e5d1763cee7bd6
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index fe91272..d3eb29b 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -7981,7 +7981,8 @@
   return resolved;
 }
 
-mirror::MethodType* ClassLinker::ResolveMethodType(const DexFile& dex_file,
+mirror::MethodType* ClassLinker::ResolveMethodType(Thread* self,
+                                                   const DexFile& dex_file,
                                                    uint32_t proto_idx,
                                                    Handle<mirror::DexCache> dex_cache,
                                                    Handle<mirror::ClassLoader> class_loader) {
@@ -7993,7 +7994,6 @@
     return resolved.Ptr();
   }
 
-  Thread* const self = Thread::Current();
   StackHandleScope<4> hs(self);
 
   // First resolve the return type.
@@ -8043,13 +8043,14 @@
   return type.Get();
 }
 
-mirror::MethodType* ClassLinker::ResolveMethodType(uint32_t proto_idx, ArtMethod* referrer) {
-  Thread* const self = Thread::Current();
+mirror::MethodType* ClassLinker::ResolveMethodType(Thread* self,
+                                                   uint32_t proto_idx,
+                                                   ArtMethod* referrer) {
   StackHandleScope<2> hs(self);
   const DexFile* dex_file = referrer->GetDexFile();
   Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
   Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referrer->GetClassLoader()));
-  return ResolveMethodType(*dex_file, proto_idx, dex_cache, class_loader);
+  return ResolveMethodType(self, *dex_file, proto_idx, dex_cache, class_loader);
 }
 
 mirror::MethodHandle* ClassLinker::ResolveMethodHandleForField(
@@ -8344,10 +8345,10 @@
   return mirror::MethodHandleImpl::Create(self, target, kind, method_type);
 }
 
-mirror::MethodHandle* ClassLinker::ResolveMethodHandle(uint32_t method_handle_idx,
+mirror::MethodHandle* ClassLinker::ResolveMethodHandle(Thread* self,
+                                                       uint32_t method_handle_idx,
                                                        ArtMethod* referrer)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  Thread* const self = Thread::Current();
   const DexFile* const dex_file = referrer->GetDexFile();
   const DexFile::MethodHandleItem& method_handle = dex_file->GetMethodHandle(method_handle_idx);
   switch (static_cast<DexFile::MethodHandleType>(method_handle.method_handle_type_)) {
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index e436b99..eba2022 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -364,20 +364,23 @@
 
   // Resolve a method type with a given ID from the DexFile, storing
   // the result in the DexCache.
-  mirror::MethodType* ResolveMethodType(const DexFile& dex_file,
+  mirror::MethodType* ResolveMethodType(Thread* self,
+                                        const DexFile& dex_file,
                                         uint32_t proto_idx,
                                         Handle<mirror::DexCache> dex_cache,
                                         Handle<mirror::ClassLoader> class_loader)
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
 
-  mirror::MethodType* ResolveMethodType(uint32_t proto_idx,  ArtMethod* referrer)
+  mirror::MethodType* ResolveMethodType(Thread* self, uint32_t proto_idx, ArtMethod* referrer)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Resolve a method handle with a given ID from the DexFile. The
   // result is not cached in the DexCache as the instance will only be
   // used once in most circumstances.
-  mirror::MethodHandle* ResolveMethodHandle(uint32_t method_handle_idx, ArtMethod* referrer)
+  mirror::MethodHandle* ResolveMethodHandle(Thread* self,
+                                            uint32_t method_handle_idx,
+                                            ArtMethod* referrer)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Returns true on success, false if there's an exception pending.
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 6ea1fbe..bd73692 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -1476,7 +1476,6 @@
 
 TEST_F(ClassLinkerMethodHandlesTest, TestResolveMethodTypes) {
   ScopedObjectAccess soa(Thread::Current());
-
   StackHandleScope<7> hs(soa.Self());
 
   Handle<mirror::ClassLoader> class_loader(
@@ -1494,7 +1493,7 @@
 
   const DexFile& dex_file = *(method1->GetDexFile());
   Handle<mirror::DexCache> dex_cache = hs.NewHandle(
-      class_linker_->FindDexCache(Thread::Current(), dex_file));
+      class_linker_->FindDexCache(soa.Self(), dex_file));
 
   const DexFile::MethodId& method1_id = dex_file.GetMethodId(method1->GetDexMethodIndex());
 
@@ -1503,20 +1502,29 @@
   // Its RType = Ljava/lang/String;
   // Its PTypes = { Ljava/lang/String; }
   Handle<mirror::MethodType> method1_type = hs.NewHandle(
-      class_linker_->ResolveMethodType(dex_file, method1_id.proto_idx_, dex_cache, class_loader));
+      class_linker_->ResolveMethodType(soa.Self(),
+                                       dex_file,
+                                       method1_id.proto_idx_,
+                                       dex_cache,
+                                       class_loader));
 
   // Assert that the method type was resolved successfully.
   ASSERT_TRUE(method1_type != nullptr);
 
   // Assert that the return type and the method arguments are as we expect.
-  Handle<mirror::Class> string_class(
-      hs.NewHandle(class_linker_->FindClass(soa.Self(), "Ljava/lang/String;", class_loader)));
+  Handle<mirror::Class> string_class(hs.NewHandle(class_linker_->FindClass(soa.Self(),
+                                                                           "Ljava/lang/String;",
+                                                                           class_loader)));
   ASSERT_EQ(string_class.Get(), method1_type->GetRType());
   ASSERT_EQ(string_class.Get(), method1_type->GetPTypes()->Get(0));
 
   // Resolve the method type again and assert that we get back the same value.
   Handle<mirror::MethodType> method1_type2 = hs.NewHandle(
-      class_linker_->ResolveMethodType(dex_file, method1_id.proto_idx_, dex_cache, class_loader));
+      class_linker_->ResolveMethodType(soa.Self(),
+                                       dex_file,
+                                       method1_id.proto_idx_,
+                                       dex_cache,
+                                       class_loader));
   ASSERT_EQ(method1_type.Get(), method1_type2.Get());
 
   // Resolve the MethodType associated with a different method signature
@@ -1529,8 +1537,11 @@
   ASSERT_FALSE(method2->IsDirect());
   const DexFile::MethodId& method2_id = dex_file.GetMethodId(method2->GetDexMethodIndex());
   Handle<mirror::MethodType> method2_type = hs.NewHandle(
-      class_linker_->ResolveMethodType(dex_file, method2_id.proto_idx_, dex_cache, class_loader));
-
+      class_linker_->ResolveMethodType(soa.Self(),
+                                       dex_file,
+                                       method2_id.proto_idx_,
+                                       dex_cache,
+                                       class_loader));
   ASSERT_TRUE(method1_type.Get() != method2_type.Get());
 }
 
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index ea7a83c..cf5cc11 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -2603,7 +2603,7 @@
   gc_visitor.VisitArguments();
 
   // Wrap raw_method_handle in a Handle for safety.
-  StackHandleScope<5> hs(self);
+  StackHandleScope<2> hs(self);
   Handle<mirror::MethodHandle> method_handle(
       hs.NewHandle(ObjPtr<mirror::MethodHandle>::DownCast(MakeObjPtr(raw_method_handle))));
   raw_method_handle = nullptr;
@@ -2622,11 +2622,9 @@
     return static_cast<uintptr_t>('V');
   }
 
-  Handle<mirror::Class> caller_class(hs.NewHandle(caller_method->GetDeclaringClass()));
-  Handle<mirror::MethodType> method_type(hs.NewHandle(linker->ResolveMethodType(
-      *dex_file, proto_idx,
-      hs.NewHandle<mirror::DexCache>(caller_class->GetDexCache()),
-      hs.NewHandle<mirror::ClassLoader>(caller_class->GetClassLoader()))));
+  Handle<mirror::MethodType> method_type(
+      hs.NewHandle(linker->ResolveMethodType(self, proto_idx, caller_method)));
+
   // This implies we couldn't resolve one or more types in this method handle.
   if (UNLIKELY(method_type.IsNull())) {
     CHECK(self->IsExceptionPending());
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 5938113..9fb9fe7 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -610,7 +610,7 @@
   // The invoke_method_idx here is the name of the signature polymorphic method that
   // was symbolically invoked in bytecode (say MethodHandle.invoke or MethodHandle.invokeExact)
   // and not the method that we'll dispatch to in the end.
-  StackHandleScope<5> hs(self);
+  StackHandleScope<2> hs(self);
   Handle<mirror::MethodHandle> method_handle(hs.NewHandle(
       ObjPtr<mirror::MethodHandle>::DownCast(
           MakeObjPtr(shadow_frame.GetVRegReference(vRegC)))));
@@ -629,11 +629,8 @@
   // with the callsite. This information is stored in the dex cache so it's
   // guaranteed to be fast after the first resolution.
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  Handle<mirror::Class> caller_class(hs.NewHandle(shadow_frame.GetMethod()->GetDeclaringClass()));
-  Handle<mirror::MethodType> callsite_type(hs.NewHandle(class_linker->ResolveMethodType(
-      caller_class->GetDexFile(), callsite_proto_id,
-      hs.NewHandle<mirror::DexCache>(caller_class->GetDexCache()),
-      hs.NewHandle<mirror::ClassLoader>(caller_class->GetClassLoader()))));
+  Handle<mirror::MethodType> callsite_type(hs.NewHandle(
+      class_linker->ResolveMethodType(self, callsite_proto_id, shadow_frame.GetMethod())));
 
   // This implies we couldn't resolve one or more types in this method handle.
   if (UNLIKELY(callsite_type == nullptr)) {
@@ -695,7 +692,7 @@
   uint32_t method_handle_idx = static_cast<uint32_t>(it.GetJavaValue().i);
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   Handle<mirror::MethodHandle>
-      bootstrap(hs.NewHandle(class_linker->ResolveMethodHandle(method_handle_idx, referrer)));
+      bootstrap(hs.NewHandle(class_linker->ResolveMethodHandle(self, method_handle_idx, referrer)));
   if (bootstrap.IsNull()) {
     DCHECK(self->IsExceptionPending());
     return nullptr;
@@ -740,7 +737,8 @@
   // The third parameter is the method type associated with the name.
   uint32_t method_type_idx = static_cast<uint32_t>(it.GetJavaValue().i);
   Handle<mirror::MethodType>
-      method_type(hs.NewHandle(class_linker->ResolveMethodType(*dex_file,
+      method_type(hs.NewHandle(class_linker->ResolveMethodType(self,
+                                                               *dex_file,
                                                                method_type_idx,
                                                                dex_cache,
                                                                class_loader)));
@@ -778,7 +776,7 @@
       case EncodedArrayValueIterator::ValueType::kMethodType: {
         uint32_t idx = static_cast<uint32_t>(jvalue.i);
         ObjPtr<mirror::MethodType> ref =
-            class_linker->ResolveMethodType(*dex_file, idx, dex_cache, class_loader);
+            class_linker->ResolveMethodType(self, *dex_file, idx, dex_cache, class_loader);
         if (ref.IsNull()) {
           DCHECK(self->IsExceptionPending());
           return nullptr;
@@ -790,7 +788,7 @@
       case EncodedArrayValueIterator::ValueType::kMethodHandle: {
         uint32_t idx = static_cast<uint32_t>(jvalue.i);
         ObjPtr<mirror::MethodHandle> ref =
-            class_linker->ResolveMethodHandle(idx, referrer);
+            class_linker->ResolveMethodHandle(self, idx, referrer);
         if (ref.IsNull()) {
           DCHECK(self->IsExceptionPending());
           return nullptr;
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 1c79619..e7f67eb 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -206,11 +206,12 @@
   }
 }
 
-static inline mirror::MethodHandle* ResolveMethodHandle(uint32_t method_handle_index,
+static inline mirror::MethodHandle* ResolveMethodHandle(Thread* self,
+                                                        uint32_t method_handle_index,
                                                         ArtMethod* referrer)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  return class_linker->ResolveMethodHandle(method_handle_index, referrer);
+  return class_linker->ResolveMethodHandle(self, method_handle_index, referrer);
 }
 
 static inline mirror::MethodType* ResolveMethodType(Thread* self,
@@ -218,11 +219,7 @@
                                                     ArtMethod* referrer)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  const DexFile* dex_file = referrer->GetDexFile();
-  StackHandleScope<2> hs(self);
-  Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
-  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referrer->GetClassLoader()));
-  return class_linker->ResolveMethodType(*dex_file, method_type_index, dex_cache, class_loader);
+  return class_linker->ResolveMethodType(self, method_type_index, referrer);
 }
 
 // Performs a signature polymorphic invoke (invoke-polymorphic/invoke-polymorphic-range).
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index 74d7901..094f086 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -534,8 +534,8 @@
       }
       case Instruction::CONST_METHOD_HANDLE: {
         PREAMBLE();
-        ObjPtr<mirror::MethodHandle> mh =
-            Runtime::Current()->GetClassLinker()->ResolveMethodHandle(inst->VRegB_21c(), method);
+        ClassLinker* cl = Runtime::Current()->GetClassLinker();
+        ObjPtr<mirror::MethodHandle> mh = cl->ResolveMethodHandle(self, inst->VRegB_21c(), method);
         if (UNLIKELY(mh == nullptr)) {
           HANDLE_PENDING_EXCEPTION();
         } else {
@@ -546,8 +546,8 @@
       }
       case Instruction::CONST_METHOD_TYPE: {
         PREAMBLE();
-        ObjPtr<mirror::MethodType> mt =
-            Runtime::Current()->GetClassLinker()->ResolveMethodType(inst->VRegB_21c(), method);
+        ClassLinker* cl = Runtime::Current()->GetClassLinker();
+        ObjPtr<mirror::MethodType> mt = cl->ResolveMethodType(self, inst->VRegB_21c(), method);
         if (UNLIKELY(mt == nullptr)) {
           HANDLE_PENDING_EXCEPTION();
         } else {
diff --git a/runtime/interpreter/mterp/Makefile_mterp b/runtime/interpreter/mterp/Makefile_mterp
index f0c30ad..ac8da69 100644
--- a/runtime/interpreter/mterp/Makefile_mterp
+++ b/runtime/interpreter/mterp/Makefile_mterp
@@ -25,7 +25,7 @@
 # To generate sources:
 # for arch in arm arm64 x86 x86_64 mips mips64
 # do
-#   TARGET_ARCH_EXT=$arch make -f Makefile-mterp
+#   TARGET_ARCH_EXT=$arch make -f Makefile_mterp
 # done
 #
 
diff --git a/runtime/interpreter/mterp/arm/const.S b/runtime/interpreter/mterp/arm/const.S
new file mode 100644
index 0000000..f6f8157
--- /dev/null
+++ b/runtime/interpreter/mterp/arm/const.S
@@ -0,0 +1,18 @@
+%default { "helper":"UndefinedConstHandler" }
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
+    .extern $helper
+    EXPORT_PC
+    FETCH   r0, 1                       @ r0<- BBBB
+    mov     r1, rINST, lsr #8           @ r1<- AA
+    add     r2, rFP, #OFF_FP_SHADOWFRAME
+    mov     r3, rSELF
+    bl      $helper                     @ (index, tgt_reg, shadow_frame, self)
+    PREFETCH_INST 2                     @ load rINST
+    cmp     r0, #0                      @ fail?
+    bne     MterpPossibleException      @ let reference interpreter deal with it.
+    ADVANCE 2                           @ advance rPC
+    GET_INST_OPCODE ip                  @ extract opcode from rINST
+    GOTO_OPCODE ip                      @ jump to next instruction
diff --git a/runtime/interpreter/mterp/arm/invoke_polymorphic.S b/runtime/interpreter/mterp/arm/invoke_polymorphic.S
new file mode 100644
index 0000000..f569d61
--- /dev/null
+++ b/runtime/interpreter/mterp/arm/invoke_polymorphic.S
@@ -0,0 +1,21 @@
+%default { "helper":"UndefinedInvokeHandler" }
+    /*
+     * invoke-polymorphic handler wrapper.
+     */
+    /* op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB, proto@HHHH */
+    .extern $helper
+    EXPORT_PC
+    mov     r0, rSELF
+    add     r1, rFP, #OFF_FP_SHADOWFRAME
+    mov     r2, rPC
+    mov     r3, rINST
+    bl      $helper
+    cmp     r0, #0
+    beq     MterpException
+    FETCH_ADVANCE_INST 4
+    bl      MterpShouldSwitchInterpreters
+    cmp     r0, #0
+    bne     MterpFallback
+    GET_INST_OPCODE ip
+    GOTO_OPCODE ip
diff --git a/runtime/interpreter/mterp/arm/op_const_class.S b/runtime/interpreter/mterp/arm/op_const_class.S
index 0b111f4..ff5c98c 100644
--- a/runtime/interpreter/mterp/arm/op_const_class.S
+++ b/runtime/interpreter/mterp/arm/op_const_class.S
@@ -1,13 +1 @@
-    /* const/class vAA, Class@BBBB */
-    EXPORT_PC
-    FETCH   r0, 1                       @ r0<- BBBB
-    mov     r1, rINST, lsr #8           @ r1<- AA
-    add     r2, rFP, #OFF_FP_SHADOWFRAME
-    mov     r3, rSELF
-    bl      MterpConstClass             @ (index, tgt_reg, shadow_frame, self)
-    PREFETCH_INST 2
-    cmp     r0, #0
-    bne     MterpPossibleException
-    ADVANCE 2
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip                      @ jump to next instruction
+%include "arm/const.S" { "helper":"MterpConstClass" }
diff --git a/runtime/interpreter/mterp/arm/op_const_method_handle.S b/runtime/interpreter/mterp/arm/op_const_method_handle.S
new file mode 100644
index 0000000..71f0550
--- /dev/null
+++ b/runtime/interpreter/mterp/arm/op_const_method_handle.S
@@ -0,0 +1 @@
+%include "arm/const.S" { "helper":"MterpConstMethodHandle" }
diff --git a/runtime/interpreter/mterp/arm/op_const_method_type.S b/runtime/interpreter/mterp/arm/op_const_method_type.S
new file mode 100644
index 0000000..2cccdaf
--- /dev/null
+++ b/runtime/interpreter/mterp/arm/op_const_method_type.S
@@ -0,0 +1 @@
+%include "arm/const.S" { "helper":"MterpConstMethodType" }
diff --git a/runtime/interpreter/mterp/arm/op_const_string.S b/runtime/interpreter/mterp/arm/op_const_string.S
index 4b8302a..75ec34f 100644
--- a/runtime/interpreter/mterp/arm/op_const_string.S
+++ b/runtime/interpreter/mterp/arm/op_const_string.S
@@ -1,13 +1 @@
-    /* const/string vAA, String@BBBB */
-    EXPORT_PC
-    FETCH r0, 1                         @ r0<- BBBB
-    mov     r1, rINST, lsr #8           @ r1<- AA
-    add     r2, rFP, #OFF_FP_SHADOWFRAME
-    mov     r3, rSELF
-    bl      MterpConstString            @ (index, tgt_reg, shadow_frame, self)
-    PREFETCH_INST 2                     @ load rINST
-    cmp     r0, #0                      @ fail?
-    bne     MterpPossibleException      @ let reference interpreter deal with it.
-    ADVANCE 2                           @ advance rPC
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip                      @ jump to next instruction
+%include "arm/const.S" { "helper":"MterpConstString" }
diff --git a/runtime/interpreter/mterp/arm/op_invoke_custom.S b/runtime/interpreter/mterp/arm/op_invoke_custom.S
new file mode 100644
index 0000000..2af875c
--- /dev/null
+++ b/runtime/interpreter/mterp/arm/op_invoke_custom.S
@@ -0,0 +1,8 @@
+%include "arm/invoke.S" { "helper":"MterpInvokeCustom" }
+    /*
+     * Handle an invoke-custom invocation.
+     *
+     * for: invoke-custom, invoke-custom/range
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, call_site@BBBB */
+    /* op vAA, {vCCCC..v(CCCC+AA-1)}, call_site@BBBB */
diff --git a/runtime/interpreter/mterp/arm/op_invoke_custom_range.S b/runtime/interpreter/mterp/arm/op_invoke_custom_range.S
new file mode 100644
index 0000000..32575c4
--- /dev/null
+++ b/runtime/interpreter/mterp/arm/op_invoke_custom_range.S
@@ -0,0 +1 @@
+%include "arm/invoke.S" { "helper":"MterpInvokeCustomRange" }
diff --git a/runtime/interpreter/mterp/arm/op_invoke_polymorphic.S b/runtime/interpreter/mterp/arm/op_invoke_polymorphic.S
new file mode 100644
index 0000000..816a7ae
--- /dev/null
+++ b/runtime/interpreter/mterp/arm/op_invoke_polymorphic.S
@@ -0,0 +1 @@
+%include "arm/invoke_polymorphic.S" { "helper":"MterpInvokePolymorphic" }
diff --git a/runtime/interpreter/mterp/arm/op_invoke_polymorphic_range.S b/runtime/interpreter/mterp/arm/op_invoke_polymorphic_range.S
new file mode 100644
index 0000000..2541c27
--- /dev/null
+++ b/runtime/interpreter/mterp/arm/op_invoke_polymorphic_range.S
@@ -0,0 +1 @@
+%include "arm/invoke_polymorphic.S" { "helper":"MterpInvokePolymorphicRange" }
diff --git a/runtime/interpreter/mterp/arm/op_unused_fe.S b/runtime/interpreter/mterp/arm/op_unused_fe.S
deleted file mode 100644
index 10948dc..0000000
--- a/runtime/interpreter/mterp/arm/op_unused_fe.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "arm/unused.S"
diff --git a/runtime/interpreter/mterp/arm/op_unused_ff.S b/runtime/interpreter/mterp/arm/op_unused_ff.S
deleted file mode 100644
index 10948dc..0000000
--- a/runtime/interpreter/mterp/arm/op_unused_ff.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "arm/unused.S"
diff --git a/runtime/interpreter/mterp/arm64/const.S b/runtime/interpreter/mterp/arm64/const.S
new file mode 100644
index 0000000..6f82bbf
--- /dev/null
+++ b/runtime/interpreter/mterp/arm64/const.S
@@ -0,0 +1,17 @@
+%default { "helper":"UndefinedConstHandler" }
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
+    .extern $helper
+    EXPORT_PC
+    FETCH w0, 1                         // w0<- BBBB
+    lsr     w1, wINST, #8               // w1<- AA
+    add     x2, xFP, #OFF_FP_SHADOWFRAME
+    mov     x3, xSELF
+    bl      $helper                     // (index, tgt_reg, shadow_frame, self)
+    PREFETCH_INST 2                     // load rINST
+    cbnz    w0, MterpPossibleException  // let reference interpreter deal with it.
+    ADVANCE 2                           // advance rPC
+    GET_INST_OPCODE ip                  // extract opcode from rINST
+    GOTO_OPCODE ip                      // jump to next instruction
diff --git a/runtime/interpreter/mterp/arm64/invoke_polymorphic.S b/runtime/interpreter/mterp/arm64/invoke_polymorphic.S
new file mode 100644
index 0000000..7906f0a
--- /dev/null
+++ b/runtime/interpreter/mterp/arm64/invoke_polymorphic.S
@@ -0,0 +1,19 @@
+%default { "helper":"UndefinedInvokeHandler" }
+    /*
+     * invoke-polymorphic handler wrapper.
+     */
+    /* op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB, proto@HHHH */
+    .extern $helper
+    EXPORT_PC
+    mov     x0, xSELF
+    add     x1, xFP, #OFF_FP_SHADOWFRAME
+    mov     x2, xPC
+    mov     x3, xINST
+    bl      $helper
+    cbz     w0, MterpException
+    FETCH_ADVANCE_INST 4
+    bl      MterpShouldSwitchInterpreters
+    cbnz    w0, MterpFallback
+    GET_INST_OPCODE ip
+    GOTO_OPCODE ip
diff --git a/runtime/interpreter/mterp/arm64/op_const_class.S b/runtime/interpreter/mterp/arm64/op_const_class.S
index 971cfa0..7228245 100644
--- a/runtime/interpreter/mterp/arm64/op_const_class.S
+++ b/runtime/interpreter/mterp/arm64/op_const_class.S
@@ -1,12 +1 @@
-    /* const/class vAA, Class//BBBB */
-    EXPORT_PC
-    FETCH   w0, 1                       // w0<- BBBB
-    lsr     w1, wINST, #8               // w1<- AA
-    add     x2, xFP, #OFF_FP_SHADOWFRAME
-    mov     x3, xSELF
-    bl      MterpConstClass             // (index, tgt_reg, shadow_frame, self)
-    PREFETCH_INST 2
-    cbnz    w0, MterpPossibleException
-    ADVANCE 2
-    GET_INST_OPCODE ip                  // extract opcode from rINST
-    GOTO_OPCODE ip                      // jump to next instruction
+%include "arm64/const.S" { "helper":"MterpConstClass" }
diff --git a/runtime/interpreter/mterp/arm64/op_const_method_handle.S b/runtime/interpreter/mterp/arm64/op_const_method_handle.S
new file mode 100644
index 0000000..0df0fa6
--- /dev/null
+++ b/runtime/interpreter/mterp/arm64/op_const_method_handle.S
@@ -0,0 +1 @@
+%include "arm64/const.S" { "helper":"MterpConstMethodHandle" }
diff --git a/runtime/interpreter/mterp/arm64/op_const_method_type.S b/runtime/interpreter/mterp/arm64/op_const_method_type.S
new file mode 100644
index 0000000..1adfe5a
--- /dev/null
+++ b/runtime/interpreter/mterp/arm64/op_const_method_type.S
@@ -0,0 +1 @@
+%include "arm64/const.S" { "helper":"MterpConstMethodType" }
diff --git a/runtime/interpreter/mterp/arm64/op_const_string.S b/runtime/interpreter/mterp/arm64/op_const_string.S
index 896f1e7..8cf0d6d 100644
--- a/runtime/interpreter/mterp/arm64/op_const_string.S
+++ b/runtime/interpreter/mterp/arm64/op_const_string.S
@@ -1,12 +1 @@
-    /* const/string vAA, String//BBBB */
-    EXPORT_PC
-    FETCH w0, 1                         // w0<- BBBB
-    lsr     w1, wINST, #8               // w1<- AA
-    add     x2, xFP, #OFF_FP_SHADOWFRAME
-    mov     x3, xSELF
-    bl      MterpConstString            // (index, tgt_reg, shadow_frame, self)
-    PREFETCH_INST 2                     // load rINST
-    cbnz    w0, MterpPossibleException  // let reference interpreter deal with it.
-    ADVANCE 2                           // advance rPC
-    GET_INST_OPCODE ip                  // extract opcode from rINST
-    GOTO_OPCODE ip                      // jump to next instruction
+%include "arm64/const.S" { "helper":"MterpConstString" }
diff --git a/runtime/interpreter/mterp/arm64/op_invoke_custom.S b/runtime/interpreter/mterp/arm64/op_invoke_custom.S
new file mode 100644
index 0000000..3686584
--- /dev/null
+++ b/runtime/interpreter/mterp/arm64/op_invoke_custom.S
@@ -0,0 +1 @@
+%include "arm64/invoke.S" { "helper":"MterpInvokeCustom" }
diff --git a/runtime/interpreter/mterp/arm64/op_invoke_custom_range.S b/runtime/interpreter/mterp/arm64/op_invoke_custom_range.S
new file mode 100644
index 0000000..06de86a
--- /dev/null
+++ b/runtime/interpreter/mterp/arm64/op_invoke_custom_range.S
@@ -0,0 +1 @@
+%include "arm64/invoke.S" { "helper":"MterpInvokeCustomRange" }
diff --git a/runtime/interpreter/mterp/arm64/op_invoke_polymorphic.S b/runtime/interpreter/mterp/arm64/op_invoke_polymorphic.S
new file mode 100644
index 0000000..aace98f
--- /dev/null
+++ b/runtime/interpreter/mterp/arm64/op_invoke_polymorphic.S
@@ -0,0 +1 @@
+%include "arm64/invoke_polymorphic.S" { "helper":"MterpInvokePolymorphic" }
diff --git a/runtime/interpreter/mterp/arm64/op_invoke_polymorphic_range.S b/runtime/interpreter/mterp/arm64/op_invoke_polymorphic_range.S
new file mode 100644
index 0000000..30c8c09
--- /dev/null
+++ b/runtime/interpreter/mterp/arm64/op_invoke_polymorphic_range.S
@@ -0,0 +1 @@
+%include "arm64/invoke_polymorphic.S" { "helper":"MterpInvokePolymorphicRange" }
diff --git a/runtime/interpreter/mterp/arm64/op_unused_fe.S b/runtime/interpreter/mterp/arm64/op_unused_fe.S
deleted file mode 100644
index 204ecef..0000000
--- a/runtime/interpreter/mterp/arm64/op_unused_fe.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "arm64/unused.S"
diff --git a/runtime/interpreter/mterp/arm64/op_unused_ff.S b/runtime/interpreter/mterp/arm64/op_unused_ff.S
deleted file mode 100644
index 204ecef..0000000
--- a/runtime/interpreter/mterp/arm64/op_unused_ff.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "arm64/unused.S"
diff --git a/runtime/interpreter/mterp/config_arm b/runtime/interpreter/mterp/config_arm
index b19426b..a45efd9 100644
--- a/runtime/interpreter/mterp/config_arm
+++ b/runtime/interpreter/mterp/config_arm
@@ -286,12 +286,12 @@
     # op op_unused_f7 FALLBACK
     # op op_unused_f8 FALLBACK
     # op op_unused_f9 FALLBACK
-    op op_invoke_polymorphic FALLBACK
-    op op_invoke_polymorphic_range FALLBACK
-    op op_invoke_custom FALLBACK
-    op op_invoke_custom_range FALLBACK
-    # op op_unused_fe FALLBACK
-    # op op_unused_ff FALLBACK
+    # op op_invoke_polymorphic FALLBACK
+    # op op_invoke_polymorphic_range FALLBACK
+    # op op_invoke_custom FALLBACK
+    # op op_invoke_custom_range FALLBACK
+    # op op_const_method_handle FALLBACK
+    # op op_const_method_type FALLBACK
 op-end
 
 # common subroutines for asm
diff --git a/runtime/interpreter/mterp/config_arm64 b/runtime/interpreter/mterp/config_arm64
index 0987964..0831c3b 100644
--- a/runtime/interpreter/mterp/config_arm64
+++ b/runtime/interpreter/mterp/config_arm64
@@ -284,12 +284,12 @@
     # op op_unused_f7 FALLBACK
     # op op_unused_f8 FALLBACK
     # op op_unused_f9 FALLBACK
-    op op_invoke_polymorphic FALLBACK
-    op op_invoke_polymorphic_range FALLBACK
-    op op_invoke_custom FALLBACK
-    op op_invoke_custom_range FALLBACK
-    # op op_unused_fe FALLBACK
-    # op op_unused_ff FALLBACK
+    # op op_invoke_polymorphic FALLBACK
+    # op op_invoke_polymorphic_range FALLBACK
+    # op op_invoke_custom FALLBACK
+    # op op_invoke_custom_range FALLBACK
+    # op op_const_method_handle FALLBACK
+    # op op_const_method_type FALLBACK
 op-end
 
 # common subroutines for asm; we emit the footer before alternate
diff --git a/runtime/interpreter/mterp/config_mips b/runtime/interpreter/mterp/config_mips
index fe07385..d6173da 100644
--- a/runtime/interpreter/mterp/config_mips
+++ b/runtime/interpreter/mterp/config_mips
@@ -286,12 +286,12 @@
     # op op_unused_f7 FALLBACK
     # op op_unused_f8 FALLBACK
     # op op_unused_f9 FALLBACK
-    op op_invoke_polymorphic FALLBACK
-    op op_invoke_polymorphic_range FALLBACK
-    op op_invoke_custom FALLBACK
-    op op_invoke_custom_range FALLBACK
-    # op op_unused_fe FALLBACK
-    # op op_unused_ff FALLBACK
+    # op op_invoke_polymorphic FALLBACK
+    # op op_invoke_polymorphic_range FALLBACK
+    # op op_invoke_custom FALLBACK
+    # op op_invoke_custom_range FALLBACK
+    # op op_const_method_handle FALLBACK
+    # op op_const_method_type FALLBACK
 op-end
 
 # common subroutines for asm
diff --git a/runtime/interpreter/mterp/config_mips64 b/runtime/interpreter/mterp/config_mips64
index d24cf4d..a9bf362 100644
--- a/runtime/interpreter/mterp/config_mips64
+++ b/runtime/interpreter/mterp/config_mips64
@@ -286,12 +286,12 @@
     # op op_unused_f7 FALLBACK
     # op op_unused_f8 FALLBACK
     # op op_unused_f9 FALLBACK
-    op op_invoke_polymorphic FALLBACK
-    op op_invoke_polymorphic_range FALLBACK
-    op op_invoke_custom FALLBACK
-    op op_invoke_custom_range FALLBACK
-    # op op_unused_fe FALLBACK
-    # op op_unused_ff FALLBACK
+    # op op_invoke_polymorphic FALLBACK
+    # op op_invoke_polymorphic_range FALLBACK
+    # op op_invoke_custom FALLBACK
+    # op op_invoke_custom_range FALLBACK
+    # op op_const_method_handle FALLBACK
+    # op op_const_method_type FALLBACK
 op-end
 
 # common subroutines for asm
diff --git a/runtime/interpreter/mterp/config_x86 b/runtime/interpreter/mterp/config_x86
index 076baf2..2417851 100644
--- a/runtime/interpreter/mterp/config_x86
+++ b/runtime/interpreter/mterp/config_x86
@@ -290,12 +290,12 @@
     # op op_unused_f7 FALLBACK
     # op op_unused_f8 FALLBACK
     # op op_unused_f9 FALLBACK
-    op op_invoke_polymorphic FALLBACK
-    op op_invoke_polymorphic_range FALLBACK
-    op op_invoke_custom FALLBACK
-    op op_invoke_custom_range FALLBACK
-    # op op_unused_fe FALLBACK
-    # op op_unused_ff FALLBACK
+    # op op_invoke_polymorphic FALLBACK
+    # op op_invoke_polymorphic_range FALLBACK
+    # op op_invoke_custom FALLBACK
+    # op op_invoke_custom_range FALLBACK
+    # op op_const_method_handle FALLBACK
+    # op op_const_method_type FALLBACK
 op-end
 
 # common subroutines for asm
diff --git a/runtime/interpreter/mterp/config_x86_64 b/runtime/interpreter/mterp/config_x86_64
index 44b671a..89fbf43 100644
--- a/runtime/interpreter/mterp/config_x86_64
+++ b/runtime/interpreter/mterp/config_x86_64
@@ -290,12 +290,12 @@
     # op op_unused_f7 FALLBACK
     # op op_unused_f8 FALLBACK
     # op op_unused_f9 FALLBACK
-    op op_invoke_polymorphic FALLBACK
-    op op_invoke_polymorphic_range FALLBACK
-    op op_invoke_custom FALLBACK
-    op op_invoke_custom_range FALLBACK
-    # op op_unused_fe FALLBACK
-    # op op_unused_ff FALLBACK
+    # op op_invoke_polymorphic FALLBACK
+    # op op_invoke_polymorphic_range FALLBACK
+    # op op_invoke_custom FALLBACK
+    # op op_invoke_custom_range FALLBACK
+    # op op_const_method_handle FALLBACK
+    # op op_const_method_type FALLBACK
 op-end
 
 # common subroutines for asm
diff --git a/runtime/interpreter/mterp/mips/const.S b/runtime/interpreter/mterp/mips/const.S
new file mode 100644
index 0000000..5d8379d
--- /dev/null
+++ b/runtime/interpreter/mterp/mips/const.S
@@ -0,0 +1,17 @@
+%default { "helper":"UndefinedConstHandler" }
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
+    .extern $helper
+    EXPORT_PC()
+    FETCH(a0, 1)                        # a0 <- BBBB
+    GET_OPA(a1)                         # a1 <- AA
+    addu   a2, rFP, OFF_FP_SHADOWFRAME  # a2 <- shadow frame
+    move   a3, rSELF
+    JAL($helper)                        # v0 <- Mterp(index, tgt_reg, shadow_frame, self)
+    PREFETCH_INST(2)                    # load rINST
+    bnez   v0, MterpPossibleException
+    ADVANCE(2)                          # advance rPC
+    GET_INST_OPCODE(t0)                 # extract opcode from rINST
+    GOTO_OPCODE(t0)                     # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips/invoke_polymorphic.S b/runtime/interpreter/mterp/mips/invoke_polymorphic.S
new file mode 100644
index 0000000..5c963f0
--- /dev/null
+++ b/runtime/interpreter/mterp/mips/invoke_polymorphic.S
@@ -0,0 +1,19 @@
+%default { "helper":"UndefinedInvokeHandler" }
+    /*
+     * invoke-polymorphic handler wrapper.
+     */
+    /* op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB, proto@HHHH */
+    .extern $helper
+    EXPORT_PC()
+    move    a0, rSELF
+    addu    a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rPC
+    move    a3, rINST
+    JAL($helper)
+    beqz    v0, MterpException
+    FETCH_ADVANCE_INST(4)
+    JAL(MterpShouldSwitchInterpreters)
+    bnez    v0, MterpFallback
+    GET_INST_OPCODE(t0)
+    GOTO_OPCODE(t0)
diff --git a/runtime/interpreter/mterp/mips/op_const_class.S b/runtime/interpreter/mterp/mips/op_const_class.S
index 9adea44..5b3c968 100644
--- a/runtime/interpreter/mterp/mips/op_const_class.S
+++ b/runtime/interpreter/mterp/mips/op_const_class.S
@@ -1,12 +1 @@
-    /* const/class vAA, class@BBBB */
-    EXPORT_PC()
-    FETCH(a0, 1)                        # a0 <- BBBB
-    GET_OPA(a1)                         # a1 <- AA
-    addu   a2, rFP, OFF_FP_SHADOWFRAME  # a2 <- shadow frame
-    move   a3, rSELF
-    JAL(MterpConstClass)
-    PREFETCH_INST(2)                    # load rINST
-    bnez   v0, MterpPossibleException
-    ADVANCE(2)                          # advance rPC
-    GET_INST_OPCODE(t0)                 # extract opcode from rINST
-    GOTO_OPCODE(t0)                     # jump to next instruction
+%include "mips/const.S" { "helper":"MterpConstClass" }
diff --git a/runtime/interpreter/mterp/mips/op_const_method_handle.S b/runtime/interpreter/mterp/mips/op_const_method_handle.S
new file mode 100644
index 0000000..4011e43
--- /dev/null
+++ b/runtime/interpreter/mterp/mips/op_const_method_handle.S
@@ -0,0 +1 @@
+%include "mips/const.S" { "helper":"MterpConstMethodHandle" }
diff --git a/runtime/interpreter/mterp/mips/op_const_method_type.S b/runtime/interpreter/mterp/mips/op_const_method_type.S
new file mode 100644
index 0000000..18a5e0f
--- /dev/null
+++ b/runtime/interpreter/mterp/mips/op_const_method_type.S
@@ -0,0 +1 @@
+%include "mips/const.S" { "helper":"MterpConstMethodType" }
diff --git a/runtime/interpreter/mterp/mips/op_const_string.S b/runtime/interpreter/mterp/mips/op_const_string.S
index 006e114..0bab6b4 100644
--- a/runtime/interpreter/mterp/mips/op_const_string.S
+++ b/runtime/interpreter/mterp/mips/op_const_string.S
@@ -1,12 +1 @@
-    /* const/string vAA, string@BBBB */
-    EXPORT_PC()
-    FETCH(a0, 1)                        # a0 <- BBBB
-    GET_OPA(a1)                         # a1 <- AA
-    addu   a2, rFP, OFF_FP_SHADOWFRAME  # a2 <- shadow frame
-    move   a3, rSELF
-    JAL(MterpConstString)               # v0 <- Mterp(index, tgt_reg, shadow_frame, self)
-    PREFETCH_INST(2)                    # load rINST
-    bnez   v0, MterpPossibleException
-    ADVANCE(2)                          # advance rPC
-    GET_INST_OPCODE(t0)                 # extract opcode from rINST
-    GOTO_OPCODE(t0)                     # jump to next instruction
+%include "mips/const.S" { "helper":"MterpConstString" }
diff --git a/runtime/interpreter/mterp/mips/op_invoke_custom.S b/runtime/interpreter/mterp/mips/op_invoke_custom.S
new file mode 100644
index 0000000..f9241c4
--- /dev/null
+++ b/runtime/interpreter/mterp/mips/op_invoke_custom.S
@@ -0,0 +1 @@
+%include "mips/invoke.S" { "helper":"MterpInvokeCustom" }
diff --git a/runtime/interpreter/mterp/mips/op_invoke_custom_range.S b/runtime/interpreter/mterp/mips/op_invoke_custom_range.S
new file mode 100644
index 0000000..862a614
--- /dev/null
+++ b/runtime/interpreter/mterp/mips/op_invoke_custom_range.S
@@ -0,0 +1 @@
+%include "mips/invoke.S" { "helper":"MterpInvokeCustomRange" }
diff --git a/runtime/interpreter/mterp/mips/op_invoke_polymorphic.S b/runtime/interpreter/mterp/mips/op_invoke_polymorphic.S
new file mode 100644
index 0000000..85e01e7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips/op_invoke_polymorphic.S
@@ -0,0 +1 @@
+%include "mips/invoke_polymorphic.S" { "helper":"MterpInvokePolymorphic" }
diff --git a/runtime/interpreter/mterp/mips/op_invoke_polymorphic_range.S b/runtime/interpreter/mterp/mips/op_invoke_polymorphic_range.S
new file mode 100644
index 0000000..ce63978
--- /dev/null
+++ b/runtime/interpreter/mterp/mips/op_invoke_polymorphic_range.S
@@ -0,0 +1 @@
+%include "mips/invoke_polymorphic.S" { "helper":"MterpInvokePolymorphicRange" }
diff --git a/runtime/interpreter/mterp/mips/op_unused_fe.S b/runtime/interpreter/mterp/mips/op_unused_fe.S
deleted file mode 100644
index 99ef3cf..0000000
--- a/runtime/interpreter/mterp/mips/op_unused_fe.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "mips/unused.S"
diff --git a/runtime/interpreter/mterp/mips/op_unused_ff.S b/runtime/interpreter/mterp/mips/op_unused_ff.S
deleted file mode 100644
index 99ef3cf..0000000
--- a/runtime/interpreter/mterp/mips/op_unused_ff.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "mips/unused.S"
diff --git a/runtime/interpreter/mterp/mips64/const.S b/runtime/interpreter/mterp/mips64/const.S
new file mode 100644
index 0000000..2ec1173
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/const.S
@@ -0,0 +1,17 @@
+%default { "helper":"UndefinedConstHandler" }
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
+    .extern $helper
+    EXPORT_PC
+    lhu     a0, 2(rPC)                  # a0 <- BBBB
+    srl     a1, rINST, 8                # a1 <- AA
+    daddu   a2, rFP, OFF_FP_SHADOWFRAME
+    move    a3, rSELF
+    jal     $helper                     # (index, tgt_reg, shadow_frame, self)
+    PREFETCH_INST 2                     # load rINST
+    bnez    v0, MterpPossibleException  # let reference interpreter deal with it.
+    ADVANCE 2                           # advance rPC
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/invoke_polymorphic.S b/runtime/interpreter/mterp/mips64/invoke_polymorphic.S
new file mode 100644
index 0000000..fa82083
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/invoke_polymorphic.S
@@ -0,0 +1,20 @@
+%default { "helper":"UndefinedInvokeHandler" }
+    /*
+     * invoke-polymorphic handler wrapper.
+     */
+    /* op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB, proto@HHHH */
+    .extern $helper
+    .extern MterpShouldSwitchInterpreters
+    EXPORT_PC
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rPC
+    move    a3, rINST
+    jal     $helper
+    beqzc   v0, MterpException
+    FETCH_ADVANCE_INST 4
+    jal     MterpShouldSwitchInterpreters
+    bnezc   v0, MterpFallback
+    GET_INST_OPCODE v0
+    GOTO_OPCODE v0
diff --git a/runtime/interpreter/mterp/mips64/op_const_class.S b/runtime/interpreter/mterp/mips64/op_const_class.S
index adf79df..3f0c716 100644
--- a/runtime/interpreter/mterp/mips64/op_const_class.S
+++ b/runtime/interpreter/mterp/mips64/op_const_class.S
@@ -1,13 +1 @@
-    /* const/class vAA, Class//BBBB */
-    .extern MterpConstClass
-    EXPORT_PC
-    lhu     a0, 2(rPC)                  # a0 <- BBBB
-    srl     a1, rINST, 8                # a1 <- AA
-    daddu   a2, rFP, OFF_FP_SHADOWFRAME
-    move    a3, rSELF
-    jal     MterpConstClass             # (index, tgt_reg, shadow_frame, self)
-    PREFETCH_INST 2                     # load rINST
-    bnez    v0, MterpPossibleException  # let reference interpreter deal with it.
-    ADVANCE 2                           # advance rPC
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+%include "mips64/const.S" { "helper":"MterpConstClass" }
diff --git a/runtime/interpreter/mterp/mips64/op_const_method_handle.S b/runtime/interpreter/mterp/mips64/op_const_method_handle.S
new file mode 100644
index 0000000..43584d1
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_const_method_handle.S
@@ -0,0 +1 @@
+%include "mips64/const.S" { "helper":"MterpConstMethodHandle" }
diff --git a/runtime/interpreter/mterp/mips64/op_const_method_type.S b/runtime/interpreter/mterp/mips64/op_const_method_type.S
new file mode 100644
index 0000000..553b284
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_const_method_type.S
@@ -0,0 +1 @@
+%include "mips64/const.S" { "helper":"MterpConstMethodType" }
diff --git a/runtime/interpreter/mterp/mips64/op_const_string.S b/runtime/interpreter/mterp/mips64/op_const_string.S
index 4684c11..96cbb5a 100644
--- a/runtime/interpreter/mterp/mips64/op_const_string.S
+++ b/runtime/interpreter/mterp/mips64/op_const_string.S
@@ -1,13 +1 @@
-    /* const/string vAA, String//BBBB */
-    .extern MterpConstString
-    EXPORT_PC
-    lhu     a0, 2(rPC)                  # a0 <- BBBB
-    srl     a1, rINST, 8                # a1 <- AA
-    daddu   a2, rFP, OFF_FP_SHADOWFRAME
-    move    a3, rSELF
-    jal     MterpConstString            # (index, tgt_reg, shadow_frame, self)
-    PREFETCH_INST 2                     # load rINST
-    bnez    v0, MterpPossibleException  # let reference interpreter deal with it.
-    ADVANCE 2                           # advance rPC
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+%include "mips64/const.S" { "helper":"MterpConstString" }
diff --git a/runtime/interpreter/mterp/mips64/op_invoke_custom.S b/runtime/interpreter/mterp/mips64/op_invoke_custom.S
new file mode 100644
index 0000000..964253d
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_invoke_custom.S
@@ -0,0 +1 @@
+%include "mips64/invoke.S" { "helper":"MterpInvokeCustom" }
diff --git a/runtime/interpreter/mterp/mips64/op_invoke_custom_range.S b/runtime/interpreter/mterp/mips64/op_invoke_custom_range.S
new file mode 100644
index 0000000..e6585e3
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_invoke_custom_range.S
@@ -0,0 +1 @@
+%include "mips64/invoke.S" { "helper":"MterpInvokeCustomRange" }
diff --git a/runtime/interpreter/mterp/mips64/op_invoke_polymorphic.S b/runtime/interpreter/mterp/mips64/op_invoke_polymorphic.S
new file mode 100644
index 0000000..d9324d7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_invoke_polymorphic.S
@@ -0,0 +1 @@
+%include "mips64/invoke_polymorphic.S" { "helper":"MterpInvokePolymorphic" }
diff --git a/runtime/interpreter/mterp/mips64/op_invoke_polymorphic_range.S b/runtime/interpreter/mterp/mips64/op_invoke_polymorphic_range.S
new file mode 100644
index 0000000..8e0ecb5
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_invoke_polymorphic_range.S
@@ -0,0 +1 @@
+%include "mips64/invoke_polymorphic.S" { "helper":"MterpInvokePolymorphicRange" }
diff --git a/runtime/interpreter/mterp/mips64/op_unused_fe.S b/runtime/interpreter/mterp/mips64/op_unused_fe.S
deleted file mode 100644
index 29463d7..0000000
--- a/runtime/interpreter/mterp/mips64/op_unused_fe.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "mips64/unused.S"
diff --git a/runtime/interpreter/mterp/mips64/op_unused_ff.S b/runtime/interpreter/mterp/mips64/op_unused_ff.S
deleted file mode 100644
index 29463d7..0000000
--- a/runtime/interpreter/mterp/mips64/op_unused_ff.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "mips64/unused.S"
diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc
index 2318125..404c260 100644
--- a/runtime/interpreter/mterp/mterp.cc
+++ b/runtime/interpreter/mterp/mterp.cc
@@ -211,6 +211,28 @@
       self, *shadow_frame, inst, inst_data, result_register);
 }
 
+extern "C" size_t MterpInvokeCustom(Thread* self,
+                                    ShadowFrame* shadow_frame,
+                                    uint16_t* dex_pc_ptr,
+                                    uint16_t inst_data)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  JValue* result_register = shadow_frame->GetResultRegister();
+  const Instruction* inst = Instruction::At(dex_pc_ptr);
+  return DoInvokeCustom<false /* is_range */>(
+      self, *shadow_frame, inst, inst_data, result_register);
+}
+
+extern "C" size_t MterpInvokePolymorphic(Thread* self,
+                                         ShadowFrame* shadow_frame,
+                                         uint16_t* dex_pc_ptr,
+                                         uint16_t inst_data)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  JValue* result_register = shadow_frame->GetResultRegister();
+  const Instruction* inst = Instruction::At(dex_pc_ptr);
+  return DoInvokePolymorphic<false /* is_range */>(
+      self, *shadow_frame, inst, inst_data, result_register);
+}
+
 extern "C" size_t MterpInvokeVirtualRange(Thread* self,
                                           ShadowFrame* shadow_frame,
                                           uint16_t* dex_pc_ptr,
@@ -266,6 +288,27 @@
       self, *shadow_frame, inst, inst_data, result_register);
 }
 
+extern "C" size_t MterpInvokeCustomRange(Thread* self,
+                                         ShadowFrame* shadow_frame,
+                                         uint16_t* dex_pc_ptr,
+                                         uint16_t inst_data)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  JValue* result_register = shadow_frame->GetResultRegister();
+  const Instruction* inst = Instruction::At(dex_pc_ptr);
+  return DoInvokeCustom<true /* is_range */>(self, *shadow_frame, inst, inst_data, result_register);
+}
+
+extern "C" size_t MterpInvokePolymorphicRange(Thread* self,
+                                              ShadowFrame* shadow_frame,
+                                              uint16_t* dex_pc_ptr,
+                                              uint16_t inst_data)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  JValue* result_register = shadow_frame->GetResultRegister();
+  const Instruction* inst = Instruction::At(dex_pc_ptr);
+  return DoInvokePolymorphic<true /* is_range */>(
+      self, *shadow_frame, inst, inst_data, result_register);
+}
+
 extern "C" size_t MterpInvokeVirtualQuick(Thread* self,
                                           ShadowFrame* shadow_frame,
                                           uint16_t* dex_pc_ptr,
@@ -339,6 +382,32 @@
   return false;
 }
 
+extern "C" size_t MterpConstMethodHandle(uint32_t index,
+                                         uint32_t tgt_vreg,
+                                         ShadowFrame* shadow_frame,
+                                         Thread* self)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  ObjPtr<mirror::MethodHandle> mh = ResolveMethodHandle(self, index, shadow_frame->GetMethod());
+  if (UNLIKELY(mh == nullptr)) {
+    return true;
+  }
+  shadow_frame->SetVRegReference(tgt_vreg, mh.Ptr());
+  return false;
+}
+
+extern "C" size_t MterpConstMethodType(uint32_t index,
+                                       uint32_t tgt_vreg,
+                                       ShadowFrame* shadow_frame,
+                                       Thread* self)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  ObjPtr<mirror::MethodType> mt = ResolveMethodType(self, index, shadow_frame->GetMethod());
+  if (UNLIKELY(mt == nullptr)) {
+    return true;
+  }
+  shadow_frame->SetVRegReference(tgt_vreg, mt.Ptr());
+  return false;
+}
+
 extern "C" size_t MterpCheckCast(uint32_t index,
                                  StackReference<mirror::Object>* vreg_addr,
                                  art::ArtMethod* method,
diff --git a/runtime/interpreter/mterp/out/mterp_arm.S b/runtime/interpreter/mterp/out/mterp_arm.S
index d6a27b8..393a9cc 100644
--- a/runtime/interpreter/mterp/out/mterp_arm.S
+++ b/runtime/interpreter/mterp/out/mterp_arm.S
@@ -841,13 +841,18 @@
     .balign 128
 .L_op_const_string: /* 0x1a */
 /* File: arm/op_const_string.S */
-    /* const/string vAA, String@BBBB */
+/* File: arm/const.S */
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
+    .extern MterpConstString
     EXPORT_PC
-    FETCH r0, 1                         @ r0<- BBBB
+    FETCH   r0, 1                       @ r0<- BBBB
     mov     r1, rINST, lsr #8           @ r1<- AA
     add     r2, rFP, #OFF_FP_SHADOWFRAME
     mov     r3, rSELF
-    bl      MterpConstString            @ (index, tgt_reg, shadow_frame, self)
+    bl      MterpConstString                     @ (index, tgt_reg, shadow_frame, self)
     PREFETCH_INST 2                     @ load rINST
     cmp     r0, #0                      @ fail?
     bne     MterpPossibleException      @ let reference interpreter deal with it.
@@ -855,6 +860,7 @@
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     GOTO_OPCODE ip                      @ jump to next instruction
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_const_string_jumbo: /* 0x1b */
@@ -879,20 +885,26 @@
     .balign 128
 .L_op_const_class: /* 0x1c */
 /* File: arm/op_const_class.S */
-    /* const/class vAA, Class@BBBB */
+/* File: arm/const.S */
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
+    .extern MterpConstClass
     EXPORT_PC
     FETCH   r0, 1                       @ r0<- BBBB
     mov     r1, rINST, lsr #8           @ r1<- AA
     add     r2, rFP, #OFF_FP_SHADOWFRAME
     mov     r3, rSELF
-    bl      MterpConstClass             @ (index, tgt_reg, shadow_frame, self)
-    PREFETCH_INST 2
-    cmp     r0, #0
-    bne     MterpPossibleException
-    ADVANCE 2
+    bl      MterpConstClass                     @ (index, tgt_reg, shadow_frame, self)
+    PREFETCH_INST 2                     @ load rINST
+    cmp     r0, #0                      @ fail?
+    bne     MterpPossibleException      @ let reference interpreter deal with it.
+    ADVANCE 2                           @ advance rPC
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     GOTO_OPCODE ip                      @ jump to next instruction
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_monitor_enter: /* 0x1d */
@@ -7335,51 +7347,166 @@
 /* ------------------------------ */
     .balign 128
 .L_op_invoke_polymorphic: /* 0xfa */
-/* Transfer stub to alternate interpreter */
-    b    MterpFallback
+/* File: arm/op_invoke_polymorphic.S */
+/* File: arm/invoke_polymorphic.S */
+    /*
+     * invoke-polymorphic handler wrapper.
+     */
+    /* op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB, proto@HHHH */
+    .extern MterpInvokePolymorphic
+    EXPORT_PC
+    mov     r0, rSELF
+    add     r1, rFP, #OFF_FP_SHADOWFRAME
+    mov     r2, rPC
+    mov     r3, rINST
+    bl      MterpInvokePolymorphic
+    cmp     r0, #0
+    beq     MterpException
+    FETCH_ADVANCE_INST 4
+    bl      MterpShouldSwitchInterpreters
+    cmp     r0, #0
+    bne     MterpFallback
+    GET_INST_OPCODE ip
+    GOTO_OPCODE ip
 
 
 /* ------------------------------ */
     .balign 128
 .L_op_invoke_polymorphic_range: /* 0xfb */
-/* Transfer stub to alternate interpreter */
-    b    MterpFallback
+/* File: arm/op_invoke_polymorphic_range.S */
+/* File: arm/invoke_polymorphic.S */
+    /*
+     * invoke-polymorphic handler wrapper.
+     */
+    /* op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB, proto@HHHH */
+    .extern MterpInvokePolymorphicRange
+    EXPORT_PC
+    mov     r0, rSELF
+    add     r1, rFP, #OFF_FP_SHADOWFRAME
+    mov     r2, rPC
+    mov     r3, rINST
+    bl      MterpInvokePolymorphicRange
+    cmp     r0, #0
+    beq     MterpException
+    FETCH_ADVANCE_INST 4
+    bl      MterpShouldSwitchInterpreters
+    cmp     r0, #0
+    bne     MterpFallback
+    GET_INST_OPCODE ip
+    GOTO_OPCODE ip
 
 
 /* ------------------------------ */
     .balign 128
 .L_op_invoke_custom: /* 0xfc */
-/* Transfer stub to alternate interpreter */
-    b    MterpFallback
+/* File: arm/op_invoke_custom.S */
+/* File: arm/invoke.S */
+    /*
+     * Generic invoke handler wrapper.
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+    .extern MterpInvokeCustom
+    EXPORT_PC
+    mov     r0, rSELF
+    add     r1, rFP, #OFF_FP_SHADOWFRAME
+    mov     r2, rPC
+    mov     r3, rINST
+    bl      MterpInvokeCustom
+    cmp     r0, #0
+    beq     MterpException
+    FETCH_ADVANCE_INST 3
+    bl      MterpShouldSwitchInterpreters
+    cmp     r0, #0
+    bne     MterpFallback
+    GET_INST_OPCODE ip
+    GOTO_OPCODE ip
 
 
+    /*
+     * Handle an invoke-custom invocation.
+     *
+     * for: invoke-custom, invoke-custom/range
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, call_site@BBBB */
+    /* op vAA, {vCCCC..v(CCCC+AA-1)}, call_site@BBBB */
+
 /* ------------------------------ */
     .balign 128
 .L_op_invoke_custom_range: /* 0xfd */
-/* Transfer stub to alternate interpreter */
-    b    MterpFallback
+/* File: arm/op_invoke_custom_range.S */
+/* File: arm/invoke.S */
+    /*
+     * Generic invoke handler wrapper.
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+    .extern MterpInvokeCustomRange
+    EXPORT_PC
+    mov     r0, rSELF
+    add     r1, rFP, #OFF_FP_SHADOWFRAME
+    mov     r2, rPC
+    mov     r3, rINST
+    bl      MterpInvokeCustomRange
+    cmp     r0, #0
+    beq     MterpException
+    FETCH_ADVANCE_INST 3
+    bl      MterpShouldSwitchInterpreters
+    cmp     r0, #0
+    bne     MterpFallback
+    GET_INST_OPCODE ip
+    GOTO_OPCODE ip
+
 
 
 /* ------------------------------ */
     .balign 128
-.L_op_unused_fe: /* 0xfe */
-/* File: arm/op_unused_fe.S */
-/* File: arm/unused.S */
-/*
- * Bail to reference interpreter to throw.
- */
-  b MterpFallback
+.L_op_const_method_handle: /* 0xfe */
+/* File: arm/op_const_method_handle.S */
+/* File: arm/const.S */
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
+    .extern MterpConstMethodHandle
+    EXPORT_PC
+    FETCH   r0, 1                       @ r0<- BBBB
+    mov     r1, rINST, lsr #8           @ r1<- AA
+    add     r2, rFP, #OFF_FP_SHADOWFRAME
+    mov     r3, rSELF
+    bl      MterpConstMethodHandle                     @ (index, tgt_reg, shadow_frame, self)
+    PREFETCH_INST 2                     @ load rINST
+    cmp     r0, #0                      @ fail?
+    bne     MterpPossibleException      @ let reference interpreter deal with it.
+    ADVANCE 2                           @ advance rPC
+    GET_INST_OPCODE ip                  @ extract opcode from rINST
+    GOTO_OPCODE ip                      @ jump to next instruction
 
 
 /* ------------------------------ */
     .balign 128
-.L_op_unused_ff: /* 0xff */
-/* File: arm/op_unused_ff.S */
-/* File: arm/unused.S */
-/*
- * Bail to reference interpreter to throw.
- */
-  b MterpFallback
+.L_op_const_method_type: /* 0xff */
+/* File: arm/op_const_method_type.S */
+/* File: arm/const.S */
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
+    .extern MterpConstMethodType
+    EXPORT_PC
+    FETCH   r0, 1                       @ r0<- BBBB
+    mov     r1, rINST, lsr #8           @ r1<- AA
+    add     r2, rFP, #OFF_FP_SHADOWFRAME
+    mov     r3, rSELF
+    bl      MterpConstMethodType                     @ (index, tgt_reg, shadow_frame, self)
+    PREFETCH_INST 2                     @ load rINST
+    cmp     r0, #0                      @ fail?
+    bne     MterpPossibleException      @ let reference interpreter deal with it.
+    ADVANCE 2                           @ advance rPC
+    GET_INST_OPCODE ip                  @ extract opcode from rINST
+    GOTO_OPCODE ip                      @ jump to next instruction
 
 
     .balign 128
@@ -11790,7 +11917,7 @@
 
 /* ------------------------------ */
     .balign 128
-.L_ALT_op_unused_fe: /* 0xfe */
+.L_ALT_op_const_method_handle: /* 0xfe */
 /* File: arm/alt_stub.S */
 /*
  * Inter-instruction transfer stub.  Call out to MterpCheckBefore to handle
@@ -11807,7 +11934,7 @@
 
 /* ------------------------------ */
     .balign 128
-.L_ALT_op_unused_ff: /* 0xff */
+.L_ALT_op_const_method_type: /* 0xff */
 /* File: arm/alt_stub.S */
 /*
  * Inter-instruction transfer stub.  Call out to MterpCheckBefore to handle
diff --git a/runtime/interpreter/mterp/out/mterp_arm64.S b/runtime/interpreter/mterp/out/mterp_arm64.S
index 3d05996..80a7f12 100644
--- a/runtime/interpreter/mterp/out/mterp_arm64.S
+++ b/runtime/interpreter/mterp/out/mterp_arm64.S
@@ -849,19 +849,25 @@
     .balign 128
 .L_op_const_string: /* 0x1a */
 /* File: arm64/op_const_string.S */
-    /* const/string vAA, String//BBBB */
+/* File: arm64/const.S */
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
+    .extern MterpConstString
     EXPORT_PC
     FETCH w0, 1                         // w0<- BBBB
     lsr     w1, wINST, #8               // w1<- AA
     add     x2, xFP, #OFF_FP_SHADOWFRAME
     mov     x3, xSELF
-    bl      MterpConstString            // (index, tgt_reg, shadow_frame, self)
+    bl      MterpConstString                     // (index, tgt_reg, shadow_frame, self)
     PREFETCH_INST 2                     // load rINST
     cbnz    w0, MterpPossibleException  // let reference interpreter deal with it.
     ADVANCE 2                           // advance rPC
     GET_INST_OPCODE ip                  // extract opcode from rINST
     GOTO_OPCODE ip                      // jump to next instruction
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_const_string_jumbo: /* 0x1b */
@@ -885,19 +891,25 @@
     .balign 128
 .L_op_const_class: /* 0x1c */
 /* File: arm64/op_const_class.S */
-    /* const/class vAA, Class//BBBB */
+/* File: arm64/const.S */
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
+    .extern MterpConstClass
     EXPORT_PC
-    FETCH   w0, 1                       // w0<- BBBB
+    FETCH w0, 1                         // w0<- BBBB
     lsr     w1, wINST, #8               // w1<- AA
     add     x2, xFP, #OFF_FP_SHADOWFRAME
     mov     x3, xSELF
-    bl      MterpConstClass             // (index, tgt_reg, shadow_frame, self)
-    PREFETCH_INST 2
-    cbnz    w0, MterpPossibleException
-    ADVANCE 2
+    bl      MterpConstClass                     // (index, tgt_reg, shadow_frame, self)
+    PREFETCH_INST 2                     // load rINST
+    cbnz    w0, MterpPossibleException  // let reference interpreter deal with it.
+    ADVANCE 2                           // advance rPC
     GET_INST_OPCODE ip                  // extract opcode from rINST
     GOTO_OPCODE ip                      // jump to next instruction
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_monitor_enter: /* 0x1d */
@@ -6902,51 +6914,149 @@
 /* ------------------------------ */
     .balign 128
 .L_op_invoke_polymorphic: /* 0xfa */
-/* Transfer stub to alternate interpreter */
-    b    MterpFallback
+/* File: arm64/op_invoke_polymorphic.S */
+/* File: arm64/invoke_polymorphic.S */
+    /*
+     * invoke-polymorphic handler wrapper.
+     */
+    /* op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB, proto@HHHH */
+    .extern MterpInvokePolymorphic
+    EXPORT_PC
+    mov     x0, xSELF
+    add     x1, xFP, #OFF_FP_SHADOWFRAME
+    mov     x2, xPC
+    mov     x3, xINST
+    bl      MterpInvokePolymorphic
+    cbz     w0, MterpException
+    FETCH_ADVANCE_INST 4
+    bl      MterpShouldSwitchInterpreters
+    cbnz    w0, MterpFallback
+    GET_INST_OPCODE ip
+    GOTO_OPCODE ip
 
 
 /* ------------------------------ */
     .balign 128
 .L_op_invoke_polymorphic_range: /* 0xfb */
-/* Transfer stub to alternate interpreter */
-    b    MterpFallback
+/* File: arm64/op_invoke_polymorphic_range.S */
+/* File: arm64/invoke_polymorphic.S */
+    /*
+     * invoke-polymorphic handler wrapper.
+     */
+    /* op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB, proto@HHHH */
+    .extern MterpInvokePolymorphicRange
+    EXPORT_PC
+    mov     x0, xSELF
+    add     x1, xFP, #OFF_FP_SHADOWFRAME
+    mov     x2, xPC
+    mov     x3, xINST
+    bl      MterpInvokePolymorphicRange
+    cbz     w0, MterpException
+    FETCH_ADVANCE_INST 4
+    bl      MterpShouldSwitchInterpreters
+    cbnz    w0, MterpFallback
+    GET_INST_OPCODE ip
+    GOTO_OPCODE ip
 
 
 /* ------------------------------ */
     .balign 128
 .L_op_invoke_custom: /* 0xfc */
-/* Transfer stub to alternate interpreter */
-    b    MterpFallback
+/* File: arm64/op_invoke_custom.S */
+/* File: arm64/invoke.S */
+    /*
+     * Generic invoke handler wrapper.
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+    .extern MterpInvokeCustom
+    EXPORT_PC
+    mov     x0, xSELF
+    add     x1, xFP, #OFF_FP_SHADOWFRAME
+    mov     x2, xPC
+    mov     x3, xINST
+    bl      MterpInvokeCustom
+    cbz     w0, MterpException
+    FETCH_ADVANCE_INST 3
+    bl      MterpShouldSwitchInterpreters
+    cbnz    w0, MterpFallback
+    GET_INST_OPCODE ip
+    GOTO_OPCODE ip
+
 
 
 /* ------------------------------ */
     .balign 128
 .L_op_invoke_custom_range: /* 0xfd */
-/* Transfer stub to alternate interpreter */
-    b    MterpFallback
+/* File: arm64/op_invoke_custom_range.S */
+/* File: arm64/invoke.S */
+    /*
+     * Generic invoke handler wrapper.
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+    .extern MterpInvokeCustomRange
+    EXPORT_PC
+    mov     x0, xSELF
+    add     x1, xFP, #OFF_FP_SHADOWFRAME
+    mov     x2, xPC
+    mov     x3, xINST
+    bl      MterpInvokeCustomRange
+    cbz     w0, MterpException
+    FETCH_ADVANCE_INST 3
+    bl      MterpShouldSwitchInterpreters
+    cbnz    w0, MterpFallback
+    GET_INST_OPCODE ip
+    GOTO_OPCODE ip
+
 
 
 /* ------------------------------ */
     .balign 128
-.L_op_unused_fe: /* 0xfe */
-/* File: arm64/op_unused_fe.S */
-/* File: arm64/unused.S */
-/*
- * Bail to reference interpreter to throw.
- */
-  b MterpFallback
+.L_op_const_method_handle: /* 0xfe */
+/* File: arm64/op_const_method_handle.S */
+/* File: arm64/const.S */
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
+    .extern MterpConstMethodHandle
+    EXPORT_PC
+    FETCH w0, 1                         // w0<- BBBB
+    lsr     w1, wINST, #8               // w1<- AA
+    add     x2, xFP, #OFF_FP_SHADOWFRAME
+    mov     x3, xSELF
+    bl      MterpConstMethodHandle                     // (index, tgt_reg, shadow_frame, self)
+    PREFETCH_INST 2                     // load rINST
+    cbnz    w0, MterpPossibleException  // let reference interpreter deal with it.
+    ADVANCE 2                           // advance rPC
+    GET_INST_OPCODE ip                  // extract opcode from rINST
+    GOTO_OPCODE ip                      // jump to next instruction
 
 
 /* ------------------------------ */
     .balign 128
-.L_op_unused_ff: /* 0xff */
-/* File: arm64/op_unused_ff.S */
-/* File: arm64/unused.S */
-/*
- * Bail to reference interpreter to throw.
- */
-  b MterpFallback
+.L_op_const_method_type: /* 0xff */
+/* File: arm64/op_const_method_type.S */
+/* File: arm64/const.S */
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
+    .extern MterpConstMethodType
+    EXPORT_PC
+    FETCH w0, 1                         // w0<- BBBB
+    lsr     w1, wINST, #8               // w1<- AA
+    add     x2, xFP, #OFF_FP_SHADOWFRAME
+    mov     x3, xSELF
+    bl      MterpConstMethodType                     // (index, tgt_reg, shadow_frame, self)
+    PREFETCH_INST 2                     // load rINST
+    cbnz    w0, MterpPossibleException  // let reference interpreter deal with it.
+    ADVANCE 2                           // advance rPC
+    GET_INST_OPCODE ip                  // extract opcode from rINST
+    GOTO_OPCODE ip                      // jump to next instruction
 
 
     .balign 128
@@ -11607,7 +11717,7 @@
 
 /* ------------------------------ */
     .balign 128
-.L_ALT_op_unused_fe: /* 0xfe */
+.L_ALT_op_const_method_handle: /* 0xfe */
 /* File: arm64/alt_stub.S */
 /*
  * Inter-instruction transfer stub.  Call out to MterpCheckBefore to handle
@@ -11624,7 +11734,7 @@
 
 /* ------------------------------ */
     .balign 128
-.L_ALT_op_unused_ff: /* 0xff */
+.L_ALT_op_const_method_type: /* 0xff */
 /* File: arm64/alt_stub.S */
 /*
  * Inter-instruction transfer stub.  Call out to MterpCheckBefore to handle
diff --git a/runtime/interpreter/mterp/out/mterp_mips.S b/runtime/interpreter/mterp/out/mterp_mips.S
index 144c8e5..74fee39 100644
--- a/runtime/interpreter/mterp/out/mterp_mips.S
+++ b/runtime/interpreter/mterp/out/mterp_mips.S
@@ -1226,19 +1226,25 @@
     .balign 128
 .L_op_const_string: /* 0x1a */
 /* File: mips/op_const_string.S */
-    /* const/string vAA, string@BBBB */
+/* File: mips/const.S */
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
+    .extern MterpConstString
     EXPORT_PC()
     FETCH(a0, 1)                        # a0 <- BBBB
     GET_OPA(a1)                         # a1 <- AA
     addu   a2, rFP, OFF_FP_SHADOWFRAME  # a2 <- shadow frame
     move   a3, rSELF
-    JAL(MterpConstString)               # v0 <- Mterp(index, tgt_reg, shadow_frame, self)
+    JAL(MterpConstString)                        # v0 <- Mterp(index, tgt_reg, shadow_frame, self)
     PREFETCH_INST(2)                    # load rINST
     bnez   v0, MterpPossibleException
     ADVANCE(2)                          # advance rPC
     GET_INST_OPCODE(t0)                 # extract opcode from rINST
     GOTO_OPCODE(t0)                     # jump to next instruction
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_const_string_jumbo: /* 0x1b */
@@ -1262,19 +1268,25 @@
     .balign 128
 .L_op_const_class: /* 0x1c */
 /* File: mips/op_const_class.S */
-    /* const/class vAA, class@BBBB */
+/* File: mips/const.S */
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
+    .extern MterpConstClass
     EXPORT_PC()
     FETCH(a0, 1)                        # a0 <- BBBB
     GET_OPA(a1)                         # a1 <- AA
     addu   a2, rFP, OFF_FP_SHADOWFRAME  # a2 <- shadow frame
     move   a3, rSELF
-    JAL(MterpConstClass)
+    JAL(MterpConstClass)                        # v0 <- Mterp(index, tgt_reg, shadow_frame, self)
     PREFETCH_INST(2)                    # load rINST
     bnez   v0, MterpPossibleException
     ADVANCE(2)                          # advance rPC
     GET_INST_OPCODE(t0)                 # extract opcode from rINST
     GOTO_OPCODE(t0)                     # jump to next instruction
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_monitor_enter: /* 0x1d */
@@ -7715,47 +7727,147 @@
 /* ------------------------------ */
     .balign 128
 .L_op_invoke_polymorphic: /* 0xfa */
-/* Transfer stub to alternate interpreter */
-    b    MterpFallback
+/* File: mips/op_invoke_polymorphic.S */
+/* File: mips/invoke_polymorphic.S */
+    /*
+     * invoke-polymorphic handler wrapper.
+     */
+    /* op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB, proto@HHHH */
+    .extern MterpInvokePolymorphic
+    EXPORT_PC()
+    move    a0, rSELF
+    addu    a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rPC
+    move    a3, rINST
+    JAL(MterpInvokePolymorphic)
+    beqz    v0, MterpException
+    FETCH_ADVANCE_INST(4)
+    JAL(MterpShouldSwitchInterpreters)
+    bnez    v0, MterpFallback
+    GET_INST_OPCODE(t0)
+    GOTO_OPCODE(t0)
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_invoke_polymorphic_range: /* 0xfb */
-/* Transfer stub to alternate interpreter */
-    b    MterpFallback
+/* File: mips/op_invoke_polymorphic_range.S */
+/* File: mips/invoke_polymorphic.S */
+    /*
+     * invoke-polymorphic handler wrapper.
+     */
+    /* op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB, proto@HHHH */
+    .extern MterpInvokePolymorphicRange
+    EXPORT_PC()
+    move    a0, rSELF
+    addu    a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rPC
+    move    a3, rINST
+    JAL(MterpInvokePolymorphicRange)
+    beqz    v0, MterpException
+    FETCH_ADVANCE_INST(4)
+    JAL(MterpShouldSwitchInterpreters)
+    bnez    v0, MterpFallback
+    GET_INST_OPCODE(t0)
+    GOTO_OPCODE(t0)
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_invoke_custom: /* 0xfc */
-/* Transfer stub to alternate interpreter */
-    b    MterpFallback
+/* File: mips/op_invoke_custom.S */
+/* File: mips/invoke.S */
+    /*
+     * Generic invoke handler wrapper.
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+    .extern MterpInvokeCustom
+    EXPORT_PC()
+    move    a0, rSELF
+    addu    a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rPC
+    move    a3, rINST
+    JAL(MterpInvokeCustom)
+    beqz    v0, MterpException
+    FETCH_ADVANCE_INST(3)
+    JAL(MterpShouldSwitchInterpreters)
+    bnez    v0, MterpFallback
+    GET_INST_OPCODE(t0)
+    GOTO_OPCODE(t0)
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_invoke_custom_range: /* 0xfd */
-/* Transfer stub to alternate interpreter */
-    b    MterpFallback
-
-/* ------------------------------ */
-    .balign 128
-.L_op_unused_fe: /* 0xfe */
-/* File: mips/op_unused_fe.S */
-/* File: mips/unused.S */
-/*
- * Bail to reference interpreter to throw.
- */
-  b MterpFallback
+/* File: mips/op_invoke_custom_range.S */
+/* File: mips/invoke.S */
+    /*
+     * Generic invoke handler wrapper.
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+    .extern MterpInvokeCustomRange
+    EXPORT_PC()
+    move    a0, rSELF
+    addu    a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rPC
+    move    a3, rINST
+    JAL(MterpInvokeCustomRange)
+    beqz    v0, MterpException
+    FETCH_ADVANCE_INST(3)
+    JAL(MterpShouldSwitchInterpreters)
+    bnez    v0, MterpFallback
+    GET_INST_OPCODE(t0)
+    GOTO_OPCODE(t0)
 
 
 /* ------------------------------ */
     .balign 128
-.L_op_unused_ff: /* 0xff */
-/* File: mips/op_unused_ff.S */
-/* File: mips/unused.S */
-/*
- * Bail to reference interpreter to throw.
- */
-  b MterpFallback
+.L_op_const_method_handle: /* 0xfe */
+/* File: mips/op_const_method_handle.S */
+/* File: mips/const.S */
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
+    .extern MterpConstMethodHandle
+    EXPORT_PC()
+    FETCH(a0, 1)                        # a0 <- BBBB
+    GET_OPA(a1)                         # a1 <- AA
+    addu   a2, rFP, OFF_FP_SHADOWFRAME  # a2 <- shadow frame
+    move   a3, rSELF
+    JAL(MterpConstMethodHandle)                        # v0 <- Mterp(index, tgt_reg, shadow_frame, self)
+    PREFETCH_INST(2)                    # load rINST
+    bnez   v0, MterpPossibleException
+    ADVANCE(2)                          # advance rPC
+    GET_INST_OPCODE(t0)                 # extract opcode from rINST
+    GOTO_OPCODE(t0)                     # jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 128
+.L_op_const_method_type: /* 0xff */
+/* File: mips/op_const_method_type.S */
+/* File: mips/const.S */
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
+    .extern MterpConstMethodType
+    EXPORT_PC()
+    FETCH(a0, 1)                        # a0 <- BBBB
+    GET_OPA(a1)                         # a1 <- AA
+    addu   a2, rFP, OFF_FP_SHADOWFRAME  # a2 <- shadow frame
+    move   a3, rSELF
+    JAL(MterpConstMethodType)                        # v0 <- Mterp(index, tgt_reg, shadow_frame, self)
+    PREFETCH_INST(2)                    # load rINST
+    bnez   v0, MterpPossibleException
+    ADVANCE(2)                          # advance rPC
+    GET_INST_OPCODE(t0)                 # extract opcode from rINST
+    GOTO_OPCODE(t0)                     # jump to next instruction
 
 
     .balign 128
@@ -12414,7 +12526,7 @@
 
 /* ------------------------------ */
     .balign 128
-.L_ALT_op_unused_fe: /* 0xfe */
+.L_ALT_op_const_method_handle: /* 0xfe */
 /* File: mips/alt_stub.S */
 /*
  * Inter-instruction transfer stub.  Call out to MterpCheckBefore to handle
@@ -12432,7 +12544,7 @@
 
 /* ------------------------------ */
     .balign 128
-.L_ALT_op_unused_ff: /* 0xff */
+.L_ALT_op_const_method_type: /* 0xff */
 /* File: mips/alt_stub.S */
 /*
  * Inter-instruction transfer stub.  Call out to MterpCheckBefore to handle
diff --git a/runtime/interpreter/mterp/out/mterp_mips64.S b/runtime/interpreter/mterp/out/mterp_mips64.S
index 28f1887..408267e 100644
--- a/runtime/interpreter/mterp/out/mterp_mips64.S
+++ b/runtime/interpreter/mterp/out/mterp_mips64.S
@@ -828,20 +828,25 @@
     .balign 128
 .L_op_const_string: /* 0x1a */
 /* File: mips64/op_const_string.S */
-    /* const/string vAA, String//BBBB */
+/* File: mips64/const.S */
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
     .extern MterpConstString
     EXPORT_PC
     lhu     a0, 2(rPC)                  # a0 <- BBBB
     srl     a1, rINST, 8                # a1 <- AA
     daddu   a2, rFP, OFF_FP_SHADOWFRAME
     move    a3, rSELF
-    jal     MterpConstString            # (index, tgt_reg, shadow_frame, self)
+    jal     MterpConstString                     # (index, tgt_reg, shadow_frame, self)
     PREFETCH_INST 2                     # load rINST
     bnez    v0, MterpPossibleException  # let reference interpreter deal with it.
     ADVANCE 2                           # advance rPC
     GET_INST_OPCODE v0                  # extract opcode from rINST
     GOTO_OPCODE v0                      # jump to next instruction
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_const_string_jumbo: /* 0x1b */
@@ -866,20 +871,25 @@
     .balign 128
 .L_op_const_class: /* 0x1c */
 /* File: mips64/op_const_class.S */
-    /* const/class vAA, Class//BBBB */
+/* File: mips64/const.S */
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
     .extern MterpConstClass
     EXPORT_PC
     lhu     a0, 2(rPC)                  # a0 <- BBBB
     srl     a1, rINST, 8                # a1 <- AA
     daddu   a2, rFP, OFF_FP_SHADOWFRAME
     move    a3, rSELF
-    jal     MterpConstClass             # (index, tgt_reg, shadow_frame, self)
+    jal     MterpConstClass                     # (index, tgt_reg, shadow_frame, self)
     PREFETCH_INST 2                     # load rINST
     bnez    v0, MterpPossibleException  # let reference interpreter deal with it.
     ADVANCE 2                           # advance rPC
     GET_INST_OPCODE v0                  # extract opcode from rINST
     GOTO_OPCODE v0                      # jump to next instruction
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_monitor_enter: /* 0x1d */
@@ -7106,47 +7116,151 @@
 /* ------------------------------ */
     .balign 128
 .L_op_invoke_polymorphic: /* 0xfa */
-/* Transfer stub to alternate interpreter */
-    b       MterpFallback
+/* File: mips64/op_invoke_polymorphic.S */
+/* File: mips64/invoke_polymorphic.S */
+    /*
+     * invoke-polymorphic handler wrapper.
+     */
+    /* op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB, proto@HHHH */
+    .extern MterpInvokePolymorphic
+    .extern MterpShouldSwitchInterpreters
+    EXPORT_PC
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rPC
+    move    a3, rINST
+    jal     MterpInvokePolymorphic
+    beqzc   v0, MterpException
+    FETCH_ADVANCE_INST 4
+    jal     MterpShouldSwitchInterpreters
+    bnezc   v0, MterpFallback
+    GET_INST_OPCODE v0
+    GOTO_OPCODE v0
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_invoke_polymorphic_range: /* 0xfb */
-/* Transfer stub to alternate interpreter */
-    b       MterpFallback
+/* File: mips64/op_invoke_polymorphic_range.S */
+/* File: mips64/invoke_polymorphic.S */
+    /*
+     * invoke-polymorphic handler wrapper.
+     */
+    /* op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB, proto@HHHH */
+    .extern MterpInvokePolymorphicRange
+    .extern MterpShouldSwitchInterpreters
+    EXPORT_PC
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rPC
+    move    a3, rINST
+    jal     MterpInvokePolymorphicRange
+    beqzc   v0, MterpException
+    FETCH_ADVANCE_INST 4
+    jal     MterpShouldSwitchInterpreters
+    bnezc   v0, MterpFallback
+    GET_INST_OPCODE v0
+    GOTO_OPCODE v0
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_invoke_custom: /* 0xfc */
-/* Transfer stub to alternate interpreter */
-    b       MterpFallback
+/* File: mips64/op_invoke_custom.S */
+/* File: mips64/invoke.S */
+    /*
+     * Generic invoke handler wrapper.
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+    .extern MterpInvokeCustom
+    .extern MterpShouldSwitchInterpreters
+    EXPORT_PC
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rPC
+    move    a3, rINST
+    jal     MterpInvokeCustom
+    beqzc   v0, MterpException
+    FETCH_ADVANCE_INST 3
+    jal     MterpShouldSwitchInterpreters
+    bnezc   v0, MterpFallback
+    GET_INST_OPCODE v0
+    GOTO_OPCODE v0
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_invoke_custom_range: /* 0xfd */
-/* Transfer stub to alternate interpreter */
-    b       MterpFallback
-
-/* ------------------------------ */
-    .balign 128
-.L_op_unused_fe: /* 0xfe */
-/* File: mips64/op_unused_fe.S */
-/* File: mips64/unused.S */
-/*
- * Bail to reference interpreter to throw.
- */
-    b       MterpFallback
+/* File: mips64/op_invoke_custom_range.S */
+/* File: mips64/invoke.S */
+    /*
+     * Generic invoke handler wrapper.
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+    .extern MterpInvokeCustomRange
+    .extern MterpShouldSwitchInterpreters
+    EXPORT_PC
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rPC
+    move    a3, rINST
+    jal     MterpInvokeCustomRange
+    beqzc   v0, MterpException
+    FETCH_ADVANCE_INST 3
+    jal     MterpShouldSwitchInterpreters
+    bnezc   v0, MterpFallback
+    GET_INST_OPCODE v0
+    GOTO_OPCODE v0
 
 
 /* ------------------------------ */
     .balign 128
-.L_op_unused_ff: /* 0xff */
-/* File: mips64/op_unused_ff.S */
-/* File: mips64/unused.S */
-/*
- * Bail to reference interpreter to throw.
- */
-    b       MterpFallback
+.L_op_const_method_handle: /* 0xfe */
+/* File: mips64/op_const_method_handle.S */
+/* File: mips64/const.S */
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
+    .extern MterpConstMethodHandle
+    EXPORT_PC
+    lhu     a0, 2(rPC)                  # a0 <- BBBB
+    srl     a1, rINST, 8                # a1 <- AA
+    daddu   a2, rFP, OFF_FP_SHADOWFRAME
+    move    a3, rSELF
+    jal     MterpConstMethodHandle                     # (index, tgt_reg, shadow_frame, self)
+    PREFETCH_INST 2                     # load rINST
+    bnez    v0, MterpPossibleException  # let reference interpreter deal with it.
+    ADVANCE 2                           # advance rPC
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 128
+.L_op_const_method_type: /* 0xff */
+/* File: mips64/op_const_method_type.S */
+/* File: mips64/const.S */
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
+    .extern MterpConstMethodType
+    EXPORT_PC
+    lhu     a0, 2(rPC)                  # a0 <- BBBB
+    srl     a1, rINST, 8                # a1 <- AA
+    daddu   a2, rFP, OFF_FP_SHADOWFRAME
+    move    a3, rSELF
+    jal     MterpConstMethodType                     # (index, tgt_reg, shadow_frame, self)
+    PREFETCH_INST 2                     # load rINST
+    bnez    v0, MterpPossibleException  # let reference interpreter deal with it.
+    ADVANCE 2                           # advance rPC
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
 
 
     .balign 128
@@ -12003,7 +12117,7 @@
 
 /* ------------------------------ */
     .balign 128
-.L_ALT_op_unused_fe: /* 0xfe */
+.L_ALT_op_const_method_handle: /* 0xfe */
 /* File: mips64/alt_stub.S */
 /*
  * Inter-instruction transfer stub.  Call out to MterpCheckBefore to handle
@@ -12022,7 +12136,7 @@
 
 /* ------------------------------ */
     .balign 128
-.L_ALT_op_unused_ff: /* 0xff */
+.L_ALT_op_const_method_type: /* 0xff */
 /* File: mips64/alt_stub.S */
 /*
  * Inter-instruction transfer stub.  Call out to MterpCheckBefore to handle
diff --git a/runtime/interpreter/mterp/out/mterp_x86.S b/runtime/interpreter/mterp/out/mterp_x86.S
index 169501d..984ecfa 100644
--- a/runtime/interpreter/mterp/out/mterp_x86.S
+++ b/runtime/interpreter/mterp/out/mterp_x86.S
@@ -783,7 +783,12 @@
     .balign 128
 .L_op_const_string: /* 0x1a */
 /* File: x86/op_const_string.S */
-    /* const/string vAA, String@BBBB */
+/* File: x86/const.S */
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
+    .extern MterpConstString
     EXPORT_PC
     movzwl  2(rPC), %eax                    # eax <- BBBB
     movl    %eax, OUT_ARG0(%esp)
@@ -792,12 +797,13 @@
     movl    %eax, OUT_ARG2(%esp)
     movl    rSELF, %eax
     movl    %eax, OUT_ARG3(%esp)
-    call    SYMBOL(MterpConstString)        # (index, tgt_reg, shadow_frame, self)
+    call    SYMBOL(MterpConstString)                 # (index, tgt_reg, shadow_frame, self)
     RESTORE_IBASE
     testb   %al, %al
     jnz     MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_const_string_jumbo: /* 0x1b */
@@ -821,21 +827,27 @@
     .balign 128
 .L_op_const_class: /* 0x1c */
 /* File: x86/op_const_class.S */
-    /* const/class vAA, Class@BBBB */
+/* File: x86/const.S */
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
+    .extern MterpConstClass
     EXPORT_PC
-    movzwl  2(rPC), %eax                    # eax<- BBBB
+    movzwl  2(rPC), %eax                    # eax <- BBBB
     movl    %eax, OUT_ARG0(%esp)
     movl    rINST, OUT_ARG1(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG2(%esp)
     movl    rSELF, %eax
     movl    %eax, OUT_ARG3(%esp)
-    call    SYMBOL(MterpConstClass)         # (index, tgt_reg, shadow_frame, self)
+    call    SYMBOL(MterpConstClass)                 # (index, tgt_reg, shadow_frame, self)
     RESTORE_IBASE
     testb   %al, %al
     jnz     MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_monitor_enter: /* 0x1d */
@@ -6281,51 +6293,175 @@
 /* ------------------------------ */
     .balign 128
 .L_op_invoke_polymorphic: /* 0xfa */
-/* Transfer stub to alternate interpreter */
-    jmp     MterpFallback
+/* File: x86/op_invoke_polymorphic.S */
+/* File: x86/invoke_polymorphic.S */
+    /*
+     * invoke-polymorphic handler wrapper.
+     */
+    /* op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB, proto@HHHH */
+    .extern MterpInvokePolymorphic
+    EXPORT_PC
+    movl    rSELF, %ecx
+    movl    %ecx, OUT_ARG0(%esp)
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG1(%esp)
+    movl    rPC, OUT_ARG2(%esp)
+    REFRESH_INST 250
+    movl    rINST, OUT_ARG3(%esp)
+    call    SYMBOL(MterpInvokePolymorphic)
+    testb   %al, %al
+    jz      MterpException
+    ADVANCE_PC 4
+    call    SYMBOL(MterpShouldSwitchInterpreters)
+    testb   %al, %al
+    jnz     MterpFallback
+    RESTORE_IBASE
+    FETCH_INST
+    GOTO_NEXT
 
 
 /* ------------------------------ */
     .balign 128
 .L_op_invoke_polymorphic_range: /* 0xfb */
-/* Transfer stub to alternate interpreter */
-    jmp     MterpFallback
+/* File: x86/op_invoke_polymorphic_range.S */
+/* File: x86/invoke_polymorphic.S */
+    /*
+     * invoke-polymorphic handler wrapper.
+     */
+    /* op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB, proto@HHHH */
+    .extern MterpInvokePolymorphicRange
+    EXPORT_PC
+    movl    rSELF, %ecx
+    movl    %ecx, OUT_ARG0(%esp)
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG1(%esp)
+    movl    rPC, OUT_ARG2(%esp)
+    REFRESH_INST 251
+    movl    rINST, OUT_ARG3(%esp)
+    call    SYMBOL(MterpInvokePolymorphicRange)
+    testb   %al, %al
+    jz      MterpException
+    ADVANCE_PC 4
+    call    SYMBOL(MterpShouldSwitchInterpreters)
+    testb   %al, %al
+    jnz     MterpFallback
+    RESTORE_IBASE
+    FETCH_INST
+    GOTO_NEXT
 
 
 /* ------------------------------ */
     .balign 128
 .L_op_invoke_custom: /* 0xfc */
-/* Transfer stub to alternate interpreter */
-    jmp     MterpFallback
+/* File: x86/op_invoke_custom.S */
+/* File: x86/invoke.S */
+/*
+ * Generic invoke handler wrapper.
+ */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+    .extern MterpInvokeCustom
+    EXPORT_PC
+    movl    rSELF, %ecx
+    movl    %ecx, OUT_ARG0(%esp)
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG1(%esp)
+    movl    rPC, OUT_ARG2(%esp)
+    REFRESH_INST 252
+    movl    rINST, OUT_ARG3(%esp)
+    call    SYMBOL(MterpInvokeCustom)
+    testb   %al, %al
+    jz      MterpException
+    ADVANCE_PC 3
+    call    SYMBOL(MterpShouldSwitchInterpreters)
+    testb   %al, %al
+    jnz     MterpFallback
+    RESTORE_IBASE
+    FETCH_INST
+    GOTO_NEXT
 
 
 /* ------------------------------ */
     .balign 128
 .L_op_invoke_custom_range: /* 0xfd */
-/* Transfer stub to alternate interpreter */
-    jmp     MterpFallback
+/* File: x86/op_invoke_custom_range.S */
+/* File: x86/invoke.S */
+/*
+ * Generic invoke handler wrapper.
+ */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+    .extern MterpInvokeCustomRange
+    EXPORT_PC
+    movl    rSELF, %ecx
+    movl    %ecx, OUT_ARG0(%esp)
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG1(%esp)
+    movl    rPC, OUT_ARG2(%esp)
+    REFRESH_INST 253
+    movl    rINST, OUT_ARG3(%esp)
+    call    SYMBOL(MterpInvokeCustomRange)
+    testb   %al, %al
+    jz      MterpException
+    ADVANCE_PC 3
+    call    SYMBOL(MterpShouldSwitchInterpreters)
+    testb   %al, %al
+    jnz     MterpFallback
+    RESTORE_IBASE
+    FETCH_INST
+    GOTO_NEXT
 
 
 /* ------------------------------ */
     .balign 128
-.L_op_unused_fe: /* 0xfe */
-/* File: x86/op_unused_fe.S */
-/* File: x86/unused.S */
-/*
- * Bail to reference interpreter to throw.
- */
-    jmp     MterpFallback
+.L_op_const_method_handle: /* 0xfe */
+/* File: x86/op_const_method_handle.S */
+/* File: x86/const.S */
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
+    .extern MterpConstMethodHandle
+    EXPORT_PC
+    movzwl  2(rPC), %eax                    # eax <- BBBB
+    movl    %eax, OUT_ARG0(%esp)
+    movl    rINST, OUT_ARG1(%esp)
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)
+    call    SYMBOL(MterpConstMethodHandle)                 # (index, tgt_reg, shadow_frame, self)
+    RESTORE_IBASE
+    testb   %al, %al
+    jnz     MterpPossibleException
+    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
 /* ------------------------------ */
     .balign 128
-.L_op_unused_ff: /* 0xff */
-/* File: x86/op_unused_ff.S */
-/* File: x86/unused.S */
-/*
- * Bail to reference interpreter to throw.
- */
-    jmp     MterpFallback
+.L_op_const_method_type: /* 0xff */
+/* File: x86/op_const_method_type.S */
+/* File: x86/const.S */
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
+    .extern MterpConstMethodType
+    EXPORT_PC
+    movzwl  2(rPC), %eax                    # eax <- BBBB
+    movl    %eax, OUT_ARG0(%esp)
+    movl    rINST, OUT_ARG1(%esp)
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)
+    call    SYMBOL(MterpConstMethodType)                 # (index, tgt_reg, shadow_frame, self)
+    RESTORE_IBASE
+    testb   %al, %al
+    jnz     MterpPossibleException
+    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
     .balign 128
@@ -12452,7 +12588,7 @@
 
 /* ------------------------------ */
     .balign 128
-.L_ALT_op_unused_fe: /* 0xfe */
+.L_ALT_op_const_method_handle: /* 0xfe */
 /* File: x86/alt_stub.S */
 /*
  * Inter-instruction transfer stub.  Call out to MterpCheckBefore to handle
@@ -12476,7 +12612,7 @@
 
 /* ------------------------------ */
     .balign 128
-.L_ALT_op_unused_ff: /* 0xff */
+.L_ALT_op_const_method_type: /* 0xff */
 /* File: x86/alt_stub.S */
 /*
  * Inter-instruction transfer stub.  Call out to MterpCheckBefore to handle
diff --git a/runtime/interpreter/mterp/out/mterp_x86_64.S b/runtime/interpreter/mterp/out/mterp_x86_64.S
index b643072..84f8b52 100644
--- a/runtime/interpreter/mterp/out/mterp_x86_64.S
+++ b/runtime/interpreter/mterp/out/mterp_x86_64.S
@@ -739,17 +739,23 @@
     .balign 128
 .L_op_const_string: /* 0x1a */
 /* File: x86_64/op_const_string.S */
-    /* const/string vAA, String@BBBB */
+/* File: x86_64/const.S */
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
+    .extern MterpConstString
     EXPORT_PC
-    movzwq  2(rPC), OUT_ARG0                # OUT_ARG0 <- BBBB
+    movzwq  2(rPC), OUT_ARG0                # eax <- OUT_ARG0
     movq    rINSTq, OUT_ARG1
     leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2
     movq    rSELF, OUT_ARG3
-    call    SYMBOL(MterpConstString)        # (index, tgt_reg, shadow_frame, self)
+    call    SYMBOL(MterpConstString)                 # (index, tgt_reg, shadow_frame, self)
     testb   %al, %al
     jnz     MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_const_string_jumbo: /* 0x1b */
@@ -769,17 +775,23 @@
     .balign 128
 .L_op_const_class: /* 0x1c */
 /* File: x86_64/op_const_class.S */
-    /* const/class vAA, Class@BBBB */
+/* File: x86_64/const.S */
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
+    .extern MterpConstClass
     EXPORT_PC
     movzwq  2(rPC), OUT_ARG0                # eax <- OUT_ARG0
     movq    rINSTq, OUT_ARG1
     leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2
     movq    rSELF, OUT_ARG3
-    call    SYMBOL(MterpConstClass)         # (index, tgt_reg, shadow_frame, self)
+    call    SYMBOL(MterpConstClass)                 # (index, tgt_reg, shadow_frame, self)
     testb   %al, %al
     jnz     MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_monitor_enter: /* 0x1d */
@@ -6048,51 +6060,155 @@
 /* ------------------------------ */
     .balign 128
 .L_op_invoke_polymorphic: /* 0xfa */
-/* Transfer stub to alternate interpreter */
-    jmp     MterpFallback
+/* File: x86_64/op_invoke_polymorphic.S */
+/* File: x86_64/invoke_polymorphic.S */
+    /*
+     * invoke-polymorphic handler wrapper.
+     */
+    /* op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB, proto@HHHH */
+    .extern MterpInvokePolymorphic
+    EXPORT_PC
+    movq    rSELF, OUT_ARG0
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG1
+    movq    rPC, OUT_ARG2
+    REFRESH_INST 250
+    movl    rINST, OUT_32_ARG3
+    call    SYMBOL(MterpInvokePolymorphic)
+    testb   %al, %al
+    jz      MterpException
+    ADVANCE_PC 4
+    call    SYMBOL(MterpShouldSwitchInterpreters)
+    testb   %al, %al
+    jnz     MterpFallback
+    FETCH_INST
+    GOTO_NEXT
 
 
 /* ------------------------------ */
     .balign 128
 .L_op_invoke_polymorphic_range: /* 0xfb */
-/* Transfer stub to alternate interpreter */
-    jmp     MterpFallback
+/* File: x86_64/op_invoke_polymorphic_range.S */
+/* File: x86_64/invoke_polymorphic.S */
+    /*
+     * invoke-polymorphic handler wrapper.
+     */
+    /* op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB, proto@HHHH */
+    .extern MterpInvokePolymorphicRange
+    EXPORT_PC
+    movq    rSELF, OUT_ARG0
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG1
+    movq    rPC, OUT_ARG2
+    REFRESH_INST 251
+    movl    rINST, OUT_32_ARG3
+    call    SYMBOL(MterpInvokePolymorphicRange)
+    testb   %al, %al
+    jz      MterpException
+    ADVANCE_PC 4
+    call    SYMBOL(MterpShouldSwitchInterpreters)
+    testb   %al, %al
+    jnz     MterpFallback
+    FETCH_INST
+    GOTO_NEXT
 
 
 /* ------------------------------ */
     .balign 128
 .L_op_invoke_custom: /* 0xfc */
-/* Transfer stub to alternate interpreter */
-    jmp     MterpFallback
+/* File: x86_64/op_invoke_custom.S */
+/* File: x86_64/invoke.S */
+/*
+ * Generic invoke handler wrapper.
+ */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+    .extern MterpInvokeCustom
+    EXPORT_PC
+    movq    rSELF, OUT_ARG0
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG1
+    movq    rPC, OUT_ARG2
+    REFRESH_INST 252
+    movl    rINST, OUT_32_ARG3
+    call    SYMBOL(MterpInvokeCustom)
+    testb   %al, %al
+    jz      MterpException
+    ADVANCE_PC 3
+    call    SYMBOL(MterpShouldSwitchInterpreters)
+    testb   %al, %al
+    jnz     MterpFallback
+    FETCH_INST
+    GOTO_NEXT
 
 
 /* ------------------------------ */
     .balign 128
 .L_op_invoke_custom_range: /* 0xfd */
-/* Transfer stub to alternate interpreter */
-    jmp     MterpFallback
+/* File: x86_64/op_invoke_custom_range.S */
+/* File: x86_64/invoke.S */
+/*
+ * Generic invoke handler wrapper.
+ */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+    .extern MterpInvokeCustomRange
+    EXPORT_PC
+    movq    rSELF, OUT_ARG0
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG1
+    movq    rPC, OUT_ARG2
+    REFRESH_INST 253
+    movl    rINST, OUT_32_ARG3
+    call    SYMBOL(MterpInvokeCustomRange)
+    testb   %al, %al
+    jz      MterpException
+    ADVANCE_PC 3
+    call    SYMBOL(MterpShouldSwitchInterpreters)
+    testb   %al, %al
+    jnz     MterpFallback
+    FETCH_INST
+    GOTO_NEXT
 
 
 /* ------------------------------ */
     .balign 128
-.L_op_unused_fe: /* 0xfe */
-/* File: x86_64/op_unused_fe.S */
-/* File: x86_64/unused.S */
-/*
- * Bail to reference interpreter to throw.
- */
-    jmp     MterpFallback
+.L_op_const_method_handle: /* 0xfe */
+/* File: x86_64/op_const_method_handle.S */
+/* File: x86_64/const.S */
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
+    .extern MterpConstMethodHandle
+    EXPORT_PC
+    movzwq  2(rPC), OUT_ARG0                # eax <- OUT_ARG0
+    movq    rINSTq, OUT_ARG1
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2
+    movq    rSELF, OUT_ARG3
+    call    SYMBOL(MterpConstMethodHandle)                 # (index, tgt_reg, shadow_frame, self)
+    testb   %al, %al
+    jnz     MterpPossibleException
+    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
 /* ------------------------------ */
     .balign 128
-.L_op_unused_ff: /* 0xff */
-/* File: x86_64/op_unused_ff.S */
-/* File: x86_64/unused.S */
-/*
- * Bail to reference interpreter to throw.
- */
-    jmp     MterpFallback
+.L_op_const_method_type: /* 0xff */
+/* File: x86_64/op_const_method_type.S */
+/* File: x86_64/const.S */
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
+    .extern MterpConstMethodType
+    EXPORT_PC
+    movzwq  2(rPC), OUT_ARG0                # eax <- OUT_ARG0
+    movq    rINSTq, OUT_ARG1
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2
+    movq    rSELF, OUT_ARG3
+    call    SYMBOL(MterpConstMethodType)                 # (index, tgt_reg, shadow_frame, self)
+    testb   %al, %al
+    jnz     MterpPossibleException
+    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
     .balign 128
@@ -11711,7 +11827,7 @@
 
 /* ------------------------------ */
     .balign 128
-.L_ALT_op_unused_fe: /* 0xfe */
+.L_ALT_op_const_method_handle: /* 0xfe */
 /* File: x86_64/alt_stub.S */
 /*
  * Inter-instruction transfer stub.  Call out to MterpCheckBefore to handle
@@ -11733,7 +11849,7 @@
 
 /* ------------------------------ */
     .balign 128
-.L_ALT_op_unused_ff: /* 0xff */
+.L_ALT_op_const_method_type: /* 0xff */
 /* File: x86_64/alt_stub.S */
 /*
  * Inter-instruction transfer stub.  Call out to MterpCheckBefore to handle
diff --git a/runtime/interpreter/mterp/x86/const.S b/runtime/interpreter/mterp/x86/const.S
new file mode 100644
index 0000000..f0cac1a
--- /dev/null
+++ b/runtime/interpreter/mterp/x86/const.S
@@ -0,0 +1,19 @@
+%default { "helper":"UndefinedConstHandler" }
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
+    .extern $helper
+    EXPORT_PC
+    movzwl  2(rPC), %eax                    # eax <- BBBB
+    movl    %eax, OUT_ARG0(%esp)
+    movl    rINST, OUT_ARG1(%esp)
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)
+    call    SYMBOL($helper)                 # (index, tgt_reg, shadow_frame, self)
+    RESTORE_IBASE
+    testb   %al, %al
+    jnz     MterpPossibleException
+    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/invoke_polymorphic.S b/runtime/interpreter/mterp/x86/invoke_polymorphic.S
new file mode 100644
index 0000000..5690b22
--- /dev/null
+++ b/runtime/interpreter/mterp/x86/invoke_polymorphic.S
@@ -0,0 +1,25 @@
+%default { "helper":"UndefinedInvokeHandler" }
+    /*
+     * invoke-polymorphic handler wrapper.
+     */
+    /* op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB, proto@HHHH */
+    .extern $helper
+    EXPORT_PC
+    movl    rSELF, %ecx
+    movl    %ecx, OUT_ARG0(%esp)
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG1(%esp)
+    movl    rPC, OUT_ARG2(%esp)
+    REFRESH_INST ${opnum}
+    movl    rINST, OUT_ARG3(%esp)
+    call    SYMBOL($helper)
+    testb   %al, %al
+    jz      MterpException
+    ADVANCE_PC 4
+    call    SYMBOL(MterpShouldSwitchInterpreters)
+    testb   %al, %al
+    jnz     MterpFallback
+    RESTORE_IBASE
+    FETCH_INST
+    GOTO_NEXT
diff --git a/runtime/interpreter/mterp/x86/op_const_class.S b/runtime/interpreter/mterp/x86/op_const_class.S
index 60be789..71648b5 100644
--- a/runtime/interpreter/mterp/x86/op_const_class.S
+++ b/runtime/interpreter/mterp/x86/op_const_class.S
@@ -1,14 +1 @@
-    /* const/class vAA, Class@BBBB */
-    EXPORT_PC
-    movzwl  2(rPC), %eax                    # eax<- BBBB
-    movl    %eax, OUT_ARG0(%esp)
-    movl    rINST, OUT_ARG1(%esp)
-    leal    OFF_FP_SHADOWFRAME(rFP), %eax
-    movl    %eax, OUT_ARG2(%esp)
-    movl    rSELF, %eax
-    movl    %eax, OUT_ARG3(%esp)
-    call    SYMBOL(MterpConstClass)         # (index, tgt_reg, shadow_frame, self)
-    RESTORE_IBASE
-    testb   %al, %al
-    jnz     MterpPossibleException
-    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
+%include "x86/const.S" { "helper":"MterpConstClass" }
diff --git a/runtime/interpreter/mterp/x86/op_const_method_handle.S b/runtime/interpreter/mterp/x86/op_const_method_handle.S
new file mode 100644
index 0000000..77948fd
--- /dev/null
+++ b/runtime/interpreter/mterp/x86/op_const_method_handle.S
@@ -0,0 +1 @@
+%include "x86/const.S" { "helper":"MterpConstMethodHandle" }
diff --git a/runtime/interpreter/mterp/x86/op_const_method_type.S b/runtime/interpreter/mterp/x86/op_const_method_type.S
new file mode 100644
index 0000000..03c6ce5
--- /dev/null
+++ b/runtime/interpreter/mterp/x86/op_const_method_type.S
@@ -0,0 +1 @@
+%include "x86/const.S" { "helper":"MterpConstMethodType" }
diff --git a/runtime/interpreter/mterp/x86/op_const_string.S b/runtime/interpreter/mterp/x86/op_const_string.S
index ff93b23..5553aab 100644
--- a/runtime/interpreter/mterp/x86/op_const_string.S
+++ b/runtime/interpreter/mterp/x86/op_const_string.S
@@ -1,14 +1 @@
-    /* const/string vAA, String@BBBB */
-    EXPORT_PC
-    movzwl  2(rPC), %eax                    # eax <- BBBB
-    movl    %eax, OUT_ARG0(%esp)
-    movl    rINST, OUT_ARG1(%esp)
-    leal    OFF_FP_SHADOWFRAME(rFP), %eax
-    movl    %eax, OUT_ARG2(%esp)
-    movl    rSELF, %eax
-    movl    %eax, OUT_ARG3(%esp)
-    call    SYMBOL(MterpConstString)        # (index, tgt_reg, shadow_frame, self)
-    RESTORE_IBASE
-    testb   %al, %al
-    jnz     MterpPossibleException
-    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
+%include "x86/const.S" { "helper":"MterpConstString" }
diff --git a/runtime/interpreter/mterp/x86/op_invoke_custom.S b/runtime/interpreter/mterp/x86/op_invoke_custom.S
new file mode 100644
index 0000000..eddd5b3
--- /dev/null
+++ b/runtime/interpreter/mterp/x86/op_invoke_custom.S
@@ -0,0 +1 @@
+%include "x86/invoke.S" { "helper":"MterpInvokeCustom" }
diff --git a/runtime/interpreter/mterp/x86/op_invoke_custom_range.S b/runtime/interpreter/mterp/x86/op_invoke_custom_range.S
new file mode 100644
index 0000000..1a4e884
--- /dev/null
+++ b/runtime/interpreter/mterp/x86/op_invoke_custom_range.S
@@ -0,0 +1 @@
+%include "x86/invoke.S" { "helper":"MterpInvokeCustomRange" }
diff --git a/runtime/interpreter/mterp/x86/op_invoke_polymorphic.S b/runtime/interpreter/mterp/x86/op_invoke_polymorphic.S
new file mode 100644
index 0000000..3907689
--- /dev/null
+++ b/runtime/interpreter/mterp/x86/op_invoke_polymorphic.S
@@ -0,0 +1 @@
+%include "x86/invoke_polymorphic.S" { "helper":"MterpInvokePolymorphic" }
diff --git a/runtime/interpreter/mterp/x86/op_invoke_polymorphic_range.S b/runtime/interpreter/mterp/x86/op_invoke_polymorphic_range.S
new file mode 100644
index 0000000..59a8230
--- /dev/null
+++ b/runtime/interpreter/mterp/x86/op_invoke_polymorphic_range.S
@@ -0,0 +1 @@
+%include "x86/invoke_polymorphic.S" { "helper":"MterpInvokePolymorphicRange" }
diff --git a/runtime/interpreter/mterp/x86/op_unused_fe.S b/runtime/interpreter/mterp/x86/op_unused_fe.S
deleted file mode 100644
index 31d98c1..0000000
--- a/runtime/interpreter/mterp/x86/op_unused_fe.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "x86/unused.S"
diff --git a/runtime/interpreter/mterp/x86/op_unused_ff.S b/runtime/interpreter/mterp/x86/op_unused_ff.S
deleted file mode 100644
index 31d98c1..0000000
--- a/runtime/interpreter/mterp/x86/op_unused_ff.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "x86/unused.S"
diff --git a/runtime/interpreter/mterp/x86_64/const.S b/runtime/interpreter/mterp/x86_64/const.S
new file mode 100644
index 0000000..1ddf20f
--- /dev/null
+++ b/runtime/interpreter/mterp/x86_64/const.S
@@ -0,0 +1,15 @@
+%default { "helper":"UndefinedConstHandler" }
+    /* const/class vAA, type@BBBB */
+    /* const/method-handle vAA, method_handle@BBBB */
+    /* const/method-type vAA, proto@BBBB */
+    /* const/string vAA, string@@BBBB */
+    .extern $helper
+    EXPORT_PC
+    movzwq  2(rPC), OUT_ARG0                # eax <- OUT_ARG0
+    movq    rINSTq, OUT_ARG1
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2
+    movq    rSELF, OUT_ARG3
+    call    SYMBOL($helper)                 # (index, tgt_reg, shadow_frame, self)
+    testb   %al, %al
+    jnz     MterpPossibleException
+    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86_64/invoke_polymorphic.S b/runtime/interpreter/mterp/x86_64/invoke_polymorphic.S
new file mode 100644
index 0000000..5157860
--- /dev/null
+++ b/runtime/interpreter/mterp/x86_64/invoke_polymorphic.S
@@ -0,0 +1,22 @@
+%default { "helper":"UndefinedInvokeHandler" }
+    /*
+     * invoke-polymorphic handler wrapper.
+     */
+    /* op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB, proto@HHHH */
+    .extern $helper
+    EXPORT_PC
+    movq    rSELF, OUT_ARG0
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG1
+    movq    rPC, OUT_ARG2
+    REFRESH_INST ${opnum}
+    movl    rINST, OUT_32_ARG3
+    call    SYMBOL($helper)
+    testb   %al, %al
+    jz      MterpException
+    ADVANCE_PC 4
+    call    SYMBOL(MterpShouldSwitchInterpreters)
+    testb   %al, %al
+    jnz     MterpFallback
+    FETCH_INST
+    GOTO_NEXT
diff --git a/runtime/interpreter/mterp/x86_64/op_const_class.S b/runtime/interpreter/mterp/x86_64/op_const_class.S
index 494920a..0c402e1 100644
--- a/runtime/interpreter/mterp/x86_64/op_const_class.S
+++ b/runtime/interpreter/mterp/x86_64/op_const_class.S
@@ -1,10 +1 @@
-    /* const/class vAA, Class@BBBB */
-    EXPORT_PC
-    movzwq  2(rPC), OUT_ARG0                # eax <- OUT_ARG0
-    movq    rINSTq, OUT_ARG1
-    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2
-    movq    rSELF, OUT_ARG3
-    call    SYMBOL(MterpConstClass)         # (index, tgt_reg, shadow_frame, self)
-    testb   %al, %al
-    jnz     MterpPossibleException
-    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
+%include "x86_64/const.S" { "helper":"MterpConstClass" }
diff --git a/runtime/interpreter/mterp/x86_64/op_const_method_handle.S b/runtime/interpreter/mterp/x86_64/op_const_method_handle.S
new file mode 100644
index 0000000..2b8b0a2
--- /dev/null
+++ b/runtime/interpreter/mterp/x86_64/op_const_method_handle.S
@@ -0,0 +1 @@
+%include "x86_64/const.S" { "helper":"MterpConstMethodHandle" }
diff --git a/runtime/interpreter/mterp/x86_64/op_const_method_type.S b/runtime/interpreter/mterp/x86_64/op_const_method_type.S
new file mode 100644
index 0000000..33ce952
--- /dev/null
+++ b/runtime/interpreter/mterp/x86_64/op_const_method_type.S
@@ -0,0 +1 @@
+%include "x86_64/const.S" { "helper":"MterpConstMethodType" }
diff --git a/runtime/interpreter/mterp/x86_64/op_const_string.S b/runtime/interpreter/mterp/x86_64/op_const_string.S
index 7c199ec..5a29bd3 100644
--- a/runtime/interpreter/mterp/x86_64/op_const_string.S
+++ b/runtime/interpreter/mterp/x86_64/op_const_string.S
@@ -1,10 +1 @@
-    /* const/string vAA, String@BBBB */
-    EXPORT_PC
-    movzwq  2(rPC), OUT_ARG0                # OUT_ARG0 <- BBBB
-    movq    rINSTq, OUT_ARG1
-    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2
-    movq    rSELF, OUT_ARG3
-    call    SYMBOL(MterpConstString)        # (index, tgt_reg, shadow_frame, self)
-    testb   %al, %al
-    jnz     MterpPossibleException
-    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
+%include "x86_64/const.S" { "helper":"MterpConstString" }
diff --git a/runtime/interpreter/mterp/x86_64/op_invoke_custom.S b/runtime/interpreter/mterp/x86_64/op_invoke_custom.S
new file mode 100644
index 0000000..f4011f6
--- /dev/null
+++ b/runtime/interpreter/mterp/x86_64/op_invoke_custom.S
@@ -0,0 +1 @@
+%include "x86_64/invoke.S" { "helper":"MterpInvokeCustom" }
diff --git a/runtime/interpreter/mterp/x86_64/op_invoke_custom_range.S b/runtime/interpreter/mterp/x86_64/op_invoke_custom_range.S
new file mode 100644
index 0000000..94612c4
--- /dev/null
+++ b/runtime/interpreter/mterp/x86_64/op_invoke_custom_range.S
@@ -0,0 +1 @@
+%include "x86_64/invoke.S" { "helper":"MterpInvokeCustomRange" }
diff --git a/runtime/interpreter/mterp/x86_64/op_invoke_polymorphic.S b/runtime/interpreter/mterp/x86_64/op_invoke_polymorphic.S
new file mode 100644
index 0000000..4529445
--- /dev/null
+++ b/runtime/interpreter/mterp/x86_64/op_invoke_polymorphic.S
@@ -0,0 +1 @@
+%include "x86_64/invoke_polymorphic.S" { "helper":"MterpInvokePolymorphic" }
diff --git a/runtime/interpreter/mterp/x86_64/op_invoke_polymorphic_range.S b/runtime/interpreter/mterp/x86_64/op_invoke_polymorphic_range.S
new file mode 100644
index 0000000..01981c1
--- /dev/null
+++ b/runtime/interpreter/mterp/x86_64/op_invoke_polymorphic_range.S
@@ -0,0 +1 @@
+%include "x86_64/invoke_polymorphic.S" { "helper":"MterpInvokePolymorphicRange" }
diff --git a/runtime/interpreter/mterp/x86_64/op_unused_fe.S b/runtime/interpreter/mterp/x86_64/op_unused_fe.S
deleted file mode 100644
index 280615f..0000000
--- a/runtime/interpreter/mterp/x86_64/op_unused_fe.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "x86_64/unused.S"
diff --git a/runtime/interpreter/mterp/x86_64/op_unused_ff.S b/runtime/interpreter/mterp/x86_64/op_unused_ff.S
deleted file mode 100644
index 280615f..0000000
--- a/runtime/interpreter/mterp/x86_64/op_unused_ff.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "x86_64/unused.S"
diff --git a/runtime/mirror/dex_cache_test.cc b/runtime/mirror/dex_cache_test.cc
index a3d9035..8198636 100644
--- a/runtime/mirror/dex_cache_test.cc
+++ b/runtime/mirror/dex_cache_test.cc
@@ -148,12 +148,18 @@
 
   const DexFile::MethodId& method1_id = dex_file.GetMethodId(method1->GetDexMethodIndex());
   const DexFile::MethodId& method2_id = dex_file.GetMethodId(method2->GetDexMethodIndex());
-
   Handle<mirror::MethodType> method1_type = hs.NewHandle(
-      class_linker_->ResolveMethodType(dex_file, method1_id.proto_idx_, dex_cache, class_loader));
+      class_linker_->ResolveMethodType(soa.Self(),
+                                       dex_file,
+                                       method1_id.proto_idx_,
+                                       dex_cache,
+                                       class_loader));
   Handle<mirror::MethodType> method2_type = hs.NewHandle(
-      class_linker_->ResolveMethodType(dex_file, method2_id.proto_idx_, dex_cache, class_loader));
-
+      class_linker_->ResolveMethodType(soa.Self(),
+                                       dex_file,
+                                       method2_id.proto_idx_,
+                                       dex_cache,
+                                       class_loader));
   EXPECT_EQ(method1_type.Get(), dex_cache->GetResolvedMethodType(method1_id.proto_idx_));
   EXPECT_EQ(method2_type.Get(), dex_cache->GetResolvedMethodType(method2_id.proto_idx_));