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 #5077

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -1382,14 +1382,6 @@ const char* os::dll_file_extension() { return ".so"; }
// directory not the java application's temp directory, ala java.io.tmpdir.
const char* os::get_temp_directory() { return "/tmp"; }

static bool file_exists(const char* filename) {
struct stat statbuf;
if (filename == NULL || strlen(filename) == 0) {
return false;
}
return os::stat(filename, &statbuf) == 0;
}

// check if addr is inside libjvm.so
bool os::address_is_in_vm(address addr) {
static address libjvm_base_addr;
@@ -2424,7 +2416,7 @@ static void print_sys_devices_cpu_info(outputStream* st, char* buf, size_t bufle
snprintf(hbuf_type, 60, "/sys/devices/system/cpu/cpu0/cache/index%u/type", i);
snprintf(hbuf_size, 60, "/sys/devices/system/cpu/cpu0/cache/index%u/size", i);
snprintf(hbuf_coherency_line_size, 80, "/sys/devices/system/cpu/cpu0/cache/index%u/coherency_line_size", i);
if (file_exists(hbuf_level)) {
if (os::file_exists(hbuf_level)) {
_print_ascii_file_h("cache level", hbuf_level, st);
_print_ascii_file_h("cache type", hbuf_type, st);
_print_ascii_file_h("cache size", hbuf_size, st);
@@ -367,11 +367,14 @@ void DynamicArchive::prepare_for_dynamic_dumping() {
}

void DynamicArchive::dump(const char* archive_name, TRAPS) {
assert(UseSharedSpaces && RecordDynamicDumpInfo, "already checked in arguments.cpp?");
assert((UseSharedSpaces && RecordDynamicDumpInfo) || AutoCreateSharedArchive, "already checked in arguments.cpp?");
assert(ArchiveClassesAtExit == nullptr, "already checked in arguments.cpp?");
ArchiveClassesAtExit = archive_name;
if (Arguments::init_shared_archive_paths()) {
prepare_for_dynamic_dumping();
if (!AutoCreateSharedArchive) {
// When dump at exit, prepare_for_dynamic_dumping already called.
prepare_for_dynamic_dumping();
}
if (DynamicDumpSharedSpaces) {
dump(CHECK);
}
@@ -76,6 +76,23 @@
#define O_BINARY 0 // otherwise do nothing.
#endif

#define CDS_MAX_PATH (2*K)
// Utility class to release file header memory
// and close open file handle
class ReleaseFileHeader {
void* _header;
int _fd;
public:
ReleaseFileHeader(void* header, int fd) {
_header = header;
_fd = fd;
}
~ReleaseFileHeader() {
os::free(_header);
os::close(_fd);
}
};

// Complain and stop. All error conditions occurring during the writing of
// an archive file should stop the process. Unrecoverable errors during
// the reading of the archive file should stop the process.
@@ -120,7 +137,6 @@ void FileMapInfo::fail_continue(const char *msg, ...) {
fail_exit(msg, ap);
} else {
if (log_is_enabled(Info, cds)) {
ResourceMark rm;
LogStream ls(Log(cds)::info());
ls.print("UseSharedSpaces: ");
ls.vprint_cr(msg, ap);
@@ -186,6 +202,17 @@ FileMapInfo::FileMapInfo(bool is_static) {
_header->set_has_platform_or_app_classes(true);
_file_offset = 0;
_file_open = false;
if (is_static) {
_full_path = Arguments::GetSharedArchivePath();
} else {
_full_path = Arguments::GetSharedDynamicArchivePath();
}
if (AutoCreateSharedArchive) {
if (!_is_static && !validate_archive()) {
// regenerate shared archive at exit
DynamicDumpSharedSpaces = true;
}
}
}

FileMapInfo::~FileMapInfo() {
@@ -196,6 +223,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) {
@@ -1023,33 +1066,29 @@ bool FileMapInfo::check_archive(const char* archive_name, bool is_static) {

size_t sz = is_static ? sizeof(FileMapHeader) : sizeof(DynamicArchiveHeader);
void* header = os::malloc(sz, mtInternal);

ReleaseFileHeader rl(header, fd);
memset(header, 0, sz);
size_t n = os::read(fd, header, (unsigned int)sz);
if (n != sz) {
os::free(header);
os::close(fd);
vm_exit_during_initialization("Unable to read header from shared archive", archive_name);
return false;
}
if (is_static) {
FileMapHeader* static_header = (FileMapHeader*)header;
if (static_header->magic() != CDS_ARCHIVE_MAGIC) {
os::free(header);
os::close(fd);
vm_exit_during_initialization("Not a base shared archive", archive_name);
log_info(cds)("The shared archive file has a bad magic number.");
log_info(cds)("Not a valid base shared archive: %s", archive_name);
return false;
}
} else {
DynamicArchiveHeader* dynamic_header = (DynamicArchiveHeader*)header;
if (dynamic_header->magic() != CDS_DYNAMIC_ARCHIVE_MAGIC) {
os::free(header);
os::close(fd);
vm_exit_during_initialization("Not a top shared archive", archive_name);
log_info(cds)("The shared archive file has a bad dynamic magic number.");
log_info(cds)("Not a valid top shared archive: %s", archive_name);
return false;
}
}
os::free(header);
os::close(fd);
return true;
}

@@ -1060,49 +1099,53 @@ bool FileMapInfo::get_base_archive_name_from_header(const char* archive_name,
*size = 0;
return false;
}

// read the header as a dynamic archive header
size_t sz = sizeof(DynamicArchiveHeader);
DynamicArchiveHeader* dynamic_header = (DynamicArchiveHeader*)os::malloc(sz, mtInternal);

ReleaseFileHeader rl((void*)dynamic_header, fd);
*base_archive_name = nullptr;
size_t n = os::read(fd, dynamic_header, (unsigned int)sz);
if (n != sz) {
fail_continue("Unable to read the file header.");
os::free(dynamic_header);
os::close(fd);
return false;
}
if (dynamic_header->magic() != CDS_DYNAMIC_ARCHIVE_MAGIC) {
// Not a dynamic header, no need to proceed further.
*size = 0;
os::free(dynamic_header);
os::close(fd);

unsigned int magic = dynamic_header->magic();
if (magic == CDS_ARCHIVE_MAGIC) {
// this is a static archive
// do not call fail_continue since RequireSharedSpaces will cause to exit
log_info(cds)("This is a static archive");
return false;
}
if (dynamic_header->base_archive_is_default()) {
*base_archive_name = Arguments::get_default_shared_archive_path();
} else {
// read the base archive name
if (magic != CDS_DYNAMIC_ARCHIVE_MAGIC) {
fail_continue("The shared archive file has a bad magic number.");
}
size_t name_size = dynamic_header->base_archive_name_size();
if (name_size == 0) {
os::free(dynamic_header);
os::close(fd);
// read the base archive name
if (name_size <= 0 || name_size > CDS_MAX_PATH) {
fail_continue("Base archive name size is wrong.");
return false;
}
*base_archive_name = NEW_C_HEAP_ARRAY(char, name_size, mtInternal);
n = os::read(fd, *base_archive_name, (unsigned int)name_size);
if (n != name_size) {
fail_continue("Unable to read the base archive name from the header.");
FREE_C_HEAP_ARRAY(char, *base_archive_name);
*base_archive_name = NULL;
os::free(dynamic_header);
os::close(fd);
*size = 0;
*base_archive_name = nullptr;
return false;
}
sz = sizeof(FileMapHeader);
FileMapHeader* static_header = (FileMapHeader*) os::malloc(sz, mtInternal);
int fdh = os::open(*base_archive_name, O_RDONLY | O_BINARY, 0);
ReleaseFileHeader rl((void*)static_header, fdh);
if (fdh < 0) {
fail_continue("Unable to open base archive.");
return false;
}
return true;
}

os::free(dynamic_header);
os::close(fd);
return true;
}

// Read the FileMapInfo information from the file.
@@ -1116,15 +1159,15 @@ bool FileMapInfo::init_from_file(int fd) {
}

if (!Arguments::has_jimage()) {
FileMapInfo::fail_continue("The shared archive file cannot be used with an exploded module build.");
fail_continue("The shared archive file cannot be used with an exploded module build.");
return false;
}

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

@@ -1138,14 +1181,14 @@ bool FileMapInfo::init_from_file(int fd) {
if (header()->header_size() != sz) {
log_info(cds)("_header_size expected: " SIZE_FORMAT, sz);
log_info(cds)(" actual: " SIZE_FORMAT, header()->header_size());
FileMapInfo::fail_continue("The shared archive file has an incorrect header size.");
fail_continue("The shared archive file has an incorrect header size.");
return false;
}

const char* actual_ident = header()->jvm_ident();

if (actual_ident[JVM_IDENT_MAX-1] != 0) {
FileMapInfo::fail_continue("JVM version identifier is corrupted.");
fail_continue("JVM version identifier is corrupted.");
return false;
}

@@ -1154,7 +1197,7 @@ bool FileMapInfo::init_from_file(int fd) {
if (strncmp(actual_ident, expected_ident, JVM_IDENT_MAX-1) != 0) {
log_info(cds)("_jvm_ident expected: %s", expected_ident);
log_info(cds)(" actual: %s", actual_ident);
FileMapInfo::fail_continue("The shared archive file was created by a different"
fail_continue("The shared archive file was created by a different"
" version or build of HotSpot");
return false;
}
@@ -1164,7 +1207,7 @@ bool FileMapInfo::init_from_file(int fd) {
if (expected_crc != header()->crc()) {
log_info(cds)("_crc expected: %d", expected_crc);
log_info(cds)(" actual: %d", header()->crc());
FileMapInfo::fail_continue("Header checksum verification failed.");
fail_continue("Header checksum verification failed.");
return false;
}
}
@@ -1197,11 +1240,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) {
@@ -1273,7 +1311,7 @@ void FileMapInfo::write_header() {

if (header()->magic() == CDS_DYNAMIC_ARCHIVE_MAGIC) {
char* base_archive_name = (char*)Arguments::GetSharedArchivePath();
if (base_archive_name != NULL) {
if (base_archive_name != nullptr && header()->base_archive_name_size() != 0) {
write_bytes(base_archive_name, header()->base_archive_name_size());
}
}
@@ -2194,14 +2232,16 @@ bool FileMapInfo::initialize() {
FileMapInfo::fail_continue("CDS is disabled because early JVMTI ClassFileLoadHook is in use.");
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("Read static archive failed.");
} else {
FileMapInfo::fail_continue("Read dynamic archive failed.");
if (AutoCreateSharedArchive) {
DynamicDumpSharedSpaces = true;
}
}
return false;
}
return true;
@@ -450,6 +450,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);
@@ -92,11 +92,6 @@ static size_t parse_value(const char* value_str) {
return value;
}

static bool file_exists(const char* filename) {
struct stat dummy_stat;
return os::stat(filename, &dummy_stat) == 0;
}

static uint number_of_digits(uint number) {
return number < 10 ? 1 : (number < 100 ? 2 : 3);
}
@@ -139,7 +134,7 @@ static uint next_file_number(const char* filename,
assert(ret > 0 && static_cast<size_t>(ret) == len - 1,
"incorrect buffer length calculation");

if (file_exists(archive_name) && !is_regular_file(archive_name)) {
if (os::file_exists(archive_name) && !is_regular_file(archive_name)) {
// We've encountered something that's not a regular file among the
// possible file rotation targets. Fail immediately to prevent
// problems later.
@@ -150,7 +145,7 @@ static uint next_file_number(const char* filename,
}

// Stop looking if we find an unused file name
if (!file_exists(archive_name)) {
if (!os::file_exists(archive_name)) {
next_num = i;
found = true;
break;
@@ -233,7 +228,7 @@ bool LogFileOutput::initialize(const char* options, outputStream* errstream) {
return false;
}

bool file_exist = file_exists(_file_name);
bool file_exist = os::file_exists(_file_name);
if (file_exist && _is_default_file_count && is_fifo_file(_file_name)) {
_file_count = 0; // Prevent file rotation for fifo's such as named pipes.
}