Remove one template argument to the switch interpreter.

Dynamically check for SkipAccessChecks instead.

arm64 apex goes from 49545216 bytes to 49324032, ~200KB savings.

Test: test.py

Change-Id: Iaa64f56485b15c0e3c0eaa31e469a2795035debe
diff --git a/runtime/Android.bp b/runtime/Android.bp
index f162807..bfe04f3 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -183,8 +183,6 @@
         "interpreter/interpreter_common.cc",
         "interpreter/interpreter_switch_impl0.cc",
         "interpreter/interpreter_switch_impl1.cc",
-        "interpreter/interpreter_switch_impl2.cc",
-        "interpreter/interpreter_switch_impl3.cc",
         "interpreter/lock_count_data.cc",
         "interpreter/shadow_frame.cc",
         "interpreter/unstarted_runtime.cc",
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 7841e3a..dce4066 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -565,8 +565,8 @@
   }
 
   void SetMustCountLocks() REQUIRES_SHARED(Locks::mutator_lock_) {
-    AddAccessFlags(kAccMustCountLocks);
     ClearAccessFlags(kAccSkipAccessChecks);
+    AddAccessFlags(kAccMustCountLocks);
   }
 
   // Returns true if the method is using the nterp entrypoint fast path.
diff --git a/runtime/common_dex_operations.h b/runtime/common_dex_operations.h
index 0b9d3fb..ce2090c 100644
--- a/runtime/common_dex_operations.h
+++ b/runtime/common_dex_operations.h
@@ -175,7 +175,7 @@
   return true;
 }
 
-template<Primitive::Type field_type, bool do_assignability_check, bool transaction_active>
+template<Primitive::Type field_type, bool transaction_active>
 ALWAYS_INLINE bool DoFieldPutCommon(Thread* self,
                                     const ShadowFrame& shadow_frame,
                                     ObjPtr<mirror::Object> obj,
@@ -236,7 +236,7 @@
       break;
     case Primitive::kPrimNot: {
       ObjPtr<mirror::Object> reg = value.GetL();
-      if (do_assignability_check && reg != nullptr) {
+      if (reg != nullptr && !shadow_frame.GetMethod()->SkipAccessChecks()) {
         // FieldHelper::GetType can resolve classes, use a handle wrapper which will restore the
         // object in the destructor.
         ObjPtr<mirror::Class> field_class;
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index cbe7543..4a1dfba 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -289,7 +289,6 @@
 }
 
 
-template <bool kAccessCheck>
 ALWAYS_INLINE
 inline ObjPtr<mirror::Class> CheckArrayAlloc(dex::TypeIndex type_idx,
                                              int32_t component_count,
@@ -311,7 +310,7 @@
     }
     CHECK(klass->IsArrayClass()) << klass->PrettyClass();
   }
-  if (kAccessCheck) {
+  if (!method->SkipAccessChecks()) {
     ObjPtr<mirror::Class> referrer = method->GetDeclaringClass();
     if (UNLIKELY(!referrer->CanAccess(klass))) {
       ThrowIllegalAccessErrorClass(referrer, klass);
@@ -326,7 +325,7 @@
 // it cannot be resolved, throw an error. If it can, use it to create an array.
 // When verification/compiler hasn't been able to verify access, optionally perform an access
 // check.
-template <bool kAccessCheck, bool kInstrumented>
+template <bool kInstrumented>
 ALWAYS_INLINE
 inline ObjPtr<mirror::Array> AllocArrayFromCode(dex::TypeIndex type_idx,
                                                 int32_t component_count,
@@ -334,8 +333,7 @@
                                                 Thread* self,
                                                 gc::AllocatorType allocator_type) {
   bool slow_path = false;
-  ObjPtr<mirror::Class> klass =
-      CheckArrayAlloc<kAccessCheck>(type_idx, component_count, method, &slow_path);
+  ObjPtr<mirror::Class> klass = CheckArrayAlloc(type_idx, component_count, method, &slow_path);
   if (UNLIKELY(slow_path)) {
     if (klass == nullptr) {
       return nullptr;
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index a69b055..ae80352 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -77,7 +77,6 @@
     REQUIRES(!Roles::uninterruptible_);
 
 
-template <bool kAccessCheck>
 ALWAYS_INLINE inline ObjPtr<mirror::Class> CheckArrayAlloc(dex::TypeIndex type_idx,
                                                            int32_t component_count,
                                                            ArtMethod* method,
@@ -89,7 +88,7 @@
 // it cannot be resolved, throw an error. If it can, use it to create an array.
 // When verification/compiler hasn't been able to verify access, optionally perform an access
 // check.
-template <bool kAccessCheck, bool kInstrumented = true>
+template <bool kInstrumented = true>
 ALWAYS_INLINE inline ObjPtr<mirror::Array> AllocArrayFromCode(dex::TypeIndex type_idx,
                                                               int32_t component_count,
                                                               ArtMethod* method,
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 42596d8..0dc8d8b 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -237,21 +237,11 @@
                             JValue result_register,
                             bool interpret_one_instruction) REQUIRES_SHARED(Locks::mutator_lock_) {
   if (Runtime::Current()->IsActiveTransaction()) {
-    if (shadow_frame.GetMethod()->SkipAccessChecks()) {
-      return ExecuteSwitchImpl<false, true>(
-          self, accessor, shadow_frame, result_register, interpret_one_instruction);
-    } else {
-      return ExecuteSwitchImpl<true, true>(
-          self, accessor, shadow_frame, result_register, interpret_one_instruction);
-    }
+    return ExecuteSwitchImpl<true>(
+        self, accessor, shadow_frame, result_register, interpret_one_instruction);
   } else {
-    if (shadow_frame.GetMethod()->SkipAccessChecks()) {
-      return ExecuteSwitchImpl<false, false>(
-          self, accessor, shadow_frame, result_register, interpret_one_instruction);
-    } else {
-      return ExecuteSwitchImpl<true, false>(
-          self, accessor, shadow_frame, result_register, interpret_one_instruction);
-    }
+    return ExecuteSwitchImpl<false>(
+        self, accessor, shadow_frame, result_register, interpret_one_instruction);
   }
 }
 
@@ -311,8 +301,12 @@
         // any value.
         DCHECK(Runtime::Current()->AreNonStandardExitsEnabled());
         JValue ret = JValue();
-        PerformNonStandardReturn<MonitorState::kNoMonitorsLocked>(
-            self, shadow_frame, ret, instrumentation, accessor.InsSize());
+        PerformNonStandardReturn(self,
+                                 shadow_frame,
+                                 ret,
+                                 instrumentation,
+                                 accessor.InsSize(),
+                                 /* unlock_monitors= */ false);
         return ret;
       }
       if (UNLIKELY(self->IsExceptionPending())) {
@@ -322,8 +316,12 @@
         JValue ret = JValue();
         if (UNLIKELY(shadow_frame.GetForcePopFrame())) {
           DCHECK(Runtime::Current()->AreNonStandardExitsEnabled());
-          PerformNonStandardReturn<MonitorState::kNoMonitorsLocked>(
-              self, shadow_frame, ret, instrumentation, accessor.InsSize());
+          PerformNonStandardReturn(self,
+                                   shadow_frame,
+                                   ret,
+                                   instrumentation,
+                                   accessor.InsSize(),
+                                   /* unlock_monitors= */ false);
         }
         return ret;
       }
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 033b4da..7b4923b 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -231,7 +231,7 @@
 // about ALWAYS_INLINE (-Werror, -Wgcc-compat) in definitions.
 //
 
-template <bool is_range, bool do_assignability_check>
+template <bool is_range>
 static ALWAYS_INLINE bool DoCallCommon(ArtMethod* called_method,
                                        Thread* self,
                                        ShadowFrame& shadow_frame,
@@ -1181,8 +1181,7 @@
   }
 }
 
-template <bool is_range,
-          bool do_assignability_check>
+template <bool is_range>
 static inline bool DoCallCommon(ArtMethod* called_method,
                                 Thread* self,
                                 ShadowFrame& shadow_frame,
@@ -1261,7 +1260,7 @@
   ShadowFrame* new_shadow_frame = shadow_frame_unique_ptr.get();
 
   // Initialize new shadow frame by copying the registers from the callee shadow frame.
-  if (do_assignability_check) {
+  if (!shadow_frame.GetMethod()->SkipAccessChecks()) {
     // Slow path.
     // We might need to do class loading, which incurs a thread state change to kNative. So
     // register the shadow frame as under construction and allow suspension again.
@@ -1304,7 +1303,7 @@
         // Handle Object references. 1 virtual register slot.
         case 'L': {
           ObjPtr<mirror::Object> o = shadow_frame.GetVRegReference(src_reg);
-          if (do_assignability_check && o != nullptr) {
+          if (o != nullptr) {
             const dex::TypeIndex type_idx = params->GetTypeItem(shorty_pos).type_idx_;
             ObjPtr<mirror::Class> arg_type = method->GetDexCache()->GetResolvedType(type_idx);
             if (arg_type == nullptr) {
@@ -1378,7 +1377,7 @@
   return !self->IsExceptionPending();
 }
 
-template<bool is_range, bool do_assignability_check>
+template<bool is_range>
 NO_STACK_PROTECTOR
 bool DoCall(ArtMethod* called_method,
             Thread* self,
@@ -1402,7 +1401,7 @@
     inst->GetVarArgs(arg, inst_data);
   }
 
-  return DoCallCommon<is_range, do_assignability_check>(
+  return DoCallCommon<is_range>(
       called_method,
       self,
       shadow_frame,
@@ -1413,7 +1412,7 @@
       is_string_init);
 }
 
-template <bool is_range, bool do_access_check, bool transaction_active>
+template <bool is_range, bool transaction_active>
 bool DoFilledNewArray(const Instruction* inst,
                       const ShadowFrame& shadow_frame,
                       Thread* self,
@@ -1430,6 +1429,7 @@
     return false;
   }
   uint16_t type_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c();
+  bool do_access_check = !shadow_frame.GetMethod()->SkipAccessChecks();
   ObjPtr<mirror::Class> array_class = ResolveVerifyAndClinit(dex::TypeIndex(type_idx),
                                                              shadow_frame.GetMethod(),
                                                              self,
@@ -1534,20 +1534,50 @@
   }
 }
 
+void UnlockHeldMonitors(Thread* self, ShadowFrame* shadow_frame)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  DCHECK(shadow_frame->GetForcePopFrame() || Runtime::Current()->IsTransactionAborted());
+  // Unlock all monitors.
+  if (shadow_frame->GetMethod()->MustCountLocks()) {
+    DCHECK(!shadow_frame->GetMethod()->SkipAccessChecks());
+    // Get the monitors from the shadow-frame monitor-count data.
+    shadow_frame->GetLockCountData().VisitMonitors(
+      [&](mirror::Object** obj) REQUIRES_SHARED(Locks::mutator_lock_) {
+        // Since we don't use the 'obj' pointer after the DoMonitorExit everything should be fine
+        // WRT suspension.
+        DoMonitorExit(self, shadow_frame, *obj);
+      });
+  } else {
+    std::vector<verifier::MethodVerifier::DexLockInfo> locks;
+    verifier::MethodVerifier::FindLocksAtDexPc(shadow_frame->GetMethod(),
+                                               shadow_frame->GetDexPC(),
+                                               &locks,
+                                               Runtime::Current()->GetTargetSdkVersion());
+    for (const auto& reg : locks) {
+      if (UNLIKELY(reg.dex_registers.empty())) {
+        LOG(ERROR) << "Unable to determine reference locked by "
+                   << shadow_frame->GetMethod()->PrettyMethod() << " at pc "
+                   << shadow_frame->GetDexPC();
+      } else {
+        DoMonitorExit(
+            self, shadow_frame, shadow_frame->GetVRegReference(*reg.dex_registers.begin()));
+      }
+    }
+  }
+}
+
 // 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,                                 \
-                                                  ShadowFrame& shadow_frame,                    \
-                                                  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);
-EXPLICIT_DO_CALL_TEMPLATE_DECL(true, false);
-EXPLICIT_DO_CALL_TEMPLATE_DECL(true, true);
+#define EXPLICIT_DO_CALL_TEMPLATE_DECL(_is_range)                      \
+  template REQUIRES_SHARED(Locks::mutator_lock_)                       \
+  bool DoCall<_is_range>(ArtMethod* method,                            \
+                         Thread* self,                                 \
+                         ShadowFrame& shadow_frame,                    \
+                         const Instruction* inst,                      \
+                         uint16_t inst_data,                           \
+                         bool string_init,                             \
+                         JValue* result)
+EXPLICIT_DO_CALL_TEMPLATE_DECL(false);
+EXPLICIT_DO_CALL_TEMPLATE_DECL(true);
 #undef EXPLICIT_DO_CALL_TEMPLATE_DECL
 
 // Explicit DoInvokePolymorphic template function declarations.
@@ -1561,16 +1591,15 @@
 #undef EXPLICIT_DO_INVOKE_POLYMORPHIC_TEMPLATE_DECL
 
 // Explicit DoFilledNewArray template function declarations.
-#define EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(_is_range_, _check, _transaction_active)       \
+#define EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(_is_range_, _transaction_active)               \
   template REQUIRES_SHARED(Locks::mutator_lock_)                                                  \
-  bool DoFilledNewArray<_is_range_, _check, _transaction_active>(const Instruction* inst,         \
-                                                                 const ShadowFrame& shadow_frame, \
-                                                                 Thread* self, JValue* result)
-#define EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL(_transaction_active)       \
-  EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(false, false, _transaction_active);  \
-  EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(false, true, _transaction_active);   \
-  EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(true, false, _transaction_active);   \
-  EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(true, true, _transaction_active)
+  bool DoFilledNewArray<_is_range_, _transaction_active>(const Instruction* inst,                 \
+                                                         const ShadowFrame& shadow_frame,         \
+                                                         Thread* self,                            \
+                                                         JValue* result)
+#define EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL(_transaction_active)                       \
+  EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(false, _transaction_active);                         \
+  EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(true, _transaction_active)
 EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL(false);
 EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL(true);
 #undef EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 35e329c..b8d6817 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -70,7 +70,6 @@
 void ThrowNullPointerExceptionFromInterpreter()
     REQUIRES_SHARED(Locks::mutator_lock_);
 
-template <bool kMonitorCounting>
 static inline void DoMonitorEnter(Thread* self, ShadowFrame* frame, ObjPtr<mirror::Object> ref)
     NO_THREAD_SAFETY_ANALYSIS
     REQUIRES(!Roles::uninterruptible_) {
@@ -84,28 +83,29 @@
     DCHECK(unlocked);
     return;
   }
-  if (kMonitorCounting && frame->GetMethod()->MustCountLocks()) {
+  if (frame->GetMethod()->MustCountLocks()) {
+    DCHECK(!frame->GetMethod()->SkipAccessChecks());
     frame->GetLockCountData().AddMonitor(self, h_ref.Get());
   }
 }
 
-template <bool kMonitorCounting>
 static inline void DoMonitorExit(Thread* self, ShadowFrame* frame, ObjPtr<mirror::Object> ref)
     NO_THREAD_SAFETY_ANALYSIS
     REQUIRES(!Roles::uninterruptible_) {
   StackHandleScope<1> hs(self);
   Handle<mirror::Object> h_ref(hs.NewHandle(ref));
   h_ref->MonitorExit(self);
-  if (kMonitorCounting && frame->GetMethod()->MustCountLocks()) {
+  if (frame->GetMethod()->MustCountLocks()) {
+    DCHECK(!frame->GetMethod()->SkipAccessChecks());
     frame->GetLockCountData().RemoveMonitorOrThrow(self, h_ref.Get());
   }
 }
 
-template <bool kMonitorCounting>
 static inline bool DoMonitorCheckOnExit(Thread* self, ShadowFrame* frame)
     NO_THREAD_SAFETY_ANALYSIS
     REQUIRES(!Roles::uninterruptible_) {
-  if (kMonitorCounting && frame->GetMethod()->MustCountLocks()) {
+  if (frame->GetMethod()->MustCountLocks()) {
+    DCHECK(!frame->GetMethod()->SkipAccessChecks());
     return frame->GetLockCountData().CheckAllMonitorsReleasedOrThrow(self);
   }
   return true;
@@ -124,7 +124,7 @@
 // Invokes the given method. This is part of the invocation support and is used by DoInvoke,
 // DoFastInvoke and DoInvokeVirtualQuick functions.
 // Returns true on success, otherwise throws an exception and returns false.
-template<bool is_range, bool do_assignability_check>
+template<bool is_range>
 bool DoCall(ArtMethod* called_method,
             Thread* self,
             ShadowFrame& shadow_frame,
@@ -157,54 +157,16 @@
   return ins->HasMethodExitListeners() || ins->HasWatchedFramePopListeners();
 }
 
-// NO_INLINE so we won't bloat the interpreter with this very cold lock-release code.
-template <bool kMonitorCounting>
-static NO_INLINE void UnlockHeldMonitors(Thread* self, ShadowFrame* shadow_frame)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  DCHECK(shadow_frame->GetForcePopFrame() ||
-         Runtime::Current()->IsTransactionAborted());
-  // Unlock all monitors.
-  if (kMonitorCounting && shadow_frame->GetMethod()->MustCountLocks()) {
-    // Get the monitors from the shadow-frame monitor-count data.
-    shadow_frame->GetLockCountData().VisitMonitors(
-      [&](mirror::Object** obj) REQUIRES_SHARED(Locks::mutator_lock_) {
-        // Since we don't use the 'obj' pointer after the DoMonitorExit everything should be fine
-        // WRT suspension.
-        DoMonitorExit<kMonitorCounting>(self, shadow_frame, *obj);
-      });
-  } else {
-    std::vector<verifier::MethodVerifier::DexLockInfo> locks;
-    verifier::MethodVerifier::FindLocksAtDexPc(shadow_frame->GetMethod(),
-                                                shadow_frame->GetDexPC(),
-                                                &locks,
-                                                Runtime::Current()->GetTargetSdkVersion());
-    for (const auto& reg : locks) {
-      if (UNLIKELY(reg.dex_registers.empty())) {
-        LOG(ERROR) << "Unable to determine reference locked by "
-                    << shadow_frame->GetMethod()->PrettyMethod() << " at pc "
-                    << shadow_frame->GetDexPC();
-      } else {
-        DoMonitorExit<kMonitorCounting>(
-            self, shadow_frame, shadow_frame->GetVRegReference(*reg.dex_registers.begin()));
-      }
-    }
-  }
-}
+COLD_ATTR void UnlockHeldMonitors(Thread* self, ShadowFrame* shadow_frame)
+    REQUIRES_SHARED(Locks::mutator_lock_);
 
-enum class MonitorState {
-  kNoMonitorsLocked,
-  kCountingMonitors,
-  kNormalMonitors,
-};
-
-template<MonitorState kMonitorState>
 static inline ALWAYS_INLINE void PerformNonStandardReturn(
       Thread* self,
       ShadowFrame& frame,
       JValue& result,
       const instrumentation::Instrumentation* instrumentation,
-      uint16_t num_dex_inst) REQUIRES_SHARED(Locks::mutator_lock_) {
-  static constexpr bool kMonitorCounting = (kMonitorState == MonitorState::kCountingMonitors);
+      uint16_t num_dex_inst,
+      bool unlock_monitors = true) REQUIRES_SHARED(Locks::mutator_lock_) {
   ObjPtr<mirror::Object> thiz(frame.GetThisObject(num_dex_inst));
   StackHandleScope<1u> hs(self);
   if (UNLIKELY(self->IsExceptionPending())) {
@@ -212,10 +174,10 @@
                  << self->GetException()->Dump();
     self->ClearException();
   }
-  if (kMonitorState != MonitorState::kNoMonitorsLocked) {
-    UnlockHeldMonitors<kMonitorCounting>(self, &frame);
+  if (unlock_monitors) {
+    UnlockHeldMonitors(self, &frame);
+    DoMonitorCheckOnExit(self, &frame);
   }
-  DoMonitorCheckOnExit<kMonitorCounting>(self, &frame);
   result = JValue();
   if (UNLIKELY(NeedsMethodExitEvent(instrumentation))) {
     SendMethodExitEvents(self, instrumentation, frame, frame.GetMethod(), result);
@@ -224,7 +186,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>
+template<InvokeType type, bool is_range>
 static ALWAYS_INLINE bool DoInvoke(Thread* self,
                                    ShadowFrame& shadow_frame,
                                    const Instruction* inst,
@@ -247,7 +209,7 @@
     return false;
   }
 
-  return DoCall<is_range, do_access_check>(
+  return DoCall<is_range>(
       called_method, self, shadow_frame, inst, inst_data, string_init, result);
 }
 
@@ -393,7 +355,6 @@
 // Returns true on success, otherwise throws an exception and returns false.
 template<FindFieldType find_type,
          Primitive::Type field_type,
-         bool do_access_check,
          bool transaction_active = false>
 ALWAYS_INLINE bool DoFieldGet(Thread* self,
                               ShadowFrame& shadow_frame,
@@ -517,15 +478,13 @@
 
 // Handles iput-XXX and sput-XXX instructions.
 // Returns true on success, otherwise throws an exception and returns false.
-template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check,
-         bool transaction_active>
+template<FindFieldType find_type, Primitive::Type field_type, bool transaction_active>
 ALWAYS_INLINE bool DoFieldPut(Thread* self,
                               const ShadowFrame& shadow_frame,
                               const Instruction* inst,
                               uint16_t inst_data)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   bool should_report = Runtime::Current()->GetInstrumentation()->HasFieldWriteListeners();
-  const bool do_assignability_check = do_access_check;
   bool is_static = (find_type == StaticObjectWrite) || (find_type == StaticPrimitiveWrite);
   uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
   bool resolve_field_type = (shadow_frame.GetVRegReference(vregA) != nullptr);
@@ -578,11 +537,11 @@
     return false;
   }
   if (should_report) {
-    return DoFieldPutCommon<field_type, do_assignability_check, transaction_active>(self,
-                                                                                    shadow_frame,
-                                                                                    obj,
-                                                                                    field,
-                                                                                    value);
+    return DoFieldPutCommon<field_type, transaction_active>(self,
+                                                            shadow_frame,
+                                                            obj,
+                                                            field,
+                                                            value);
   }
 #define FIELD_SET(prim, type, jtype) \
   case Primitive::kPrim ## prim: \
@@ -717,13 +676,16 @@
 
 // Handles filled-new-array and filled-new-array-range instructions.
 // Returns true on success, otherwise throws an exception and returns false.
-template <bool is_range, bool do_access_check, bool transaction_active>
-bool DoFilledNewArray(const Instruction* inst, const ShadowFrame& shadow_frame,
-                      Thread* self, JValue* result);
+template <bool is_range, bool transaction_active>
+bool DoFilledNewArray(const Instruction* inst,
+                      const ShadowFrame& shadow_frame,
+                      Thread* self,
+                      JValue* result);
 
 // Handles packed-switch instruction.
 // Returns the branch offset to the next instruction to execute.
-static inline int32_t DoPackedSwitch(const Instruction* inst, const ShadowFrame& shadow_frame,
+static inline int32_t DoPackedSwitch(const Instruction* inst,
+                                     const ShadowFrame& shadow_frame,
                                      uint16_t inst_data)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   DCHECK(inst->Opcode() == Instruction::PACKED_SWITCH);
diff --git a/runtime/interpreter/interpreter_switch_impl-inl.h b/runtime/interpreter/interpreter_switch_impl-inl.h
index 215194e..ddde26d 100644
--- a/runtime/interpreter/interpreter_switch_impl-inl.h
+++ b/runtime/interpreter/interpreter_switch_impl-inl.h
@@ -50,7 +50,7 @@
 // The function names must match the names from dex_instruction_list.h and have no arguments.
 // Return value: The handlers must return false if the instruction throws or returns (exits).
 //
-template<bool do_access_check, bool transaction_active, Instruction::Format kFormat>
+template<bool transaction_active, Instruction::Format kFormat>
 class InstructionHandler {
  public:
 #define HANDLER_ATTRIBUTES ALWAYS_INLINE FLATTEN WARN_UNUSED REQUIRES_SHARED(Locks::mutator_lock_)
@@ -64,7 +64,7 @@
       DCHECK(abort_exception != nullptr);
       DCHECK(abort_exception->GetClass()->DescriptorEquals(Transaction::kAbortExceptionDescriptor));
       Self()->ClearException();
-      PerformNonStandardReturn<kMonitorState>(
+      PerformNonStandardReturn(
           Self(), shadow_frame_, ctx_->result, Instrumentation(), Accessor().InsSize());
       Self()->SetException(abort_exception.Get());
       ExitInterpreterLoop();
@@ -76,7 +76,7 @@
   HANDLER_ATTRIBUTES bool CheckForceReturn() {
     if (shadow_frame_.GetForcePopFrame()) {
       DCHECK(Runtime::Current()->AreNonStandardExitsEnabled());
-      PerformNonStandardReturn<kMonitorState>(
+      PerformNonStandardReturn(
           Self(), shadow_frame_, ctx_->result, Instrumentation(), Accessor().InsSize());
       ExitInterpreterLoop();
       return false;
@@ -100,7 +100,7 @@
                                 /* skip_listeners= */ skip_event,
                                 /* skip_throw_listener= */ skip_event)) {
       // Structured locking is to be enforced for abnormal termination, too.
-      DoMonitorCheckOnExit<do_assignability_check>(Self(), &shadow_frame_);
+      DoMonitorCheckOnExit(Self(), &shadow_frame_);
       ctx_->result = JValue(); /* Handled in caller. */
       ExitInterpreterLoop();
       return false;  // Return to caller.
@@ -204,7 +204,7 @@
 
   HANDLER_ATTRIBUTES bool HandleReturn(JValue result) {
     Self()->AllowThreadSuspension();
-    if (!DoMonitorCheckOnExit<do_assignability_check>(Self(), &shadow_frame_)) {
+    if (!DoMonitorCheckOnExit(Self(), &shadow_frame_)) {
       return false;
     }
     if (UNLIKELY(NeedsMethodExitEvent(Instrumentation()) &&
@@ -341,19 +341,19 @@
 
   template<FindFieldType find_type, Primitive::Type field_type>
   HANDLER_ATTRIBUTES bool HandleGet() {
-    return DoFieldGet<find_type, field_type, do_access_check, transaction_active>(
+    return DoFieldGet<find_type, field_type, transaction_active>(
         Self(), shadow_frame_, inst_, inst_data_);
   }
 
   template<FindFieldType find_type, Primitive::Type field_type>
   HANDLER_ATTRIBUTES bool HandlePut() {
-    return DoFieldPut<find_type, field_type, do_access_check, transaction_active>(
+    return DoFieldPut<find_type, field_type, transaction_active>(
         Self(), shadow_frame_, inst_, inst_data_);
   }
 
   template<InvokeType type, bool is_range>
   HANDLER_ATTRIBUTES bool HandleInvoke() {
-    bool success = DoInvoke<type, is_range, do_access_check>(
+    bool success = DoInvoke<type, is_range>(
         Self(), shadow_frame_, inst_, inst_data_, ResultRegister());
     return PossiblyHandlePendingExceptionOnInvoke(!success);
   }
@@ -457,12 +457,12 @@
   HANDLER_ATTRIBUTES bool RETURN_OBJECT() {
     JValue result;
     Self()->AllowThreadSuspension();
-    if (!DoMonitorCheckOnExit<do_assignability_check>(Self(), &shadow_frame_)) {
+    if (!DoMonitorCheckOnExit(Self(), &shadow_frame_)) {
       return false;
     }
     const size_t ref_idx = A();
     ObjPtr<mirror::Object> obj_result = GetVRegReference(ref_idx);
-    if (do_assignability_check && obj_result != nullptr) {
+    if (obj_result != nullptr && UNLIKELY(DoAssignabilityChecks())) {
       ObjPtr<mirror::Class> return_type = shadow_frame_.GetMethod()->ResolveReturnType();
       // Re-load since it might have moved.
       obj_result = GetVRegReference(ref_idx);
@@ -481,22 +481,23 @@
         return false;  // Pending exception.
       }
     }
-    StackHandleScope<1> hs(Self());
-    MutableHandle<mirror::Object> h_result(hs.NewHandle(obj_result));
     result.SetL(obj_result);
-    if (UNLIKELY(NeedsMethodExitEvent(Instrumentation()) &&
-                 !SendMethodExitEvents(Self(),
-                                       Instrumentation(),
-                                       shadow_frame_,
-                                       shadow_frame_.GetMethod(),
-                                       h_result))) {
-      DCHECK(Self()->IsExceptionPending());
-      // Do not raise exception event if it is caused by other instrumentation event.
-      shadow_frame_.SetSkipNextExceptionEvent(true);
-      return false;  // Pending exception.
+    if (UNLIKELY(NeedsMethodExitEvent(Instrumentation()))) {
+      StackHandleScope<1> hs(Self());
+      MutableHandle<mirror::Object> h_result(hs.NewHandle(obj_result));
+      if (!SendMethodExitEvents(Self(),
+                                Instrumentation(),
+                                shadow_frame_,
+                                shadow_frame_.GetMethod(),
+                                h_result)) {
+        DCHECK(Self()->IsExceptionPending());
+        // Do not raise exception event if it is caused by other instrumentation event.
+        shadow_frame_.SetSkipNextExceptionEvent(true);
+        return false;  // Pending exception.
+      }
+      // Re-load since it might have moved or been replaced during the MethodExitEvent.
+      result.SetL(h_result.Get());
     }
-    // Re-load since it might have moved or been replaced during the MethodExitEvent.
-    result.SetL(h_result.Get());
     ctx_->result = result;
     ExitInterpreterLoop();
     return false;
@@ -551,11 +552,12 @@
   }
 
   HANDLER_ATTRIBUTES bool CONST_CLASS() {
-    ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(B()),
-                                                     shadow_frame_.GetMethod(),
-                                                     Self(),
-                                                     false,
-                                                     do_access_check);
+    ObjPtr<mirror::Class> c =
+        ResolveVerifyAndClinit(dex::TypeIndex(B()),
+                               shadow_frame_.GetMethod(),
+                               Self(),
+                               false,
+                               !shadow_frame_.GetMethod()->SkipAccessChecks());
     if (UNLIKELY(c == nullptr)) {
       return false;  // Pending exception.
     }
@@ -596,7 +598,7 @@
       ThrowNullPointerExceptionFromInterpreter();
       return false;  // Pending exception.
     }
-    DoMonitorEnter<do_assignability_check>(Self(), &shadow_frame_, obj);
+    DoMonitorEnter(Self(), &shadow_frame_, obj);
     return !Self()->IsExceptionPending();
   }
 
@@ -609,16 +611,17 @@
       ThrowNullPointerExceptionFromInterpreter();
       return false;  // Pending exception.
     }
-    DoMonitorExit<do_assignability_check>(Self(), &shadow_frame_, obj);
+    DoMonitorExit(Self(), &shadow_frame_, obj);
     return !Self()->IsExceptionPending();
   }
 
   HANDLER_ATTRIBUTES bool CHECK_CAST() {
-    ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(B()),
-                                                     shadow_frame_.GetMethod(),
-                                                     Self(),
-                                                     false,
-                                                     do_access_check);
+    ObjPtr<mirror::Class> c =
+        ResolveVerifyAndClinit(dex::TypeIndex(B()),
+                               shadow_frame_.GetMethod(),
+                               Self(),
+                               false,
+                               !shadow_frame_.GetMethod()->SkipAccessChecks());
     if (UNLIKELY(c == nullptr)) {
       return false;  // Pending exception.
     }
@@ -631,11 +634,12 @@
   }
 
   HANDLER_ATTRIBUTES bool INSTANCE_OF() {
-    ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(C()),
-                                                     shadow_frame_.GetMethod(),
-                                                     Self(),
-                                                     false,
-                                                     do_access_check);
+    ObjPtr<mirror::Class> c =
+        ResolveVerifyAndClinit(dex::TypeIndex(C()),
+                               shadow_frame_.GetMethod(),
+                               Self(),
+                               false,
+                               !shadow_frame_.GetMethod()->SkipAccessChecks());
     if (UNLIKELY(c == nullptr)) {
       return false;  // Pending exception.
     }
@@ -656,11 +660,12 @@
 
   HANDLER_ATTRIBUTES bool NEW_INSTANCE() {
     ObjPtr<mirror::Object> obj = nullptr;
-    ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(B()),
-                                                     shadow_frame_.GetMethod(),
-                                                     Self(),
-                                                     false,
-                                                     do_access_check);
+    ObjPtr<mirror::Class> c =
+        ResolveVerifyAndClinit(dex::TypeIndex(B()),
+                               shadow_frame_.GetMethod(),
+                               Self(),
+                               false,
+                               !shadow_frame_.GetMethod()->SkipAccessChecks());
     if (LIKELY(c != nullptr)) {
       // Don't allow finalizable objects to be allocated during a transaction since these can't
       // be finalized without a started runtime.
@@ -687,7 +692,7 @@
 
   HANDLER_ATTRIBUTES bool NEW_ARRAY() {
     int32_t length = GetVReg(B());
-    ObjPtr<mirror::Object> obj = AllocArrayFromCode<do_access_check>(
+    ObjPtr<mirror::Object> obj = AllocArrayFromCode(
         dex::TypeIndex(C()),
         length,
         shadow_frame_.GetMethod(),
@@ -701,12 +706,12 @@
   }
 
   HANDLER_ATTRIBUTES bool FILLED_NEW_ARRAY() {
-    return DoFilledNewArray<false, do_access_check, transaction_active>(
+    return DoFilledNewArray<false, transaction_active>(
         inst_, shadow_frame_, Self(), ResultRegister());
   }
 
   HANDLER_ATTRIBUTES bool FILLED_NEW_ARRAY_RANGE() {
-    return DoFilledNewArray<true, do_access_check, transaction_active>(
+    return DoFilledNewArray<true, transaction_active>(
         inst_, shadow_frame_, Self(), ResultRegister());
   }
 
@@ -731,7 +736,7 @@
     ObjPtr<mirror::Object> exception = GetVRegReference(A());
     if (UNLIKELY(exception == nullptr)) {
       ThrowNullPointerException();
-    } else if (do_assignability_check && !exception->GetClass()->IsThrowableClass()) {
+    } else if (DoAssignabilityChecks() && !exception->GetClass()->IsThrowableClass()) {
       // This should never happen.
       std::string temp;
       Self()->ThrowNewExceptionF("Ljava/lang/InternalError;",
@@ -1741,9 +1746,9 @@
   }
 
  private:
-  static constexpr bool do_assignability_check = do_access_check;
-  static constexpr MonitorState kMonitorState =
-      do_assignability_check ? MonitorState::kCountingMonitors : MonitorState::kNormalMonitors;
+  bool DoAssignabilityChecks() const REQUIRES_SHARED(Locks::mutator_lock_) {
+    return !shadow_frame_.GetMethod()->SkipAccessChecks();
+  }
 
   ALWAYS_INLINE const CodeItemDataAccessor& Accessor() { return ctx_->accessor; }
   ALWAYS_INLINE const uint16_t* Insns() { return ctx_->accessor.Insns(); }
@@ -1815,7 +1820,7 @@
 #endif
 
 #define OPCODE_CASE(OPCODE, OPCODE_NAME, NAME, FORMAT, i, a, e, v)                                \
-template<bool do_access_check, bool transaction_active>                                           \
+template<bool transaction_active>                                                                 \
 ASAN_NO_INLINE NO_STACK_PROTECTOR static bool OP_##OPCODE_NAME(                                   \
     SwitchImplContext* ctx,                                                                       \
     const instrumentation::Instrumentation* instrumentation,                                      \
@@ -1826,14 +1831,14 @@
     uint16_t inst_data,                                                                           \
     const Instruction*& next,                                                                     \
     bool& exit) REQUIRES_SHARED(Locks::mutator_lock_) {                                           \
-  InstructionHandler<do_access_check, transaction_active, Instruction::FORMAT> handler(           \
+  InstructionHandler<transaction_active, Instruction::FORMAT> handler(                            \
       ctx, instrumentation, self, shadow_frame, dex_pc, inst, inst_data, next, exit);             \
   return LIKELY(handler.OPCODE_NAME());                                                           \
 }
 DEX_INSTRUCTION_LIST(OPCODE_CASE)
 #undef OPCODE_CASE
 
-template<bool do_access_check, bool transaction_active>
+template<bool transaction_active>
 NO_STACK_PROTECTOR
 void ExecuteSwitchImplCpp(SwitchImplContext* ctx) {
   Thread* self = ctx->self;
@@ -1858,7 +1863,7 @@
     uint16_t inst_data = inst->Fetch16(0);
     bool exit = false;
     bool success;  // Moved outside to keep frames small under asan.
-    if (InstructionHandler<do_access_check, transaction_active, Instruction::kInvalidFormat>(
+    if (InstructionHandler<transaction_active, Instruction::kInvalidFormat>(
             ctx, instrumentation, self, shadow_frame, dex_pc, inst, inst_data, next, exit).
             Preamble()) {
       DCHECK_EQ(self->IsExceptionPending(), inst->Opcode(inst_data) == Instruction::MOVE_EXCEPTION);
@@ -1866,7 +1871,7 @@
 #define OPCODE_CASE(OPCODE, OPCODE_NAME, NAME, FORMAT, i, a, e, v)                                \
         case OPCODE: {                                                                            \
           next = inst->RelativeAt(Instruction::SizeInCodeUnits(Instruction::FORMAT));             \
-          success = OP_##OPCODE_NAME<do_access_check, transaction_active>(                        \
+          success = OP_##OPCODE_NAME<transaction_active>(                                         \
               ctx, instrumentation, self, shadow_frame, dex_pc, inst, inst_data, next, exit);     \
           if (success && LIKELY(!interpret_one_instruction)) {                                    \
             continue;                                                                             \
@@ -1882,7 +1887,7 @@
       return;  // Return statement or debugger forced exit.
     }
     if (self->IsExceptionPending()) {
-      if (!InstructionHandler<do_access_check, transaction_active, Instruction::kInvalidFormat>(
+      if (!InstructionHandler<transaction_active, Instruction::kInvalidFormat>(
               ctx, instrumentation, self, shadow_frame, dex_pc, inst, inst_data, next, exit).
               HandlePendingException()) {
         shadow_frame.SetDexPC(dex::kDexNoIndex);
diff --git a/runtime/interpreter/interpreter_switch_impl.h b/runtime/interpreter/interpreter_switch_impl.h
index d4dca11..3a42c21 100644
--- a/runtime/interpreter/interpreter_switch_impl.h
+++ b/runtime/interpreter/interpreter_switch_impl.h
@@ -45,7 +45,7 @@
 };
 
 // The actual internal implementation of the switch interpreter.
-template<bool do_access_check, bool transaction_active>
+template<bool transaction_active>
 void ExecuteSwitchImplCpp(SwitchImplContext* ctx)
   REQUIRES_SHARED(Locks::mutator_lock_);
 
@@ -55,9 +55,11 @@
   REQUIRES_SHARED(Locks::mutator_lock_);
 
 // Wrapper around the switch interpreter which ensures we can unwind through it.
-template<bool do_access_check, bool transaction_active>
-ALWAYS_INLINE JValue ExecuteSwitchImpl(Thread* self, const CodeItemDataAccessor& accessor,
-                                       ShadowFrame& shadow_frame, JValue result_register,
+template<bool transaction_active>
+ALWAYS_INLINE JValue ExecuteSwitchImpl(Thread* self,
+                                       const CodeItemDataAccessor& accessor,
+                                       ShadowFrame& shadow_frame,
+                                       JValue result_register,
                                        bool interpret_one_instruction)
   REQUIRES_SHARED(Locks::mutator_lock_) {
   SwitchImplContext ctx {
@@ -68,7 +70,7 @@
     .interpret_one_instruction = interpret_one_instruction,
     .result = JValue(),
   };
-  void* impl = reinterpret_cast<void*>(&ExecuteSwitchImplCpp<do_access_check, transaction_active>);
+  void* impl = reinterpret_cast<void*>(&ExecuteSwitchImplCpp<transaction_active>);
   const uint16_t* dex_pc = ctx.accessor.Insns();
   ExecuteSwitchImplAsm(&ctx, impl, dex_pc);
   return ctx.result;
diff --git a/runtime/interpreter/interpreter_switch_impl0.cc b/runtime/interpreter/interpreter_switch_impl0.cc
index 00159ec..b4e5f50 100644
--- a/runtime/interpreter/interpreter_switch_impl0.cc
+++ b/runtime/interpreter/interpreter_switch_impl0.cc
@@ -24,7 +24,7 @@
 
 // Explicit definition of ExecuteSwitchImplCpp.
 template HOT_ATTR
-void ExecuteSwitchImplCpp<false, false>(SwitchImplContext* ctx);
+void ExecuteSwitchImplCpp<false>(SwitchImplContext* ctx);
 
 }  // namespace interpreter
 }  // namespace art
diff --git a/runtime/interpreter/interpreter_switch_impl1.cc b/runtime/interpreter/interpreter_switch_impl1.cc
index 3a86765..f8f9fcc 100644
--- a/runtime/interpreter/interpreter_switch_impl1.cc
+++ b/runtime/interpreter/interpreter_switch_impl1.cc
@@ -24,7 +24,7 @@
 
 // Explicit definition of ExecuteSwitchImplCpp.
 template
-void ExecuteSwitchImplCpp<false, true>(SwitchImplContext* ctx);
+void ExecuteSwitchImplCpp<true>(SwitchImplContext* ctx);
 
 }  // namespace interpreter
 }  // namespace art
diff --git a/runtime/interpreter/interpreter_switch_impl2.cc b/runtime/interpreter/interpreter_switch_impl2.cc
deleted file mode 100644
index c2739c1..0000000
--- a/runtime/interpreter/interpreter_switch_impl2.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-// The interpreter function takes considerable time to compile and link.
-// We compile the explicit definitions separately to speed up the build.
-
-#include "interpreter_switch_impl-inl.h"
-
-namespace art {
-namespace interpreter {
-
-// Explicit definition of ExecuteSwitchImplCpp.
-template HOT_ATTR
-void ExecuteSwitchImplCpp<true, false>(SwitchImplContext* ctx);
-
-}  // namespace interpreter
-}  // namespace art
diff --git a/runtime/interpreter/interpreter_switch_impl3.cc b/runtime/interpreter/interpreter_switch_impl3.cc
deleted file mode 100644
index 808e4bc..0000000
--- a/runtime/interpreter/interpreter_switch_impl3.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-// The interpreter function takes considerable time to compile and link.
-// We compile the explicit definitions separately to speed up the build.
-
-#include "interpreter_switch_impl-inl.h"
-
-namespace art {
-namespace interpreter {
-
-// Explicit definition of ExecuteSwitchImplCpp.
-template
-void ExecuteSwitchImplCpp<true, true>(SwitchImplContext* ctx);
-
-}  // namespace interpreter
-}  // namespace art
diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc
index dfda20a..3227ef7 100644
--- a/runtime/interpreter/unstarted_runtime_test.cc
+++ b/runtime/interpreter/unstarted_runtime_test.cc
@@ -415,13 +415,13 @@
   shadow_frame->SetVRegReference(1, string_arg.Get());
 
   ArtMethod* factory = WellKnownClasses::StringInitToStringFactory(method);
-  interpreter::DoCall<false, false>(factory,
-                                    self,
-                                    *shadow_frame,
-                                    Instruction::At(inst_data),
-                                    inst_data[0],
-                                    /* string_init= */ true,
-                                    &result);
+  interpreter::DoCall<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());
 
@@ -1015,13 +1015,13 @@
   UniqueDeoptShadowFramePtr shadow_frame = CreateShadowFrame(10, method, 0);
 
   shadow_frame->SetVRegDouble(0, 1.23);
-  interpreter::DoCall<false, false>(method,
-                                    self,
-                                    *shadow_frame,
-                                    Instruction::At(inst_data),
-                                    inst_data[0],
-                                    /* string_init= */ false,
-                                    &result);
+  interpreter::DoCall<false>(method,
+                             self,
+                             *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);
 
@@ -1173,13 +1173,13 @@
       // create instruction data for invoke-direct {v0} of method with fake index
       uint16_t inst_data[3] = { 0x1070, 0x0000, 0x0010 };
 
-      interpreter::DoCall<false, false>(boot_cp_init,
-                                        self,
-                                        *shadow_frame,
-                                        Instruction::At(inst_data),
-                                        inst_data[0],
-                                        /* string_init= */ false,
-                                        &result);
+      interpreter::DoCall<false>(boot_cp_init,
+                                 self,
+                                 *shadow_frame,
+                                 Instruction::At(inst_data),
+                                 inst_data[0],
+                                 /* string_init= */ false,
+                                 &result);
       CHECK(!self->IsExceptionPending());
     }
 
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index 059a33f..c8c6ef9 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -551,31 +551,30 @@
                                  JValue& value) REQUIRES_SHARED(Locks::mutator_lock_) {
   DCHECK(!Runtime::Current()->IsActiveTransaction());
   static const bool kTransaction = false;         // Not in a transaction.
-  static const bool kAssignabilityCheck = false;  // No access check.
   switch (field_type) {
     case Primitive::kPrimBoolean:
       return
-          DoFieldPutCommon<Primitive::kPrimBoolean, kAssignabilityCheck, kTransaction>(
+          DoFieldPutCommon<Primitive::kPrimBoolean, kTransaction>(
               self, shadow_frame, obj, field, value);
     case Primitive::kPrimByte:
-      return DoFieldPutCommon<Primitive::kPrimByte, kAssignabilityCheck, kTransaction>(
+      return DoFieldPutCommon<Primitive::kPrimByte, kTransaction>(
           self, shadow_frame, obj, field, value);
     case Primitive::kPrimChar:
-      return DoFieldPutCommon<Primitive::kPrimChar, kAssignabilityCheck, kTransaction>(
+      return DoFieldPutCommon<Primitive::kPrimChar, kTransaction>(
           self, shadow_frame, obj, field, value);
     case Primitive::kPrimShort:
-      return DoFieldPutCommon<Primitive::kPrimShort, kAssignabilityCheck, kTransaction>(
+      return DoFieldPutCommon<Primitive::kPrimShort, kTransaction>(
           self, shadow_frame, obj, field, value);
     case Primitive::kPrimInt:
     case Primitive::kPrimFloat:
-      return DoFieldPutCommon<Primitive::kPrimInt, kAssignabilityCheck, kTransaction>(
+      return DoFieldPutCommon<Primitive::kPrimInt, kTransaction>(
           self, shadow_frame, obj, field, value);
     case Primitive::kPrimLong:
     case Primitive::kPrimDouble:
-      return DoFieldPutCommon<Primitive::kPrimLong, kAssignabilityCheck, kTransaction>(
+      return DoFieldPutCommon<Primitive::kPrimLong, kTransaction>(
           self, shadow_frame, obj, field, value);
     case Primitive::kPrimNot:
-      return DoFieldPutCommon<Primitive::kPrimNot, kAssignabilityCheck, kTransaction>(
+      return DoFieldPutCommon<Primitive::kPrimNot, kTransaction>(
           self, shadow_frame, obj, field, value);
     case Primitive::kPrimVoid:
       LOG(FATAL) << "Unreachable: " << field_type;