Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
195 changes: 136 additions & 59 deletions src/hotspot/share/cds/cdsConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,10 @@ bool CDSConfig::_old_cds_flags_used = false;
bool CDSConfig::_new_aot_flags_used = false;
bool CDSConfig::_disable_heap_dumping = false;

char* CDSConfig::_default_archive_path = nullptr;
char* CDSConfig::_static_archive_path = nullptr;
char* CDSConfig::_dynamic_archive_path = nullptr;
const char* CDSConfig::_default_archive_path = nullptr;
const char* CDSConfig::_input_static_archive_path = nullptr;
const char* CDSConfig::_input_dynamic_archive_path = nullptr;
const char* CDSConfig::_output_archive_path = nullptr;

JavaThread* CDSConfig::_dumper_thread = nullptr;

Expand All @@ -66,7 +67,11 @@ int CDSConfig::get_status() {
(is_using_archive() ? IS_USING_ARCHIVE : 0);
}

void CDSConfig::initialize() {
DEBUG_ONLY(static bool _cds_ergo_initialize_started = false);

void CDSConfig::ergo_initialize() {
DEBUG_ONLY(_cds_ergo_initialize_started = true);

if (is_dumping_static_archive() && !is_dumping_final_static_archive()) {
// Note: -Xshare and -XX:AOTMode flags are mutually exclusive.
// - Classic workflow: -Xshare:on and -Xshare:dump cannot take effect at the same time.
Expand All @@ -83,18 +88,23 @@ void CDSConfig::initialize() {

// 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.
//
// UseSharedSpaces may be disabled if -XX:SharedArchiveFile is invalid.
if (is_dumping_static_archive() || is_using_archive()) {
init_shared_archive_paths();
if (new_aot_flags_used()) {
ergo_init_aot_paths();
} else {
ergo_init_classic_archive_paths();
}
}

if (!is_dumping_heap()) {
_is_dumping_full_module_graph = false;
}
}

char* CDSConfig::default_archive_path() {
const char* CDSConfig::default_archive_path() {
// The path depends on UseCompressedOops, etc, which are set by GC ergonomics just
// before CDSConfig::ergo_initialize() is called.
assert(_cds_ergo_initialize_started, "sanity");
if (_default_archive_path == nullptr) {
stringStream tmp;
const char* subdir = WINDOWS_ONLY("bin") NOT_WINDOWS("lib");
Expand All @@ -116,12 +126,12 @@ char* CDSConfig::default_archive_path() {
return _default_archive_path;
}

int CDSConfig::num_archives(const char* archive_path) {
if (archive_path == nullptr) {
int CDSConfig::num_archive_paths(const char* path_spec) {
if (path_spec == nullptr) {
return 0;
}
int npaths = 1;
char* p = (char*)archive_path;
char* p = (char*)path_spec;
while (*p != '\0') {
if (*p == os::path_separator()[0]) {
npaths++;
Expand All @@ -131,9 +141,9 @@ int CDSConfig::num_archives(const char* archive_path) {
return npaths;
}

void CDSConfig::extract_shared_archive_paths(const char* archive_path,
char** base_archive_path,
char** top_archive_path) {
void CDSConfig::extract_archive_paths(const char* archive_path,
const char** base_archive_path,
const char** top_archive_path) {
char* begin_ptr = (char*)archive_path;
char* end_ptr = strchr((char*)archive_path, os::path_separator()[0]);
if (end_ptr == nullptr || end_ptr == begin_ptr) {
Expand All @@ -157,7 +167,8 @@ void CDSConfig::extract_shared_archive_paths(const char* archive_path,
*top_archive_path = cur_path;
}

void CDSConfig::init_shared_archive_paths() {
void CDSConfig::ergo_init_classic_archive_paths() {
assert(_cds_ergo_initialize_started, "sanity");
if (ArchiveClassesAtExit != nullptr) {
assert(!RecordDynamicDumpInfo, "already checked");
if (is_dumping_static_archive()) {
Expand All @@ -172,21 +183,24 @@ void CDSConfig::init_shared_archive_paths() {
}

if (SharedArchiveFile == nullptr) {
_static_archive_path = default_archive_path();
_input_static_archive_path = default_archive_path();
if (is_dumping_static_archive()) {
_output_archive_path = _input_static_archive_path;
}
} else {
int archives = num_archives(SharedArchiveFile);
assert(archives > 0, "must be");
int num_archives = num_archive_paths(SharedArchiveFile);
assert(num_archives > 0, "must be");

if (is_dumping_archive() && archives > 1) {
if (is_dumping_archive() && num_archives > 1) {
vm_exit_during_initialization(
"Cannot have more than 1 archive file specified in -XX:SharedArchiveFile during CDS dumping");
}

if (is_dumping_static_archive()) {
assert(archives == 1, "must be");
assert(num_archives == 1, "just checked above");
// Static dump is simple: only one archive is allowed in SharedArchiveFile. This file
// will be overwritten no matter regardless of its contents
_static_archive_path = os::strdup_check_oom(SharedArchiveFile, mtArguments);
// will be overwritten regardless of its contents
_output_archive_path = SharedArchiveFile;
} else {
// SharedArchiveFile may specify one or two files. In case (c), the path for base.jsa
// is read from top.jsa
Expand All @@ -197,48 +211,49 @@ void CDSConfig::init_shared_archive_paths() {
// 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 (num_archives > 2) {
vm_exit_during_initialization(
"Cannot have more than 2 archive files specified in the -XX:SharedArchiveFile option");
}
if (archives == 1) {
char* base_archive_path = nullptr;

if (num_archives == 1) {
const char* base_archive_path = nullptr;
bool success =
FileMapInfo::get_base_archive_name_from_header(SharedArchiveFile, &base_archive_path);
if (!success) {
// If +AutoCreateSharedArchive and the specified shared archive does not exist,
// regenerate the dynamic archive base on default archive.
if (AutoCreateSharedArchive && !os::file_exists(SharedArchiveFile)) {
enable_dumping_dynamic_archive();
ArchiveClassesAtExit = const_cast<char *>(SharedArchiveFile);
_static_archive_path = default_archive_path();
SharedArchiveFile = nullptr;
} else {
enable_dumping_dynamic_archive(SharedArchiveFile);
FLAG_SET_ERGO(ArchiveClassesAtExit, SharedArchiveFile);
_input_static_archive_path = default_archive_path();
FLAG_SET_ERGO(SharedArchiveFile, nullptr);
} else {
if (AutoCreateSharedArchive) {
warning("-XX:+AutoCreateSharedArchive is unsupported when base CDS archive is not loaded. Run with -Xlog:cds for more info.");
AutoCreateSharedArchive = false;
}
log_error(cds)("Not a valid %s (%s)", new_aot_flags_used() ? "AOT cache" : "archive", SharedArchiveFile);
log_error(cds)("Not a valid archive (%s)", SharedArchiveFile);
Arguments::no_shared_spaces("invalid archive");
}
} else if (base_archive_path == nullptr) {
// User has specified a single archive, which is a static archive.
_static_archive_path = const_cast<char *>(SharedArchiveFile);
_input_static_archive_path = SharedArchiveFile;
} else {
// User has specified a single archive, which is a dynamic archive.
_dynamic_archive_path = const_cast<char *>(SharedArchiveFile);
_static_archive_path = base_archive_path; // has been c-heap allocated.
_input_dynamic_archive_path = SharedArchiveFile;
_input_static_archive_path = base_archive_path; // has been c-heap allocated.
}
} else {
extract_shared_archive_paths((const char*)SharedArchiveFile,
&_static_archive_path, &_dynamic_archive_path);
if (_static_archive_path == nullptr) {
assert(_dynamic_archive_path == nullptr, "must be");
extract_archive_paths(SharedArchiveFile,
&_input_static_archive_path, &_input_dynamic_archive_path);
if (_input_static_archive_path == nullptr) {
assert(_input_dynamic_archive_path == nullptr, "must be");
Arguments::no_shared_spaces("invalid archive");
}
}

if (_dynamic_archive_path != nullptr) {
if (_input_dynamic_archive_path != 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",
Expand Down Expand Up @@ -353,14 +368,22 @@ bool CDSConfig::has_unsupported_runtime_module_options() {
return false;
}

#define CHECK_ALIAS(f) check_flag_alias(FLAG_IS_DEFAULT(f), #f)
#define CHECK_NEW_FLAG(f) check_new_flag(FLAG_IS_DEFAULT(f), #f)

void CDSConfig::check_flag_alias(bool alias_is_default, const char* alias_name) {
if (old_cds_flags_used() && !alias_is_default) {
void CDSConfig::check_new_flag(bool new_flag_is_default, const char* new_flag_name) {
if (old_cds_flags_used() && !new_flag_is_default) {
vm_exit_during_initialization(err_msg("Option %s cannot be used at the same time with "
"-Xshare:on, -Xshare:auto, -Xshare:off, -Xshare:dump, "
"DumpLoadedClassList, SharedClassListFile, or SharedArchiveFile",
alias_name));
new_flag_name));
}
}

#define CHECK_SINGLE_PATH(f) check_flag_single_path(#f, f)

void CDSConfig::check_flag_single_path(const char* flag_name, const char* value) {
if (value != nullptr && num_archive_paths(value) != 1) {
vm_exit_during_initialization(err_msg("Option %s must specify a single file name", flag_name));
}
}

Expand All @@ -371,9 +394,13 @@ void CDSConfig::check_aot_flags() {
_old_cds_flags_used = true;
}

CHECK_ALIAS(AOTCache);
CHECK_ALIAS(AOTConfiguration);
CHECK_ALIAS(AOTMode);
// "New" AOT flags must not be mixed with "classic" flags such as -Xshare:dump
CHECK_NEW_FLAG(AOTCache);
CHECK_NEW_FLAG(AOTConfiguration);
CHECK_NEW_FLAG(AOTMode);

CHECK_SINGLE_PATH(AOTCache);
CHECK_SINGLE_PATH(AOTConfiguration);

if (FLAG_IS_DEFAULT(AOTCache) && FLAG_IS_DEFAULT(AOTConfiguration) && FLAG_IS_DEFAULT(AOTMode)) {
// AOTCache/AOTConfiguration/AOTMode not used.
Expand Down Expand Up @@ -411,11 +438,6 @@ void CDSConfig::check_aotmode_auto_or_on() {
vm_exit_during_initialization("AOTConfiguration can only be used with -XX:AOTMode=record or -XX:AOTMode=create");
}

if (!FLAG_IS_DEFAULT(AOTCache)) {
assert(FLAG_IS_DEFAULT(SharedArchiveFile), "already checked");
FLAG_SET_ERGO(SharedArchiveFile, AOTCache);
}

UseSharedSpaces = true;
if (FLAG_IS_DEFAULT(AOTMode) || (strcmp(AOTMode, "auto") == 0)) {
RequireSharedSpaces = false;
Expand All @@ -430,10 +452,6 @@ void CDSConfig::check_aotmode_record() {
vm_exit_during_initialization("AOTCache must not be specified when using -XX:AOTMode=record");
}

assert(FLAG_IS_DEFAULT(DumpLoadedClassList), "already checked");
assert(FLAG_IS_DEFAULT(SharedArchiveFile), "already checked");
FLAG_SET_ERGO(SharedArchiveFile, AOTConfiguration);
FLAG_SET_ERGO(DumpLoadedClassList, nullptr);
UseSharedSpaces = false;
RequireSharedSpaces = false;
_is_dumping_static_archive = true;
Expand All @@ -449,10 +467,7 @@ void CDSConfig::check_aotmode_create() {
vm_exit_during_initialization("AOTCache must be specified when using -XX:AOTMode=create");
}

assert(FLAG_IS_DEFAULT(SharedArchiveFile), "already checked");

_is_dumping_final_static_archive = true;
FLAG_SET_ERGO(SharedArchiveFile, AOTConfiguration);
UseSharedSpaces = true;
RequireSharedSpaces = true;

Expand All @@ -463,7 +478,29 @@ void CDSConfig::check_aotmode_create() {
CDSConfig::enable_dumping_static_archive();
}

void CDSConfig::ergo_init_aot_paths() {
assert(_cds_ergo_initialize_started, "sanity");
if (is_dumping_static_archive()) {
if (is_dumping_preimage_static_archive()) {
_output_archive_path = AOTConfiguration;
} else {
assert(is_dumping_final_static_archive(), "must be");
_input_static_archive_path = AOTConfiguration;
_output_archive_path = AOTCache;
}
} else if (is_using_archive()) {
if (FLAG_IS_DEFAULT(AOTCache)) {
// Only -XX:AOTMode={auto,on} is specified
_input_static_archive_path = default_archive_path();
} else {
_input_static_archive_path = AOTCache;
}
}
}

bool CDSConfig::check_vm_args_consistency(bool patch_mod_javabase, bool mode_flag_cmd_line) {
assert(!_cds_ergo_initialize_started, "This is called earlier than CDSConfig::ergo_initialize()");

check_aot_flags();

if (!FLAG_IS_DEFAULT(AOTMode)) {
Expand Down Expand Up @@ -514,7 +551,7 @@ bool CDSConfig::check_vm_args_consistency(bool patch_mod_javabase, bool mode_fla
if (ArchiveClassesAtExit == nullptr && !RecordDynamicDumpInfo) {
disable_dumping_dynamic_archive();
} else {
enable_dumping_dynamic_archive();
enable_dumping_dynamic_archive(ArchiveClassesAtExit);
}

if (AutoCreateSharedArchive) {
Expand Down Expand Up @@ -546,6 +583,34 @@ bool CDSConfig::check_vm_args_consistency(bool patch_mod_javabase, bool mode_fla
return true;
}

void CDSConfig::prepare_for_dumping() {
assert(CDSConfig::is_dumping_archive(), "sanity");

if (is_dumping_dynamic_archive() && !is_using_archive()) {
assert(!is_dumping_static_archive(), "cannot be dumping both static and dynamic archives");

// 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."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to start transitioning existing -Xlog:cds options to be :aot options? I think making the switch would match out long term direction

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but I think we should do it only if AOTClassLinking is enabled. For legacy CDS we should continue use -Xlog:cds.
I am using -Xlog:aot+codecache in AOT code caching.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created JDK-8354055 - Change "cds" logging tag to "aot". There are documentation/compatibility issues so we need to do some planning.

This particular block of code is moved from dynamicArchive.cpp to cdsConfig.cpp and I kept the logging tag the same.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @iklam. I agree with the approach of doing this in a separate issue.

if (RecordDynamicDumpInfo) {
log_error(cds)("-XX:+RecordDynamicDumpInfo%s", __THEMSG);
MetaspaceShared::unrecoverable_loading_error();
} else {
assert(ArchiveClassesAtExit != nullptr, "sanity");
log_warning(cds)("-XX:ArchiveClassesAtExit" __THEMSG);
}
#undef __THEMSG
disable_dumping_dynamic_archive();
return;
}

check_unsupported_dumping_module_options();
}

bool CDSConfig::is_dumping_classic_static_archive() {
return _is_dumping_static_archive &&
!is_dumping_preimage_static_archive() &&
Expand All @@ -560,6 +625,18 @@ bool CDSConfig::is_dumping_final_static_archive() {
return _is_dumping_final_static_archive;
}

void CDSConfig::enable_dumping_dynamic_archive(const char* output_path) {
_is_dumping_dynamic_archive = true;
if (output_path == nullptr) {
// output_path can be null when the VM is started with -XX:+RecordDynamicDumpInfo
// in anticipation of "jcmd VM.cds dynamic_dump", which will provide the actual
// output path.
_output_archive_path = nullptr;
} else {
_output_archive_path = os::strdup_check_oom(output_path, mtArguments);
}
}

bool CDSConfig::allow_only_single_java_thread() {
// See comments in JVM_StartThread()
return is_dumping_classic_static_archive() || is_dumping_final_static_archive();
Expand Down
Loading