ART: Make method handle runtime code callable from compiler.

Most of this change is moving the existing method handles code, but it
also introduces a new header file, common_dex_operations.h, that has
some operations taken from interpreter_common.{h,cc} that are also used
by method handles (perform call, set field, get field).

Bug: 30550796
Test: m test-art-host
Change-Id: I2235e13770a5562950f2767f65a25ca273479150
diff --git a/runtime/common_dex_operations.h b/runtime/common_dex_operations.h
new file mode 100644
index 0000000..6693eef
--- /dev/null
+++ b/runtime/common_dex_operations.h
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_COMMON_DEX_OPERATIONS_H_
+#define ART_RUNTIME_COMMON_DEX_OPERATIONS_H_
+
+#include "art_field.h"
+#include "art_method.h"
+#include "class_linker.h"
+#include "interpreter/unstarted_runtime.h"
+#include "runtime.h"
+#include "stack.h"
+#include "thread.h"
+
+namespace art {
+
+namespace interpreter {
+  void ArtInterpreterToInterpreterBridge(Thread* self,
+                                        const DexFile::CodeItem* code_item,
+                                        ShadowFrame* shadow_frame,
+                                        JValue* result)
+     REQUIRES_SHARED(Locks::mutator_lock_);
+
+  void ArtInterpreterToCompiledCodeBridge(Thread* self,
+                                          ArtMethod* caller,
+                                          const DexFile::CodeItem* code_item,
+                                          ShadowFrame* shadow_frame,
+                                          JValue* result);
+}  // namespace interpreter
+
+inline void PerformCall(Thread* self,
+                        const DexFile::CodeItem* code_item,
+                        ArtMethod* caller_method,
+                        const size_t first_dest_reg,
+                        ShadowFrame* callee_frame,
+                        JValue* result)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  if (LIKELY(Runtime::Current()->IsStarted())) {
+    ArtMethod* target = callee_frame->GetMethod();
+    if (ClassLinker::ShouldUseInterpreterEntrypoint(
+        target,
+        target->GetEntryPointFromQuickCompiledCode())) {
+      interpreter::ArtInterpreterToInterpreterBridge(self, code_item, callee_frame, result);
+    } else {
+      interpreter::ArtInterpreterToCompiledCodeBridge(
+          self, caller_method, code_item, callee_frame, result);
+    }
+  } else {
+    interpreter::UnstartedRuntime::Invoke(self, code_item, callee_frame, result, first_dest_reg);
+  }
+}
+
+template<Primitive::Type field_type>
+static ALWAYS_INLINE void DoFieldGetCommon(Thread* self,
+                                           const ShadowFrame& shadow_frame,
+                                           ObjPtr<mirror::Object> obj,
+                                           ArtField* field,
+                                           JValue* result)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  field->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self);
+
+  // Report this field access to instrumentation if needed.
+  instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
+  if (UNLIKELY(instrumentation->HasFieldReadListeners())) {
+    StackHandleScope<1> hs(self);
+    // Wrap in handle wrapper in case the listener does thread suspension.
+    HandleWrapperObjPtr<mirror::Object> h(hs.NewHandleWrapper(&obj));
+    ObjPtr<mirror::Object> this_object;
+    if (!field->IsStatic()) {
+      this_object = obj;
+    }
+    instrumentation->FieldReadEvent(self,
+                                    this_object.Ptr(),
+                                    shadow_frame.GetMethod(),
+                                    shadow_frame.GetDexPC(),
+                                    field);
+  }
+
+  switch (field_type) {
+    case Primitive::kPrimBoolean:
+      result->SetZ(field->GetBoolean(obj));
+      break;
+    case Primitive::kPrimByte:
+      result->SetB(field->GetByte(obj));
+      break;
+    case Primitive::kPrimChar:
+      result->SetC(field->GetChar(obj));
+      break;
+    case Primitive::kPrimShort:
+      result->SetS(field->GetShort(obj));
+      break;
+    case Primitive::kPrimInt:
+      result->SetI(field->GetInt(obj));
+      break;
+    case Primitive::kPrimLong:
+      result->SetJ(field->GetLong(obj));
+      break;
+    case Primitive::kPrimNot:
+      result->SetL(field->GetObject(obj));
+      break;
+    case Primitive::kPrimVoid:
+      LOG(FATAL) << "Unreachable " << field_type;
+      break;
+  }
+}
+
+template<Primitive::Type field_type, bool do_assignability_check, bool transaction_active>
+ALWAYS_INLINE bool DoFieldPutCommon(Thread* self,
+                                    const ShadowFrame& shadow_frame,
+                                    ObjPtr<mirror::Object> obj,
+                                    ArtField* field,
+                                    const JValue& value)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  field->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self);
+
+  // Report this field access to instrumentation if needed. Since we only have the offset of
+  // the field from the base of the object, we need to look for it first.
+  instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
+  if (UNLIKELY(instrumentation->HasFieldWriteListeners())) {
+    StackHandleScope<1> hs(self);
+    // Wrap in handle wrapper in case the listener does thread suspension.
+    HandleWrapperObjPtr<mirror::Object> h(hs.NewHandleWrapper(&obj));
+    ObjPtr<mirror::Object> this_object = field->IsStatic() ? nullptr : obj;
+    instrumentation->FieldWriteEvent(self, this_object.Ptr(),
+                                     shadow_frame.GetMethod(),
+                                     shadow_frame.GetDexPC(),
+                                     field,
+                                     value);
+  }
+
+  switch (field_type) {
+    case Primitive::kPrimBoolean:
+      field->SetBoolean<transaction_active>(obj, value.GetZ());
+      break;
+    case Primitive::kPrimByte:
+      field->SetByte<transaction_active>(obj, value.GetB());
+      break;
+    case Primitive::kPrimChar:
+      field->SetChar<transaction_active>(obj, value.GetC());
+      break;
+    case Primitive::kPrimShort:
+      field->SetShort<transaction_active>(obj, value.GetS());
+      break;
+    case Primitive::kPrimInt:
+      field->SetInt<transaction_active>(obj, value.GetI());
+      break;
+    case Primitive::kPrimLong:
+      field->SetLong<transaction_active>(obj, value.GetJ());
+      break;
+    case Primitive::kPrimNot: {
+      ObjPtr<mirror::Object> reg = value.GetL();
+      if (do_assignability_check && reg != nullptr) {
+        // FieldHelper::GetType can resolve classes, use a handle wrapper which will restore the
+        // object in the destructor.
+        ObjPtr<mirror::Class> field_class;
+        {
+          StackHandleScope<2> hs(self);
+          HandleWrapperObjPtr<mirror::Object> h_reg(hs.NewHandleWrapper(&reg));
+          HandleWrapperObjPtr<mirror::Object> h_obj(hs.NewHandleWrapper(&obj));
+          field_class = field->GetType<true>();
+        }
+        if (!reg->VerifierInstanceOf(field_class.Ptr())) {
+          // This should never happen.
+          std::string temp1, temp2, temp3;
+          self->ThrowNewExceptionF("Ljava/lang/InternalError;",
+                                   "Put '%s' that is not instance of field '%s' in '%s'",
+                                   reg->GetClass()->GetDescriptor(&temp1),
+                                   field_class->GetDescriptor(&temp2),
+                                   field->GetDeclaringClass()->GetDescriptor(&temp3));
+          return false;
+        }
+      }
+      field->SetObj<transaction_active>(obj, reg);
+      break;
+    }
+    case Primitive::kPrimVoid: {
+      LOG(FATAL) << "Unreachable " << field_type;
+      break;
+    }
+  }
+  return true;
+}
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_COMMON_DEX_OPERATIONS_H_
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index a09e71b..ca26207 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -32,7 +32,6 @@
 #include "reflection.h"
 #include "reflection-inl.h"
 #include "stack.h"
-#include "unstarted_runtime.h"
 #include "verifier/method_verifier.h"
 #include "well_known_classes.h"
 
@@ -43,60 +42,6 @@
   ThrowNullPointerExceptionFromDexPC();
 }
 
-template<Primitive::Type field_type>
-static ALWAYS_INLINE void DoFieldGetCommon(Thread* self,
-                                           const ShadowFrame& shadow_frame,
-                                           ObjPtr<mirror::Object>& obj,
-                                           ArtField* field,
-                                           JValue* result)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  field->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self);
-
-  // Report this field access to instrumentation if needed.
-  instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
-  if (UNLIKELY(instrumentation->HasFieldReadListeners())) {
-    StackHandleScope<1> hs(self);
-    // Wrap in handle wrapper in case the listener does thread suspension.
-    HandleWrapperObjPtr<mirror::Object> h(hs.NewHandleWrapper(&obj));
-    ObjPtr<mirror::Object> this_object;
-    if (!field->IsStatic()) {
-      this_object = obj;
-    }
-    instrumentation->FieldReadEvent(self,
-                                    this_object.Ptr(),
-                                    shadow_frame.GetMethod(),
-                                    shadow_frame.GetDexPC(),
-                                    field);
-  }
-
-  switch (field_type) {
-    case Primitive::kPrimBoolean:
-      result->SetZ(field->GetBoolean(obj));
-      break;
-    case Primitive::kPrimByte:
-      result->SetB(field->GetByte(obj));
-      break;
-    case Primitive::kPrimChar:
-      result->SetC(field->GetChar(obj));
-      break;
-    case Primitive::kPrimShort:
-      result->SetS(field->GetShort(obj));
-      break;
-    case Primitive::kPrimInt:
-      result->SetI(field->GetInt(obj));
-      break;
-    case Primitive::kPrimLong:
-      result->SetJ(field->GetLong(obj));
-      break;
-    case Primitive::kPrimNot:
-      result->SetL(field->GetObject(obj));
-      break;
-    default:
-      LOG(FATAL) << "Unreachable: " << field_type;
-      UNREACHABLE();
-  }
-}
-
 template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
 bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst,
                 uint16_t inst_data) {
@@ -184,48 +129,6 @@
 #undef EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL
 #undef EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL
 
-// Helper for getters in invoke-polymorphic.
-inline static void DoFieldGetForInvokePolymorphic(Thread* self,
-                                                  const ShadowFrame& shadow_frame,
-                                                  ObjPtr<mirror::Object>& obj,
-                                                  ArtField* field,
-                                                  Primitive::Type field_type,
-                                                  JValue* result)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  switch (field_type) {
-    case Primitive::kPrimBoolean:
-      DoFieldGetCommon<Primitive::kPrimBoolean>(self, shadow_frame, obj, field, result);
-      break;
-    case Primitive::kPrimByte:
-      DoFieldGetCommon<Primitive::kPrimByte>(self, shadow_frame, obj, field, result);
-      break;
-    case Primitive::kPrimChar:
-      DoFieldGetCommon<Primitive::kPrimChar>(self, shadow_frame, obj, field, result);
-      break;
-    case Primitive::kPrimShort:
-      DoFieldGetCommon<Primitive::kPrimShort>(self, shadow_frame, obj, field, result);
-      break;
-    case Primitive::kPrimInt:
-      DoFieldGetCommon<Primitive::kPrimInt>(self, shadow_frame, obj, field, result);
-      break;
-    case Primitive::kPrimLong:
-      DoFieldGetCommon<Primitive::kPrimLong>(self, shadow_frame, obj, field, result);
-      break;
-    case Primitive::kPrimFloat:
-      DoFieldGetCommon<Primitive::kPrimInt>(self, shadow_frame, obj, field, result);
-      break;
-    case Primitive::kPrimDouble:
-      DoFieldGetCommon<Primitive::kPrimLong>(self, shadow_frame, obj, field, result);
-      break;
-    case Primitive::kPrimNot:
-      DoFieldGetCommon<Primitive::kPrimNot>(self, shadow_frame, obj, field, result);
-      break;
-    case Primitive::kPrimVoid:
-      LOG(FATAL) << "Unreachable: " << field_type;
-      UNREACHABLE();
-  }
-}
-
 // Handles iget-quick, iget-wide-quick and iget-object-quick instructions.
 // Returns true on success, otherwise throws an exception and returns false.
 template<Primitive::Type field_type>
@@ -300,42 +203,6 @@
 EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimNot);      // iget-object-quick.
 #undef EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL
 
-static JValue GetFieldValue(const ShadowFrame& shadow_frame,
-                            Primitive::Type field_type,
-                            uint32_t vreg)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  JValue field_value;
-  switch (field_type) {
-    case Primitive::kPrimBoolean:
-      field_value.SetZ(static_cast<uint8_t>(shadow_frame.GetVReg(vreg)));
-      break;
-    case Primitive::kPrimByte:
-      field_value.SetB(static_cast<int8_t>(shadow_frame.GetVReg(vreg)));
-      break;
-    case Primitive::kPrimChar:
-      field_value.SetC(static_cast<uint16_t>(shadow_frame.GetVReg(vreg)));
-      break;
-    case Primitive::kPrimShort:
-      field_value.SetS(static_cast<int16_t>(shadow_frame.GetVReg(vreg)));
-      break;
-    case Primitive::kPrimInt:
-    case Primitive::kPrimFloat:
-      field_value.SetI(shadow_frame.GetVReg(vreg));
-      break;
-    case Primitive::kPrimLong:
-    case Primitive::kPrimDouble:
-      field_value.SetJ(shadow_frame.GetVRegLong(vreg));
-      break;
-    case Primitive::kPrimNot:
-      field_value.SetL(shadow_frame.GetVRegReference(vreg));
-      break;
-    case Primitive::kPrimVoid:
-      LOG(FATAL) << "Unreachable: " << field_type;
-      UNREACHABLE();
-  }
-  return field_value;
-}
-
 template<Primitive::Type field_type>
 static JValue GetFieldValue(const ShadowFrame& shadow_frame, uint32_t vreg)
     REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -369,82 +236,6 @@
   return field_value;
 }
 
-template<Primitive::Type field_type, bool do_assignability_check, bool transaction_active>
-static inline bool DoFieldPutCommon(Thread* self,
-                                    const ShadowFrame& shadow_frame,
-                                    ObjPtr<mirror::Object>& obj,
-                                    ArtField* f,
-                                    const JValue& value)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  f->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self);
-
-  // Report this field access to instrumentation if needed. Since we only have the offset of
-  // the field from the base of the object, we need to look for it first.
-  instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
-  if (UNLIKELY(instrumentation->HasFieldWriteListeners())) {
-    StackHandleScope<1> hs(self);
-    // Wrap in handle wrapper in case the listener does thread suspension.
-    HandleWrapperObjPtr<mirror::Object> h(hs.NewHandleWrapper(&obj));
-    ObjPtr<mirror::Object> this_object = f->IsStatic() ? nullptr : obj;
-    instrumentation->FieldWriteEvent(self, this_object.Ptr(),
-                                     shadow_frame.GetMethod(),
-                                     shadow_frame.GetDexPC(),
-                                     f,
-                                     value);
-  }
-
-  switch (field_type) {
-    case Primitive::kPrimBoolean:
-      f->SetBoolean<transaction_active>(obj, value.GetZ());
-      break;
-    case Primitive::kPrimByte:
-      f->SetByte<transaction_active>(obj, value.GetB());
-      break;
-    case Primitive::kPrimChar:
-      f->SetChar<transaction_active>(obj, value.GetC());
-      break;
-    case Primitive::kPrimShort:
-      f->SetShort<transaction_active>(obj, value.GetS());
-      break;
-    case Primitive::kPrimInt:
-      f->SetInt<transaction_active>(obj, value.GetI());
-      break;
-    case Primitive::kPrimLong:
-      f->SetLong<transaction_active>(obj, value.GetJ());
-      break;
-    case Primitive::kPrimNot: {
-      ObjPtr<mirror::Object> reg = value.GetL();
-      if (do_assignability_check && reg != nullptr) {
-        // FieldHelper::GetType can resolve classes, use a handle wrapper which will restore the
-        // object in the destructor.
-        ObjPtr<mirror::Class> field_class;
-        {
-          StackHandleScope<2> hs(self);
-          HandleWrapperObjPtr<mirror::Object> h_reg(hs.NewHandleWrapper(&reg));
-          HandleWrapperObjPtr<mirror::Object> h_obj(hs.NewHandleWrapper(&obj));
-          field_class = f->GetType<true>();
-        }
-        if (!reg->VerifierInstanceOf(field_class.Ptr())) {
-          // This should never happen.
-          std::string temp1, temp2, temp3;
-          self->ThrowNewExceptionF("Ljava/lang/InternalError;",
-                                   "Put '%s' that is not instance of field '%s' in '%s'",
-                                   reg->GetClass()->GetDescriptor(&temp1),
-                                   field_class->GetDescriptor(&temp2),
-                                   f->GetDeclaringClass()->GetDescriptor(&temp3));
-          return false;
-        }
-      }
-      f->SetObj<transaction_active>(obj, reg);
-      break;
-    }
-    default:
-      LOG(FATAL) << "Unreachable: " << field_type;
-      UNREACHABLE();
-  }
-  return true;
-}
-
 template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check,
          bool transaction_active>
 bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame, const Instruction* inst,
@@ -511,46 +302,6 @@
 #undef EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL
 #undef EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL
 
-// Helper for setters in invoke-polymorphic.
-bool DoFieldPutForInvokePolymorphic(Thread* self,
-                                    ShadowFrame& shadow_frame,
-                                    ObjPtr<mirror::Object>& obj,
-                                    ArtField* field,
-                                    Primitive::Type field_type,
-                                    const JValue& value)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  static const bool kDoCheckAssignability = false;
-  static const bool kTransaction = false;
-  switch (field_type) {
-    case Primitive::kPrimBoolean:
-      return DoFieldPutCommon<Primitive::kPrimBoolean, kDoCheckAssignability, kTransaction>(
-          self, shadow_frame, obj, field, value);
-    case Primitive::kPrimByte:
-      return DoFieldPutCommon<Primitive::kPrimByte, kDoCheckAssignability, kTransaction>(
-          self, shadow_frame, obj, field, value);
-    case Primitive::kPrimChar:
-      return DoFieldPutCommon<Primitive::kPrimChar, kDoCheckAssignability, kTransaction>(
-          self, shadow_frame, obj, field, value);
-    case Primitive::kPrimShort:
-      return DoFieldPutCommon<Primitive::kPrimShort, kDoCheckAssignability, kTransaction>(
-          self, shadow_frame, obj, field, value);
-    case Primitive::kPrimInt:
-    case Primitive::kPrimFloat:
-      return DoFieldPutCommon<Primitive::kPrimInt, kDoCheckAssignability, kTransaction>(
-          self, shadow_frame, obj, field, value);
-    case Primitive::kPrimLong:
-    case Primitive::kPrimDouble:
-      return DoFieldPutCommon<Primitive::kPrimLong, kDoCheckAssignability, kTransaction>(
-          self, shadow_frame, obj, field, value);
-    case Primitive::kPrimNot:
-      return DoFieldPutCommon<Primitive::kPrimNot, kDoCheckAssignability, kTransaction>(
-          self, shadow_frame, obj, field, value);
-    case Primitive::kPrimVoid:
-      LOG(FATAL) << "Unreachable: " << field_type;
-      UNREACHABLE();
-  }
-}
-
 template<Primitive::Type field_type, bool transaction_active>
 bool DoIPutQuick(const ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) {
   ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
@@ -697,36 +448,6 @@
                                        uint32_t vregC) REQUIRES_SHARED(Locks::mutator_lock_);
 
 template <bool is_range>
-static ALWAYS_INLINE bool DoCallPolymorphic(ArtMethod* called_method,
-                                            Handle<mirror::MethodType> callsite_type,
-                                            Handle<mirror::MethodType> target_type,
-                                            Thread* self,
-                                            ShadowFrame& shadow_frame,
-                                            JValue* result,
-                                            uint32_t (&arg)[Instruction::kMaxVarArgRegs],
-                                            uint32_t vregC,
-                                            const MethodHandleKind handle_kind)
-  REQUIRES_SHARED(Locks::mutator_lock_);
-
-template <bool is_range>
-static ALWAYS_INLINE bool DoCallTransform(ArtMethod* called_method,
-                                          Handle<mirror::MethodType> callsite_type,
-                                          Handle<mirror::MethodType> callee_type,
-                                          Thread* self,
-                                          ShadowFrame& shadow_frame,
-                                          Handle<mirror::MethodHandleImpl> receiver,
-                                          JValue* result,
-                                          uint32_t (&arg)[Instruction::kMaxVarArgRegs],
-                                          uint32_t vregC) REQUIRES_SHARED(Locks::mutator_lock_);
-
-ALWAYS_INLINE void PerformCall(Thread* self,
-                               const DexFile::CodeItem* code_item,
-                               ArtMethod* caller_method,
-                               const size_t first_dest_reg,
-                               ShadowFrame* callee_frame,
-                               JValue* result) REQUIRES_SHARED(Locks::mutator_lock_);
-
-template <bool is_range>
 ALWAYS_INLINE void CopyRegisters(ShadowFrame& caller_frame,
                                  ShadowFrame* callee_frame,
                                  const uint32_t (&arg)[Instruction::kMaxVarArgRegs],
@@ -798,55 +519,12 @@
   }
 }
 
-inline static bool IsInvokeExact(const DexFile& dex_file, int invoke_method_idx) {
-  // This check uses string comparison as it needs less code and data
-  // to do than fetching the associated ArtMethod from the DexCache
-  // and checking against ArtMethods in the well known classes. The
-  // verifier needs to perform a more rigorous check.
-  const char* method_name = dex_file.GetMethodName(dex_file.GetMethodId(invoke_method_idx));
-  bool is_invoke_exact = (0 == strcmp(method_name, "invokeExact"));
-  DCHECK(is_invoke_exact || (0 == strcmp(method_name, "invoke")));
-  return is_invoke_exact;
-}
-
-inline static ObjPtr<mirror::Class> GetAndInitializeDeclaringClass(Thread* self, ArtField* field)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  // Method handle invocations on static fields should ensure class is
-  // initialized. This usually happens when an instance is constructed
-  // or class members referenced, but this is not guaranteed when
-  // looking up method handles.
-  ObjPtr<mirror::Class> klass = field->GetDeclaringClass();
-  if (UNLIKELY(!klass->IsInitialized())) {
-    StackHandleScope<1> hs(self);
-    HandleWrapperObjPtr<mirror::Class> h(hs.NewHandleWrapper(&klass));
-    if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(self, h, true, true)) {
-      DCHECK(self->IsExceptionPending());
-      return nullptr;
-    }
-  }
-  return klass;
-}
-
-// Returns true iff. the callsite type for a polymorphic invoke is transformer
-// like, i.e that it has a single input argument whose type is
-// dalvik.system.EmulatedStackFrame.
-static inline bool IsCallerTransformer(Handle<mirror::MethodType> callsite_type)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  ObjPtr<mirror::ObjectArray<mirror::Class>> param_types(callsite_type->GetPTypes());
-  if (param_types->GetLength() == 1) {
-    ObjPtr<mirror::Class> param(param_types->GetWithoutChecks(0));
-    return param == WellKnownClasses::ToClass(WellKnownClasses::dalvik_system_EmulatedStackFrame);
-  }
-
-  return false;
-}
-
 template<bool is_range, bool do_access_check>
-inline bool DoInvokePolymorphic(Thread* self,
-                                ShadowFrame& shadow_frame,
-                                const Instruction* inst,
-                                uint16_t inst_data,
-                                JValue* result)
+bool DoInvokePolymorphic(Thread* self,
+                         ShadowFrame& shadow_frame,
+                         const Instruction* inst,
+                         uint16_t inst_data,
+                         JValue* result)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   // Invoke-polymorphic instructions always take a receiver. i.e, they are never static.
   const uint32_t vRegC = (is_range) ? inst->VRegC_4rcc() : inst->VRegC_45cc();
@@ -857,15 +535,10 @@
   // and provides sane return result in error cases.
   result->SetJ(0);
 
-  // Determine if this invocation is MethodHandle.invoke() or
-  // MethodHandle.invokeExact().
-  bool is_invoke_exact = IsInvokeExact(shadow_frame.GetMethod()->GetDeclaringClass()->GetDexFile(),
-                                       invoke_method_idx);
-
   // 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<6> hs(self);
+  StackHandleScope<5> hs(self);
   Handle<mirror::MethodHandleImpl> method_handle(hs.NewHandle(
       ObjPtr<mirror::MethodHandleImpl>::DownCast(
           MakeObjPtr(shadow_frame.GetVRegReference(vRegC)))));
@@ -877,7 +550,7 @@
   }
 
   // The vRegH value gives the index of the proto_id associated with this
-  // signature polymorphic callsite.
+  // signature polymorphic call site.
   const uint32_t callsite_proto_id = (is_range) ? inst->VRegH_4rcc() : inst->VRegH_45cc();
 
   // Call through to the classlinker and ask it to resolve the static type associated
@@ -896,224 +569,43 @@
     return false;
   }
 
-  const MethodHandleKind handle_kind = method_handle->GetHandleKind();
-  Handle<mirror::MethodType> handle_type(hs.NewHandle(method_handle->GetMethodType()));
-  CHECK(handle_type.Get() != nullptr);
-  {
-    // We need to check the nominal type of the handle in addition to the
-    // real type. The "nominal" type is present when MethodHandle.asType is
-    // called any handle, and results in the declared type of the handle
-    // changing.
-    ObjPtr<mirror::MethodType> nominal_type(method_handle->GetNominalType());
-    ObjPtr<mirror::MethodType> check_type(nullptr);
-    if (LIKELY(nominal_type.Ptr() == nullptr)) {
-      check_type.Assign(handle_type.Get());
-    } else {
-      check_type.Assign(nominal_type.Ptr());
-    }
+  ArtMethod* invoke_method =
+      class_linker->ResolveMethod<ClassLinker::kForceICCECheck>(self,
+                                                                invoke_method_idx,
+                                                                shadow_frame.GetMethod(),
+                                                                kVirtual);
 
-    if (is_invoke_exact) {
-      if (UNLIKELY(!callsite_type->IsExactMatch(check_type.Ptr()))) {
-        ThrowWrongMethodTypeException(check_type.Ptr(), callsite_type.Get());
-        return false;
-      }
-    } else if (!IsInvokeTransform(handle_kind)) {
-      if (UNLIKELY(!IsCallerTransformer(callsite_type) &&
-                   !callsite_type->IsConvertible(check_type.Ptr()))) {
-        ThrowWrongMethodTypeException(check_type.Ptr(), callsite_type.Get());
-        return false;
-      }
-    }
-  }
-
-  uint32_t arg[Instruction::kMaxVarArgRegs] = {};
-  uint32_t first_src_reg = 0;
+  // There is a common dispatch method for method handles that takes
+  // arguments either from a range or an array of arguments depending
+  // on whether the DEX instruction is invoke-polymorphic/range or
+  // invoke-polymorphic. The array here is for the latter.
+  uint32_t args[Instruction::kMaxVarArgRegs] = {};
   if (is_range) {
-    first_src_reg = (inst->VRegC_4rcc() + 1);
+    // VRegC is the register holding the method handle. Arguments passed
+    // to the method handle's target do not include the method handle.
+    uint32_t first_arg = inst->VRegC_4rcc() + 1;
+    return DoInvokePolymorphic<is_range, do_access_check>(self,
+                                                          invoke_method,
+                                                          shadow_frame,
+                                                          method_handle,
+                                                          callsite_type,
+                                                          args /* unused */,
+                                                          first_arg,
+                                                          result);
   } else {
-    inst->GetVarArgs(arg, inst_data);
-    arg[0] = arg[1];
-    arg[1] = arg[2];
-    arg[2] = arg[3];
-    arg[3] = arg[4];
-    arg[4] = 0;
-    first_src_reg = arg[0];
-  }
-
-  if (IsInvoke(handle_kind)) {
-    // Get the method we're actually invoking along with the kind of
-    // invoke that is desired. We don't need to perform access checks at this
-    // point because they would have been performed on our behalf at the point
-    // of creation of the method handle.
-    ArtMethod* called_method = method_handle->GetTargetMethod();
-    CHECK(called_method != nullptr);
-
-    if (handle_kind == kInvokeVirtual || handle_kind == kInvokeInterface) {
-      // TODO: Unfortunately, we have to postpone dynamic receiver based checks
-      // because the receiver might be cast or might come from an emulated stack
-      // frame, which means that it is unknown at this point. We perform these
-      // checks inside DoCallPolymorphic right before we do the actual invoke.
-    } else if (handle_kind == kInvokeDirect) {
-      // String constructors are a special case, they are replaced with StringFactory
-      // methods.
-      if (called_method->IsConstructor() && called_method->GetDeclaringClass()->IsStringClass()) {
-        DCHECK(handle_type->GetRType()->IsStringClass());
-        called_method = WellKnownClasses::StringInitToStringFactory(called_method);
-      }
-    } else if (handle_kind == kInvokeSuper) {
-      ObjPtr<mirror::Class> declaring_class = called_method->GetDeclaringClass();
-
-      // Note that we're not dynamically dispatching on the type of the receiver
-      // here. We use the static type of the "receiver" object that we've
-      // recorded in the method handle's type, which will be the same as the
-      // special caller that was specified at the point of lookup.
-      ObjPtr<mirror::Class> referrer_class = handle_type->GetPTypes()->Get(0);
-      if (!declaring_class->IsInterface()) {
-        ObjPtr<mirror::Class> super_class = referrer_class->GetSuperClass();
-        uint16_t vtable_index = called_method->GetMethodIndex();
-        DCHECK(super_class != nullptr);
-        DCHECK(super_class->HasVTable());
-        // Note that super_class is a super of referrer_class and called_method
-        // will always be declared by super_class (or one of its super classes).
-        DCHECK_LT(vtable_index, super_class->GetVTableLength());
-        called_method = super_class->GetVTableEntry(vtable_index, kRuntimePointerSize);
-      } else {
-        called_method = referrer_class->FindVirtualMethodForInterfaceSuper(
-            called_method, kRuntimePointerSize);
-      }
-
-      CHECK(called_method != nullptr);
-    }
-
-    if (IsInvokeTransform(handle_kind)) {
-      // There are two cases here - method handles representing regular
-      // transforms and those representing call site transforms. Method
-      // handles for call site transforms adapt their MethodType to match
-      // the call site. For these, the |callee_type| is the same as the
-      // |callsite_type|. The VarargsCollector is such a tranform, its
-      // method type depends on the call site, ie. x(a) or x(a, b), or
-      // x(a, b, c). The VarargsCollector invokes a variable arity method
-      // with the arity arguments in an array.
-      Handle<mirror::MethodType> callee_type =
-          (handle_kind == kInvokeCallSiteTransform) ? callsite_type : handle_type;
-      return DoCallTransform<is_range>(called_method,
-                                       callsite_type,
-                                       callee_type,
-                                       self,
-                                       shadow_frame,
-                                       method_handle /* receiver */,
-                                       result,
-                                       arg,
-                                       first_src_reg);
-    } else {
-      return DoCallPolymorphic<is_range>(called_method,
-                                         callsite_type,
-                                         handle_type,
-                                         self,
-                                         shadow_frame,
-                                         result,
-                                         arg,
-                                         first_src_reg,
-                                         handle_kind);
-    }
-  } else {
-    DCHECK(!is_range);
-    ArtField* field = method_handle->GetTargetField();
-    Primitive::Type field_type = field->GetTypeAsPrimitiveType();
-
-    switch (handle_kind) {
-      case kInstanceGet: {
-        ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(first_src_reg);
-        DoFieldGetForInvokePolymorphic(self, shadow_frame, obj, field, field_type, result);
-        if (!ConvertReturnValue(callsite_type, handle_type, result)) {
-          DCHECK(self->IsExceptionPending());
-          return false;
-        }
-        return true;
-      }
-      case kStaticGet: {
-        ObjPtr<mirror::Object> obj = GetAndInitializeDeclaringClass(self, field);
-        if (obj == nullptr) {
-          DCHECK(self->IsExceptionPending());
-          return false;
-        }
-        DoFieldGetForInvokePolymorphic(self, shadow_frame, obj, field, field_type, result);
-        if (!ConvertReturnValue(callsite_type, handle_type, result)) {
-          DCHECK(self->IsExceptionPending());
-          return false;
-        }
-        return true;
-      }
-      case kInstancePut: {
-        JValue value = GetFieldValue(shadow_frame, field_type, arg[1]);
-        if (!ConvertArgumentValue(callsite_type, handle_type, 1, &value)) {
-          DCHECK(self->IsExceptionPending());
-          return false;
-        }
-        ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(first_src_reg);
-        return DoFieldPutForInvokePolymorphic(self, shadow_frame, obj, field, field_type, value);
-      }
-      case kStaticPut: {
-        JValue value = GetFieldValue(shadow_frame, field_type, arg[0]);
-        if (!ConvertArgumentValue(callsite_type, handle_type, 0, &value)) {
-          DCHECK(self->IsExceptionPending());
-          return false;
-        }
-        ObjPtr<mirror::Object> obj = field->GetDeclaringClass();
-        return DoFieldPutForInvokePolymorphic(self, shadow_frame, obj, field, field_type, value);
-      }
-      default:
-        LOG(FATAL) << "Unreachable: " << handle_kind;
-        UNREACHABLE();
-    }
-  }
-}
-
-// Calculate the number of ins for a proxy or native method, where we
-// can't just look at the code item.
-static inline size_t GetInsForProxyOrNativeMethod(ArtMethod* method)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  DCHECK(method->IsNative() || method->IsProxyMethod());
-
-  method = method->GetInterfaceMethodIfProxy(kRuntimePointerSize);
-  size_t num_ins = 0;
-  // Separate accounting for the receiver, which isn't a part of the
-  // shorty.
-  if (!method->IsStatic()) {
-    ++num_ins;
-  }
-
-  uint32_t shorty_len = 0;
-  const char* shorty = method->GetShorty(&shorty_len);
-  for (size_t i = 1; i < shorty_len; ++i) {
-    const char c = shorty[i];
-    ++num_ins;
-    if (c == 'J' || c == 'D') {
-      ++num_ins;
-    }
-  }
-
-  return num_ins;
-}
-
-inline void PerformCall(Thread* self,
-                        const DexFile::CodeItem* code_item,
-                        ArtMethod* caller_method,
-                        const size_t first_dest_reg,
-                        ShadowFrame* callee_frame,
-                        JValue* result) {
-  if (LIKELY(Runtime::Current()->IsStarted())) {
-    ArtMethod* target = callee_frame->GetMethod();
-    if (ClassLinker::ShouldUseInterpreterEntrypoint(
-        target,
-        target->GetEntryPointFromQuickCompiledCode())) {
-      ArtInterpreterToInterpreterBridge(self, code_item, callee_frame, result);
-    } else {
-      ArtInterpreterToCompiledCodeBridge(
-          self, caller_method, code_item, callee_frame, result);
-    }
-  } else {
-    UnstartedRuntime::Invoke(self, code_item, callee_frame, result, first_dest_reg);
+    // Get the register arguments for the invoke.
+    inst->GetVarArgs(args, inst_data);
+    // Drop the first register which is the method handle performing the invoke.
+    memcpy(args, args + 1, sizeof(args[0]) * (Instruction::kMaxVarArgRegs - 1));
+    args[Instruction::kMaxVarArgRegs - 1] = 0;
+    return DoInvokePolymorphic<is_range, do_access_check>(self,
+                                                          invoke_method,
+                                                          shadow_frame,
+                                                          method_handle,
+                                                          callsite_type,
+                                                          args,
+                                                          args[0],
+                                                          result);
   }
 }
 
@@ -1139,217 +631,6 @@
   }
 }
 
-template <bool is_range>
-static inline bool DoCallPolymorphic(ArtMethod* called_method,
-                                     Handle<mirror::MethodType> callsite_type,
-                                     Handle<mirror::MethodType> target_type,
-                                     Thread* self,
-                                     ShadowFrame& shadow_frame,
-                                     JValue* result,
-                                     uint32_t (&arg)[Instruction::kMaxVarArgRegs],
-                                     uint32_t first_src_reg,
-                                     const MethodHandleKind handle_kind) {
-  // Compute method information.
-  const DexFile::CodeItem* code_item = called_method->GetCodeItem();
-
-  // Number of registers for the callee's call frame. Note that for non-exact
-  // invokes, we always derive this information from the callee method. We
-  // cannot guarantee during verification that the number of registers encoded
-  // in the invoke is equal to the number of ins for the callee. This is because
-  // some transformations (such as boxing a long -> Long or wideining an
-  // int -> long will change that number.
-  uint16_t num_regs;
-  size_t num_input_regs;
-  size_t first_dest_reg;
-  if (LIKELY(code_item != nullptr)) {
-    num_regs = code_item->registers_size_;
-    first_dest_reg = num_regs - code_item->ins_size_;
-    num_input_regs = code_item->ins_size_;
-    // Parameter registers go at the end of the shadow frame.
-    DCHECK_NE(first_dest_reg, (size_t)-1);
-  } else {
-    // No local regs for proxy and native methods.
-    DCHECK(called_method->IsNative() || called_method->IsProxyMethod());
-    num_regs = num_input_regs = GetInsForProxyOrNativeMethod(called_method);
-    first_dest_reg = 0;
-  }
-
-  // Allocate shadow frame on the stack.
-  ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr =
-      CREATE_SHADOW_FRAME(num_regs, &shadow_frame, called_method, /* dex pc */ 0);
-  ShadowFrame* new_shadow_frame = shadow_frame_unique_ptr.get();
-
-  // Whether this polymorphic invoke was issued by a transformer method.
-  bool is_caller_transformer = false;
-  // Thread might be suspended during PerformArgumentConversions due to the
-  // allocations performed during boxing.
-  {
-    ScopedStackedShadowFramePusher pusher(
-        self, new_shadow_frame, StackedShadowFrameType::kShadowFrameUnderConstruction);
-    if (callsite_type->IsExactMatch(target_type.Get())) {
-      // This is an exact invoke, we can take the fast path of just copying all
-      // registers without performing any argument conversions.
-      CopyRegisters<is_range>(shadow_frame,
-                              new_shadow_frame,
-                              arg,
-                              first_src_reg,
-                              first_dest_reg,
-                              num_input_regs);
-    } else {
-      // This includes the case where we're entering this invoke-polymorphic
-      // from a transformer method. In that case, the callsite_type will contain
-      // a single argument of type dalvik.system.EmulatedStackFrame. In that
-      // case, we'll have to unmarshal the EmulatedStackFrame into the
-      // new_shadow_frame and perform argument conversions on it.
-      if (IsCallerTransformer(callsite_type)) {
-        is_caller_transformer = true;
-        // The emulated stack frame is the first and only argument when we're coming
-        // through from a transformer.
-        ObjPtr<mirror::EmulatedStackFrame> emulated_stack_frame(
-            reinterpret_cast<mirror::EmulatedStackFrame*>(
-                shadow_frame.GetVRegReference(first_src_reg)));
-        if (!emulated_stack_frame->WriteToShadowFrame(self,
-                                                      target_type,
-                                                      first_dest_reg,
-                                                      new_shadow_frame)) {
-          DCHECK(self->IsExceptionPending());
-          result->SetL(0);
-          return false;
-        }
-      } else if (!ConvertAndCopyArgumentsFromCallerFrame<is_range>(self,
-                                                                   callsite_type,
-                                                                   target_type,
-                                                                   shadow_frame,
-                                                                   first_src_reg,
-                                                                   first_dest_reg,
-                                                                   arg,
-                                                                   new_shadow_frame)) {
-        DCHECK(self->IsExceptionPending());
-        result->SetL(0);
-        return false;
-      }
-    }
-  }
-
-  // See TODO in DoInvokePolymorphic : We need to perform this dynamic, receiver
-  // based dispatch right before we perform the actual call, because the
-  // receiver isn't known very early.
-  if (handle_kind == kInvokeVirtual || handle_kind == kInvokeInterface) {
-    ObjPtr<mirror::Object> receiver(new_shadow_frame->GetVRegReference(first_dest_reg));
-    ObjPtr<mirror::Class> declaring_class(called_method->GetDeclaringClass());
-    // Verify that _vRegC is an object reference and of the type expected by
-    // the receiver.
-    if (!VerifyObjectIsClass(receiver, declaring_class)) {
-      DCHECK(self->IsExceptionPending());
-      return false;
-    }
-
-    called_method = receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(
-        called_method, kRuntimePointerSize);
-  }
-
-  PerformCall(self, code_item, shadow_frame.GetMethod(), first_dest_reg, new_shadow_frame, result);
-  if (self->IsExceptionPending()) {
-    return false;
-  }
-
-  // If the caller of this signature polymorphic method was a transformer,
-  // we need to copy the result back out to the emulated stack frame.
-  if (is_caller_transformer) {
-    StackHandleScope<2> hs(self);
-    Handle<mirror::EmulatedStackFrame> emulated_stack_frame(
-        hs.NewHandle(reinterpret_cast<mirror::EmulatedStackFrame*>(
-            shadow_frame.GetVRegReference(first_src_reg))));
-    Handle<mirror::MethodType> emulated_stack_type(hs.NewHandle(emulated_stack_frame->GetType()));
-    JValue local_result;
-    local_result.SetJ(result->GetJ());
-
-    if (ConvertReturnValue(emulated_stack_type, target_type, &local_result)) {
-      emulated_stack_frame->SetReturnValue(self, local_result);
-      return true;
-    } else {
-      DCHECK(self->IsExceptionPending());
-      return false;
-    }
-  } else {
-    return ConvertReturnValue(callsite_type, target_type, result);
-  }
-}
-
-template <bool is_range>
-static inline bool DoCallTransform(ArtMethod* called_method,
-                                   Handle<mirror::MethodType> callsite_type,
-                                   Handle<mirror::MethodType> callee_type,
-                                   Thread* self,
-                                   ShadowFrame& shadow_frame,
-                                   Handle<mirror::MethodHandleImpl> receiver,
-                                   JValue* result,
-                                   uint32_t (&arg)[Instruction::kMaxVarArgRegs],
-                                   uint32_t first_src_reg) {
-  // This can be fixed to two, because the method we're calling here
-  // (MethodHandle.transformInternal) doesn't have any locals and the signature
-  // is known :
-  //
-  // private MethodHandle.transformInternal(EmulatedStackFrame sf);
-  //
-  // This means we need only two vregs :
-  // - One for the receiver object.
-  // - One for the only method argument (an EmulatedStackFrame).
-  static constexpr size_t kNumRegsForTransform = 2;
-
-  const DexFile::CodeItem* code_item = called_method->GetCodeItem();
-  DCHECK(code_item != nullptr);
-  DCHECK_EQ(kNumRegsForTransform, code_item->registers_size_);
-  DCHECK_EQ(kNumRegsForTransform, code_item->ins_size_);
-
-  ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr =
-      CREATE_SHADOW_FRAME(kNumRegsForTransform, &shadow_frame, called_method, /* dex pc */ 0);
-  ShadowFrame* new_shadow_frame = shadow_frame_unique_ptr.get();
-
-  StackHandleScope<1> hs(self);
-  MutableHandle<mirror::EmulatedStackFrame> sf(hs.NewHandle<mirror::EmulatedStackFrame>(nullptr));
-  if (IsCallerTransformer(callsite_type)) {
-    // If we're entering this transformer from another transformer, we can pass
-    // through the handle directly to the callee, instead of having to
-    // instantiate a new stack frame based on the shadow frame.
-    sf.Assign(reinterpret_cast<mirror::EmulatedStackFrame*>(
-        shadow_frame.GetVRegReference(first_src_reg)));
-  } else {
-    sf.Assign(mirror::EmulatedStackFrame::CreateFromShadowFrameAndArgs<is_range>(
-        self,
-        callsite_type,
-        callee_type,
-        shadow_frame,
-        first_src_reg,
-        arg));
-
-    // Something went wrong while creating the emulated stack frame, we should
-    // throw the pending exception.
-    if (sf.Get() == nullptr) {
-      DCHECK(self->IsExceptionPending());
-      return false;
-    }
-  }
-
-  new_shadow_frame->SetVRegReference(0, receiver.Get());
-  new_shadow_frame->SetVRegReference(1, sf.Get());
-
-  PerformCall(self,
-              code_item,
-              shadow_frame.GetMethod(),
-              0 /* first dest reg */,
-              new_shadow_frame,
-              result);
-  if (self->IsExceptionPending()) {
-    return false;
-  }
-
-  // If the called transformer method we called has returned a value, then we
-  // need to copy it back to |result|.
-  sf->GetReturnValue(self, result);
-  return ConvertReturnValue(callsite_type, callee_type, result);
-}
-
 template <bool is_range,
           bool do_assignability_check>
 static inline bool DoCallCommon(ArtMethod* called_method,
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index b599949..aeb438f 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -33,6 +33,7 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "class_linker-inl.h"
+#include "common_dex_operations.h"
 #include "common_throws.h"
 #include "dex_file-inl.h"
 #include "dex_instruction-inl.h"
@@ -48,6 +49,7 @@
 #include "obj_ptr.h"
 #include "stack.h"
 #include "thread.h"
+#include "unstarted_runtime.h"
 #include "well_known_classes.h"
 
 namespace art {
@@ -153,8 +155,10 @@
 
 // Performs a signature polymorphic invoke (invoke-polymorphic/invoke-polymorphic-range).
 template<bool is_range, bool do_access_check>
-bool DoInvokePolymorphic(Thread* self, ShadowFrame& shadow_frame,
-                         const Instruction* inst, uint16_t inst_data,
+bool DoInvokePolymorphic(Thread* self,
+                         ShadowFrame& shadow_frame,
+                         const Instruction* inst,
+                         uint16_t inst_data,
                          JValue* result);
 
 // Handles invoke-virtual-quick and invoke-virtual-quick-range instructions.
diff --git a/runtime/method_handles-inl.h b/runtime/method_handles-inl.h
index 1240792..08b8ad9 100644
--- a/runtime/method_handles-inl.h
+++ b/runtime/method_handles-inl.h
@@ -134,36 +134,6 @@
   return true;
 }
 
-template <bool is_range>
-bool ConvertAndCopyArgumentsFromCallerFrame(Thread* self,
-                                            Handle<mirror::MethodType> callsite_type,
-                                            Handle<mirror::MethodType> callee_type,
-                                            const ShadowFrame& caller_frame,
-                                            uint32_t first_src_reg,
-                                            uint32_t first_dest_reg,
-                                            const uint32_t (&arg)[Instruction::kMaxVarArgRegs],
-                                            ShadowFrame* callee_frame)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  ObjPtr<mirror::ObjectArray<mirror::Class>> from_types(callsite_type->GetPTypes());
-  ObjPtr<mirror::ObjectArray<mirror::Class>> to_types(callee_type->GetPTypes());
-
-  const int32_t num_method_params = from_types->GetLength();
-  if (to_types->GetLength() != num_method_params) {
-    ThrowWrongMethodTypeException(callee_type.Get(), callsite_type.Get());
-    return false;
-  }
-
-  ShadowFrameGetter<is_range> getter(first_src_reg, arg, caller_frame);
-  ShadowFrameSetter setter(callee_frame, first_dest_reg);
-
-  return PerformConversions<ShadowFrameGetter<is_range>, ShadowFrameSetter>(self,
-                                                                            callsite_type,
-                                                                            callee_type,
-                                                                            &getter,
-                                                                            &setter,
-                                                                            num_method_params);
-}
-
 }  // namespace art
 
 #endif  // ART_RUNTIME_METHOD_HANDLES_INL_H_
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index da510ce..99886e5 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -18,8 +18,12 @@
 
 #include "android-base/stringprintf.h"
 
+#include "common_dex_operations.h"
 #include "jvalue.h"
 #include "jvalue-inl.h"
+#include "mirror/emulated_stack_frame.h"
+#include "mirror/method_handle_impl.h"
+#include "mirror/method_type.h"
 #include "reflection.h"
 #include "reflection-inl.h"
 #include "well_known_classes.h"
@@ -282,4 +286,822 @@
   }
 }
 
+namespace {
+
+template <bool is_range>
+inline void CopyArgumentsFromCallerFrame(const ShadowFrame& caller_frame,
+                                         ShadowFrame* callee_frame,
+                                         const uint32_t (&args)[Instruction::kMaxVarArgRegs],
+                                         uint32_t first_arg,
+                                         const size_t first_dst_reg,
+                                         const size_t num_regs)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  for (size_t i = 0; i < num_regs; ++i) {
+    size_t dst_reg = first_dst_reg + i;
+    size_t src_reg = is_range ? (first_arg + i) : args[i];
+    // Uint required, so that sign extension does not make this wrong on 64-bit systems
+    uint32_t src_value = caller_frame.GetVReg(src_reg);
+    ObjPtr<mirror::Object> o = caller_frame.GetVRegReference<kVerifyNone>(src_reg);
+    // If both register locations contains the same value, the register probably holds a reference.
+    // Note: As an optimization, non-moving collectors leave a stale reference value
+    // in the references array even after the original vreg was overwritten to a non-reference.
+    if (src_value == reinterpret_cast<uintptr_t>(o.Ptr())) {
+      callee_frame->SetVRegReference(dst_reg, o.Ptr());
+    } else {
+      callee_frame->SetVReg(dst_reg, src_value);
+    }
+  }
+}
+
+template <bool is_range>
+inline bool ConvertAndCopyArgumentsFromCallerFrame(
+    Thread* self,
+    Handle<mirror::MethodType> callsite_type,
+    Handle<mirror::MethodType> callee_type,
+    const ShadowFrame& caller_frame,
+    const uint32_t (&args)[Instruction::kMaxVarArgRegs],
+    uint32_t first_arg,
+    uint32_t first_dst_reg,
+    ShadowFrame* callee_frame)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  ObjPtr<mirror::ObjectArray<mirror::Class>> from_types(callsite_type->GetPTypes());
+  ObjPtr<mirror::ObjectArray<mirror::Class>> to_types(callee_type->GetPTypes());
+
+  const int32_t num_method_params = from_types->GetLength();
+  if (to_types->GetLength() != num_method_params) {
+    ThrowWrongMethodTypeException(callee_type.Get(), callsite_type.Get());
+    return false;
+  }
+
+  ShadowFrameGetter<is_range> getter(first_arg, args, caller_frame);
+  ShadowFrameSetter setter(callee_frame, first_dst_reg);
+
+  return PerformConversions<ShadowFrameGetter<is_range>, ShadowFrameSetter>(self,
+                                                                            callsite_type,
+                                                                            callee_type,
+                                                                            &getter,
+                                                                            &setter,
+                                                                            num_method_params);
+}
+
+inline bool IsMethodHandleInvokeExact(const ArtMethod* const method) {
+  if (method == jni::DecodeArtMethod(WellKnownClasses::java_lang_invoke_MethodHandle_invokeExact)) {
+    return true;
+  } else {
+    DCHECK_EQ(method, jni::DecodeArtMethod(WellKnownClasses::java_lang_invoke_MethodHandle_invoke));
+    return false;
+  }
+}
+
+inline bool IsInvoke(const mirror::MethodHandle::Kind handle_kind) {
+  return handle_kind <= mirror::MethodHandle::Kind::kLastInvokeKind;
+}
+
+inline bool IsInvokeTransform(const mirror::MethodHandle::Kind handle_kind) {
+  return (handle_kind == mirror::MethodHandle::Kind::kInvokeTransform
+          || handle_kind == mirror::MethodHandle::Kind::kInvokeCallSiteTransform);
+}
+
+inline bool IsFieldAccess(mirror::MethodHandle::Kind handle_kind) {
+  return (handle_kind >= mirror::MethodHandle::Kind::kFirstAccessorKind
+          && handle_kind <= mirror::MethodHandle::Kind::kLastAccessorKind);
+}
+
+// Calculate the number of ins for a proxy or native method, where we
+// can't just look at the code item.
+static inline size_t GetInsForProxyOrNativeMethod(ArtMethod* method)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  DCHECK(method->IsNative() || method->IsProxyMethod());
+
+  method = method->GetInterfaceMethodIfProxy(kRuntimePointerSize);
+  size_t num_ins = 0;
+  // Separate accounting for the receiver, which isn't a part of the
+  // shorty.
+  if (!method->IsStatic()) {
+    ++num_ins;
+  }
+
+  uint32_t shorty_len = 0;
+  const char* shorty = method->GetShorty(&shorty_len);
+  for (size_t i = 1; i < shorty_len; ++i) {
+    const char c = shorty[i];
+    ++num_ins;
+    if (c == 'J' || c == 'D') {
+      ++num_ins;
+    }
+  }
+
+  return num_ins;
+}
+
+// Returns true iff. the callsite type for a polymorphic invoke is transformer
+// like, i.e that it has a single input argument whose type is
+// dalvik.system.EmulatedStackFrame.
+static inline bool IsCallerTransformer(Handle<mirror::MethodType> callsite_type)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  ObjPtr<mirror::ObjectArray<mirror::Class>> param_types(callsite_type->GetPTypes());
+  if (param_types->GetLength() == 1) {
+    ObjPtr<mirror::Class> param(param_types->GetWithoutChecks(0));
+    return param == WellKnownClasses::ToClass(WellKnownClasses::dalvik_system_EmulatedStackFrame);
+  }
+
+  return false;
+}
+
+template <bool is_range>
+static inline bool DoCallPolymorphic(ArtMethod* called_method,
+                                     Handle<mirror::MethodType> callsite_type,
+                                     Handle<mirror::MethodType> target_type,
+                                     Thread* self,
+                                     ShadowFrame& shadow_frame,
+                                     const uint32_t (&args)[Instruction::kMaxVarArgRegs],
+                                     uint32_t first_arg,
+                                     JValue* result,
+                                     const mirror::MethodHandle::Kind handle_kind)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  // Compute method information.
+  const DexFile::CodeItem* code_item = called_method->GetCodeItem();
+
+  // Number of registers for the callee's call frame. Note that for non-exact
+  // invokes, we always derive this information from the callee method. We
+  // cannot guarantee during verification that the number of registers encoded
+  // in the invoke is equal to the number of ins for the callee. This is because
+  // some transformations (such as boxing a long -> Long or wideining an
+  // int -> long will change that number.
+  uint16_t num_regs;
+  size_t num_input_regs;
+  size_t first_dest_reg;
+  if (LIKELY(code_item != nullptr)) {
+    num_regs = code_item->registers_size_;
+    first_dest_reg = num_regs - code_item->ins_size_;
+    num_input_regs = code_item->ins_size_;
+    // Parameter registers go at the end of the shadow frame.
+    DCHECK_NE(first_dest_reg, (size_t)-1);
+  } else {
+    // No local regs for proxy and native methods.
+    DCHECK(called_method->IsNative() || called_method->IsProxyMethod());
+    num_regs = num_input_regs = GetInsForProxyOrNativeMethod(called_method);
+    first_dest_reg = 0;
+  }
+
+  // Allocate shadow frame on the stack.
+  ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr =
+      CREATE_SHADOW_FRAME(num_regs, &shadow_frame, called_method, /* dex pc */ 0);
+  ShadowFrame* new_shadow_frame = shadow_frame_unique_ptr.get();
+
+  // Whether this polymorphic invoke was issued by a transformer method.
+  bool is_caller_transformer = false;
+  // Thread might be suspended during PerformArgumentConversions due to the
+  // allocations performed during boxing.
+  {
+    ScopedStackedShadowFramePusher pusher(
+        self, new_shadow_frame, StackedShadowFrameType::kShadowFrameUnderConstruction);
+    if (callsite_type->IsExactMatch(target_type.Get())) {
+      // This is an exact invoke, we can take the fast path of just copying all
+      // registers without performing any argument conversions.
+      CopyArgumentsFromCallerFrame<is_range>(shadow_frame,
+                                             new_shadow_frame,
+                                             args,
+                                             first_arg,
+                                             first_dest_reg,
+                                             num_input_regs);
+    } else {
+      // This includes the case where we're entering this invoke-polymorphic
+      // from a transformer method. In that case, the callsite_type will contain
+      // a single argument of type dalvik.system.EmulatedStackFrame. In that
+      // case, we'll have to unmarshal the EmulatedStackFrame into the
+      // new_shadow_frame and perform argument conversions on it.
+      if (IsCallerTransformer(callsite_type)) {
+        is_caller_transformer = true;
+        // The emulated stack frame is the first and only argument when we're coming
+        // through from a transformer.
+        size_t first_arg_register = (is_range) ? first_arg : args[0];
+        ObjPtr<mirror::EmulatedStackFrame> emulated_stack_frame(
+            reinterpret_cast<mirror::EmulatedStackFrame*>(
+                shadow_frame.GetVRegReference(first_arg_register)));
+        if (!emulated_stack_frame->WriteToShadowFrame(self,
+                                                      target_type,
+                                                      first_dest_reg,
+                                                      new_shadow_frame)) {
+          DCHECK(self->IsExceptionPending());
+          result->SetL(0);
+          return false;
+        }
+      } else if (!ConvertAndCopyArgumentsFromCallerFrame<is_range>(self,
+                                                                   callsite_type,
+                                                                   target_type,
+                                                                   shadow_frame,
+                                                                   args,
+                                                                   first_arg,
+                                                                   first_dest_reg,
+                                                                   new_shadow_frame)) {
+        DCHECK(self->IsExceptionPending());
+        result->SetL(0);
+        return false;
+      }
+    }
+  }
+
+  // See TODO in DoInvokePolymorphic : We need to perform this dynamic, receiver
+  // based dispatch right before we perform the actual call, because the
+  // receiver isn't known very early.
+  if (handle_kind == mirror::MethodHandle::Kind::kInvokeVirtual ||
+      handle_kind == mirror::MethodHandle::Kind::kInvokeInterface) {
+    ObjPtr<mirror::Object> receiver(new_shadow_frame->GetVRegReference(first_dest_reg));
+    ObjPtr<mirror::Class> declaring_class(called_method->GetDeclaringClass());
+    // Verify that _vRegC is an object reference and of the type expected by
+    // the receiver.
+    if (!VerifyObjectIsClass(receiver, declaring_class)) {
+      DCHECK(self->IsExceptionPending());
+      return false;
+    }
+
+    called_method = receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(
+        called_method, kRuntimePointerSize);
+  }
+
+  PerformCall(self, code_item, shadow_frame.GetMethod(), first_dest_reg, new_shadow_frame, result);
+  if (self->IsExceptionPending()) {
+    return false;
+  }
+
+  // If the caller of this signature polymorphic method was a transformer,
+  // we need to copy the result back out to the emulated stack frame.
+  if (is_caller_transformer) {
+    StackHandleScope<2> hs(self);
+    size_t first_callee_register = is_range ? (first_arg) : args[0];
+    Handle<mirror::EmulatedStackFrame> emulated_stack_frame(
+        hs.NewHandle(reinterpret_cast<mirror::EmulatedStackFrame*>(
+            shadow_frame.GetVRegReference(first_callee_register))));
+    Handle<mirror::MethodType> emulated_stack_type(hs.NewHandle(emulated_stack_frame->GetType()));
+    JValue local_result;
+    local_result.SetJ(result->GetJ());
+
+    if (ConvertReturnValue(emulated_stack_type, target_type, &local_result)) {
+      emulated_stack_frame->SetReturnValue(self, local_result);
+      return true;
+    } else {
+      DCHECK(self->IsExceptionPending());
+      return false;
+    }
+  } else {
+    return ConvertReturnValue(callsite_type, target_type, result);
+  }
+}
+
+template <bool is_range>
+static inline bool DoCallTransform(ArtMethod* called_method,
+                                   Handle<mirror::MethodType> callsite_type,
+                                   Handle<mirror::MethodType> callee_type,
+                                   Thread* self,
+                                   ShadowFrame& shadow_frame,
+                                   Handle<mirror::MethodHandleImpl> receiver,
+                                   const uint32_t (&args)[Instruction::kMaxVarArgRegs],
+                                   uint32_t first_arg,
+                                   JValue* result)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  // This can be fixed to two, because the method we're calling here
+  // (MethodHandle.transformInternal) doesn't have any locals and the signature
+  // is known :
+  //
+  // private MethodHandle.transformInternal(EmulatedStackFrame sf);
+  //
+  // This means we need only two vregs :
+  // - One for the receiver object.
+  // - One for the only method argument (an EmulatedStackFrame).
+  static constexpr size_t kNumRegsForTransform = 2;
+
+  const DexFile::CodeItem* code_item = called_method->GetCodeItem();
+  DCHECK(code_item != nullptr);
+  DCHECK_EQ(kNumRegsForTransform, code_item->registers_size_);
+  DCHECK_EQ(kNumRegsForTransform, code_item->ins_size_);
+
+  ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr =
+      CREATE_SHADOW_FRAME(kNumRegsForTransform, &shadow_frame, called_method, /* dex pc */ 0);
+  ShadowFrame* new_shadow_frame = shadow_frame_unique_ptr.get();
+
+  StackHandleScope<1> hs(self);
+  MutableHandle<mirror::EmulatedStackFrame> sf(hs.NewHandle<mirror::EmulatedStackFrame>(nullptr));
+  if (IsCallerTransformer(callsite_type)) {
+    // If we're entering this transformer from another transformer, we can pass
+    // through the handle directly to the callee, instead of having to
+    // instantiate a new stack frame based on the shadow frame.
+    size_t first_callee_register = is_range ? first_arg : args[0];
+    sf.Assign(reinterpret_cast<mirror::EmulatedStackFrame*>(
+        shadow_frame.GetVRegReference(first_callee_register)));
+  } else {
+    sf.Assign(mirror::EmulatedStackFrame::CreateFromShadowFrameAndArgs<is_range>(self,
+                                                                                 callsite_type,
+                                                                                 callee_type,
+                                                                                 shadow_frame,
+                                                                                 first_arg,
+                                                                                 args));
+
+    // Something went wrong while creating the emulated stack frame, we should
+    // throw the pending exception.
+    if (sf.Get() == nullptr) {
+      DCHECK(self->IsExceptionPending());
+      return false;
+    }
+  }
+
+  new_shadow_frame->SetVRegReference(0, receiver.Get());
+  new_shadow_frame->SetVRegReference(1, sf.Get());
+
+  PerformCall(self,
+              code_item,
+              shadow_frame.GetMethod(),
+              0 /* first destination register */,
+              new_shadow_frame,
+              result);
+  if (self->IsExceptionPending()) {
+    return false;
+  }
+
+  // If the called transformer method we called has returned a value, then we
+  // need to copy it back to |result|.
+  sf->GetReturnValue(self, result);
+  return ConvertReturnValue(callsite_type, callee_type, result);
+}
+
+inline static ObjPtr<mirror::Class> GetAndInitializeDeclaringClass(Thread* self, ArtField* field)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  // Method handle invocations on static fields should ensure class is
+  // initialized. This usually happens when an instance is constructed
+  // or class members referenced, but this is not guaranteed when
+  // looking up method handles.
+  ObjPtr<mirror::Class> klass = field->GetDeclaringClass();
+  if (UNLIKELY(!klass->IsInitialized())) {
+    StackHandleScope<1> hs(self);
+    HandleWrapperObjPtr<mirror::Class> h(hs.NewHandleWrapper(&klass));
+    if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(self, h, true, true)) {
+      DCHECK(self->IsExceptionPending());
+      return nullptr;
+    }
+  }
+  return klass;
+}
+
+template <bool is_range>
+bool DoInvokePolymorphicUnchecked(Thread* self,
+                                  ShadowFrame& shadow_frame,
+                                  Handle<mirror::MethodHandleImpl> method_handle,
+                                  Handle<mirror::MethodType> callsite_type,
+                                  const uint32_t (&args)[Instruction::kMaxVarArgRegs],
+                                  uint32_t first_arg,
+                                  JValue* result)
+  REQUIRES_SHARED(Locks::mutator_lock_) {
+  StackHandleScope<1> hs(self);
+  Handle<mirror::MethodType> handle_type(hs.NewHandle(method_handle->GetMethodType()));
+  const mirror::MethodHandle::Kind handle_kind = method_handle->GetHandleKind();
+  if (IsInvoke(handle_kind)) {
+    // Get the method we're actually invoking along with the kind of
+    // invoke that is desired. We don't need to perform access checks at this
+    // point because they would have been performed on our behalf at the point
+    // of creation of the method handle.
+    ArtMethod* called_method = method_handle->GetTargetMethod();
+    CHECK(called_method != nullptr);
+
+    if (handle_kind == mirror::MethodHandle::Kind::kInvokeVirtual ||
+        handle_kind == mirror::MethodHandle::Kind::kInvokeInterface) {
+      // TODO: Unfortunately, we have to postpone dynamic receiver based checks
+      // because the receiver might be cast or might come from an emulated stack
+      // frame, which means that it is unknown at this point. We perform these
+      // checks inside DoCallPolymorphic right before we do the actual invoke.
+    } else if (handle_kind == mirror::MethodHandle::Kind::kInvokeDirect) {
+      // String constructors are a special case, they are replaced with StringFactory
+      // methods.
+      if (called_method->IsConstructor() && called_method->GetDeclaringClass()->IsStringClass()) {
+        DCHECK(handle_type->GetRType()->IsStringClass());
+        called_method = WellKnownClasses::StringInitToStringFactory(called_method);
+      }
+    } else if (handle_kind == mirror::MethodHandle::Kind::kInvokeSuper) {
+      ObjPtr<mirror::Class> declaring_class = called_method->GetDeclaringClass();
+
+      // Note that we're not dynamically dispatching on the type of the receiver
+      // here. We use the static type of the "receiver" object that we've
+      // recorded in the method handle's type, which will be the same as the
+      // special caller that was specified at the point of lookup.
+      ObjPtr<mirror::Class> referrer_class = handle_type->GetPTypes()->Get(0);
+      if (!declaring_class->IsInterface()) {
+        ObjPtr<mirror::Class> super_class = referrer_class->GetSuperClass();
+        uint16_t vtable_index = called_method->GetMethodIndex();
+        DCHECK(super_class != nullptr);
+        DCHECK(super_class->HasVTable());
+        // Note that super_class is a super of referrer_class and called_method
+        // will always be declared by super_class (or one of its super classes).
+        DCHECK_LT(vtable_index, super_class->GetVTableLength());
+        called_method = super_class->GetVTableEntry(vtable_index, kRuntimePointerSize);
+      } else {
+        called_method = referrer_class->FindVirtualMethodForInterfaceSuper(
+            called_method, kRuntimePointerSize);
+      }
+      CHECK(called_method != nullptr);
+    }
+    if (IsInvokeTransform(handle_kind)) {
+      // There are two cases here - method handles representing regular
+      // transforms and those representing call site transforms. Method
+      // handles for call site transforms adapt their MethodType to match
+      // the call site. For these, the |callee_type| is the same as the
+      // |callsite_type|. The VarargsCollector is such a tranform, its
+      // method type depends on the call site, ie. x(a) or x(a, b), or
+      // x(a, b, c). The VarargsCollector invokes a variable arity method
+      // with the arity arguments in an array.
+      Handle<mirror::MethodType> callee_type =
+          (handle_kind == mirror::MethodHandle::Kind::kInvokeCallSiteTransform) ? callsite_type
+          : handle_type;
+      return DoCallTransform<is_range>(called_method,
+                                       callsite_type,
+                                       callee_type,
+                                       self,
+                                       shadow_frame,
+                                       method_handle /* receiver */,
+                                       args,
+                                       first_arg,
+                                       result);
+
+    } else {
+      return DoCallPolymorphic<is_range>(called_method,
+                                         callsite_type,
+                                         handle_type,
+                                         self,
+                                         shadow_frame,
+                                         args,
+                                         first_arg,
+                                         result,
+                                         handle_kind);
+    }
+  } else {
+    LOG(FATAL) << "Unreachable: " << handle_kind;
+    UNREACHABLE();
+  }
+}
+
+// Helper for getters in invoke-polymorphic.
+inline static void DoFieldGetForInvokePolymorphic(Thread* self,
+                                                  const ShadowFrame& shadow_frame,
+                                                  ObjPtr<mirror::Object>& obj,
+                                                  ArtField* field,
+                                                  Primitive::Type field_type,
+                                                  JValue* result)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  switch (field_type) {
+    case Primitive::kPrimBoolean:
+      DoFieldGetCommon<Primitive::kPrimBoolean>(self, shadow_frame, obj, field, result);
+      break;
+    case Primitive::kPrimByte:
+      DoFieldGetCommon<Primitive::kPrimByte>(self, shadow_frame, obj, field, result);
+      break;
+    case Primitive::kPrimChar:
+      DoFieldGetCommon<Primitive::kPrimChar>(self, shadow_frame, obj, field, result);
+      break;
+    case Primitive::kPrimShort:
+      DoFieldGetCommon<Primitive::kPrimShort>(self, shadow_frame, obj, field, result);
+      break;
+    case Primitive::kPrimInt:
+      DoFieldGetCommon<Primitive::kPrimInt>(self, shadow_frame, obj, field, result);
+      break;
+    case Primitive::kPrimLong:
+      DoFieldGetCommon<Primitive::kPrimLong>(self, shadow_frame, obj, field, result);
+      break;
+    case Primitive::kPrimFloat:
+      DoFieldGetCommon<Primitive::kPrimInt>(self, shadow_frame, obj, field, result);
+      break;
+    case Primitive::kPrimDouble:
+      DoFieldGetCommon<Primitive::kPrimLong>(self, shadow_frame, obj, field, result);
+      break;
+    case Primitive::kPrimNot:
+      DoFieldGetCommon<Primitive::kPrimNot>(self, shadow_frame, obj, field, result);
+      break;
+    case Primitive::kPrimVoid:
+      LOG(FATAL) << "Unreachable: " << field_type;
+      UNREACHABLE();
+  }
+}
+
+// Helper for setters in invoke-polymorphic.
+template <bool do_assignability_check>
+inline bool DoFieldPutForInvokePolymorphic(Thread* self,
+                                           ShadowFrame& shadow_frame,
+                                           ObjPtr<mirror::Object>& obj,
+                                           ArtField* field,
+                                           Primitive::Type field_type,
+                                           const JValue& value)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  static const bool kTransaction = false;
+  switch (field_type) {
+    case Primitive::kPrimBoolean:
+      return DoFieldPutCommon<Primitive::kPrimBoolean, do_assignability_check, kTransaction>(
+          self, shadow_frame, obj, field, value);
+    case Primitive::kPrimByte:
+      return DoFieldPutCommon<Primitive::kPrimByte, do_assignability_check, kTransaction>(
+          self, shadow_frame, obj, field, value);
+    case Primitive::kPrimChar:
+      return DoFieldPutCommon<Primitive::kPrimChar, do_assignability_check, kTransaction>(
+          self, shadow_frame, obj, field, value);
+    case Primitive::kPrimShort:
+      return DoFieldPutCommon<Primitive::kPrimShort, do_assignability_check, kTransaction>(
+          self, shadow_frame, obj, field, value);
+    case Primitive::kPrimInt:
+    case Primitive::kPrimFloat:
+      return DoFieldPutCommon<Primitive::kPrimInt, do_assignability_check, kTransaction>(
+          self, shadow_frame, obj, field, value);
+    case Primitive::kPrimLong:
+    case Primitive::kPrimDouble:
+      return DoFieldPutCommon<Primitive::kPrimLong, do_assignability_check, kTransaction>(
+          self, shadow_frame, obj, field, value);
+    case Primitive::kPrimNot:
+      return DoFieldPutCommon<Primitive::kPrimNot, do_assignability_check, kTransaction>(
+          self, shadow_frame, obj, field, value);
+    case Primitive::kPrimVoid:
+      LOG(FATAL) << "Unreachable: " << field_type;
+      UNREACHABLE();
+  }
+}
+
+static JValue GetValueFromShadowFrame(const ShadowFrame& shadow_frame,
+                                      Primitive::Type field_type,
+                                      uint32_t vreg)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  JValue field_value;
+  switch (field_type) {
+    case Primitive::kPrimBoolean:
+      field_value.SetZ(static_cast<uint8_t>(shadow_frame.GetVReg(vreg)));
+      break;
+    case Primitive::kPrimByte:
+      field_value.SetB(static_cast<int8_t>(shadow_frame.GetVReg(vreg)));
+      break;
+    case Primitive::kPrimChar:
+      field_value.SetC(static_cast<uint16_t>(shadow_frame.GetVReg(vreg)));
+      break;
+    case Primitive::kPrimShort:
+      field_value.SetS(static_cast<int16_t>(shadow_frame.GetVReg(vreg)));
+      break;
+    case Primitive::kPrimInt:
+    case Primitive::kPrimFloat:
+      field_value.SetI(shadow_frame.GetVReg(vreg));
+      break;
+    case Primitive::kPrimLong:
+    case Primitive::kPrimDouble:
+      field_value.SetJ(shadow_frame.GetVRegLong(vreg));
+      break;
+    case Primitive::kPrimNot:
+      field_value.SetL(shadow_frame.GetVRegReference(vreg));
+      break;
+    case Primitive::kPrimVoid:
+      LOG(FATAL) << "Unreachable: " << field_type;
+      UNREACHABLE();
+  }
+  return field_value;
+}
+
+template <bool is_range, bool do_conversions, bool do_assignability_check>
+bool DoInvokePolymorphicFieldAccess(Thread* self,
+                                    ShadowFrame& shadow_frame,
+                                    Handle<mirror::MethodHandleImpl> method_handle,
+                                    Handle<mirror::MethodType> callsite_type,
+                                    const uint32_t (&args)[Instruction::kMaxVarArgRegs],
+                                    uint32_t first_arg,
+                                    JValue* result)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  StackHandleScope<1> hs(self);
+  Handle<mirror::MethodType> handle_type(hs.NewHandle(method_handle->GetMethodType()));
+  const mirror::MethodHandle::Kind handle_kind = method_handle->GetHandleKind();
+  ArtField* field = method_handle->GetTargetField();
+  Primitive::Type field_type = field->GetTypeAsPrimitiveType();
+
+  switch (handle_kind) {
+    case mirror::MethodHandle::kInstanceGet: {
+      size_t obj_reg = is_range ? first_arg : args[0];
+      ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(obj_reg);
+      DoFieldGetForInvokePolymorphic(self, shadow_frame, obj, field, field_type, result);
+      if (do_conversions && !ConvertReturnValue(callsite_type, handle_type, result)) {
+        DCHECK(self->IsExceptionPending());
+        return false;
+      }
+      return true;
+    }
+    case mirror::MethodHandle::kStaticGet: {
+      ObjPtr<mirror::Object> obj = GetAndInitializeDeclaringClass(self, field);
+      if (obj == nullptr) {
+        DCHECK(self->IsExceptionPending());
+        return false;
+      }
+      DoFieldGetForInvokePolymorphic(self, shadow_frame, obj, field, field_type, result);
+      if (do_conversions && !ConvertReturnValue(callsite_type, handle_type, result)) {
+        DCHECK(self->IsExceptionPending());
+        return false;
+      }
+      return true;
+    }
+    case mirror::MethodHandle::kInstancePut: {
+      size_t obj_reg = is_range ? first_arg : args[0];
+      size_t value_reg = is_range ? (first_arg + 1) : args[1];
+      JValue value = GetValueFromShadowFrame(shadow_frame, field_type, value_reg);
+      if (do_conversions && !ConvertArgumentValue(callsite_type, handle_type, 1, &value)) {
+        DCHECK(self->IsExceptionPending());
+        return false;
+      }
+      ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(obj_reg);
+      return DoFieldPutForInvokePolymorphic<do_assignability_check>(self,
+                                                                    shadow_frame,
+                                                                    obj,
+                                                                    field,
+                                                                    field_type,
+                                                                    value);
+    }
+    case mirror::MethodHandle::kStaticPut: {
+      ObjPtr<mirror::Object> obj = GetAndInitializeDeclaringClass(self, field);
+      if (obj == nullptr) {
+        DCHECK(self->IsExceptionPending());
+        return false;
+      }
+      size_t value_reg = is_range ? first_arg : args[0];
+      JValue value = GetValueFromShadowFrame(shadow_frame, field_type, value_reg);
+      if (do_conversions && !ConvertArgumentValue(callsite_type, handle_type, 0, &value)) {
+        DCHECK(self->IsExceptionPending());
+        return false;
+      }
+      return DoFieldPutForInvokePolymorphic<do_assignability_check>(self,
+                                                                    shadow_frame,
+                                                                    obj,
+                                                                    field,
+                                                                    field_type,
+                                                                    value);
+    }
+    default:
+      LOG(FATAL) << "Unreachable: " << handle_kind;
+      UNREACHABLE();
+  }
+}
+
+template <bool is_range, bool do_assignability_check>
+static inline bool DoInvokePolymorphicNonExact(Thread* self,
+                                               ShadowFrame& shadow_frame,
+                                               Handle<mirror::MethodHandleImpl> method_handle,
+                                               Handle<mirror::MethodType> callsite_type,
+                                               const uint32_t (&args)[Instruction::kMaxVarArgRegs],
+                                               uint32_t first_arg,
+                                               JValue* result)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  const mirror::MethodHandle::Kind handle_kind = method_handle->GetHandleKind();
+  ObjPtr<mirror::MethodType> handle_type(method_handle->GetMethodType());
+  CHECK(handle_type != nullptr);
+
+  if (!IsInvokeTransform(handle_kind)) {
+    if (UNLIKELY(!IsCallerTransformer(callsite_type) &&
+                 !callsite_type->IsConvertible(handle_type.Ptr()))) {
+      ThrowWrongMethodTypeException(handle_type.Ptr(), callsite_type.Get());
+      return false;
+    }
+  }
+
+  if (IsFieldAccess(handle_kind)) {
+    if (UNLIKELY(callsite_type->IsExactMatch(handle_type.Ptr()))) {
+      const bool do_convert = false;
+      return DoInvokePolymorphicFieldAccess<is_range, do_convert, do_assignability_check>(
+          self,
+          shadow_frame,
+          method_handle,
+          callsite_type,
+          args,
+          first_arg,
+          result);
+    } else {
+      const bool do_convert = true;
+      return DoInvokePolymorphicFieldAccess<is_range, do_convert, do_assignability_check>(
+          self,
+          shadow_frame,
+          method_handle,
+          callsite_type,
+          args,
+          first_arg,
+          result);
+    }
+  }
+
+  if (UNLIKELY(callsite_type->IsExactMatch(handle_type.Ptr()))) {
+    return DoInvokePolymorphicUnchecked<is_range>(self,
+                                                  shadow_frame,
+                                                  method_handle,
+                                                  callsite_type,
+                                                  args,
+                                                  first_arg,
+                                                  result);
+  } else {
+    return DoInvokePolymorphicUnchecked<is_range>(self,
+                                                  shadow_frame,
+                                                  method_handle,
+                                                  callsite_type,
+                                                  args,
+                                                  first_arg,
+                                                  result);
+  }
+}
+
+template <bool is_range, bool do_assignability_check>
+bool DoInvokePolymorphicExact(Thread* self,
+                              ShadowFrame& shadow_frame,
+                              Handle<mirror::MethodHandleImpl> method_handle,
+                              Handle<mirror::MethodType> callsite_type,
+                              const uint32_t (&args)[Instruction::kMaxVarArgRegs],
+                              uint32_t first_arg,
+                              JValue* result)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  // We need to check the nominal type of the handle in addition to the
+  // real type. The "nominal" type is present when MethodHandle.asType is
+  // called any handle, and results in the declared type of the handle
+  // changing.
+  ObjPtr<mirror::MethodType> nominal_type(method_handle->GetNominalType());
+  if (UNLIKELY(nominal_type != nullptr)) {
+    if (UNLIKELY(!callsite_type->IsExactMatch(nominal_type.Ptr()))) {
+      ThrowWrongMethodTypeException(nominal_type.Ptr(), callsite_type.Get());
+      return false;
+    }
+    return DoInvokePolymorphicNonExact<is_range, do_assignability_check>(self,
+                                                                         shadow_frame,
+                                                                         method_handle,
+                                                                         callsite_type,
+                                                                         args,
+                                                                         first_arg,
+                                                                         result);
+  }
+
+  ObjPtr<mirror::MethodType> handle_type(method_handle->GetMethodType());
+  if (UNLIKELY(!callsite_type->IsExactMatch(handle_type.Ptr()))) {
+    ThrowWrongMethodTypeException(handle_type.Ptr(), callsite_type.Get());
+    return false;
+  }
+
+  const mirror::MethodHandle::Kind handle_kind = method_handle->GetHandleKind();
+  if (IsFieldAccess(handle_kind)) {
+    const bool do_convert = false;
+    return DoInvokePolymorphicFieldAccess<is_range, do_convert, do_assignability_check>(
+        self,
+        shadow_frame,
+        method_handle,
+        callsite_type,
+        args,
+        first_arg,
+        result);
+  }
+
+  return DoInvokePolymorphicUnchecked<is_range>(self,
+                                                shadow_frame,
+                                                method_handle,
+                                                callsite_type,
+                                                args,
+                                                first_arg,
+                                                result);
+}
+
+}  // namespace
+
+template <bool is_range, bool do_assignability_check>
+bool DoInvokePolymorphic(Thread* self,
+                         ArtMethod* invoke_method,
+                         ShadowFrame& shadow_frame,
+                         Handle<mirror::MethodHandleImpl> method_handle,
+                         Handle<mirror::MethodType> callsite_type,
+                         const uint32_t (&args)[Instruction::kMaxVarArgRegs],
+                         uint32_t first_arg,
+                         JValue* result)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  if (IsMethodHandleInvokeExact(invoke_method)) {
+    return DoInvokePolymorphicExact<is_range, do_assignability_check>(self,
+                                                                      shadow_frame,
+                                                                      method_handle,
+                                                                      callsite_type,
+                                                                      args,
+                                                                      first_arg,
+                                                                      result);
+  } else {
+    return DoInvokePolymorphicNonExact<is_range, do_assignability_check>(self,
+                                                                         shadow_frame,
+                                                                         method_handle,
+                                                                         callsite_type,
+                                                                         args,
+                                                                         first_arg,
+                                                                         result);
+  }
+}
+
+#define EXPLICIT_DO_INVOKE_POLYMORPHIC_TEMPLATE_DECL(_is_range, _do_assignability_check) \
+template REQUIRES_SHARED(Locks::mutator_lock_)                                           \
+bool DoInvokePolymorphic<_is_range, _do_assignability_check>(                            \
+    Thread* self,                                                                        \
+    ArtMethod* invoke_method,                                                            \
+    ShadowFrame& shadow_frame,                                                           \
+    Handle<mirror::MethodHandleImpl> method_handle,                                      \
+    Handle<mirror::MethodType> callsite_type,                                            \
+    const uint32_t (&args)[Instruction::kMaxVarArgRegs],                                 \
+    uint32_t first_arg,                                                                  \
+    JValue* result)
+
+EXPLICIT_DO_INVOKE_POLYMORPHIC_TEMPLATE_DECL(true, true);
+EXPLICIT_DO_INVOKE_POLYMORPHIC_TEMPLATE_DECL(true, false);
+EXPLICIT_DO_INVOKE_POLYMORPHIC_TEMPLATE_DECL(false, true);
+EXPLICIT_DO_INVOKE_POLYMORPHIC_TEMPLATE_DECL(false, false);
+#undef EXPLICIT_DO_INVOKE_POLYMORPHIC_TEMPLATE_DECL
+
 }  // namespace art
diff --git a/runtime/method_handles.h b/runtime/method_handles.h
index d0a4902..734d7c7 100644
--- a/runtime/method_handles.h
+++ b/runtime/method_handles.h
@@ -23,48 +23,16 @@
 #include "handle.h"
 #include "jvalue.h"
 #include "mirror/class.h"
-#include "mirror/method_type.h"
 
 namespace art {
 
 namespace mirror {
+  class MethodHandleImpl;
   class MethodType;
-}
+}  // mirror
 
 class ShadowFrame;
 
-// Defines the behaviour of a given method handle. The behaviour
-// of a handle of a given kind is identical to the dex bytecode behaviour
-// of the equivalent instruction.
-//
-// NOTE: These must be kept in sync with the constants defined in
-// java.lang.invoke.MethodHandle.
-enum MethodHandleKind {
-  kInvokeVirtual = 0,
-  kInvokeSuper,
-  kInvokeDirect,
-  kInvokeStatic,
-  kInvokeInterface,
-  kInvokeTransform,
-  kInvokeCallSiteTransform,
-  kInstanceGet,
-  kInstancePut,
-  kStaticGet,
-  kStaticPut,
-  kLastValidKind = kStaticPut,
-  kLastInvokeKind = kInvokeCallSiteTransform
-};
-
-// Whether the given method handle kind is some variant of an invoke.
-inline bool IsInvoke(const MethodHandleKind handle_kind) {
-  return handle_kind <= kLastInvokeKind;
-}
-
-// Whether the given method handle kind is some variant of a tranform.
-inline bool IsInvokeTransform(const MethodHandleKind handle_kind) {
-  return handle_kind == kInvokeTransform || handle_kind == kInvokeCallSiteTransform;
-}
-
 // Returns true if there is a possible conversion from |from| to |to|
 // for a MethodHandle parameter.
 bool IsParameterTypeConvertible(ObjPtr<mirror::Class> from,
@@ -158,19 +126,6 @@
                         S* setter,
                         int32_t num_conversions) REQUIRES_SHARED(Locks::mutator_lock_);
 
-// A convenience wrapper around |PerformConversions|, for the case where
-// the setter and getter are both ShadowFrame based.
-template <bool is_range>
-bool ConvertAndCopyArgumentsFromCallerFrame(Thread* self,
-                                            Handle<mirror::MethodType> callsite_type,
-                                            Handle<mirror::MethodType> callee_type,
-                                            const ShadowFrame& caller_frame,
-                                            uint32_t first_src_reg,
-                                            uint32_t first_dest_reg,
-                                            const uint32_t (&arg)[Instruction::kMaxVarArgRegs],
-                                            ShadowFrame* callee_frame)
-    REQUIRES_SHARED(Locks::mutator_lock_);
-
 // A convenience class that allows for iteration through a list of
 // input argument registers |arg| for non-range invokes or a list of
 // consecutive registers starting with a given based for range
@@ -178,7 +133,8 @@
 //
 // This is used to iterate over input arguments while performing standard
 // argument conversions.
-template <bool is_range> class ShadowFrameGetter {
+template <bool is_range>
+class ShadowFrameGetter {
  public:
   ShadowFrameGetter(size_t first_src_reg,
                     const uint32_t (&arg)[Instruction::kMaxVarArgRegs],
@@ -246,6 +202,17 @@
   size_t arg_index_;
 };
 
+template <bool is_range, bool do_assignability_check>
+bool DoInvokePolymorphic(Thread* self,
+                         ArtMethod* invoke_method,
+                         ShadowFrame& shadow_frame,
+                         Handle<mirror::MethodHandleImpl> method_handle,
+                         Handle<mirror::MethodType> callsite_type,
+                         const uint32_t (&args)[Instruction::kMaxVarArgRegs],
+                         uint32_t first_arg,
+                         JValue* result)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_METHOD_HANDLES_H_
diff --git a/runtime/mirror/method_handle_impl.h b/runtime/mirror/method_handle_impl.h
index 5ea82b5..abe999a 100644
--- a/runtime/mirror/method_handle_impl.h
+++ b/runtime/mirror/method_handle_impl.h
@@ -32,6 +32,37 @@
 // C++ mirror of java.lang.invoke.MethodHandle
 class MANAGED MethodHandle : public Object {
  public:
+  // Defines the behaviour of a given method handle. The behaviour
+  // of a handle of a given kind is identical to the dex bytecode behaviour
+  // of the equivalent instruction.
+  //
+  // NOTE: These must be kept in sync with the constants defined in
+  // java.lang.invoke.MethodHandle.
+  enum Kind {
+    kInvokeVirtual = 0,
+    kInvokeSuper,
+    kInvokeDirect,
+    kInvokeStatic,
+    kInvokeInterface,
+    kInvokeTransform,
+    kInvokeCallSiteTransform,
+    kInstanceGet,
+    kInstancePut,
+    kStaticGet,
+    kStaticPut,
+    kLastValidKind = kStaticPut,
+    kFirstAccessorKind = kInstanceGet,
+    kLastAccessorKind = kStaticPut,
+    kLastInvokeKind = kInvokeCallSiteTransform
+  };
+
+  Kind GetHandleKind() REQUIRES_SHARED(Locks::mutator_lock_) {
+    const int32_t handle_kind = GetField32(OFFSET_OF_OBJECT_MEMBER(MethodHandle, handle_kind_));
+    DCHECK(handle_kind >= 0 &&
+           handle_kind <= static_cast<int32_t>(Kind::kLastValidKind));
+    return static_cast<Kind>(handle_kind);
+  }
+
   mirror::MethodType* GetMethodType() REQUIRES_SHARED(Locks::mutator_lock_) {
     return GetFieldObject<mirror::MethodType>(OFFSET_OF_OBJECT_MEMBER(MethodHandle, method_type_));
   }
@@ -50,13 +81,6 @@
         GetField64(OFFSET_OF_OBJECT_MEMBER(MethodHandle, art_field_or_method_)));
   }
 
-  MethodHandleKind GetHandleKind() REQUIRES_SHARED(Locks::mutator_lock_) {
-    const int32_t handle_kind = GetField32(OFFSET_OF_OBJECT_MEMBER(MethodHandle, handle_kind_));
-
-    DCHECK(handle_kind >= 0 && handle_kind <= MethodHandleKind::kLastValidKind);
-    return static_cast<MethodHandleKind>(handle_kind);
-  }
-
   static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_);
 
  private:
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 009170c..7b5ced1 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -52,6 +52,7 @@
 jclass WellKnownClasses::java_lang_Daemons;
 jclass WellKnownClasses::java_lang_Error;
 jclass WellKnownClasses::java_lang_ExceptionInInitializerError;
+jclass WellKnownClasses::java_lang_invoke_MethodHandle;
 jclass WellKnownClasses::java_lang_IllegalAccessError;
 jclass WellKnownClasses::java_lang_NoClassDefFoundError;
 jclass WellKnownClasses::java_lang_Object;
@@ -93,6 +94,8 @@
 jmethodID WellKnownClasses::java_lang_Double_valueOf;
 jmethodID WellKnownClasses::java_lang_Float_valueOf;
 jmethodID WellKnownClasses::java_lang_Integer_valueOf;
+jmethodID WellKnownClasses::java_lang_invoke_MethodHandle_invoke;
+jmethodID WellKnownClasses::java_lang_invoke_MethodHandle_invokeExact;
 jmethodID WellKnownClasses::java_lang_Long_valueOf;
 jmethodID WellKnownClasses::java_lang_ref_FinalizerReference_add;
 jmethodID WellKnownClasses::java_lang_ref_ReferenceQueue_add;
@@ -288,6 +291,7 @@
   java_lang_Error = CacheClass(env, "java/lang/Error");
   java_lang_ExceptionInInitializerError = CacheClass(env, "java/lang/ExceptionInInitializerError");
   java_lang_IllegalAccessError = CacheClass(env, "java/lang/IllegalAccessError");
+  java_lang_invoke_MethodHandle = CacheClass(env, "java/lang/invoke/MethodHandle");
   java_lang_NoClassDefFoundError = CacheClass(env, "java/lang/NoClassDefFoundError");
   java_lang_reflect_Constructor = CacheClass(env, "java/lang/reflect/Constructor");
   java_lang_reflect_Executable = CacheClass(env, "java/lang/reflect/Executable");
@@ -321,7 +325,12 @@
   java_lang_Daemons_requestHeapTrim = CacheMethod(env, java_lang_Daemons, true, "requestHeapTrim", "()V");
   java_lang_Daemons_start = CacheMethod(env, java_lang_Daemons, true, "start", "()V");
   java_lang_Daemons_stop = CacheMethod(env, java_lang_Daemons, true, "stop", "()V");
-
+  java_lang_invoke_MethodHandle_invoke =
+      CacheMethod(env, java_lang_invoke_MethodHandle, false,
+                  "invoke", "([Ljava/lang/Object;)Ljava/lang/Object;");
+  java_lang_invoke_MethodHandle_invokeExact =
+      CacheMethod(env, java_lang_invoke_MethodHandle, false,
+                  "invokeExact", "([Ljava/lang/Object;)Ljava/lang/Object;");
   ScopedLocalRef<jclass> java_lang_ref_FinalizerReference(env, env->FindClass("java/lang/ref/FinalizerReference"));
   java_lang_ref_FinalizerReference_add = CacheMethod(env, java_lang_ref_FinalizerReference.get(), true, "add", "(Ljava/lang/Object;)V");
   ScopedLocalRef<jclass> java_lang_ref_ReferenceQueue(env, env->FindClass("java/lang/ref/ReferenceQueue"));
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index 227996a..371be61 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -63,6 +63,7 @@
   static jclass java_lang_Error;
   static jclass java_lang_ExceptionInInitializerError;
   static jclass java_lang_IllegalAccessError;
+  static jclass java_lang_invoke_MethodHandle;
   static jclass java_lang_NoClassDefFoundError;
   static jclass java_lang_Object;
   static jclass java_lang_OutOfMemoryError;
@@ -103,6 +104,8 @@
   static jmethodID java_lang_Double_valueOf;
   static jmethodID java_lang_Float_valueOf;
   static jmethodID java_lang_Integer_valueOf;
+  static jmethodID java_lang_invoke_MethodHandle_invoke;
+  static jmethodID java_lang_invoke_MethodHandle_invokeExact;
   static jmethodID java_lang_Long_valueOf;
   static jmethodID java_lang_ref_FinalizerReference_add;
   static jmethodID java_lang_ref_ReferenceQueue_add;