--- a/src/hotspot/share/memory/filemap.cpp Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/memory/filemap.cpp Fri May 17 08:29:55 2019 -0700
@@ -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_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 @@
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 @@
}
}
-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));
+ _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;
- _header = (FileMapHeader*)os::malloc(sizeof(FileMapHeader), mtInternal);
- _header->_version = INVALID_CDS_ARCHIVE_VERSION;
- _header->_has_platform_or_app_classes = true;
}
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 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 @@
_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 @@
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 @@
_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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
_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 @@
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 @@
}
#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 @@
_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 @@
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 @@
_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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
#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 @@
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::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 @@
// [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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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");