8207812: Implement Dynamic CDS Archive

Improve the usability of AppCDS

Co-authored-by: Ioi Lam <ioi.lam@oracle.com>
Co-authored-by: Jiangli Zhou <jianglizhou@google.com>
Reviewed-by: acorn, jiangli, mseledtsov
This commit is contained in:
Calvin Cheung 2019-05-17 08:29:55 -07:00
parent e6c52060dc
commit 72dc5721e0
120 changed files with 6325 additions and 862 deletions

View file

@ -34,6 +34,7 @@
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "logging/logMessage.hpp"
#include "memory/dynamicArchive.hpp"
#include "memory/filemap.hpp"
#include "memory/heapShared.inline.hpp"
#include "memory/iterator.inline.hpp"
@ -42,6 +43,7 @@
#include "memory/metaspaceShared.hpp"
#include "memory/oopFactory.hpp"
#include "memory/universe.hpp"
#include "oops/compressedOops.hpp"
#include "oops/compressedOops.inline.hpp"
#include "oops/objArrayOop.hpp"
#include "oops/oop.inline.hpp"
@ -101,7 +103,12 @@ void FileMapInfo::fail_stop(const char *msg, ...) {
void FileMapInfo::fail_continue(const char *msg, ...) {
va_list ap;
va_start(ap, msg);
MetaspaceShared::set_archive_loading_failed();
if (_dynamic_archive_info == NULL) {
MetaspaceShared::set_archive_loading_failed();
} else {
// _dynamic_archive_info has been setup after mapping the base archive
DynamicArchive::disable();
}
if (PrintSharedArchiveAndExit && _validating_shared_path_table) {
// If we are doing PrintSharedArchiveAndExit and some of the classpath entries
// do not validate, we can still continue "limping" to validate the remaining
@ -120,9 +127,15 @@ void FileMapInfo::fail_continue(const char *msg, ...) {
ls.vprint_cr(msg, ap);
}
}
UseSharedSpaces = false;
assert(current_info() != NULL, "singleton must be registered");
current_info()->close();
if (_dynamic_archive_info == NULL) {
UseSharedSpaces = false;
assert(current_info() != NULL, "singleton must be registered");
current_info()->close();
} else {
// We are failing when loading the top archive, but the base archive should
// continue to work.
log_warning(cds, dynamic)("Unable to use shared archive. The top archive failed to load: %s", _dynamic_archive_info->_full_path);
}
}
va_end(ap);
}
@ -159,20 +172,36 @@ template <int N> static void get_header_version(char (&header_version) [N]) {
}
}
FileMapInfo::FileMapInfo() {
assert(_current_info == NULL, "must be singleton"); // not thread safe
_current_info = this;
FileMapInfo::FileMapInfo(bool is_static) {
memset((void*)this, 0, sizeof(FileMapInfo));
_file_offset = 0;
_file_open = false;
_header = (FileMapHeader*)os::malloc(sizeof(FileMapHeader), mtInternal);
_is_static = is_static;
size_t header_size;
if (is_static) {
assert(_current_info == NULL, "must be singleton"); // not thread safe
_current_info = this;
header_size = sizeof(FileMapHeader);
} else {
assert(_dynamic_archive_info == NULL, "must be singleton"); // not thread safe
_dynamic_archive_info = this;
header_size = sizeof(DynamicArchiveHeader);
}
_header = (FileMapHeader*)os::malloc(header_size, mtInternal);
memset((void*)_header, 0, header_size);
_header->_header_size = header_size;
_header->_version = INVALID_CDS_ARCHIVE_VERSION;
_header->_has_platform_or_app_classes = true;
_file_offset = 0;
_file_open = false;
}
FileMapInfo::~FileMapInfo() {
assert(_current_info == this, "must be singleton"); // not thread safe
_current_info = NULL;
if (_is_static) {
assert(_current_info == this, "must be singleton"); // not thread safe
_current_info = NULL;
} else {
assert(_dynamic_archive_info == this, "must be singleton"); // not thread safe
_dynamic_archive_info = NULL;
}
}
void FileMapInfo::populate_header(size_t alignment) {
@ -180,7 +209,11 @@ void FileMapInfo::populate_header(size_t alignment) {
}
void FileMapHeader::populate(FileMapInfo* mapinfo, size_t alignment) {
_magic = CDS_ARCHIVE_MAGIC;
if (DynamicDumpSharedSpaces) {
_magic = CDS_DYNAMIC_ARCHIVE_MAGIC;
} else {
_magic = CDS_ARCHIVE_MAGIC;
}
_version = CURRENT_CDS_ARCHIVE_VERSION;
_alignment = alignment;
_obj_alignment = ObjectAlignmentInBytes;
@ -191,9 +224,7 @@ void FileMapHeader::populate(FileMapInfo* mapinfo, size_t alignment) {
_max_heap_size = MaxHeapSize;
_narrow_klass_base = CompressedKlassPointers::base();
_narrow_klass_shift = CompressedKlassPointers::shift();
_shared_path_table_size = mapinfo->_shared_path_table_size;
_shared_path_table = mapinfo->_shared_path_table;
_shared_path_entry_size = mapinfo->_shared_path_entry_size;
if (HeapShared::is_heap_object_archiving_allowed()) {
_heap_reserved = Universe::heap()->reserved_region();
}
@ -208,6 +239,7 @@ void FileMapHeader::populate(FileMapInfo* mapinfo, size_t alignment) {
ClassLoaderExt::finalize_shared_paths_misc_info();
_app_class_paths_start_index = ClassLoaderExt::app_class_paths_start_index();
_app_module_paths_start_index = ClassLoaderExt::app_module_paths_start_index();
_num_module_paths = ClassLoader::num_module_path_entries();
_max_used_path_index = ClassLoaderExt::max_used_path_index();
_verify_local = BytecodeVerificationLocal;
@ -215,10 +247,13 @@ void FileMapHeader::populate(FileMapInfo* mapinfo, size_t alignment) {
_has_platform_or_app_classes = ClassLoaderExt::has_platform_or_app_classes();
_shared_base_address = SharedBaseAddress;
_allow_archiving_with_java_agent = AllowArchivingWithJavaAgent;
// the following 2 fields will be set in write_header for dynamic archive header
_base_archive_name_size = 0;
_base_archive_is_default = false;
}
void SharedClassPathEntry::init(const char* name, bool is_modules_image, TRAPS) {
assert(DumpSharedSpaces, "dump time only");
assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "dump time only");
_timestamp = 0;
_filesize = 0;
@ -297,6 +332,7 @@ bool SharedClassPathEntry::validate(bool is_class_path) {
// If PrintSharedArchiveAndExit is enabled, don't report failure to the
// caller. Please see above comments for more details.
ok = true;
MetaspaceShared::set_archive_loading_failed();
}
return ok;
}
@ -306,8 +342,27 @@ void SharedClassPathEntry::metaspace_pointers_do(MetaspaceClosure* it) {
it->push(&_manifest);
}
void SharedPathTable::metaspace_pointers_do(MetaspaceClosure* it) {
it->push(&_table);
for (int i=0; i<_size; i++) {
path_at(i)->metaspace_pointers_do(it);
}
}
void SharedPathTable::dumptime_init(ClassLoaderData* loader_data, Thread* THREAD) {
size_t entry_size = sizeof(SharedClassPathEntry);
int num_boot_classpath_entries = ClassLoader::num_boot_classpath_entries();
int num_app_classpath_entries = ClassLoader::num_app_classpath_entries();
int num_module_path_entries = ClassLoader::num_module_path_entries();
int num_entries = num_boot_classpath_entries + num_app_classpath_entries + num_module_path_entries;
size_t bytes = entry_size * num_entries;
_table = MetadataFactory::new_array<u8>(loader_data, (int)(bytes + 7 / 8), THREAD);
_size = num_entries;
}
void FileMapInfo::allocate_shared_path_table() {
assert(DumpSharedSpaces, "Sanity");
assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "Sanity");
Thread* THREAD = Thread::current();
ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
@ -316,16 +371,7 @@ void FileMapInfo::allocate_shared_path_table() {
assert(jrt != NULL,
"No modular java runtime image present when allocating the CDS classpath entry table");
size_t entry_size = sizeof(SharedClassPathEntry); // assert ( should be 8 byte aligned??)
int num_boot_classpath_entries = ClassLoader::num_boot_classpath_entries();
int num_app_classpath_entries = ClassLoader::num_app_classpath_entries();
int num_module_path_entries = ClassLoader::num_module_path_entries();
int num_entries = num_boot_classpath_entries + num_app_classpath_entries + num_module_path_entries;
size_t bytes = entry_size * num_entries;
_shared_path_table = MetadataFactory::new_array<u8>(loader_data, (int)(bytes + 7 / 8), THREAD);
_shared_path_table_size = num_entries;
_shared_path_entry_size = entry_size;
_shared_path_table.dumptime_init(loader_data, THREAD);
// 1. boot class path
int i = 0;
@ -343,7 +389,7 @@ void FileMapInfo::allocate_shared_path_table() {
cpe = ClassLoader::get_next_boot_classpath_entry(cpe);
i++;
}
assert(i == num_boot_classpath_entries,
assert(i == ClassLoader::num_boot_classpath_entries(),
"number of boot class path entry mismatch");
// 2. app class path
@ -369,15 +415,15 @@ void FileMapInfo::allocate_shared_path_table() {
mpe = mpe->next();
i++;
}
assert(i == num_entries, "number of shared path entry mismatch");
assert(i == _shared_path_table.size(), "number of shared path entry mismatch");
}
void FileMapInfo::check_nonempty_dir_in_shared_path_table() {
assert(DumpSharedSpaces, "dump time only");
assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "dump time only");
bool has_nonempty_dir = false;
int last = _shared_path_table_size - 1;
int last = _shared_path_table.size() - 1;
if (last > ClassLoaderExt::max_used_path_index()) {
// no need to check any path beyond max_used_path_index
last = ClassLoaderExt::max_used_path_index();
@ -479,9 +525,29 @@ bool FileMapInfo::validate_shared_path_table() {
assert(UseSharedSpaces, "runtime only");
_validating_shared_path_table = true;
// Load the shared path table info from the archive header
_shared_path_table = _header->_shared_path_table;
_shared_path_entry_size = _header->_shared_path_entry_size;
_shared_path_table_size = _header->_shared_path_table_size;
if (DynamicDumpSharedSpaces) {
// Only support dynamic dumping with the usage of the default CDS archive
// or a simple base archive.
// If the base layer archive contains additional path component besides
// the runtime image and the -cp, dynamic dumping is disabled.
//
// When dynamic archiving is enabled, the _shared_path_table is overwritten
// to include the application path and stored in the top layer archive.
assert(shared_path(0)->is_modules_image(), "first shared_path must be the modules image");
if (_header->_app_class_paths_start_index > 1) {
DynamicDumpSharedSpaces = false;
warning(
"Dynamic archiving is disabled because base layer archive has appended boot classpath");
}
if (_header->_num_module_paths > 0) {
DynamicDumpSharedSpaces = false;
warning(
"Dynamic archiving is disabled because base layer archive has module path");
}
}
int module_paths_start_index = _header->_app_module_paths_start_index;
@ -491,14 +557,18 @@ bool FileMapInfo::validate_shared_path_table() {
if (shared_path(i)->validate()) {
log_info(class, path)("ok");
} else {
assert(!UseSharedSpaces, "UseSharedSpaces should be disabled");
if (_dynamic_archive_info != NULL && _dynamic_archive_info->_is_static) {
assert(!UseSharedSpaces, "UseSharedSpaces should be disabled");
}
return false;
}
} else if (i >= module_paths_start_index) {
if (shared_path(i)->validate(false /* not a class path entry */)) {
log_info(class, path)("ok");
} else {
assert(!UseSharedSpaces, "UseSharedSpaces should be disabled");
if (_dynamic_archive_info != NULL && _dynamic_archive_info->_is_static) {
assert(!UseSharedSpaces, "UseSharedSpaces should be disabled");
}
return false;
}
}
@ -510,18 +580,151 @@ bool FileMapInfo::validate_shared_path_table() {
if (_classpath_entries_for_jvmti != NULL) {
os::free(_classpath_entries_for_jvmti);
}
size_t sz = sizeof(ClassPathEntry*) * _shared_path_table_size;
size_t sz = sizeof(ClassPathEntry*) * get_number_of_shared_paths();
_classpath_entries_for_jvmti = (ClassPathEntry**)os::malloc(sz, mtClass);
memset(_classpath_entries_for_jvmti, 0, sz);
memset((void*)_classpath_entries_for_jvmti, 0, sz);
#endif
return true;
}
bool FileMapInfo::same_files(const char* file1, const char* file2) {
if (strcmp(file1, file2) == 0) {
return true;
}
bool is_same = false;
// if the two paths diff only in case
struct stat st1;
struct stat st2;
int ret1;
int ret2;
ret1 = os::stat(file1, &st1);
ret2 = os::stat(file2, &st2);
if (ret1 < 0 || ret2 < 0) {
// one of the files is invalid. So they are not the same.
is_same = false;
} else if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) {
// different files
is_same = false;
#ifndef _WINDOWS
} else if (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino) {
// same files
is_same = true;
#else
} else if ((st1.st_size == st2.st_size) && (st1.st_ctime == st2.st_ctime) &&
(st1.st_mtime == st2.st_mtime)) {
// same files
is_same = true;
#endif
}
return is_same;
}
bool FileMapInfo::check_archive(const char* archive_name, bool is_static) {
int fd = os::open(archive_name, O_RDONLY | O_BINARY, 0);
if (fd < 0) {
// do not vm_exit_during_initialization here because Arguments::init_shared_archive_paths()
// requires a shared archive name. The open_for_read() function will log a message regarding
// failure in opening a shared archive.
return false;
}
size_t sz = is_static ? sizeof(FileMapHeader) : sizeof(DynamicArchiveHeader);
void* header = os::malloc(sz, mtInternal);
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);
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);
return false;
}
}
os::free(header);
os::close(fd);
return true;
}
bool FileMapInfo::get_base_archive_name_from_header(const char* archive_name,
int* size, char** base_archive_name) {
int fd = os::open(archive_name, O_RDONLY | O_BINARY, 0);
if (fd < 0) {
*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);
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);
return false;
}
if (dynamic_header->_base_archive_is_default) {
*base_archive_name = Arguments::get_default_shared_archive_path();
} else {
// skip over the _paths_misc_info
sz = dynamic_header->_paths_misc_info_size;
lseek(fd, (long)sz, SEEK_CUR);
// read the base archive name
size_t name_size = dynamic_header->_base_archive_name_size;
if (name_size == 0) {
os::free(dynamic_header);
os::close(fd);
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);
return false;
}
}
os::free(dynamic_header);
os::close(fd);
return true;
}
void FileMapInfo::restore_shared_path_table() {
_shared_path_table = _current_info->_header->_shared_path_table;
}
// Read the FileMapInfo information from the file.
bool FileMapInfo::init_from_file(int fd) {
size_t sz = sizeof(FileMapHeader);
bool FileMapInfo::init_from_file(int fd, bool is_static) {
size_t sz = is_static ? sizeof(FileMapHeader) : sizeof(DynamicArchiveHeader);
size_t n = os::read(fd, _header, (unsigned int)sz);
if (n != sz) {
fail_continue("Unable to read the file header.");
@ -531,14 +734,10 @@ bool FileMapInfo::init_from_file(int fd) {
fail_continue("The shared archive file has the wrong version.");
return false;
}
_file_offset = (long)n;
_file_offset = n;
size_t info_size = _header->_paths_misc_info_size;
_paths_misc_info = NEW_C_HEAP_ARRAY_RETURN_NULL(char, info_size, mtClass);
if (_paths_misc_info == NULL) {
fail_continue("Unable to read the file header.");
return false;
}
_paths_misc_info = NEW_C_HEAP_ARRAY(char, info_size, mtClass);
n = os::read(fd, _paths_misc_info, (unsigned int)info_size);
if (n != info_size) {
fail_continue("Unable to read the shared path info header.");
@ -546,29 +745,45 @@ bool FileMapInfo::init_from_file(int fd) {
_paths_misc_info = NULL;
return false;
}
_file_offset += n + _header->_base_archive_name_size; // accounts for the size of _base_archive_name
size_t len = lseek(fd, 0, SEEK_END);
CDSFileMapRegion* si = space_at(MetaspaceShared::last_valid_region);
// The last space might be empty
if (si->_file_offset > len || len - si->_file_offset < si->_used) {
fail_continue("The shared archive file has been truncated.");
return false;
if (is_static) {
if (_header->_magic != CDS_ARCHIVE_MAGIC) {
fail_continue("Incorrect static archive magic number");
return false;
}
// just checking the last region is sufficient since the archive is written
// in sequential order
size_t len = lseek(fd, 0, SEEK_END);
CDSFileMapRegion* si = space_at(MetaspaceShared::last_valid_region);
// The last space might be empty
if (si->_file_offset > len || len - si->_file_offset < si->_used) {
fail_continue("The shared archive file has been truncated.");
return false;
}
SharedBaseAddress = _header->_shared_base_address;
}
_file_offset += (long)n;
SharedBaseAddress = _header->_shared_base_address;
return true;
}
// Read the FileMapInfo information from the file.
bool FileMapInfo::open_for_read() {
_full_path = Arguments::GetSharedArchivePath();
bool FileMapInfo::open_for_read(const char* path) {
if (_file_open) {
return true;
}
if (path == NULL) {
_full_path = Arguments::GetSharedArchivePath();
} else {
_full_path = path;
}
int fd = os::open(_full_path, O_RDONLY | O_BINARY, 0);
if (fd < 0) {
if (errno == ENOENT) {
// Not locating the shared archive is ok.
fail_continue("Specified shared archive not found.");
fail_continue("Specified shared archive not found (%s).", _full_path);
} else {
fail_continue("Failed to open shared archive file (%s).",
os::strerror(errno));
@ -581,11 +796,14 @@ bool FileMapInfo::open_for_read() {
return true;
}
// Write the FileMapInfo information to the file.
void FileMapInfo::open_for_write() {
_full_path = Arguments::GetSharedArchivePath();
void FileMapInfo::open_for_write(const char* path) {
if (path == NULL) {
_full_path = Arguments::GetSharedArchivePath();
} else {
_full_path = path;
}
LogMessage(cds) msg;
if (msg.is_info()) {
msg.info("Dumping shared data to file: ");
@ -593,7 +811,7 @@ void FileMapInfo::open_for_write() {
}
#ifdef _WINDOWS // On Windows, need WRITE permission to remove the file.
chmod(_full_path, _S_IREAD | _S_IWRITE);
chmod(_full_path, _S_IREAD | _S_IWRITE);
#endif
// Use remove() to delete the existing file because, on Unix, this will
@ -617,40 +835,59 @@ void FileMapInfo::write_header() {
_header->_paths_misc_info_size = info_size;
align_file_position();
write_bytes(_header, sizeof(FileMapHeader));
char* base_archive_name = NULL;
if (_header->_magic == CDS_DYNAMIC_ARCHIVE_MAGIC) {
base_archive_name = (char*)Arguments::GetSharedArchivePath();
_header->_base_archive_name_size = (int)strlen(base_archive_name) + 1;
_header->_base_archive_is_default = FLAG_IS_DEFAULT(SharedArchiveFile);
}
assert(is_file_position_aligned(), "must be");
write_bytes(_header, _header->_header_size);
write_bytes(ClassLoader::get_shared_paths_misc_info(), (size_t)info_size);
if (base_archive_name != NULL) {
write_bytes(base_archive_name, (size_t)_header->_base_archive_name_size);
}
align_file_position();
}
// Dump region to file.
// This is called twice for each region during archiving, once before
// the archive file is open (_file_open is false) and once after.
void FileMapInfo::write_region(int region, char* base, size_t size,
bool read_only, bool allow_exec) {
assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "Dump time only");
CDSFileMapRegion* si = space_at(region);
char* target_base = base;
if (DynamicDumpSharedSpaces) {
target_base = DynamicArchive::buffer_to_target(base);
}
if (_file_open) {
guarantee(si->_file_offset == _file_offset, "file offset mismatch.");
log_info(cds)("Shared file region %d: " SIZE_FORMAT_HEX_W(08)
" bytes, addr " INTPTR_FORMAT " file offset " SIZE_FORMAT_HEX_W(08),
region, size, p2i(base), _file_offset);
region, size, p2i(target_base), _file_offset);
} else {
si->_file_offset = _file_offset;
}
if (HeapShared::is_heap_region(region)) {
assert((base - (char*)CompressedOops::base()) % HeapWordSize == 0, "Sanity");
if (base != NULL) {
si->_addr._offset = (intx)CompressedOops::encode_not_null((oop)base);
assert((target_base - (char*)CompressedKlassPointers::base()) % HeapWordSize == 0, "Sanity");
if (target_base != NULL) {
si->_addr._offset = (intx)CompressedOops::encode_not_null((oop)target_base);
} else {
si->_addr._offset = 0;
}
} else {
si->_addr._base = base;
si->_addr._base = target_base;
}
si->_used = size;
si->_read_only = read_only;
si->_allow_exec = allow_exec;
// Use the current 'base' when computing the CRC value and writing out data
si->_crc = ClassLoader::crc32(0, base, (jint)size);
if (base != NULL) {
write_bytes_aligned(base, size);
@ -734,8 +971,7 @@ void FileMapInfo::write_bytes(const void* buffer, size_t nbytes) {
if (_file_open) {
size_t n = os::write(_fd, buffer, (unsigned int)nbytes);
if (n != nbytes) {
// It is dangerous to leave the corrupted shared archive file around,
// close and remove the file. See bug 6372906.
// If the shared archive is corrupted, close it and remove it.
close();
remove(_full_path);
fail_stop("Unable to write to shared archive file.");
@ -744,6 +980,10 @@ void FileMapInfo::write_bytes(const void* buffer, size_t nbytes) {
_file_offset += nbytes;
}
bool FileMapInfo::is_file_position_aligned() const {
return _file_offset == align_up(_file_offset,
os::vm_allocation_granularity());
}
// Align file position to an allocation unit boundary.
@ -843,6 +1083,30 @@ ReservedSpace FileMapInfo::reserve_shared_memory() {
static const char* shared_region_name[] = { "MiscData", "ReadWrite", "ReadOnly", "MiscCode", "OptionalData",
"String1", "String2", "OpenArchive1", "OpenArchive2" };
char* FileMapInfo::map_regions(int regions[], char* saved_base[], size_t len) {
char* prev_top = NULL;
char* curr_base;
char* curr_top;
int i = 0;
for (i = 0; i < (int)len; i++) {
curr_base = map_region(regions[i], &curr_top);
if (curr_base == NULL) {
return NULL;
}
if (i > 0) {
// We require that mc->rw->ro->md->od to be laid out consecutively, with no
// gaps between them. That way, we can ensure that the OS won't be able to
// allocate any new memory spaces inside _shared_metaspace_{base,top}, which
// would mess up the simple comparision in MetaspaceShared::is_in_shared_metaspace().
assert(curr_base == prev_top, "must be");
}
log_info(cds)("Mapped region #%d at base %p top %p", regions[i], curr_base, curr_top);
saved_base[i] = curr_base;
prev_top = curr_top;
}
return curr_top;
}
char* FileMapInfo::map_region(int i, char** top_ret) {
assert(!HeapShared::is_heap_region(i), "sanity");
CDSFileMapRegion* si = space_at(i);
@ -869,6 +1133,7 @@ char* FileMapInfo::map_region(int i, char** top_ret) {
si->_allow_exec);
if (base == NULL || base != requested_addr) {
fail_continue("Unable to map %s shared space at required address.", shared_region_name[i]);
_memory_mapping_failed = true;
return NULL;
}
#ifdef _WINDOWS
@ -885,6 +1150,18 @@ char* FileMapInfo::map_region(int i, char** top_ret) {
return base;
}
size_t FileMapInfo::read_bytes(void* buffer, size_t count) {
assert(_file_open, "Archive file is not open");
size_t n = os::read(_fd, buffer, (unsigned int)count);
if (n != count) {
// Close the file if there's a problem reading it.
close();
return 0;
}
_file_offset += count;
return count;
}
address FileMapInfo::decode_start_address(CDSFileMapRegion* spc, bool with_current_oop_encoding_mode) {
if (with_current_oop_encoding_mode) {
return (address)CompressedOops::decode_not_null(offset_of_space(spc));
@ -1126,13 +1403,13 @@ bool FileMapInfo::map_heap_data(MemRegion **heap_mem, int first,
p2i(addr), regions[i].byte_size());
return false;
}
}
if (!verify_mapped_heap_regions(first, region_num)) {
// dealloc the regions from java heap
dealloc_archive_heap_regions(regions, region_num, is_open_archive);
log_info(cds)("UseSharedSpaces: mapped heap regions are corrupt");
return false;
if (VerifySharedSpaces && !region_crc_check(addr, regions[i].byte_size(), si->_crc)) {
// dealloc the regions from java heap
dealloc_archive_heap_regions(regions, region_num, is_open_archive);
log_info(cds)("UseSharedSpaces: mapped heap regions are corrupt");
return false;
}
}
// the shared heap data is mapped successfully
@ -1141,18 +1418,6 @@ bool FileMapInfo::map_heap_data(MemRegion **heap_mem, int first,
return true;
}
bool FileMapInfo::verify_mapped_heap_regions(int first, int num) {
assert(num > 0, "sanity");
if (VerifySharedSpaces) {
for (int i = first; i < first + num; i++) {
if (!verify_region_checksum(i)) {
return false;
}
}
}
return true;
}
void FileMapInfo::patch_archived_heap_embedded_pointers() {
if (!_heap_pointers_need_patching) {
return;
@ -1205,6 +1470,15 @@ void FileMapInfo::dealloc_archive_heap_regions(MemRegion* regions, int num, bool
}
#endif // INCLUDE_CDS_JAVA_HEAP
bool FileMapInfo::region_crc_check(char* buf, size_t size, int expected_crc) {
int crc = ClassLoader::crc32(0, buf, (jint)size);
if (crc != expected_crc) {
fail_continue("Checksum verification failed.");
return false;
}
return true;
}
bool FileMapInfo::verify_region_checksum(int i) {
assert(VerifySharedSpaces, "sanity");
@ -1213,19 +1487,16 @@ bool FileMapInfo::verify_region_checksum(int i) {
if (sz == 0) {
return true; // no data
}
if ((HeapShared::is_closed_archive_heap_region(i) &&
!HeapShared::closed_archive_heap_region_mapped()) ||
(HeapShared::is_open_archive_heap_region(i) &&
!HeapShared::open_archive_heap_region_mapped())) {
return true; // archived heap data is not mapped
return region_crc_check(region_addr(i), sz, space_at(i)->_crc);
}
void FileMapInfo::unmap_regions(int regions[], char* saved_base[], size_t len) {
for (int i = 0; i < (int)len; i++) {
if (saved_base[i] != NULL) {
unmap_region(regions[i]);
}
}
const char* buf = region_addr(i);
int crc = ClassLoader::crc32(0, buf, (jint)sz);
if (crc != space_at(i)->_crc) {
fail_continue("Checksum verification failed.");
return false;
}
return true;
}
// Unmap a memory region in the address space.
@ -1253,19 +1524,15 @@ void FileMapInfo::assert_mark(bool check) {
}
void FileMapInfo::metaspace_pointers_do(MetaspaceClosure* it) {
it->push(&_shared_path_table);
for (int i=0; i<_shared_path_table_size; i++) {
shared_path(i)->metaspace_pointers_do(it);
}
_shared_path_table.metaspace_pointers_do(it);
}
FileMapInfo* FileMapInfo::_current_info = NULL;
FileMapInfo* FileMapInfo::_dynamic_archive_info = NULL;
bool FileMapInfo::_heap_pointers_need_patching = false;
Array<u8>* FileMapInfo::_shared_path_table = NULL;
int FileMapInfo::_shared_path_table_size = 0;
size_t FileMapInfo::_shared_path_entry_size = 0x1234baad;
SharedPathTable FileMapInfo::_shared_path_table;
bool FileMapInfo::_validating_shared_path_table = false;
bool FileMapInfo::_memory_mapping_failed = false;
// Open the shared archive file, read and validate the header
// information (version, boot classpath, etc.). If initialization
@ -1277,7 +1544,7 @@ bool FileMapInfo::_validating_shared_path_table = false;
// [1] validate_header() - done here. This checks the header, including _paths_misc_info.
// [2] validate_shared_path_table - this is done later, because the table is in the RW
// region of the archive, which is not mapped yet.
bool FileMapInfo::initialize() {
bool FileMapInfo::initialize(bool is_static) {
assert(UseSharedSpaces, "UseSharedSpaces expected.");
if (JvmtiExport::should_post_class_file_load_hook() && JvmtiExport::has_early_class_hook_env()) {
@ -1293,8 +1560,8 @@ bool FileMapInfo::initialize() {
return false;
}
init_from_file(_fd);
if (!validate_header()) {
init_from_file(_fd, is_static);
if (!validate_header(is_static)) {
return false;
}
return true;
@ -1315,7 +1582,7 @@ int FileMapHeader::compute_crc() {
char* start = (char*)this;
// start computing from the field after _crc
char* buf = (char*)&_crc + sizeof(_crc);
size_t sz = sizeof(FileMapHeader) - (buf - start);
size_t sz = _header_size - (buf - start);
int crc = ClassLoader::crc32(0, buf, (jint)sz);
return crc;
}
@ -1336,7 +1603,7 @@ bool FileMapHeader::validate() {
FileMapInfo::fail_continue("The shared archive file is the wrong version.");
return false;
}
if (_magic != CDS_ARCHIVE_MAGIC) {
if (_magic != CDS_ARCHIVE_MAGIC && _magic != CDS_DYNAMIC_ARCHIVE_MAGIC) {
FileMapInfo::fail_continue("The shared archive file has a bad magic number.");
return false;
}
@ -1401,11 +1668,11 @@ bool FileMapHeader::validate() {
return true;
}
bool FileMapInfo::validate_header() {
bool FileMapInfo::validate_header(bool is_static) {
bool status = _header->validate();
if (status) {
if (!ClassLoader::check_shared_paths_misc_info(_paths_misc_info, _header->_paths_misc_info_size)) {
if (!ClassLoader::check_shared_paths_misc_info(_paths_misc_info, _header->_paths_misc_info_size, is_static)) {
if (!PrintSharedArchiveAndExit) {
fail_continue("shared class paths mismatch (hint: enable -Xlog:class+path=info to diagnose the failure)");
status = false;
@ -1435,7 +1702,7 @@ bool FileMapInfo::is_in_shared_region(const void* p, int idx) {
// Unmap mapped regions of shared space.
void FileMapInfo::stop_sharing_and_unmap(const char* msg) {
MetaspaceObj::set_shared_metaspace_range(NULL, NULL);
MetaspaceShared::set_shared_metaspace_range(NULL, NULL);
FileMapInfo *map_info = FileMapInfo::current_info();
if (map_info) {
@ -1502,7 +1769,7 @@ ClassPathEntry* FileMapInfo::get_classpath_entry_for_jvmti(int i, TRAPS) {
ClassFileStream* FileMapInfo::open_stream_for_jvmti(InstanceKlass* ik, Handle class_loader, TRAPS) {
int path_index = ik->shared_classpath_index();
assert(path_index >= 0, "should be called for shared built-in classes only");
assert(path_index < (int)_shared_path_table_size, "sanity");
assert(path_index < (int)get_number_of_shared_paths(), "sanity");
ClassPathEntry* cpe = get_classpath_entry_for_jvmti(path_index, CHECK_NULL);
assert(cpe != NULL, "must be");