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.
|
// 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);
|
assert_locked_or_safepoint(CodeCache_lock);
|
||||||
UnloadingScope scope(is_alive);
|
|
||||||
CompiledMethodIterator iter(CompiledMethodIterator::only_alive);
|
CompiledMethodIterator iter(CompiledMethodIterator::only_alive);
|
||||||
while(iter.next()) {
|
while(iter.next()) {
|
||||||
iter.method()->do_unloading(unloading_occurred);
|
iter.method()->do_unloading(unloading_occurred);
|
||||||
|
@ -197,7 +197,7 @@ class CodeCache : AllStatic {
|
|||||||
~UnloadingScope();
|
~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 uint8_t unloading_cycle() { return _unloading_cycle; }
|
||||||
|
|
||||||
static void increment_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
|
// 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();
|
nmethodBucket* b = dependencies_not_unloading();
|
||||||
set_dependencies(NULL);
|
set_dependencies(NULL);
|
||||||
int marked = 0;
|
int marked = 0;
|
||||||
int removed = 0;
|
|
||||||
while (b != NULL) {
|
while (b != NULL) {
|
||||||
nmethod* nm = b->get_nmethod();
|
nmethod* nm = b->get_nmethod();
|
||||||
if (b->count() > 0 && nm->is_alive() && !nm->is_marked_for_deoptimization()) {
|
if (b->count() > 0 && nm->is_alive() && !nm->is_marked_for_deoptimization()) {
|
||||||
nm->mark_for_deoptimization();
|
nm->mark_for_deoptimization();
|
||||||
marked++;
|
marked++;
|
||||||
}
|
}
|
||||||
nmethodBucket* next = b->next_not_unloading();
|
b = release_and_get_next_not_unloading(b);
|
||||||
removed++;
|
|
||||||
release(b);
|
|
||||||
b = next;
|
|
||||||
}
|
|
||||||
if (UsePerfData && removed > 0) {
|
|
||||||
_perf_total_buckets_deallocated_count->inc(removed);
|
|
||||||
}
|
}
|
||||||
return marked;
|
return marked;
|
||||||
}
|
}
|
||||||
|
@ -120,8 +120,10 @@ class DependencyContext : public StackObj {
|
|||||||
int mark_dependent_nmethods(DepChange& changes);
|
int mark_dependent_nmethods(DepChange& changes);
|
||||||
void add_dependent_nmethod(nmethod* nm);
|
void add_dependent_nmethod(nmethod* nm);
|
||||||
void remove_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();
|
void clean_unloading_dependents();
|
||||||
|
static nmethodBucket* release_and_get_next_not_unloading(nmethodBucket* b);
|
||||||
static void purge_dependency_contexts();
|
static void purge_dependency_contexts();
|
||||||
static void release(nmethodBucket* b);
|
static void release(nmethodBucket* b);
|
||||||
static void cleaning_start();
|
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,
|
void G1CollectedHeap::complete_cleaning(bool class_unloading_occurred) {
|
||||||
bool class_unloading_occurred) {
|
|
||||||
uint num_workers = workers()->active_workers();
|
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);
|
workers()->run_task(&unlink_task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1261,7 +1261,7 @@ public:
|
|||||||
void rebuild_code_roots();
|
void rebuild_code_roots();
|
||||||
|
|
||||||
// Performs cleaning of data structures after class unloading.
|
// 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
|
// Verification
|
||||||
|
|
||||||
|
@ -1689,8 +1689,9 @@ void G1ConcurrentMark::weak_refs_work() {
|
|||||||
// Unload Klasses, String, Code Cache, etc.
|
// Unload Klasses, String, Code Cache, etc.
|
||||||
if (ClassUnloadingWithConcurrentMark) {
|
if (ClassUnloadingWithConcurrentMark) {
|
||||||
GCTraceTime(Debug, gc, phases) debug("Class Unloading", _gc_timer_cm);
|
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);
|
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.
|
// Class unloading and cleanup.
|
||||||
if (ClassUnloading) {
|
if (ClassUnloading) {
|
||||||
GCTraceTime(Debug, gc, phases) debug("Phase 1: Class Unloading and Cleanup", scope()->timer());
|
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.
|
// Unload classes and purge the SystemDictionary.
|
||||||
bool purged_class = SystemDictionary::do_unloading(scope()->timer());
|
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);
|
scope()->tracer()->report_object_count_after_gc(&_is_alive);
|
||||||
|
@ -51,12 +51,11 @@ void JVMCICleaningTask::work(bool unloading_occurred) {
|
|||||||
}
|
}
|
||||||
#endif // INCLUDE_JVMCI
|
#endif // INCLUDE_JVMCI
|
||||||
|
|
||||||
G1ParallelCleaningTask::G1ParallelCleaningTask(BoolObjectClosure* is_alive,
|
G1ParallelCleaningTask::G1ParallelCleaningTask(uint num_workers,
|
||||||
uint num_workers,
|
|
||||||
bool unloading_occurred) :
|
bool unloading_occurred) :
|
||||||
WorkerTask("G1 Parallel Cleaning"),
|
WorkerTask("G1 Parallel Cleaning"),
|
||||||
_unloading_occurred(unloading_occurred),
|
_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)
|
JVMCI_ONLY(_jvmci_cleaning_task() COMMA)
|
||||||
_klass_cleaning_task() {
|
_klass_cleaning_task() {
|
||||||
}
|
}
|
||||||
|
@ -54,8 +54,7 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// The constructor is run in the VMThread.
|
// The constructor is run in the VMThread.
|
||||||
G1ParallelCleaningTask(BoolObjectClosure* is_alive,
|
G1ParallelCleaningTask(uint num_workers,
|
||||||
uint num_workers,
|
|
||||||
bool unloading_occurred);
|
bool unloading_occurred);
|
||||||
|
|
||||||
void work(uint worker_id);
|
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);
|
GCTraceTime(Debug, gc, phases) tm_m("Class Unloading", &_gc_timer);
|
||||||
|
CodeCache::UnloadingScope scope(is_alive_closure());
|
||||||
|
|
||||||
// Follow system dictionary roots and unload classes.
|
// Follow system dictionary roots and unload classes.
|
||||||
bool purged_class = SystemDictionary::do_unloading(&_gc_timer);
|
bool purged_class = SystemDictionary::do_unloading(&_gc_timer);
|
||||||
|
|
||||||
// Unload nmethods.
|
// Unload nmethods.
|
||||||
CodeCache::do_unloading(is_alive_closure(), purged_class);
|
CodeCache::do_unloading(purged_class);
|
||||||
|
|
||||||
// Prune dead klasses from subklass/sibling/implementor lists.
|
// Prune dead klasses from subklass/sibling/implementor lists.
|
||||||
Klass::clean_weak_klass_links(purged_class);
|
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());
|
GCTraceTime(Debug, gc, phases) tm_m("Class Unloading", gc_timer());
|
||||||
|
CodeCache::UnloadingScope scope(&is_alive);
|
||||||
|
|
||||||
// Unload classes and purge the SystemDictionary.
|
// Unload classes and purge the SystemDictionary.
|
||||||
bool purged_class = SystemDictionary::do_unloading(gc_timer());
|
bool purged_class = SystemDictionary::do_unloading(gc_timer());
|
||||||
|
|
||||||
// Unload nmethods.
|
// Unload nmethods.
|
||||||
CodeCache::do_unloading(&is_alive, purged_class);
|
CodeCache::do_unloading(purged_class);
|
||||||
|
|
||||||
// Prune dead klasses from subklass/sibling/implementor lists.
|
// Prune dead klasses from subklass/sibling/implementor lists.
|
||||||
Klass::clean_weak_klass_links(purged_class);
|
Klass::clean_weak_klass_links(purged_class);
|
||||||
|
@ -32,8 +32,7 @@
|
|||||||
#include "logging/log.hpp"
|
#include "logging/log.hpp"
|
||||||
#include "runtime/atomic.hpp"
|
#include "runtime/atomic.hpp"
|
||||||
|
|
||||||
CodeCacheUnloadingTask::CodeCacheUnloadingTask(uint num_workers, BoolObjectClosure* is_alive, bool unloading_occurred) :
|
CodeCacheUnloadingTask::CodeCacheUnloadingTask(uint num_workers, bool unloading_occurred) :
|
||||||
_unloading_scope(is_alive),
|
|
||||||
_unloading_occurred(unloading_occurred),
|
_unloading_occurred(unloading_occurred),
|
||||||
_num_workers(num_workers),
|
_num_workers(num_workers),
|
||||||
_first_nmethod(NULL),
|
_first_nmethod(NULL),
|
||||||
|
@ -32,7 +32,6 @@
|
|||||||
|
|
||||||
class CodeCacheUnloadingTask {
|
class CodeCacheUnloadingTask {
|
||||||
|
|
||||||
CodeCache::UnloadingScope _unloading_scope;
|
|
||||||
const bool _unloading_occurred;
|
const bool _unloading_occurred;
|
||||||
const uint _num_workers;
|
const uint _num_workers;
|
||||||
|
|
||||||
@ -41,7 +40,7 @@ class CodeCacheUnloadingTask {
|
|||||||
CompiledMethod* volatile _claimed_nmethod;
|
CompiledMethod* volatile _claimed_nmethod;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CodeCacheUnloadingTask(uint num_workers, BoolObjectClosure* is_alive, bool unloading_occurred);
|
CodeCacheUnloadingTask(uint num_workers, bool unloading_occurred);
|
||||||
~CodeCacheUnloadingTask();
|
~CodeCacheUnloadingTask();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -73,6 +73,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
|
#include "code/codeCache.hpp"
|
||||||
#include "memory/classLoaderMetaspace.hpp"
|
#include "memory/classLoaderMetaspace.hpp"
|
||||||
#include "memory/metaspaceUtils.hpp"
|
#include "memory/metaspaceUtils.hpp"
|
||||||
#include "oops/compressedOops.inline.hpp"
|
#include "oops/compressedOops.inline.hpp"
|
||||||
@ -1790,13 +1791,14 @@ void ShenandoahHeap::stw_unload_classes(bool full_gc) {
|
|||||||
ShenandoahPhaseTimings::Phase phase = full_gc ?
|
ShenandoahPhaseTimings::Phase phase = full_gc ?
|
||||||
ShenandoahPhaseTimings::full_gc_purge_class_unload :
|
ShenandoahPhaseTimings::full_gc_purge_class_unload :
|
||||||
ShenandoahPhaseTimings::degen_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);
|
ShenandoahGCPhase gc_phase(phase);
|
||||||
ShenandoahGCWorkerPhase worker_phase(phase);
|
ShenandoahGCWorkerPhase worker_phase(phase);
|
||||||
bool purged_class = SystemDictionary::do_unloading(gc_timer());
|
bool purged_class = SystemDictionary::do_unloading(gc_timer());
|
||||||
|
|
||||||
ShenandoahIsAliveSelector is_alive;
|
|
||||||
uint num_workers = _workers->active_workers();
|
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);
|
_workers->run_task(&unlink_task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,13 +32,12 @@
|
|||||||
#include "runtime/safepoint.hpp"
|
#include "runtime/safepoint.hpp"
|
||||||
|
|
||||||
ShenandoahClassUnloadingTask::ShenandoahClassUnloadingTask(ShenandoahPhaseTimings::Phase phase,
|
ShenandoahClassUnloadingTask::ShenandoahClassUnloadingTask(ShenandoahPhaseTimings::Phase phase,
|
||||||
BoolObjectClosure* is_alive,
|
|
||||||
uint num_workers,
|
uint num_workers,
|
||||||
bool unloading_occurred) :
|
bool unloading_occurred) :
|
||||||
WorkerTask("Shenandoah Class Unloading"),
|
WorkerTask("Shenandoah Class Unloading"),
|
||||||
_phase(phase),
|
_phase(phase),
|
||||||
_unloading_occurred(unloading_occurred),
|
_unloading_occurred(unloading_occurred),
|
||||||
_code_cache_task(num_workers, is_alive, unloading_occurred),
|
_code_cache_task(num_workers, unloading_occurred),
|
||||||
_klass_cleaning_task() {
|
_klass_cleaning_task() {
|
||||||
assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint");
|
assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint");
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,6 @@ private:
|
|||||||
KlassCleaningTask _klass_cleaning_task;
|
KlassCleaningTask _klass_cleaning_task;
|
||||||
public:
|
public:
|
||||||
ShenandoahClassUnloadingTask(ShenandoahPhaseTimings::Phase phase,
|
ShenandoahClassUnloadingTask(ShenandoahPhaseTimings::Phase phase,
|
||||||
BoolObjectClosure* is_alive,
|
|
||||||
uint num_workers,
|
uint num_workers,
|
||||||
bool unloading_occurred);
|
bool unloading_occurred);
|
||||||
|
|
||||||
|
@ -1495,7 +1495,7 @@ JVM_ENTRY(void, MHN_clearCallSiteContext(JNIEnv* env, jobject igcls, jobject con
|
|||||||
NoSafepointVerifier nsv;
|
NoSafepointVerifier nsv;
|
||||||
MutexLocker mu2(THREAD, CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
MutexLocker mu2(THREAD, CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||||
DependencyContext deps = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context());
|
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) {
|
if (marked > 0) {
|
||||||
// At least one nmethod has been marked for deoptimization
|
// At least one nmethod has been marked for deoptimization
|
||||||
|
Loading…
Reference in New Issue
Block a user