8341371: CDS cannot load archived heap objects with -XX:+UseSerialGC -XX:-UseCompressedOops

Reviewed-by: ccheung, iklam
This commit is contained in:
Matias Saavedra Silva 2024-10-28 14:31:35 +00:00
parent 120a9357b3
commit 9f6211bcf1
12 changed files with 128 additions and 42 deletions

View File

@ -142,15 +142,22 @@ class PatchCompressedEmbeddedPointersQuick: public BitMapClosure {
class PatchUncompressedEmbeddedPointers: public BitMapClosure {
oop* _start;
intptr_t _delta;
public:
PatchUncompressedEmbeddedPointers(oop* start) : _start(start) {}
PatchUncompressedEmbeddedPointers(oop* start, intx runtime_offset) :
_start(start),
_delta(runtime_offset) {}
PatchUncompressedEmbeddedPointers(oop* start) :
_start(start),
_delta(ArchiveHeapLoader::mapped_heap_delta()) {}
bool do_bit(size_t offset) {
oop* p = _start + offset;
intptr_t dumptime_oop = (intptr_t)((void*)*p);
assert(dumptime_oop != 0, "null oops should have been filtered out at dump time");
intptr_t runtime_oop = dumptime_oop + ArchiveHeapLoader::mapped_heap_delta();
intptr_t runtime_oop = dumptime_oop + _delta;
RawAccess<IS_NOT_NULL>::oop_store(p, cast_to_oop(runtime_oop));
return true;
}
@ -221,10 +228,6 @@ void ArchiveHeapLoader::init_loaded_heap_relocation(LoadedArchiveHeapRegion* loa
}
bool ArchiveHeapLoader::can_load() {
if (!UseCompressedOops) {
// Pointer relocation for uncompressed oops is unimplemented.
return false;
}
return Universe::heap()->can_load_archived_objects();
}
@ -312,13 +315,18 @@ bool ArchiveHeapLoader::load_heap_region_impl(FileMapInfo* mapinfo, LoadedArchiv
uintptr_t oopmap = bitmap_base + r->oopmap_offset();
BitMapView bm((BitMap::bm_word_t*)oopmap, r->oopmap_size_in_bits());
PatchLoadedRegionPointers patcher((narrowOop*)load_address + FileMapInfo::current_info()->heap_oopmap_start_pos(), loaded_region);
bm.iterate(&patcher);
if (UseCompressedOops) {
PatchLoadedRegionPointers patcher((narrowOop*)load_address + FileMapInfo::current_info()->heap_oopmap_start_pos(), loaded_region);
bm.iterate(&patcher);
} else {
PatchUncompressedEmbeddedPointers patcher((oop*)load_address + FileMapInfo::current_info()->heap_oopmap_start_pos(), loaded_region->_runtime_offset);
bm.iterate(&patcher);
}
return true;
}
bool ArchiveHeapLoader::load_heap_region(FileMapInfo* mapinfo) {
assert(UseCompressedOops, "loaded heap for !UseCompressedOops is unimplemented");
assert(can_load(), "loaded heap for must be supported");
init_narrow_oop_decoding(mapinfo->narrow_oop_base(), mapinfo->narrow_oop_shift());
LoadedArchiveHeapRegion loaded_region;
@ -358,8 +366,12 @@ class VerifyLoadedHeapEmbeddedPointers: public BasicOopIterateClosure {
}
}
virtual void do_oop(oop* p) {
// Uncompressed oops are not supported by loaded heaps.
Unimplemented();
oop v = *p;
if(v != nullptr) {
uintptr_t u = cast_from_oop<uintptr_t>(v);
ArchiveHeapLoader::assert_in_loaded_heap(u);
guarantee(_table->contains(u), "must point to beginning of object in loaded archived region");
}
}
};

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2024, 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
@ -146,6 +146,7 @@ private:
inline static oop decode_from_archive_impl(narrowOop v) NOT_CDS_JAVA_HEAP_RETURN_(nullptr);
class PatchLoadedRegionPointers;
class PatchUncompressedLoadedRegionPointers;
public:

View File

@ -2054,8 +2054,7 @@ void FileMapInfo::map_or_load_heap_region() {
success = ArchiveHeapLoader::load_heap_region(this);
} else {
if (!UseCompressedOops && !ArchiveHeapLoader::can_map()) {
// TODO - remove implicit knowledge of G1
log_info(cds)("Cannot use CDS heap data. UseG1GC is required for -XX:-UseCompressedOops");
log_info(cds)("Cannot use CDS heap data. Selected GC not compatible -XX:-UseCompressedOops");
} else {
log_info(cds)("Cannot use CDS heap data. UseEpsilonGC, UseG1GC, UseSerialGC, UseParallelGC, or UseShenandoahGC are required.");
}
@ -2135,7 +2134,7 @@ address FileMapInfo::heap_region_requested_address() {
assert(CDSConfig::is_using_archive(), "runtime only");
FileMapRegion* r = region_at(MetaspaceShared::hp);
assert(is_aligned(r->mapping_offset(), sizeof(HeapWord)), "must be");
assert(ArchiveHeapLoader::can_map(), "cannot be used by ArchiveHeapLoader::can_load() mode");
assert(ArchiveHeapLoader::can_use(), "GC must support mapping or loading");
if (UseCompressedOops) {
// We can avoid relocation if each region's offset from the runtime CompressedOops::base()
// is the same as its offset from the CompressedOops::base() during dumptime.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2022, Red Hat, Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -128,7 +128,7 @@ public:
bool is_in_reserved(const void* addr) const { return _reserved.contains(addr); }
// Support for loading objects from CDS archive into the heap
bool can_load_archived_objects() const override { return UseCompressedOops; }
bool can_load_archived_objects() const override { return true; }
HeapWord* allocate_loaded_archive_space(size_t size) override;
void print_on(outputStream* st) const override;

View File

@ -246,7 +246,7 @@ public:
}
// Support for loading objects from CDS archive into the heap
bool can_load_archived_objects() const override { return UseCompressedOops; }
bool can_load_archived_objects() const override { return true; }
HeapWord* allocate_loaded_archive_space(size_t size) override;
void complete_loaded_archive_space(MemRegion archive_space) override;

View File

@ -291,7 +291,7 @@ public:
void safepoint_synchronize_end() override;
// Support for loading objects from CDS archive into the heap
bool can_load_archived_objects() const override { return UseCompressedOops; }
bool can_load_archived_objects() const override { return true; }
HeapWord* allocate_loaded_archive_space(size_t size) override;
void complete_loaded_archive_space(MemRegion archive_space) override;

View File

@ -543,7 +543,7 @@ public:
// ---------- CDS archive support
bool can_load_archived_objects() const override { return UseCompressedOops; }
bool can_load_archived_objects() const override { return true; }
HeapWord* allocate_loaded_archive_space(size_t size) override;
void complete_loaded_archive_space(MemRegion archive_space) override;

View File

@ -2159,8 +2159,7 @@ WB_ENTRY(jboolean, WB_IsJVMCISupportedByGC(JNIEnv* env))
WB_END
WB_ENTRY(jboolean, WB_CanWriteJavaHeapArchive(JNIEnv* env))
return HeapShared::can_write()
&& ArchiveHeapLoader::can_use(); // work-around JDK-8341371
return HeapShared::can_write();
WB_END

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2024, 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
@ -37,16 +37,41 @@
* @run driver TestEpsilonGCWithCDS
*/
// Below is exactly the same as above, except:
// - requires vm.bits == "64"
// - extra argument "false"
/*
* @test Loading CDS archived heap objects into EpsilonGC
* @bug 8234679 8341371
* @requires vm.cds
* @requires vm.gc.Epsilon
* @requires vm.gc.G1
* @requires vm.bits == "64"
*
* @comment don't run this test if any -XX::+Use???GC options are specified, since they will
* interfere with the test.
* @requires vm.gc == null
*
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
* @compile test-classes/Hello.java
* @run driver TestEpsilonGCWithCDS false
*/
import jdk.test.lib.Platform;
import jdk.test.lib.process.OutputAnalyzer;
public class TestEpsilonGCWithCDS {
public final static String HELLO = "Hello World";
static String helloJar;
static boolean useCompressedOops = true;
public static void main(String... args) throws Exception {
helloJar = JarBuilder.build("hello", "Hello");
if (args.length > 0 && args[0].equals("false")) {
useCompressedOops = false;
}
// Check if we can use EpsilonGC during dump time, or run time, or both.
test(false, true);
test(true, false);
@ -70,6 +95,8 @@ public class TestEpsilonGCWithCDS {
String execGC = execWithEpsilon ? Epsilon : G1;
String small1 = useSmallRegions ? "-Xmx256m" : "-showversion";
String small2 = useSmallRegions ? "-XX:ObjectAlignmentInBytes=64" : "-showversion";
String errMsg = "Cannot use CDS heap data. Selected GC not compatible -XX:-UseCompressedOops";
String coops = useCompressedOops ? "-XX:+UseCompressedOops" : "-XX:-UseCompressedOops";
OutputAnalyzer out;
System.out.println("0. Dump with " + dumpGC);
@ -79,6 +106,7 @@ public class TestEpsilonGCWithCDS {
dumpGC,
small1,
small2,
coops,
"-Xlog:cds");
out.shouldContain("Dumping shared data to file:");
out.shouldHaveExitValue(0);
@ -89,9 +117,11 @@ public class TestEpsilonGCWithCDS {
execGC,
small1,
small2,
coops,
"-Xlog:cds",
"Hello");
out.shouldContain(HELLO);
out.shouldNotContain(errMsg);
out.shouldHaveExitValue(0);
}
}

View File

@ -37,16 +37,41 @@
* @run driver TestParallelGCWithCDS
*/
// Below is exactly the same as above, except:
// - requires vm.bits == "64"
// - extra argument "false"
/*
* @test Loading CDS archived heap objects into ParallelGC
* @bug 8274788 8341371
* @requires vm.cds
* @requires vm.gc.Parallel
* @requires vm.gc.G1
* @requires vm.bits == "64"
*
* @comment don't run this test if any -XX::+Use???GC options are specified, since they will
* interfere with the test.
* @requires vm.gc == null
*
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
* @compile test-classes/Hello.java
* @run driver TestParallelGCWithCDS false
*/
import jdk.test.lib.Platform;
import jdk.test.lib.process.OutputAnalyzer;
public class TestParallelGCWithCDS {
public final static String HELLO = "Hello World";
static String helloJar;
static boolean useCompressedOops = true;
public static void main(String... args) throws Exception {
helloJar = JarBuilder.build("hello", "Hello");
if (args.length > 0 && args[0].equals("false")) {
useCompressedOops = false;
}
// Check if we can use ParallelGC during dump time, or run time, or both.
test(false, true);
test(true, false);
@ -69,6 +94,8 @@ public class TestParallelGCWithCDS {
String execGC = execWithParallel ? Parallel : G1;
String small1 = useSmallRegions ? "-Xmx256m" : "-showversion";
String small2 = useSmallRegions ? "-XX:ObjectAlignmentInBytes=64" : "-showversion";
String errMsg = "Cannot use CDS heap data. Selected GC not compatible -XX:-UseCompressedOops";
String coops = useCompressedOops ? "-XX:+UseCompressedOops" : "-XX:-UseCompressedOops";
OutputAnalyzer out;
System.out.println("0. Dump with " + dumpGC);
@ -77,6 +104,7 @@ public class TestParallelGCWithCDS {
dumpGC,
small1,
small2,
coops,
"-Xlog:cds");
out.shouldContain("Dumping shared data to file:");
out.shouldHaveExitValue(0);
@ -86,9 +114,11 @@ public class TestParallelGCWithCDS {
execGC,
small1,
small2,
coops,
"-Xlog:cds",
"Hello");
out.shouldContain(HELLO);
out.shouldNotContain(errMsg);
out.shouldHaveExitValue(0);
int n = 2;
@ -109,10 +139,12 @@ public class TestParallelGCWithCDS {
small1,
small2,
xmx,
coops,
"-Xlog:cds",
"Hello");
if (out.getExitValue() == 0) {
out.shouldContain(HELLO);
out.shouldNotContain(errMsg);
} else {
String pattern = "((Too small maximum heap)" +
"|(GC triggered before VM initialization completed)" +

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2024, 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
@ -98,6 +98,7 @@ public class TestSerialGCWithCDS {
String execGC = execWithSerial ? Serial : G1;
String small1 = useSmallRegions ? "-Xmx256m" : DUMMY;
String small2 = useSmallRegions ? "-XX:ObjectAlignmentInBytes=64" : DUMMY;
String errMsg = "Cannot use CDS heap data. Selected GC not compatible -XX:-UseCompressedOops";
String coops;
if (Platform.is64bit()) {
coops = useCompressedOops ? "-XX:+UseCompressedOops" : "-XX:-UseCompressedOops";
@ -125,7 +126,7 @@ public class TestSerialGCWithCDS {
coops,
"-Xlog:cds",
"Hello");
checkExecOutput(dumpWithSerial, execWithSerial, out);
out.shouldNotContain(errMsg);
System.out.println("2. Exec with " + execGC + " and test ArchiveRelocationMode");
out = TestCommon.exec(helloJar,
@ -136,7 +137,7 @@ public class TestSerialGCWithCDS {
"-Xlog:cds,cds+heap",
"-XX:ArchiveRelocationMode=1", // always relocate shared metadata
"Hello");
checkExecOutput(dumpWithSerial, execWithSerial, out);
out.shouldNotContain(errMsg);
int n = 2;
if (dumpWithSerial == false && execWithSerial == true) {
@ -160,7 +161,7 @@ public class TestSerialGCWithCDS {
"-Xlog:cds",
"Hello");
if (out.getExitValue() == 0) {
checkExecOutput(dumpWithSerial, execWithSerial, out);
out.shouldNotContain(errMsg);
} else {
String output = out.getStdout() + out.getStderr();
String exp1 = "Too small maximum heap";
@ -173,19 +174,4 @@ public class TestSerialGCWithCDS {
}
}
}
static void checkExecOutput(boolean dumpWithSerial, boolean execWithSerial, OutputAnalyzer out) {
String errMsg = "Cannot use CDS heap data. UseG1GC is required for -XX:-UseCompressedOops";
if (Platform.is64bit() &&
!Platform.isWindows() && // archive heap not supported on Windows.
!dumpWithSerial && // Dumped with G1, so we have an archived heap
execWithSerial && // Running with serial
!useCompressedOops) { // ArchiveHeapLoader::can_load() always returns false when COOP is disabled
out.shouldContain(errMsg);
}
if (!execWithSerial) {
// We should never see this message with G1
out.shouldNotContain(errMsg);
}
}
}

View File

@ -35,16 +35,38 @@
* @run driver TestShenandoahWithCDS
*/
// Below is exactly the same as above, except:
// - requires vm.bits == "64"
// - extra argument "false"
/*
* @test
* @bug 8293650 8341371
* @requires vm.cds
* @requires vm.bits == 64
* @requires vm.gc.Shenandoah
* @requires vm.gc.G1
* @requires vm.gc == null
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
* @compile test-classes/Hello.java
* @run driver TestShenandoahWithCDS false
*/
import jdk.test.lib.Platform;
import jdk.test.lib.process.OutputAnalyzer;
public class TestShenandoahWithCDS {
public final static String HELLO = "Hello World";
static String helloJar;
static boolean useCompressedOops = true;
public static void main(String... args) throws Exception {
helloJar = JarBuilder.build("hello", "Hello");
if (args.length > 0 && args[0].equals("false")) {
useCompressedOops = false;
}
// Run with the variety of region sizes, and combinations
// of G1/Shenandoah at dump/exec times. "-1" means to use G1.
final int[] regionSizes = { -1, 256, 512, 1024, 2048 };
@ -62,6 +84,8 @@ public class TestShenandoahWithCDS {
String optExecGC = (execRegionSize != -1) ? "-XX:+UseShenandoahGC" : "-XX:+UseG1GC";
String optDumpRegionSize = (dumpRegionSize != -1) ? "-XX:ShenandoahRegionSize=" + dumpRegionSize + "K" : exp;
String optExecRegionSize = (execRegionSize != -1) ? "-XX:ShenandoahRegionSize=" + execRegionSize + "K" : exp;
String errMsg = "Cannot use CDS heap data. Selected GC not compatible -XX:-UseCompressedOops";
String coops = useCompressedOops ? "-XX:+UseCompressedOops" : "-XX:-UseCompressedOops";
OutputAnalyzer out;
System.out.println("0. Dump with " + optDumpGC + " and " + optDumpRegionSize);
@ -71,6 +95,7 @@ public class TestShenandoahWithCDS {
"-Xmx1g",
optDumpGC,
optDumpRegionSize,
coops,
"-Xlog:cds");
out.shouldContain("Dumping shared data to file:");
out.shouldHaveExitValue(0);
@ -81,9 +106,11 @@ public class TestShenandoahWithCDS {
"-Xmx1g",
optExecGC,
optExecRegionSize,
coops,
"-Xlog:cds",
"Hello");
out.shouldContain(HELLO);
out.shouldNotContain(errMsg);
out.shouldHaveExitValue(0);
}
}