Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8261455: Automatically generate the CDS archive if necessary #5997

Closed
wants to merge 8 commits into from
@@ -367,9 +367,10 @@ void DynamicArchive::prepare_for_dynamic_dumping() {
}
}

void DynamicArchive::dump(const char* archive_name, TRAPS) {
void DynamicArchive::dump(const char* archive_name, TRAPS) {
assert(UseSharedSpaces && RecordDynamicDumpInfo, "already checked in arguments.cpp?");
assert(ArchiveClassesAtExit == nullptr, "already checked in arguments.cpp?");
assert(!AutoCreateSharedArchive, "Should not call this function, instead call dump(TRAPS)");
ArchiveClassesAtExit = archive_name;
if (Arguments::init_shared_archive_paths()) {
prepare_for_dynamic_dumping();
@@ -173,9 +173,17 @@ FileMapInfo::FileMapInfo(bool is_static) {
if (_is_static) {
assert(_current_info == NULL, "must be singleton"); // not thread safe
_current_info = this;
_full_path = Arguments::GetSharedArchivePath();
} else {
assert(_dynamic_archive_info == NULL, "must be singleton"); // not thread safe
_dynamic_archive_info = this;
_full_path = Arguments::GetSharedDynamicArchivePath();
if (AutoCreateSharedArchive) {
if (!validate_archive()) {
// regenerate shared archive at exit
yminqi marked this conversation as resolved.
Show resolved Hide resolved
DynamicDumpSharedSpaces = true;
}
}
}
_file_offset = 0;
_file_open = false;
@@ -189,6 +197,22 @@ FileMapInfo::~FileMapInfo() {
assert(_dynamic_archive_info == this, "must be singleton"); // not thread safe
_dynamic_archive_info = NULL;
}
if (_file_open) {
os::close(_fd);
}
}

// Do preliminary validation on archive. More checks are in initialization.
bool FileMapInfo::validate_archive() {
if (!os::file_exists(_full_path)) {
return false;
}
// validate header info
if (!check_archive(_full_path, _is_static)) {
return false;
}

return true;
}

void FileMapInfo::populate_header(size_t core_region_alignment) {
@@ -1095,6 +1119,10 @@ class FileHeaderHelper {
FREE_C_HEAP_ARRAY(char, *target);
return false;
}
if (*(*target + name_size - 1) != '\0' || strlen(*target) != name_size - 1) {
log_info(cds)("Base archive name is damaged");
return false;
}
yminqi marked this conversation as resolved.
Show resolved Hide resolved
if (!os::file_exists(*target)) {
log_info(cds)("Base archive %s does not exist", *target);
FREE_C_HEAP_ARRAY(char, *target);
@@ -1126,7 +1154,9 @@ bool FileMapInfo::check_archive(const char* archive_name, bool is_static) {
}
} else {
if (header->_magic != CDS_DYNAMIC_ARCHIVE_MAGIC) {
vm_exit_during_initialization("Not a top shared archive", archive_name);
if (!AutoCreateSharedArchive) {
vm_exit_during_initialization("Not a top shared archive", archive_name);
}
return false;
}
unsigned int name_size = header->_base_archive_name_size;
@@ -2297,13 +2327,16 @@ bool FileMapInfo::initialize() {
return false;
}

if (!open_for_read()) {
return false;
}
if (!init_from_file(_fd)) {
return false;
}
if (!validate_header()) {
// AutoCreateSharedArchive
if (!open_for_read() || !init_from_file(_fd) || !validate_header()) {
if (_is_static) {
FileMapInfo::fail_continue("Initialize static archive failed.");
} else {
FileMapInfo::fail_continue("Initialize dynamic archive failed.");
if (AutoCreateSharedArchive) {
DynamicDumpSharedSpaces = true;
}
}
return false;
}
return true;
@@ -444,6 +444,7 @@ class FileMapInfo : public CHeapObj<mtInternal> {
static void assert_mark(bool check);

// File manipulation.
bool validate_archive() NOT_CDS_RETURN_(false);
bool initialize() NOT_CDS_RETURN_(false);
bool open_for_read();
void open_for_write(const char* path = NULL);
@@ -3130,6 +3130,17 @@ jint Arguments::finalize_vm_init_args(bool patch_mod_javabase) {
return JNI_ERR;
}

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

if (ArchiveClassesAtExit == NULL && !RecordDynamicDumpInfo) {
FLAG_SET_DEFAULT(DynamicDumpSharedSpaces, false);
} else {
@@ -3507,6 +3518,7 @@ bool Arguments::init_shared_archive_paths() {
SharedDynamicArchivePath = nullptr;
}
}

if (SharedArchiveFile == NULL) {
SharedArchivePath = get_default_shared_archive_path();
} else {
@@ -3524,6 +3536,7 @@ bool Arguments::init_shared_archive_paths() {
}
}
}

if (!is_dumping_archive()){
if (archives > 2) {
vm_exit_during_initialization(
@@ -3538,6 +3551,11 @@ bool Arguments::init_shared_archive_paths() {
} else {
SharedDynamicArchivePath = temp_archive_path;
}
// +AutoCreateSharedArchive, regenerate the dynamic archive base on default archive.
if (AutoCreateSharedArchive && !os::file_exists(SharedArchivePath)) {
SharedDynamicArchivePath = temp_archive_path;
SharedArchivePath = get_default_shared_archive_path();
}
} else {
extract_shared_archive_paths((const char*)SharedArchiveFile,
&SharedArchivePath, &SharedDynamicArchivePath);
@@ -1825,6 +1825,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") \
\
@@ -57,6 +57,7 @@
#include "oops/oop.inline.hpp"
#include "oops/symbol.hpp"
#include "prims/jvmtiExport.hpp"
#include "runtime/arguments.hpp"
yminqi marked this conversation as resolved.
Show resolved Hide resolved
#include "runtime/deoptimization.hpp"
#include "runtime/flags/flagSetting.hpp"
#include "runtime/handles.inline.hpp"
@@ -3268,7 +3268,7 @@ 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) {
if (DynamicDumpSharedSpaces && Arguments::GetSharedDynamicArchivePath() != nullptr) {
yminqi marked this conversation as resolved.
Show resolved Hide resolved
DynamicArchive::prepare_for_dynamic_dumping();
}
#endif
@@ -139,7 +139,8 @@ private static void doTest(String baseArchiveName, String topArchiveName) throws
runTwo(baseArchiveName, wrongBasePathOffset,
appJar, mainClass, 1,
new String[] {"An error has occurred while processing the shared archive file.",
"Header checksum verification failed",
"Base archive name is damaged",
"Error occurred during initialization of VM",
"Unable to use shared archive"});
// 5. Make base archive name not terminated with '\0'
System.out.println("\n5. Make base archive name not terminated with '\0'");
@@ -152,8 +153,8 @@ private static void doTest(String baseArchiveName, String topArchiveName) throws

runTwo(baseArchiveName, wrongBaseName,
appJar, mainClass, 1,
new String[] {"Base archive " + baseArchiveName,
" does not exist",
"Header checksum verification failed"});
new String[] {"Base archive name is damaged",
"Error occurred during initialization of VM",
"Unable to use shared archive"});
}
}
@@ -94,6 +94,19 @@ public static String getNewArchiveName(String stem) {
return TestCommon.getNewArchiveName(stem);
}

/**
* Excute a JVM to dump a base archive by
* -Xshare:dump -XX:SharedArchiveFile=baseArchiveName
*/
public static Result dumpBaseArchive(String baseArchiveName, String... cmdLineSuffix)
throws Exception
{
OutputAnalyzer output = TestCommon.dumpBaseArchive(baseArchiveName, cmdLineSuffix);
CDSOptions opts = new CDSOptions();
opts.setXShareMode("dump");
return new Result(opts, output);
}

/**
* Execute a JVM using the base archive (given by baseArchiveName) with the command line
* (given by cmdLineSuffix). At JVM exit, dump all eligible classes into the top archive