8276787: Improve warning messages for -XX:+RecordDynamicDumpInfo
Reviewed-by: ccheung, stuefe
This commit is contained in:
parent
8ed384cfb6
commit
a77d8ddf11
@ -50,7 +50,9 @@
|
|||||||
|
|
||||||
|
|
||||||
class DynamicArchiveBuilder : public ArchiveBuilder {
|
class DynamicArchiveBuilder : public ArchiveBuilder {
|
||||||
|
const char* _archive_name;
|
||||||
public:
|
public:
|
||||||
|
DynamicArchiveBuilder(const char* archive_name) : _archive_name(archive_name) {}
|
||||||
void mark_pointer(address* ptr_loc) {
|
void mark_pointer(address* ptr_loc) {
|
||||||
ArchivePtrMarker::mark_pointer(ptr_loc);
|
ArchivePtrMarker::mark_pointer(ptr_loc);
|
||||||
}
|
}
|
||||||
@ -318,7 +320,7 @@ void DynamicArchiveBuilder::write_archive(char* serialized_data) {
|
|||||||
FileMapInfo* dynamic_info = FileMapInfo::dynamic_info();
|
FileMapInfo* dynamic_info = FileMapInfo::dynamic_info();
|
||||||
assert(dynamic_info != NULL, "Sanity");
|
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);
|
ArchiveBuilder::write_archive(dynamic_info, NULL, NULL, NULL, NULL);
|
||||||
|
|
||||||
address base = _requested_dynamic_archive_bottom;
|
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 {
|
class VM_PopulateDynamicDumpSharedSpace: public VM_GC_Sync_Operation {
|
||||||
DynamicArchiveBuilder builder;
|
DynamicArchiveBuilder _builder;
|
||||||
public:
|
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; }
|
VMOp_Type type() const { return VMOp_PopulateDumpSharedSpace; }
|
||||||
void doit() {
|
void doit() {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
@ -349,11 +352,30 @@ public:
|
|||||||
}
|
}
|
||||||
FileMapInfo::check_nonempty_dir_in_shared_path_table();
|
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;
|
EXCEPTION_MARK;
|
||||||
ResourceMark rm(THREAD);
|
ResourceMark rm(THREAD);
|
||||||
MetaspaceShared::link_shared_classes(THREAD);
|
MetaspaceShared::link_shared_classes(THREAD);
|
||||||
@ -367,41 +389,27 @@ void DynamicArchive::prepare_for_dynamic_dumping() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DynamicArchive::dump(const char* archive_name, TRAPS) {
|
// This is called by "jcmd VM.cds dynamic_dump"
|
||||||
assert(UseSharedSpaces && RecordDynamicDumpInfo, "already checked in arguments.cpp?");
|
void DynamicArchive::dump_for_jcmd(const char* archive_name, TRAPS) {
|
||||||
assert(ArchiveClassesAtExit == nullptr, "already checked in arguments.cpp?");
|
assert(UseSharedSpaces && RecordDynamicDumpInfo, "already checked in arguments.cpp");
|
||||||
ArchiveClassesAtExit = archive_name;
|
assert(ArchiveClassesAtExit == nullptr, "already checked in arguments.cpp");
|
||||||
if (Arguments::init_shared_archive_paths()) {
|
assert(DynamicDumpSharedSpaces, "already checked by check_for_dynamic_dump() during VM startup");
|
||||||
prepare_for_dynamic_dumping();
|
MetaspaceShared::link_shared_classes(CHECK);
|
||||||
if (DynamicDumpSharedSpaces) {
|
dump(archive_name, THREAD);
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DynamicArchive::dump(TRAPS) {
|
void DynamicArchive::dump(const char* archive_name, TRAPS) {
|
||||||
if (Arguments::GetSharedDynamicArchivePath() == NULL) {
|
|
||||||
log_warning(cds, dynamic)("SharedDynamicArchivePath is not specified");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy shared path table to saved.
|
// copy shared path table to saved.
|
||||||
FileMapInfo::clone_shared_path_table(CHECK);
|
FileMapInfo::clone_shared_path_table(CHECK);
|
||||||
|
|
||||||
VM_PopulateDynamicDumpSharedSpace op;
|
VM_PopulateDynamicDumpSharedSpace op(archive_name);
|
||||||
VMThread::execute(&op);
|
VMThread::execute(&op);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DynamicArchive::should_dump_at_vm_exit() {
|
||||||
|
return DynamicDumpSharedSpaces && (ArchiveClassesAtExit != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
bool DynamicArchive::validate(FileMapInfo* dynamic_info) {
|
bool DynamicArchive::validate(FileMapInfo* dynamic_info) {
|
||||||
assert(!dynamic_info->is_static(), "must be");
|
assert(!dynamic_info->is_static(), "must be");
|
||||||
// Check if the recorded base archive matches with the current one
|
// Check if the recorded base archive matches with the current one
|
||||||
|
@ -59,9 +59,11 @@ public:
|
|||||||
|
|
||||||
class DynamicArchive : AllStatic {
|
class DynamicArchive : AllStatic {
|
||||||
public:
|
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(const char* archive_name, TRAPS);
|
||||||
static void dump(TRAPS);
|
|
||||||
static bool is_mapped() { return FileMapInfo::dynamic_info() != NULL; }
|
static bool is_mapped() { return FileMapInfo::dynamic_info() != NULL; }
|
||||||
static bool validate(FileMapInfo* dynamic_info);
|
static bool validate(FileMapInfo* dynamic_info);
|
||||||
};
|
};
|
||||||
|
@ -749,10 +749,6 @@ void Metaspace::global_initialize() {
|
|||||||
// If any of the archived space fails to map, UseSharedSpaces
|
// If any of the archived space fails to map, UseSharedSpaces
|
||||||
// is reset to false.
|
// 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
|
#endif // INCLUDE_CDS
|
||||||
|
|
||||||
#ifdef _LP64
|
#ifdef _LP64
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
|
#include "cds/dynamicArchive.hpp"
|
||||||
#include "cds/heapShared.hpp"
|
#include "cds/heapShared.hpp"
|
||||||
#include "cds/metaspaceShared.hpp"
|
#include "cds/metaspaceShared.hpp"
|
||||||
#include "classfile/classLoader.hpp"
|
#include "classfile/classLoader.hpp"
|
||||||
@ -765,6 +766,7 @@ jint universe_init() {
|
|||||||
Universe::_do_stack_walk_cache = new LatestMethodCache();
|
Universe::_do_stack_walk_cache = new LatestMethodCache();
|
||||||
|
|
||||||
#if INCLUDE_CDS
|
#if INCLUDE_CDS
|
||||||
|
DynamicArchive::check_for_dynamic_dump();
|
||||||
if (UseSharedSpaces) {
|
if (UseSharedSpaces) {
|
||||||
// Read the data structures supporting the shared spaces (shared
|
// Read the data structures supporting the shared spaces (shared
|
||||||
// system dictionary, symbol table, etc.). After that, access to
|
// system dictionary, symbol table, etc.). After that, access to
|
||||||
|
@ -426,8 +426,8 @@ extern volatile jint vm_created;
|
|||||||
JVM_ENTRY_NO_ENV(void, JVM_BeforeHalt())
|
JVM_ENTRY_NO_ENV(void, JVM_BeforeHalt())
|
||||||
#if INCLUDE_CDS
|
#if INCLUDE_CDS
|
||||||
// Link all classes for dynamic CDS dumping before vm exit.
|
// Link all classes for dynamic CDS dumping before vm exit.
|
||||||
if (DynamicDumpSharedSpaces) {
|
if (DynamicArchive::should_dump_at_vm_exit()) {
|
||||||
DynamicArchive::prepare_for_dynamic_dumping();
|
DynamicArchive::prepare_for_dump_at_exit();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
EventShutdown event;
|
EventShutdown event;
|
||||||
@ -3706,7 +3706,7 @@ JVM_ENTRY(void, JVM_DumpDynamicArchive(JNIEnv *env, jstring archiveName))
|
|||||||
ResourceMark rm(THREAD);
|
ResourceMark rm(THREAD);
|
||||||
Handle file_handle(THREAD, JNIHandles::resolve_non_null(archiveName));
|
Handle file_handle(THREAD, JNIHandles::resolve_non_null(archiveName));
|
||||||
char* archive_name = java_lang_String::as_utf8_string(file_handle());
|
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
|
#endif // INCLUDE_CDS
|
||||||
JVM_END
|
JVM_END
|
||||||
|
|
||||||
|
@ -1439,6 +1439,8 @@ bool Arguments::check_unsupported_cds_runtime_properties() {
|
|||||||
if (get_property(unsupported_properties[i]) != NULL) {
|
if (get_property(unsupported_properties[i]) != NULL) {
|
||||||
if (RequireSharedSpaces) {
|
if (RequireSharedSpaces) {
|
||||||
warning("CDS is disabled when the %s option is specified.", unsupported_options[i]);
|
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;
|
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.
|
// TODO: revisit the following for the static archive case.
|
||||||
set_mode_flags(_int);
|
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
|
// RecordDynamicDumpInfo is not compatible with ArchiveClassesAtExit
|
||||||
if (ArchiveClassesAtExit != NULL && RecordDynamicDumpInfo) {
|
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;
|
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()) {
|
if (UseSharedSpaces && !DumpSharedSpaces && check_unsupported_cds_runtime_properties()) {
|
||||||
FLAG_SET_DEFAULT(UseSharedSpaces, false);
|
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
|
#endif
|
||||||
|
|
||||||
#ifndef CAN_SHOW_REGISTERS_ON_ASSERT
|
#ifndef CAN_SHOW_REGISTERS_ON_ASSERT
|
||||||
@ -3422,9 +3426,7 @@ jint Arguments::set_shared_spaces_flags_and_archive_paths() {
|
|||||||
#if INCLUDE_CDS
|
#if INCLUDE_CDS
|
||||||
// Initialize shared archive paths which could include both base and dynamic archive paths
|
// 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.
|
// This must be after set_ergonomics_flags() called so flag UseCompressedOops is set properly.
|
||||||
if (!init_shared_archive_paths()) {
|
init_shared_archive_paths();
|
||||||
return JNI_ENOMEM;
|
|
||||||
}
|
|
||||||
#endif // INCLUDE_CDS
|
#endif // INCLUDE_CDS
|
||||||
return JNI_OK;
|
return JNI_OK;
|
||||||
}
|
}
|
||||||
@ -3487,45 +3489,45 @@ void Arguments::extract_shared_archive_paths(const char* archive_path,
|
|||||||
len = end_ptr - begin_ptr;
|
len = end_ptr - begin_ptr;
|
||||||
cur_path = NEW_C_HEAP_ARRAY(char, len + 1, mtInternal);
|
cur_path = NEW_C_HEAP_ARRAY(char, len + 1, mtInternal);
|
||||||
strncpy(cur_path, begin_ptr, len + 1);
|
strncpy(cur_path, begin_ptr, len + 1);
|
||||||
//cur_path[len] = '\0';
|
|
||||||
FileMapInfo::check_archive((const char*)cur_path, false /*is_static*/);
|
FileMapInfo::check_archive((const char*)cur_path, false /*is_static*/);
|
||||||
*top_archive_path = cur_path;
|
*top_archive_path = cur_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Arguments::init_shared_archive_paths() {
|
void Arguments::init_shared_archive_paths() {
|
||||||
if (ArchiveClassesAtExit != NULL) {
|
if (ArchiveClassesAtExit != nullptr) {
|
||||||
|
assert(!RecordDynamicDumpInfo, "already checked");
|
||||||
if (DumpSharedSpaces) {
|
if (DumpSharedSpaces) {
|
||||||
vm_exit_during_initialization("-XX:ArchiveClassesAtExit cannot be used with -Xshare:dump");
|
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();
|
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();
|
SharedArchivePath = get_default_shared_archive_path();
|
||||||
} else {
|
} else {
|
||||||
int archives = num_archives(SharedArchiveFile);
|
int archives = num_archives(SharedArchiveFile);
|
||||||
if (is_dumping_archive()) {
|
assert(archives > 0, "must be");
|
||||||
if (archives > 1) {
|
|
||||||
vm_exit_during_initialization(
|
if (is_dumping_archive() && archives > 1) {
|
||||||
"Cannot have more than 1 archive file specified in -XX:SharedArchiveFile during CDS dumping");
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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) {
|
if (archives > 2) {
|
||||||
vm_exit_during_initialization(
|
vm_exit_during_initialization(
|
||||||
"Cannot have more than 2 archive files specified in the -XX:SharedArchiveFile option");
|
"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,
|
extract_shared_archive_paths((const char*)SharedArchiveFile,
|
||||||
&SharedArchivePath, &SharedDynamicArchivePath);
|
&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
|
#endif // INCLUDE_CDS
|
||||||
|
|
||||||
|
@ -618,7 +618,7 @@ class Arguments : AllStatic {
|
|||||||
static void fix_appclasspath();
|
static void fix_appclasspath();
|
||||||
|
|
||||||
static char* get_default_shared_archive_path() NOT_CDS_RETURN_(NULL);
|
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
|
// Operation modi
|
||||||
static Mode mode() { return _mode; }
|
static Mode mode() { return _mode; }
|
||||||
|
@ -503,9 +503,10 @@ void before_exit(JavaThread* thread) {
|
|||||||
os::terminate_signal_thread();
|
os::terminate_signal_thread();
|
||||||
|
|
||||||
#if INCLUDE_CDS
|
#if INCLUDE_CDS
|
||||||
if (DynamicDumpSharedSpaces) {
|
if (DynamicArchive::should_dump_at_vm_exit()) {
|
||||||
|
assert(ArchiveClassesAtExit != NULL, "Must be already set");
|
||||||
ExceptionMark em(thread);
|
ExceptionMark em(thread);
|
||||||
DynamicArchive::dump(thread);
|
DynamicArchive::dump(ArchiveClassesAtExit, thread);
|
||||||
if (thread->has_pending_exception()) {
|
if (thread->has_pending_exception()) {
|
||||||
ResourceMark rm(thread);
|
ResourceMark rm(thread);
|
||||||
oop pending_exception = thread->pending_exception();
|
oop pending_exception = thread->pending_exception();
|
||||||
|
@ -3303,8 +3303,8 @@ void JavaThread::invoke_shutdown_hooks() {
|
|||||||
// Link all classes for dynamic CDS dumping before vm exit.
|
// Link all classes for dynamic CDS dumping before vm exit.
|
||||||
// Same operation is being done in JVM_BeforeHalt for handling the
|
// Same operation is being done in JVM_BeforeHalt for handling the
|
||||||
// case where the application calls System.exit().
|
// case where the application calls System.exit().
|
||||||
if (DynamicDumpSharedSpaces) {
|
if (DynamicArchive::should_dump_at_vm_exit()) {
|
||||||
DynamicArchive::prepare_for_dynamic_dumping();
|
DynamicArchive::prepare_for_dump_at_exit();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* @test
|
* @test
|
||||||
|
* @bug 8276787
|
||||||
* @summary Some negative tests for the SharedArchiveFile option
|
* @summary Some negative tests for the SharedArchiveFile option
|
||||||
* @requires vm.cds
|
* @requires vm.cds
|
||||||
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds /test/hotspot/jtreg/runtime/cds/appcds/test-classes
|
* @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
|
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. SharedArchiveFileOption
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import jdk.test.lib.helpers.ClassFileInstaller;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import jdk.test.lib.Asserts;
|
||||||
|
import jdk.test.lib.helpers.ClassFileInstaller;
|
||||||
|
import jtreg.SkippedException;
|
||||||
|
|
||||||
public class SharedArchiveFileOption extends DynamicArchiveTestBase {
|
public class SharedArchiveFileOption extends DynamicArchiveTestBase {
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
@ -53,12 +55,32 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase {
|
|||||||
doTest(baseArchiveName, topArchiveName);
|
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 {
|
private static void doTest(String baseArchiveName, String topArchiveName) throws Exception {
|
||||||
String appJar = ClassFileInstaller.getJarPath("hello.jar");
|
String appJar = ClassFileInstaller.getJarPath("hello.jar");
|
||||||
String mainClass = "Hello";
|
String mainClass = "Hello";
|
||||||
String dummyArchiveName = getNewArchiveName("dummy");
|
String dummyArchiveName = getNewArchiveName("dummy");
|
||||||
|
|
||||||
// -Xshare:dump specified with -XX:ArchiveClassesAtExit
|
testcase("-Xshare:dump specified with -XX:ArchiveClassesAtExit");
|
||||||
dump2(dummyArchiveName, dummyArchiveName,
|
dump2(dummyArchiveName, dummyArchiveName,
|
||||||
"-Xlog:cds",
|
"-Xlog:cds",
|
||||||
"-Xlog:cds+dynamic=debug",
|
"-Xlog:cds+dynamic=debug",
|
||||||
@ -68,8 +90,7 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase {
|
|||||||
output.shouldContain("-XX:ArchiveClassesAtExit cannot be used with -Xshare:dump");
|
output.shouldContain("-XX:ArchiveClassesAtExit cannot be used with -Xshare:dump");
|
||||||
});
|
});
|
||||||
|
|
||||||
// more than 1 archive file specified in -XX:SharedArchiveFile during
|
testcase("more than 1 archive file specified in -XX:SharedArchiveFile during dynamic dump");
|
||||||
// dynamic dumpgin
|
|
||||||
String dummyArchives = dummyArchiveName + File.pathSeparator + dummyArchiveName;
|
String dummyArchives = dummyArchiveName + File.pathSeparator + dummyArchiveName;
|
||||||
dump2(dummyArchives, dummyArchiveName,
|
dump2(dummyArchives, dummyArchiveName,
|
||||||
"-Xlog:cds",
|
"-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");
|
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,
|
dump2(baseArchiveName, topArchiveName,
|
||||||
"-Xlog:cds",
|
"-Xlog:cds",
|
||||||
"-Xlog:cds+dynamic=debug",
|
"-Xlog:cds+dynamic=debug",
|
||||||
@ -88,7 +109,7 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase {
|
|||||||
output.shouldContain("Written dynamic archive 0x");
|
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,
|
dump2(baseArchiveName, baseArchiveName,
|
||||||
"-Xlog:cds",
|
"-Xlog:cds",
|
||||||
"-Xlog:cds+dynamic=debug",
|
"-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,
|
run2(topArchiveName, baseArchiveName,
|
||||||
"-Xlog:class+load",
|
"-Xlog:class+load",
|
||||||
"-Xlog:cds+dynamic=debug,cds=debug",
|
"-Xlog:cds+dynamic=debug,cds=debug",
|
||||||
@ -108,7 +129,7 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase {
|
|||||||
output.shouldMatch("Not a base shared archive:.*top.*.jsa");
|
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,
|
run2(baseArchiveName, baseArchiveName2,
|
||||||
"-Xlog:class+load",
|
"-Xlog:class+load",
|
||||||
"-Xlog:cds+dynamic=debug,cds=debug",
|
"-Xlog:cds+dynamic=debug,cds=debug",
|
||||||
@ -117,7 +138,7 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase {
|
|||||||
output.shouldMatch("Not a top shared archive:.*base.*.jsa");
|
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;
|
String baseArchives = baseArchiveName + File.pathSeparator + baseArchiveName2;
|
||||||
run2(baseArchives, topArchiveName,
|
run2(baseArchives, topArchiveName,
|
||||||
"-Xlog:class+load",
|
"-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");
|
"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;
|
final String topArchive = File.pathSeparator + topArchiveName;
|
||||||
run2(topArchive, null,
|
run2(topArchive, null,
|
||||||
"-Xlog:class+load",
|
"-Xlog:class+load",
|
||||||
@ -139,7 +160,7 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase {
|
|||||||
"Base archive was not specified: " + topArchive);
|
"Base archive was not specified: " + topArchive);
|
||||||
});
|
});
|
||||||
|
|
||||||
// top archive not specified
|
testcase("top archive not specified");
|
||||||
final String baseArchive = baseArchiveName + File.pathSeparator;
|
final String baseArchive = baseArchiveName + File.pathSeparator;
|
||||||
run2(baseArchive, null,
|
run2(baseArchive, null,
|
||||||
"-Xlog:class+load",
|
"-Xlog:class+load",
|
||||||
@ -149,5 +170,96 @@ public class SharedArchiveFileOption extends DynamicArchiveTestBase {
|
|||||||
output.shouldContain(
|
output.shouldContain(
|
||||||
"Top archive was not specified: " + baseArchive);
|
"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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ public class CDSTestUtils {
|
|||||||
public static final String MSG_RANGE_ALREADT_IN_USE =
|
public static final String MSG_RANGE_ALREADT_IN_USE =
|
||||||
"Unable to allocate region, java heap range is already in use.";
|
"Unable to allocate region, java heap range is already in use.";
|
||||||
public static final String MSG_DYNAMIC_NOT_SUPPORTED =
|
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 static final boolean DYNAMIC_DUMP = Boolean.getBoolean("test.dynamic.cds.archive");
|
||||||
|
|
||||||
public interface Checker {
|
public interface Checker {
|
||||||
@ -326,9 +326,7 @@ public class CDSTestUtils {
|
|||||||
// Special case -- sometimes Xshare:on fails because it failed to map
|
// Special case -- sometimes Xshare:on fails because it failed to map
|
||||||
// at given address. This behavior is platform-specific, machine config-specific
|
// at given address. This behavior is platform-specific, machine config-specific
|
||||||
// and can be random (see ASLR).
|
// and can be random (see ASLR).
|
||||||
if (isUnableToMap(output)) {
|
checkMappingFailure(output);
|
||||||
throw new SkippedException(UnableToMapMsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e != null) {
|
if (e != null) {
|
||||||
throw e;
|
throw e;
|
||||||
@ -351,19 +349,28 @@ public class CDSTestUtils {
|
|||||||
// instead of utilizing multiple messages.
|
// instead of utilizing multiple messages.
|
||||||
// These are suggestions to improve testibility of the VM. However, implementing them
|
// These are suggestions to improve testibility of the VM. However, implementing them
|
||||||
// could also improve usability in the field.
|
// could also improve usability in the field.
|
||||||
public static boolean isUnableToMap(OutputAnalyzer output) {
|
private static String hasUnableToMapMessage(OutputAnalyzer output) {
|
||||||
String outStr = output.getOutput();
|
String outStr = output.getOutput();
|
||||||
if ((output.getExitValue() == 1) &&
|
if ((output.getExitValue() == 1)) {
|
||||||
(outStr.contains(MSG_RANGE_NOT_WITHIN_HEAP) || outStr.contains(MSG_DYNAMIC_NOT_SUPPORTED))) {
|
if (outStr.contains(MSG_RANGE_NOT_WITHIN_HEAP)) {
|
||||||
return true;
|
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 {
|
public static void checkMappingFailure(OutputAnalyzer out) throws SkippedException {
|
||||||
if (isUnableToMap(out)) {
|
String match = hasUnableToMapMessage(out);
|
||||||
throw new SkippedException(UnableToMapMsg);
|
if (match != null) {
|
||||||
|
throw new SkippedException(UnableToMapMsg + ": " + match);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -472,10 +479,7 @@ public class CDSTestUtils {
|
|||||||
public static OutputAnalyzer checkExecExpectError(OutputAnalyzer output,
|
public static OutputAnalyzer checkExecExpectError(OutputAnalyzer output,
|
||||||
int expectedExitValue,
|
int expectedExitValue,
|
||||||
String... extraMatches) throws Exception {
|
String... extraMatches) throws Exception {
|
||||||
if (isUnableToMap(output)) {
|
checkMappingFailure(output);
|
||||||
throw new SkippedException(UnableToMapMsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
output.shouldHaveExitValue(expectedExitValue);
|
output.shouldHaveExitValue(expectedExitValue);
|
||||||
checkMatches(output, extraMatches);
|
checkMatches(output, extraMatches);
|
||||||
return output;
|
return output;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user