8291718: Remove mark_for_deoptimization from klass unloading

Reviewed-by: eosterlund, dlong
This commit is contained in:
Axel Boldt-Christmas 2022-08-15 09:53:39 +00:00 committed by Erik Österlund
parent 9d7c13eb14
commit fd4b2f2868
18 changed files with 41 additions and 36 deletions

View File

@ -758,9 +758,8 @@ int CodeCache::alignment_offset() {
}
// Mark nmethods for unloading if they contain otherwise unreachable oops.
void CodeCache::do_unloading(BoolObjectClosure* is_alive, bool unloading_occurred) {
void CodeCache::do_unloading(bool unloading_occurred) {
assert_locked_or_safepoint(CodeCache_lock);
UnloadingScope scope(is_alive);
CompiledMethodIterator iter(CompiledMethodIterator::only_alive);
while(iter.next()) {
iter.method()->do_unloading(unloading_occurred);

View File

@ -197,7 +197,7 @@ class CodeCache : AllStatic {
~UnloadingScope();
};
static void do_unloading(BoolObjectClosure* is_alive, bool unloading_occurred);
static void do_unloading(bool unloading_occurred);
static uint8_t unloading_cycle() { return _unloading_cycle; }
static void increment_unloading_cycle();

View File

@ -205,26 +205,31 @@ void DependencyContext::clean_unloading_dependents() {
}
}
nmethodBucket* DependencyContext::release_and_get_next_not_unloading(nmethodBucket* b) {
nmethodBucket* next = b->next_not_unloading();
release(b);
return next;
}
//
// Invalidate all dependencies in the context
int DependencyContext::remove_all_dependents() {
void DependencyContext::remove_all_dependents() {
nmethodBucket* b = dependencies_not_unloading();
set_dependencies(NULL);
assert(b == nullptr, "All dependents should be unloading");
}
int DependencyContext::remove_and_mark_for_deoptimization_all_dependents() {
nmethodBucket* b = dependencies_not_unloading();
set_dependencies(NULL);
int marked = 0;
int removed = 0;
while (b != NULL) {
nmethod* nm = b->get_nmethod();
if (b->count() > 0 && nm->is_alive() && !nm->is_marked_for_deoptimization()) {
nm->mark_for_deoptimization();
marked++;
}
nmethodBucket* next = b->next_not_unloading();
removed++;
release(b);
b = next;
}
if (UsePerfData && removed > 0) {
_perf_total_buckets_deallocated_count->inc(removed);
b = release_and_get_next_not_unloading(b);
}
return marked;
}

View File

@ -120,8 +120,10 @@ class DependencyContext : public StackObj {
int mark_dependent_nmethods(DepChange& changes);
void add_dependent_nmethod(nmethod* nm);
void remove_dependent_nmethod(nmethod* nm);
int remove_all_dependents();
void remove_all_dependents();
int remove_and_mark_for_deoptimization_all_dependents();
void clean_unloading_dependents();
static nmethodBucket* release_and_get_next_not_unloading(nmethodBucket* b);
static void purge_dependency_contexts();
static void release(nmethodBucket* b);
static void cleaning_start();

View File

@ -2882,10 +2882,9 @@ void G1CollectedHeap::do_collection_pause_at_safepoint_helper(double target_paus
}
}
void G1CollectedHeap::complete_cleaning(BoolObjectClosure* is_alive,
bool class_unloading_occurred) {
void G1CollectedHeap::complete_cleaning(bool class_unloading_occurred) {
uint num_workers = workers()->active_workers();
G1ParallelCleaningTask unlink_task(is_alive, num_workers, class_unloading_occurred);
G1ParallelCleaningTask unlink_task(num_workers, class_unloading_occurred);
workers()->run_task(&unlink_task);
}

View File

@ -1261,7 +1261,7 @@ public:
void rebuild_code_roots();
// Performs cleaning of data structures after class unloading.
void complete_cleaning(BoolObjectClosure* is_alive, bool class_unloading_occurred);
void complete_cleaning(bool class_unloading_occurred);
// Verification

View File

@ -1689,8 +1689,9 @@ void G1ConcurrentMark::weak_refs_work() {
// Unload Klasses, String, Code Cache, etc.
if (ClassUnloadingWithConcurrentMark) {
GCTraceTime(Debug, gc, phases) debug("Class Unloading", _gc_timer_cm);
CodeCache::UnloadingScope scope(&g1_is_alive);
bool purged_classes = SystemDictionary::do_unloading(_gc_timer_cm);
_g1h->complete_cleaning(&g1_is_alive, purged_classes);
_g1h->complete_cleaning(purged_classes);
}
}

View File

@ -301,9 +301,10 @@ void G1FullCollector::phase1_mark_live_objects() {
// Class unloading and cleanup.
if (ClassUnloading) {
GCTraceTime(Debug, gc, phases) debug("Phase 1: Class Unloading and Cleanup", scope()->timer());
CodeCache::UnloadingScope unloading_scope(&_is_alive);
// Unload classes and purge the SystemDictionary.
bool purged_class = SystemDictionary::do_unloading(scope()->timer());
_heap->complete_cleaning(&_is_alive, purged_class);
_heap->complete_cleaning(purged_class);
}
scope()->tracer()->report_object_count_after_gc(&_is_alive);

View File

@ -51,12 +51,11 @@ void JVMCICleaningTask::work(bool unloading_occurred) {
}
#endif // INCLUDE_JVMCI
G1ParallelCleaningTask::G1ParallelCleaningTask(BoolObjectClosure* is_alive,
uint num_workers,
G1ParallelCleaningTask::G1ParallelCleaningTask(uint num_workers,
bool unloading_occurred) :
WorkerTask("G1 Parallel Cleaning"),
_unloading_occurred(unloading_occurred),
_code_cache_task(num_workers, is_alive, unloading_occurred),
_code_cache_task(num_workers, unloading_occurred),
JVMCI_ONLY(_jvmci_cleaning_task() COMMA)
_klass_cleaning_task() {
}

View File

@ -54,8 +54,7 @@ private:
public:
// The constructor is run in the VMThread.
G1ParallelCleaningTask(BoolObjectClosure* is_alive,
uint num_workers,
G1ParallelCleaningTask(uint num_workers,
bool unloading_occurred);
void work(uint worker_id);

View File

@ -2056,12 +2056,13 @@ void PSParallelCompact::marking_phase(ParallelOldTracer *gc_tracer) {
{
GCTraceTime(Debug, gc, phases) tm_m("Class Unloading", &_gc_timer);
CodeCache::UnloadingScope scope(is_alive_closure());
// Follow system dictionary roots and unload classes.
bool purged_class = SystemDictionary::do_unloading(&_gc_timer);
// Unload nmethods.
CodeCache::do_unloading(is_alive_closure(), purged_class);
CodeCache::do_unloading(purged_class);
// Prune dead klasses from subklass/sibling/implementor lists.
Klass::clean_weak_klass_links(purged_class);

View File

@ -215,12 +215,13 @@ void GenMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) {
{
GCTraceTime(Debug, gc, phases) tm_m("Class Unloading", gc_timer());
CodeCache::UnloadingScope scope(&is_alive);
// Unload classes and purge the SystemDictionary.
bool purged_class = SystemDictionary::do_unloading(gc_timer());
// Unload nmethods.
CodeCache::do_unloading(&is_alive, purged_class);
CodeCache::do_unloading(purged_class);
// Prune dead klasses from subklass/sibling/implementor lists.
Klass::clean_weak_klass_links(purged_class);

View File

@ -32,8 +32,7 @@
#include "logging/log.hpp"
#include "runtime/atomic.hpp"
CodeCacheUnloadingTask::CodeCacheUnloadingTask(uint num_workers, BoolObjectClosure* is_alive, bool unloading_occurred) :
_unloading_scope(is_alive),
CodeCacheUnloadingTask::CodeCacheUnloadingTask(uint num_workers, bool unloading_occurred) :
_unloading_occurred(unloading_occurred),
_num_workers(num_workers),
_first_nmethod(NULL),

View File

@ -32,7 +32,6 @@
class CodeCacheUnloadingTask {
CodeCache::UnloadingScope _unloading_scope;
const bool _unloading_occurred;
const uint _num_workers;
@ -41,7 +40,7 @@ class CodeCacheUnloadingTask {
CompiledMethod* volatile _claimed_nmethod;
public:
CodeCacheUnloadingTask(uint num_workers, BoolObjectClosure* is_alive, bool unloading_occurred);
CodeCacheUnloadingTask(uint num_workers, bool unloading_occurred);
~CodeCacheUnloadingTask();
private:

View File

@ -73,6 +73,7 @@
#endif
#include "classfile/systemDictionary.hpp"
#include "code/codeCache.hpp"
#include "memory/classLoaderMetaspace.hpp"
#include "memory/metaspaceUtils.hpp"
#include "oops/compressedOops.inline.hpp"
@ -1790,13 +1791,14 @@ void ShenandoahHeap::stw_unload_classes(bool full_gc) {
ShenandoahPhaseTimings::Phase phase = full_gc ?
ShenandoahPhaseTimings::full_gc_purge_class_unload :
ShenandoahPhaseTimings::degen_gc_purge_class_unload;
ShenandoahIsAliveSelector is_alive;
CodeCache::UnloadingScope scope(is_alive.is_alive_closure());
ShenandoahGCPhase gc_phase(phase);
ShenandoahGCWorkerPhase worker_phase(phase);
bool purged_class = SystemDictionary::do_unloading(gc_timer());
ShenandoahIsAliveSelector is_alive;
uint num_workers = _workers->active_workers();
ShenandoahClassUnloadingTask unlink_task(phase, is_alive.is_alive_closure(), num_workers, purged_class);
ShenandoahClassUnloadingTask unlink_task(phase, num_workers, purged_class);
_workers->run_task(&unlink_task);
}

View File

@ -32,13 +32,12 @@
#include "runtime/safepoint.hpp"
ShenandoahClassUnloadingTask::ShenandoahClassUnloadingTask(ShenandoahPhaseTimings::Phase phase,
BoolObjectClosure* is_alive,
uint num_workers,
bool unloading_occurred) :
WorkerTask("Shenandoah Class Unloading"),
_phase(phase),
_unloading_occurred(unloading_occurred),
_code_cache_task(num_workers, is_alive, unloading_occurred),
_code_cache_task(num_workers, unloading_occurred),
_klass_cleaning_task() {
assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint");
}

View File

@ -59,7 +59,6 @@ private:
KlassCleaningTask _klass_cleaning_task;
public:
ShenandoahClassUnloadingTask(ShenandoahPhaseTimings::Phase phase,
BoolObjectClosure* is_alive,
uint num_workers,
bool unloading_occurred);

View File

@ -1495,7 +1495,7 @@ JVM_ENTRY(void, MHN_clearCallSiteContext(JNIEnv* env, jobject igcls, jobject con
NoSafepointVerifier nsv;
MutexLocker mu2(THREAD, CodeCache_lock, Mutex::_no_safepoint_check_flag);
DependencyContext deps = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context());
marked = deps.remove_all_dependents();
marked = deps.remove_and_mark_for_deoptimization_all_dependents();
}
if (marked > 0) {
// At least one nmethod has been marked for deoptimization