Switch to non debuggable only if entry/exit stubs are not required
We used to switch to non-debuggable at the end of method tracing or when
jvmti event is being detached without any further checks. When there are
multiple instrumentation agents active at the same time (for ex: tracing
+ debugger) this might mean we switch the state while entry / exit stubs
are still needed by other agent. Fix method tracing and jvmti detach to
first remove the instrumentation keys added by the agent and then check
to see if entry / exit stubs are needed for some other reason before
switching the runtime state.
Bug: 206029744
Test: art/test.py
Change-Id: I71b55ec109d84d8559f85eede6ccf1f45d5b72dd
diff --git a/openjdkjvmti/deopt_manager.cc b/openjdkjvmti/deopt_manager.cc
index 99acb87..978843c 100644
--- a/openjdkjvmti/deopt_manager.cc
+++ b/openjdkjvmti/deopt_manager.cc
@@ -381,25 +381,16 @@
deoptimization_status_lock_.ExclusiveLock(self);
ScopedDeoptimizationContext sdc(self, this);
- art::jit::Jit* jit = runtime->GetJit();
- if (jit != nullptr && !runtime->IsShuttingDown(self)) {
- jit->GetCodeCache()->InvalidateAllCompiledCode();
- jit->GetCodeCache()->TransitionToDebuggable();
- jit->GetJitCompiler()->SetDebuggableCompilerOption(false);
- }
-
art::RuntimeCallbacks* callbacks = runtime->GetRuntimeCallbacks();
callbacks->RemoveMethodInspectionCallback(&inspection_callback_);
- if (!runtime->IsJavaDebuggableAtInit()) {
- runtime->SetRuntimeDebugState(art::Runtime::RuntimeDebugState::kNonJavaDebuggable);
+
+ if (runtime->IsShuttingDown(self)) {
+ return;
}
- // TODO(mythria): DeoptManager should use only one key. Merge
- // kInstrumentationKey and kDeoptManagerInstrumentationKey.
- if (!runtime->IsShuttingDown(self)) {
- art::Runtime::Current()->GetInstrumentation()->DisableDeoptimization(kInstrumentationKey);
- art::Runtime::Current()->GetInstrumentation()->DisableDeoptimization(
- kDeoptManagerInstrumentationKey);
- }
+
+ runtime->GetInstrumentation()->DisableDeoptimization(kInstrumentationKey);
+ runtime->GetInstrumentation()->DisableDeoptimization(kDeoptManagerInstrumentationKey);
+ runtime->GetInstrumentation()->MaybeSwitchRuntimeDebugState(self);
}
void DeoptManager::RemoveDeoptimizeAllMethodsLocked(art::Thread* self) {
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 0112681..1e0c679 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -1194,6 +1194,27 @@
}
}
+void Instrumentation::MaybeSwitchRuntimeDebugState(Thread* self) {
+ Runtime* runtime = Runtime::Current();
+ // Return early if runtime is shutting down.
+ if (runtime->IsShuttingDown(self)) {
+ return;
+ }
+
+ // Don't switch the state if we started off as JavaDebuggable or if we still need entry / exit
+ // hooks for other reasons.
+ if (EntryExitStubsInstalled() || runtime->IsJavaDebuggableAtInit()) {
+ return;
+ }
+
+ art::jit::Jit* jit = runtime->GetJit();
+ if (jit != nullptr) {
+ jit->GetCodeCache()->InvalidateAllCompiledCode();
+ jit->GetJitCompiler()->SetDebuggableCompilerOption(false);
+ }
+ runtime->SetRuntimeDebugState(art::Runtime::RuntimeDebugState::kNonJavaDebuggable);
+}
+
// Indicates if instrumentation should notify method enter/exit events to the listeners.
bool Instrumentation::ShouldNotifyMethodEnterExitEvents() const {
if (!HasMethodEntryListeners() && !HasMethodExitListeners()) {
diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h
index f46dcf1..439a314 100644
--- a/runtime/instrumentation.h
+++ b/runtime/instrumentation.h
@@ -247,6 +247,11 @@
void EnableEntryExitHooks(const char* key)
REQUIRES(Locks::mutator_lock_, Roles::uninterruptible_);
+ // Switches the runtime state to non-java debuggable if entry / exit hooks are no longer required
+ // and the runtime did not start off as java debuggable.
+ void MaybeSwitchRuntimeDebugState(Thread* self)
+ REQUIRES(Locks::mutator_lock_, Roles::uninterruptible_);
+
bool AreAllMethodsDeoptimized() const {
return InterpreterStubsInstalled();
}
diff --git a/runtime/trace.cc b/runtime/trace.cc
index 387816f..e73a28b 100644
--- a/runtime/trace.cc
+++ b/runtime/trace.cc
@@ -493,14 +493,7 @@
instrumentation::Instrumentation::kMethodExited |
instrumentation::Instrumentation::kMethodUnwind);
runtime->GetInstrumentation()->DisableMethodTracing(kTracerInstrumentationKey);
- if (!runtime->IsJavaDebuggableAtInit() && !runtime->IsShuttingDown(self)) {
- art::jit::Jit* jit = runtime->GetJit();
- if (jit != nullptr) {
- jit->GetCodeCache()->InvalidateAllCompiledCode();
- jit->GetJitCompiler()->SetDebuggableCompilerOption(false);
- }
- runtime->SetRuntimeDebugState(art::Runtime::RuntimeDebugState::kNonJavaDebuggable);
- }
+ runtime->GetInstrumentation()->MaybeSwitchRuntimeDebugState(self);
}
}
// At this point, code may read buf_ as it's writers are shutdown