From f3dfdfa3fdc97c2c850251d58f91134e0ae82240 Mon Sep 17 00:00:00 2001 From: Rui Li Date: Wed, 29 Oct 2025 21:40:36 +0000 Subject: [PATCH] 8369013: Shenandoah: passive mode should support enabling ShenandoahCardBarrier Reviewed-by: wkemper --- .../shenandoah/mode/shenandoahPassiveMode.cpp | 5 -- .../gc/shenandoah/shenandoahDegeneratedGC.cpp | 6 ++ .../shenandoah/shenandoahGenerationalHeap.hpp | 5 +- .../share/gc/shenandoah/shenandoahHeap.cpp | 7 +++ .../share/gc/shenandoah/shenandoahHeap.hpp | 2 +- .../shenandoah/shenandoahScanRemembered.cpp | 16 +++++ .../shenandoah/shenandoahScanRemembered.hpp | 4 ++ .../TestPassiveModeWithCardBarrier.java | 59 +++++++++++++++++++ .../options/TestWrongBarrierEnable.java | 20 +++++-- 9 files changed, 111 insertions(+), 13 deletions(-) create mode 100644 test/hotspot/jtreg/gc/shenandoah/options/TestPassiveModeWithCardBarrier.java diff --git a/src/hotspot/share/gc/shenandoah/mode/shenandoahPassiveMode.cpp b/src/hotspot/share/gc/shenandoah/mode/shenandoahPassiveMode.cpp index 20f8ecc43e8..4c0bc209d78 100644 --- a/src/hotspot/share/gc/shenandoah/mode/shenandoahPassiveMode.cpp +++ b/src/hotspot/share/gc/shenandoah/mode/shenandoahPassiveMode.cpp @@ -48,11 +48,6 @@ void ShenandoahPassiveMode::initialize_flags() const { SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahCloneBarrier); SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahStackWatermarkBarrier); SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahCardBarrier); - - // Final configuration checks - // Passive mode does not instantiate the machinery to support the card table. - // Exit if the flag has been explicitly set. - SHENANDOAH_CHECK_FLAG_UNSET(ShenandoahCardBarrier); } ShenandoahHeuristics* ShenandoahPassiveMode::initialize_heuristics(ShenandoahSpaceInfo* space_info) const { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp index 2b791619d2e..53b83edd47b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp @@ -95,6 +95,12 @@ void ShenandoahDegenGC::op_degenerated() { // some phase, we have to upgrade the Degenerate GC to Full GC. heap->clear_cancelled_gc(); + // If it's passive mode with ShenandoahCardBarrier turned on: clean the write table + // without swapping the tables since no scan happens in passive mode anyway + if (ShenandoahCardBarrier && !heap->mode()->is_generational()) { + heap->old_generation()->card_scan()->mark_write_table_as_clean(); + } + #ifdef ASSERT if (heap->mode()->is_generational()) { ShenandoahOldGeneration* old_generation = heap->old_generation(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp index d3584a6f9a0..4c8c9fe0118 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp @@ -25,7 +25,6 @@ #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHGENERATIONALHEAP #define SHARE_GC_SHENANDOAH_SHENANDOAHGENERATIONALHEAP -#include "gc/shenandoah/shenandoahAsserts.hpp" #include "gc/shenandoah/shenandoahHeap.hpp" #include "memory/universe.hpp" #include "utilities/checkedCast.hpp" @@ -44,13 +43,13 @@ public: void initialize_heuristics() override; static ShenandoahGenerationalHeap* heap() { - shenandoah_assert_generational(); + assert(ShenandoahCardBarrier, "Should have card barrier to use genenrational heap"); CollectedHeap* heap = Universe::heap(); return cast(heap); } static ShenandoahGenerationalHeap* cast(CollectedHeap* heap) { - shenandoah_assert_generational(); + assert(ShenandoahCardBarrier, "Should have card barrier to use genenrational heap"); return checked_cast(heap); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index cb22c794d85..344811449ab 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -248,6 +248,13 @@ jint ShenandoahHeap::initialize() { // Now we know the number of regions and heap sizes, initialize the heuristics. initialize_heuristics(); + // If ShenandoahCardBarrier is enabled but it's not generational mode + // it means we're under passive mode and we have to initialize old gen + // for the purpose of having card table. + if (ShenandoahCardBarrier && !(mode()->is_generational())) { + _old_generation = new ShenandoahOldGeneration(max_workers(), max_capacity()); + } + assert(_heap_region.byte_size() == heap_rs.size(), "Need to know reserved size for card table"); // diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index d6bc17b844b..eae975b9409 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -530,7 +530,7 @@ public: } ShenandoahOldGeneration* old_generation() const { - assert(mode()->is_generational(), "Old generation requires generational mode"); + assert(ShenandoahCardBarrier, "Card mark barrier should be on"); return _old_generation; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp index 4a0215f15f1..af6cd6d39ab 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp @@ -123,6 +123,18 @@ void ShenandoahDirectCardMarkRememberedSet::mark_read_table_as_clean() { log_develop_debug(gc, barrier)("Cleaned read_table from " PTR_FORMAT " to " PTR_FORMAT, p2i(&(read_table[0])), p2i(end_bp)); } +void ShenandoahDirectCardMarkRememberedSet::mark_write_table_as_clean() { + CardValue* write_table = _card_table->write_byte_map(); + CardValue* bp = &(write_table)[0]; + CardValue* end_bp = &(write_table)[_card_table->last_valid_index()]; + + while (bp <= end_bp) { + *bp++ = CardTable::clean_card_val(); + } + + log_develop_debug(gc, barrier)("Cleaned write_table from " PTR_FORMAT " to " PTR_FORMAT, p2i(&(write_table[0])), p2i(end_bp)); +} + // No lock required because arguments align with card boundaries. void ShenandoahCardCluster::reset_object_range(HeapWord* from, HeapWord* to) { assert(((((unsigned long long) from) & (CardTable::card_size() - 1)) == 0) && @@ -330,6 +342,10 @@ void ShenandoahScanRemembered::mark_read_table_as_clean() { _rs->mark_read_table_as_clean(); } +void ShenandoahScanRemembered::mark_write_table_as_clean() { + _rs->mark_write_table_as_clean(); +} + void ShenandoahScanRemembered::reset_object_range(HeapWord* from, HeapWord* to) { _scc->reset_object_range(from, to); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp index 5df34159c0f..d04a768530f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp @@ -244,6 +244,8 @@ public: // See comment in ShenandoahScanRemembered inline void mark_read_table_as_clean(); + inline void mark_write_table_as_clean(); + // Merge any dirty values from write table into the read table, while leaving // the write table unchanged. void merge_write_table(HeapWord* start, size_t word_count); @@ -769,6 +771,8 @@ public: // the "write" table. void mark_read_table_as_clean(); + void mark_write_table_as_clean(); + // Swaps read and write card tables pointers in effect setting a clean card // table for the next GC cycle. void swap_card_tables() { _rs->swap_card_tables(); } diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestPassiveModeWithCardBarrier.java b/test/hotspot/jtreg/gc/shenandoah/options/TestPassiveModeWithCardBarrier.java new file mode 100644 index 00000000000..64e0a0b2a93 --- /dev/null +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestPassiveModeWithCardBarrier.java @@ -0,0 +1,59 @@ +/* + * Copyright Amazon.com Inc. 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @summary Test passive mode with card barrier with a gc heavy app. A simple hello world in TestSelectiveBarrierFlags + * does not always surface crashes + * @requires vm.gc.Shenandoah + * @library /test/lib + * + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+UseShenandoahGC -Xmx128m -XX:ShenandoahGCMode=passive -XX:+ShenandoahCardBarrier TestPassiveModeWithCardBarrier + */ + +import java.util.*; +import java.util.concurrent.*; + +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +public class TestPassiveModeWithCardBarrier { + public static void main(String[] args) throws Exception { + List junk = new ArrayList<>(); + int junkLength = 1000; + int totalRounds = 10; + int round = 0; + + while (round++ < totalRounds) { + for (int i = 0; i < junkLength; i++) { + junk.add(new byte[1024]); + } + + System.out.println(junk.hashCode()); + } + + // trigger a full gc in case it was all degen + System.gc(); + } +} diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierEnable.java b/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierEnable.java index 411c2b1003d..348aa5367e9 100644 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierEnable.java +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierEnable.java @@ -37,18 +37,30 @@ import jdk.test.lib.process.OutputAnalyzer; public class TestWrongBarrierEnable { public static void main(String[] args) throws Exception { - String[] concurrent = { "ShenandoahSATBBarrier" }; + String[] concurrent = { + "ShenandoahLoadRefBarrier", + "ShenandoahSATBBarrier", + "ShenandoahCASBarrier", + "ShenandoahCloneBarrier", + "ShenandoahStackWatermarkBarrier", + }; String[] generational = { "ShenandoahCardBarrier" }; - String[] all = { "ShenandoahSATBBarrier", "ShenandoahCardBarrier" }; + String[] all = { + "ShenandoahLoadRefBarrier", + "ShenandoahSATBBarrier", + "ShenandoahCASBarrier", + "ShenandoahCloneBarrier", + "ShenandoahStackWatermarkBarrier", + "ShenandoahCardBarrier" + }; shouldPassAll("-XX:ShenandoahGCHeuristics=adaptive", concurrent); shouldPassAll("-XX:ShenandoahGCHeuristics=static", concurrent); shouldPassAll("-XX:ShenandoahGCHeuristics=compact", concurrent); shouldPassAll("-XX:ShenandoahGCHeuristics=aggressive", concurrent); - shouldPassAll("-XX:ShenandoahGCMode=passive", concurrent); + shouldPassAll("-XX:ShenandoahGCMode=passive", all); shouldPassAll("-XX:ShenandoahGCMode=generational", all); shouldFailAll("-XX:ShenandoahGCMode=satb", generational); - shouldFailAll("-XX:ShenandoahGCMode=passive", generational); } private static void shouldFailAll(String h, String[] barriers) throws Exception {