diff --git a/src/hotspot/share/cds/archiveUtils.cpp b/src/hotspot/share/cds/archiveUtils.cpp index 4622a27cbec..430de362f9b 100644 --- a/src/hotspot/share/cds/archiveUtils.cpp +++ b/src/hotspot/share/cds/archiveUtils.cpp @@ -320,9 +320,8 @@ void WriteClosure::do_ptr(void** p) { void ReadClosure::do_ptr(void** p) { assert(*p == nullptr, "initializing previous initialized pointer."); intptr_t obj = nextPtr(); - assert((intptr_t)obj >= 0 || (intptr_t)obj < -100, - "hit tag while initializing ptrs."); - *p = (void*)obj != nullptr ? (void*)(SharedBaseAddress + obj) : (void*)obj; + assert(obj >= 0, "sanity."); + *p = (obj != 0) ? (void*)(_base_address + obj) : (void*)obj; } void ReadClosure::do_u4(u4* p) { diff --git a/src/hotspot/share/cds/archiveUtils.hpp b/src/hotspot/share/cds/archiveUtils.hpp index 410b0b84001..f00895078ef 100644 --- a/src/hotspot/share/cds/archiveUtils.hpp +++ b/src/hotspot/share/cds/archiveUtils.hpp @@ -230,13 +230,14 @@ public: class ReadClosure : public SerializeClosure { private: intptr_t** _ptr_array; - + intptr_t _base_address; inline intptr_t nextPtr() { return *(*_ptr_array)++; } public: - ReadClosure(intptr_t** ptr_array) { _ptr_array = ptr_array; } + ReadClosure(intptr_t** ptr_array, intptr_t base_address) : + _ptr_array(ptr_array), _base_address(base_address) {} void do_ptr(void** p); void do_u4(u4* p); diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index 223791cdd36..469f93d1e0c 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -274,6 +274,7 @@ void FileMapHeader::print(outputStream* st) { st->print_cr("- compressed_oops: %d", _compressed_oops); st->print_cr("- compressed_class_ptrs: %d", _compressed_class_ptrs); st->print_cr("- cloned_vtables_offset: " SIZE_FORMAT_X, _cloned_vtables_offset); + st->print_cr("- early_serialized_data_offset: " SIZE_FORMAT_X, _early_serialized_data_offset); st->print_cr("- serialized_data_offset: " SIZE_FORMAT_X, _serialized_data_offset); st->print_cr("- jvm_ident: %s", _jvm_ident); st->print_cr("- shared_path_table_offset: " SIZE_FORMAT_X, _shared_path_table_offset); diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp index f7c2e9c19de..f3aa389c30e 100644 --- a/src/hotspot/share/cds/filemap.hpp +++ b/src/hotspot/share/cds/filemap.hpp @@ -193,6 +193,7 @@ private: bool _compressed_oops; // save the flag UseCompressedOops bool _compressed_class_ptrs; // save the flag UseCompressedClassPointers size_t _cloned_vtables_offset; // The address of the first cloned vtable + size_t _early_serialized_data_offset; // Data accessed using {ReadClosure,WriteClosure}::serialize() size_t _serialized_data_offset; // Data accessed using {ReadClosure,WriteClosure}::serialize() bool _has_non_jar_in_classpath; // non-jar file entry exists in classpath unsigned int _common_app_classpath_prefix_size; // size of the common prefix of app class paths @@ -261,6 +262,7 @@ public: uintx max_heap_size() const { return _max_heap_size; } CompressedOops::Mode narrow_oop_mode() const { return _narrow_oop_mode; } char* cloned_vtables() const { return from_mapped_offset(_cloned_vtables_offset); } + char* early_serialized_data() const { return from_mapped_offset(_early_serialized_data_offset); } char* serialized_data() const { return from_mapped_offset(_serialized_data_offset); } const char* jvm_ident() const { return _jvm_ident; } char* requested_base_address() const { return _requested_base_address; } @@ -283,6 +285,7 @@ public: void set_has_platform_or_app_classes(bool v) { _has_platform_or_app_classes = v; } void set_cloned_vtables(char* p) { set_as_offset(p, &_cloned_vtables_offset); } + void set_early_serialized_data(char* p) { set_as_offset(p, &_early_serialized_data_offset); } void set_serialized_data(char* p) { set_as_offset(p, &_serialized_data_offset); } void set_mapped_base_address(char* p) { _mapped_base_address = p; } void set_heap_root_segments(HeapRootSegments segments) { _heap_root_segments = segments; } @@ -396,6 +399,8 @@ public: char* cloned_vtables() const { return header()->cloned_vtables(); } void set_cloned_vtables(char* p) const { header()->set_cloned_vtables(p); } + char* early_serialized_data() const { return header()->early_serialized_data(); } + void set_early_serialized_data(char* p) const { header()->set_early_serialized_data(p); } char* serialized_data() const { return header()->serialized_data(); } void set_serialized_data(char* p) const { header()->set_serialized_data(p); } diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index 2a43fd2dd4f..1d17fb7cfe3 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -359,8 +359,43 @@ void MetaspaceShared::read_extra_data(JavaThread* current, const char* filename) } } -// Read/write a data stream for restoring/preserving metadata pointers and -// miscellaneous data from/to the shared archive file. +// About "serialize" -- +// +// This is (probably a badly named) way to read/write a data stream of pointers and +// miscellaneous data from/to the shared archive file. The usual code looks like this: +// +// // These two global C++ variables are initialized during dump time. +// static int _archived_int; +// static MetaspaceObj* archived_ptr; +// +// void MyClass::serialize(SerializeClosure* soc) { +// soc->do_int(&_archived_int); +// soc->do_int(&_archived_ptr); +// } +// +// At dumptime, these two variables are stored into the CDS archive. +// At runtime, these two variables are loaded from the CDS archive. +// In addition, the pointer is relocated as necessary. +// +// Some of the xxx::serialize() functions may have side effects and assume that +// the archive is already mapped. For example, SymbolTable::serialize_shared_table_header() +// unconditionally makes the set of archived symbols available. Therefore, we put most +// of these xxx::serialize() functions inside MetaspaceShared::serialize(), which +// is called AFTER we made the decision to map the archive. +// +// However, some of the "serialized" data are used to decide whether an archive should +// be mapped or not (e.g., for checking if the -Djdk.module.main property is compatible +// with the archive). The xxx::serialize() functions for these data must be put inside +// MetaspaceShared::early_serialize(). Such functions must not produce side effects that +// assume we will always decides to map the archive. + +void MetaspaceShared::early_serialize(SerializeClosure* soc) { + int tag = 0; + soc->do_tag(--tag); + CDS_JAVA_HEAP_ONLY(Modules::serialize(soc);) + CDS_JAVA_HEAP_ONLY(Modules::serialize_addmods_names(soc);) + soc->do_tag(666); +} void MetaspaceShared::serialize(SerializeClosure* soc) { int tag = 0; @@ -402,8 +437,6 @@ void MetaspaceShared::serialize(SerializeClosure* soc) { SystemDictionaryShared::serialize_vm_classes(soc); soc->do_tag(--tag); - CDS_JAVA_HEAP_ONLY(Modules::serialize(soc);) - CDS_JAVA_HEAP_ONLY(Modules::serialize_addmods_names(soc);) CDS_JAVA_HEAP_ONLY(ClassLoaderDataShared::serialize(soc);) LambdaFormInvokers::serialize(soc); @@ -455,6 +488,7 @@ private: log_info(cds)("Dumping symbol table ..."); SymbolTable::write_to_archive(symbols); } + char* dump_early_read_only_tables(); char* dump_read_only_tables(); public: @@ -494,6 +528,21 @@ public: } }; +char* VM_PopulateDumpSharedSpace::dump_early_read_only_tables() { + ArchiveBuilder::OtherROAllocMark mark; + + // Write module name into archive + CDS_JAVA_HEAP_ONLY(Modules::dump_main_module_name();) + // Write module names from --add-modules into archive + CDS_JAVA_HEAP_ONLY(Modules::dump_addmods_names();) + + DumpRegion* ro_region = ArchiveBuilder::current()->ro_region(); + char* start = ro_region->top(); + WriteClosure wc(ro_region); + MetaspaceShared::early_serialize(&wc); + return start; +} + char* VM_PopulateDumpSharedSpace::dump_read_only_tables() { ArchiveBuilder::OtherROAllocMark mark; @@ -501,10 +550,7 @@ char* VM_PopulateDumpSharedSpace::dump_read_only_tables() { // Write lambform lines into archive LambdaFormInvokers::dump_static_archive_invokers(); - // Write module name into archive - CDS_JAVA_HEAP_ONLY(Modules::dump_main_module_name();) - // Write module names from --add-modules into archive - CDS_JAVA_HEAP_ONLY(Modules::dump_addmods_names();) + // Write the other data to the output array. DumpRegion* ro_region = ArchiveBuilder::current()->ro_region(); char* start = ro_region->top(); @@ -543,6 +589,7 @@ void VM_PopulateDumpSharedSpace::doit() { log_info(cds)("Make classes shareable"); _builder.make_klasses_shareable(); + char* early_serialized_data = dump_early_read_only_tables(); char* serialized_data = dump_read_only_tables(); SystemDictionaryShared::adjust_lambda_proxy_class_dictionary(); @@ -556,6 +603,7 @@ void VM_PopulateDumpSharedSpace::doit() { assert(static_archive != nullptr, "SharedArchiveFile not set?"); _map_info = new FileMapInfo(static_archive, true); _map_info->populate_header(MetaspaceShared::core_region_alignment()); + _map_info->set_early_serialized_data(early_serialized_data); _map_info->set_serialized_data(serialized_data); _map_info->set_cloned_vtables(CppVtables::vtables_serialized_base()); } @@ -1473,6 +1521,14 @@ MapArchiveResult MetaspaceShared::map_archive(FileMapInfo* mapinfo, char* mapped return MAP_ARCHIVE_OTHER_FAILURE; } + if (mapinfo->is_static()) { + // Currently, only static archive uses early serialized data. + char* buffer = mapinfo->early_serialized_data(); + intptr_t* array = (intptr_t*)buffer; + ReadClosure rc(&array, (intptr_t)mapped_base_address); + early_serialize(&rc); + } + mapinfo->set_is_mapped(true); return MAP_ARCHIVE_SUCCESS; } @@ -1509,7 +1565,7 @@ void MetaspaceShared::initialize_shared_spaces() { // shared string/symbol tables. char* buffer = static_mapinfo->serialized_data(); intptr_t* array = (intptr_t*)buffer; - ReadClosure rc(&array); + ReadClosure rc(&array, (intptr_t)SharedBaseAddress); serialize(&rc); // Finish up archived heap initialization. These must be @@ -1526,7 +1582,7 @@ void MetaspaceShared::initialize_shared_spaces() { FileMapInfo *dynamic_mapinfo = FileMapInfo::dynamic_info(); if (dynamic_mapinfo != nullptr) { intptr_t* buffer = (intptr_t*)dynamic_mapinfo->serialized_data(); - ReadClosure rc(&buffer); + ReadClosure rc(&buffer, (intptr_t)SharedBaseAddress); ArchiveBuilder::serialize_dynamic_archivable_items(&rc); DynamicArchive::setup_array_klasses(); dynamic_mapinfo->close(); diff --git a/src/hotspot/share/cds/metaspaceShared.hpp b/src/hotspot/share/cds/metaspaceShared.hpp index ecc158cc3ef..0b4f6f2ecd4 100644 --- a/src/hotspot/share/cds/metaspaceShared.hpp +++ b/src/hotspot/share/cds/metaspaceShared.hpp @@ -111,6 +111,7 @@ public: static void unrecoverable_writing_error(const char* message = nullptr); static void writing_error(const char* message = nullptr); + static void early_serialize(SerializeClosure* sc) NOT_CDS_RETURN; static void serialize(SerializeClosure* sc) NOT_CDS_RETURN; // JVM/TI RedefineClasses() support: diff --git a/src/hotspot/share/classfile/modules.cpp b/src/hotspot/share/classfile/modules.cpp index 94e407d045f..2a8f8bd2424 100644 --- a/src/hotspot/share/classfile/modules.cpp +++ b/src/hotspot/share/classfile/modules.cpp @@ -599,6 +599,9 @@ void Modules::serialize(SerializeClosure* soc) { } log_info(cds)("optimized module handling: %s", CDSConfig::is_using_optimized_module_handling() ? "enabled" : "disabled"); log_info(cds)("full module graph: %s", CDSConfig::is_using_full_module_graph() ? "enabled" : "disabled"); + + // Don't hold onto the pointer, in case we might decide to unmap the archive. + _archived_main_module_name = nullptr; } } @@ -641,6 +644,9 @@ void Modules::serialize_addmods_names(SerializeClosure* soc) { } log_info(cds)("optimized module handling: %s", CDSConfig::is_using_optimized_module_handling() ? "enabled" : "disabled"); log_info(cds)("full module graph: %s", CDSConfig::is_using_full_module_graph() ? "enabled" : "disabled"); + + // Don't hold onto the pointer, in case we might decide to unmap the archive. + _archived_addmods_names = nullptr; } }