summaryrefslogtreecommitdiff
path: root/openjdkjvmti/deopt_manager.cc
diff options
context:
space:
mode:
Diffstat (limited to 'openjdkjvmti/deopt_manager.cc')
-rw-r--r--openjdkjvmti/deopt_manager.cc150
1 files changed, 93 insertions, 57 deletions
diff --git a/openjdkjvmti/deopt_manager.cc b/openjdkjvmti/deopt_manager.cc
index 312a797b9d..978843c6ea 100644
--- a/openjdkjvmti/deopt_manager.cc
+++ b/openjdkjvmti/deopt_manager.cc
@@ -47,10 +47,12 @@
#include "gc/scoped_gc_critical_section.h"
#include "instrumentation.h"
#include "jit/jit.h"
+#include "jit/jit_code_cache.h"
#include "jni/jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/object_array-inl.h"
#include "nativehelper/scoped_local_ref.h"
+#include "oat_file_manager.h"
#include "read_barrier_config.h"
#include "runtime_callbacks.h"
#include "scoped_thread_state_change-inl.h"
@@ -61,16 +63,15 @@
namespace openjdkjvmti {
-// TODO We should make this much more selective in the future so we only return true when we
+static constexpr const char* kInstrumentationKey = "JVMTI_DeoptRequester";
+
+// We could make this much more selective in the future so we only return true when we
// actually care about the method at this time (ie active frames had locals changed). For now we
-// just assume that if anything has changed any frame's locals we care about all methods. If nothing
-// has we only care about methods with active breakpoints on them. In the future we should probably
-// rewrite all of this to instead do this at the ShadowFrame or thread granularity.
-bool JvmtiMethodInspectionCallback::IsMethodBeingInspected(art::ArtMethod* method) {
- // In non-java-debuggable runtimes the breakpoint check would miss if we have breakpoints on
- // methods that are inlined. Since these features are best effort in non-java-debuggable
- // runtimes it is OK to be less precise. For debuggable runtimes, inlining is disabled.
- return manager_->HaveLocalsChanged() || manager_->MethodHasBreakpoints(method);
+// just assume that if anything has changed any frame's locals we care about all methods. This only
+// impacts whether we are able to OSR or not so maybe not really important to maintain frame
+// specific information.
+bool JvmtiMethodInspectionCallback::HaveLocalsChanged() {
+ return manager_->HaveLocalsChanged();
}
DeoptManager::DeoptManager()
@@ -94,14 +95,6 @@ void DeoptManager::Setup() {
callbacks->AddMethodInspectionCallback(&inspection_callback_);
}
-void DeoptManager::Shutdown() {
- art::ScopedThreadStateChange stsc(art::Thread::Current(),
- art::ThreadState::kWaitingForDebuggerToAttach);
- art::ScopedSuspendAll ssa("remove method Inspection Callback");
- art::RuntimeCallbacks* callbacks = art::Runtime::Current()->GetRuntimeCallbacks();
- callbacks->RemoveMethodInspectionCallback(&inspection_callback_);
-}
-
void DeoptManager::DumpDeoptInfo(art::Thread* self, std::ostream& stream) {
art::ScopedObjectAccess soa(self);
art::MutexLock mutll(self, *art::Locks::thread_list_lock_);
@@ -151,48 +144,59 @@ void DeoptManager::DumpDeoptInfo(art::Thread* self, std::ostream& stream) {
void DeoptManager::FinishSetup() {
art::Thread* self = art::Thread::Current();
- art::MutexLock mu(self, deoptimization_status_lock_);
-
art::Runtime* runtime = art::Runtime::Current();
- // See if we need to do anything.
- if (!runtime->IsJavaDebuggable()) {
- // See if we can enable all JVMTI functions. If this is false, only kArtTiVersion agents can be
- // retrieved and they will all be best-effort.
- if (PhaseUtil::GetPhaseUnchecked() == JVMTI_PHASE_ONLOAD) {
- // We are still early enough to change the compiler options and get full JVMTI support.
- LOG(INFO) << "Openjdkjvmti plugin loaded on a non-debuggable runtime. Changing runtime to "
- << "debuggable state. Please pass '--debuggable' to dex2oat and "
- << "'-Xcompiler-option --debuggable' to dalvikvm in the future.";
- DCHECK(runtime->GetJit() == nullptr) << "Jit should not be running yet!";
- runtime->AddCompilerOption("--debuggable");
- runtime->SetJavaDebuggable(true);
- } else {
- LOG(WARNING) << "Openjdkjvmti plugin was loaded on a non-debuggable Runtime. Plugin was "
- << "loaded too late to change runtime state to DEBUGGABLE. Only kArtTiVersion "
- << "(0x" << std::hex << kArtTiVersion << ") environments are available. Some "
- << "functionality might not work properly.";
- if (runtime->GetJit() == nullptr &&
- runtime->GetJITOptions()->UseJitCompilation() &&
- !runtime->GetInstrumentation()->IsForcedInterpretOnly()) {
- // If we don't have a jit we should try to start the jit for performance reasons. We only
- // need to do this for late attach on non-debuggable processes because for debuggable
- // processes we already rely on jit and we cannot force this jit to start if we are still in
- // OnLoad since the runtime hasn't started up sufficiently. This is only expected to happen
- // on userdebug/eng builds.
- LOG(INFO) << "Attempting to start jit for openjdkjvmti plugin.";
- // Note: use rwx allowed = true, because if this is the system server, we will not be
- // allowed to allocate any JIT code cache, anyways.
- runtime->CreateJitCodeCache(/*rwx_memory_allowed=*/true);
- runtime->CreateJit();
- if (runtime->GetJit() == nullptr) {
- LOG(WARNING) << "Could not start jit for openjdkjvmti plugin. This process might be "
- << "quite slow as it is running entirely in the interpreter. Try running "
- << "'setenforce 0' and restarting this process.";
- }
- }
- }
+ if (runtime->IsJavaDebuggable()) {
+ return;
+ }
+
+ // See if we can enable all JVMTI functions.
+ if (PhaseUtil::GetPhaseUnchecked() == JVMTI_PHASE_ONLOAD) {
+ // We are still early enough to change the compiler options and get full JVMTI support.
+ LOG(INFO) << "Openjdkjvmti plugin loaded on a non-debuggable runtime. Changing runtime to "
+ << "debuggable state. Please pass '--debuggable' to dex2oat and "
+ << "'-Xcompiler-option --debuggable' to dalvikvm in the future.";
+ DCHECK(runtime->GetJit() == nullptr) << "Jit should not be running yet!";
+ art::ScopedSuspendAll ssa(__FUNCTION__);
+ // TODO check if we need to hold deoptimization_status_lock_ here.
+ art::MutexLock mu(self, deoptimization_status_lock_);
+ runtime->AddCompilerOption("--debuggable");
+ runtime->SetRuntimeDebugState(art::Runtime::RuntimeDebugState::kJavaDebuggableAtInit);
runtime->DeoptimizeBootImage();
+ return;
+ }
+
+ // Runtime has already started in non-debuggable mode. Only kArtTiVersion agents can be
+ // retrieved and they will all be best-effort.
+ LOG(WARNING) << "Openjdkjvmti plugin was loaded on a non-debuggable Runtime. Plugin was "
+ << "loaded too late to change runtime state to support all capabilities. Only "
+ << "kArtTiVersion (0x" << std::hex << kArtTiVersion << ") environments are "
+ << "available. Some functionality might not work properly.";
+
+ // Transition the runtime to debuggable:
+ // 1. Wait for any background verification tasks to finish. We don't support
+ // background verification after moving to debuggable state.
+ runtime->GetOatFileManager().WaitForBackgroundVerificationTasksToFinish();
+
+ // Do the transition in ScopedJITSuspend, so we don't start any JIT compilations
+ // before the transition to debuggable is finished.
+ art::jit::ScopedJitSuspend suspend_jit;
+ art::ScopedSuspendAll ssa(__FUNCTION__);
+
+ // 2. Discard any JITed code that was generated before, since they would be
+ // compiled without debug support.
+ art::jit::Jit* jit = runtime->GetJit();
+ if (jit != nullptr) {
+ jit->GetCodeCache()->InvalidateAllCompiledCode();
+ jit->GetCodeCache()->TransitionToDebuggable();
+ jit->GetJitCompiler()->SetDebuggableCompilerOption(true);
}
+
+ // 3. Change the state to JavaDebuggable, so that debug features can be
+ // enabled from now on.
+ runtime->SetRuntimeDebugState(art::Runtime::RuntimeDebugState::kJavaDebuggable);
+
+ // 4. Update all entrypoints to avoid using any AOT code.
+ runtime->GetInstrumentation()->UpdateEntrypointsForDebuggable();
}
bool DeoptManager::MethodHasBreakpoints(art::ArtMethod* method) {
@@ -365,6 +369,30 @@ void DeoptManager::AddDeoptimizeAllMethodsLocked(art::Thread* self) {
}
}
+void DeoptManager::Shutdown() {
+ art::Thread* self = art::Thread::Current();
+ art::Runtime* runtime = art::Runtime::Current();
+
+ // Do the transition in ScopedJITSuspend, so we don't start any JIT compilations
+ // before the transition to debuggable is finished.
+ art::jit::ScopedJitSuspend suspend_jit;
+
+ art::ScopedThreadStateChange sts(self, art::ThreadState::kSuspended);
+ deoptimization_status_lock_.ExclusiveLock(self);
+ ScopedDeoptimizationContext sdc(self, this);
+
+ art::RuntimeCallbacks* callbacks = runtime->GetRuntimeCallbacks();
+ callbacks->RemoveMethodInspectionCallback(&inspection_callback_);
+
+ if (runtime->IsShuttingDown(self)) {
+ return;
+ }
+
+ runtime->GetInstrumentation()->DisableDeoptimization(kInstrumentationKey);
+ runtime->GetInstrumentation()->DisableDeoptimization(kDeoptManagerInstrumentationKey);
+ runtime->GetInstrumentation()->MaybeSwitchRuntimeDebugState(self);
+}
+
void DeoptManager::RemoveDeoptimizeAllMethodsLocked(art::Thread* self) {
DCHECK_GT(global_deopt_count_, 0u) << "Request to remove non-existent global deoptimization!";
global_deopt_count_--;
@@ -438,7 +466,6 @@ jvmtiError DeoptManager::RemoveDeoptimizeThreadMethods(art::ScopedObjectAccessUn
return OK;
}
-static constexpr const char* kInstrumentationKey = "JVMTI_DeoptRequester";
void DeoptManager::RemoveDeoptimizationRequester() {
art::Thread* self = art::Thread::Current();
@@ -460,6 +487,15 @@ void DeoptManager::AddDeoptimizationRequester() {
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);
}