Limited deopt request from jvmti should enable entry / exit hooks

When an event requires a limited deopt support we should enable entry /
exit hooks. We only call this in debuggable runtimes and hence none of
the entrypoints need to be updated but we still need to inform that
entry / exit hooks have to be called and also record that we need entry
/ exit hooks corresponding to the deopt manager's instrumentation key.

We didn't see a problem earlier, since limited deopt was only used only
for setting breakpoints and breakpoints instrument the stack explicitly.
This would be a problem when we extend other events like method entry /
exit to use limited deopt support.

Bug: 206029744
Test: art/test.py

Change-Id: Ic0c19cf6da70b3c34fc2e9b67898d9e5e223e2b4
diff --git a/openjdkjvmti/deopt_manager.cc b/openjdkjvmti/deopt_manager.cc
index 129aa0f..99acb87 100644
--- a/openjdkjvmti/deopt_manager.cc
+++ b/openjdkjvmti/deopt_manager.cc
@@ -496,6 +496,15 @@
   art::ScopedThreadStateChange stsc(self, art::ThreadState::kSuspended);
   deoptimization_status_lock_.ExclusiveLock(self);
   deopter_count_++;
+  if (deopter_count_ == 1) {
+    // When we add a deoptimization requester, we should enable entry / exit hooks. We only call
+    // this in debuggable runtimes and hence it won't be necessary to update entrypoints but we
+    // still need to inform instrumentation that we need to actually run entry / exit hooks. Though
+    // entrypoints are capable of running entry / exit hooks they won't run them unless enabled.
+    ScopedDeoptimizationContext sdc(self, this);
+    art::Runtime::Current()->GetInstrumentation()->EnableEntryExitHooks(kInstrumentationKey);
+    return;
+  }
   deoptimization_status_lock_.ExclusiveUnlock(self);
 }
 
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 0863ddf..87630c1 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -887,6 +887,11 @@
   instrumentation_level_ = requested_level;
 }
 
+void Instrumentation::EnableEntryExitHooks(const char* key) {
+  DCHECK(Runtime::Current()->IsJavaDebuggable());
+  ConfigureStubs(key, InstrumentationLevel::kInstrumentWithInstrumentationStubs);
+}
+
 void Instrumentation::MaybeRestoreInstrumentationStack() {
   // Restore stack only if there is no method currently deoptimized.
   if (!IsDeoptimizedMethodsEmpty()) {
diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h
index aecad1f..f7e8aee 100644
--- a/runtime/instrumentation.h
+++ b/runtime/instrumentation.h
@@ -243,6 +243,11 @@
   void DisableDeoptimization(const char* key)
       REQUIRES(Locks::mutator_lock_, Roles::uninterruptible_);
 
+  // Enables entry exit hooks support. This is called in preparation for debug requests that require
+  // calling method entry / exit hooks.
+  void EnableEntryExitHooks(const char* key)
+      REQUIRES(Locks::mutator_lock_, Roles::uninterruptible_);
+
   bool AreAllMethodsDeoptimized() const {
     return InterpreterStubsInstalled();
   }