From a0c8fce9d76ee809d5f67b83b07c6829e44aed07 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 19 Mar 2026 09:57:28 +0000 Subject: [PATCH] 8379511: G1: G1CollectorState should derive concurrent cycle state from G1ConcurrentMark Reviewed-by: iwalulya, ayang --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 2 +- src/hotspot/share/gc/g1/g1CollectorState.cpp | 25 +++++++- src/hotspot/share/gc/g1/g1CollectorState.hpp | 26 ++------ src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 57 +++++++++-------- src/hotspot/share/gc/g1/g1ConcurrentMark.hpp | 11 +++- .../share/gc/g1/g1ConcurrentMarkThread.cpp | 16 ++--- .../share/gc/g1/g1ConcurrentMarkThread.hpp | 46 ++++++++------ .../gc/g1/g1ConcurrentMarkThread.inline.hpp | 61 +++++++++++++++---- src/hotspot/share/gc/g1/g1PeriodicGCTask.cpp | 6 +- src/hotspot/share/gc/g1/g1Policy.cpp | 22 ++----- src/hotspot/share/gc/g1/g1Policy.hpp | 2 +- src/hotspot/share/gc/g1/g1RemSet.cpp | 2 +- src/hotspot/share/gc/g1/g1VMOperations.cpp | 15 ++--- src/hotspot/share/gc/g1/g1YoungCollector.cpp | 2 +- .../g1/g1YoungGCAllocationFailureInjector.cpp | 10 +-- .../gc/g1/g1YoungGCPostEvacuateTasks.cpp | 2 +- src/hotspot/share/prims/whitebox.cpp | 2 +- 17 files changed, 185 insertions(+), 122 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index abc45254782..8b41a3b2079 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -2554,7 +2554,7 @@ HeapWord* G1CollectedHeap::do_collection_pause(size_t word_size, void G1CollectedHeap::start_concurrent_cycle(bool concurrent_operation_is_full_mark) { assert(_cm->is_fully_initialized(), "sanity"); - assert(!_cm->in_progress(), "Can not start concurrent operation while in progress"); + assert(!collector_state()->is_in_concurrent_cycle(), "Can not start concurrent cycle when already running"); MutexLocker x(G1CGC_lock, Mutex::_no_safepoint_check_flag); if (concurrent_operation_is_full_mark) { _cm->start_full_concurrent_cycle(); diff --git a/src/hotspot/share/gc/g1/g1CollectorState.cpp b/src/hotspot/share/gc/g1/g1CollectorState.cpp index d41ee22fdce..b64e9d45674 100644 --- a/src/hotspot/share/gc/g1/g1CollectorState.cpp +++ b/src/hotspot/share/gc/g1/g1CollectorState.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,9 @@ * */ +#include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectorState.hpp" +#include "gc/g1/g1ConcurrentMarkThread.inline.hpp" #include "gc/g1/g1GCPauseType.hpp" G1GCPauseType G1CollectorState::young_gc_pause_type(bool concurrent_operation_is_full_mark) const { @@ -44,3 +46,24 @@ G1GCPauseType G1CollectorState::young_gc_pause_type(bool concurrent_operation_is return G1GCPauseType::YoungGC; } } + +bool G1CollectorState::is_in_concurrent_cycle() const { + G1ConcurrentMark* cm = G1CollectedHeap::heap()->concurrent_mark(); + return cm->is_in_concurrent_cycle(); +} + +bool G1CollectorState::is_in_marking() const { + G1ConcurrentMark* cm = G1CollectedHeap::heap()->concurrent_mark(); + return cm->is_in_marking(); +} + +bool G1CollectorState::is_in_mark_or_rebuild() const { + G1ConcurrentMark* cm = G1CollectedHeap::heap()->concurrent_mark(); + return is_in_marking() || cm->is_in_rebuild_or_scrub(); +} + +bool G1CollectorState::is_in_reset_for_next_cycle() const { + G1ConcurrentMark* cm = G1CollectedHeap::heap()->concurrent_mark(); + return cm->is_in_reset_for_next_cycle(); +} + diff --git a/src/hotspot/share/gc/g1/g1CollectorState.hpp b/src/hotspot/share/gc/g1/g1CollectorState.hpp index fca30792344..ddf9d7fd181 100644 --- a/src/hotspot/share/gc/g1/g1CollectorState.hpp +++ b/src/hotspot/share/gc/g1/g1CollectorState.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,16 +60,6 @@ class G1CollectorState { // do the concurrent start phase work. volatile bool _initiate_conc_mark_if_possible; - // Marking is in progress. Set from start of the concurrent start pause to the - // end of the Remark pause. - bool _mark_in_progress; - // Marking or rebuilding remembered set work is in progress. Set from the end - // of the concurrent start pause to the end of the Cleanup pause. - bool _mark_or_rebuild_in_progress; - - // The marking bitmap is currently being cleared or about to be cleared. - bool _clear_bitmap_in_progress; - // Set during a full gc pause. bool _in_full_gc; @@ -81,9 +71,6 @@ public: _in_concurrent_start_gc(false), _initiate_conc_mark_if_possible(false), - _mark_in_progress(false), - _mark_or_rebuild_in_progress(false), - _clear_bitmap_in_progress(false), _in_full_gc(false) { } // Phase setters @@ -96,10 +83,6 @@ public: void set_initiate_conc_mark_if_possible(bool v) { _initiate_conc_mark_if_possible = v; } - void set_mark_in_progress(bool v) { _mark_in_progress = v; } - void set_mark_or_rebuild_in_progress(bool v) { _mark_or_rebuild_in_progress = v; } - void set_clear_bitmap_in_progress(bool v) { _clear_bitmap_in_progress = v; } - // Phase getters bool in_young_only_phase() const { return _in_young_only_phase && !_in_full_gc; } bool in_mixed_phase() const { return !_in_young_only_phase && !_in_full_gc; } @@ -111,9 +94,10 @@ public: bool initiate_conc_mark_if_possible() const { return _initiate_conc_mark_if_possible; } - bool mark_in_progress() const { return _mark_in_progress; } - bool mark_or_rebuild_in_progress() const { return _mark_or_rebuild_in_progress; } - bool clear_bitmap_in_progress() const { return _clear_bitmap_in_progress; } + bool is_in_concurrent_cycle() const; + bool is_in_marking() const; + bool is_in_mark_or_rebuild() const; + bool is_in_reset_for_next_cycle() const; // Calculate GC Pause Type from internal state. G1GCPauseType young_gc_pause_type(bool concurrent_operation_is_full_mark) const; diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 33b21d8348d..ab28feb520f 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -573,8 +573,20 @@ void G1ConcurrentMark::fully_initialize() { reset_at_marking_complete(); } -bool G1ConcurrentMark::in_progress() const { - return is_fully_initialized() ? _cm_thread->in_progress() : false; +bool G1ConcurrentMark::is_in_concurrent_cycle() const { + return is_fully_initialized() ? _cm_thread->is_in_progress() : false; +} + +bool G1ConcurrentMark::is_in_marking() const { + return is_fully_initialized() ? cm_thread()->is_in_marking() : false; +} + +bool G1ConcurrentMark::is_in_rebuild_or_scrub() const { + return cm_thread()->is_in_rebuild_or_scrub(); +} + +bool G1ConcurrentMark::is_in_reset_for_next_cycle() const { + return cm_thread()->is_in_reset_for_next_cycle(); } PartialArrayStateManager* G1ConcurrentMark::partial_array_state_manager() const { @@ -622,7 +634,7 @@ void G1ConcurrentMark::humongous_object_eagerly_reclaimed(G1HeapRegion* r) { // Need to clear mark bit of the humongous object. Doing this unconditionally is fine. mark_bitmap()->clear(r->bottom()); - if (!_g1h->collector_state()->mark_or_rebuild_in_progress()) { + if (!_g1h->collector_state()->is_in_mark_or_rebuild()) { return; } @@ -729,7 +741,7 @@ private: } bool is_clear_concurrent_undo() { - return suspendible() && _cm->cm_thread()->in_undo_mark(); + return suspendible() && _cm->cm_thread()->is_in_undo_cycle(); } bool has_aborted() { @@ -785,8 +797,7 @@ private: // as asserts here to minimize their overhead on the product. However, we // will have them as guarantees at the beginning / end of the bitmap // clearing to get some checking in the product. - assert(!suspendible() || _cm->in_progress(), "invariant"); - assert(!suspendible() || !G1CollectedHeap::heap()->collector_state()->mark_or_rebuild_in_progress(), "invariant"); + assert(!suspendible() || _cm->is_in_reset_for_next_cycle(), "invariant"); // Abort iteration if necessary. if (has_aborted()) { @@ -836,23 +847,14 @@ void G1ConcurrentMark::clear_bitmap(WorkerThreads* workers, bool may_yield) { void G1ConcurrentMark::cleanup_for_next_mark() { // Make sure that the concurrent mark thread looks to still be in // the current cycle. - guarantee(is_fully_initialized(), "should be initializd"); - guarantee(in_progress(), "invariant"); - - // We are finishing up the current cycle by clearing the next - // marking bitmap and getting it ready for the next cycle. During - // this time no other cycle can start. So, let's make sure that this - // is the case. - guarantee(!_g1h->collector_state()->mark_or_rebuild_in_progress(), "invariant"); + guarantee(is_in_reset_for_next_cycle(), "invariant"); clear_bitmap(_concurrent_workers, true); reset_partial_array_state_manager(); - // Repeat the asserts from above. - guarantee(is_fully_initialized(), "should be initializd"); - guarantee(in_progress(), "invariant"); - guarantee(!_g1h->collector_state()->mark_or_rebuild_in_progress(), "invariant"); + // Should not have changed state yet (even if a Full GC interrupted us). + guarantee(is_in_reset_for_next_cycle(), "invariant"); } void G1ConcurrentMark::reset_partial_array_state_manager() { @@ -977,14 +979,14 @@ void G1ConcurrentMark::start_full_concurrent_cycle() { // during it. No need to call it here. // Signal the thread to start work. - cm_thread()->start_full_mark(); + cm_thread()->start_full_cycle(); } void G1ConcurrentMark::start_undo_concurrent_cycle() { root_regions()->cancel_scan(); // Signal the thread to start work. - cm_thread()->start_undo_mark(); + cm_thread()->start_undo_cycle(); } void G1ConcurrentMark::notify_concurrent_cycle_completed() { @@ -1186,8 +1188,6 @@ uint G1ConcurrentMark::completed_mark_cycles() const { } void G1ConcurrentMark::concurrent_cycle_end(bool mark_cycle_completed) { - _g1h->collector_state()->set_clear_bitmap_in_progress(false); - _g1h->trace_heap_after_gc(_gc_tracer_cm); if (mark_cycle_completed) { @@ -1372,6 +1372,9 @@ void G1ConcurrentMark::remark() { G1ObjectCountIsAliveClosure is_alive(_g1h); _gc_tracer_cm->report_object_count_after_gc(&is_alive, _g1h->workers()); } + + // Successfully completed marking, advance state. + cm_thread()->set_full_cycle_rebuild_and_scrub(); } else { // We overflowed. Restart concurrent marking. _restart_for_overflow.store_relaxed(true); @@ -1392,6 +1395,8 @@ void G1ConcurrentMark::remark() { _g1h->update_perf_counter_cpu_time(); policy->record_concurrent_mark_remark_end(); + + return; } void G1ConcurrentMark::compute_new_sizes() { @@ -1454,6 +1459,10 @@ void G1ConcurrentMark::cleanup() { GCTraceTime(Debug, gc, phases) debug("Finalize Concurrent Mark Cleanup", _gc_timer_cm); policy->record_concurrent_mark_cleanup_end(needs_remembered_set_rebuild()); } + + // Advance state. + cm_thread()->set_full_cycle_reset_for_next_cycle(); + return; } // 'Keep Alive' oop closure used by both serial parallel reference processing. @@ -1880,7 +1889,7 @@ public: void G1ConcurrentMark::verify_no_collection_set_oops() { assert(SafepointSynchronize::is_at_safepoint() || !is_init_completed(), "should be at a safepoint or initializing"); - if (!_g1h->collector_state()->mark_or_rebuild_in_progress()) { + if (!is_fully_initialized() || !_g1h->collector_state()->is_in_mark_or_rebuild()) { return; } @@ -1958,7 +1967,7 @@ bool G1ConcurrentMark::concurrent_cycle_abort() { // has been signalled is already rare), and this work should be negligible compared // to actual full gc work. - if (!is_fully_initialized() || (!cm_thread()->in_progress() && !cm_thread()->should_terminate())) { + if (!is_fully_initialized() || (!cm_thread()->is_in_progress() && !cm_thread()->should_terminate())) { return false; } diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp index 8bd04437097..de97179d210 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp @@ -353,6 +353,7 @@ class G1ConcurrentMark : public CHeapObj { friend class G1CMRootRegionScanTask; friend class G1CMTask; friend class G1ClearBitMapTask; + friend class G1CollectorState; friend class G1ConcurrentMarkThread; G1ConcurrentMarkThread* _cm_thread; // The thread doing the work @@ -528,6 +529,12 @@ class G1ConcurrentMark : public CHeapObj { G1ConcurrentMarkThread* cm_thread() const; + // Concurrent cycle state queries. + bool is_in_concurrent_cycle() const; + bool is_in_marking() const; + bool is_in_rebuild_or_scrub() const; + bool is_in_reset_for_next_cycle() const; + public: // To be called when an object is marked the first time, e.g. after a successful // mark_in_bitmap call. Updates various statistics data. @@ -561,7 +568,7 @@ public: void fully_initialize(); bool is_fully_initialized() const { return _cm_thread != nullptr; } - bool in_progress() const; + uint max_num_tasks() const {return _max_num_tasks; } // Clear statistics gathered during the concurrent cycle for the given region after @@ -666,8 +673,10 @@ public: // Do concurrent preclean work. void preclean(); + // Executes the Remark pause. void remark(); + // Executes the Cleanup pause. void cleanup(); // Mark in the marking bitmap. Used during evacuation failure to diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp index 629cbae935e..31d61b8b388 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -112,22 +112,22 @@ class G1ConcPhaseTimer : public GCTraceConcTimeImpl title("Concurrent %s Cycle", _state == FullMark ? "Mark" : "Undo"); + FormatBuffer<128> title("Concurrent %s Cycle", is_in_full_concurrent_cycle() ? "Mark" : "Undo"); GCTraceConcTime(Info, gc) tt(title); concurrent_cycle_start(); - if (_state == FullMark) { + if (_state == FullCycleMarking) { concurrent_mark_cycle_do(); } else { - assert(_state == UndoMark, "Must do undo mark but is %d", _state); + assert(_state == UndoCycleResetForNextCycle, "Must do undo mark but is %d", _state); concurrent_undo_cycle_do(); } - concurrent_cycle_end(_state == FullMark && !_cm->has_aborted()); + concurrent_cycle_end(is_in_full_concurrent_cycle() && !_cm->has_aborted()); update_perf_counter_cpu_time(); } @@ -135,7 +135,7 @@ void G1ConcurrentMarkThread::run_service() { } void G1ConcurrentMarkThread::stop_service() { - if (in_progress()) { + if (is_in_progress()) { // We are not allowed to abort the marking threads during root region scan. // Needs to be done separately. _cm->root_region_scan_abort_and_wait(); @@ -149,7 +149,7 @@ void G1ConcurrentMarkThread::stop_service() { bool G1ConcurrentMarkThread::wait_for_next_cycle() { MonitorLocker ml(G1CGC_lock, Mutex::_no_safepoint_check_flag); - while (!in_progress() && !should_terminate()) { + while (!is_in_progress() && !should_terminate()) { ml.wait(); } diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.hpp index 22be7d9ffbb..e75298fdcb4 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,25 +32,34 @@ class G1Policy; // The concurrent mark thread triggers the various steps of the concurrent marking // cycle, including various marking cleanup. +// +// The concurrent cycle may either be "Full" (i.e. include marking, rebuilding and +// scrubbing, resetting for the next cycle) or "Undo", i.e. shortened to just the +// reset part. class G1ConcurrentMarkThread: public ConcurrentGCThread { G1ConcurrentMark* _cm; enum ServiceState : uint { Idle, - FullMark, - UndoMark + FullCycleMarking, + FullCycleRebuildOrScrub, + FullCycleResetForNextCycle, + UndoCycleResetForNextCycle }; volatile ServiceState _state; + // Returns whether we are in a "Full" cycle. + bool is_in_full_concurrent_cycle() const; + // Wait for next cycle. Returns the command passed over. bool wait_for_next_cycle(); bool mark_loop_needs_restart() const; - // Phases and subphases for the full concurrent marking cycle in order. + // Phases and subphases for the full concurrent cycle in order. // - // All these methods return true if the marking should be aborted. + // All these methods return true if the cycle should be aborted. bool phase_clear_cld_claimed_marks(); bool phase_scan_root_regions(); @@ -88,22 +97,25 @@ class G1ConcurrentMarkThread: public ConcurrentGCThread { double total_mark_cpu_time_s(); // Cpu time used by all marking worker threads in seconds. double worker_threads_cpu_time_s(); - - G1ConcurrentMark* cm() { return _cm; } - + // State management. void set_idle(); - void start_full_mark(); - void start_undo_mark(); + void start_full_cycle(); + void start_undo_cycle(); - bool idle() const; + void set_full_cycle_rebuild_and_scrub(); + void set_full_cycle_reset_for_next_cycle(); + + bool is_idle() const; // Returns true from the moment a concurrent cycle is - // initiated (during the concurrent start pause when started() is set) - // to the moment when the cycle completes (just after the next - // marking bitmap has been cleared and in_progress() is - // cleared). - bool in_progress() const; + // initiated (during the concurrent start pause when calling one of the + // start_*_cycle() methods) to the moment when the cycle completes. + bool is_in_progress() const; - bool in_undo_mark() const; + bool is_in_marking() const; + bool is_in_rebuild_or_scrub() const; + bool is_in_reset_for_next_cycle() const; + + bool is_in_undo_cycle() const; // Update the perf data counter for concurrent mark. void update_perf_counter_cpu_time(); diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.inline.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.inline.hpp index e80c5023405..8cb7881e000 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.inline.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.inline.hpp @@ -40,29 +40,64 @@ inline double G1ConcurrentMarkThread::worker_threads_cpu_time_s() { return _cm->worker_threads_cpu_time_s(); } +inline bool G1ConcurrentMarkThread::is_in_full_concurrent_cycle() const { + ServiceState state = _state; + return (state == FullCycleMarking || state == FullCycleRebuildOrScrub || state == FullCycleResetForNextCycle); +} + inline void G1ConcurrentMarkThread::set_idle() { - assert(_state == FullMark || _state == UndoMark, "must not be starting a new cycle"); + // Concurrent cycle may be aborted any time. + assert(!is_idle(), "must not be idle"); _state = Idle; } -inline void G1ConcurrentMarkThread::start_full_mark() { - assert(_state == Idle, "cycle in progress"); - _state = FullMark; +inline void G1ConcurrentMarkThread::start_full_cycle() { + assert(SafepointSynchronize::is_at_safepoint(), "must be"); + assert(is_idle(), "cycle in progress"); + _state = FullCycleMarking; } -inline void G1ConcurrentMarkThread::start_undo_mark() { - assert(_state == Idle, "cycle in progress"); - _state = UndoMark; +inline void G1ConcurrentMarkThread::start_undo_cycle() { + assert(SafepointSynchronize::is_at_safepoint(), "must be"); + assert(is_idle(), "cycle in progress"); + _state = UndoCycleResetForNextCycle; } -inline bool G1ConcurrentMarkThread::idle() const { return _state == Idle; } - -inline bool G1ConcurrentMarkThread::in_progress() const { - return !idle(); +inline void G1ConcurrentMarkThread::set_full_cycle_rebuild_and_scrub() { + assert(SafepointSynchronize::is_at_safepoint(), "must be"); + assert(_state == FullCycleMarking, "must be"); + _state = FullCycleRebuildOrScrub; } -inline bool G1ConcurrentMarkThread::in_undo_mark() const { - return _state == UndoMark; +inline void G1ConcurrentMarkThread::set_full_cycle_reset_for_next_cycle() { + assert(SafepointSynchronize::is_at_safepoint(), "must be"); + assert(_state == FullCycleRebuildOrScrub, "must be"); + _state = FullCycleResetForNextCycle; +} + +inline bool G1ConcurrentMarkThread::is_in_marking() const { + return _state == FullCycleMarking; +} + +inline bool G1ConcurrentMarkThread::is_in_rebuild_or_scrub() const { + return _state == FullCycleRebuildOrScrub; +} + +inline bool G1ConcurrentMarkThread::is_in_reset_for_next_cycle() const { + ServiceState state = _state; + return state == FullCycleResetForNextCycle || state == UndoCycleResetForNextCycle; +} + +inline bool G1ConcurrentMarkThread::is_idle() const { + return _state == Idle; +} + +inline bool G1ConcurrentMarkThread::is_in_progress() const { + return !is_idle(); +} + +inline bool G1ConcurrentMarkThread::is_in_undo_cycle() const { + return _state == UndoCycleResetForNextCycle; } #endif // SHARE_GC_G1_G1CONCURRENTMARKTHREAD_INLINE_HPP diff --git a/src/hotspot/share/gc/g1/g1PeriodicGCTask.cpp b/src/hotspot/share/gc/g1/g1PeriodicGCTask.cpp index f280d76f3c7..ee11bbd961f 100644 --- a/src/hotspot/share/gc/g1/g1PeriodicGCTask.cpp +++ b/src/hotspot/share/gc/g1/g1PeriodicGCTask.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,8 +38,8 @@ bool G1PeriodicGCTask::should_start_periodic_gc(G1CollectedHeap* g1h, // Ensure no GC safepoints while we're doing the checks, to avoid data races. SuspendibleThreadSetJoiner sts; - // If we are currently in a concurrent mark we are going to uncommit memory soon. - if (g1h->concurrent_mark()->in_progress()) { + // If we are currently in a concurrent cycle we are going to uncommit memory soon. + if (g1h->collector_state()->is_in_concurrent_cycle()) { log_debug(gc, periodic)("Concurrent cycle in progress. Skipping."); return false; } diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index 98e6acc1d77..3c8b81bdb8f 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -579,9 +579,6 @@ void G1Policy::record_full_collection_end(size_t allocation_word_size) { collector_state()->set_in_young_gc_before_mixed(false); collector_state()->set_initiate_conc_mark_if_possible(need_to_start_conc_mark("end of Full GC", allocation_word_size)); collector_state()->set_in_concurrent_start_gc(false); - collector_state()->set_mark_in_progress(false); - collector_state()->set_mark_or_rebuild_in_progress(false); - collector_state()->set_clear_bitmap_in_progress(false); _eden_surv_rate_group->start_adding_regions(); // also call this on any additional surv rate groups @@ -709,7 +706,6 @@ void G1Policy::record_concurrent_mark_remark_end() { double elapsed_time_ms = (end_time_sec - start_time_sec) * 1000.0; _analytics->report_concurrent_mark_remark_times_ms(elapsed_time_ms); record_pause(G1GCPauseType::Remark, start_time_sec, end_time_sec); - collector_state()->set_mark_in_progress(false); } G1CollectionSetCandidates* G1Policy::candidates() const { @@ -739,7 +735,7 @@ double G1Policy::constant_other_time_ms(double pause_time_ms) const { } bool G1Policy::about_to_start_mixed_phase() const { - return _g1h->concurrent_mark()->in_progress() || collector_state()->in_young_gc_before_mixed(); + return collector_state()->is_in_concurrent_cycle() || collector_state()->in_young_gc_before_mixed(); } bool G1Policy::need_to_start_conc_mark(const char* source, size_t allocation_word_size) { @@ -971,12 +967,8 @@ void G1Policy::record_young_collection_end(bool concurrent_operation_is_full_mar _eden_surv_rate_group->start_adding_regions(); - assert(!(G1GCPauseTypeHelper::is_concurrent_start_pause(this_pause) && collector_state()->mark_or_rebuild_in_progress()), - "If the last pause has been concurrent start, we should not have been in the marking window"); - if (G1GCPauseTypeHelper::is_concurrent_start_pause(this_pause)) { - collector_state()->set_mark_in_progress(concurrent_operation_is_full_mark); - collector_state()->set_mark_or_rebuild_in_progress(concurrent_operation_is_full_mark); - } + assert(!(G1GCPauseTypeHelper::is_concurrent_start_pause(this_pause) && collector_state()->is_in_concurrent_cycle()), + "If the last pause has been concurrent start, we should not have been in the marking cycle"); _free_regions_at_end_of_collection = _g1h->num_free_regions(); @@ -1235,7 +1227,7 @@ bool G1Policy::force_concurrent_start_if_outside_cycle(GCCause::Cause gc_cause) // We actually check whether we are marking here and not if we are in a // reclamation phase. This means that we will schedule a concurrent mark // even while we are still in the process of reclaiming memory. - bool during_cycle = _g1h->concurrent_mark()->in_progress(); + bool during_cycle = collector_state()->is_in_concurrent_cycle(); if (!during_cycle) { log_debug(gc, ergo)("Request concurrent cycle initiation (requested by GC cause). " "GC cause: %s", @@ -1328,8 +1320,8 @@ void G1Policy::decide_on_concurrent_start_pause() { // We do not allow concurrent start to be piggy-backed on a mixed GC. assert(!collector_state()->in_concurrent_start_gc() || collector_state()->in_young_only_phase(), "sanity"); - // We also do not allow mixed GCs during marking. - assert(!collector_state()->mark_or_rebuild_in_progress() || collector_state()->in_young_only_phase(), "sanity"); + // We also do not allow mixed GCs during marking/rebuilding. + assert(!collector_state()->is_in_mark_or_rebuild() || collector_state()->in_young_only_phase(), "sanity %d %d", collector_state()->is_in_concurrent_cycle(), collector_state()->in_young_only_phase()); } void G1Policy::record_concurrent_mark_cleanup_end(bool has_rebuilt_remembered_sets) { @@ -1349,8 +1341,6 @@ void G1Policy::record_concurrent_mark_cleanup_end(bool has_rebuilt_remembered_se log_debug(gc, ergo)("request young-only gcs (candidate old regions not available)"); } collector_state()->set_in_young_gc_before_mixed(mixed_gc_pending); - collector_state()->set_mark_or_rebuild_in_progress(false); - collector_state()->set_clear_bitmap_in_progress(true); double end_sec = os::elapsedTime(); double start_sec = cur_pause_start_sec(); diff --git a/src/hotspot/share/gc/g1/g1Policy.hpp b/src/hotspot/share/gc/g1/g1Policy.hpp index 9513c79869e..ccbde31a465 100644 --- a/src/hotspot/share/gc/g1/g1Policy.hpp +++ b/src/hotspot/share/gc/g1/g1Policy.hpp @@ -115,7 +115,7 @@ class G1Policy: public CHeapObj { G1ConcurrentStartToMixedTimeTracker _concurrent_start_to_mixed; bool should_update_surv_rate_group_predictors() { - return collector_state()->in_young_only_phase() && !collector_state()->mark_or_rebuild_in_progress(); + return collector_state()->in_young_only_phase() && !collector_state()->is_in_mark_or_rebuild(); } double pending_cards_processing_time() const; diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index 0c9a0fad8f2..4b4a8a68c30 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.cpp +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp @@ -1026,7 +1026,7 @@ class G1MergeHeapRootsTask : public WorkerTask { // the pause occurs during the Concurrent Cleanup for Next Mark phase. // Only at that point the region's bitmap may contain marks while being in the collection // set at the same time. - return _g1h->collector_state()->clear_bitmap_in_progress() && + return _g1h->collector_state()->is_in_reset_for_next_cycle() && hr->is_old(); } diff --git a/src/hotspot/share/gc/g1/g1VMOperations.cpp b/src/hotspot/share/gc/g1/g1VMOperations.cpp index 56ab3a4b0fe..f98f0b078f3 100644 --- a/src/hotspot/share/gc/g1/g1VMOperations.cpp +++ b/src/hotspot/share/gc/g1/g1VMOperations.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -84,8 +84,9 @@ void VM_G1TryInitiateConcMark::doit() { GCCauseSetter x(g1h, _gc_cause); - _mark_in_progress = g1h->collector_state()->mark_in_progress(); - _cycle_already_in_progress = g1h->concurrent_mark()->in_progress(); + G1CollectorState* state = g1h->collector_state(); + _mark_in_progress = state->is_in_marking(); + _cycle_already_in_progress = state->is_in_concurrent_cycle(); if (!g1h->policy()->force_concurrent_start_if_outside_cycle(_gc_cause)) { // Failure to force the next GC pause to be a concurrent start indicates @@ -166,11 +167,11 @@ void VM_G1PauseConcurrent::doit_epilogue() { } void VM_G1PauseRemark::work() { - G1CollectedHeap* g1h = G1CollectedHeap::heap(); - g1h->concurrent_mark()->remark(); + G1ConcurrentMark* cm = G1CollectedHeap::heap()->concurrent_mark(); + cm->remark(); } void VM_G1PauseCleanup::work() { - G1CollectedHeap* g1h = G1CollectedHeap::heap(); - g1h->concurrent_mark()->cleanup(); + G1ConcurrentMark* cm = G1CollectedHeap::heap()->concurrent_mark(); + cm->cleanup(); } diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.cpp b/src/hotspot/share/gc/g1/g1YoungCollector.cpp index 71a76a2e48b..3fceb42b6d7 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.cpp @@ -391,7 +391,7 @@ class G1PrepareEvacuationTask : public WorkerTask { if (!obj->is_typeArray()) { // All regions that were allocated before marking have a TAMS != bottom. bool allocated_before_mark_start = region->bottom() != _g1h->concurrent_mark()->top_at_mark_start(region); - bool mark_in_progress = _g1h->collector_state()->mark_in_progress(); + bool mark_in_progress = _g1h->collector_state()->is_in_marking(); if (allocated_before_mark_start && mark_in_progress) { return false; diff --git a/src/hotspot/share/gc/g1/g1YoungGCAllocationFailureInjector.cpp b/src/hotspot/share/gc/g1/g1YoungGCAllocationFailureInjector.cpp index 75cff2b339b..6ba72f6cde0 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCAllocationFailureInjector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCAllocationFailureInjector.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,9 +61,9 @@ void G1YoungGCAllocationFailureInjector::select_allocation_failure_regions() { bool G1YoungGCAllocationFailureInjector::arm_if_needed_for_gc_type(bool for_young_only_phase, bool during_concurrent_start, - bool mark_or_rebuild_in_progress) { + bool in_concurrent_cycle) { bool res = false; - if (mark_or_rebuild_in_progress) { + if (in_concurrent_cycle) { res |= G1GCAllocationFailureALotDuringConcMark; } if (during_concurrent_start) { @@ -91,12 +91,12 @@ void G1YoungGCAllocationFailureInjector::arm_if_needed() { G1CollectorState* collector_state = g1h->collector_state(); const bool in_young_only_phase = collector_state->in_young_only_phase(); const bool in_concurrent_start_gc = collector_state->in_concurrent_start_gc(); - const bool mark_or_rebuild_in_progress = collector_state->mark_or_rebuild_in_progress(); + const bool in_concurrent_cycle = collector_state->is_in_concurrent_cycle(); _inject_allocation_failure_for_current_gc &= arm_if_needed_for_gc_type(in_young_only_phase, in_concurrent_start_gc, - mark_or_rebuild_in_progress); + in_concurrent_cycle); if (_inject_allocation_failure_for_current_gc) { select_allocation_failure_regions(); diff --git a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp index a0013d27172..769cc9a077c 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp @@ -395,7 +395,7 @@ public: { ResourceMark rm; bool allocated_after_mark_start = r->bottom() == _g1h->concurrent_mark()->top_at_mark_start(r); - bool mark_in_progress = _g1h->collector_state()->mark_in_progress(); + bool mark_in_progress = _g1h->collector_state()->is_in_marking(); guarantee(obj->is_typeArray() || (allocated_after_mark_start || !mark_in_progress), "Only eagerly reclaiming primitive arrays is supported, other humongous objects only if allocated after mark start, but the object " PTR_FORMAT " (%s) is not (mark %d allocated after mark: %d).", diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 1a440584fe1..5df1461c0fd 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -578,7 +578,7 @@ WB_END WB_ENTRY(jboolean, WB_G1InConcurrentMark(JNIEnv* env, jobject o)) if (UseG1GC) { G1CollectedHeap* g1h = G1CollectedHeap::heap(); - return g1h->concurrent_mark()->in_progress(); + return g1h->collector_state()->is_in_concurrent_cycle(); } THROW_MSG_0(vmSymbols::java_lang_UnsupportedOperationException(), "WB_G1InConcurrentMark: G1 GC is not enabled"); WB_END