Use the thread local cache in interpreter / unresolved entrypoints

Refactor and cleanup how we lookup the method to invoke. Also remove old
mterp related code.

Test: test.py
Change-Id: I135b38c45612c5266b51c0eb39a67ac988541ae7
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 8e77b43..172d857 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -173,7 +173,6 @@
         "interpreter/interpreter.cc",
         "interpreter/interpreter_cache.cc",
         "interpreter/interpreter_common.cc",
-        "interpreter/interpreter_intrinsics.cc",
         "interpreter/interpreter_switch_impl0.cc",
         "interpreter/interpreter_switch_impl1.cc",
         "interpreter/interpreter_switch_impl2.cc",
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index 4ee1013..b454d49 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -486,6 +486,131 @@
 #undef EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL
 #undef EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL
 
+static inline bool IsStringInit(const DexFile* dex_file, uint32_t method_idx)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  const dex::MethodId& method_id = dex_file->GetMethodId(method_idx);
+  const char* class_name = dex_file->StringByTypeIdx(method_id.class_idx_);
+  const char* method_name = dex_file->GetMethodName(method_id);
+  // Instead of calling ResolveMethod() which has suspend point and can trigger
+  // GC, look up the method symbolically.
+  // Compare method's class name and method name against string init.
+  // It's ok since it's not allowed to create your own java/lang/String.
+  // TODO: verify that assumption.
+  if ((strcmp(class_name, "Ljava/lang/String;") == 0) &&
+      (strcmp(method_name, "<init>") == 0)) {
+    return true;
+  }
+  return false;
+}
+
+static inline bool IsStringInit(const Instruction& instr, ArtMethod* caller)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  if (instr.Opcode() == Instruction::INVOKE_DIRECT ||
+      instr.Opcode() == Instruction::INVOKE_DIRECT_RANGE) {
+    uint16_t callee_method_idx = (instr.Opcode() == Instruction::INVOKE_DIRECT_RANGE) ?
+        instr.VRegB_3rc() : instr.VRegB_35c();
+    return IsStringInit(caller->GetDexFile(), callee_method_idx);
+  }
+  return false;
+}
+
+extern "C" size_t NterpGetMethod(Thread* self, ArtMethod* caller, const uint16_t* dex_pc_ptr);
+
+template <InvokeType type>
+ArtMethod* FindMethodToCall(Thread* self,
+                            ArtMethod* caller,
+                            ObjPtr<mirror::Object>* this_object,
+                            const Instruction& inst,
+                            /*out*/ bool* string_init)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
+
+  // Try to find the method in thread-local cache.
+  size_t tls_value = 0u;
+  if (!self->GetInterpreterCache()->Get(self, &inst, &tls_value)) {
+    DCHECK(!self->IsExceptionPending());
+    // NterpGetMethod can suspend, so save this_object.
+    StackHandleScope<1> hs(self);
+    HandleWrapperObjPtr<mirror::Object> h_this(hs.NewHandleWrapper(this_object));
+    tls_value = NterpGetMethod(self, caller, reinterpret_cast<const uint16_t*>(&inst));
+    if (self->IsExceptionPending()) {
+      return nullptr;
+    }
+  }
+
+  if (type != kStatic && UNLIKELY((*this_object) == nullptr)) {
+    if (UNLIKELY(IsStringInit(inst, caller))) {
+      // Hack for String init:
+      //
+      // We assume that the input of String.<init> in verified code is always
+      // an uninitialized reference. If it is a null constant, it must have been
+      // optimized out by the compiler and we arrive here after deoptimization.
+      // Do not throw NullPointerException.
+    } else {
+      // Maintain interpreter-like semantics where NullPointerException is thrown
+      // after potential NoSuchMethodError from class linker.
+      const uint32_t method_idx = inst.VRegB();
+      ThrowNullPointerExceptionForMethodAccess(method_idx, type);
+      return nullptr;
+    }
+  }
+
+  static constexpr size_t kStringInitMethodFlag = 0b1;
+  static constexpr size_t kInvokeInterfaceOnObjectMethodFlag = 0b1;
+  static constexpr size_t kDefaultMethodFlag = 0b10;
+  static constexpr size_t kMethodMask = ~0b11;
+
+  ArtMethod* called_method = nullptr;
+  switch (type) {
+    case kDirect:
+    case kSuper:
+    case kStatic:
+      // Note: for the interpreter, the String.<init> special casing for invocation is handled
+      // in DoCallCommon.
+      *string_init = ((tls_value & kStringInitMethodFlag) != 0);
+      DCHECK_EQ(*string_init, IsStringInit(inst, caller));
+      called_method = reinterpret_cast<ArtMethod*>(tls_value & kMethodMask);
+      break;
+    case kInterface:
+      if ((tls_value & kInvokeInterfaceOnObjectMethodFlag) != 0) {
+        // invokeinterface on a j.l.Object method.
+        uint16_t method_index = tls_value >> 16;
+        called_method = (*this_object)->GetClass()->GetVTableEntry(method_index, pointer_size);
+      } else {
+        ArtMethod* interface_method = reinterpret_cast<ArtMethod*>(tls_value & kMethodMask);
+        if ((tls_value & kDefaultMethodFlag) != 0) {
+          // Default non-abstract method.
+          called_method = (*this_object)->GetClass()->GetImt(pointer_size)->Get(
+              interface_method->GetMethodIndex(), pointer_size);
+        } else {
+          // Regular abstract interface method.
+          called_method = (*this_object)->GetClass()->GetImt(pointer_size)->Get(
+              interface_method->GetImtIndex(), pointer_size);
+        }
+        if (called_method->IsRuntimeMethod()) {
+          called_method = (*this_object)->GetClass()->FindVirtualMethodForInterface(
+              interface_method, pointer_size);
+          if (UNLIKELY(called_method == nullptr)) {
+            ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(
+                interface_method, *this_object, caller);
+            return nullptr;
+          }
+        }
+      }
+      break;
+    case kVirtual:
+      called_method = (*this_object)->GetClass()->GetVTableEntry(tls_value, pointer_size);
+      break;
+  }
+
+  if (UNLIKELY(!called_method->IsInvokable())) {
+    called_method->ThrowInvocationTimeError((type == kStatic) ? nullptr : *this_object);
+    return nullptr;
+  }
+  DCHECK(!called_method->IsRuntimeMethod()) << called_method->PrettyMethod();
+  return called_method;
+}
+
 template<bool access_check>
 ALWAYS_INLINE ArtMethod* FindSuperMethodToCall(uint32_t method_idx,
                                               ArtMethod* resolved_method,
@@ -546,130 +671,6 @@
   return super_class->GetVTableEntry(vtable_index, linker->GetImagePointerSize());
 }
 
-// Follow virtual/interface indirections if applicable.
-// Will throw null-pointer exception the if the object is null.
-template<InvokeType type, bool access_check>
-ALWAYS_INLINE ArtMethod* FindMethodToCall(uint32_t method_idx,
-                                          ArtMethod* resolved_method,
-                                          ObjPtr<mirror::Object>* this_object,
-                                          ArtMethod* referrer,
-                                          Thread* self)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
-  // Null pointer check.
-  if (UNLIKELY(*this_object == nullptr && type != kStatic)) {
-    if (UNLIKELY(resolved_method->GetDeclaringClass()->IsStringClass() &&
-                 resolved_method->IsConstructor())) {
-      // Hack for String init:
-      //
-      // We assume that the input of String.<init> in verified code is always
-      // an unitialized reference. If it is a null constant, it must have been
-      // optimized out by the compiler. Do not throw NullPointerException.
-    } else {
-      // Maintain interpreter-like semantics where NullPointerException is thrown
-      // after potential NoSuchMethodError from class linker.
-      ThrowNullPointerExceptionForMethodAccess(method_idx, type);
-      return nullptr;  // Failure.
-    }
-  }
-  switch (type) {
-    case kStatic:
-    case kDirect:
-      return resolved_method;
-    case kVirtual: {
-      ObjPtr<mirror::Class> klass = (*this_object)->GetClass();
-      uint16_t vtable_index = resolved_method->GetMethodIndex();
-      if (access_check &&
-          (!klass->HasVTable() ||
-           vtable_index >= static_cast<uint32_t>(klass->GetVTableLength()))) {
-        // Behavior to agree with that of the verifier.
-        ThrowNoSuchMethodError(type, resolved_method->GetDeclaringClass(),
-                               resolved_method->GetName(), resolved_method->GetSignature());
-        return nullptr;  // Failure.
-      }
-      DCHECK(klass->HasVTable()) << klass->PrettyClass();
-      return klass->GetVTableEntry(vtable_index, class_linker->GetImagePointerSize());
-    }
-    case kSuper: {
-      return FindSuperMethodToCall<access_check>(method_idx, resolved_method, referrer, self);
-    }
-    case kInterface: {
-      size_t imt_index = resolved_method->GetImtIndex();
-      PointerSize pointer_size = class_linker->GetImagePointerSize();
-      ObjPtr<mirror::Class> klass = (*this_object)->GetClass();
-      ArtMethod* imt_method = klass->GetImt(pointer_size)->Get(imt_index, pointer_size);
-      if (!imt_method->IsRuntimeMethod()) {
-        if (kIsDebugBuild) {
-          ArtMethod* method = klass->FindVirtualMethodForInterface(
-              resolved_method, class_linker->GetImagePointerSize());
-          CHECK_EQ(imt_method, method) << ArtMethod::PrettyMethod(resolved_method) << " / "
-                                       << imt_method->PrettyMethod() << " / "
-                                       << ArtMethod::PrettyMethod(method) << " / "
-                                       << klass->PrettyClass();
-        }
-        return imt_method;
-      } else {
-        ArtMethod* interface_method = klass->FindVirtualMethodForInterface(
-            resolved_method, class_linker->GetImagePointerSize());
-        if (UNLIKELY(interface_method == nullptr)) {
-          ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(resolved_method,
-                                                                     *this_object, referrer);
-          return nullptr;  // Failure.
-        }
-        return interface_method;
-      }
-    }
-    default:
-      LOG(FATAL) << "Unknown invoke type " << type;
-      return nullptr;  // Failure.
-  }
-}
-
-template<InvokeType type, bool access_check>
-inline ArtMethod* FindMethodFromCode(uint32_t method_idx,
-                                     ObjPtr<mirror::Object>* this_object,
-                                     ArtMethod* referrer,
-                                     Thread* self) {
-  ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
-  constexpr ClassLinker::ResolveMode resolve_mode =
-      access_check ? ClassLinker::ResolveMode::kCheckICCEAndIAE
-                   : ClassLinker::ResolveMode::kNoChecks;
-  ArtMethod* resolved_method;
-  if (type == kStatic) {
-    resolved_method = class_linker->ResolveMethod<resolve_mode>(self, method_idx, referrer, type);
-  } else {
-    StackHandleScope<1> hs(self);
-    HandleWrapperObjPtr<mirror::Object> h_this(hs.NewHandleWrapper(this_object));
-    resolved_method = class_linker->ResolveMethod<resolve_mode>(self, method_idx, referrer, type);
-  }
-  if (UNLIKELY(resolved_method == nullptr)) {
-    DCHECK(self->IsExceptionPending());  // Throw exception and unwind.
-    return nullptr;  // Failure.
-  }
-  return FindMethodToCall<type, access_check>(
-      method_idx, resolved_method, this_object, referrer, self);
-}
-
-// Explicit template declarations of FindMethodFromCode for all invoke types.
-#define EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL(_type, _access_check)                 \
-  template REQUIRES_SHARED(Locks::mutator_lock_) ALWAYS_INLINE                       \
-  ArtMethod* FindMethodFromCode<_type, _access_check>(uint32_t method_idx,         \
-                                                      ObjPtr<mirror::Object>* this_object, \
-                                                      ArtMethod* referrer, \
-                                                      Thread* self)
-#define EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(_type) \
-    EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL(_type, false);   \
-    EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL(_type, true)
-
-EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kStatic);
-EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kDirect);
-EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kVirtual);
-EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kSuper);
-EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kInterface);
-
-#undef EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL
-#undef EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL
-
 inline ObjPtr<mirror::Class> ResolveVerifyAndClinit(dex::TypeIndex type_idx,
                                                     ArtMethod* referrer,
                                                     Thread* self,
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index 8b6fc69..ae56875 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -143,11 +143,12 @@
     REQUIRES_SHARED(Locks::mutator_lock_)
     REQUIRES(!Roles::uninterruptible_);
 
-template<InvokeType type, bool access_check>
-inline ArtMethod* FindMethodFromCode(uint32_t method_idx,
-                                     ObjPtr<mirror::Object>* this_object,
-                                     ArtMethod* referrer,
-                                     Thread* self)
+template<InvokeType type>
+inline ArtMethod* FindMethodToCall(Thread* self,
+                                   ArtMethod* referrer,
+                                   ObjPtr<mirror::Object>* this_object,
+                                   const Instruction& inst,
+                                   /*out*/ bool* string_init)
     REQUIRES_SHARED(Locks::mutator_lock_)
     REQUIRES(!Roles::uninterruptible_);
 
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index fc77110..e7fa148 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -2267,12 +2267,18 @@
     uint32_t shorty_len;
     const char* shorty = dex_file->GetMethodShorty(dex_file->GetMethodId(method_idx), &shorty_len);
     {
-      // Remember the args in case a GC happens in FindMethodFromCode.
+      // Remember the args in case a GC happens in FindMethodToCall.
       ScopedObjectAccessUnchecked soa(self->GetJniEnv());
       RememberForGcArgumentVisitor visitor(sp, type == kStatic, shorty, shorty_len, &soa);
       visitor.VisitArguments();
-      method = FindMethodFromCode<type, /*access_check=*/true>(
-          method_idx, &this_object, caller_method, self);
+
+      uint32_t dex_pc = QuickArgumentVisitor::GetCallingDexPc(sp);
+      CodeItemInstructionAccessor accessor(caller_method->DexInstructions());
+      CHECK_LT(dex_pc, accessor.InsnsSizeInCodeUnits());
+      const Instruction& instr = accessor.InstructionAt(dex_pc);
+      bool string_init = false;
+      method = FindMethodToCall<type>(self, caller_method, &this_object, instr, &string_init);
+
       visitor.FixupReferences();
     }
 
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 0ffc38b..6f0a5c9 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -511,7 +511,7 @@
         new_dex_pc = dex_pc + instr->SizeInCodeUnits();
       } else if (instr->IsInvoke()) {
         DCHECK(deopt_method_type == DeoptimizationMethodType::kDefault);
-        if (IsStringInit(instr, shadow_frame->GetMethod())) {
+        if (IsStringInit(*instr, shadow_frame->GetMethod())) {
           uint16_t this_obj_vreg = GetReceiverRegisterForStringInit(instr);
           // Move the StringFactory.newStringFromChars() result into the register representing
           // "this object" when invoking the string constructor in the original dex instruction.
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index c6b2ddc..69a9c0e 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -242,7 +242,8 @@
                                        JValue* result,
                                        uint16_t number_of_inputs,
                                        uint32_t (&arg)[Instruction::kMaxVarArgRegs],
-                                       uint32_t vregC) REQUIRES_SHARED(Locks::mutator_lock_);
+                                       uint32_t vregC,
+                                       bool string_init) REQUIRES_SHARED(Locks::mutator_lock_);
 
 template <bool is_range>
 ALWAYS_INLINE void CopyRegisters(ShadowFrame& caller_frame,
@@ -1194,15 +1195,8 @@
                                 JValue* result,
                                 uint16_t number_of_inputs,
                                 uint32_t (&arg)[Instruction::kMaxVarArgRegs],
-                                uint32_t vregC) {
-  bool string_init = false;
-  // Replace calls to String.<init> with equivalent StringFactory call.
-  if (UNLIKELY(called_method->GetDeclaringClass()->IsStringClass()
-               && called_method->IsConstructor())) {
-    called_method = WellKnownClasses::StringInitToStringFactory(called_method);
-    string_init = true;
-  }
-
+                                uint32_t vregC,
+                                bool string_init) {
   // Compute method information.
   CodeItemDataAccessor accessor(called_method->DexInstructionData());
   // Number of registers for the callee's call frame.
@@ -1393,8 +1387,13 @@
 
 template<bool is_range, bool do_assignability_check>
 NO_STACK_PROTECTOR
-bool DoCall(ArtMethod* called_method, Thread* self, ShadowFrame& shadow_frame,
-            const Instruction* inst, uint16_t inst_data, JValue* result) {
+bool DoCall(ArtMethod* called_method,
+            Thread* self,
+            ShadowFrame& shadow_frame,
+            const Instruction* inst,
+            uint16_t inst_data,
+            bool is_string_init,
+            JValue* result) {
   // Argument word count.
   const uint16_t number_of_inputs =
       (is_range) ? inst->VRegA_3rc(inst_data) : inst->VRegA_35c(inst_data);
@@ -1411,8 +1410,14 @@
   }
 
   return DoCallCommon<is_range, do_assignability_check>(
-      called_method, self, shadow_frame,
-      result, number_of_inputs, arg, vregC);
+      called_method,
+      self,
+      shadow_frame,
+      result,
+      number_of_inputs,
+      arg,
+      vregC,
+      is_string_init);
 }
 
 template <bool is_range, bool do_access_check, bool transaction_active>
@@ -1539,9 +1544,12 @@
 // Explicit DoCall template function declarations.
 #define EXPLICIT_DO_CALL_TEMPLATE_DECL(_is_range, _do_assignability_check)                      \
   template REQUIRES_SHARED(Locks::mutator_lock_)                                                \
-  bool DoCall<_is_range, _do_assignability_check>(ArtMethod* method, Thread* self,              \
+  bool DoCall<_is_range, _do_assignability_check>(ArtMethod* method,                            \
+                                                  Thread* self,                                 \
                                                   ShadowFrame& shadow_frame,                    \
-                                                  const Instruction* inst, uint16_t inst_data,  \
+                                                  const Instruction* inst,                      \
+                                                  uint16_t inst_data,                           \
+                                                  bool string_init,                             \
                                                   JValue* result)
 EXPLICIT_DO_CALL_TEMPLATE_DECL(false, false);
 EXPLICIT_DO_CALL_TEMPLATE_DECL(false, true);
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index fe9cf57..49d7e64 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -20,7 +20,6 @@
 #include "android-base/macros.h"
 #include "instrumentation.h"
 #include "interpreter.h"
-#include "interpreter_intrinsics.h"
 #include "transaction.h"
 
 #include <math.h>
@@ -126,8 +125,13 @@
 // DoFastInvoke and DoInvokeVirtualQuick functions.
 // Returns true on success, otherwise throws an exception and returns false.
 template<bool is_range, bool do_assignability_check>
-bool DoCall(ArtMethod* called_method, Thread* self, ShadowFrame& shadow_frame,
-            const Instruction* inst, uint16_t inst_data, JValue* result);
+bool DoCall(ArtMethod* called_method,
+            Thread* self,
+            ShadowFrame& shadow_frame,
+            const Instruction* inst,
+            uint16_t inst_data,
+            bool string_init,
+            JValue* result);
 
 // Called by the switch interpreter to know if we can stay in it.
 bool ShouldStayInSwitchInterpreter(ArtMethod* method)
@@ -220,7 +224,7 @@
 
 // Handles all invoke-XXX/range instructions except for invoke-polymorphic[/range].
 // Returns true on success, otherwise throws an exception and returns false.
-template<InvokeType type, bool is_range, bool do_access_check, bool is_mterp>
+template<InvokeType type, bool is_range, bool do_access_check>
 static ALWAYS_INLINE bool DoInvoke(Thread* self,
                                    ShadowFrame& shadow_frame,
                                    const Instruction* inst,
@@ -231,68 +235,19 @@
   if (UNLIKELY(self->ObserveAsyncException())) {
     return false;
   }
-  const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
-  const uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
+  const uint32_t vregC = is_range ? inst->VRegC_3rc() : inst->VRegC_35c();
+  ObjPtr<mirror::Object> obj = type == kStatic ? nullptr : shadow_frame.GetVRegReference(vregC);
   ArtMethod* sf_method = shadow_frame.GetMethod();
-
-  // Try to find the method in small thread-local cache first (only used when
-  // nterp is not used as mterp and nterp use the cache in an incompatible way).
-  InterpreterCache* tls_cache = self->GetInterpreterCache();
-  size_t tls_value;
-  ArtMethod* resolved_method;
-  if (!IsNterpSupported() && LIKELY(tls_cache->Get(self, inst, &tls_value))) {
-    resolved_method = reinterpret_cast<ArtMethod*>(tls_value);
-  } else {
-    ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
-    constexpr ClassLinker::ResolveMode resolve_mode =
-        do_access_check ? ClassLinker::ResolveMode::kCheckICCEAndIAE
-                        : ClassLinker::ResolveMode::kNoChecks;
-    resolved_method = class_linker->ResolveMethod<resolve_mode>(self, method_idx, sf_method, type);
-    if (UNLIKELY(resolved_method == nullptr)) {
-      CHECK(self->IsExceptionPending());
-      result->SetJ(0);
-      return false;
-    }
-    if (!IsNterpSupported()) {
-      tls_cache->Set(self, inst, reinterpret_cast<size_t>(resolved_method));
-    }
-  }
-
-  // Null pointer check and virtual method resolution.
-  ArtMethod* called_method = nullptr;
-  {
-    // `FindMethodToCall` might suspend, so don't keep `receiver` as a local
-    // variable after the call.
-    ObjPtr<mirror::Object> receiver =
-        (type == kStatic) ? nullptr : shadow_frame.GetVRegReference(vregC);
-    called_method = FindMethodToCall<type, do_access_check>(
-        method_idx, resolved_method, &receiver, sf_method, self);
-    if (UNLIKELY(called_method == nullptr)) {
-      CHECK(self->IsExceptionPending());
-      result->SetJ(0);
-      return false;
-    }
-  }
-  if (UNLIKELY(!called_method->IsInvokable())) {
-    called_method->ThrowInvocationTimeError(
-        (type == kStatic) ? nullptr : shadow_frame.GetVRegReference(vregC));
+  bool string_init = false;
+  ArtMethod* called_method = FindMethodToCall<type>(self, sf_method, &obj, *inst, &string_init);
+  if (called_method == nullptr) {
+    DCHECK(self->IsExceptionPending());
     result->SetJ(0);
     return false;
   }
 
-  jit::Jit* jit = Runtime::Current()->GetJit();
-  if (is_mterp && !is_range && called_method->IsIntrinsic()) {
-    if (MterpHandleIntrinsic(&shadow_frame, called_method, inst, inst_data,
-                             shadow_frame.GetResultRegister())) {
-      if (jit != nullptr && sf_method != nullptr) {
-        jit->NotifyInterpreterToCompiledCodeTransition(self, sf_method);
-      }
-      return !self->IsExceptionPending();
-    }
-  }
-
-  return DoCall<is_range, do_access_check>(called_method, self, shadow_frame, inst, inst_data,
-                                           result);
+  return DoCall<is_range, do_access_check>(
+      called_method, self, shadow_frame, inst, inst_data, string_init, result);
 }
 
 static inline ObjPtr<mirror::MethodHandle> ResolveMethodHandle(Thread* self,
@@ -760,34 +715,6 @@
                                         uint16_t arg_offset,
                                         JValue* result);
 
-static inline bool IsStringInit(const DexFile* dex_file, uint32_t method_idx)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  const dex::MethodId& method_id = dex_file->GetMethodId(method_idx);
-  const char* class_name = dex_file->StringByTypeIdx(method_id.class_idx_);
-  const char* method_name = dex_file->GetMethodName(method_id);
-  // Instead of calling ResolveMethod() which has suspend point and can trigger
-  // GC, look up the method symbolically.
-  // Compare method's class name and method name against string init.
-  // It's ok since it's not allowed to create your own java/lang/String.
-  // TODO: verify that assumption.
-  if ((strcmp(class_name, "Ljava/lang/String;") == 0) &&
-      (strcmp(method_name, "<init>") == 0)) {
-    return true;
-  }
-  return false;
-}
-
-static inline bool IsStringInit(const Instruction* instr, ArtMethod* caller)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  if (instr->Opcode() == Instruction::INVOKE_DIRECT ||
-      instr->Opcode() == Instruction::INVOKE_DIRECT_RANGE) {
-    uint16_t callee_method_idx = (instr->Opcode() == Instruction::INVOKE_DIRECT_RANGE) ?
-        instr->VRegB_3rc() : instr->VRegB_35c();
-    return IsStringInit(caller->GetDexFile(), callee_method_idx);
-  }
-  return false;
-}
-
 // Set string value created from StringFactory.newStringFromXXX() into all aliases of
 // StringFactory.newEmptyString().
 void SetStringInitValueToAllAliases(ShadowFrame* shadow_frame,
diff --git a/runtime/interpreter/interpreter_intrinsics.cc b/runtime/interpreter/interpreter_intrinsics.cc
deleted file mode 100644
index c8344bc..0000000
--- a/runtime/interpreter/interpreter_intrinsics.cc
+++ /dev/null
@@ -1,678 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "interpreter/interpreter_intrinsics.h"
-
-#include "dex/dex_instruction.h"
-#include "intrinsics_enum.h"
-#include "interpreter/interpreter_common.h"
-
-namespace art {
-namespace interpreter {
-
-
-#define BINARY_INTRINSIC(name, op, get1, get2, set)                 \
-static ALWAYS_INLINE bool name(ShadowFrame* shadow_frame,           \
-                               const Instruction* inst,             \
-                               uint16_t inst_data,                  \
-                               JValue* result_register)             \
-    REQUIRES_SHARED(Locks::mutator_lock_) {                         \
-  uint32_t arg[Instruction::kMaxVarArgRegs] = {};                   \
-  inst->GetVarArgs(arg, inst_data);                                 \
-  result_register->set(op(shadow_frame->get1, shadow_frame->get2)); \
-  return true;                                                      \
-}
-
-#define BINARY_II_INTRINSIC(name, op, set) \
-    BINARY_INTRINSIC(name, op, GetVReg(arg[0]), GetVReg(arg[1]), set)
-
-#define BINARY_JJ_INTRINSIC(name, op, set) \
-    BINARY_INTRINSIC(name, op, GetVRegLong(arg[0]), GetVRegLong(arg[2]), set)
-
-#define BINARY_JI_INTRINSIC(name, op, set) \
-    BINARY_INTRINSIC(name, op, GetVRegLong(arg[0]), GetVReg(arg[2]), set)
-
-#define UNARY_INTRINSIC(name, op, get, set)                  \
-static ALWAYS_INLINE bool name(ShadowFrame* shadow_frame,    \
-                               const Instruction* inst,      \
-                               uint16_t inst_data,           \
-                               JValue* result_register)      \
-    REQUIRES_SHARED(Locks::mutator_lock_) {                  \
-  uint32_t arg[Instruction::kMaxVarArgRegs] = {};            \
-  inst->GetVarArgs(arg, inst_data);                          \
-  result_register->set(op(shadow_frame->get(arg[0])));       \
-  return true;                                               \
-}
-
-
-// java.lang.Integer.reverse(I)I
-UNARY_INTRINSIC(MterpIntegerReverse, ReverseBits32, GetVReg, SetI);
-
-// java.lang.Integer.reverseBytes(I)I
-UNARY_INTRINSIC(MterpIntegerReverseBytes, BSWAP, GetVReg, SetI);
-
-// java.lang.Integer.bitCount(I)I
-UNARY_INTRINSIC(MterpIntegerBitCount, POPCOUNT, GetVReg, SetI);
-
-// java.lang.Integer.compare(II)I
-BINARY_II_INTRINSIC(MterpIntegerCompare, Compare, SetI);
-
-// java.lang.Integer.highestOneBit(I)I
-UNARY_INTRINSIC(MterpIntegerHighestOneBit, HighestOneBitValue, GetVReg, SetI);
-
-// java.lang.Integer.LowestOneBit(I)I
-UNARY_INTRINSIC(MterpIntegerLowestOneBit, LowestOneBitValue, GetVReg, SetI);
-
-// java.lang.Integer.numberOfLeadingZeros(I)I
-UNARY_INTRINSIC(MterpIntegerNumberOfLeadingZeros, JAVASTYLE_CLZ, GetVReg, SetI);
-
-// java.lang.Integer.numberOfTrailingZeros(I)I
-UNARY_INTRINSIC(MterpIntegerNumberOfTrailingZeros, JAVASTYLE_CTZ, GetVReg, SetI);
-
-// java.lang.Integer.rotateRight(II)I
-BINARY_II_INTRINSIC(MterpIntegerRotateRight, (Rot<int32_t, false>), SetI);
-
-// java.lang.Integer.rotateLeft(II)I
-BINARY_II_INTRINSIC(MterpIntegerRotateLeft, (Rot<int32_t, true>), SetI);
-
-// java.lang.Integer.signum(I)I
-UNARY_INTRINSIC(MterpIntegerSignum, Signum, GetVReg, SetI);
-
-// java.lang.Long.reverse(J)J
-UNARY_INTRINSIC(MterpLongReverse, ReverseBits64, GetVRegLong, SetJ);
-
-// java.lang.Long.reverseBytes(J)J
-UNARY_INTRINSIC(MterpLongReverseBytes, BSWAP, GetVRegLong, SetJ);
-
-// java.lang.Long.bitCount(J)I
-UNARY_INTRINSIC(MterpLongBitCount, POPCOUNT, GetVRegLong, SetI);
-
-// java.lang.Long.compare(JJ)I
-BINARY_JJ_INTRINSIC(MterpLongCompare, Compare, SetI);
-
-// java.lang.Long.highestOneBit(J)J
-UNARY_INTRINSIC(MterpLongHighestOneBit, HighestOneBitValue, GetVRegLong, SetJ);
-
-// java.lang.Long.lowestOneBit(J)J
-UNARY_INTRINSIC(MterpLongLowestOneBit, LowestOneBitValue, GetVRegLong, SetJ);
-
-// java.lang.Long.numberOfLeadingZeros(J)I
-UNARY_INTRINSIC(MterpLongNumberOfLeadingZeros, JAVASTYLE_CLZ, GetVRegLong, SetJ);
-
-// java.lang.Long.numberOfTrailingZeros(J)I
-UNARY_INTRINSIC(MterpLongNumberOfTrailingZeros, JAVASTYLE_CTZ, GetVRegLong, SetJ);
-
-// java.lang.Long.rotateRight(JI)J
-BINARY_JI_INTRINSIC(MterpLongRotateRight, (Rot<int64_t, false>), SetJ);
-
-// java.lang.Long.rotateLeft(JI)J
-BINARY_JI_INTRINSIC(MterpLongRotateLeft, (Rot<int64_t, true>), SetJ);
-
-// java.lang.Long.signum(J)I
-UNARY_INTRINSIC(MterpLongSignum, Signum, GetVRegLong, SetI);
-
-// java.lang.Short.reverseBytes(S)S
-UNARY_INTRINSIC(MterpShortReverseBytes, BSWAP, GetVRegShort, SetS);
-
-// java.lang.Math.min(II)I
-BINARY_II_INTRINSIC(MterpMathMinIntInt, std::min, SetI);
-
-// java.lang.Math.min(JJ)J
-BINARY_JJ_INTRINSIC(MterpMathMinLongLong, std::min, SetJ);
-
-// java.lang.Math.max(II)I
-BINARY_II_INTRINSIC(MterpMathMaxIntInt, std::max, SetI);
-
-// java.lang.Math.max(JJ)J
-BINARY_JJ_INTRINSIC(MterpMathMaxLongLong, std::max, SetJ);
-
-// java.lang.Math.abs(I)I
-UNARY_INTRINSIC(MterpMathAbsInt, std::abs, GetVReg, SetI);
-
-// java.lang.Math.abs(J)J
-UNARY_INTRINSIC(MterpMathAbsLong, std::abs, GetVRegLong, SetJ);
-
-// java.lang.Math.abs(F)F
-UNARY_INTRINSIC(MterpMathAbsFloat, 0x7fffffff&, GetVReg, SetI);
-
-// java.lang.Math.abs(D)D
-UNARY_INTRINSIC(MterpMathAbsDouble, INT64_C(0x7fffffffffffffff)&, GetVRegLong, SetJ);
-
-// java.lang.Math.sqrt(D)D
-UNARY_INTRINSIC(MterpMathSqrt, std::sqrt, GetVRegDouble, SetD);
-
-// java.lang.Math.ceil(D)D
-UNARY_INTRINSIC(MterpMathCeil, std::ceil, GetVRegDouble, SetD);
-
-// java.lang.Math.floor(D)D
-UNARY_INTRINSIC(MterpMathFloor, std::floor, GetVRegDouble, SetD);
-
-// java.lang.Math.sin(D)D
-UNARY_INTRINSIC(MterpMathSin, std::sin, GetVRegDouble, SetD);
-
-// java.lang.Math.cos(D)D
-UNARY_INTRINSIC(MterpMathCos, std::cos, GetVRegDouble, SetD);
-
-// java.lang.Math.tan(D)D
-UNARY_INTRINSIC(MterpMathTan, std::tan, GetVRegDouble, SetD);
-
-// java.lang.Math.asin(D)D
-UNARY_INTRINSIC(MterpMathAsin, std::asin, GetVRegDouble, SetD);
-
-// java.lang.Math.acos(D)D
-UNARY_INTRINSIC(MterpMathAcos, std::acos, GetVRegDouble, SetD);
-
-// java.lang.Math.atan(D)D
-UNARY_INTRINSIC(MterpMathAtan, std::atan, GetVRegDouble, SetD);
-
-// java.lang.String.charAt(I)C
-static ALWAYS_INLINE bool MterpStringCharAt(ShadowFrame* shadow_frame,
-                                            const Instruction* inst,
-                                            uint16_t inst_data,
-                                            JValue* result_register)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  uint32_t arg[Instruction::kMaxVarArgRegs] = {};
-  inst->GetVarArgs(arg, inst_data);
-  ObjPtr<mirror::String> str = shadow_frame->GetVRegReference(arg[0])->AsString();
-  int length = str->GetLength();
-  int index = shadow_frame->GetVReg(arg[1]);
-  uint16_t res;
-  if (UNLIKELY(index < 0) || (index >= length)) {
-    return false;  // Punt and let non-intrinsic version deal with the throw.
-  }
-  if (str->IsCompressed()) {
-    res = str->GetValueCompressed()[index];
-  } else {
-    res = str->GetValue()[index];
-  }
-  result_register->SetC(res);
-  return true;
-}
-
-// java.lang.String.compareTo(Ljava/lang/string)I
-static ALWAYS_INLINE bool MterpStringCompareTo(ShadowFrame* shadow_frame,
-                                               const Instruction* inst,
-                                               uint16_t inst_data,
-                                               JValue* result_register)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  uint32_t arg[Instruction::kMaxVarArgRegs] = {};
-  inst->GetVarArgs(arg, inst_data);
-  ObjPtr<mirror::String> str = shadow_frame->GetVRegReference(arg[0])->AsString();
-  ObjPtr<mirror::Object> arg1 = shadow_frame->GetVRegReference(arg[1]);
-  if (arg1 == nullptr) {
-    return false;
-  }
-  result_register->SetI(str->CompareTo(arg1->AsString()));
-  return true;
-}
-
-#define STRING_INDEXOF_INTRINSIC(name, starting_pos)             \
-static ALWAYS_INLINE bool Mterp##name(ShadowFrame* shadow_frame, \
-                                      const Instruction* inst,   \
-                                      uint16_t inst_data,        \
-                                      JValue* result_register)   \
-    REQUIRES_SHARED(Locks::mutator_lock_) {                      \
-  uint32_t arg[Instruction::kMaxVarArgRegs] = {};                \
-  inst->GetVarArgs(arg, inst_data);                              \
-  ObjPtr<mirror::String> str = shadow_frame->GetVRegReference(arg[0])->AsString(); \
-  int ch = shadow_frame->GetVReg(arg[1]);                        \
-  if (ch >= 0x10000) {                                           \
-    /* Punt if supplementary char. */                            \
-    return false;                                                \
-  }                                                              \
-  result_register->SetI(str->FastIndexOf(ch, starting_pos));     \
-  return true;                                                   \
-}
-
-// java.lang.String.indexOf(I)I
-STRING_INDEXOF_INTRINSIC(StringIndexOf, 0);
-
-// java.lang.String.indexOf(II)I
-STRING_INDEXOF_INTRINSIC(StringIndexOfAfter, shadow_frame->GetVReg(arg[2]));
-
-#define SIMPLE_STRING_INTRINSIC(name, operation)                 \
-static ALWAYS_INLINE bool Mterp##name(ShadowFrame* shadow_frame, \
-                                      const Instruction* inst,   \
-                                      uint16_t inst_data,        \
-                                      JValue* result_register)   \
-    REQUIRES_SHARED(Locks::mutator_lock_) {                      \
-  uint32_t arg[Instruction::kMaxVarArgRegs] = {};                \
-  inst->GetVarArgs(arg, inst_data);                              \
-  ObjPtr<mirror::String> str = shadow_frame->GetVRegReference(arg[0])->AsString(); \
-  result_register->operation;                                    \
-  return true;                                                   \
-}
-
-// java.lang.String.isEmpty()Z
-SIMPLE_STRING_INTRINSIC(StringIsEmpty, SetZ(str->GetLength() == 0))
-
-// java.lang.String.length()I
-SIMPLE_STRING_INTRINSIC(StringLength, SetI(str->GetLength()))
-
-// java.lang.String.getCharsNoCheck(II[CI)V
-static ALWAYS_INLINE bool MterpStringGetCharsNoCheck(ShadowFrame* shadow_frame,
-                                                     const Instruction* inst,
-                                                     uint16_t inst_data,
-                                                     JValue* result_register ATTRIBUTE_UNUSED)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  // Start, end & index already checked by caller - won't throw.  Destination is uncompressed.
-  uint32_t arg[Instruction::kMaxVarArgRegs] = {};
-  inst->GetVarArgs(arg, inst_data);
-  ObjPtr<mirror::String> str = shadow_frame->GetVRegReference(arg[0])->AsString();
-  int32_t start = shadow_frame->GetVReg(arg[1]);
-  int32_t end = shadow_frame->GetVReg(arg[2]);
-  int32_t index = shadow_frame->GetVReg(arg[4]);
-  ObjPtr<mirror::CharArray> array = shadow_frame->GetVRegReference(arg[3])->AsCharArray();
-  uint16_t* dst = array->GetData() + index;
-  int32_t len = (end - start);
-  if (str->IsCompressed()) {
-    const uint8_t* src_8 = str->GetValueCompressed() + start;
-    for (int i = 0; i < len; i++) {
-      dst[i] = src_8[i];
-    }
-  } else {
-    uint16_t* src_16 = str->GetValue() + start;
-    memcpy(dst, src_16, len * sizeof(uint16_t));
-  }
-  return true;
-}
-
-// java.lang.String.equalsLjava/lang/Object;)Z
-static ALWAYS_INLINE bool MterpStringEquals(ShadowFrame* shadow_frame,
-                                            const Instruction* inst,
-                                            uint16_t inst_data,
-                                            JValue* result_register)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  uint32_t arg[Instruction::kMaxVarArgRegs] = {};
-  inst->GetVarArgs(arg, inst_data);
-  ObjPtr<mirror::String> str = shadow_frame->GetVRegReference(arg[0])->AsString();
-  ObjPtr<mirror::Object> obj = shadow_frame->GetVRegReference(arg[1]);
-  bool res = false;  // Assume not equal.
-  if ((obj != nullptr) && obj->IsString()) {
-    ObjPtr<mirror::String> str2 = obj->AsString();
-    if (str->GetCount() == str2->GetCount()) {
-      // Length & compression status are same.  Can use block compare.
-      void* bytes1;
-      void* bytes2;
-      int len = str->GetLength();
-      if (str->IsCompressed()) {
-        bytes1 = str->GetValueCompressed();
-        bytes2 = str2->GetValueCompressed();
-      } else {
-        len *= sizeof(uint16_t);
-        bytes1 = str->GetValue();
-        bytes2 = str2->GetValue();
-      }
-      res = (memcmp(bytes1, bytes2, len) == 0);
-    }
-  }
-  result_register->SetZ(res);
-  return true;
-}
-
-#define VARHANDLE_FENCE_INTRINSIC(name, std_memory_operation)              \
-static ALWAYS_INLINE bool name(ShadowFrame* shadow_frame ATTRIBUTE_UNUSED, \
-                               const Instruction* inst ATTRIBUTE_UNUSED,   \
-                               uint16_t inst_data ATTRIBUTE_UNUSED,        \
-                               JValue* result_register ATTRIBUTE_UNUSED)   \
-    REQUIRES_SHARED(Locks::mutator_lock_) {                                \
-  std::atomic_thread_fence(std_memory_operation);                          \
-  return true;                                                             \
-}
-
-// The VarHandle fence methods are static (unlike jdk.internal.misc.Unsafe versions).
-// The fences for the LoadLoadFence and StoreStoreFence are stronger
-// than strictly required, but the impact should be marginal.
-VARHANDLE_FENCE_INTRINSIC(MterpVarHandleFullFence, std::memory_order_seq_cst)
-VARHANDLE_FENCE_INTRINSIC(MterpVarHandleAcquireFence, std::memory_order_acquire)
-VARHANDLE_FENCE_INTRINSIC(MterpVarHandleReleaseFence, std::memory_order_release)
-VARHANDLE_FENCE_INTRINSIC(MterpVarHandleLoadLoadFence, std::memory_order_acquire)
-VARHANDLE_FENCE_INTRINSIC(MterpVarHandleStoreStoreFence, std::memory_order_release)
-
-#define METHOD_HANDLE_INVOKE_INTRINSIC(name)                                                      \
-static ALWAYS_INLINE bool Mterp##name(ShadowFrame* shadow_frame,                                  \
-                               const Instruction* inst,                                           \
-                               uint16_t inst_data,                                                \
-                               JValue* result)                                                    \
-    REQUIRES_SHARED(Locks::mutator_lock_) {                                                       \
-  if (inst->Opcode() == Instruction::INVOKE_POLYMORPHIC) {                                        \
-    return DoInvokePolymorphic<false>(Thread::Current(), *shadow_frame, inst, inst_data, result); \
-  } else {                                                                                        \
-    return DoInvokePolymorphic<true>(Thread::Current(), *shadow_frame, inst, inst_data, result);  \
-  }                                                                                               \
-}
-
-METHOD_HANDLE_INVOKE_INTRINSIC(MethodHandleInvokeExact)
-METHOD_HANDLE_INVOKE_INTRINSIC(MethodHandleInvoke)
-
-#define VAR_HANDLE_ACCESSOR_INTRINSIC(name)                                   \
-static ALWAYS_INLINE bool Mterp##name(ShadowFrame* shadow_frame,              \
-                               const Instruction* inst,                       \
-                               uint16_t inst_data,                            \
-                               JValue* result)                                \
-    REQUIRES_SHARED(Locks::mutator_lock_) {                                   \
-  return Do##name(Thread::Current(), *shadow_frame, inst, inst_data, result); \
-}
-
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleCompareAndExchange)
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleCompareAndExchangeAcquire)
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleCompareAndExchangeRelease)
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleCompareAndSet)
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGet);
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAcquire)
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndAdd)
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndAddAcquire)
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndAddRelease)
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndBitwiseAnd)
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndBitwiseAndAcquire)
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndBitwiseAndRelease)
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndBitwiseOr)
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndBitwiseOrAcquire)
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndBitwiseOrRelease)
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndBitwiseXor)
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndBitwiseXorAcquire)
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndBitwiseXorRelease)
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndSet)
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndSetAcquire)
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndSetRelease)
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetOpaque)
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetVolatile)
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleSet)
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleSetOpaque)
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleSetRelease)
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleSetVolatile)
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleWeakCompareAndSet)
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleWeakCompareAndSetAcquire)
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleWeakCompareAndSetPlain)
-VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleWeakCompareAndSetRelease)
-
-static ALWAYS_INLINE bool MterpReachabilityFence(ShadowFrame* shadow_frame ATTRIBUTE_UNUSED,
-                                                 const Instruction* inst ATTRIBUTE_UNUSED,
-                                                 uint16_t inst_data ATTRIBUTE_UNUSED,
-                                                 JValue* result_register ATTRIBUTE_UNUSED)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  // Do nothing; Its only purpose is to keep the argument reference live
-  // at preceding suspend points. That's automatic in the interpreter.
-  return true;
-}
-
-// Macro to help keep track of what's left to implement.
-#define UNIMPLEMENTED_CASE(name)    \
-    case Intrinsics::k##name:       \
-      res = false;                  \
-      break;
-
-#define INTRINSIC_CASE(name)                                           \
-    case Intrinsics::k##name:                                          \
-      res = Mterp##name(shadow_frame, inst, inst_data, result_register); \
-      break;
-
-bool MterpHandleIntrinsic(ShadowFrame* shadow_frame,
-                          ArtMethod* const called_method,
-                          const Instruction* inst,
-                          uint16_t inst_data,
-                          JValue* result_register)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  Intrinsics intrinsic = static_cast<Intrinsics>(called_method->GetIntrinsic());
-  bool res = false;  // Assume failure
-  switch (intrinsic) {
-    UNIMPLEMENTED_CASE(DoubleDoubleToRawLongBits /* (D)J */)
-    UNIMPLEMENTED_CASE(DoubleDoubleToLongBits /* (D)J */)
-    UNIMPLEMENTED_CASE(DoubleIsInfinite /* (D)Z */)
-    UNIMPLEMENTED_CASE(DoubleIsNaN /* (D)Z */)
-    UNIMPLEMENTED_CASE(DoubleLongBitsToDouble /* (J)D */)
-    UNIMPLEMENTED_CASE(FloatFloatToRawIntBits /* (F)I */)
-    UNIMPLEMENTED_CASE(FloatFloatToIntBits /* (F)I */)
-    UNIMPLEMENTED_CASE(FloatIsInfinite /* (F)Z */)
-    UNIMPLEMENTED_CASE(FloatIsNaN /* (F)Z */)
-    UNIMPLEMENTED_CASE(FloatIntBitsToFloat /* (I)F */)
-    UNIMPLEMENTED_CASE(IntegerDivideUnsigned /* (II)I */)
-    UNIMPLEMENTED_CASE(LongDivideUnsigned /* (JJ)J */)
-    INTRINSIC_CASE(IntegerReverse)
-    INTRINSIC_CASE(IntegerReverseBytes)
-    INTRINSIC_CASE(IntegerBitCount)
-    INTRINSIC_CASE(IntegerCompare)
-    INTRINSIC_CASE(IntegerHighestOneBit)
-    INTRINSIC_CASE(IntegerLowestOneBit)
-    INTRINSIC_CASE(IntegerNumberOfLeadingZeros)
-    INTRINSIC_CASE(IntegerNumberOfTrailingZeros)
-    INTRINSIC_CASE(IntegerRotateRight)
-    INTRINSIC_CASE(IntegerRotateLeft)
-    INTRINSIC_CASE(IntegerSignum)
-    INTRINSIC_CASE(LongReverse)
-    INTRINSIC_CASE(LongReverseBytes)
-    INTRINSIC_CASE(LongBitCount)
-    INTRINSIC_CASE(LongCompare)
-    INTRINSIC_CASE(LongHighestOneBit)
-    INTRINSIC_CASE(LongLowestOneBit)
-    INTRINSIC_CASE(LongNumberOfLeadingZeros)
-    INTRINSIC_CASE(LongNumberOfTrailingZeros)
-    INTRINSIC_CASE(LongRotateRight)
-    INTRINSIC_CASE(LongRotateLeft)
-    INTRINSIC_CASE(LongSignum)
-    INTRINSIC_CASE(ShortReverseBytes)
-    INTRINSIC_CASE(MathAbsDouble)
-    INTRINSIC_CASE(MathAbsFloat)
-    INTRINSIC_CASE(MathAbsLong)
-    INTRINSIC_CASE(MathAbsInt)
-    UNIMPLEMENTED_CASE(MathFmaDouble /* (DDD)D */)
-    UNIMPLEMENTED_CASE(MathFmaFloat /* (FFF)F */)
-    UNIMPLEMENTED_CASE(MathMinDoubleDouble /* (DD)D */)
-    UNIMPLEMENTED_CASE(MathMinFloatFloat /* (FF)F */)
-    INTRINSIC_CASE(MathMinLongLong)
-    INTRINSIC_CASE(MathMinIntInt)
-    UNIMPLEMENTED_CASE(MathMaxDoubleDouble /* (DD)D */)
-    UNIMPLEMENTED_CASE(MathMaxFloatFloat /* (FF)F */)
-    INTRINSIC_CASE(MathMaxLongLong)
-    INTRINSIC_CASE(MathMaxIntInt)
-    INTRINSIC_CASE(MathCos)
-    INTRINSIC_CASE(MathSin)
-    INTRINSIC_CASE(MathAcos)
-    INTRINSIC_CASE(MathAsin)
-    INTRINSIC_CASE(MathAtan)
-    UNIMPLEMENTED_CASE(MathAtan2 /* (DD)D */)
-    UNIMPLEMENTED_CASE(MathCbrt /* (D)D */)
-    UNIMPLEMENTED_CASE(MathCosh /* (D)D */)
-    UNIMPLEMENTED_CASE(MathExp /* (D)D */)
-    UNIMPLEMENTED_CASE(MathExpm1 /* (D)D */)
-    UNIMPLEMENTED_CASE(MathHypot /* (DD)D */)
-    UNIMPLEMENTED_CASE(MathLog /* (D)D */)
-    UNIMPLEMENTED_CASE(MathLog10 /* (D)D */)
-    UNIMPLEMENTED_CASE(MathNextAfter /* (DD)D */)
-    UNIMPLEMENTED_CASE(MathPow /* (DD)D */)
-    UNIMPLEMENTED_CASE(MathSinh /* (D)D */)
-    INTRINSIC_CASE(MathTan)
-    UNIMPLEMENTED_CASE(MathTanh /* (D)D */)
-    INTRINSIC_CASE(MathSqrt)
-    INTRINSIC_CASE(MathCeil)
-    INTRINSIC_CASE(MathFloor)
-    UNIMPLEMENTED_CASE(MathRint /* (D)D */)
-    UNIMPLEMENTED_CASE(MathRoundDouble /* (D)J */)
-    UNIMPLEMENTED_CASE(MathRoundFloat /* (F)I */)
-    UNIMPLEMENTED_CASE(MathMultiplyHigh /* (JJ)J */)
-    UNIMPLEMENTED_CASE(SystemArrayCopyByte /* ([BI[BII)V */)
-    UNIMPLEMENTED_CASE(SystemArrayCopyChar /* ([CI[CII)V */)
-    UNIMPLEMENTED_CASE(SystemArrayCopyInt /* ([II[III)V */)
-    UNIMPLEMENTED_CASE(SystemArrayCopy /* (Ljava/lang/Object;ILjava/lang/Object;II)V */)
-    UNIMPLEMENTED_CASE(ThreadCurrentThread /* ()Ljava/lang/Thread; */)
-    UNIMPLEMENTED_CASE(MemoryPeekByte /* (J)B */)
-    UNIMPLEMENTED_CASE(MemoryPeekIntNative /* (J)I */)
-    UNIMPLEMENTED_CASE(MemoryPeekLongNative /* (J)J */)
-    UNIMPLEMENTED_CASE(MemoryPeekShortNative /* (J)S */)
-    UNIMPLEMENTED_CASE(MemoryPokeByte /* (JB)V */)
-    UNIMPLEMENTED_CASE(MemoryPokeIntNative /* (JI)V */)
-    UNIMPLEMENTED_CASE(MemoryPokeLongNative /* (JJ)V */)
-    UNIMPLEMENTED_CASE(MemoryPokeShortNative /* (JS)V */)
-    INTRINSIC_CASE(ReachabilityFence /* (Ljava/lang/Object;)V */)
-    INTRINSIC_CASE(StringCharAt)
-    INTRINSIC_CASE(StringCompareTo)
-    INTRINSIC_CASE(StringEquals)
-    INTRINSIC_CASE(StringGetCharsNoCheck)
-    INTRINSIC_CASE(StringIndexOf)
-    INTRINSIC_CASE(StringIndexOfAfter)
-    UNIMPLEMENTED_CASE(StringStringIndexOf /* (Ljava/lang/String;)I */)
-    UNIMPLEMENTED_CASE(StringStringIndexOfAfter /* (Ljava/lang/String;I)I */)
-    INTRINSIC_CASE(StringIsEmpty)
-    INTRINSIC_CASE(StringLength)
-    UNIMPLEMENTED_CASE(StringNewStringFromBytes /* ([BIII)Ljava/lang/String; */)
-    UNIMPLEMENTED_CASE(StringNewStringFromChars /* (II[C)Ljava/lang/String; */)
-    UNIMPLEMENTED_CASE(StringNewStringFromString /* (Ljava/lang/String;)Ljava/lang/String; */)
-    UNIMPLEMENTED_CASE(StringBufferAppend /* (Ljava/lang/String;)Ljava/lang/StringBuffer; */)
-    UNIMPLEMENTED_CASE(StringBufferLength /* ()I */)
-    UNIMPLEMENTED_CASE(StringBufferToString /* ()Ljava/lang/String; */)
-    UNIMPLEMENTED_CASE(
-        StringBuilderAppendObject /* (Ljava/lang/Object;)Ljava/lang/StringBuilder; */)
-    UNIMPLEMENTED_CASE(
-        StringBuilderAppendString /* (Ljava/lang/String;)Ljava/lang/StringBuilder; */)
-    UNIMPLEMENTED_CASE(
-        StringBuilderAppendCharSequence /* (Ljava/lang/CharSequence;)Ljava/lang/StringBuilder; */)
-    UNIMPLEMENTED_CASE(StringBuilderAppendCharArray /* ([C)Ljava/lang/StringBuilder; */)
-    UNIMPLEMENTED_CASE(StringBuilderAppendBoolean /* (Z)Ljava/lang/StringBuilder; */)
-    UNIMPLEMENTED_CASE(StringBuilderAppendChar /* (C)Ljava/lang/StringBuilder; */)
-    UNIMPLEMENTED_CASE(StringBuilderAppendInt /* (I)Ljava/lang/StringBuilder; */)
-    UNIMPLEMENTED_CASE(StringBuilderAppendLong /* (J)Ljava/lang/StringBuilder; */)
-    UNIMPLEMENTED_CASE(StringBuilderAppendFloat /* (F)Ljava/lang/StringBuilder; */)
-    UNIMPLEMENTED_CASE(StringBuilderAppendDouble /* (D)Ljava/lang/StringBuilder; */)
-    UNIMPLEMENTED_CASE(StringBuilderLength /* ()I */)
-    UNIMPLEMENTED_CASE(StringBuilderToString /* ()Ljava/lang/String; */)
-    UNIMPLEMENTED_CASE(UnsafeCASInt /* (Ljava/lang/Object;JII)Z */)
-    UNIMPLEMENTED_CASE(UnsafeCASLong /* (Ljava/lang/Object;JJJ)Z */)
-    UNIMPLEMENTED_CASE(UnsafeCASObject /* (Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z */)
-    UNIMPLEMENTED_CASE(UnsafeGet /* (Ljava/lang/Object;J)I */)
-    UNIMPLEMENTED_CASE(UnsafeGetVolatile /* (Ljava/lang/Object;J)I */)
-    UNIMPLEMENTED_CASE(UnsafeGetObject /* (Ljava/lang/Object;J)Ljava/lang/Object; */)
-    UNIMPLEMENTED_CASE(UnsafeGetObjectVolatile /* (Ljava/lang/Object;J)Ljava/lang/Object; */)
-    UNIMPLEMENTED_CASE(UnsafeGetLong /* (Ljava/lang/Object;J)J */)
-    UNIMPLEMENTED_CASE(UnsafeGetLongVolatile /* (Ljava/lang/Object;J)J */)
-    UNIMPLEMENTED_CASE(UnsafePut /* (Ljava/lang/Object;JI)V */)
-    UNIMPLEMENTED_CASE(UnsafePutOrdered /* (Ljava/lang/Object;JI)V */)
-    UNIMPLEMENTED_CASE(UnsafePutVolatile /* (Ljava/lang/Object;JI)V */)
-    UNIMPLEMENTED_CASE(UnsafePutObject /* (Ljava/lang/Object;JLjava/lang/Object;)V */)
-    UNIMPLEMENTED_CASE(UnsafePutObjectOrdered /* (Ljava/lang/Object;JLjava/lang/Object;)V */)
-    UNIMPLEMENTED_CASE(UnsafePutObjectVolatile /* (Ljava/lang/Object;JLjava/lang/Object;)V */)
-    UNIMPLEMENTED_CASE(UnsafePutLong /* (Ljava/lang/Object;JJ)V */)
-    UNIMPLEMENTED_CASE(UnsafePutLongOrdered /* (Ljava/lang/Object;JJ)V */)
-    UNIMPLEMENTED_CASE(UnsafePutLongVolatile /* (Ljava/lang/Object;JJ)V */)
-    UNIMPLEMENTED_CASE(UnsafeGetAndAddInt /* (Ljava/lang/Object;JI)I */)
-    UNIMPLEMENTED_CASE(UnsafeGetAndAddLong /* (Ljava/lang/Object;JJ)J */)
-    UNIMPLEMENTED_CASE(UnsafeGetAndSetInt /* (Ljava/lang/Object;JI)I */)
-    UNIMPLEMENTED_CASE(UnsafeGetAndSetLong /* (Ljava/lang/Object;JJ)J */)
-    UNIMPLEMENTED_CASE(UnsafeGetAndSetObject /* (Ljava/lang/Object;JLjava/lang/Object;)Ljava/lang/Object; */)
-    UNIMPLEMENTED_CASE(UnsafeLoadFence /* ()V */)
-    UNIMPLEMENTED_CASE(UnsafeStoreFence /* ()V */)
-    UNIMPLEMENTED_CASE(UnsafeFullFence /* ()V */)
-    UNIMPLEMENTED_CASE(JdkUnsafeCASInt /* (Ljava/lang/Object;JII)Z */)
-    UNIMPLEMENTED_CASE(JdkUnsafeCASLong /* (Ljava/lang/Object;JJJ)Z */)
-    UNIMPLEMENTED_CASE(JdkUnsafeCASObject /* (Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z */)
-    UNIMPLEMENTED_CASE(JdkUnsafeCompareAndSetInt /* (Ljava/lang/Object;JII)Z */)
-    UNIMPLEMENTED_CASE(JdkUnsafeCompareAndSetLong /* (Ljava/lang/Object;JJJ)Z */)
-    UNIMPLEMENTED_CASE(JdkUnsafeCompareAndSetObject /* (Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z */)
-    UNIMPLEMENTED_CASE(JdkUnsafeGet /* (Ljava/lang/Object;J)I */)
-    UNIMPLEMENTED_CASE(JdkUnsafeGetVolatile /* (Ljava/lang/Object;J)I */)
-    UNIMPLEMENTED_CASE(JdkUnsafeGetAcquire /* (Ljava/lang/Object;J)I */)
-    UNIMPLEMENTED_CASE(JdkUnsafeGetObject /* (Ljava/lang/Object;J)Ljava/lang/Object; */)
-    UNIMPLEMENTED_CASE(JdkUnsafeGetObjectVolatile /* (Ljava/lang/Object;J)Ljava/lang/Object; */)
-    UNIMPLEMENTED_CASE(JdkUnsafeGetObjectAcquire /* (Ljava/lang/Object;J)Ljava/lang/Object; */)
-    UNIMPLEMENTED_CASE(JdkUnsafeGetLong /* (Ljava/lang/Object;J)J */)
-    UNIMPLEMENTED_CASE(JdkUnsafeGetLongVolatile /* (Ljava/lang/Object;J)J */)
-    UNIMPLEMENTED_CASE(JdkUnsafeGetLongAcquire /* (Ljava/lang/Object;J)J */)
-    UNIMPLEMENTED_CASE(JdkUnsafePut /* (Ljava/lang/Object;JI)V */)
-    UNIMPLEMENTED_CASE(JdkUnsafePutOrdered /* (Ljava/lang/Object;JI)V */)
-    UNIMPLEMENTED_CASE(JdkUnsafePutVolatile /* (Ljava/lang/Object;JI)V */)
-    UNIMPLEMENTED_CASE(JdkUnsafePutRelease /* (Ljava/lang/Object;JI)V */)
-    UNIMPLEMENTED_CASE(JdkUnsafePutObject /* (Ljava/lang/Object;JLjava/lang/Object;)V */)
-    UNIMPLEMENTED_CASE(JdkUnsafePutObjectOrdered /* (Ljava/lang/Object;JLjava/lang/Object;)V */)
-    UNIMPLEMENTED_CASE(JdkUnsafePutObjectVolatile /* (Ljava/lang/Object;JLjava/lang/Object;)V */)
-    UNIMPLEMENTED_CASE(JdkUnsafePutObjectRelease /* (Ljava/lang/Object;JLjava/lang/Object;)V */)
-    UNIMPLEMENTED_CASE(JdkUnsafePutLong /* (Ljava/lang/Object;JJ)V */)
-    UNIMPLEMENTED_CASE(JdkUnsafePutLongOrdered /* (Ljava/lang/Object;JJ)V */)
-    UNIMPLEMENTED_CASE(JdkUnsafePutLongVolatile /* (Ljava/lang/Object;JJ)V */)
-    UNIMPLEMENTED_CASE(JdkUnsafePutLongRelease /* (Ljava/lang/Object;JJ)V */)
-    UNIMPLEMENTED_CASE(JdkUnsafeGetAndAddInt /* (Ljava/lang/Object;JI)I */)
-    UNIMPLEMENTED_CASE(JdkUnsafeGetAndAddLong /* (Ljava/lang/Object;JJ)J */)
-    UNIMPLEMENTED_CASE(JdkUnsafeGetAndSetInt /* (Ljava/lang/Object;JI)I */)
-    UNIMPLEMENTED_CASE(JdkUnsafeGetAndSetLong /* (Ljava/lang/Object;JJ)J */)
-    UNIMPLEMENTED_CASE(JdkUnsafeGetAndSetObject /* (Ljava/lang/Object;JLjava/lang/Object;)Ljava/lang/Object; */)
-    UNIMPLEMENTED_CASE(JdkUnsafeLoadFence /* ()V */)
-    UNIMPLEMENTED_CASE(JdkUnsafeStoreFence /* ()V */)
-    UNIMPLEMENTED_CASE(JdkUnsafeFullFence /* ()V */)
-    UNIMPLEMENTED_CASE(ReferenceGetReferent /* ()Ljava/lang/Object; */)
-    UNIMPLEMENTED_CASE(ReferenceRefersTo /* (Ljava/lang/Object;)Z */)
-    UNIMPLEMENTED_CASE(IntegerValueOf /* (I)Ljava/lang/Integer; */)
-    UNIMPLEMENTED_CASE(ThreadInterrupted /* ()Z */)
-    UNIMPLEMENTED_CASE(CRC32Update /* (II)I */)
-    UNIMPLEMENTED_CASE(CRC32UpdateBytes /* (I[BII)I */)
-    UNIMPLEMENTED_CASE(CRC32UpdateByteBuffer /* (IJII)I */)
-    UNIMPLEMENTED_CASE(FP16Compare /* (SS)I */)
-    UNIMPLEMENTED_CASE(FP16ToFloat /* (S)F */)
-    UNIMPLEMENTED_CASE(FP16ToHalf /* (F)S */)
-    UNIMPLEMENTED_CASE(FP16Floor /* (S)S */)
-    UNIMPLEMENTED_CASE(FP16Ceil /* (S)S */)
-    UNIMPLEMENTED_CASE(FP16Rint /* (S)S */)
-    UNIMPLEMENTED_CASE(FP16Greater /* (SS)Z */)
-    UNIMPLEMENTED_CASE(FP16GreaterEquals /* (SS)Z */)
-    UNIMPLEMENTED_CASE(FP16Less /* (SS)Z */)
-    UNIMPLEMENTED_CASE(FP16LessEquals /* (SS)Z */)
-    UNIMPLEMENTED_CASE(FP16Min /* (SS)S */)
-    UNIMPLEMENTED_CASE(FP16Max /* (SS)S */)
-    INTRINSIC_CASE(VarHandleFullFence)
-    INTRINSIC_CASE(VarHandleAcquireFence)
-    INTRINSIC_CASE(VarHandleReleaseFence)
-    INTRINSIC_CASE(VarHandleLoadLoadFence)
-    INTRINSIC_CASE(VarHandleStoreStoreFence)
-    INTRINSIC_CASE(MethodHandleInvokeExact)
-    INTRINSIC_CASE(MethodHandleInvoke)
-    INTRINSIC_CASE(VarHandleCompareAndExchange)
-    INTRINSIC_CASE(VarHandleCompareAndExchangeAcquire)
-    INTRINSIC_CASE(VarHandleCompareAndExchangeRelease)
-    INTRINSIC_CASE(VarHandleCompareAndSet)
-    INTRINSIC_CASE(VarHandleGet)
-    INTRINSIC_CASE(VarHandleGetAcquire)
-    INTRINSIC_CASE(VarHandleGetAndAdd)
-    INTRINSIC_CASE(VarHandleGetAndAddAcquire)
-    INTRINSIC_CASE(VarHandleGetAndAddRelease)
-    INTRINSIC_CASE(VarHandleGetAndBitwiseAnd)
-    INTRINSIC_CASE(VarHandleGetAndBitwiseAndAcquire)
-    INTRINSIC_CASE(VarHandleGetAndBitwiseAndRelease)
-    INTRINSIC_CASE(VarHandleGetAndBitwiseOr)
-    INTRINSIC_CASE(VarHandleGetAndBitwiseOrAcquire)
-    INTRINSIC_CASE(VarHandleGetAndBitwiseOrRelease)
-    INTRINSIC_CASE(VarHandleGetAndBitwiseXor)
-    INTRINSIC_CASE(VarHandleGetAndBitwiseXorAcquire)
-    INTRINSIC_CASE(VarHandleGetAndBitwiseXorRelease)
-    INTRINSIC_CASE(VarHandleGetAndSet)
-    INTRINSIC_CASE(VarHandleGetAndSetAcquire)
-    INTRINSIC_CASE(VarHandleGetAndSetRelease)
-    INTRINSIC_CASE(VarHandleGetOpaque)
-    INTRINSIC_CASE(VarHandleGetVolatile)
-    INTRINSIC_CASE(VarHandleSet)
-    INTRINSIC_CASE(VarHandleSetOpaque)
-    INTRINSIC_CASE(VarHandleSetRelease)
-    INTRINSIC_CASE(VarHandleSetVolatile)
-    INTRINSIC_CASE(VarHandleWeakCompareAndSet)
-    INTRINSIC_CASE(VarHandleWeakCompareAndSetAcquire)
-    INTRINSIC_CASE(VarHandleWeakCompareAndSetPlain)
-    INTRINSIC_CASE(VarHandleWeakCompareAndSetRelease)
-    case Intrinsics::kNone:
-      res = false;
-      break;
-    // Note: no default case to ensure we catch any newly added intrinsics.
-  }
-  return res;
-}
-
-}  // namespace interpreter
-}  // namespace art
diff --git a/runtime/interpreter/interpreter_intrinsics.h b/runtime/interpreter/interpreter_intrinsics.h
deleted file mode 100644
index 2a23002..0000000
--- a/runtime/interpreter/interpreter_intrinsics.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2017 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_INTERPRETER_INTERPRETER_INTRINSICS_H_
-#define ART_RUNTIME_INTERPRETER_INTERPRETER_INTRINSICS_H_
-
-#include "jvalue.h"
-
-namespace art {
-
-class ArtMethod;
-class Instruction;
-class ShadowFrame;
-
-namespace interpreter {
-
-// Invokes to methods identified as intrinics are routed here.  If there is
-// no interpreter implementation, return false and a normal invoke will proceed.
-bool MterpHandleIntrinsic(ShadowFrame* shadow_frame,
-                          ArtMethod* const called_method,
-                          const Instruction* inst,
-                          uint16_t inst_data,
-                          JValue* result_register);
-
-}  // namespace interpreter
-}  // namespace art
-
-#endif  // ART_RUNTIME_INTERPRETER_INTERPRETER_INTRINSICS_H_
diff --git a/runtime/interpreter/interpreter_switch_impl-inl.h b/runtime/interpreter/interpreter_switch_impl-inl.h
index 62bf7d8..2858daf 100644
--- a/runtime/interpreter/interpreter_switch_impl-inl.h
+++ b/runtime/interpreter/interpreter_switch_impl-inl.h
@@ -353,7 +353,7 @@
 
   template<InvokeType type, bool is_range>
   HANDLER_ATTRIBUTES bool HandleInvoke() {
-    bool success = DoInvoke<type, is_range, do_access_check, /*is_mterp=*/ false>(
+    bool success = DoInvoke<type, is_range, do_access_check>(
         Self(), shadow_frame_, inst_, inst_data_, ResultRegister());
     return PossiblyHandlePendingExceptionOnInvoke(!success);
   }
diff --git a/runtime/interpreter/mterp/nterp.cc b/runtime/interpreter/mterp/nterp.cc
index 17f17af..cc2ec4f 100644
--- a/runtime/interpreter/mterp/nterp.cc
+++ b/runtime/interpreter/mterp/nterp.cc
@@ -26,7 +26,6 @@
 #include "entrypoints/entrypoint_utils-inl.h"
 #include "interpreter/interpreter_cache-inl.h"
 #include "interpreter/interpreter_common.h"
-#include "interpreter/interpreter_intrinsics.h"
 #include "interpreter/shadow_frame-inl.h"
 #include "mirror/string-alloc-inl.h"
 #include "nterp_helpers.h"
@@ -96,13 +95,13 @@
 }
 
 template<typename T>
-inline void UpdateCache(Thread* self, uint16_t* dex_pc_ptr, T value) {
+inline void UpdateCache(Thread* self, const uint16_t* dex_pc_ptr, T value) {
   DCHECK(kUseReadBarrier) << "Nterp only works with read barriers";
   self->GetInterpreterCache()->Set(self, dex_pc_ptr, value);
 }
 
 template<typename T>
-inline void UpdateCache(Thread* self, uint16_t* dex_pc_ptr, T* value) {
+inline void UpdateCache(Thread* self, const uint16_t* dex_pc_ptr, T* value) {
   UpdateCache(self, dex_pc_ptr, reinterpret_cast<size_t>(value));
 }
 
@@ -252,7 +251,7 @@
 }
 
 FLATTEN
-extern "C" size_t NterpGetMethod(Thread* self, ArtMethod* caller, uint16_t* dex_pc_ptr)
+extern "C" size_t NterpGetMethod(Thread* self, ArtMethod* caller, const uint16_t* dex_pc_ptr)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   UpdateHotness(caller);
   const Instruction* inst = Instruction::At(dex_pc_ptr);
diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc
index 75a692e..70948b8 100644
--- a/runtime/interpreter/unstarted_runtime_test.cc
+++ b/runtime/interpreter/unstarted_runtime_test.cc
@@ -420,11 +420,13 @@
   shadow_frame->SetVRegReference(0, reference_empty_string.Get());
   shadow_frame->SetVRegReference(1, string_arg.Get());
 
-  interpreter::DoCall<false, false>(method,
+  ArtMethod* factory = WellKnownClasses::StringInitToStringFactory(method);
+  interpreter::DoCall<false, false>(factory,
                                     self,
                                     *shadow_frame,
                                     Instruction::At(inst_data),
                                     inst_data[0],
+                                    /* string_init= */ true,
                                     &result);
   ObjPtr<mirror::String> string_result = down_cast<mirror::String*>(result.GetL());
   EXPECT_EQ(string_arg->GetLength(), string_result->GetLength());
@@ -1024,6 +1026,7 @@
                                     *shadow_frame,
                                     Instruction::At(inst_data),
                                     inst_data[0],
+                                    /* string_init= */ false,
                                     &result);
   ObjPtr<mirror::String> string_result = down_cast<mirror::String*>(result.GetL());
   ASSERT_TRUE(string_result != nullptr);
@@ -1179,6 +1182,7 @@
                                         *shadow_frame,
                                         Instruction::At(inst_data),
                                         inst_data[0],
+                                        /* string_init= */ false,
                                         &result);
       CHECK(!self->IsExceptionPending());
     }