8369013: Shenandoah: passive mode should support enabling ShenandoahCardBarrier

Reviewed-by: wkemper
This commit is contained in:
Rui Li 2025-10-29 21:40:36 +00:00 committed by Xiaolong Peng
parent d62553d8dc
commit f3dfdfa3fd
9 changed files with 111 additions and 13 deletions

View File

@ -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 {

View File

@ -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();

View File

@ -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<ShenandoahGenerationalHeap*>(heap);
}

View File

@ -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");
//

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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(); }

View File

@ -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<byte[]> 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();
}
}

View File

@ -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 {