Move some fast invoke checks to CanUseMterp

This speeds up arm64 golem interpreter benchmarks by 1.5%.

Test: test.py -b -r --interpreter --host
Change-Id: Ia9d7c885cd488de56c6b726373072070b509bdf1
diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h
index b3fae25..3bd4fb5 100644
--- a/runtime/instrumentation.h
+++ b/runtime/instrumentation.h
@@ -384,15 +384,6 @@
         have_exception_handled_listeners_;
   }
 
-  // Any instrumentation *other* than what is needed for Jit profiling active?
-  bool NonJitProfilingActive() const REQUIRES_SHARED(Locks::mutator_lock_) {
-    return have_dex_pc_listeners_ || have_method_exit_listeners_ ||
-        have_field_read_listeners_ || have_field_write_listeners_ ||
-        have_exception_thrown_listeners_ || have_method_unwind_listeners_ ||
-        have_branch_listeners_ || have_watched_frame_pop_listeners_ ||
-        have_exception_handled_listeners_;
-  }
-
   // Inform listeners that a method has been entered. A dex PC is provided as we may install
   // listeners into executing code and get method enter events for methods already on the stack.
   void MethodEnterEvent(Thread* thread, mirror::Object* this_object,
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index b37a278..5784b9b 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -248,6 +248,14 @@
     bool from_deoptimize = false) REQUIRES_SHARED(Locks::mutator_lock_) {
   DCHECK(!shadow_frame.GetMethod()->IsAbstract());
   DCHECK(!shadow_frame.GetMethod()->IsNative());
+
+  // Check that we are using the right interpreter.
+  if (kIsDebugBuild && self->UseMterp() != CanUseMterp()) {
+    // The flag might be currently being updated on all threads. Retry with lock.
+    MutexLock tll_mu(self, *Locks::thread_list_lock_);
+    DCHECK_EQ(self->UseMterp(), CanUseMterp());
+  }
+
   if (LIKELY(!from_deoptimize)) {  // Entering the method, but not via deoptimization.
     if (kIsDebugBuild) {
       CHECK_EQ(shadow_frame.GetDexPC(), 0u);
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 96588c8..9924aa5 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -128,10 +128,8 @@
 static ALWAYS_INLINE bool UseInterpreterToInterpreterFastPath(ArtMethod* method)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   Runtime* runtime = Runtime::Current();
-  if (!runtime->IsStarted()) {
-    return false;
-  }
   const void* quick_code = method->GetEntryPointFromQuickCompiledCode();
+  DCHECK(runtime->IsStarted());
   if (!runtime->GetClassLinker()->IsQuickToInterpreterBridge(quick_code)) {
     return false;
   }
@@ -144,16 +142,11 @@
   if (type == kStatic && !method->GetDeclaringClass()->IsInitialized()) {
     return false;
   }
-  if (runtime->IsActiveTransaction() || runtime->GetInstrumentation()->HasMethodEntryListeners()) {
-    return false;
-  }
+  DCHECK(!runtime->IsActiveTransaction());
   ProfilingInfo* profiling_info = method->GetProfilingInfo(kRuntimePointerSize);
   if ((profiling_info != nullptr) && (profiling_info->GetSavedEntryPoint() != nullptr)) {
     return false;
   }
-  if (runtime->GetJit() != nullptr && runtime->GetJit()->JitAtFirstUse()) {
-    return false;
-  }
   return true;
 }
 
@@ -171,7 +164,9 @@
                                    JValue* result)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   // Make sure to check for async exceptions before anything else.
-  if (UNLIKELY(self->ObserveAsyncException())) {
+  if (is_mterp && self->UseMterp()) {
+    DCHECK(!self->ObserveAsyncException());
+  } else if (UNLIKELY(self->ObserveAsyncException())) {
     return false;
   }
   const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
@@ -229,7 +224,7 @@
     }
   }
 
-  if (is_mterp && UseInterpreterToInterpreterFastPath<type>(called_method)) {
+  if (is_mterp && self->UseMterp() && UseInterpreterToInterpreterFastPath<type>(called_method)) {
     const uint16_t number_of_inputs =
         (is_range) ? inst->VRegA_3rc(inst_data) : inst->VRegA_35c(inst_data);
     CodeItemDataAccessor accessor(called_method->DexInstructionData());
diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc
index 4b6f430..ba109bc 100644
--- a/runtime/interpreter/mterp/mterp.cc
+++ b/runtime/interpreter/mterp/mterp.cc
@@ -146,15 +146,18 @@
     REQUIRES_SHARED(Locks::mutator_lock_) {
   const Runtime* const runtime = Runtime::Current();
   return
+      runtime->IsStarted() &&
+      !runtime->IsAotCompiler() &&
       !Dbg::IsDebuggerActive() &&
-      !runtime->GetInstrumentation()->NonJitProfilingActive() &&
+      !runtime->GetInstrumentation()->IsActive() &&
       // mterp only knows how to deal with the normal exits. It cannot handle any of the
       // non-standard force-returns.
       !runtime->AreNonStandardExitsEnabled() &&
       // An async exception has been thrown. We need to go to the switch interpreter. MTerp doesn't
       // know how to deal with these so we could end up never dealing with it if we are in an
       // infinite loop.
-      !runtime->AreAsyncExceptionsThrown();
+      !runtime->AreAsyncExceptionsThrown() &&
+      (runtime->GetJit() == nullptr || !runtime->GetJit()->JitAtFirstUse());
 }
 
 
@@ -560,6 +563,7 @@
     MutexLock tll_mu(self, *Locks::thread_list_lock_);
     DCHECK_EQ(self->UseMterp(), CanUseMterp());
   }
+  DCHECK(!Runtime::Current()->IsActiveTransaction());
   const Instruction* inst = Instruction::At(dex_pc_ptr);
   uint16_t inst_data = inst->Fetch16(0);
   if (inst->Opcode(inst_data) == Instruction::MOVE_EXCEPTION) {
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index f54bf87..f5c0704 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -225,7 +225,9 @@
   if ((runtime_flags & DEBUG_ALWAYS_JIT) != 0) {
     jit::JitOptions* jit_options = runtime->GetJITOptions();
     CHECK(jit_options != nullptr);
-    jit_options->SetJitAtFirstUse();
+    Runtime::Current()->DoAndMaybeSwitchInterpreter([=]() {
+        jit_options->SetJitAtFirstUse();
+    });
     runtime_flags &= ~DEBUG_ALWAYS_JIT;
   }
 
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 40c7301..a152692 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -744,7 +744,7 @@
 
   self->TransitionFromRunnableToSuspended(kNative);
 
-  started_ = true;
+  DoAndMaybeSwitchInterpreter([=](){ started_ = true; });
 
   if (!IsImageDex2OatEnabled() || !GetHeap()->HasBootImageSpace()) {
     ScopedObjectAccess soa(self);
@@ -2488,7 +2488,8 @@
     DCHECK(!jit_options_->UseJitCompilation());
   }
   std::string error_msg;
-  jit_.reset(jit::Jit::Create(jit_options_.get(), &error_msg));
+  jit::Jit* jit = jit::Jit::Create(jit_options_.get(), &error_msg);
+  DoAndMaybeSwitchInterpreter([=](){ jit_.reset(jit); });
   if (jit_.get() == nullptr) {
     LOG(WARNING) << "Failed to create JIT " << error_msg;
     return;