diff options
-rw-r--r-- | openjdkjvmti/deopt_manager.cc | 142 | ||||
-rw-r--r-- | openjdkjvmti/deopt_manager.h | 37 | ||||
-rw-r--r-- | openjdkjvmti/events.cc | 30 | ||||
-rw-r--r-- | runtime/jit/jit.cc | 9 | ||||
-rw-r--r-- | runtime/jit/jit_code_cache.cc | 15 | ||||
-rw-r--r-- | runtime/jit/jit_code_cache.h | 2 |
6 files changed, 35 insertions, 200 deletions
diff --git a/openjdkjvmti/deopt_manager.cc b/openjdkjvmti/deopt_manager.cc index b444cc789f..2f24d7ea3d 100644 --- a/openjdkjvmti/deopt_manager.cc +++ b/openjdkjvmti/deopt_manager.cc @@ -40,9 +40,7 @@ #include "dex/dex_file_annotations.h" #include "dex/modifiers.h" #include "events-inl.h" -#include "intrinsics_list.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" @@ -86,13 +84,11 @@ DeoptManager::DeoptManager() deoptimization_condition_("JVMTI_DeoptimizationCondition", deoptimization_status_lock_), performing_deoptimization_(false), global_deopt_count_(0), - global_interpreter_deopt_count_(0), deopter_count_(0), breakpoint_status_lock_("JVMTI_BreakpointStatusLock", static_cast<art::LockLevel>(art::LockLevel::kAbortLock + 1)), inspection_callback_(this), - set_local_variable_called_(false), - already_disabled_intrinsics_(false) { } + set_local_variable_called_(false) { } void DeoptManager::Setup() { art::ScopedThreadStateChange stsc(art::Thread::Current(), @@ -163,18 +159,18 @@ bool DeoptManager::MethodHasBreakpointsLocked(art::ArtMethod* method) { return elem != breakpoint_status_.end() && elem->second != 0; } -void DeoptManager::RemoveDeoptimizeAllMethods(FullDeoptRequirement req) { +void DeoptManager::RemoveDeoptimizeAllMethods() { art::Thread* self = art::Thread::Current(); art::ScopedThreadSuspension sts(self, art::kSuspended); deoptimization_status_lock_.ExclusiveLock(self); - RemoveDeoptimizeAllMethodsLocked(self, req); + RemoveDeoptimizeAllMethodsLocked(self); } -void DeoptManager::AddDeoptimizeAllMethods(FullDeoptRequirement req) { +void DeoptManager::AddDeoptimizeAllMethods() { art::Thread* self = art::Thread::Current(); art::ScopedThreadSuspension sts(self, art::kSuspended); deoptimization_status_lock_.ExclusiveLock(self); - AddDeoptimizeAllMethodsLocked(self, req); + AddDeoptimizeAllMethodsLocked(self); } void DeoptManager::AddMethodBreakpoint(art::ArtMethod* method) { @@ -211,7 +207,7 @@ void DeoptManager::AddMethodBreakpoint(art::ArtMethod* method) { deoptimization_status_lock_.ExclusiveUnlock(self); return; } else if (is_default) { - AddDeoptimizeAllMethodsLocked(self, FullDeoptRequirement::kInterpreter); + AddDeoptimizeAllMethodsLocked(self); } else { PerformLimitedDeoptimization(self, method); } @@ -248,7 +244,7 @@ void DeoptManager::RemoveMethodBreakpoint(art::ArtMethod* method) { return; } else if (is_last_breakpoint) { if (UNLIKELY(is_default)) { - RemoveDeoptimizeAllMethodsLocked(self, FullDeoptRequirement::kInterpreter); + RemoveDeoptimizeAllMethodsLocked(self); } else { PerformLimitedUndeoptimization(self, method); } @@ -276,22 +272,13 @@ class ScopedDeoptimizationContext : public art::ValueObject { RELEASE(deopt->deoptimization_status_lock_) ACQUIRE(art::Locks::mutator_lock_) ACQUIRE(art::Roles::uninterruptible_) - : self_(self), - deopt_(deopt), - uninterruptible_cause_(nullptr), - jit_(art::Runtime::Current()->GetJit()) { + : self_(self), deopt_(deopt), uninterruptible_cause_(nullptr) { deopt_->WaitForDeoptimizationToFinishLocked(self_); DCHECK(!deopt->performing_deoptimization_) << "Already performing deoptimization on another thread!"; // Use performing_deoptimization_ to keep track of the lock. deopt_->performing_deoptimization_ = true; deopt_->deoptimization_status_lock_.Unlock(self_); - // Stop the jit. We might need to disable all intrinsics which needs the jit disabled and this - // is the only place we can do that. Since this isn't expected to be entered too often it should - // be fine to always stop it. - if (jit_ != nullptr) { - jit_->Stop(); - } art::Runtime::Current()->GetThreadList()->SuspendAll("JMVTI Deoptimizing methods", /*long_suspend*/ false); uninterruptible_cause_ = self_->StartAssertNoThreadSuspension("JVMTI deoptimizing methods"); @@ -304,10 +291,6 @@ class ScopedDeoptimizationContext : public art::ValueObject { self_->EndAssertNoThreadSuspension(uninterruptible_cause_); // Release the mutator lock. art::Runtime::Current()->GetThreadList()->ResumeAll(); - // Let the jit start again. - if (jit_ != nullptr) { - jit_->Start(); - } // Let other threads know it's fine to proceed. art::MutexLock lk(self_, deopt_->deoptimization_status_lock_); deopt_->performing_deoptimization_ = false; @@ -318,44 +301,22 @@ class ScopedDeoptimizationContext : public art::ValueObject { art::Thread* self_; DeoptManager* deopt_; const char* uninterruptible_cause_; - art::jit::Jit* jit_; }; -void DeoptManager::AddDeoptimizeAllMethodsLocked(art::Thread* self, FullDeoptRequirement req) { - DCHECK_GE(global_deopt_count_, global_interpreter_deopt_count_); +void DeoptManager::AddDeoptimizeAllMethodsLocked(art::Thread* self) { global_deopt_count_++; - if (req == FullDeoptRequirement::kInterpreter) { - global_interpreter_deopt_count_++; - } if (global_deopt_count_ == 1) { - PerformGlobalDeoptimization(self, - /*needs_interpreter*/ global_interpreter_deopt_count_ > 0, - /*disable_intrinsics*/ global_interpreter_deopt_count_ == 0); - } else if (req == FullDeoptRequirement::kInterpreter && global_interpreter_deopt_count_ == 1) { - // First kInterpreter request. - PerformGlobalDeoptimization(self, - /*needs_interpreter*/true, - /*disable_intrinsics*/false); + PerformGlobalDeoptimization(self); } else { WaitForDeoptimizationToFinish(self); } } -void DeoptManager::RemoveDeoptimizeAllMethodsLocked(art::Thread* self, FullDeoptRequirement req) { +void DeoptManager::RemoveDeoptimizeAllMethodsLocked(art::Thread* self) { DCHECK_GT(global_deopt_count_, 0u) << "Request to remove non-existent global deoptimization!"; - DCHECK_GE(global_deopt_count_, global_interpreter_deopt_count_); global_deopt_count_--; - if (req == FullDeoptRequirement::kInterpreter) { - global_interpreter_deopt_count_--; - } if (global_deopt_count_ == 0) { - PerformGlobalUndeoptimization(self, - /*still_needs_stubs*/ false, - /*disable_intrinsics*/ false); - } else if (req == FullDeoptRequirement::kInterpreter && global_interpreter_deopt_count_ == 0) { - PerformGlobalUndeoptimization(self, - /*still_needs_stubs*/ global_deopt_count_ > 0, - /*disable_intrinsics*/ global_deopt_count_ > 0); + PerformGlobalUndeoptimization(self); } else { WaitForDeoptimizationToFinish(self); } @@ -371,85 +332,18 @@ void DeoptManager::PerformLimitedUndeoptimization(art::Thread* self, art::ArtMet art::Runtime::Current()->GetInstrumentation()->Undeoptimize(method); } -void DeoptManager::PerformGlobalDeoptimization(art::Thread* self, - bool needs_interpreter, - bool disable_intrinsics) { +void DeoptManager::PerformGlobalDeoptimization(art::Thread* self) { ScopedDeoptimizationContext sdc(self, this); - art::Runtime::Current()->GetInstrumentation()->EnableMethodTracing( - kDeoptManagerInstrumentationKey, needs_interpreter); - MaybeDisableIntrinsics(disable_intrinsics); + art::Runtime::Current()->GetInstrumentation()->DeoptimizeEverything( + kDeoptManagerInstrumentationKey); } -void DeoptManager::PerformGlobalUndeoptimization(art::Thread* self, - bool still_needs_stubs, - bool disable_intrinsics) { +void DeoptManager::PerformGlobalUndeoptimization(art::Thread* self) { ScopedDeoptimizationContext sdc(self, this); - if (still_needs_stubs) { - art::Runtime::Current()->GetInstrumentation()->EnableMethodTracing( - kDeoptManagerInstrumentationKey, /*needs_interpreter*/false); - MaybeDisableIntrinsics(disable_intrinsics); - } else { - art::Runtime::Current()->GetInstrumentation()->DisableMethodTracing( - kDeoptManagerInstrumentationKey); - // We shouldn't care about intrinsics if we don't need tracing anymore. - DCHECK(!disable_intrinsics); - } -} - -static void DisableSingleIntrinsic(const char* class_name, - const char* method_name, - const char* signature) - REQUIRES(art::Locks::mutator_lock_, art::Roles::uninterruptible_) { - // Since these intrinsics are all loaded during runtime startup this cannot fail and will not - // suspend. - art::Thread* self = art::Thread::Current(); - art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker(); - art::ObjPtr<art::mirror::Class> cls = class_linker->FindSystemClass(self, class_name); - - if (cls == nullptr) { - LOG(FATAL) << "Could not find class of intrinsic " - << class_name << "->" << method_name << signature; - } - - art::ArtMethod* method = cls->FindClassMethod(method_name, signature, art::kRuntimePointerSize); - if (method == nullptr || method->GetDeclaringClass() != cls) { - LOG(FATAL) << "Could not find method of intrinsic " - << class_name << "->" << method_name << signature; - } - - if (LIKELY(method->IsIntrinsic())) { - method->SetNotIntrinsic(); - } else { - LOG(WARNING) << method->PrettyMethod() << " was already marked as non-intrinsic!"; - } + art::Runtime::Current()->GetInstrumentation()->UndeoptimizeEverything( + kDeoptManagerInstrumentationKey); } -void DeoptManager::MaybeDisableIntrinsics(bool do_disable) { - if (!do_disable || already_disabled_intrinsics_) { - // Don't toggle intrinsics on and off. It will lead to too much purging of the jit and would - // require us to keep around the intrinsics status of all methods. - return; - } - already_disabled_intrinsics_ = true; - // First just mark all intrinsic methods as no longer intrinsics. -#define DISABLE_INTRINSIC(_1, _2, _3, _4, _5, decl_class_name, meth_name, meth_desc) \ - DisableSingleIntrinsic(decl_class_name, meth_name, meth_desc); - INTRINSICS_LIST(DISABLE_INTRINSIC); -#undef DISABLE_INTRINSIC - // Next tell the jit to throw away all of its code (since there might be intrinsic code in them. - // TODO it would be nice to be more selective. - art::jit::Jit* jit = art::Runtime::Current()->GetJit(); - if (jit != nullptr) { - jit->GetCodeCache()->ClearAllCompiledDexCode(); - } - art::MutexLock mu(art::Thread::Current(), *art::Locks::thread_list_lock_); - // Now make all threads go to interpreter. - art::Runtime::Current()->GetThreadList()->ForEach( - [](art::Thread* thr, void* ctx) REQUIRES(art::Locks::mutator_lock_) { - reinterpret_cast<DeoptManager*>(ctx)->DeoptimizeThread(thr); - }, - this); -} void DeoptManager::RemoveDeoptimizationRequester() { art::Thread* self = art::Thread::Current(); diff --git a/openjdkjvmti/deopt_manager.h b/openjdkjvmti/deopt_manager.h index 1a13c0ff15..6e991dee3d 100644 --- a/openjdkjvmti/deopt_manager.h +++ b/openjdkjvmti/deopt_manager.h @@ -51,11 +51,6 @@ class Class; namespace openjdkjvmti { -enum class FullDeoptRequirement { - kStubs, - kInterpreter, -}; - class DeoptManager; struct JvmtiMethodInspectionCallback : public art::MethodInspectionCallback { @@ -99,11 +94,11 @@ class DeoptManager { REQUIRES(!deoptimization_status_lock_, !art::Roles::uninterruptible_) REQUIRES_SHARED(art::Locks::mutator_lock_); - void AddDeoptimizeAllMethods(FullDeoptRequirement requirement) + void AddDeoptimizeAllMethods() REQUIRES(!deoptimization_status_lock_, !art::Roles::uninterruptible_) REQUIRES_SHARED(art::Locks::mutator_lock_); - void RemoveDeoptimizeAllMethods(FullDeoptRequirement requirement) + void RemoveDeoptimizeAllMethods() REQUIRES(!deoptimization_status_lock_, !art::Roles::uninterruptible_) REQUIRES_SHARED(art::Locks::mutator_lock_); @@ -137,23 +132,19 @@ class DeoptManager { void WaitForDeoptimizationToFinishLocked(art::Thread* self) REQUIRES(deoptimization_status_lock_, !art::Locks::mutator_lock_); - void AddDeoptimizeAllMethodsLocked(art::Thread* self, FullDeoptRequirement req) + void AddDeoptimizeAllMethodsLocked(art::Thread* self) RELEASE(deoptimization_status_lock_) REQUIRES(!art::Roles::uninterruptible_, !art::Locks::mutator_lock_); - void RemoveDeoptimizeAllMethodsLocked(art::Thread* self, FullDeoptRequirement req) + void RemoveDeoptimizeAllMethodsLocked(art::Thread* self) RELEASE(deoptimization_status_lock_) REQUIRES(!art::Roles::uninterruptible_, !art::Locks::mutator_lock_); - void PerformGlobalDeoptimization(art::Thread* self, - bool needs_interpreter, - bool disable_intrinsics) + void PerformGlobalDeoptimization(art::Thread* self) RELEASE(deoptimization_status_lock_) REQUIRES(!art::Roles::uninterruptible_, !art::Locks::mutator_lock_); - void PerformGlobalUndeoptimization(art::Thread* self, - bool still_needs_stubs, - bool disable_intrinsics) + void PerformGlobalUndeoptimization(art::Thread* self) RELEASE(deoptimization_status_lock_) REQUIRES(!art::Roles::uninterruptible_, !art::Locks::mutator_lock_); @@ -165,25 +156,15 @@ class DeoptManager { RELEASE(deoptimization_status_lock_) REQUIRES(!art::Roles::uninterruptible_, !art::Locks::mutator_lock_); - // Disables intrinsics and purges the jit code cache if needed. - void MaybeDisableIntrinsics(bool do_disable) - REQUIRES(art::Locks::mutator_lock_, - !deoptimization_status_lock_, - art::Roles::uninterruptible_); - static constexpr const char* kDeoptManagerInstrumentationKey = "JVMTI_DeoptManager"; art::Mutex deoptimization_status_lock_ ACQUIRED_BEFORE(art::Locks::classlinker_classes_lock_); art::ConditionVariable deoptimization_condition_ GUARDED_BY(deoptimization_status_lock_); bool performing_deoptimization_ GUARDED_BY(deoptimization_status_lock_); - // Number of times we have gotten requests to deopt everything both requiring and not requiring - // interpreter. + // Number of times we have gotten requests to deopt everything. uint32_t global_deopt_count_ GUARDED_BY(deoptimization_status_lock_); - // Number of deopt-everything requests that require interpreter. - uint32_t global_interpreter_deopt_count_ GUARDED_BY(deoptimization_status_lock_); - // Number of users of deoptimization there currently are. uint32_t deopter_count_ GUARDED_BY(deoptimization_status_lock_); @@ -201,10 +182,6 @@ class DeoptManager { // OSR after this. std::atomic<bool> set_local_variable_called_; - // If we have already disabled intrinsics. Since doing this throws out all JIT code we really will - // only ever do it once and never undo it. - bool already_disabled_intrinsics_ GUARDED_BY(art::Locks::mutator_lock_); - // Helper for setting up/tearing-down for deoptimization. friend class ScopedDeoptimizationContext; }; diff --git a/openjdkjvmti/events.cc b/openjdkjvmti/events.cc index 10a4923935..f71a5dc72d 100644 --- a/openjdkjvmti/events.cc +++ b/openjdkjvmti/events.cc @@ -888,29 +888,16 @@ static bool EventNeedsFullDeopt(ArtJvmtiEvent event) { case ArtJvmtiEvent::kBreakpoint: case ArtJvmtiEvent::kException: return false; - default: - return true; - } -} - -static FullDeoptRequirement GetFullDeoptRequirement(ArtJvmtiEvent event) { - switch (event) { - // TODO We should support more of these as Limited or at least do something to make them - // discriminate by thread. + // TODO We should support more of these or at least do something to make them discriminate by + // thread. case ArtJvmtiEvent::kMethodEntry: - case ArtJvmtiEvent::kMethodExit: - // We only need MethodEntered and MethodExited for these so we can use Stubs. We will need to - // disable intrinsics. - // TODO Offer a version of this without disabling intrinsics. - return FullDeoptRequirement::kStubs; case ArtJvmtiEvent::kExceptionCatch: + case ArtJvmtiEvent::kMethodExit: case ArtJvmtiEvent::kFieldModification: case ArtJvmtiEvent::kFieldAccess: case ArtJvmtiEvent::kSingleStep: - // NB If we ever make this runnable using stubs or some other method we will need to be careful - // that it doesn't require disabling intrinsics. case ArtJvmtiEvent::kFramePop: - return FullDeoptRequirement::kInterpreter; + return true; default: LOG(FATAL) << "Unexpected event type!"; UNREACHABLE(); @@ -920,18 +907,19 @@ static FullDeoptRequirement GetFullDeoptRequirement(ArtJvmtiEvent event) { void EventHandler::SetupTraceListener(JvmtiMethodTraceListener* listener, ArtJvmtiEvent event, bool enable) { + bool needs_full_deopt = EventNeedsFullDeopt(event); // Make sure we can deopt. { art::ScopedObjectAccess soa(art::Thread::Current()); DeoptManager* deopt_manager = DeoptManager::Get(); if (enable) { deopt_manager->AddDeoptimizationRequester(); - if (EventNeedsFullDeopt(event)) { - deopt_manager->AddDeoptimizeAllMethods(GetFullDeoptRequirement(event)); + if (needs_full_deopt) { + deopt_manager->AddDeoptimizeAllMethods(); } } else { - if (EventNeedsFullDeopt(event)) { - deopt_manager->RemoveDeoptimizeAllMethods(GetFullDeoptRequirement(event)); + if (needs_full_deopt) { + deopt_manager->RemoveDeoptimizeAllMethods(); } deopt_manager->RemoveDeoptimizationRequester(); } diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc index 86f06064ad..ed449b5433 100644 --- a/runtime/jit/jit.cc +++ b/runtime/jit/jit.cc @@ -768,20 +768,13 @@ void Jit::WaitForCompilationToFinish(Thread* self) { void Jit::Stop() { Thread* self = Thread::Current(); // TODO(ngeoffray): change API to not require calling WaitForCompilationToFinish twice. - // During shutdown and startup the thread-pool can be null. - if (GetThreadPool() == nullptr) { - return; - } WaitForCompilationToFinish(self); GetThreadPool()->StopWorkers(self); WaitForCompilationToFinish(self); } void Jit::Start() { - // During shutdown and startup the thread-pool can be null. - if (GetThreadPool() != nullptr) { - GetThreadPool()->StartWorkers(Thread::Current()); - } + GetThreadPool()->StartWorkers(Thread::Current()); } ScopedJitSuspend::ScopedJitSuspend() { diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc index 70a717154b..eeb35156b5 100644 --- a/runtime/jit/jit_code_cache.cc +++ b/runtime/jit/jit_code_cache.cc @@ -362,21 +362,6 @@ const void* JitCodeCache::GetJniStubCode(ArtMethod* method) { return nullptr; } -void JitCodeCache::ClearAllCompiledDexCode() { - MutexLock mu(Thread::Current(), lock_); - // Get rid of OSR code waiting to be put on a thread. - osr_code_map_.clear(); - - // We don't clear out or even touch method_code_map_ since that is what we use to go the other - // way, move from code currently-running to the method it's from. Getting rid of it would break - // the jit-gc, stack-walking and signal handling. Since we never look through it to go the other - // way (from method -> code) everything is fine. - - for (ProfilingInfo* p : profiling_infos_) { - p->SetSavedEntryPoint(nullptr); - } -} - const void* JitCodeCache::FindCompiledCodeForInstrumentation(ArtMethod* method) { // If jit-gc is still on we use the SavedEntryPoint field for doing that and so cannot use it to // find the instrumentation entrypoint. diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h index ee6111a430..49a19a18f1 100644 --- a/runtime/jit/jit_code_cache.h +++ b/runtime/jit/jit_code_cache.h @@ -215,8 +215,6 @@ class JitCodeCache { REQUIRES(!lock_) REQUIRES_SHARED(Locks::mutator_lock_); - void ClearAllCompiledDexCode() REQUIRES(!lock_, Locks::mutator_lock_); - void CopyInlineCacheInto(const InlineCache& ic, Handle<mirror::ObjectArray<mirror::Class>> array) REQUIRES(!lock_) REQUIRES_SHARED(Locks::mutator_lock_); |