8276787: Improve warning messages for -XX:+RecordDynamicDumpInfo

Reviewed-by: ccheung, stuefe
This commit is contained in:
Ioi Lam 2021-11-16 21:03:33 +00:00
parent 8ed384cfb6
commit a77d8ddf11
11 changed files with 255 additions and 113 deletions

View File

@ -50,7 +50,9 @@
class DynamicArchiveBuilder : public ArchiveBuilder {
const char* _archive_name;
public:
DynamicArchiveBuilder(const char* archive_name) : _archive_name(archive_name) {}
void mark_pointer(address* ptr_loc) {
ArchivePtrMarker::mark_pointer(ptr_loc);
}
@ -318,7 +320,7 @@ void DynamicArchiveBuilder::write_archive(char* serialized_data) {
FileMapInfo* dynamic_info = FileMapInfo::dynamic_info();
assert(dynamic_info != NULL, "Sanity");
dynamic_info->open_for_write(Arguments::GetSharedDynamicArchivePath());
dynamic_info->open_for_write(_archive_name);
ArchiveBuilder::write_archive(dynamic_info, NULL, NULL, NULL, NULL);
address base = _requested_dynamic_archive_bottom;
@ -333,9 +335,10 @@ void DynamicArchiveBuilder::write_archive(char* serialized_data) {
}
class VM_PopulateDynamicDumpSharedSpace: public VM_GC_Sync_Operation {
DynamicArchiveBuilder builder;
DynamicArchiveBuilder _builder;
public:
VM_PopulateDynamicDumpSharedSpace() : VM_GC_Sync_Operation() {}
VM_PopulateDynamicDumpSharedSpace(const char* archive_name)
: VM_GC_Sync_Operation(), _builder(archive_name) {}
VMOp_Type type() const { return VMOp_PopulateDumpSharedSpace; }
void doit() {
ResourceMark rm;
@ -349,11 +352,30 @@ public:
}
FileMapInfo::check_nonempty_dir_in_shared_path_table();
builder.doit();
_builder.doit();
}
};
void DynamicArchive::prepare_for_dynamic_dumping() {
void DynamicArchive::check_for_dynamic_dump() {
if (DynamicDumpSharedSpaces && !UseSharedSpaces) {
// This could happen if SharedArchiveFile has failed to load:
// - -Xshare:off was specified
// - SharedArchiveFile points to an non-existent file.
// - SharedArchiveFile points to an archive that has failed CRC check
// - SharedArchiveFile is not specified and the VM doesn't have a compatible default archive
#define __THEMSG " is unsupported when base CDS archive is not loaded. Run with -Xlog:cds for more info."
if (RecordDynamicDumpInfo) {
vm_exit_during_initialization("-XX:+RecordDynamicDumpInfo" __THEMSG, NULL);
} else {
assert(ArchiveClassesAtExit != nullptr, "sanity");
vm_exit_during_initialization("-XX:ArchiveClassesAtExit" __THEMSG, NULL);
#undef __THEMSG
}
}
}
void DynamicArchive::prepare_for_dump_at_exit() {
EXCEPTION_MARK;
ResourceMark rm(THREAD);
MetaspaceShared::link_shared_classes(THREAD);
@ -367,41 +389,27 @@ void DynamicArchive::prepare_for_dynamic_dumping() {
}
}
void DynamicArchive::dump(const char* archive_name, TRAPS) {
assert(UseSharedSpaces && RecordDynamicDumpInfo, "already checked in arguments.cpp?");
assert(ArchiveClassesAtExit == nullptr, "already checked in arguments.cpp?");
ArchiveClassesAtExit = archive_name;
if (Arguments::init_shared_archive_paths()) {
prepare_for_dynamic_dumping();
if (DynamicDumpSharedSpaces) {
dump(CHECK);
}
} else {
ArchiveClassesAtExit = nullptr;
THROW_MSG(vmSymbols::java_lang_RuntimeException(),
"Could not setup SharedDynamicArchivePath");
}
// prevent do dynamic dump at exit.
ArchiveClassesAtExit = nullptr;
if (!Arguments::init_shared_archive_paths()) {
THROW_MSG(vmSymbols::java_lang_RuntimeException(),
"Could not restore SharedDynamicArchivePath");
}
// This is called by "jcmd VM.cds dynamic_dump"
void DynamicArchive::dump_for_jcmd(const char* archive_name, TRAPS) {
assert(UseSharedSpaces && RecordDynamicDumpInfo, "already checked in arguments.cpp");
assert(ArchiveClassesAtExit == nullptr, "already checked in arguments.cpp");
assert(DynamicDumpSharedSpaces, "already checked by check_for_dynamic_dump() during VM startup");
MetaspaceShared::link_shared_classes(CHECK);
dump(archive_name, THREAD);
}
void DynamicArchive::dump(TRAPS) {
if (Arguments::GetSharedDynamicArchivePath() == NULL) {
log_warning(cds, dynamic)("SharedDynamicArchivePath is not specified");
return;
}
void DynamicArchive::dump(const char* archive_name, TRAPS) {
// copy shared path table to saved.
FileMapInfo::clone_shared_path_table(CHECK);
VM_PopulateDynamicDumpSharedSpace op;
VM_PopulateDynamicDumpSharedSpace op(archive_name);
VMThread::execute(&op);
}
bool DynamicArchive::should_dump_at_vm_exit() {
return DynamicDumpSharedSpaces && (ArchiveClassesAtExit != nullptr);
}
bool DynamicArchive::validate(FileMapInfo* dynamic_info) {
assert(!dynamic_info->is_static(), "must be");
// Check if the recorded base archive matches with the current one

View File

@ -59,9 +59,11 @@ public:
class DynamicArchive : AllStatic {
public:
static void prepare_for_dynamic_dumping();
static void check_for_dynamic_dump();
static bool should_dump_at_vm_exit();
static void prepare_for_dump_at_exit();
static void dump_for_jcmd(const char* archive_name, TRAPS);
static void dump(const char* archive_name, TRAPS);
static void dump(TRAPS);
static bool is_mapped() { return FileMapInfo::dynamic_info() != NULL; }
static bool validate(FileMapInfo* dynamic_info);
};

View File

@ -749,10 +749,6 @@ void Metaspace::global_initialize() {
// If any of the archived space fails to map, UseSharedSpaces
// is reset to false.
}
if (DynamicDumpSharedSpaces && !UseSharedSpaces) {
vm_exit_during_initialization("DynamicDumpSharedSpaces is unsupported when base CDS archive is not loaded", NULL);
}
#endif // INCLUDE_CDS
#ifdef _LP64

View File

@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
#include "cds/dynamicArchive.hpp"
#include "cds/heapShared.hpp"
#include "cds/metaspaceShared.hpp"
#include "classfile/classLoader.hpp"
@ -765,6 +766,7 @@ jint universe_init() {
Universe::_do_stack_walk_cache = new LatestMethodCache();
#if INCLUDE_CDS
DynamicArchive::check_for_dynamic_dump();
if (UseSharedSpaces) {
// Read the data structures supporting the shared spaces (shared
// system dictionary, symbol table, etc.). After that, access to

View File

@ -426,8 +426,8 @@ extern volatile jint vm_created;
JVM_ENTRY_NO_ENV(void, JVM_BeforeHalt())
#if INCLUDE_CDS
// Link all classes for dynamic CDS dumping before vm exit.
if (DynamicDumpSharedSpaces) {
DynamicArchive::prepare_for_dynamic_dumping();
if (DynamicArchive::should_dump_at_vm_exit()) {
DynamicArchive::prepare_for_dump_at_exit();
}
#endif
EventShutdown event;
@ -3706,7 +3706,7 @@ JVM_ENTRY(void, JVM_DumpDynamicArchive(JNIEnv *env, jstring archiveName))
ResourceMark rm(THREAD);
Handle file_handle(THREAD, JNIHandles::resolve_non_null(archiveName));
char* archive_name = java_lang_String::as_utf8_string(file_handle());
DynamicArchive::dump(archive_name, CHECK);
DynamicArchive::dump_for_jcmd(archive_name, CHECK);
#endif // INCLUDE_CDS
JVM_END

View File

@ -1439,6 +1439,8 @@ bool Arguments::check_unsupported_cds_runtime_properties() {
if (get_property(unsupported_properties[i]) != NULL) {
if (RequireSharedSpaces) {
warning("CDS is disabled when the %s option is specified.", unsupported_options[i]);
} else {
log_info(cds)("CDS is disabled when the %s option is specified.", unsupported_options[i]);
}
return true;
}
@ -3117,17 +3119,11 @@ jint Arguments::finalize_vm_init_args(bool patch_mod_javabase) {
// TODO: revisit the following for the static archive case.
set_mode_flags(_int);
}
if (DumpSharedSpaces || ArchiveClassesAtExit != NULL) {
// Always verify non-system classes during CDS dump
if (!BytecodeVerificationRemote) {
BytecodeVerificationRemote = true;
log_info(cds)("All non-system classes will be verified (-Xverify:remote) during CDS dump time.");
}
}
// RecordDynamicDumpInfo is not compatible with ArchiveClassesAtExit
if (ArchiveClassesAtExit != NULL && RecordDynamicDumpInfo) {
log_info(cds)("RecordDynamicDumpInfo is for jcmd only, could not set with -XX:ArchiveClassesAtExit.");
jio_fprintf(defaultStream::output_stream(),
"-XX:+RecordDynamicDumpInfo cannot be used with -XX:ArchiveClassesAtExit.\n");
return JNI_ERR;
}
@ -3143,6 +3139,14 @@ jint Arguments::finalize_vm_init_args(bool patch_mod_javabase) {
if (UseSharedSpaces && !DumpSharedSpaces && check_unsupported_cds_runtime_properties()) {
FLAG_SET_DEFAULT(UseSharedSpaces, false);
}
if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
// Always verify non-system classes during CDS dump
if (!BytecodeVerificationRemote) {
BytecodeVerificationRemote = true;
log_info(cds)("All non-system classes will be verified (-Xverify:remote) during CDS dump time.");
}
}
#endif
#ifndef CAN_SHOW_REGISTERS_ON_ASSERT
@ -3422,9 +3426,7 @@ jint Arguments::set_shared_spaces_flags_and_archive_paths() {
#if INCLUDE_CDS
// Initialize shared archive paths which could include both base and dynamic archive paths
// This must be after set_ergonomics_flags() called so flag UseCompressedOops is set properly.
if (!init_shared_archive_paths()) {
return JNI_ENOMEM;
}
init_shared_archive_paths();
#endif // INCLUDE_CDS
return JNI_OK;
}
@ -3487,45 +3489,45 @@ void Arguments::extract_shared_archive_paths(const char* archive_path,
len = end_ptr - begin_ptr;
cur_path = NEW_C_HEAP_ARRAY(char, len + 1, mtInternal);
strncpy(cur_path, begin_ptr, len + 1);
//cur_path[len] = '\0';
FileMapInfo::check_archive((const char*)cur_path, false /*is_static*/);
*top_archive_path = cur_path;
}
bool Arguments::init_shared_archive_paths() {
if (ArchiveClassesAtExit != NULL) {
void Arguments::init_shared_archive_paths() {
if (ArchiveClassesAtExit != nullptr) {
assert(!RecordDynamicDumpInfo, "already checked");
if (DumpSharedSpaces) {
vm_exit_during_initialization("-XX:ArchiveClassesAtExit cannot be used with -Xshare:dump");
}
if (FLAG_SET_CMDLINE(DynamicDumpSharedSpaces, true) != JVMFlag::SUCCESS) {
return false;
}
check_unsupported_dumping_properties();
SharedDynamicArchivePath = os::strdup_check_oom(ArchiveClassesAtExit, mtArguments);
} else {
if (SharedDynamicArchivePath != nullptr) {
os::free(SharedDynamicArchivePath);
SharedDynamicArchivePath = nullptr;
}
}
if (SharedArchiveFile == NULL) {
if (SharedArchiveFile == nullptr) {
SharedArchivePath = get_default_shared_archive_path();
} else {
int archives = num_archives(SharedArchiveFile);
if (is_dumping_archive()) {
if (archives > 1) {
vm_exit_during_initialization(
"Cannot have more than 1 archive file specified in -XX:SharedArchiveFile during CDS dumping");
}
if (DynamicDumpSharedSpaces) {
if (os::same_files(SharedArchiveFile, ArchiveClassesAtExit)) {
vm_exit_during_initialization(
"Cannot have the same archive file specified for -XX:SharedArchiveFile and -XX:ArchiveClassesAtExit",
SharedArchiveFile);
}
}
assert(archives > 0, "must be");
if (is_dumping_archive() && archives > 1) {
vm_exit_during_initialization(
"Cannot have more than 1 archive file specified in -XX:SharedArchiveFile during CDS dumping");
}
if (!is_dumping_archive()){
if (DumpSharedSpaces) {
assert(archives == 1, "must be");
// Static dump is simple: only one archive is allowed in SharedArchiveFile. This file
// will be overwritten no matter regardless of its contents
SharedArchivePath = os::strdup_check_oom(SharedArchiveFile, mtArguments);
} else {
// SharedArchiveFile may specify one or two files. In case (c), the path for base.jsa
// is read from top.jsa
// (a) 1 file: -XX:SharedArchiveFile=base.jsa
// (b) 2 files: -XX:SharedArchiveFile=base.jsa:top.jsa
// (c) 2 files: -XX:SharedArchiveFile=top.jsa
//
// However, if either RecordDynamicDumpInfo or ArchiveClassesAtExit is used, we do not
// allow cases (b) and (c). Case (b) is already checked above.
if (archives > 2) {
vm_exit_during_initialization(
"Cannot have more than 2 archive files specified in the -XX:SharedArchiveFile option");
@ -3543,11 +3545,26 @@ bool Arguments::init_shared_archive_paths() {
extract_shared_archive_paths((const char*)SharedArchiveFile,
&SharedArchivePath, &SharedDynamicArchivePath);
}
} else { // CDS dumping
SharedArchivePath = os::strdup_check_oom(SharedArchiveFile, mtArguments);
if (SharedDynamicArchivePath != nullptr) {
// Check for case (c)
if (RecordDynamicDumpInfo) {
vm_exit_during_initialization("-XX:+RecordDynamicDumpInfo is unsupported when a dynamic CDS archive is specified in -XX:SharedArchiveFile",
SharedArchiveFile);
}
if (ArchiveClassesAtExit != nullptr) {
vm_exit_during_initialization("-XX:ArchiveClassesAtExit is unsupported when a dynamic CDS archive is specified in -XX:SharedArchiveFile",
SharedArchiveFile);
}
}
if (ArchiveClassesAtExit != nullptr && os::same_files(SharedArchiveFile, ArchiveClassesAtExit)) {
vm_exit_during_initialization(
"Cannot have the same archive file specified for -XX:SharedArchiveFile and -XX:ArchiveClassesAtExit",
SharedArchiveFile);
}
}
}
return (SharedArchivePath != NULL);
}
#endif // INCLUDE_CDS

View File

@ -618,7 +618,7 @@ class Arguments : AllStatic {
static void fix_appclasspath();
static char* get_default_shared_archive_path() NOT_CDS_RETURN_(NULL);
static bool init_shared_archive_paths() NOT_CDS_RETURN_(false);
static void init_shared_archive_paths() NOT_CDS_RETURN;
// Operation modi
static Mode mode() { return _mode; }

View File

@ -503,9 +503,10 @@ void before_exit(JavaThread* thread) {
os::terminate_signal_thread();
#if INCLUDE_CDS
if (DynamicDumpSharedSpaces) {
if (DynamicArchive::should_dump_at_vm_exit()) {
assert(ArchiveClassesAtExit != NULL, "Must be already set");
ExceptionMark em(thread);
DynamicArchive::dump(thread);
DynamicArchive::dump(ArchiveClassesAtExit, thread);
if (thread->has_pending_exception()) {
ResourceMark rm(thread);
oop pending_exception = thread->pending_exception();

View File

@ -3303,8 +3303,8 @@ void JavaThread::invoke_shutdown_hooks() {
// Link all classes for dynamic CDS dumping before vm exit.
// Same operation is being done in JVM_BeforeHalt for handling the
// case where the application calls System.exit().
if (DynamicDumpSharedSpaces) {
DynamicArchive::prepare_for_dynamic_dumping();
if (DynamicArchive::should_dump_at_vm_exit()) {
DynamicArchive::prepare_for_dump_at_exit();
}
#endif

View File

@ -24,6 +24,7 @@
/*
* @test
* @bug 8276787
* @summary Some negative tests for the SharedArchiveFile option
* @requires vm.cds
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds /test/hotspot/jtreg/runtime/cds/appcds/test-classes
@ -34,9 +35,10 @@
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. SharedArchiveFileOption
*/
import jdk.test.lib.helpers.ClassFileInstaller;
import java.io.File;
import jdk.test.lib.Asserts;
import jdk.test.lib.helpers.ClassFileInstaller;
import jtreg.SkippedException;
public class SharedArchiveFileOption extends DynamicArchiveTestBase {
public static void main(String[] args) throws Exception {
@ -53,12 +55,32 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase {
doTest(baseArchiveName, topArchiveName);
}
private static int testnum = 0;
private static void testcase(String s) {
System.out.println("\n\nTest #" + (++testnum) + " " + s);
}
private interface MyRunnable {
public void run() throws Exception;
}
private static void mustSkipWith(String expectedMsg, MyRunnable r) throws Exception {
try {
r.run();
} catch (SkippedException e) {
System.out.println("Got SkippedException: " + e);
Asserts.assertTrue(e.getMessage().contains(expectedMsg), "SkippedException must have message " + expectedMsg);
return;
}
Asserts.fail("SkippedException should have been thrown");
}
private static void doTest(String baseArchiveName, String topArchiveName) throws Exception {
String appJar = ClassFileInstaller.getJarPath("hello.jar");
String mainClass = "Hello";
String dummyArchiveName = getNewArchiveName("dummy");
// -Xshare:dump specified with -XX:ArchiveClassesAtExit
testcase("-Xshare:dump specified with -XX:ArchiveClassesAtExit");
dump2(dummyArchiveName, dummyArchiveName,
"-Xlog:cds",
"-Xlog:cds+dynamic=debug",
@ -68,8 +90,7 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase {
output.shouldContain("-XX:ArchiveClassesAtExit cannot be used with -Xshare:dump");
});
// more than 1 archive file specified in -XX:SharedArchiveFile during
// dynamic dumpgin
testcase("more than 1 archive file specified in -XX:SharedArchiveFile during dynamic dump");
String dummyArchives = dummyArchiveName + File.pathSeparator + dummyArchiveName;
dump2(dummyArchives, dummyArchiveName,
"-Xlog:cds",
@ -79,7 +100,7 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase {
output.shouldContain("Cannot have more than 1 archive file specified in -XX:SharedArchiveFile during CDS dumping");
});
// normal dynamic archive dumping
testcase("normal dynamic archive dumping");
dump2(baseArchiveName, topArchiveName,
"-Xlog:cds",
"-Xlog:cds+dynamic=debug",
@ -88,7 +109,7 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase {
output.shouldContain("Written dynamic archive 0x");
});
// same archive file specified for -XX:SharedArchiveFile and -XX:ArchiveClassesAtExit
testcase("same archive file specified for -XX:SharedArchiveFile and -XX:ArchiveClassesAtExit");
dump2(baseArchiveName, baseArchiveName,
"-Xlog:cds",
"-Xlog:cds+dynamic=debug",
@ -99,7 +120,7 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase {
});
// a top archive specified in the base archive position
testcase("a top archive specified in the base archive position");
run2(topArchiveName, baseArchiveName,
"-Xlog:class+load",
"-Xlog:cds+dynamic=debug,cds=debug",
@ -108,7 +129,7 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase {
output.shouldMatch("Not a base shared archive:.*top.*.jsa");
});
// a base archive specified in the top archive position
testcase("a base archive specified in the top archive position");
run2(baseArchiveName, baseArchiveName2,
"-Xlog:class+load",
"-Xlog:cds+dynamic=debug,cds=debug",
@ -117,7 +138,7 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase {
output.shouldMatch("Not a top shared archive:.*base.*.jsa");
});
// more than 2 archives specified in the -XX:ShareArchiveFile option
testcase("more than 2 archives specified in the -XX:ShareArchiveFile option");
String baseArchives = baseArchiveName + File.pathSeparator + baseArchiveName2;
run2(baseArchives, topArchiveName,
"-Xlog:class+load",
@ -128,7 +149,7 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase {
"Cannot have more than 2 archive files specified in the -XX:SharedArchiveFile option");
});
// base archive not specified
testcase("base archive not specified");
final String topArchive = File.pathSeparator + topArchiveName;
run2(topArchive, null,
"-Xlog:class+load",
@ -139,7 +160,7 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase {
"Base archive was not specified: " + topArchive);
});
// top archive not specified
testcase("top archive not specified");
final String baseArchive = baseArchiveName + File.pathSeparator;
run2(baseArchive, null,
"-Xlog:class+load",
@ -149,5 +170,96 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase {
output.shouldContain(
"Top archive was not specified: " + baseArchive);
});
testcase("A dynamic archive is already loaded when -XX:SharedArchiveFile is specified");
dump2(baseArchiveName /*this is overridden by -XX:SharedArchiveFile= below*/,
topArchiveName,
"-XX:SharedArchiveFile=" + topArchiveName,
"-cp", appJar, mainClass)
.assertAbnormalExit("-XX:ArchiveClassesAtExit is unsupported when a dynamic CDS archive is specified in -XX:SharedArchiveFile:");
testcase("A dynamic archive is already loaded when -XX:+RecordDynamicDumpInfo is specified");
run2(null, topArchiveName,
"-XX:+RecordDynamicDumpInfo",
"-cp", appJar, mainClass)
.assertAbnormalExit("-XX:+RecordDynamicDumpInfo is unsupported when a dynamic CDS archive is specified in -XX:SharedArchiveFile:");
testcase("-XX:+RecordDynamicDumpInfo cannot be used with -XX:ArchiveClassesAtExit");
dump2(baseArchiveName,
topArchiveName,
"-XX:+RecordDynamicDumpInfo",
"-cp", appJar, mainClass)
.assertAbnormalExit("-XX:+RecordDynamicDumpInfo cannot be used with -XX:ArchiveClassesAtExit");
testcase("Specifying -XX:+RecordDynamicDumpInfo should not cause dynamic dump");
run2(baseArchiveName, null,
"-XX:+RecordDynamicDumpInfo",
"-Xlog:cds+dynamic=debug",
"-cp", appJar, mainClass)
.assertNormalExit(output -> {
output.shouldNotMatch("\\[cds,dynamic");
});
{
String ERROR = "-XX:ArchiveClassesAtExit is unsupported when base CDS archive is not loaded";
testcase("-XX:ArchiveClassesAtExit with CDS disabled (-Xshare:off)");
mustSkipWith(ERROR, () -> {
dump2(baseArchiveName,
topArchiveName,
"-Xshare:off",
"-cp", appJar, mainClass);
});
testcase("-XX:ArchiveClassesAtExit with CDS disabled (Base archive cannot be mapped -- doesn't exist");
mustSkipWith(ERROR, () -> {
dump2(baseArchiveName + ".notExist",
topArchiveName,
"-Xlog:cds",
"-Xshare:auto",
"-cp", appJar, mainClass);
});
testcase("-XX:ArchiveClassesAtExit with CDS disabled (incompatible VM options)");
dump2(baseArchiveName,
topArchiveName,
"--patch-module",
"foo.bar=xxx",
"-Xshare:auto",
"-Xlog:cds",
"-cp", appJar, mainClass)
.assertAbnormalExit("Cannot use the following option when dumping the shared archive: --patch-module");
}
{
String ERROR = "-XX:+RecordDynamicDumpInfo is unsupported when base CDS archive is not loaded";
testcase("-XX:+RecordDynamicDumpInfo with CDS disabled (-Xshare:off)");
run2(baseArchiveName, null,
"-XX:+RecordDynamicDumpInfo",
"-Xshare:off",
"-cp", appJar, mainClass)
.assertAbnormalExit(ERROR);
testcase("-XX:+RecordDynamicDumpInfo with CDS disabled (Base archive cannot be mapped -- doesn't exist");
run2(baseArchiveName + ".notExist", null,
"-XX:+RecordDynamicDumpInfo",
"-Xshare:auto",
"-Xlog:cds",
"-cp", appJar, mainClass)
.assertAbnormalExit(ERROR);
testcase("-XX:+RecordDynamicDumpInfo with CDS disabled (incompatible VM options)");
run2(baseArchiveName + ".notExist", null,
"-XX:+RecordDynamicDumpInfo",
"--patch-module",
"foo.bar=xxx",
"-Xshare:auto",
"-Xlog:cds",
"-cp", appJar, mainClass)
.assertAbnormalExit("CDS is disabled when the --patch-module option is specified",
ERROR);
}
}
}

View File

@ -41,7 +41,7 @@ public class CDSTestUtils {
public static final String MSG_RANGE_ALREADT_IN_USE =
"Unable to allocate region, java heap range is already in use.";
public static final String MSG_DYNAMIC_NOT_SUPPORTED =
"DynamicDumpSharedSpaces is unsupported when base CDS archive is not loaded";
"-XX:ArchiveClassesAtExit is unsupported when base CDS archive is not loaded";
public static final boolean DYNAMIC_DUMP = Boolean.getBoolean("test.dynamic.cds.archive");
public interface Checker {
@ -326,9 +326,7 @@ public class CDSTestUtils {
// Special case -- sometimes Xshare:on fails because it failed to map
// at given address. This behavior is platform-specific, machine config-specific
// and can be random (see ASLR).
if (isUnableToMap(output)) {
throw new SkippedException(UnableToMapMsg);
}
checkMappingFailure(output);
if (e != null) {
throw e;
@ -351,19 +349,28 @@ public class CDSTestUtils {
// instead of utilizing multiple messages.
// These are suggestions to improve testibility of the VM. However, implementing them
// could also improve usability in the field.
public static boolean isUnableToMap(OutputAnalyzer output) {
private static String hasUnableToMapMessage(OutputAnalyzer output) {
String outStr = output.getOutput();
if ((output.getExitValue() == 1) &&
(outStr.contains(MSG_RANGE_NOT_WITHIN_HEAP) || outStr.contains(MSG_DYNAMIC_NOT_SUPPORTED))) {
return true;
if ((output.getExitValue() == 1)) {
if (outStr.contains(MSG_RANGE_NOT_WITHIN_HEAP)) {
return MSG_RANGE_NOT_WITHIN_HEAP;
}
if (outStr.contains(MSG_DYNAMIC_NOT_SUPPORTED)) {
return MSG_DYNAMIC_NOT_SUPPORTED;
}
}
return false;
return null;
}
public static boolean isUnableToMap(OutputAnalyzer output) {
return hasUnableToMapMessage(output) != null;
}
public static void checkMappingFailure(OutputAnalyzer out) throws SkippedException {
if (isUnableToMap(out)) {
throw new SkippedException(UnableToMapMsg);
String match = hasUnableToMapMessage(out);
if (match != null) {
throw new SkippedException(UnableToMapMsg + ": " + match);
}
}
@ -472,10 +479,7 @@ public class CDSTestUtils {
public static OutputAnalyzer checkExecExpectError(OutputAnalyzer output,
int expectedExitValue,
String... extraMatches) throws Exception {
if (isUnableToMap(output)) {
throw new SkippedException(UnableToMapMsg);
}
checkMappingFailure(output);
output.shouldHaveExitValue(expectedExitValue);
checkMatches(output, extraMatches);
return output;