Path: blob/master/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp
40957 views
/*1* Copyright (c) 2021, Red Hat, Inc. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "precompiled.hpp"2526#include "gc/shared/barrierSetNMethod.hpp"27#include "gc/shared/collectorCounters.hpp"28#include "gc/shenandoah/shenandoahBreakpoint.hpp"29#include "gc/shenandoah/shenandoahCollectorPolicy.hpp"30#include "gc/shenandoah/shenandoahConcurrentGC.hpp"31#include "gc/shenandoah/shenandoahFreeSet.hpp"32#include "gc/shenandoah/shenandoahLock.hpp"33#include "gc/shenandoah/shenandoahMark.inline.hpp"34#include "gc/shenandoah/shenandoahMonitoringSupport.hpp"35#include "gc/shenandoah/shenandoahOopClosures.inline.hpp"36#include "gc/shenandoah/shenandoahPhaseTimings.hpp"37#include "gc/shenandoah/shenandoahReferenceProcessor.hpp"38#include "gc/shenandoah/shenandoahRootProcessor.inline.hpp"39#include "gc/shenandoah/shenandoahStackWatermark.hpp"40#include "gc/shenandoah/shenandoahUtils.hpp"41#include "gc/shenandoah/shenandoahVerifier.hpp"42#include "gc/shenandoah/shenandoahVMOperations.hpp"43#include "gc/shenandoah/shenandoahWorkGroup.hpp"44#include "gc/shenandoah/shenandoahWorkerPolicy.hpp"45#include "memory/allocation.hpp"46#include "prims/jvmtiTagMap.hpp"47#include "runtime/vmThread.hpp"48#include "utilities/events.hpp"4950// Breakpoint support51class ShenandoahBreakpointGCScope : public StackObj {52public:53ShenandoahBreakpointGCScope() {54ShenandoahBreakpoint::at_before_gc();55}5657~ShenandoahBreakpointGCScope() {58ShenandoahBreakpoint::at_after_gc();59}60};6162class ShenandoahBreakpointMarkScope : public StackObj {63public:64ShenandoahBreakpointMarkScope() {65ShenandoahBreakpoint::at_after_marking_started();66}6768~ShenandoahBreakpointMarkScope() {69ShenandoahBreakpoint::at_before_marking_completed();70}71};7273ShenandoahConcurrentGC::ShenandoahConcurrentGC() :74_mark(),75_degen_point(ShenandoahDegenPoint::_degenerated_unset) {76}7778ShenandoahGC::ShenandoahDegenPoint ShenandoahConcurrentGC::degen_point() const {79return _degen_point;80}8182void ShenandoahConcurrentGC::cancel() {83ShenandoahConcurrentMark::cancel();84}8586bool ShenandoahConcurrentGC::collect(GCCause::Cause cause) {87ShenandoahHeap* const heap = ShenandoahHeap::heap();88if (cause == GCCause::_wb_breakpoint) {89ShenandoahBreakpoint::start_gc();90}91ShenandoahBreakpointGCScope breakpoint_gc_scope;9293// Reset for upcoming marking94entry_reset();9596// Start initial mark under STW97vmop_entry_init_mark();9899{100ShenandoahBreakpointMarkScope breakpoint_mark_scope;101// Concurrent mark roots102entry_mark_roots();103if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_outside_cycle)) return false;104105// Continue concurrent mark106entry_mark();107if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_mark)) return false;108}109110// Complete marking under STW, and start evacuation111vmop_entry_final_mark();112113// Concurrent stack processing114if (heap->is_evacuation_in_progress()) {115entry_thread_roots();116}117118// Process weak roots that might still point to regions that would be broken by cleanup119if (heap->is_concurrent_weak_root_in_progress()) {120entry_weak_refs();121entry_weak_roots();122}123124// Final mark might have reclaimed some immediate garbage, kick cleanup to reclaim125// the space. This would be the last action if there is nothing to evacuate.126entry_cleanup_early();127128{129ShenandoahHeapLocker locker(heap->lock());130heap->free_set()->log_status();131}132133// Perform concurrent class unloading134if (heap->unload_classes() &&135heap->is_concurrent_weak_root_in_progress()) {136entry_class_unloading();137}138139// Processing strong roots140// This may be skipped if there is nothing to update/evacuate.141// If so, strong_root_in_progress would be unset.142if (heap->is_concurrent_strong_root_in_progress()) {143entry_strong_roots();144}145146// Continue the cycle with evacuation and optional update-refs.147// This may be skipped if there is nothing to evacuate.148// If so, evac_in_progress would be unset by collection set preparation code.149if (heap->is_evacuation_in_progress()) {150// Concurrently evacuate151entry_evacuate();152if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_evac)) return false;153154// Perform update-refs phase.155vmop_entry_init_updaterefs();156entry_updaterefs();157if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_updaterefs)) return false;158159// Concurrent update thread roots160entry_update_thread_roots();161if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_updaterefs)) return false;162163vmop_entry_final_updaterefs();164165// Update references freed up collection set, kick the cleanup to reclaim the space.166entry_cleanup_complete();167} else {168vmop_entry_final_roots();169}170171return true;172}173174void ShenandoahConcurrentGC::vmop_entry_init_mark() {175ShenandoahHeap* const heap = ShenandoahHeap::heap();176TraceCollectorStats tcs(heap->monitoring_support()->stw_collection_counters());177ShenandoahTimingsTracker timing(ShenandoahPhaseTimings::init_mark_gross);178179heap->try_inject_alloc_failure();180VM_ShenandoahInitMark op(this);181VMThread::execute(&op); // jump to entry_init_mark() under safepoint182}183184void ShenandoahConcurrentGC::vmop_entry_final_mark() {185ShenandoahHeap* const heap = ShenandoahHeap::heap();186TraceCollectorStats tcs(heap->monitoring_support()->stw_collection_counters());187ShenandoahTimingsTracker timing(ShenandoahPhaseTimings::final_mark_gross);188189heap->try_inject_alloc_failure();190VM_ShenandoahFinalMarkStartEvac op(this);191VMThread::execute(&op); // jump to entry_final_mark under safepoint192}193194void ShenandoahConcurrentGC::vmop_entry_init_updaterefs() {195ShenandoahHeap* const heap = ShenandoahHeap::heap();196TraceCollectorStats tcs(heap->monitoring_support()->stw_collection_counters());197ShenandoahTimingsTracker timing(ShenandoahPhaseTimings::init_update_refs_gross);198199heap->try_inject_alloc_failure();200VM_ShenandoahInitUpdateRefs op(this);201VMThread::execute(&op);202}203204void ShenandoahConcurrentGC::vmop_entry_final_updaterefs() {205ShenandoahHeap* const heap = ShenandoahHeap::heap();206TraceCollectorStats tcs(heap->monitoring_support()->stw_collection_counters());207ShenandoahTimingsTracker timing(ShenandoahPhaseTimings::final_update_refs_gross);208209heap->try_inject_alloc_failure();210VM_ShenandoahFinalUpdateRefs op(this);211VMThread::execute(&op);212}213214void ShenandoahConcurrentGC::vmop_entry_final_roots() {215ShenandoahHeap* const heap = ShenandoahHeap::heap();216TraceCollectorStats tcs(heap->monitoring_support()->stw_collection_counters());217ShenandoahTimingsTracker timing(ShenandoahPhaseTimings::final_roots_gross);218219// This phase does not use workers, no need for setup220heap->try_inject_alloc_failure();221VM_ShenandoahFinalRoots op(this);222VMThread::execute(&op);223}224225void ShenandoahConcurrentGC::entry_init_mark() {226const char* msg = init_mark_event_message();227ShenandoahPausePhase gc_phase(msg, ShenandoahPhaseTimings::init_mark);228EventMark em("%s", msg);229230ShenandoahWorkerScope scope(ShenandoahHeap::heap()->workers(),231ShenandoahWorkerPolicy::calc_workers_for_init_marking(),232"init marking");233234op_init_mark();235}236237void ShenandoahConcurrentGC::entry_final_mark() {238const char* msg = final_mark_event_message();239ShenandoahPausePhase gc_phase(msg, ShenandoahPhaseTimings::final_mark);240EventMark em("%s", msg);241242ShenandoahWorkerScope scope(ShenandoahHeap::heap()->workers(),243ShenandoahWorkerPolicy::calc_workers_for_final_marking(),244"final marking");245246op_final_mark();247}248249void ShenandoahConcurrentGC::entry_init_updaterefs() {250static const char* msg = "Pause Init Update Refs";251ShenandoahPausePhase gc_phase(msg, ShenandoahPhaseTimings::init_update_refs);252EventMark em("%s", msg);253254// No workers used in this phase, no setup required255op_init_updaterefs();256}257258void ShenandoahConcurrentGC::entry_final_updaterefs() {259static const char* msg = "Pause Final Update Refs";260ShenandoahPausePhase gc_phase(msg, ShenandoahPhaseTimings::final_update_refs);261EventMark em("%s", msg);262263ShenandoahWorkerScope scope(ShenandoahHeap::heap()->workers(),264ShenandoahWorkerPolicy::calc_workers_for_final_update_ref(),265"final reference update");266267op_final_updaterefs();268}269270void ShenandoahConcurrentGC::entry_final_roots() {271static const char* msg = "Pause Final Roots";272ShenandoahPausePhase gc_phase(msg, ShenandoahPhaseTimings::final_roots);273EventMark em("%s", msg);274275op_final_roots();276}277278void ShenandoahConcurrentGC::entry_reset() {279ShenandoahHeap* const heap = ShenandoahHeap::heap();280TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());281static const char* msg = "Concurrent reset";282ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_reset);283EventMark em("%s", msg);284285ShenandoahWorkerScope scope(heap->workers(),286ShenandoahWorkerPolicy::calc_workers_for_conc_reset(),287"concurrent reset");288289heap->try_inject_alloc_failure();290op_reset();291}292293void ShenandoahConcurrentGC::entry_mark_roots() {294ShenandoahHeap* const heap = ShenandoahHeap::heap();295TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());296const char* msg = "Concurrent marking roots";297ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_mark_roots);298EventMark em("%s", msg);299300ShenandoahWorkerScope scope(heap->workers(),301ShenandoahWorkerPolicy::calc_workers_for_conc_marking(),302"concurrent marking roots");303304heap->try_inject_alloc_failure();305op_mark_roots();306}307308void ShenandoahConcurrentGC::entry_mark() {309ShenandoahHeap* const heap = ShenandoahHeap::heap();310TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());311const char* msg = conc_mark_event_message();312ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_mark);313EventMark em("%s", msg);314315ShenandoahWorkerScope scope(heap->workers(),316ShenandoahWorkerPolicy::calc_workers_for_conc_marking(),317"concurrent marking");318319heap->try_inject_alloc_failure();320op_mark();321}322323void ShenandoahConcurrentGC::entry_thread_roots() {324ShenandoahHeap* const heap = ShenandoahHeap::heap();325static const char* msg = "Concurrent thread roots";326ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_thread_roots);327EventMark em("%s", msg);328329ShenandoahWorkerScope scope(heap->workers(),330ShenandoahWorkerPolicy::calc_workers_for_conc_root_processing(),331msg);332333heap->try_inject_alloc_failure();334op_thread_roots();335}336337void ShenandoahConcurrentGC::entry_weak_refs() {338ShenandoahHeap* const heap = ShenandoahHeap::heap();339static const char* msg = "Concurrent weak references";340ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_weak_refs);341EventMark em("%s", msg);342343ShenandoahWorkerScope scope(heap->workers(),344ShenandoahWorkerPolicy::calc_workers_for_conc_refs_processing(),345"concurrent weak references");346347heap->try_inject_alloc_failure();348op_weak_refs();349}350351void ShenandoahConcurrentGC::entry_weak_roots() {352ShenandoahHeap* const heap = ShenandoahHeap::heap();353TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());354static const char* msg = "Concurrent weak roots";355ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_weak_roots);356EventMark em("%s", msg);357358ShenandoahWorkerScope scope(heap->workers(),359ShenandoahWorkerPolicy::calc_workers_for_conc_root_processing(),360"concurrent weak root");361362heap->try_inject_alloc_failure();363op_weak_roots();364}365366void ShenandoahConcurrentGC::entry_class_unloading() {367ShenandoahHeap* const heap = ShenandoahHeap::heap();368TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());369static const char* msg = "Concurrent class unloading";370ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_class_unload);371EventMark em("%s", msg);372373ShenandoahWorkerScope scope(heap->workers(),374ShenandoahWorkerPolicy::calc_workers_for_conc_root_processing(),375"concurrent class unloading");376377heap->try_inject_alloc_failure();378op_class_unloading();379}380381void ShenandoahConcurrentGC::entry_strong_roots() {382ShenandoahHeap* const heap = ShenandoahHeap::heap();383TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());384static const char* msg = "Concurrent strong roots";385ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_strong_roots);386EventMark em("%s", msg);387388ShenandoahGCWorkerPhase worker_phase(ShenandoahPhaseTimings::conc_strong_roots);389390ShenandoahWorkerScope scope(heap->workers(),391ShenandoahWorkerPolicy::calc_workers_for_conc_root_processing(),392"concurrent strong root");393394heap->try_inject_alloc_failure();395op_strong_roots();396}397398void ShenandoahConcurrentGC::entry_cleanup_early() {399ShenandoahHeap* const heap = ShenandoahHeap::heap();400TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());401static const char* msg = "Concurrent cleanup";402ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_cleanup_early, true /* log_heap_usage */);403EventMark em("%s", msg);404405// This phase does not use workers, no need for setup406heap->try_inject_alloc_failure();407op_cleanup_early();408}409410void ShenandoahConcurrentGC::entry_evacuate() {411ShenandoahHeap* const heap = ShenandoahHeap::heap();412TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());413414static const char* msg = "Concurrent evacuation";415ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_evac);416EventMark em("%s", msg);417418ShenandoahWorkerScope scope(heap->workers(),419ShenandoahWorkerPolicy::calc_workers_for_conc_evac(),420"concurrent evacuation");421422heap->try_inject_alloc_failure();423op_evacuate();424}425426void ShenandoahConcurrentGC::entry_update_thread_roots() {427ShenandoahHeap* const heap = ShenandoahHeap::heap();428TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());429430static const char* msg = "Concurrent update thread roots";431ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_update_thread_roots);432EventMark em("%s", msg);433434// No workers used in this phase, no setup required435heap->try_inject_alloc_failure();436op_update_thread_roots();437}438439void ShenandoahConcurrentGC::entry_updaterefs() {440ShenandoahHeap* const heap = ShenandoahHeap::heap();441TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());442static const char* msg = "Concurrent update references";443ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_update_refs);444EventMark em("%s", msg);445446ShenandoahWorkerScope scope(heap->workers(),447ShenandoahWorkerPolicy::calc_workers_for_conc_update_ref(),448"concurrent reference update");449450heap->try_inject_alloc_failure();451op_updaterefs();452}453454void ShenandoahConcurrentGC::entry_cleanup_complete() {455ShenandoahHeap* const heap = ShenandoahHeap::heap();456TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());457static const char* msg = "Concurrent cleanup";458ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_cleanup_complete, true /* log_heap_usage */);459EventMark em("%s", msg);460461// This phase does not use workers, no need for setup462heap->try_inject_alloc_failure();463op_cleanup_complete();464}465466void ShenandoahConcurrentGC::op_reset() {467ShenandoahHeap* const heap = ShenandoahHeap::heap();468if (ShenandoahPacing) {469heap->pacer()->setup_for_reset();470}471472heap->prepare_gc();473}474475class ShenandoahInitMarkUpdateRegionStateClosure : public ShenandoahHeapRegionClosure {476private:477ShenandoahMarkingContext* const _ctx;478public:479ShenandoahInitMarkUpdateRegionStateClosure() : _ctx(ShenandoahHeap::heap()->marking_context()) {}480481void heap_region_do(ShenandoahHeapRegion* r) {482assert(!r->has_live(), "Region " SIZE_FORMAT " should have no live data", r->index());483if (r->is_active()) {484// Check if region needs updating its TAMS. We have updated it already during concurrent485// reset, so it is very likely we don't need to do another write here.486if (_ctx->top_at_mark_start(r) != r->top()) {487_ctx->capture_top_at_mark_start(r);488}489} else {490assert(_ctx->top_at_mark_start(r) == r->top(),491"Region " SIZE_FORMAT " should already have correct TAMS", r->index());492}493}494495bool is_thread_safe() { return true; }496};497498void ShenandoahConcurrentGC::op_init_mark() {499ShenandoahHeap* const heap = ShenandoahHeap::heap();500assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Should be at safepoint");501assert(Thread::current()->is_VM_thread(), "can only do this in VMThread");502503assert(heap->marking_context()->is_bitmap_clear(), "need clear marking bitmap");504assert(!heap->marking_context()->is_complete(), "should not be complete");505assert(!heap->has_forwarded_objects(), "No forwarded objects on this path");506507if (ShenandoahVerify) {508heap->verifier()->verify_before_concmark();509}510511if (VerifyBeforeGC) {512Universe::verify();513}514515heap->set_concurrent_mark_in_progress(true);516517{518ShenandoahGCPhase phase(ShenandoahPhaseTimings::init_update_region_states);519ShenandoahInitMarkUpdateRegionStateClosure cl;520heap->parallel_heap_region_iterate(&cl);521}522523// Weak reference processing524ShenandoahReferenceProcessor* rp = heap->ref_processor();525rp->reset_thread_locals();526rp->set_soft_reference_policy(heap->soft_ref_policy()->should_clear_all_soft_refs());527528// Make above changes visible to worker threads529OrderAccess::fence();530// Arm nmethods for concurrent marking. When a nmethod is about to be executed,531// we need to make sure that all its metadata are marked. alternative is to remark532// thread roots at final mark pause, but it can be potential latency killer.533if (heap->unload_classes()) {534ShenandoahCodeRoots::arm_nmethods();535}536537ShenandoahStackWatermark::change_epoch_id();538if (ShenandoahPacing) {539heap->pacer()->setup_for_mark();540}541}542543void ShenandoahConcurrentGC::op_mark_roots() {544_mark.mark_concurrent_roots();545}546547void ShenandoahConcurrentGC::op_mark() {548_mark.concurrent_mark();549}550551void ShenandoahConcurrentGC::op_final_mark() {552ShenandoahHeap* const heap = ShenandoahHeap::heap();553assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Should be at safepoint");554assert(!heap->has_forwarded_objects(), "No forwarded objects on this path");555556if (ShenandoahVerify) {557heap->verifier()->verify_roots_no_forwarded();558}559560if (!heap->cancelled_gc()) {561_mark.finish_mark();562assert(!heap->cancelled_gc(), "STW mark cannot OOM");563564// Notify JVMTI that the tagmap table will need cleaning.565JvmtiTagMap::set_needs_cleaning();566567heap->prepare_regions_and_collection_set(true /*concurrent*/);568569// Has to be done after cset selection570heap->prepare_concurrent_roots();571572if (!heap->collection_set()->is_empty()) {573if (ShenandoahVerify) {574heap->verifier()->verify_before_evacuation();575}576577heap->set_evacuation_in_progress(true);578// From here on, we need to update references.579heap->set_has_forwarded_objects(true);580581// Verify before arming for concurrent processing.582// Otherwise, verification can trigger stack processing.583if (ShenandoahVerify) {584heap->verifier()->verify_during_evacuation();585}586587// Arm nmethods/stack for concurrent processing588ShenandoahCodeRoots::arm_nmethods();589ShenandoahStackWatermark::change_epoch_id();590591// Notify JVMTI that oops are changed.592JvmtiTagMap::set_needs_rehashing();593594if (ShenandoahPacing) {595heap->pacer()->setup_for_evac();596}597} else {598if (ShenandoahVerify) {599heap->verifier()->verify_after_concmark();600}601602if (VerifyAfterGC) {603Universe::verify();604}605}606}607}608609class ShenandoahConcurrentEvacThreadClosure : public ThreadClosure {610private:611OopClosure* const _oops;612613public:614ShenandoahConcurrentEvacThreadClosure(OopClosure* oops);615void do_thread(Thread* thread);616};617618ShenandoahConcurrentEvacThreadClosure::ShenandoahConcurrentEvacThreadClosure(OopClosure* oops) :619_oops(oops) {620}621622void ShenandoahConcurrentEvacThreadClosure::do_thread(Thread* thread) {623JavaThread* const jt = thread->as_Java_thread();624StackWatermarkSet::finish_processing(jt, _oops, StackWatermarkKind::gc);625}626627class ShenandoahConcurrentEvacUpdateThreadTask : public AbstractGangTask {628private:629ShenandoahJavaThreadsIterator _java_threads;630631public:632ShenandoahConcurrentEvacUpdateThreadTask(uint n_workers) :633AbstractGangTask("Shenandoah Evacuate/Update Concurrent Thread Roots"),634_java_threads(ShenandoahPhaseTimings::conc_thread_roots, n_workers) {635}636637void work(uint worker_id) {638// ShenandoahEvacOOMScope has to be setup by ShenandoahContextEvacuateUpdateRootsClosure.639// Otherwise, may deadlock with watermark lock640ShenandoahContextEvacuateUpdateRootsClosure oops_cl;641ShenandoahConcurrentEvacThreadClosure thr_cl(&oops_cl);642_java_threads.threads_do(&thr_cl, worker_id);643}644};645646void ShenandoahConcurrentGC::op_thread_roots() {647ShenandoahHeap* const heap = ShenandoahHeap::heap();648assert(heap->is_evacuation_in_progress(), "Checked by caller");649ShenandoahGCWorkerPhase worker_phase(ShenandoahPhaseTimings::conc_thread_roots);650ShenandoahConcurrentEvacUpdateThreadTask task(heap->workers()->active_workers());651heap->workers()->run_task(&task);652}653654void ShenandoahConcurrentGC::op_weak_refs() {655ShenandoahHeap* const heap = ShenandoahHeap::heap();656assert(heap->is_concurrent_weak_root_in_progress(), "Only during this phase");657// Concurrent weak refs processing658ShenandoahGCWorkerPhase worker_phase(ShenandoahPhaseTimings::conc_weak_refs);659ShenandoahBreakpoint::at_after_reference_processing_started();660heap->ref_processor()->process_references(ShenandoahPhaseTimings::conc_weak_refs, heap->workers(), true /* concurrent */);661}662663class ShenandoahEvacUpdateCleanupOopStorageRootsClosure : public BasicOopIterateClosure {664private:665ShenandoahHeap* const _heap;666ShenandoahMarkingContext* const _mark_context;667bool _evac_in_progress;668Thread* const _thread;669670public:671ShenandoahEvacUpdateCleanupOopStorageRootsClosure();672void do_oop(oop* p);673void do_oop(narrowOop* p);674};675676ShenandoahEvacUpdateCleanupOopStorageRootsClosure::ShenandoahEvacUpdateCleanupOopStorageRootsClosure() :677_heap(ShenandoahHeap::heap()),678_mark_context(ShenandoahHeap::heap()->marking_context()),679_evac_in_progress(ShenandoahHeap::heap()->is_evacuation_in_progress()),680_thread(Thread::current()) {681}682683void ShenandoahEvacUpdateCleanupOopStorageRootsClosure::do_oop(oop* p) {684const oop obj = RawAccess<>::oop_load(p);685if (!CompressedOops::is_null(obj)) {686if (!_mark_context->is_marked(obj)) {687shenandoah_assert_correct(p, obj);688Atomic::cmpxchg(p, obj, oop(NULL));689} else if (_evac_in_progress && _heap->in_collection_set(obj)) {690oop resolved = ShenandoahBarrierSet::resolve_forwarded_not_null(obj);691if (resolved == obj) {692resolved = _heap->evacuate_object(obj, _thread);693}694Atomic::cmpxchg(p, obj, resolved);695assert(_heap->cancelled_gc() ||696_mark_context->is_marked(resolved) && !_heap->in_collection_set(resolved),697"Sanity");698}699}700}701702void ShenandoahEvacUpdateCleanupOopStorageRootsClosure::do_oop(narrowOop* p) {703ShouldNotReachHere();704}705706class ShenandoahIsCLDAliveClosure : public CLDClosure {707public:708void do_cld(ClassLoaderData* cld) {709cld->is_alive();710}711};712713class ShenandoahIsNMethodAliveClosure: public NMethodClosure {714public:715void do_nmethod(nmethod* n) {716n->is_unloading();717}718};719720// This task not only evacuates/updates marked weak roots, but also "NULL"721// dead weak roots.722class ShenandoahConcurrentWeakRootsEvacUpdateTask : public AbstractGangTask {723private:724ShenandoahVMWeakRoots<true /*concurrent*/> _vm_roots;725726// Roots related to concurrent class unloading727ShenandoahClassLoaderDataRoots<true /* concurrent */, true /* single thread*/>728_cld_roots;729ShenandoahConcurrentNMethodIterator _nmethod_itr;730ShenandoahPhaseTimings::Phase _phase;731732public:733ShenandoahConcurrentWeakRootsEvacUpdateTask(ShenandoahPhaseTimings::Phase phase) :734AbstractGangTask("Shenandoah Evacuate/Update Concurrent Weak Roots"),735_vm_roots(phase),736_cld_roots(phase, ShenandoahHeap::heap()->workers()->active_workers()),737_nmethod_itr(ShenandoahCodeRoots::table()),738_phase(phase) {739if (ShenandoahHeap::heap()->unload_classes()) {740MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);741_nmethod_itr.nmethods_do_begin();742}743}744745~ShenandoahConcurrentWeakRootsEvacUpdateTask() {746if (ShenandoahHeap::heap()->unload_classes()) {747MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);748_nmethod_itr.nmethods_do_end();749}750// Notify runtime data structures of potentially dead oops751_vm_roots.report_num_dead();752}753754void work(uint worker_id) {755ShenandoahConcurrentWorkerSession worker_session(worker_id);756{757ShenandoahEvacOOMScope oom;758// jni_roots and weak_roots are OopStorage backed roots, concurrent iteration759// may race against OopStorage::release() calls.760ShenandoahEvacUpdateCleanupOopStorageRootsClosure cl;761_vm_roots.oops_do(&cl, worker_id);762}763764// If we are going to perform concurrent class unloading later on, we need to765// cleanup the weak oops in CLD and determinate nmethod's unloading state, so that we766// can cleanup immediate garbage sooner.767if (ShenandoahHeap::heap()->unload_classes()) {768// Applies ShenandoahIsCLDAlive closure to CLDs, native barrier will either NULL the769// CLD's holder or evacuate it.770{771ShenandoahIsCLDAliveClosure is_cld_alive;772_cld_roots.cld_do(&is_cld_alive, worker_id);773}774775// Applies ShenandoahIsNMethodAliveClosure to registered nmethods.776// The closure calls nmethod->is_unloading(). The is_unloading777// state is cached, therefore, during concurrent class unloading phase,778// we will not touch the metadata of unloading nmethods779{780ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CodeCacheRoots, worker_id);781ShenandoahIsNMethodAliveClosure is_nmethod_alive;782_nmethod_itr.nmethods_do(&is_nmethod_alive);783}784}785}786};787788void ShenandoahConcurrentGC::op_weak_roots() {789ShenandoahHeap* const heap = ShenandoahHeap::heap();790assert(heap->is_concurrent_weak_root_in_progress(), "Only during this phase");791// Concurrent weak root processing792{793ShenandoahTimingsTracker t(ShenandoahPhaseTimings::conc_weak_roots_work);794ShenandoahGCWorkerPhase worker_phase(ShenandoahPhaseTimings::conc_weak_roots_work);795ShenandoahConcurrentWeakRootsEvacUpdateTask task(ShenandoahPhaseTimings::conc_weak_roots_work);796heap->workers()->run_task(&task);797}798799// Perform handshake to flush out dead oops800{801ShenandoahTimingsTracker t(ShenandoahPhaseTimings::conc_weak_roots_rendezvous);802heap->rendezvous_threads();803}804}805806void ShenandoahConcurrentGC::op_class_unloading() {807ShenandoahHeap* const heap = ShenandoahHeap::heap();808assert (heap->is_concurrent_weak_root_in_progress() &&809heap->unload_classes(),810"Checked by caller");811heap->do_class_unloading();812}813814class ShenandoahEvacUpdateCodeCacheClosure : public NMethodClosure {815private:816BarrierSetNMethod* const _bs;817ShenandoahEvacuateUpdateMetadataClosure<> _cl;818819public:820ShenandoahEvacUpdateCodeCacheClosure() :821_bs(BarrierSet::barrier_set()->barrier_set_nmethod()),822_cl() {823}824825void do_nmethod(nmethod* n) {826ShenandoahNMethod* data = ShenandoahNMethod::gc_data(n);827ShenandoahReentrantLocker locker(data->lock());828// Setup EvacOOM scope below reentrant lock to avoid deadlock with829// nmethod_entry_barrier830ShenandoahEvacOOMScope oom;831data->oops_do(&_cl, true/*fix relocation*/);832_bs->disarm(n);833}834};835836class ShenandoahConcurrentRootsEvacUpdateTask : public AbstractGangTask {837private:838ShenandoahPhaseTimings::Phase _phase;839ShenandoahVMRoots<true /*concurrent*/> _vm_roots;840ShenandoahClassLoaderDataRoots<true /*concurrent*/, false /*single threaded*/> _cld_roots;841ShenandoahConcurrentNMethodIterator _nmethod_itr;842843public:844ShenandoahConcurrentRootsEvacUpdateTask(ShenandoahPhaseTimings::Phase phase) :845AbstractGangTask("Shenandoah Evacuate/Update Concurrent Strong Roots"),846_phase(phase),847_vm_roots(phase),848_cld_roots(phase, ShenandoahHeap::heap()->workers()->active_workers()),849_nmethod_itr(ShenandoahCodeRoots::table()) {850if (!ShenandoahHeap::heap()->unload_classes()) {851MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);852_nmethod_itr.nmethods_do_begin();853}854}855856~ShenandoahConcurrentRootsEvacUpdateTask() {857if (!ShenandoahHeap::heap()->unload_classes()) {858MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);859_nmethod_itr.nmethods_do_end();860}861}862863void work(uint worker_id) {864ShenandoahConcurrentWorkerSession worker_session(worker_id);865{866ShenandoahEvacOOMScope oom;867{868// vm_roots and weak_roots are OopStorage backed roots, concurrent iteration869// may race against OopStorage::release() calls.870ShenandoahContextEvacuateUpdateRootsClosure cl;871_vm_roots.oops_do<ShenandoahContextEvacuateUpdateRootsClosure>(&cl, worker_id);872}873874{875ShenandoahEvacuateUpdateMetadataClosure<> cl;876CLDToOopClosure clds(&cl, ClassLoaderData::_claim_strong);877_cld_roots.cld_do(&clds, worker_id);878}879}880881// Cannot setup ShenandoahEvacOOMScope here, due to potential deadlock with nmethod_entry_barrier.882if (!ShenandoahHeap::heap()->unload_classes()) {883ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CodeCacheRoots, worker_id);884ShenandoahEvacUpdateCodeCacheClosure cl;885_nmethod_itr.nmethods_do(&cl);886}887}888};889890void ShenandoahConcurrentGC::op_strong_roots() {891ShenandoahHeap* const heap = ShenandoahHeap::heap();892assert(heap->is_concurrent_strong_root_in_progress(), "Checked by caller");893ShenandoahConcurrentRootsEvacUpdateTask task(ShenandoahPhaseTimings::conc_strong_roots);894heap->workers()->run_task(&task);895heap->set_concurrent_strong_root_in_progress(false);896}897898void ShenandoahConcurrentGC::op_cleanup_early() {899ShenandoahHeap::heap()->free_set()->recycle_trash();900}901902void ShenandoahConcurrentGC::op_evacuate() {903ShenandoahHeap::heap()->evacuate_collection_set(true /*concurrent*/);904}905906void ShenandoahConcurrentGC::op_init_updaterefs() {907ShenandoahHeap* const heap = ShenandoahHeap::heap();908heap->set_evacuation_in_progress(false);909heap->set_concurrent_weak_root_in_progress(false);910heap->prepare_update_heap_references(true /*concurrent*/);911heap->set_update_refs_in_progress(true);912913if (ShenandoahPacing) {914heap->pacer()->setup_for_updaterefs();915}916}917918void ShenandoahConcurrentGC::op_updaterefs() {919ShenandoahHeap::heap()->update_heap_references(true /*concurrent*/);920}921922class ShenandoahUpdateThreadClosure : public HandshakeClosure {923private:924ShenandoahUpdateRefsClosure _cl;925public:926ShenandoahUpdateThreadClosure();927void do_thread(Thread* thread);928};929930ShenandoahUpdateThreadClosure::ShenandoahUpdateThreadClosure() :931HandshakeClosure("Shenandoah Update Thread Roots") {932}933934void ShenandoahUpdateThreadClosure::do_thread(Thread* thread) {935if (thread->is_Java_thread()) {936JavaThread* jt = thread->as_Java_thread();937ResourceMark rm;938jt->oops_do(&_cl, NULL);939}940}941942void ShenandoahConcurrentGC::op_update_thread_roots() {943ShenandoahUpdateThreadClosure cl;944Handshake::execute(&cl);945}946947void ShenandoahConcurrentGC::op_final_updaterefs() {948ShenandoahHeap* const heap = ShenandoahHeap::heap();949assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "must be at safepoint");950assert(!heap->_update_refs_iterator.has_next(), "Should have finished update references");951952heap->finish_concurrent_roots();953954// Clear cancelled GC, if set. On cancellation path, the block before would handle955// everything.956if (heap->cancelled_gc()) {957heap->clear_cancelled_gc();958}959960// Has to be done before cset is clear961if (ShenandoahVerify) {962heap->verifier()->verify_roots_in_to_space();963}964965heap->update_heap_region_states(true /*concurrent*/);966967heap->set_update_refs_in_progress(false);968heap->set_has_forwarded_objects(false);969970if (ShenandoahVerify) {971heap->verifier()->verify_after_updaterefs();972}973974if (VerifyAfterGC) {975Universe::verify();976}977978heap->rebuild_free_set(true /*concurrent*/);979}980981void ShenandoahConcurrentGC::op_final_roots() {982ShenandoahHeap::heap()->set_concurrent_weak_root_in_progress(false);983}984985void ShenandoahConcurrentGC::op_cleanup_complete() {986ShenandoahHeap::heap()->free_set()->recycle_trash();987}988989bool ShenandoahConcurrentGC::check_cancellation_and_abort(ShenandoahDegenPoint point) {990if (ShenandoahHeap::heap()->cancelled_gc()) {991_degen_point = point;992return true;993}994return false;995}996997const char* ShenandoahConcurrentGC::init_mark_event_message() const {998ShenandoahHeap* const heap = ShenandoahHeap::heap();999assert(!heap->has_forwarded_objects(), "Should not have forwarded objects here");1000if (heap->unload_classes()) {1001return "Pause Init Mark (unload classes)";1002} else {1003return "Pause Init Mark";1004}1005}10061007const char* ShenandoahConcurrentGC::final_mark_event_message() const {1008ShenandoahHeap* const heap = ShenandoahHeap::heap();1009assert(!heap->has_forwarded_objects(), "Should not have forwarded objects here");1010if (heap->unload_classes()) {1011return "Pause Final Mark (unload classes)";1012} else {1013return "Pause Final Mark";1014}1015}10161017const char* ShenandoahConcurrentGC::conc_mark_event_message() const {1018ShenandoahHeap* const heap = ShenandoahHeap::heap();1019assert(!heap->has_forwarded_objects(), "Should not have forwarded objects here");1020if (heap->unload_classes()) {1021return "Concurrent marking (unload classes)";1022} else {1023return "Concurrent marking";1024}1025}102610271028