diff options
Diffstat (limited to 'openjdkjvmti')
-rw-r--r-- | openjdkjvmti/OpenjdkJvmTi.cc | 14 | ||||
-rw-r--r-- | openjdkjvmti/art_jvmti.h | 9 | ||||
-rw-r--r-- | openjdkjvmti/deopt_manager.cc | 121 | ||||
-rw-r--r-- | openjdkjvmti/deopt_manager.h | 4 | ||||
-rw-r--r-- | openjdkjvmti/ti_extension.cc | 6 |
5 files changed, 86 insertions, 68 deletions
diff --git a/openjdkjvmti/OpenjdkJvmTi.cc b/openjdkjvmti/OpenjdkJvmTi.cc index 09900e1f73..d7db3d2168 100644 --- a/openjdkjvmti/OpenjdkJvmTi.cc +++ b/openjdkjvmti/OpenjdkJvmTi.cc @@ -89,12 +89,6 @@ AllocationManager* gAllocManager; } \ } while (false) -// Returns whether we are able to use all jvmti features. -static bool IsFullJvmtiAvailable() { - art::Runtime* runtime = art::Runtime::Current(); - return runtime->GetInstrumentation()->IsForcedInterpretOnly() || runtime->IsJavaDebuggable(); -} - class JvmtiFunctions { private: static jvmtiError getEnvironmentError(jvmtiEnv* env) { @@ -1474,13 +1468,7 @@ extern "C" bool ArtPlugin_Initialize() { FieldUtil::Register(gEventHandler); BreakpointUtil::Register(gEventHandler); Transformer::Register(gEventHandler); - - { - // Make sure we can deopt anything we need to. - art::ScopedSuspendAll ssa(__FUNCTION__); - gDeoptManager->FinishSetup(); - } - + gDeoptManager->FinishSetup(); runtime->GetJavaVM()->AddEnvironmentHook(GetEnvHandler); return true; diff --git a/openjdkjvmti/art_jvmti.h b/openjdkjvmti/art_jvmti.h index cdda09b9e7..bc965a232f 100644 --- a/openjdkjvmti/art_jvmti.h +++ b/openjdkjvmti/art_jvmti.h @@ -47,9 +47,11 @@ #include "base/strlcpy.h" #include "base/mutex.h" #include "events.h" +#include "instrumentation.h" #include "jni/java_vm_ext.h" #include "jni/jni_env_ext.h" #include "jvmti.h" +#include "runtime.h" #include "ti_breakpoint.h" namespace art { @@ -69,6 +71,13 @@ class ObjectTagTable; // This is the value 0x70010200. static constexpr jint kArtTiVersion = JVMTI_VERSION_1_2 | 0x40000000; +// Returns whether we are able to use all jvmti features. +static inline bool IsFullJvmtiAvailable() { + art::Runtime* runtime = art::Runtime::Current(); + return runtime->GetInstrumentation()->IsForcedInterpretOnly() || + runtime->IsJavaDebuggableAtInit(); +} + // A structure that is a jvmtiEnv with additional information for the runtime. struct ArtJvmTiEnv : public jvmtiEnv { art::JavaVMExt* art_vm; diff --git a/openjdkjvmti/deopt_manager.cc b/openjdkjvmti/deopt_manager.cc index 03042eccfd..cdc42b165d 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,6 +63,8 @@ namespace openjdkjvmti { +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. This only @@ -91,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_); @@ -148,48 +144,58 @@ 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(); + } + + // 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) { @@ -362,6 +368,26 @@ void DeoptManager::AddDeoptimizeAllMethodsLocked(art::Thread* self) { } } +void DeoptManager::Shutdown() { + art::Thread* self = art::Thread::Current(); + art::Runtime* runtime = art::Runtime::Current(); + 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->IsJavaDebuggableAtInit()) { + runtime->SetRuntimeDebugState(art::Runtime::RuntimeDebugState::kNonJavaDebuggable); + } + // 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); + } +} + void DeoptManager::RemoveDeoptimizeAllMethodsLocked(art::Thread* self) { DCHECK_GT(global_deopt_count_, 0u) << "Request to remove non-existent global deoptimization!"; global_deopt_count_--; @@ -435,7 +461,6 @@ jvmtiError DeoptManager::RemoveDeoptimizeThreadMethods(art::ScopedObjectAccessUn return OK; } -static constexpr const char* kInstrumentationKey = "JVMTI_DeoptRequester"; void DeoptManager::RemoveDeoptimizationRequester() { art::Thread* self = art::Thread::Current(); diff --git a/openjdkjvmti/deopt_manager.h b/openjdkjvmti/deopt_manager.h index 9278bf1bc2..e9b91de78a 100644 --- a/openjdkjvmti/deopt_manager.h +++ b/openjdkjvmti/deopt_manager.h @@ -110,9 +110,7 @@ class DeoptManager { REQUIRES_SHARED(art::Locks::mutator_lock_); void DeoptimizeAllThreads() REQUIRES_SHARED(art::Locks::mutator_lock_); - void FinishSetup() - REQUIRES(!deoptimization_status_lock_, !art::Roles::uninterruptible_) - REQUIRES(art::Locks::mutator_lock_); + void FinishSetup() REQUIRES(!deoptimization_status_lock_, !art::Roles::uninterruptible_); static DeoptManager* Get(); diff --git a/openjdkjvmti/ti_extension.cc b/openjdkjvmti/ti_extension.cc index 10ea43a1ee..02dc9f19c8 100644 --- a/openjdkjvmti/ti_extension.cc +++ b/openjdkjvmti/ti_extension.cc @@ -398,8 +398,7 @@ jvmtiError ExtensionUtil::GetExtensionFunctions(jvmtiEnv* env, // These require index-ids and debuggable to function art::Runtime* runtime = art::Runtime::Current(); - if (runtime->GetJniIdType() == art::JniIdType::kIndices && - (runtime->GetInstrumentation()->IsForcedInterpretOnly() || runtime->IsJavaDebuggable())) { + if (runtime->GetJniIdType() == art::JniIdType::kIndices && IsFullJvmtiAvailable()) { // IsStructurallyModifiableClass error = add_extension( reinterpret_cast<jvmtiExtensionFunction>(Redefiner::IsStructurallyModifiableClass), @@ -703,8 +702,7 @@ jvmtiError ExtensionUtil::GetExtensionEvents(jvmtiEnv* env, return error; } art::Runtime* runtime = art::Runtime::Current(); - if (runtime->GetJniIdType() == art::JniIdType::kIndices && - (runtime->GetInstrumentation()->IsForcedInterpretOnly() || runtime->IsJavaDebuggable())) { + if (runtime->GetJniIdType() == art::JniIdType::kIndices && IsFullJvmtiAvailable()) { error = add_extension( ArtJvmtiEvent::kStructuralDexFileLoadHook, "com.android.art.class.structural_dex_file_load_hook", |