Path: blob/master/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp
40957 views
/*1* Copyright (c) 2013, 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/satbMarkQueue.hpp"27#include "gc/shared/strongRootsScope.hpp"28#include "gc/shared/taskTerminator.hpp"29#include "gc/shenandoah/shenandoahBarrierSet.inline.hpp"30#include "gc/shenandoah/shenandoahClosures.inline.hpp"31#include "gc/shenandoah/shenandoahConcurrentMark.hpp"32#include "gc/shenandoah/shenandoahHeap.inline.hpp"33#include "gc/shenandoah/shenandoahMark.inline.hpp"34#include "gc/shenandoah/shenandoahReferenceProcessor.hpp"35#include "gc/shenandoah/shenandoahRootProcessor.inline.hpp"36#include "gc/shenandoah/shenandoahOopClosures.inline.hpp"37#include "gc/shenandoah/shenandoahPhaseTimings.hpp"38#include "gc/shenandoah/shenandoahStringDedup.hpp"39#include "gc/shenandoah/shenandoahTaskqueue.inline.hpp"40#include "gc/shenandoah/shenandoahUtils.hpp"41#include "memory/iterator.inline.hpp"42#include "memory/resourceArea.hpp"4344class ShenandoahUpdateRootsTask : public AbstractGangTask {45private:46ShenandoahRootUpdater* _root_updater;47bool _check_alive;48public:49ShenandoahUpdateRootsTask(ShenandoahRootUpdater* root_updater, bool check_alive) :50AbstractGangTask("Shenandoah Update Roots"),51_root_updater(root_updater),52_check_alive(check_alive){53}5455void work(uint worker_id) {56assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a safepoint");57ShenandoahParallelWorkerSession worker_session(worker_id);5859ShenandoahHeap* heap = ShenandoahHeap::heap();60ShenandoahUpdateRefsClosure cl;61if (_check_alive) {62ShenandoahForwardedIsAliveClosure is_alive;63_root_updater->roots_do<ShenandoahForwardedIsAliveClosure, ShenandoahUpdateRefsClosure>(worker_id, &is_alive, &cl);64} else {65AlwaysTrueClosure always_true;;66_root_updater->roots_do<AlwaysTrueClosure, ShenandoahUpdateRefsClosure>(worker_id, &always_true, &cl);67}68}69};7071class ShenandoahConcurrentMarkingTask : public AbstractGangTask {72private:73ShenandoahConcurrentMark* const _cm;74TaskTerminator* const _terminator;7576public:77ShenandoahConcurrentMarkingTask(ShenandoahConcurrentMark* cm, TaskTerminator* terminator) :78AbstractGangTask("Shenandoah Concurrent Mark"), _cm(cm), _terminator(terminator) {79}8081void work(uint worker_id) {82ShenandoahHeap* heap = ShenandoahHeap::heap();83ShenandoahConcurrentWorkerSession worker_session(worker_id);84ShenandoahSuspendibleThreadSetJoiner stsj(ShenandoahSuspendibleWorkers);85ShenandoahObjToScanQueue* q = _cm->get_queue(worker_id);86ShenandoahReferenceProcessor* rp = heap->ref_processor();87assert(rp != NULL, "need reference processor");88_cm->mark_loop(worker_id, _terminator, rp,89true /*cancellable*/,90ShenandoahStringDedup::is_enabled() ? ENQUEUE_DEDUP : NO_DEDUP);91}92};9394class ShenandoahSATBAndRemarkThreadsClosure : public ThreadClosure {95private:96SATBMarkQueueSet& _satb_qset;97OopClosure* const _cl;98uintx _claim_token;99100public:101ShenandoahSATBAndRemarkThreadsClosure(SATBMarkQueueSet& satb_qset, OopClosure* cl) :102_satb_qset(satb_qset),103_cl(cl),104_claim_token(Threads::thread_claim_token()) {}105106void do_thread(Thread* thread) {107if (thread->claim_threads_do(true, _claim_token)) {108// Transfer any partial buffer to the qset for completed buffer processing.109_satb_qset.flush_queue(ShenandoahThreadLocalData::satb_mark_queue(thread));110if (thread->is_Java_thread()) {111if (_cl != NULL) {112ResourceMark rm;113thread->oops_do(_cl, NULL);114}115}116}117}118};119120class ShenandoahFinalMarkingTask : public AbstractGangTask {121private:122ShenandoahConcurrentMark* _cm;123TaskTerminator* _terminator;124bool _dedup_string;125126public:127ShenandoahFinalMarkingTask(ShenandoahConcurrentMark* cm, TaskTerminator* terminator, bool dedup_string) :128AbstractGangTask("Shenandoah Final Mark"), _cm(cm), _terminator(terminator), _dedup_string(dedup_string) {129}130131void work(uint worker_id) {132ShenandoahHeap* heap = ShenandoahHeap::heap();133134ShenandoahParallelWorkerSession worker_session(worker_id);135ShenandoahReferenceProcessor* rp = heap->ref_processor();136137// First drain remaining SATB buffers.138{139ShenandoahObjToScanQueue* q = _cm->get_queue(worker_id);140141ShenandoahSATBBufferClosure cl(q);142SATBMarkQueueSet& satb_mq_set = ShenandoahBarrierSet::satb_mark_queue_set();143while (satb_mq_set.apply_closure_to_completed_buffer(&cl)) {}144assert(!heap->has_forwarded_objects(), "Not expected");145146ShenandoahMarkRefsClosure<NO_DEDUP> mark_cl(q, rp);147ShenandoahSATBAndRemarkThreadsClosure tc(satb_mq_set,148ShenandoahIUBarrier ? &mark_cl : NULL);149Threads::threads_do(&tc);150}151_cm->mark_loop(worker_id, _terminator, rp,152false /*not cancellable*/,153_dedup_string ? ENQUEUE_DEDUP : NO_DEDUP);154assert(_cm->task_queues()->is_empty(), "Should be empty");155}156};157158ShenandoahConcurrentMark::ShenandoahConcurrentMark() :159ShenandoahMark() {}160161// Mark concurrent roots during concurrent phases162class ShenandoahMarkConcurrentRootsTask : public AbstractGangTask {163private:164SuspendibleThreadSetJoiner _sts_joiner;165ShenandoahConcurrentRootScanner _root_scanner;166ShenandoahObjToScanQueueSet* const _queue_set;167ShenandoahReferenceProcessor* const _rp;168169public:170ShenandoahMarkConcurrentRootsTask(ShenandoahObjToScanQueueSet* qs,171ShenandoahReferenceProcessor* rp,172ShenandoahPhaseTimings::Phase phase,173uint nworkers);174void work(uint worker_id);175};176177ShenandoahMarkConcurrentRootsTask::ShenandoahMarkConcurrentRootsTask(ShenandoahObjToScanQueueSet* qs,178ShenandoahReferenceProcessor* rp,179ShenandoahPhaseTimings::Phase phase,180uint nworkers) :181AbstractGangTask("Shenandoah Concurrent Mark Roots"),182_root_scanner(nworkers, phase),183_queue_set(qs),184_rp(rp) {185assert(!ShenandoahHeap::heap()->has_forwarded_objects(), "Not expected");186}187188void ShenandoahMarkConcurrentRootsTask::work(uint worker_id) {189ShenandoahConcurrentWorkerSession worker_session(worker_id);190ShenandoahObjToScanQueue* q = _queue_set->queue(worker_id);191// Cannot enable string deduplication during root scanning. Otherwise,192// may result lock inversion between stack watermark and string dedup queue lock.193ShenandoahMarkRefsClosure<NO_DEDUP> cl(q, _rp);194_root_scanner.roots_do(&cl, worker_id);195}196197void ShenandoahConcurrentMark::mark_concurrent_roots() {198ShenandoahHeap* const heap = ShenandoahHeap::heap();199assert(!heap->has_forwarded_objects(), "Not expected");200201TASKQUEUE_STATS_ONLY(task_queues()->reset_taskqueue_stats());202203WorkGang* workers = heap->workers();204ShenandoahReferenceProcessor* rp = heap->ref_processor();205task_queues()->reserve(workers->active_workers());206ShenandoahMarkConcurrentRootsTask task(task_queues(), rp, ShenandoahPhaseTimings::conc_mark_roots, workers->active_workers());207208workers->run_task(&task);209}210211class ShenandoahFlushSATBHandshakeClosure : public HandshakeClosure {212private:213SATBMarkQueueSet& _qset;214public:215ShenandoahFlushSATBHandshakeClosure(SATBMarkQueueSet& qset) :216HandshakeClosure("Shenandoah Flush SATB Handshake"),217_qset(qset) {}218219void do_thread(Thread* thread) {220_qset.flush_queue(ShenandoahThreadLocalData::satb_mark_queue(thread));221}222};223224void ShenandoahConcurrentMark::concurrent_mark() {225ShenandoahHeap* const heap = ShenandoahHeap::heap();226WorkGang* workers = heap->workers();227uint nworkers = workers->active_workers();228task_queues()->reserve(nworkers);229230ShenandoahSATBMarkQueueSet& qset = ShenandoahBarrierSet::satb_mark_queue_set();231ShenandoahFlushSATBHandshakeClosure flush_satb(qset);232for (uint flushes = 0; flushes < ShenandoahMaxSATBBufferFlushes; flushes++) {233TaskTerminator terminator(nworkers, task_queues());234ShenandoahConcurrentMarkingTask task(this, &terminator);235workers->run_task(&task);236237if (heap->cancelled_gc()) {238// GC is cancelled, break out.239break;240}241242size_t before = qset.completed_buffers_num();243Handshake::execute(&flush_satb);244size_t after = qset.completed_buffers_num();245246if (before == after) {247// No more retries needed, break out.248break;249}250}251assert(task_queues()->is_empty() || heap->cancelled_gc(), "Should be empty when not cancelled");252}253254void ShenandoahConcurrentMark::finish_mark() {255assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a safepoint");256assert(Thread::current()->is_VM_thread(), "Must by VM Thread");257finish_mark_work();258assert(task_queues()->is_empty(), "Should be empty");259TASKQUEUE_STATS_ONLY(task_queues()->print_taskqueue_stats());260TASKQUEUE_STATS_ONLY(task_queues()->reset_taskqueue_stats());261262ShenandoahHeap* const heap = ShenandoahHeap::heap();263heap->set_concurrent_mark_in_progress(false);264heap->mark_complete_marking_context();265}266267void ShenandoahConcurrentMark::finish_mark_work() {268// Finally mark everything else we've got in our queues during the previous steps.269// It does two different things for concurrent vs. mark-compact GC:270// - For concurrent GC, it starts with empty task queues, drains the remaining271// SATB buffers, and then completes the marking closure.272// - For mark-compact GC, it starts out with the task queues seeded by initial273// root scan, and completes the closure, thus marking through all live objects274// The implementation is the same, so it's shared here.275ShenandoahHeap* const heap = ShenandoahHeap::heap();276ShenandoahGCPhase phase(ShenandoahPhaseTimings::finish_mark);277uint nworkers = heap->workers()->active_workers();278task_queues()->reserve(nworkers);279280StrongRootsScope scope(nworkers);281TaskTerminator terminator(nworkers, task_queues());282ShenandoahFinalMarkingTask task(this, &terminator, ShenandoahStringDedup::is_enabled());283heap->workers()->run_task(&task);284285assert(task_queues()->is_empty(), "Should be empty");286}287288289void ShenandoahConcurrentMark::cancel() {290clear();291ShenandoahReferenceProcessor* rp = ShenandoahHeap::heap()->ref_processor();292rp->abandon_partial_discovery();293}294295296