Skip to content

Commit

Permalink
8261455: Automatically generate the CDS archive if necessary
Browse files Browse the repository at this point in the history
Reviewed-by: iklam, ccheung
  • Loading branch information
yminqi committed Jan 13, 2022
1 parent d70545d commit 1228b2f
Show file tree
Hide file tree
Showing 13 changed files with 1,074 additions and 171 deletions.
4 changes: 2 additions & 2 deletions src/hotspot/share/cds/dynamicArchive.cpp
Expand Up @@ -187,7 +187,7 @@ class DynamicArchiveBuilder : public ArchiveBuilder {
};

void DynamicArchiveBuilder::init_header() {
FileMapInfo* mapinfo = new FileMapInfo(false);
FileMapInfo* mapinfo = new FileMapInfo(_archive_name, false);
assert(FileMapInfo::dynamic_info() == mapinfo, "must be");
FileMapInfo* base_info = FileMapInfo::current_info();
// header only be available after populate_header
Expand Down Expand Up @@ -327,7 +327,7 @@ void DynamicArchiveBuilder::write_archive(char* serialized_data) {
FileMapInfo* dynamic_info = FileMapInfo::dynamic_info();
assert(dynamic_info != NULL, "Sanity");

dynamic_info->open_for_write(_archive_name);
dynamic_info->open_for_write();
ArchiveBuilder::write_archive(dynamic_info, NULL, NULL, NULL, NULL);

address base = _requested_dynamic_archive_bottom;
Expand Down
115 changes: 56 additions & 59 deletions src/hotspot/share/cds/filemap.cpp
Expand Up @@ -166,8 +166,9 @@ template <int N> static void get_header_version(char (&header_version) [N]) {
assert(header_version[JVM_IDENT_MAX-1] == 0, "must be");
}

FileMapInfo::FileMapInfo(bool is_static) {
FileMapInfo::FileMapInfo(const char* full_path, bool is_static) {
memset((void*)this, 0, sizeof(FileMapInfo));
_full_path = full_path;
_is_static = is_static;
if (_is_static) {
assert(_current_info == NULL, "must be singleton"); // not thread safe
Expand All @@ -188,6 +189,9 @@ FileMapInfo::~FileMapInfo() {
assert(_dynamic_archive_info == this, "must be singleton"); // not thread safe
_dynamic_archive_info = NULL;
}
if (_file_open) {
os::close(_fd);
}
}

void FileMapInfo::populate_header(size_t core_region_alignment) {
Expand Down Expand Up @@ -1049,33 +1053,41 @@ void FileMapInfo::validate_non_existent_class_paths() {
class FileHeaderHelper {
int _fd;
bool _is_valid;
bool _is_static;
GenericCDSFileMapHeader* _header;
const char* _archive_name;
const char* _base_archive_name;

public:
FileHeaderHelper() : _fd(-1), _is_valid(false), _header(nullptr), _base_archive_name(nullptr) {}
FileHeaderHelper(const char* archive_name, bool is_static) {
_fd = -1;
_is_valid = false;
_header = nullptr;
_base_archive_name = nullptr;
_archive_name = archive_name;
_is_static = is_static;
}

~FileHeaderHelper() {
if (_fd != -1) {
os::close(_fd);
}
}

bool initialize(const char* archive_name) {
log_info(cds)("Opening shared archive: %s", archive_name);
_fd = os::open(archive_name, O_RDONLY | O_BINARY, 0);
bool initialize() {
assert(_archive_name != nullptr, "Archive name is NULL");
_fd = os::open(_archive_name, O_RDONLY | O_BINARY, 0);
if (_fd < 0) {
FileMapInfo::fail_continue("Specified shared archive not found (%s)", archive_name);
FileMapInfo::fail_continue("Specified shared archive not found (%s)", _archive_name);
return false;
}
return initialize(_fd);
}

// for an already opened file, do not set _fd
bool initialize(int fd) {
assert(fd != -1, "Archive should be opened");


assert(_archive_name != nullptr, "Archive name is NULL");
assert(fd != -1, "Archive must be opened already");
// First read the generic header so we know the exact size of the actual header.
GenericCDSFileMapHeader gen_header;
size_t size = sizeof(GenericCDSFileMapHeader);
Expand All @@ -1098,6 +1110,11 @@ class FileHeaderHelper {
return false;
}

if (gen_header._version != CURRENT_CDS_ARCHIVE_VERSION) {
FileMapInfo::fail_continue("The shared archive file version %d does not match the required version %d",
gen_header._version, CURRENT_CDS_ARCHIVE_VERSION);
}

size_t filelen = os::lseek(fd, 0, SEEK_END);
if (gen_header._header_size >= filelen) {
FileMapInfo::fail_continue("Archive file header larger than archive file");
Expand Down Expand Up @@ -1203,28 +1220,6 @@ class FileHeaderHelper {
}
};

bool FileMapInfo::check_archive(const char* archive_name, bool is_static) {
FileHeaderHelper file_helper;
if (!file_helper.initialize(archive_name)) {
// Any errors are reported by fail_continue().
return false;
}

GenericCDSFileMapHeader* header = file_helper.get_generic_file_header();
if (is_static) {
if (header->_magic != CDS_ARCHIVE_MAGIC) {
fail_continue("Not a base shared archive: %s", archive_name);
return false;
}
} else {
if (header->_magic != CDS_DYNAMIC_ARCHIVE_MAGIC) {
fail_continue("Not a top shared archive: %s", archive_name);
return false;
}
}
return true;
}

// Return value:
// false:
// <archive_name> is not a valid archive. *base_archive_name is set to null.
Expand All @@ -1234,15 +1229,18 @@ bool FileMapInfo::check_archive(const char* archive_name, bool is_static) {
// <archive_name> is a valid dynamic archive.
bool FileMapInfo::get_base_archive_name_from_header(const char* archive_name,
char** base_archive_name) {
FileHeaderHelper file_helper;
FileHeaderHelper file_helper(archive_name, false);
*base_archive_name = NULL;

if (!file_helper.initialize(archive_name)) {
if (!file_helper.initialize()) {
return false;
}
GenericCDSFileMapHeader* header = file_helper.get_generic_file_header();
if (header->_magic != CDS_DYNAMIC_ARCHIVE_MAGIC) {
assert(header->_magic == CDS_ARCHIVE_MAGIC, "must be");
if (AutoCreateSharedArchive) {
log_warning(cds)("AutoCreateSharedArchive is ignored because %s is a static archive", archive_name);
}
return true;
}

Expand All @@ -1259,19 +1257,23 @@ bool FileMapInfo::get_base_archive_name_from_header(const char* archive_name,
// Read the FileMapInfo information from the file.

bool FileMapInfo::init_from_file(int fd) {
FileHeaderHelper file_helper;
FileHeaderHelper file_helper(_full_path, _is_static);
if (!file_helper.initialize(fd)) {
fail_continue("Unable to read the file header.");
return false;
}
GenericCDSFileMapHeader* gen_header = file_helper.get_generic_file_header();

unsigned int expected_magic = is_static() ? CDS_ARCHIVE_MAGIC : CDS_DYNAMIC_ARCHIVE_MAGIC;
if (gen_header->_magic != expected_magic) {
log_info(cds)("_magic expected: 0x%08x", expected_magic);
log_info(cds)(" actual: 0x%08x", gen_header->_magic);
FileMapInfo::fail_continue("The shared archive file has a bad magic number.");
return false;
if (_is_static) {
if (gen_header->_magic != CDS_ARCHIVE_MAGIC) {
FileMapInfo::fail_continue("Not a base shared archive: %s", _full_path);
return false;
}
} else {
if (gen_header->_magic != CDS_DYNAMIC_ARCHIVE_MAGIC) {
FileMapInfo::fail_continue("Not a top shared archive: %s", _full_path);
return false;
}
}

_header = (FileMapHeader*)os::malloc(gen_header->_header_size, mtInternal);
Expand Down Expand Up @@ -1348,11 +1350,6 @@ bool FileMapInfo::open_for_read() {
if (_file_open) {
return true;
}
if (is_static()) {
_full_path = Arguments::GetSharedArchivePath();
} else {
_full_path = Arguments::GetSharedDynamicArchivePath();
}
log_info(cds)("trying to map %s", _full_path);
int fd = os::open(_full_path, O_RDONLY | O_BINARY, 0);
if (fd < 0) {
Expand All @@ -1374,12 +1371,7 @@ bool FileMapInfo::open_for_read() {

// Write the FileMapInfo information to the file.

void FileMapInfo::open_for_write(const char* path) {
if (path == NULL) {
_full_path = Arguments::GetSharedArchivePath();
} else {
_full_path = path;
}
void FileMapInfo::open_for_write() {
LogMessage(cds) msg;
if (msg.is_info()) {
msg.info("Dumping shared data to file: ");
Expand Down Expand Up @@ -2364,15 +2356,20 @@ bool FileMapInfo::initialize() {
return false;
}

if (!open_for_read()) {
return false;
}
if (!init_from_file(_fd)) {
return false;
}
if (!validate_header()) {
return false;
if (!open_for_read() || !init_from_file(_fd) || !validate_header()) {
if (_is_static) {
FileMapInfo::fail_continue("Initialize static archive failed.");
return false;
} else {
FileMapInfo::fail_continue("Initialize dynamic archive failed.");
if (AutoCreateSharedArchive) {
DynamicDumpSharedSpaces = true;
ArchiveClassesAtExit = Arguments::GetSharedDynamicArchivePath();
}
return false;
}
}

return true;
}

Expand Down
5 changes: 2 additions & 3 deletions src/hotspot/share/cds/filemap.hpp
Expand Up @@ -356,7 +356,6 @@ class FileMapInfo : public CHeapObj<mtInternal> {
public:
static bool get_base_archive_name_from_header(const char* archive_name,
char** base_archive_name);
static bool check_archive(const char* archive_name, bool is_static);
static SharedPathTable shared_path_table() {
return _shared_path_table;
}
Expand All @@ -370,7 +369,7 @@ class FileMapInfo : public CHeapObj<mtInternal> {

void log_paths(const char* msg, int start_idx, int end_idx);

FileMapInfo(bool is_static);
FileMapInfo(const char* full_apth, bool is_static);
~FileMapInfo();

// Accessors
Expand Down Expand Up @@ -441,7 +440,7 @@ class FileMapInfo : public CHeapObj<mtInternal> {
// File manipulation.
bool initialize() NOT_CDS_RETURN_(false);
bool open_for_read();
void open_for_write(const char* path = NULL);
void open_for_write();
void write_header();
void write_region(int region, char* base, size_t size,
bool read_only, bool allow_exec);
Expand Down
18 changes: 14 additions & 4 deletions src/hotspot/share/cds/metaspaceShared.cpp
Expand Up @@ -556,7 +556,9 @@ void VM_PopulateDumpSharedSpace::doit() {
builder.relocate_to_requested();

// Write the archive file
FileMapInfo* mapinfo = new FileMapInfo(true);
const char* static_archive = Arguments::GetSharedArchivePath();
assert(static_archive != nullptr, "SharedArchiveFile not set?");
FileMapInfo* mapinfo = new FileMapInfo(static_archive, true);
mapinfo->populate_header(MetaspaceShared::core_region_alignment());
mapinfo->set_serialized_data(serialized_data);
mapinfo->set_cloned_vtables(cloned_vtables);
Expand Down Expand Up @@ -946,12 +948,17 @@ void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() {
_requested_base_address = static_mapinfo->requested_base_address();
if (dynamic_mapped) {
FileMapInfo::set_shared_path_table(dynamic_mapinfo);
// turn AutoCreateSharedArchive off if successfully mapped
AutoCreateSharedArchive = false;
} else {
FileMapInfo::set_shared_path_table(static_mapinfo);
}
} else {
set_shared_metaspace_range(NULL, NULL, NULL);
UseSharedSpaces = false;
// The base archive cannot be mapped. We cannot dump the dynamic shared archive.
AutoCreateSharedArchive = false;
DynamicDumpSharedSpaces = false;
FileMapInfo::fail_continue("Unable to map shared spaces");
if (PrintSharedArchiveAndExit) {
vm_exit_during_initialization("Unable to use shared archive.");
Expand All @@ -967,7 +974,9 @@ void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() {
}

FileMapInfo* MetaspaceShared::open_static_archive() {
FileMapInfo* mapinfo = new FileMapInfo(true);
const char* static_archive = Arguments::GetSharedArchivePath();
assert(static_archive != nullptr, "SharedArchivePath is NULL");
FileMapInfo* mapinfo = new FileMapInfo(static_archive, true);
if (!mapinfo->initialize()) {
delete(mapinfo);
return NULL;
Expand All @@ -979,11 +988,12 @@ FileMapInfo* MetaspaceShared::open_dynamic_archive() {
if (DynamicDumpSharedSpaces) {
return NULL;
}
if (Arguments::GetSharedDynamicArchivePath() == NULL) {
const char* dynamic_archive = Arguments::GetSharedDynamicArchivePath();
if (dynamic_archive == nullptr) {
return NULL;
}

FileMapInfo* mapinfo = new FileMapInfo(false);
FileMapInfo* mapinfo = new FileMapInfo(dynamic_archive, false);
if (!mapinfo->initialize()) {
delete(mapinfo);
return NULL;
Expand Down
28 changes: 21 additions & 7 deletions src/hotspot/share/runtime/arguments.cpp
Expand Up @@ -3140,6 +3140,17 @@ jint Arguments::finalize_vm_init_args(bool patch_mod_javabase) {
DynamicDumpSharedSpaces = true;
}

if (AutoCreateSharedArchive) {
if (SharedArchiveFile == NULL) {
log_warning(cds)("-XX:+AutoCreateSharedArchive requires -XX:SharedArchiveFile");
return JNI_ERR;
}
if (ArchiveClassesAtExit != NULL) {
log_warning(cds)("-XX:+AutoCreateSharedArchive does not work with ArchiveClassesAtExit");
return JNI_ERR;
}
}

if (UseSharedSpaces && patch_mod_javabase) {
no_shared_spaces("CDS is disabled when " JAVA_BASE_NAME " module is patched.");
}
Expand Down Expand Up @@ -3487,9 +3498,6 @@ void Arguments::extract_shared_archive_paths(const char* archive_path,
char* cur_path = NEW_C_HEAP_ARRAY(char, len + 1, mtInternal);
strncpy(cur_path, begin_ptr, len);
cur_path[len] = '\0';
if (!FileMapInfo::check_archive((const char*)cur_path, true /*is_static*/)) {
return;
}
*base_archive_path = cur_path;

begin_ptr = ++end_ptr;
Expand All @@ -3501,9 +3509,6 @@ 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);
if (!FileMapInfo::check_archive((const char*)cur_path, false /*is_static*/)) {
return;
}
*top_archive_path = cur_path;
}

Expand Down Expand Up @@ -3556,7 +3561,16 @@ void Arguments::init_shared_archive_paths() {
bool success =
FileMapInfo::get_base_archive_name_from_header(SharedArchiveFile, &base_archive_path);
if (!success) {
no_shared_spaces("invalid archive");
// If +AutoCreateSharedArchive and the specified shared archive does not exist,
// regenerate the dynamic archive base on default archive.
if (AutoCreateSharedArchive && !os::file_exists(SharedArchiveFile)) {
DynamicDumpSharedSpaces = true;
ArchiveClassesAtExit = const_cast<char *>(SharedArchiveFile);
SharedArchivePath = get_default_shared_archive_path();
SharedArchiveFile = nullptr;
} else {
no_shared_spaces("invalid archive");
}
} else if (base_archive_path == NULL) {
// User has specified a single archive, which is a static archive.
SharedArchivePath = const_cast<char *>(SharedArchiveFile);
Expand Down
5 changes: 4 additions & 1 deletion src/hotspot/share/runtime/globals.hpp
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2022, 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
Expand Down Expand Up @@ -1802,6 +1802,9 @@ const intx ObjectAlignmentInBytes = 8;
product(bool, RecordDynamicDumpInfo, false, \
"Record class info for jcmd VM.cds dynamic_dump") \
\
product(bool, AutoCreateSharedArchive, false, \
"Create shared archive at exit if cds mapping failed") \
\
product(bool, PrintSharedArchiveAndExit, false, \
"Print shared archive file contents") \
\
Expand Down

1 comment on commit 1228b2f

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

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

Please sign in to comment.