8261455: Automatically generate the CDS archive if necessary
Reviewed-by: iklam, ccheung
This commit is contained in:
parent
d70545d710
commit
1228b2f1f8
@ -187,7 +187,7 @@ public:
|
||||
};
|
||||
|
||||
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
|
||||
@ -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;
|
||||
|
@ -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
|
||||
@ -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) {
|
||||
@ -1049,11 +1053,20 @@ 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) {
|
||||
@ -1061,11 +1074,11 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
@ -1073,9 +1086,8 @@ public:
|
||||
|
||||
// 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);
|
||||
@ -1098,6 +1110,11 @@ public:
|
||||
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");
|
||||
@ -1203,28 +1220,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
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.
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
@ -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) {
|
||||
@ -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: ");
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
@ -356,7 +356,6 @@ private:
|
||||
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;
|
||||
}
|
||||
@ -370,7 +369,7 @@ public:
|
||||
|
||||
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
|
||||
@ -441,7 +440,7 @@ public:
|
||||
// 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);
|
||||
|
@ -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);
|
||||
@ -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.");
|
||||
@ -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;
|
||||
@ -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;
|
||||
|
@ -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.");
|
||||
}
|
||||
@ -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;
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
@ -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
|
||||
@ -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") \
|
||||
\
|
||||
|
@ -47,37 +47,39 @@ public class MoveJDKTest {
|
||||
public static void main(String[] args) throws Exception {
|
||||
String java_home_src = System.getProperty("java.home");
|
||||
String java_home_dst = CDSTestUtils.getOutputDir() + File.separator + "moved_jdk";
|
||||
String homeJava = java_home_src + File.separator + "bin" + File.separator + "java";
|
||||
String dstJava = java_home_dst + File.separator + "bin" + File.separator + "java";
|
||||
|
||||
TestCommon.startNewArchiveName();
|
||||
String jsaFile = TestCommon.getCurrentArchiveName();
|
||||
String jsaOpt = "-XX:SharedArchiveFile=" + jsaFile;
|
||||
{
|
||||
ProcessBuilder pb = makeBuilder(java_home_src + "/bin/java", "-Xshare:dump", jsaOpt);
|
||||
ProcessBuilder pb = CDSTestUtils.makeBuilder(homeJava, "-Xshare:dump", jsaOpt);
|
||||
TestCommon.executeAndLog(pb, "dump")
|
||||
.shouldHaveExitValue(0);
|
||||
}
|
||||
{
|
||||
ProcessBuilder pb = makeBuilder(java_home_src + "/bin/java",
|
||||
"-Xshare:auto",
|
||||
jsaOpt,
|
||||
"-Xlog:class+path=info",
|
||||
"-version");
|
||||
ProcessBuilder pb = CDSTestUtils.makeBuilder(homeJava,
|
||||
"-Xshare:auto",
|
||||
jsaOpt,
|
||||
"-Xlog:class+path=info",
|
||||
"-version");
|
||||
OutputAnalyzer out = TestCommon.executeAndLog(pb, "exec-src");
|
||||
out.shouldHaveExitValue(0);
|
||||
out.shouldNotContain("shared class paths mismatch");
|
||||
out.shouldNotContain("BOOT classpath mismatch");
|
||||
}
|
||||
|
||||
clone(new File(java_home_src), new File(java_home_dst));
|
||||
CDSTestUtils.clone(new File(java_home_src), new File(java_home_dst));
|
||||
System.out.println("============== Cloned JDK at " + java_home_dst);
|
||||
|
||||
// Test runtime with cloned JDK
|
||||
{
|
||||
ProcessBuilder pb = makeBuilder(java_home_dst + "/bin/java",
|
||||
"-Xshare:auto",
|
||||
jsaOpt,
|
||||
"-Xlog:class+path=info",
|
||||
"-version");
|
||||
ProcessBuilder pb = CDSTestUtils.makeBuilder(dstJava,
|
||||
"-Xshare:auto",
|
||||
jsaOpt,
|
||||
"-Xlog:class+path=info",
|
||||
"-version");
|
||||
OutputAnalyzer out = TestCommon.executeAndLog(pb, "exec-dst");
|
||||
out.shouldHaveExitValue(0);
|
||||
out.shouldNotContain("shared class paths mismatch");
|
||||
@ -89,21 +91,21 @@ public class MoveJDKTest {
|
||||
String fake_modules = copyFakeModulesFromHelloJar();
|
||||
String dumptimeBootAppendOpt = "-Xbootclasspath/a:" + fake_modules;
|
||||
{
|
||||
ProcessBuilder pb = makeBuilder(java_home_src + "/bin/java",
|
||||
"-Xshare:dump",
|
||||
dumptimeBootAppendOpt,
|
||||
jsaOpt);
|
||||
ProcessBuilder pb = CDSTestUtils.makeBuilder(homeJava,
|
||||
"-Xshare:dump",
|
||||
dumptimeBootAppendOpt,
|
||||
jsaOpt);
|
||||
TestCommon.executeAndLog(pb, "dump")
|
||||
.shouldHaveExitValue(0);
|
||||
}
|
||||
{
|
||||
String runtimeBootAppendOpt = dumptimeBootAppendOpt + System.getProperty("path.separator") + helloJar;
|
||||
ProcessBuilder pb = makeBuilder(java_home_dst + "/bin/java",
|
||||
"-Xshare:auto",
|
||||
runtimeBootAppendOpt,
|
||||
jsaOpt,
|
||||
"-Xlog:class+path=info",
|
||||
"-version");
|
||||
ProcessBuilder pb = CDSTestUtils.makeBuilder(dstJava,
|
||||
"-Xshare:auto",
|
||||
runtimeBootAppendOpt,
|
||||
jsaOpt,
|
||||
"-Xlog:class+path=info",
|
||||
"-version");
|
||||
OutputAnalyzer out = TestCommon.executeAndLog(pb, "exec-dst");
|
||||
out.shouldHaveExitValue(0);
|
||||
out.shouldNotContain("shared class paths mismatch");
|
||||
@ -111,78 +113,17 @@ public class MoveJDKTest {
|
||||
}
|
||||
|
||||
// Test with no modules image in the <java home>/lib directory
|
||||
renameModulesFile(java_home_dst);
|
||||
String locDir = java_home_dst + File.separator + "lib";
|
||||
CDSTestUtils.rename(new File(locDir + File.separator + "modules"),
|
||||
new File(locDir + File.separator + "orig-modules"));
|
||||
{
|
||||
ProcessBuilder pb = makeBuilder(java_home_dst + "/bin/java",
|
||||
"-version");
|
||||
ProcessBuilder pb = CDSTestUtils.makeBuilder(dstJava, "-version");
|
||||
OutputAnalyzer out = TestCommon.executeAndLog(pb, "exec-missing-modules");
|
||||
out.shouldHaveExitValue(1);
|
||||
out.shouldContain("Failed setting boot class path.");
|
||||
}
|
||||
}
|
||||
|
||||
// Do a cheap clone of the JDK. Most files can be sym-linked. However, $JAVA_HOME/bin/java and $JAVA_HOME/lib/.../libjvm.so"
|
||||
// must be copied, because the java.home property is derived from the canonicalized paths of these 2 files.
|
||||
static void clone(File src, File dst) throws Exception {
|
||||
if (dst.exists()) {
|
||||
if (!dst.isDirectory()) {
|
||||
throw new RuntimeException("Not a directory :" + dst);
|
||||
}
|
||||
} else {
|
||||
if (!dst.mkdir()) {
|
||||
throw new RuntimeException("Cannot create directory: " + dst);
|
||||
}
|
||||
}
|
||||
final String jvmLib = System.mapLibraryName("jvm");
|
||||
for (String child : src.list()) {
|
||||
if (child.equals(".") || child.equals("..")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
File child_src = new File(src, child);
|
||||
File child_dst = new File(dst, child);
|
||||
if (child_dst.exists()) {
|
||||
throw new RuntimeException("Already exists: " + child_dst);
|
||||
}
|
||||
if (child_src.isFile()) {
|
||||
if (child.equals(jvmLib) || child.equals("java")) {
|
||||
Files.copy(child_src.toPath(), /* copy data to -> */ child_dst.toPath());
|
||||
} else {
|
||||
Files.createSymbolicLink(child_dst.toPath(), /* link to -> */ child_src.toPath());
|
||||
}
|
||||
} else {
|
||||
clone(child_src, child_dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void renameModulesFile(String javaHome) throws Exception {
|
||||
String modulesDir = javaHome + File.separator + "lib";
|
||||
File origModules = new File(modulesDir, "modules");
|
||||
if (!origModules.exists()) {
|
||||
throw new RuntimeException("modules file not found");
|
||||
}
|
||||
|
||||
File renamedModules = new File(modulesDir, "orig_modules");
|
||||
if (renamedModules.exists()) {
|
||||
throw new RuntimeException("found orig_modules unexpectedly");
|
||||
}
|
||||
|
||||
boolean success = origModules.renameTo(renamedModules);
|
||||
if (!success) {
|
||||
throw new RuntimeException("rename modules file failed");
|
||||
}
|
||||
}
|
||||
|
||||
static ProcessBuilder makeBuilder(String... args) throws Exception {
|
||||
System.out.print("[");
|
||||
for (String s : args) {
|
||||
System.out.print(" " + s);
|
||||
}
|
||||
System.out.println(" ]");
|
||||
return new ProcessBuilder(args);
|
||||
}
|
||||
|
||||
private static String copyFakeModulesFromHelloJar() throws Exception {
|
||||
String outDir = CDSTestUtils.getOutputDir();
|
||||
String newFile = "hello.modules";
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 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
|
||||
@ -181,9 +181,7 @@ public class SharedArchiveConsistency {
|
||||
copiedJsa = CDSArchiveUtils.copyArchiveFile(orgJsaFile, modVersion);
|
||||
CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetVersion(), version);
|
||||
output = shareAuto ? TestCommon.execAuto(execArgs) : TestCommon.execCommon(execArgs);
|
||||
output.shouldContain("The shared archive file has the wrong version")
|
||||
.shouldContain("_version expected: " + currentCDSArchiveVersion)
|
||||
.shouldContain("actual: " + version);
|
||||
output.shouldContain("The shared archive file version " + version + " does not match the required version " + currentCDSArchiveVersion);
|
||||
if (shareAuto) {
|
||||
output.shouldContain(HELLO_WORLD);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 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
|
||||
@ -37,7 +37,6 @@ import sun.hotspot.WhiteBox;
|
||||
class DynamicArchiveTestBase {
|
||||
private static boolean executedIn_run = false;
|
||||
private static boolean autoMode = false; // -Xshare:auto
|
||||
|
||||
private static final WhiteBox WB = WhiteBox.getWhiteBox();
|
||||
|
||||
public static interface DynamicArchiveTest {
|
||||
@ -96,6 +95,19 @@ class DynamicArchiveTestBase {
|
||||
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
|
||||
|
@ -0,0 +1,693 @@
|
||||
/*
|
||||
* Copyright (c) 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8261455
|
||||
* @summary test -XX:+AutoCreateSharedArchive feature
|
||||
* @requires vm.cds
|
||||
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds /test/hotspot/jtreg/runtime/cds/appcds/test-classes
|
||||
* @build Hello
|
||||
* @build sun.hotspot.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar hello.jar Hello
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox
|
||||
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:./WhiteBox.jar TestAutoCreateSharedArchive verifySharedSpacesOff
|
||||
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:./WhiteBox.jar TestAutoCreateSharedArchive verifySharedSpacesOn
|
||||
*/
|
||||
|
||||
/*
|
||||
* -XX:SharedArchiveFile can be specified in two styles:
|
||||
*
|
||||
* (A) Test with default base archive -XX:+SharedArchiveFile=<archive>
|
||||
* (B) Test with the base archive specified: -XX:SharedArchiveFile=<base>:<top>
|
||||
* all the following if not explained explicitly, run with flag -XX:+AutoCreateSharedArchive
|
||||
*
|
||||
* Note VerifySharedSpaces will affect output so the tests run twice: one with -XX:+VerifySharedSpaces and the other with -XX:-VerifySharedSpaces
|
||||
*
|
||||
* 10 Case (A)
|
||||
*
|
||||
* 10.01 run with non-existing archive should automatically create dynamic archive.
|
||||
* If the JDK's default CDS archive cannot be loaded, print out warning, run continue without shared archive and no shared archive created at exit.
|
||||
* 10.02 run with the created dynamic archive should pass.
|
||||
* 10.03 run with the created dynamic archive and -XX:+AutoCreateSharedArchive should pass and no shared archive created at exit.
|
||||
*
|
||||
* 11 run with static archive.
|
||||
* run with static archive should printout warning and continue, share or no share depends on the archive validation at exit,
|
||||
* no shared archive (top) will be generated.
|
||||
*
|
||||
* 12 run with damaged magic should not regenerate dynamic archive.
|
||||
* if magic is not expected, no shared archive will be regenerated at exit.
|
||||
*
|
||||
* 13 run with a bad versioned archive.
|
||||
* 13.01 run with a bad versioned (< CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION) archive should not create dynamic archive at exit.
|
||||
* 13.02 run with a bad versioned (> CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION) archive should create dynamic archive at exit.
|
||||
*
|
||||
* 14 run with an archive whose base name is not matched, no shared archive at exit.
|
||||
*
|
||||
* 15 run with an archive whose jvm_ident is corrupted should
|
||||
* create dynamic archive at exit with -XX:-VerifySharedSpaces
|
||||
* not create dynamic archive at exit with -XX:+VerifySharedSpaces
|
||||
*
|
||||
* 16 run with an archive only containing magic in the file (size of 4 bytes)
|
||||
* the archive will be created at exit.
|
||||
*
|
||||
* 20 (case B)
|
||||
*
|
||||
* 20.01 dump base archive which will be used for dumping top archive.
|
||||
* 20.02 dump top archive based on base archive obtained in 20.1.
|
||||
* 20.03 run -XX:SharedArchiveFile=<base>:<top> to verify the archives.
|
||||
* 20.04 run with -XX:SharedArchveFile=base:top (reversed)
|
||||
*
|
||||
* 21 Mismatched versions
|
||||
* 21.01 if version of top archive is higher than CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION, the archive cannot be shared and will be
|
||||
* regenerated at exit.
|
||||
* 21.02 if version of top archive is lower than CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION, the archive cannot be shared and will be
|
||||
* created at exit.
|
||||
*
|
||||
* 22 create an archive with dynamic magic number only
|
||||
* archive will be created at exit if base can be shared.
|
||||
*
|
||||
* 23 mismatched jvm_indent in base/top archive
|
||||
* 23.01 mismatched jvm_indent in top archive
|
||||
* 23.02 mismatched jvm_indent in base archive
|
||||
*
|
||||
* 24 run with non-existing shared archives
|
||||
* 24.01 run -Xshare:auto -XX:+AutoCreateSharedArchive -XX:SharedArchiveFile=base.jsa:non-exist-top.jsa
|
||||
* The top archive will be regenerated.
|
||||
* 24.02 run -Xshare:auto -XX:+AutoCreateSharedArchive -XX:SharedArchiveFile=non-exist-base.jsa:top.jsa
|
||||
* top archive will not be shared if base archive failed to load.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.File;
|
||||
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import jdk.test.lib.cds.CDSTestUtils;
|
||||
import jdk.test.lib.cds.CDSArchiveUtils;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.helpers.ClassFileInstaller;
|
||||
|
||||
public class TestAutoCreateSharedArchive extends DynamicArchiveTestBase {
|
||||
private static final String BASE_NAME = CDSTestUtils.getOutputFileName("base.jsa");
|
||||
private static final String TOP_NAME = CDSTestUtils.getOutputFileName("top.jsa");
|
||||
private static final String mainAppClass = "Hello";
|
||||
private static final String HELLO_SOURCE = "Hello source: shared objects file (top)";
|
||||
private static final String HELLO_WORLD = "Hello World";
|
||||
private static boolean verifyOn = false;
|
||||
|
||||
private static int genericHeaderMinVersion = CDSArchiveUtils.getGenericHeaderMinVersion();
|
||||
private static int currentCDSVersion = CDSArchiveUtils.getCurrentCDSArchiveVersion();
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length != 1 || (!args[0].equals("verifySharedSpacesOff") && !args[0].equals("verifySharedSpacesOn"))) {
|
||||
throw new RuntimeException("Must run with verifySharedSpacesOff or verifySharedSpacesOn");
|
||||
}
|
||||
verifyOn = args[0].equals("verifySharedSpacesOn");
|
||||
runTest(TestAutoCreateSharedArchive::testAutoCreateSharedArchive);
|
||||
}
|
||||
|
||||
public static void checkFileExists(String fileName) throws Exception {
|
||||
File file = new File(fileName);
|
||||
if (!file.exists()) {
|
||||
throw new IOException("Archive " + fileName + " is not automatically created");
|
||||
}
|
||||
}
|
||||
|
||||
public static String startNewArchive(String testName) {
|
||||
String newArchiveName = TestCommon.getNewArchiveName(testName);
|
||||
TestCommon.setCurrentArchiveName(newArchiveName);
|
||||
return newArchiveName;
|
||||
}
|
||||
|
||||
public static void print(String message) {
|
||||
System.out.println(message);
|
||||
}
|
||||
|
||||
private static void testAutoCreateSharedArchive() throws Exception {
|
||||
String appJar = ClassFileInstaller.getJarPath("hello.jar");
|
||||
boolean fileModified = false;
|
||||
|
||||
String verifySharedSpaces = verifyOn ? "-XX:+VerifySharedSpaces" : "-XX:-VerifySharedSpaces";
|
||||
File archiveFile = new File(TOP_NAME);
|
||||
if (archiveFile.exists()) {
|
||||
archiveFile.delete();
|
||||
}
|
||||
|
||||
// dump a static archive, used later.
|
||||
// 0. Dump a static archive
|
||||
print("0. dump a static archive " + BASE_NAME);
|
||||
dumpBaseArchive(BASE_NAME,
|
||||
"-Xlog:cds",
|
||||
"-cp", appJar,
|
||||
mainAppClass)
|
||||
.assertNormalExit(output -> {
|
||||
output.shouldHaveExitValue(0);
|
||||
});
|
||||
checkFileExists(BASE_NAME);
|
||||
|
||||
// The list numbers try to match JDK-8272331 (CSR for JDK-8261455) test items but not exactly matched.
|
||||
|
||||
// 10 non-existing archive should automatically create dynamic archive based on default shared archive
|
||||
// if base archive loaded.
|
||||
print("10 Test with default base shared archive");
|
||||
print(" 10.01 run with non-existing archive should automatically create dynamic archive");
|
||||
File fileTop = new File(TOP_NAME);
|
||||
if (fileTop.exists()) {
|
||||
fileTop.delete();
|
||||
}
|
||||
run(TOP_NAME,
|
||||
"-Xshare:auto",
|
||||
"-XX:+AutoCreateSharedArchive",
|
||||
"-Xlog:cds",
|
||||
"-cp", appJar,
|
||||
mainAppClass)
|
||||
.assertNormalExit(output -> {
|
||||
output.shouldHaveExitValue(0)
|
||||
.shouldContain(HELLO_WORLD)
|
||||
.shouldContain("Dumping shared data to file:")
|
||||
.shouldContain(TOP_NAME);
|
||||
});
|
||||
checkFileExists(TOP_NAME);
|
||||
|
||||
//10.02 run with the created dynamic archive should pass
|
||||
print(" 10.02 run with the created dynamic archive should pass");
|
||||
run(TOP_NAME,
|
||||
"-Xlog:cds",
|
||||
"-Xlog:class+load",
|
||||
"-cp", appJar,
|
||||
mainAppClass)
|
||||
.assertNormalExit(output -> {
|
||||
output.shouldHaveExitValue(0)
|
||||
.shouldContain(HELLO_WORLD)
|
||||
.shouldContain(HELLO_SOURCE);
|
||||
});
|
||||
// remember the FileTime
|
||||
FileTime ft1 = Files.getLastModifiedTime(Paths.get(TOP_NAME));
|
||||
|
||||
// 10.03 run with the created dynamic archive with -XX:+AutoCreateSharedArchive should pass
|
||||
// archive should not be created again.
|
||||
print(" 10.03 run with the created dynamic archive with -XX:+AutoCreateSharedArchive should pass");
|
||||
run(TOP_NAME,
|
||||
"-Xlog:cds",
|
||||
"-Xlog:class+load",
|
||||
"-Xlog:cds+dynamic=info",
|
||||
"-XX:+AutoCreateSharedArchive",
|
||||
"-cp", appJar,
|
||||
mainAppClass)
|
||||
.assertNormalExit(output -> {
|
||||
output.shouldHaveExitValue(0)
|
||||
.shouldContain(HELLO_WORLD)
|
||||
.shouldContain(HELLO_SOURCE)
|
||||
.shouldNotContain("Dumping shared data to file");
|
||||
});
|
||||
FileTime ft2 = Files.getLastModifiedTime(Paths.get(TOP_NAME));
|
||||
fileModified = !ft2.equals(ft1);
|
||||
if (fileModified) {
|
||||
throw new RuntimeException("Archive file " + TOP_NAME + " should not be updated");
|
||||
}
|
||||
|
||||
// 11 run with static archive
|
||||
print("11 run with static archive");
|
||||
ft1 = Files.getLastModifiedTime(Paths.get(BASE_NAME));
|
||||
run(BASE_NAME,
|
||||
"-Xlog:cds",
|
||||
"-Xlog:cds+dynamic=info",
|
||||
"-Xshare:auto",
|
||||
"-XX:+AutoCreateSharedArchive",
|
||||
verifySharedSpaces,
|
||||
"-cp", appJar,
|
||||
mainAppClass)
|
||||
.assertNormalExit(output -> {
|
||||
output.shouldHaveExitValue(0)
|
||||
.shouldContain(HELLO_WORLD)
|
||||
.shouldContain("AutoCreateSharedArchive is ignored because " + BASE_NAME + " is a static archive")
|
||||
.shouldNotContain("Dumping shared data to file");
|
||||
});
|
||||
ft2 = Files.getLastModifiedTime(Paths.get(BASE_NAME));
|
||||
fileModified = !ft1.equals(ft2);
|
||||
if (fileModified) {
|
||||
throw new RuntimeException("Run -XX:+AutoCreateSharedArchive on static archive create new archive");
|
||||
}
|
||||
|
||||
// 12 run with damaged magic should not regenerate dynamic archive
|
||||
print("12 run with damaged magic should not regenerate dynamic archive");
|
||||
String modMagic = startNewArchive("modify-magic");
|
||||
File copiedJsa = CDSArchiveUtils.copyArchiveFile(archiveFile, modMagic);
|
||||
CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetMagic(), 0x1234);
|
||||
ft1 = Files.getLastModifiedTime(Paths.get(modMagic));
|
||||
|
||||
run(modMagic,
|
||||
"-Xshare:auto",
|
||||
"-XX:+AutoCreateSharedArchive",
|
||||
"-Xlog:cds",
|
||||
"-Xlog:cds+dynamic=info",
|
||||
verifySharedSpaces,
|
||||
"-cp", appJar,
|
||||
mainAppClass)
|
||||
.assertNormalExit(output -> {
|
||||
output.shouldHaveExitValue(0)
|
||||
.shouldContain(HELLO_WORLD)
|
||||
.shouldNotContain("Dumping shared data to file");
|
||||
});
|
||||
ft2 = Files.getLastModifiedTime(Paths.get(modMagic));
|
||||
fileModified = !ft1.equals(ft2);
|
||||
if (fileModified) {
|
||||
throw new RuntimeException("Shared archive " + modMagic + " should not automatically be generated");
|
||||
}
|
||||
|
||||
// 13 run with a bad versioned (< genericHeaderMinVersion) archive
|
||||
print("13 run with a bad versioned archive");
|
||||
print(" 13.01 run with a bad versioned (< genericHeaderMinVersion) archive should not create new archive");
|
||||
String modVersion = startNewArchive("modify-version-b");
|
||||
copiedJsa = CDSArchiveUtils.copyArchiveFile(archiveFile, modVersion);
|
||||
final int version1 = genericHeaderMinVersion - 1;
|
||||
CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetVersion(), version1);
|
||||
ft1 = Files.getLastModifiedTime(Paths.get(modVersion));
|
||||
|
||||
run(modVersion,
|
||||
"-Xshare:auto",
|
||||
"-XX:+AutoCreateSharedArchive",
|
||||
"-Xlog:cds",
|
||||
"-Xlog:cds+dynamic=info",
|
||||
verifySharedSpaces,
|
||||
"-cp", appJar,
|
||||
mainAppClass)
|
||||
.assertNormalExit(output -> {
|
||||
output.shouldHaveExitValue(0)
|
||||
.shouldContain(HELLO_WORLD)
|
||||
.shouldContain("Cannot handle shared archive file version " + version1 + ". Must be at least " + genericHeaderMinVersion)
|
||||
.shouldContain("Unable to use shared archive: invalid archive")
|
||||
.shouldNotContain("Dumping shared data to file");
|
||||
});
|
||||
ft2 = Files.getLastModifiedTime(Paths.get(modVersion));
|
||||
fileModified = !ft1.equals(ft2);
|
||||
if (fileModified) {
|
||||
throw new RuntimeException("Run -XX:+AutoCreateSharedArchive with lower version archive " + modVersion + " should not create new archive");
|
||||
}
|
||||
// 13.02 run with a bad versioned (> currentCDSVersion) archive
|
||||
print(" 13.02 run with a bad versioned (> currentCDSVersion) archive");
|
||||
modVersion = startNewArchive("modify-version-d");
|
||||
copiedJsa = CDSArchiveUtils.copyArchiveFile(archiveFile, modVersion);
|
||||
final int version2 = currentCDSVersion + 1;
|
||||
CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetVersion(), version2);
|
||||
ft1 = Files.getLastModifiedTime(Paths.get(modVersion));
|
||||
|
||||
run(modVersion,
|
||||
"-Xshare:auto",
|
||||
"-XX:+AutoCreateSharedArchive",
|
||||
"-Xlog:cds",
|
||||
"-Xlog:cds+dynamic=info",
|
||||
verifySharedSpaces,
|
||||
"-cp", appJar,
|
||||
mainAppClass)
|
||||
.assertNormalExit(output -> {
|
||||
output.shouldHaveExitValue(0)
|
||||
.shouldContain(HELLO_WORLD)
|
||||
.shouldContain("The shared archive file version " + version2 + " does not match the required version " + currentCDSVersion)
|
||||
.shouldContain("UseSharedSpaces: The shared archive file has the wrong version")
|
||||
.shouldContain("UseSharedSpaces: Initialize dynamic archive failed")
|
||||
.shouldContain("Dumping shared data to file");
|
||||
});
|
||||
ft2 = Files.getLastModifiedTime(Paths.get(modVersion));
|
||||
fileModified = !ft1.equals(ft2);
|
||||
if (!fileModified) {
|
||||
throw new RuntimeException("Run -XX:+AutoCreateSharedArchive with higher version archive " + modVersion + " should create new archive");
|
||||
}
|
||||
|
||||
// 14 run with an archive whose base name is not matched, no share
|
||||
print("14 run with an archive whose base name is not matched, no share");
|
||||
String baseNameMismatch= startNewArchive("basename-mismatch");
|
||||
copiedJsa = CDSArchiveUtils.copyArchiveFile(archiveFile, baseNameMismatch);
|
||||
int nameSize = CDSArchiveUtils.baseArchiveNameSize(copiedJsa);
|
||||
int offset = CDSArchiveUtils.baseArchiveNameOffset(copiedJsa);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < nameSize - 4; i++) {
|
||||
sb.append('Z');
|
||||
}
|
||||
sb.append(".jsa");
|
||||
sb.append('\0');
|
||||
String newName = sb.toString();
|
||||
CDSArchiveUtils.writeData(copiedJsa, offset, newName.getBytes());
|
||||
|
||||
ft1 = Files.getLastModifiedTime(Paths.get(baseNameMismatch));
|
||||
run(baseNameMismatch,
|
||||
"-Xshare:auto",
|
||||
"-XX:+AutoCreateSharedArchive",
|
||||
"-Xlog:cds",
|
||||
"-Xlog:cds+dynamic=info",
|
||||
verifySharedSpaces,
|
||||
"-cp", appJar,
|
||||
mainAppClass)
|
||||
.assertNormalExit(output -> {
|
||||
output.shouldHaveExitValue(0)
|
||||
.shouldContain(HELLO_WORLD)
|
||||
.shouldNotContain("Dumping shared data to file");
|
||||
});
|
||||
ft2 = Files.getLastModifiedTime(Paths.get(baseNameMismatch));
|
||||
|
||||
fileModified = !ft1.equals(ft2);
|
||||
if (fileModified) {
|
||||
throw new RuntimeException("Shared archive " + baseNameMismatch+ " should not automatically be generated");
|
||||
}
|
||||
|
||||
// 15 mismatched jvm_indent in archive, create (-VerifySharedSpaces) or not (-XX:+VerifySharedSpaces) create the new archive
|
||||
print("15 mismatched jvm_indent in archive, " + (verifyOn ? "-XX:+VerifySharedSpaces not " : "-XX:-VerifySharedSpaces ") + "create new archive");
|
||||
String modJvmIdent = startNewArchive("modify-jvmident");
|
||||
copiedJsa = CDSArchiveUtils.copyArchiveFile(archiveFile, modJvmIdent);
|
||||
CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetJvmIdent(), 0x65656565);
|
||||
ft1 = Files.getLastModifiedTime(Paths.get(modJvmIdent));
|
||||
|
||||
run(modJvmIdent,
|
||||
"-Xshare:auto",
|
||||
"-XX:+AutoCreateSharedArchive",
|
||||
"-Xlog:cds",
|
||||
"-Xlog:cds+dynamic=info",
|
||||
verifySharedSpaces,
|
||||
"-cp", appJar,
|
||||
mainAppClass)
|
||||
.assertNormalExit(output -> {
|
||||
output.shouldHaveExitValue(0);
|
||||
if (verifyOn) {
|
||||
output.shouldContain("UseSharedSpaces: Header checksum verification failed")
|
||||
.shouldContain("Unable to use shared archive: invalid archive")
|
||||
.shouldNotContain("Dumping shared data to file");
|
||||
} else {
|
||||
output.shouldContain(HELLO_WORLD)
|
||||
.shouldContain("Dumping shared data to file");
|
||||
}
|
||||
});
|
||||
ft2 = Files.getLastModifiedTime(Paths.get(modJvmIdent));
|
||||
fileModified = !ft1.equals(ft2);
|
||||
if (verifyOn) {
|
||||
if (fileModified) {
|
||||
throw new RuntimeException("Shared archive " + modJvmIdent + " should not be generated");
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!fileModified) {
|
||||
throw new RuntimeException("Shared archive " + modJvmIdent + " should be generated");
|
||||
}
|
||||
}
|
||||
|
||||
// 16 run with an archive of only containing dynamic magic (size of 4) will not create new archive at exit
|
||||
print("16 run with an archive of only containing dynamic magic (size of 4) will not create new archive at exit");
|
||||
String magicOnly = startNewArchive("magic-only");
|
||||
copiedJsa = CDSArchiveUtils.createMagicOnlyFile(magicOnly, false/*dynamic*/);
|
||||
ft1 = Files.getLastModifiedTime(Paths.get(magicOnly));
|
||||
run(magicOnly,
|
||||
"-Xshare:auto",
|
||||
"-XX:+AutoCreateSharedArchive",
|
||||
"-Xlog:cds",
|
||||
"-Xlog:cds+dynamic=info",
|
||||
"-cp", appJar,
|
||||
mainAppClass)
|
||||
.assertNormalExit(output -> {
|
||||
output.shouldHaveExitValue(0)
|
||||
.shouldContain(HELLO_WORLD)
|
||||
.shouldContain("Unable to read generic CDS file map header from shared archive")
|
||||
.shouldNotContain("Dumping shared data to file:");
|
||||
});
|
||||
ft2 = Files.getLastModifiedTime(Paths.get(magicOnly));
|
||||
fileModified = !ft1.equals(ft2);
|
||||
if (fileModified) {
|
||||
throw new RuntimeException("Shared archive " + magicOnly + " should not automatically be generated");
|
||||
}
|
||||
|
||||
// Do some base tests for -XX:SharedArchiveFile=base:top, they should be same as default archive as base.
|
||||
// delete top archive
|
||||
if (archiveFile.exists()) {
|
||||
archiveFile.delete();
|
||||
}
|
||||
// delete base archive
|
||||
File baseFile = new File(BASE_NAME);
|
||||
if (baseFile.exists()) {
|
||||
baseFile.delete();
|
||||
}
|
||||
|
||||
// 20 Testing with -XX:SharedArchiveFile=base:top
|
||||
print("20 Testing with -XX:SharedArchiveFile=base:top");
|
||||
// 20.01 dump base archive and top archive
|
||||
print(" 20.01 dump base archive " + BASE_NAME);
|
||||
dumpBaseArchive(BASE_NAME, "-Xlog:cds")
|
||||
.assertNormalExit(output -> {
|
||||
output.shouldHaveExitValue(0);
|
||||
});
|
||||
checkFileExists(BASE_NAME);
|
||||
|
||||
// 20.02 dump top based on base
|
||||
print(" 20.02 dump top based on base");
|
||||
dump2(BASE_NAME, TOP_NAME,
|
||||
"-Xlog:cds",
|
||||
"-cp", appJar, mainAppClass)
|
||||
.assertNormalExit(output -> {
|
||||
output.shouldHaveExitValue(0)
|
||||
.shouldContain("Dumping shared data to file:")
|
||||
.shouldContain(TOP_NAME);
|
||||
});
|
||||
checkFileExists(TOP_NAME);
|
||||
|
||||
// 20.03 run with -XX:SharedArchveFile=base:top
|
||||
print(" 20.03 run with -XX:SharedArchveFile=base:top");
|
||||
run2(BASE_NAME, TOP_NAME,
|
||||
"-Xlog:cds",
|
||||
"-Xlog:cds+dynamic=info",
|
||||
"-Xlog:class+load",
|
||||
"-cp", appJar,
|
||||
mainAppClass)
|
||||
.assertNormalExit(output -> {
|
||||
output.shouldHaveExitValue(0)
|
||||
.shouldContain(HELLO_SOURCE);
|
||||
});
|
||||
|
||||
// 20.04 run with -XX:SharedArchveFile=top:base (reversed)
|
||||
print(" 20.04 run with -XX:SharedArchveFile=top:base (reversed)");
|
||||
run2(TOP_NAME, BASE_NAME,
|
||||
"-Xlog:cds",
|
||||
"-Xlog:cds+dynamic=info",
|
||||
"-Xlog:class+load",
|
||||
"-cp", appJar,
|
||||
mainAppClass)
|
||||
.assertAbnormalExit(output -> {
|
||||
output.shouldHaveExitValue(1)
|
||||
.shouldContain("Not a base shared archive: " + TOP_NAME)
|
||||
.shouldContain("An error has occurred while processing the shared archive file")
|
||||
.shouldNotContain(HELLO_WORLD);
|
||||
});
|
||||
|
||||
// 21 Mismatched versions
|
||||
print("21 Mismatched versions");
|
||||
// 21.01 top version is lower than CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION, regenerate top
|
||||
print(" 21.01 top version is lower than CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION, regenerate top");
|
||||
String versionB = startNewArchive("modify-version-B");
|
||||
archiveFile = new File(TOP_NAME);
|
||||
copiedJsa = CDSArchiveUtils.copyArchiveFile(archiveFile, versionB);
|
||||
CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetVersion(), version1);
|
||||
ft1 = Files.getLastModifiedTime(Paths.get(versionB));
|
||||
|
||||
run2(BASE_NAME, versionB,
|
||||
"-Xshare:auto",
|
||||
"-XX:+AutoCreateSharedArchive",
|
||||
"-Xlog:cds",
|
||||
"-Xlog:cds+dynamic=info",
|
||||
verifySharedSpaces,
|
||||
"-cp", appJar,
|
||||
mainAppClass)
|
||||
.assertNormalExit(output -> {
|
||||
output.shouldHaveExitValue(0)
|
||||
.shouldContain(HELLO_WORLD)
|
||||
.shouldContain("Cannot handle shared archive file version " + version1)
|
||||
.shouldContain(versionB)
|
||||
.shouldContain("Dumping shared data to file:");
|
||||
});
|
||||
ft2 = Files.getLastModifiedTime(Paths.get(versionB));
|
||||
fileModified = !ft1.equals(ft2);
|
||||
if (!fileModified) {
|
||||
throw new RuntimeException("Shared archive " + versionB + " should automatically be generated");
|
||||
}
|
||||
|
||||
// 21.02 top version is higher than CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION, no share for top, create archive at exit
|
||||
print(" 21.02 top version is higher than CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION, no share for top, create archive at exit");
|
||||
String versionF = startNewArchive("versionF");
|
||||
copiedJsa = CDSArchiveUtils.copyArchiveFile(archiveFile, versionF);
|
||||
CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetVersion(), version2);
|
||||
ft1 = Files.getLastModifiedTime(Paths.get(versionF));
|
||||
run2(BASE_NAME, versionF,
|
||||
"-Xshare:auto",
|
||||
"-XX:+AutoCreateSharedArchive",
|
||||
"-Xlog:cds",
|
||||
"-Xlog:cds+dynamic=info",
|
||||
verifySharedSpaces,
|
||||
"-cp", appJar,
|
||||
mainAppClass)
|
||||
.assertNormalExit(output -> {
|
||||
output.shouldContain("The shared archive file version " + version2 + " does not match the required version " + currentCDSVersion)
|
||||
.shouldContain(HELLO_WORLD)
|
||||
.shouldContain("Dumping shared data to file:");
|
||||
});
|
||||
ft2 = Files.getLastModifiedTime(Paths.get(versionB));
|
||||
fileModified = !ft1.equals(ft2);
|
||||
if (!fileModified) {
|
||||
throw new RuntimeException("Shared archive " + versionB + " should be created at exit");
|
||||
}
|
||||
|
||||
// 22 create an archive with dynamic magic number only
|
||||
// archive will be created at exit if base can be shared.
|
||||
print("22 create an archive with dynamic magic number only");
|
||||
copiedJsa = CDSArchiveUtils.createMagicOnlyFile(magicOnly, false /*dynamic*/);
|
||||
ft1 = Files.getLastModifiedTime(Paths.get(magicOnly));
|
||||
run2(BASE_NAME, magicOnly,
|
||||
"-Xshare:auto",
|
||||
"-XX:+AutoCreateSharedArchive",
|
||||
"-Xlog:cds",
|
||||
"-Xlog:cds+dynamic=info",
|
||||
verifySharedSpaces,
|
||||
"-cp", appJar,
|
||||
mainAppClass)
|
||||
.assertNormalExit(output -> {
|
||||
output.shouldContain(HELLO_WORLD)
|
||||
.shouldContain("Unable to read generic CDS file map header from shared archive")
|
||||
.shouldContain("Dumping shared data to file:");
|
||||
});
|
||||
ft2 = Files.getLastModifiedTime(Paths.get(magicOnly));
|
||||
fileModified = !ft1.equals(ft2);
|
||||
if (!fileModified) {
|
||||
throw new RuntimeException("Shared archive " + magicOnly + " should be created at exit");
|
||||
}
|
||||
|
||||
// 23 mismatched jvm_indent in top or base archive
|
||||
// 23.01 mismatched jvm_indent in top archive
|
||||
print(" 23.01 mismatched jvm_indent in top archive");
|
||||
String modJvmIdentTop = startNewArchive("modify-jvmident-top");
|
||||
copiedJsa = CDSArchiveUtils.copyArchiveFile(archiveFile, modJvmIdentTop);
|
||||
CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetJvmIdent(), 0x65656565);
|
||||
ft1 = Files.getLastModifiedTime(Paths.get(modJvmIdentTop));
|
||||
|
||||
run2(BASE_NAME, modJvmIdentTop,
|
||||
"-Xshare:auto",
|
||||
"-XX:+AutoCreateSharedArchive",
|
||||
"-Xlog:cds",
|
||||
"-Xlog:cds+dynamic=info",
|
||||
verifySharedSpaces,
|
||||
"-cp", appJar,
|
||||
mainAppClass)
|
||||
.assertNormalExit(output -> {
|
||||
output.shouldHaveExitValue(0);
|
||||
if (verifyOn) {
|
||||
output.shouldContain("UseSharedSpaces: Header checksum verification failed");
|
||||
}
|
||||
output.shouldContain(HELLO_WORLD)
|
||||
.shouldContain("Dumping shared data to file");
|
||||
});
|
||||
ft2 = Files.getLastModifiedTime(Paths.get(modJvmIdentTop));
|
||||
fileModified = !ft1.equals(ft2);
|
||||
if (!fileModified) {
|
||||
throw new RuntimeException("Shared archive " + modJvmIdentTop + " should be generated");
|
||||
}
|
||||
// 23.02 mismatched jvm_indent in base archive
|
||||
print(" 23.02 mismatched jvm_indent in base archive");
|
||||
String modJvmIdentBase = startNewArchive("modify-jvmident-base");
|
||||
copiedJsa = CDSArchiveUtils.copyArchiveFile(new File(BASE_NAME), modJvmIdentBase);
|
||||
CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetJvmIdent(), 0x65656565);
|
||||
ft1 = Files.getLastModifiedTime(Paths.get(TOP_NAME));
|
||||
|
||||
run2(modJvmIdentBase, TOP_NAME,
|
||||
"-Xshare:auto",
|
||||
"-XX:+AutoCreateSharedArchive",
|
||||
"-Xlog:cds",
|
||||
"-Xlog:cds+dynamic=info",
|
||||
verifySharedSpaces,
|
||||
"-cp", appJar,
|
||||
mainAppClass)
|
||||
.assertNormalExit(output -> {
|
||||
output.shouldHaveExitValue(0)
|
||||
.shouldContain(HELLO_WORLD);
|
||||
if (verifyOn) {
|
||||
output.shouldContain("UseSharedSpaces: Header checksum verification failed");
|
||||
}
|
||||
output.shouldContain("Unable to map shared spaces")
|
||||
.shouldNotContain("Dumping shared data to file");
|
||||
});
|
||||
ft2 = Files.getLastModifiedTime(Paths.get(TOP_NAME));
|
||||
fileModified = !ft1.equals(ft2);
|
||||
if (fileModified) {
|
||||
throw new RuntimeException("Shared archive " + TOP_NAME + " should not be generated");
|
||||
}
|
||||
|
||||
// 24 run with non-existing shared archives
|
||||
print("24 run with non-existing shared archives");
|
||||
// 24.01 run -Xshare:auto -XX:+AutoCreateSharedArchive -XX:SharedArchiveFile=base.jsa:non-exist-top.jsa
|
||||
print(" 24.01 run -Xshare:auto -XX:+AutoCreateSharedArchive -XX:SharedArchiveFile=base.jsa:non-exist-top.jsa");
|
||||
String nonExistTop = "non-existing-top.jsa";
|
||||
File fileNonExist = new File(nonExistTop);
|
||||
if (fileNonExist.exists()) {
|
||||
fileNonExist.delete();
|
||||
}
|
||||
run2(BASE_NAME, nonExistTop,
|
||||
"-Xshare:auto",
|
||||
"-XX:+AutoCreateSharedArchive",
|
||||
"-Xlog:cds",
|
||||
"-Xlog:cds+dynamic=info",
|
||||
verifySharedSpaces,
|
||||
"-cp", appJar,
|
||||
mainAppClass)
|
||||
.assertNormalExit(output -> {
|
||||
output.shouldContain("Specified shared archive not found (" + nonExistTop + ")")
|
||||
.shouldContain(HELLO_WORLD)
|
||||
.shouldContain("Dumping shared data to file:");
|
||||
});
|
||||
if (!fileNonExist.exists()) {
|
||||
throw new RuntimeException("Shared archive " + nonExistTop + " should be created at exit");
|
||||
}
|
||||
|
||||
// 24.02 run -Xshare:auto -XX:+AutoCreateSharedArchive -XX:SharedArchiveFile=non-exist-base.jsa:top.jsa
|
||||
print(" 24.02 run -Xshare:auto -XX:+AutoCreateSharedArchive -XX:SharedArchiveFile=non-exist-base.jsa:top.jsa");
|
||||
String nonExistBase = "non-existing-base.jsa";
|
||||
fileNonExist = new File(nonExistBase);
|
||||
if (fileNonExist.exists()) {
|
||||
fileNonExist.delete();
|
||||
}
|
||||
ft1 = Files.getLastModifiedTime(Paths.get(TOP_NAME));
|
||||
run2(nonExistBase, TOP_NAME,
|
||||
"-Xshare:auto",
|
||||
"-XX:+AutoCreateSharedArchive",
|
||||
"-Xlog:cds",
|
||||
"-Xlog:cds+dynamic=info",
|
||||
verifySharedSpaces,
|
||||
"-cp", appJar,
|
||||
mainAppClass)
|
||||
.assertNormalExit(output -> {
|
||||
output.shouldContain("Specified shared archive not found (" + nonExistBase + ")")
|
||||
.shouldContain(HELLO_WORLD)
|
||||
.shouldNotContain("Dumping shared data to file:");
|
||||
});
|
||||
ft2 = Files.getLastModifiedTime(Paths.get(TOP_NAME));
|
||||
fileModified = !ft1.equals(ft2);
|
||||
if (fileModified) {
|
||||
throw new RuntimeException("Shared archive " + TOP_NAME + " should not be created at exit");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (c) 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @summary Test -XX:+AutoCreateSharedArchive on a copied JDK without default shared archive
|
||||
* @bug 8261455
|
||||
* @requires vm.cds
|
||||
* @requires vm.flagless
|
||||
* @comment This test doesn't work on Windows because it depends on symlinks
|
||||
* @requires os.family != "windows"
|
||||
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
|
||||
* @compile ../test-classes/Hello.java
|
||||
* @run driver TestAutoCreateSharedArchiveNoDefaultArchive
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import jdk.test.lib.cds.CDSTestUtils;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
|
||||
public class TestAutoCreateSharedArchiveNoDefaultArchive {
|
||||
public static void main(String[] args) throws Exception {
|
||||
String mainClass = "Hello";
|
||||
String java_home_src = System.getProperty("java.home");
|
||||
String java_home_dst = CDSTestUtils.getOutputDir() + File.separator + "moved_jdk";
|
||||
CDSTestUtils.clone(new File(java_home_src), new File(java_home_dst));
|
||||
System.out.println("======== Cloned JDK at " + java_home_dst);
|
||||
|
||||
String homeJava = java_home_src + File.separator + "bin" + File.separator + "java";
|
||||
String dstJava = java_home_dst + File.separator + "bin" + File.separator + "java";
|
||||
|
||||
TestCommon.startNewArchiveName();
|
||||
String jsaFileName = TestCommon.getCurrentArchiveName();
|
||||
File jsaFile = new File(jsaFileName);
|
||||
if (jsaFile.exists()) {
|
||||
jsaFile.delete();
|
||||
}
|
||||
|
||||
String jsaOpt = "-XX:SharedArchiveFile=" + jsaFileName;
|
||||
String autoCreateArchive = "-XX:+AutoCreateSharedArchive";
|
||||
{
|
||||
ProcessBuilder pb = CDSTestUtils.makeBuilder(homeJava,
|
||||
"-Xshare:dump",
|
||||
jsaOpt);
|
||||
TestCommon.executeAndLog(pb, "dump")
|
||||
.shouldHaveExitValue(0);
|
||||
}
|
||||
{
|
||||
ProcessBuilder pb = CDSTestUtils.makeBuilder(homeJava,
|
||||
"-Xshare:auto",
|
||||
jsaOpt,
|
||||
"-Xlog:class+path=info",
|
||||
"-version");
|
||||
OutputAnalyzer out = TestCommon.executeAndLog(pb, "exec-src");
|
||||
out.shouldHaveExitValue(0);
|
||||
out.shouldNotContain("shared class paths mismatch");
|
||||
out.shouldNotContain("BOOT classpath mismatch");
|
||||
}
|
||||
|
||||
String helloJar = JarBuilder.getOrCreateHelloJar();
|
||||
|
||||
if (jsaFile.exists()) {
|
||||
jsaFile.delete();
|
||||
}
|
||||
// Test runtime with cloned JDK
|
||||
System.out.println("======== run with cloned jdk to created dynamic shared archive at exit");
|
||||
{
|
||||
ProcessBuilder pb = CDSTestUtils.makeBuilder(dstJava,
|
||||
"-Xshare:auto",
|
||||
autoCreateArchive,
|
||||
jsaOpt,
|
||||
"-Xlog:cds",
|
||||
"-Xlog:class+path=info",
|
||||
"-cp", helloJar,
|
||||
mainClass);
|
||||
OutputAnalyzer out = TestCommon.executeAndLog(pb, "exec-dst");
|
||||
out.shouldHaveExitValue(0);
|
||||
out.shouldContain("Dumping shared data to file");
|
||||
if (!jsaFile.exists()) {
|
||||
throw new RuntimeException("Shared archive " + jsaFileName + " should be created at exit");
|
||||
}
|
||||
}
|
||||
|
||||
// Now rename classes.jsa to old-classes.jsa
|
||||
String dstDir = java_home_dst + File.separator + "lib" + File.separator + "server";
|
||||
CDSTestUtils.rename(new File(dstDir + File.separator + "classes.jsa"),
|
||||
new File(dstDir + File.separator + "old-classes.jsa"));
|
||||
System.out.println("======= renamed classes.jsa to old-classes.jsa");
|
||||
|
||||
{
|
||||
ProcessBuilder pb = CDSTestUtils.makeBuilder(dstJava,
|
||||
"-Xlog:cds",
|
||||
"-version");
|
||||
TestCommon.executeAndLog(pb, "show-version")
|
||||
.shouldHaveExitValue(0)
|
||||
.shouldContain("UseSharedSpaces: Initialize static archive failed")
|
||||
.shouldContain("UseSharedSpaces: Unable to map shared spaces")
|
||||
.shouldContain("mixed mode")
|
||||
.shouldNotContain("sharing");
|
||||
}
|
||||
// delete existing jsa file
|
||||
if (jsaFile.exists()) {
|
||||
jsaFile.delete();
|
||||
}
|
||||
System.out.println("======= run with no default shared archive should not create shared archive at exit");
|
||||
{
|
||||
ProcessBuilder pb = CDSTestUtils.makeBuilder(dstJava,
|
||||
"-Xshare:auto",
|
||||
autoCreateArchive,
|
||||
jsaOpt,
|
||||
"-Xlog:cds",
|
||||
"-Xlog:class+path=info",
|
||||
"-cp", helloJar,
|
||||
mainClass);
|
||||
TestCommon.executeAndLog(pb, "no-default-archive")
|
||||
.shouldHaveExitValue(0)
|
||||
.shouldContain("UseSharedSpaces: Initialize static archive failed")
|
||||
.shouldContain("UseSharedSpaces: Unable to map shared spaces")
|
||||
.shouldNotContain("Dumping shared data to file");
|
||||
if (jsaFile.exists()) {
|
||||
throw new RuntimeException("Archive file " + jsaFileName + " should not be created at exit");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, 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
|
||||
@ -341,6 +341,18 @@ public class CDSArchiveUtils {
|
||||
return newJsaFile;
|
||||
}
|
||||
|
||||
public static File createMagicOnlyFile(String fileName, boolean createStatic) throws Exception {
|
||||
File file = new File(fileName);
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
}
|
||||
try (FileOutputStream out = new FileOutputStream(file)) {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(4).putInt(createStatic ? staticMagic: dynamicMagic);
|
||||
out.write(buffer.array(), 0, 4);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
private static FileChannel getFileChannel(File file, boolean write) throws Exception {
|
||||
List<StandardOpenOption> arry = new ArrayList<StandardOpenOption>();
|
||||
arry.add(READ);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 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
|
||||
@ -26,6 +26,9 @@ import java.io.IOException;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.CopyOption;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
@ -684,4 +687,78 @@ public class CDSTestUtils {
|
||||
private static boolean isAsciiPrintable(char ch) {
|
||||
return ch >= 32 && ch < 127;
|
||||
}
|
||||
|
||||
// JDK utility
|
||||
|
||||
// Do a cheap clone of the JDK. Most files can be sym-linked. However, $JAVA_HOME/bin/java and $JAVA_HOME/lib/.../libjvm.so"
|
||||
// must be copied, because the java.home property is derived from the canonicalized paths of these 2 files.
|
||||
// Set a list of {jvm, "java"} which will be physically copied. If a file needs copied physically, add it to the list.
|
||||
private static String[] phCopied = {System.mapLibraryName("jvm"), "java"};
|
||||
public static void clone(File src, File dst) throws Exception {
|
||||
if (dst.exists()) {
|
||||
if (!dst.isDirectory()) {
|
||||
throw new RuntimeException("Not a directory :" + dst);
|
||||
}
|
||||
} else {
|
||||
if (!dst.mkdir()) {
|
||||
throw new RuntimeException("Cannot create directory: " + dst);
|
||||
}
|
||||
}
|
||||
// final String jvmLib = System.mapLibraryName("jvm");
|
||||
for (String child : src.list()) {
|
||||
if (child.equals(".") || child.equals("..")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
File child_src = new File(src, child);
|
||||
File child_dst = new File(dst, child);
|
||||
if (child_dst.exists()) {
|
||||
throw new RuntimeException("Already exists: " + child_dst);
|
||||
}
|
||||
if (child_src.isFile()) {
|
||||
boolean needPhCopy = false;
|
||||
for (String target : phCopied) {
|
||||
if (child.equals(target)) {
|
||||
needPhCopy = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (needPhCopy) {
|
||||
Files.copy(child_src.toPath(), /* copy data to -> */ child_dst.toPath(),
|
||||
new CopyOption[] { StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES});
|
||||
} else {
|
||||
Files.createSymbolicLink(child_dst.toPath(), /* link to -> */ child_src.toPath());
|
||||
}
|
||||
} else {
|
||||
clone(child_src, child_dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// modulesDir, like $JDK/lib
|
||||
// oldName, module name under modulesDir
|
||||
// newName, new name for oldName
|
||||
public static void rename(File fromFile, File toFile) throws Exception {
|
||||
if (!fromFile.exists()) {
|
||||
throw new RuntimeException(fromFile.getName() + " does not exist");
|
||||
}
|
||||
|
||||
if (toFile.exists()) {
|
||||
throw new RuntimeException(toFile.getName() + " already exists");
|
||||
}
|
||||
|
||||
boolean success = fromFile.renameTo(toFile);
|
||||
if (!success) {
|
||||
throw new RuntimeException("rename file " + fromFile.getName()+ " to " + toFile.getName() + " failed");
|
||||
}
|
||||
}
|
||||
|
||||
public static ProcessBuilder makeBuilder(String... args) throws Exception {
|
||||
System.out.print("[");
|
||||
for (String s : args) {
|
||||
System.out.print(" " + s);
|
||||
}
|
||||
System.out.println(" ]");
|
||||
return new ProcessBuilder(args);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user