Don't deoptimize everything with can_access_local_variables

Change the can_access_local_variables setup to not need to deoptimize
everything immediately. Instead ensure all methods are
async-deoptimizable and deoptimize the thread we are examining prior
to examining the stack.

Test: ./test.py --host -j50
Bug: 33616143
Bug: 34414073
Change-Id: I312a4865c09e63a8d3fe3b2d201f1c071fb4305f
diff --git a/openjdkjvmti/events.cc b/openjdkjvmti/events.cc
index c41e15e..00c81e2 100644
--- a/openjdkjvmti/events.cc
+++ b/openjdkjvmti/events.cc
@@ -744,19 +744,34 @@
   }
 }
 
+// Makes sure that all compiled methods are AsyncDeoptimizable so we can deoptimize (and force to
+// the switch interpreter) when we try to get or set a local variable.
 void EventHandler::HandleLocalAccessCapabilityAdded() {
-  art::ScopedThreadStateChange stsc(art::Thread::Current(), art::ThreadState::kNative);
-  art::instrumentation::Instrumentation* instr = art::Runtime::Current()->GetInstrumentation();
-  art::gc::ScopedGCCriticalSection gcs(art::Thread::Current(),
-                                       art::gc::kGcCauseInstrumentation,
-                                       art::gc::kCollectorTypeInstrumentation);
-  art::ScopedSuspendAll ssa("Deoptimize everything for local variable access", true);
-  // TODO This should be disabled when there are no environments using it.
-  if (!instr->CanDeoptimize()) {
-    instr->EnableDeoptimization();
-  }
-  // TODO We should be able to support can_access_local_variables without this.
-  instr->DeoptimizeEverything("jvmti-local-variable-access");
+  class UpdateEntryPointsClassVisitor : public art::ClassVisitor {
+   public:
+    explicit UpdateEntryPointsClassVisitor(art::Runtime* runtime)
+        : runtime_(runtime) {}
+
+    bool operator()(art::ObjPtr<art::mirror::Class> klass)
+        OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
+      for (auto& m : klass->GetMethods(art::kRuntimePointerSize)) {
+        const void* code = m.GetEntryPointFromQuickCompiledCode();
+        if (m.IsNative() || m.IsProxyMethod()) {
+          continue;
+        } else if (!runtime_->GetClassLinker()->IsQuickToInterpreterBridge(code) &&
+                   !runtime_->IsAsyncDeoptimizeable(reinterpret_cast<uintptr_t>(code))) {
+          runtime_->GetInstrumentation()->UpdateMethodsCodeToInterpreterEntryPoint(&m);
+        }
+      }
+      return true;
+    }
+
+   private:
+    art::Runtime* runtime_;
+  };
+  art::ScopedObjectAccess soa(art::Thread::Current());
+  UpdateEntryPointsClassVisitor visitor(art::Runtime::Current());
+  art::Runtime::Current()->GetClassLinker()->VisitClasses(&visitor);
 }
 
 // Handle special work for the given event type, if necessary.
diff --git a/openjdkjvmti/ti_method.cc b/openjdkjvmti/ti_method.cc
index f99b167..05943e7 100644
--- a/openjdkjvmti/ti_method.cc
+++ b/openjdkjvmti/ti_method.cc
@@ -39,6 +39,7 @@
 #include "base/mutex-inl.h"
 #include "dex_file_annotations.h"
 #include "events-inl.h"
+#include "jit/jit.h"
 #include "jni_internal.h"
 #include "mirror/class-inl.h"
 #include "mirror/class_loader.h"
@@ -552,7 +553,7 @@
       return;
     }
     art::ArtMethod* method = visitor.GetMethod();
-    if (method->IsNative() || !visitor.IsShadowFrame()) {
+    if (method->IsNative()) {
       // TODO We really should support get/set for non-shadow frames.
       result_ = ERR(OPAQUE_FRAME);
       return;
@@ -560,6 +561,7 @@
       result_ = ERR(INVALID_SLOT);
       return;
     }
+    bool needs_instrument = !visitor.IsShadowFrame();
     uint32_t pc = visitor.GetDexPc(/*abort_on_failure*/ false);
     if (pc == art::DexFile::kDexNoIndex) {
       // Cannot figure out current PC.
@@ -580,6 +582,9 @@
       return;
     }
     result_ = Execute(method, visitor);
+    if (needs_instrument) {
+      art::Runtime::Current()->GetInstrumentation()->InstrumentThreadStack(self);
+    }
   }
 
   jvmtiError GetResult() const {
@@ -751,6 +756,8 @@
     return ERR(ILLEGAL_ARGUMENT);
   }
   art::Thread* self = art::Thread::Current();
+  // Suspend JIT since it can get confused if we deoptimize methods getting jitted.
+  art::jit::ScopedJitSuspend suspend_jit;
   art::ScopedObjectAccess soa(self);
   art::MutexLock mu(self, *art::Locks::thread_list_lock_);
   art::Thread* target = ThreadUtil::GetNativeThread(thread, soa);
@@ -878,6 +885,8 @@
     return ERR(ILLEGAL_ARGUMENT);
   }
   art::Thread* self = art::Thread::Current();
+  // Suspend JIT since it can get confused if we deoptimize methods getting jitted.
+  art::jit::ScopedJitSuspend suspend_jit;
   art::ScopedObjectAccess soa(self);
   art::MutexLock mu(self, *art::Locks::thread_list_lock_);
   art::Thread* target = ThreadUtil::GetNativeThread(thread, soa);
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 4d8c687..d7f6b83 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -779,6 +779,10 @@
   UpdateMethodsCodeImpl(method, quick_code);
 }
 
+void Instrumentation::UpdateMethodsCodeToInterpreterEntryPoint(ArtMethod* method) {
+  UpdateMethodsCodeImpl(method, GetQuickToInterpreterBridge());
+}
+
 void Instrumentation::UpdateMethodsCodeForJavaDebuggable(ArtMethod* method,
                                                          const void* quick_code) {
   // When the runtime is set to Java debuggable, we may update the entry points of
diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h
index 5763a41..3c5bfca 100644
--- a/runtime/instrumentation.h
+++ b/runtime/instrumentation.h
@@ -282,6 +282,10 @@
   void UpdateMethodsCode(ArtMethod* method, const void* quick_code)
       REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!deoptimized_methods_lock_);
 
+  // Update the code of a method to the interpreter respecting any installed stubs from debugger.
+  void UpdateMethodsCodeToInterpreterEntryPoint(ArtMethod* method)
+      REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!deoptimized_methods_lock_);
+
   // Update the code of a method respecting any installed stubs from debugger.
   void UpdateMethodsCodeForJavaDebuggable(ArtMethod* method, const void* quick_code)
       REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!deoptimized_methods_lock_);