8291718: Remove mark_for_deoptimization from klass unloading
Reviewed-by: eosterlund, dlong
This commit is contained in:
parent
9d7c13eb14
commit
fd4b2f2868
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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() {
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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),
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -59,7 +59,6 @@ private:
|
||||
KlassCleaningTask _klass_cleaning_task;
|
||||
public:
|
||||
ShenandoahClassUnloadingTask(ShenandoahPhaseTimings::Phase phase,
|
||||
BoolObjectClosure* is_alive,
|
||||
uint num_workers,
|
||||
bool unloading_occurred);
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user