diff --git a/8202951-Support-default-jsa.patch b/8202951-Support-default-jsa.patch new file mode 100644 index 0000000000000000000000000000000000000000..0724ff1c97e131598afaf47223b5bafdff75b8fe --- /dev/null +++ b/8202951-Support-default-jsa.patch @@ -0,0 +1,1394 @@ +From 49f7ef8df4cade226de5754172e208975343967c Mon Sep 17 00:00:00 2001 +Date: Sat, 3 Sep 2022 14:25:50 +0000 +Subject: 8202951-Support-default-jsa + +--- + common/autoconf/configure.ac | 3 + + common/autoconf/generated-configure.sh | 40 +++++ + common/autoconf/jdk-options.m4 | 32 ++++ + common/autoconf/spec.gmk.in | 4 + + common/bin/compare.sh | 1 + + hotspot/src/share/vm/cds/archiveBuilder.cpp | 34 +++- + hotspot/src/share/vm/cds/archiveBuilder.hpp | 4 + + hotspot/src/share/vm/cds/dynamicArchive.cpp | 1 + + .../src/share/vm/classfile/classLoader.cpp | 152 +++++++++++++++++- + .../src/share/vm/classfile/classLoader.hpp | 15 +- + .../share/vm/classfile/classLoaderData.hpp | 1 + + hotspot/src/share/vm/classfile/dictionary.cpp | 2 +- + .../vm/classfile/sharedPathsMiscInfo.hpp | 13 +- + .../vm/classfile/systemDictionaryShared.cpp | 2 +- + hotspot/src/share/vm/memory/filemap.cpp | 34 +++- + hotspot/src/share/vm/memory/filemap.hpp | 7 + + hotspot/src/share/vm/memory/metachunk.hpp | 2 + + hotspot/src/share/vm/memory/metaspace.cpp | 14 ++ + hotspot/src/share/vm/memory/metaspace.hpp | 2 + + .../src/share/vm/memory/metaspaceShared.cpp | 22 +++ + .../src/share/vm/memory/metaspaceShared.hpp | 5 +- + hotspot/src/share/vm/oops/instanceKlass.cpp | 5 +- + hotspot/src/share/vm/runtime/arguments.cpp | 34 ++-- + hotspot/src/share/vm/runtime/arguments.hpp | 6 + + hotspot/src/share/vm/utilities/hashtable.cpp | 1 + + hotspot/test/runtime/appcds/TestCommon.java | 74 ++++++++- + .../appcds/dynamicArchive/DynamicFlag.java | 39 +++++ + .../dynamicArchive/DynamicHelloTest.java | 42 +++++ + .../VerifyWithDynamicArchive.java | 42 +++++ + jdk/make/BuildJdk.gmk | 7 + + 30 files changed, 603 insertions(+), 37 deletions(-) + create mode 100644 hotspot/test/runtime/appcds/dynamicArchive/DynamicFlag.java + create mode 100644 hotspot/test/runtime/appcds/dynamicArchive/DynamicHelloTest.java + create mode 100644 hotspot/test/runtime/appcds/dynamicArchive/VerifyWithDynamicArchive.java + +diff --git a/common/autoconf/configure.ac b/common/autoconf/configure.ac +index 151e5a10..dbcdd59e 100644 +--- a/common/autoconf/configure.ac ++++ b/common/autoconf/configure.ac +@@ -98,6 +98,9 @@ JDKOPT_SETUP_JVM_INTERPRETER + JDKOPT_SETUP_JVM_VARIANTS + JDKOPT_SETUP_DEBUG_LEVEL + ++# Enable default CDS ARCHIVE ++JDKOPT_ENABLE_DISABLE_CDS_ARCHIVE ++ + # With basic setup done, call the custom early hook. + CUSTOM_EARLY_HOOK + +diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh +index c41c4336..f0e49f50 100644 +--- a/common/autoconf/generated-configure.sh ++++ b/common/autoconf/generated-configure.sh +@@ -883,6 +883,7 @@ OUTPUT_ROOT + CONF_NAME + SPEC + DEVKIT_LIB_DIR ++BUILD_CDS_ARCHIVE + BUILD_VARIANT_RELEASE + DEBUG_CLASSFILES + FASTDEBUG +@@ -1047,6 +1048,7 @@ with_jvm_interpreter + with_jvm_variants + enable_debug + with_debug_level ++enable_cds_archive + with_devkit + with_sys_root + with_sysroot +@@ -1857,6 +1859,8 @@ Optional Features: + [disabled] + --enable-debug set the debug level to fastdebug (shorthand for + --with-debug-level=fastdebug) [disabled] ++ --disable-cds-archive Set to disable generation of a default CDS archive ++ in the product image [enabled] + --disable-headful disable building headful support (graphical UI + support) [enabled] + --enable-hotspot-test-in-build +@@ -14704,6 +14708,42 @@ fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DEBUG_LEVEL" >&5 + $as_echo "$DEBUG_LEVEL" >&6; } + ++ ++ ++# Enable default CDS ARCHIVE ++ ++ # Check whether --enable-cds-archive was given. ++if test "${enable_cds_archive+set}" = set; then : ++ enableval=$enable_cds_archive; ++fi ++ ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if a default CDS archive should be generated" >&5 ++$as_echo_n "checking if a default CDS archive should be generated... " >&6; } ++ if test "x$COMPILE_TYPE" = "xcross"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, not possible with cross compilation" >&5 ++$as_echo "no, not possible with cross compilation" >&6; } ++ BUILD_CDS_ARCHIVE="false" ++ elif test "x$enable_cds_archive" = "xyes"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, forced" >&5 ++$as_echo "yes, forced" >&6; } ++ BUILD_CDS_ARCHIVE="true" ++ elif test "x$enable_cds_archive" = "x"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 ++$as_echo "yes" >&6; } ++ BUILD_CDS_ARCHIVE="true" ++ elif test "x$enable_cds_archive" = "xno"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, forced" >&5 ++$as_echo "no, forced" >&6; } ++ BUILD_CDS_ARCHIVE="false" ++ else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++ as_fn_error $? "--enable-cds_archive can only be yes/no or empty" "$LINENO" 5 ++ fi ++ ++ ++ + if test "x$DEBUG_LEVEL" != xrelease && \ + test "x$DEBUG_LEVEL" != xfastdebug && \ + test "x$DEBUG_LEVEL" != xslowdebug; then +diff --git a/common/autoconf/jdk-options.m4 b/common/autoconf/jdk-options.m4 +index bca78afe..c506086d 100644 +--- a/common/autoconf/jdk-options.m4 ++++ b/common/autoconf/jdk-options.m4 +@@ -789,6 +789,38 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_SYMBOLS], + AC_SUBST(ZIP_DEBUGINFO_FILES) + ]) + ++################################################################################ ++# ++# Disable the default CDS archive generation ++# cross compilation - disabled ++# ++AC_DEFUN_ONCE([JDKOPT_ENABLE_DISABLE_CDS_ARCHIVE], ++[ ++ AC_ARG_ENABLE([cds-archive], [AS_HELP_STRING([--disable-cds-archive], ++ [Set to disable generation of a default CDS archive in the product image @<:@enabled@:>@])]) ++ ++ AC_MSG_CHECKING([if a default CDS archive should be generated]) ++ if test "x$COMPILE_TYPE" = "xcross"; then ++ AC_MSG_RESULT([no, not possible with cross compilation]) ++ BUILD_CDS_ARCHIVE="false" ++ elif test "x$enable_cds_archive" = "xyes"; then ++ AC_MSG_RESULT([yes, forced]) ++ BUILD_CDS_ARCHIVE="true" ++ elif test "x$enable_cds_archive" = "x"; then ++ AC_MSG_RESULT([yes]) ++ BUILD_CDS_ARCHIVE="true" ++ elif test "x$enable_cds_archive" = "xno"; then ++ AC_MSG_RESULT([no, forced]) ++ BUILD_CDS_ARCHIVE="false" ++ else ++ AC_MSG_RESULT([no]) ++ AC_MSG_ERROR([--enable-cds_archive can only be yes/no or empty]) ++ fi ++ ++ AC_SUBST(BUILD_CDS_ARCHIVE) ++]) ++ ++ + # Support for customization of the build process. Some build files + # will include counterparts from this location, if they exist. This allows + # for a degree of customization of the build targets and the rules/recipes +diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in +index 4c3a9f61..79248cbf 100644 +--- a/common/autoconf/spec.gmk.in ++++ b/common/autoconf/spec.gmk.in +@@ -611,6 +611,10 @@ LIBZIP_CAN_USE_MMAP:=@LIBZIP_CAN_USE_MMAP@ + MSVCR_DLL:=@MSVCR_DLL@ + MSVCP_DLL:=@MSVCP_DLL@ + UCRT_DLL_DIR:=@UCRT_DLL_DIR@ ++# CDS_ARCHIVE ++BUILD_CDS_ARCHIVE:=@BUILD_CDS_ARCHIVE@ ++ ++ + + + # ADD_SRCS takes a single argument with source roots +diff --git a/common/bin/compare.sh b/common/bin/compare.sh +index ff88bb1f..a36464a9 100644 +--- a/common/bin/compare.sh ++++ b/common/bin/compare.sh +@@ -290,6 +290,7 @@ compare_general_files() { + ! -name "ct.sym" ! -name "*.diz" ! -name "*.dll" \ + ! -name "*.pdb" ! -name "*.exp" ! -name "*.ilk" \ + ! -name "*.lib" ! -name "*.war" ! -name "JavaControlPanel" \ ++ ! -name "classes.jsa" \ + | $GREP -v "./bin/" | $SORT | $FILTER) + + echo General files... +diff --git a/hotspot/src/share/vm/cds/archiveBuilder.cpp b/hotspot/src/share/vm/cds/archiveBuilder.cpp +index 144dedfa..13a62002 100644 +--- a/hotspot/src/share/vm/cds/archiveBuilder.cpp ++++ b/hotspot/src/share/vm/cds/archiveBuilder.cpp +@@ -59,6 +59,18 @@ ArchiveBuilder::SourceObjList::~SourceObjList() { + delete _objs; + } + ++static void caculate_fingerprint(Klass * klass) { ++ if (klass->oop_is_instance()) { ++ InstanceKlass* ik = InstanceKlass::cast(klass); ++ for (int i = 0; i < ik->methods()->length(); i++) { ++ Method* m = ik->methods()->at(i); ++ Fingerprinter fp(m); ++ // The side effect of this call sets method's fingerprint field. ++ fp.fingerprint(); ++ } ++ } ++} ++ + void ArchiveBuilder::SourceObjList::append(MetaspaceClosure::Ref* enclosing_ref, SourceObjInfo* src_info) { + // Save this source object for copying + _objs->append(src_info); +@@ -166,6 +178,7 @@ ArchiveBuilder::ArchiveBuilder() : + _buffer_to_requested_delta(0), + _rw_region("rw", MAX_SHARED_DELTA), + _ro_region("ro", MAX_SHARED_DELTA), ++ _md_region("md", MAX_SHARED_DELTA), + _rw_src_objs(), + _ro_src_objs(), + _src_obj_table(INITIAL_TABLE_SIZE), +@@ -384,6 +397,7 @@ bool ArchiveBuilder::gather_klass_and_symbol(MetaspaceClosure::Ref* ref, bool re + Klass* klass = (Klass*)ref->obj(); + assert(klass->is_klass(), "must be"); + if (!is_excluded(klass)) { ++ caculate_fingerprint(klass); + _klasses->append(klass); + if (klass->oop_is_instance()) { + _num_instance_klasses ++; +@@ -434,7 +448,8 @@ size_t ArchiveBuilder::estimate_archive_size() { + + address ArchiveBuilder::reserve_buffer() { + size_t buffer_size = estimate_archive_size(); +- ReservedSpace rs(buffer_size, os::vm_allocation_granularity(), false); ++ size_t package_hash_table_est = align_up(ClassLoader::estimate_size_for_archive(), (size_t)os::vm_allocation_granularity()); ++ ReservedSpace rs(buffer_size + package_hash_table_est, os::vm_allocation_granularity(), false); + if (!rs.is_reserved()) { + tty->print_cr("Failed to reserve " SIZE_FORMAT " bytes of output buffer.", buffer_size); + vm_direct_exit(0); +@@ -443,7 +458,8 @@ address ArchiveBuilder::reserve_buffer() { + // buffer_bottom is the lowest address of the 2 core regions (rw, ro) when + // we are copying the class metadata into the buffer. + address buffer_bottom = (address)rs.base(); +- _shared_rs = rs; ++ _shared_rs = rs.first_part(buffer_size); ++ _md_rs = rs.last_part(buffer_size); + + _buffer_bottom = buffer_bottom; + _last_verified_top = buffer_bottom; +@@ -508,6 +524,19 @@ void ArchiveBuilder::dump_ro_metadata() { + make_shallow_copies(&_ro_region, &_ro_src_objs); + } + ++void ArchiveBuilder::dump_md_metadata() { ++ ResourceMark rm; ++ if (InfoDynamicCDS) { ++ dynamic_cds_log->print_cr("Allocating MD objects ... "); ++ } ++ _current_dump_space = &_md_region; ++ _md_region.init(&_md_rs, &_md_vs); ++ char* md_top = _md_vs.low(); ++ char* md_end = _md_vs.high_boundary(); ++ _md_region.allocate(md_end - md_top); ++ ClassLoader::serialize_package_hash_table(&md_top, md_end); ++} ++ + void ArchiveBuilder::start_dump_space(DumpRegion* next) { + address bottom = _last_verified_top; + address top = (address)(_current_dump_space->top()); +@@ -749,6 +778,7 @@ void ArchiveBuilder::write_archive(FileMapInfo* mapinfo) { + + write_region(mapinfo, MetaspaceShared::d_rw, &_rw_region, /*read_only=*/false,/*allow_exec=*/false); + write_region(mapinfo, MetaspaceShared::d_ro, &_ro_region, /*read_only=*/true, /*allow_exec=*/false); ++ write_region(mapinfo, MetaspaceShared::d_md, &_md_region, /*read_only=*/true, /*allow_exec=*/false); + + char* bitmap = mapinfo->write_bitmap_region(ArchivePtrMarker::ptrmap()); + +diff --git a/hotspot/src/share/vm/cds/archiveBuilder.hpp b/hotspot/src/share/vm/cds/archiveBuilder.hpp +index 18cd3c62..f7a5c107 100644 +--- a/hotspot/src/share/vm/cds/archiveBuilder.hpp ++++ b/hotspot/src/share/vm/cds/archiveBuilder.hpp +@@ -163,10 +163,13 @@ private: + static const int MAX_TABLE_SIZE = 1000000; + + ReservedSpace _shared_rs; ++ ReservedSpace _md_rs; + VirtualSpace _shared_vs; ++ VirtualSpace _md_vs; + + DumpRegion _rw_region; + DumpRegion _ro_region; ++ DumpRegion _md_region; + BitMap _ptrmap; + + SourceObjList _rw_src_objs; // objs to put in rw region +@@ -327,6 +330,7 @@ public: + + void dump_rw_metadata(); + void dump_ro_metadata(); ++ void dump_md_metadata(); + void relocate_metaspaceobj_embedded_pointers(); + void relocate_roots(); + void make_klasses_shareable(); +diff --git a/hotspot/src/share/vm/cds/dynamicArchive.cpp b/hotspot/src/share/vm/cds/dynamicArchive.cpp +index efed275c..a623c5b0 100644 +--- a/hotspot/src/share/vm/cds/dynamicArchive.cpp ++++ b/hotspot/src/share/vm/cds/dynamicArchive.cpp +@@ -149,6 +149,7 @@ public: + + relocate_to_requested(); + ++ dump_md_metadata(); + write_archive(serialized_data); + release_header(); + +diff --git a/hotspot/src/share/vm/classfile/classLoader.cpp b/hotspot/src/share/vm/classfile/classLoader.cpp +index e3470ca8..04fa84d4 100644 +--- a/hotspot/src/share/vm/classfile/classLoader.cpp ++++ b/hotspot/src/share/vm/classfile/classLoader.cpp +@@ -219,6 +219,30 @@ const char* ClassLoader::package_from_name(const char* const class_name, bool* b + return (const char *)pkg_name; + } + ++const char* ClassLoader::get_file_name_from_path(const char* path) { ++ const char* pos = strrchr(path, '/'); ++ if (pos == NULL) { ++ return path; ++ } else { ++ return pos + 1; ++ } ++} ++ ++const char* ClassLoader::get_boot_class_path(const char* shared_path) { ++ const char* shared_name = get_file_name_from_path(shared_path); ++ ClassPathEntry* e = _first_entry; ++ while (e != NULL) { ++ if (e->sys_class()) { ++ const char* name = get_file_name_from_path(e->name()); ++ if (strcmp(name, shared_name) == 0) { ++ return e->name(); ++ } ++ } ++ e = e->next(); ++ } ++ return NULL; ++} ++ + MetaIndex::MetaIndex(char** meta_package_names, int num_meta_package_names) { + if (num_meta_package_names == 0) { + _meta_package_names = NULL; +@@ -512,6 +536,8 @@ void ClassLoader::setup_meta_index(const char* meta_index_path, const char* meta + int line_no = 0; + #if INCLUDE_CDS + if (DumpSharedSpaces) { ++ meta_index_path = Arguments::get_is_default_jsa() ? ++ get_file_name_from_path(meta_index_path) : meta_index_path; + if (file != NULL) { + _shared_paths_misc_info->add_required_file(meta_index_path); + } else { +@@ -644,7 +670,9 @@ void ClassLoader::setup_bootstrap_search_path() { + } + #if INCLUDE_CDS + if (DumpSharedSpaces) { +- _shared_paths_misc_info->add_boot_classpath(sys_class_path); ++ const char* new_sys_class_path = Arguments::get_is_default_jsa() ? ++ get_file_name_from_path(sys_class_path) : sys_class_path; ++ _shared_paths_misc_info->add_boot_classpath(new_sys_class_path); + } + #endif + setup_search_path(sys_class_path); +@@ -688,7 +716,7 @@ void ClassLoader::setup_search_path(const char *class_path, bool canonicalize) { + path = canonical_path; + } + } +- update_class_path_entry_list(path, /*check_for_duplicates=*/canonicalize); ++ update_class_path_entry_list(path, /*check_for_duplicates=*/canonicalize, true, true); + #if INCLUDE_CDS + if (DumpSharedSpaces) { + check_shared_classpath(path); +@@ -816,7 +844,9 @@ void ClassLoader::add_to_list(ClassPathEntry *new_entry) { + // Returns true IFF the file/dir exists and the entry was successfully created. + bool ClassLoader::update_class_path_entry_list(const char *path, + bool check_for_duplicates, +- bool throw_exception) { ++ bool throw_exception, ++ bool sys_class_type) { ++ // sys_class_type indicates whether *path is a system path. The default value is false. + struct stat st; + if (os::stat(path, &st) == 0) { + // File or directory found +@@ -826,6 +856,11 @@ bool ClassLoader::update_class_path_entry_list(const char *path, + if (new_entry == NULL) { + return false; + } ++ // If the path is a system path, set sys_class of the newly created ++ // linked list node to true. The default value is false. ++ if (sys_class_type) { ++ new_entry->set_sys_class(true); ++ } + // The kernel VM adds dynamically to the end of the classloader path and + // doesn't reorder the bootclasspath which would break java.lang.Package + // (see PackageInfo). +@@ -837,6 +872,8 @@ bool ClassLoader::update_class_path_entry_list(const char *path, + } else { + #if INCLUDE_CDS + if (DumpSharedSpaces) { ++ path = Arguments::get_is_default_jsa() ? ++ get_file_name_from_path(path) : path; + _shared_paths_misc_info->add_nonexist_path(path); + } + #endif +@@ -918,6 +955,7 @@ int ClassLoader::crc32(int crc, const char* buf, int len) { + class PackageInfo: public BasicHashtableEntry { + public: + const char* _pkgname; // Package name ++ const char* _filename; // File name + int _classpath_index; // Index of directory or JAR file loaded from + + PackageInfo* next() { +@@ -926,9 +964,10 @@ public: + + const char* pkgname() { return _pkgname; } + void set_pkgname(char* pkgname) { _pkgname = pkgname; } ++ void set_filename(char* filename) { _filename = filename; } + + const char* filename() { +- return ClassLoader::classpath_entry(_classpath_index)->name(); ++ return _filename == NULL ? ClassLoader::classpath_entry(_classpath_index)->name() : _filename; + } + + void set_index(int index) { +@@ -975,11 +1014,12 @@ public: + return get_entry(hash_to_index(hash), hash, pkgname, n); + } + +- PackageInfo* new_entry(char* pkgname, int n) { ++ PackageInfo* new_entry(char* pkgname, int n, char* filename = NULL) { + unsigned int hash = compute_hash(pkgname, n); + PackageInfo* pp; + pp = (PackageInfo*)BasicHashtable::new_entry(hash); + pp->set_pkgname(pkgname); ++ pp->set_filename(filename); + return pp; + } + +@@ -999,6 +1039,9 @@ public: + } + + CDS_ONLY(void copy_table(char** top, char* end, PackageHashtable* table);) ++ CDS_ONLY(void serialize(char** top, char* end);) ++ CDS_ONLY(void deserialize(char* start);) ++ CDS_ONLY(size_t estimate_size();) + }; + + #if INCLUDE_CDS +@@ -1035,6 +1078,93 @@ void PackageHashtable::copy_table(char** top, char* end, + *tableSize = len; + } + ++size_t PackageHashtable::estimate_size() { ++ int size = sizeof(int); ++ ClassPathEntry* e = ClassLoader::_first_entry; ++ while (e != NULL) { ++ int length = (int)(strlen(e->name()) + 1); ++ size += length; ++ e = e->next(); ++ } ++ size = align_size_up(size, sizeof(int)); ++ ++ size += sizeof(int); ++ for (int i = 0; i < table_size(); ++i) { ++ for (PackageInfo* pp = bucket(i); ++ pp != NULL; ++ pp = pp->next()) { ++ size += sizeof(int); ++ int n1 = (int)(strlen(pp->pkgname()) + 1); ++ n1 = align_size_up(n1, sizeof(int)); ++ size += n1; ++ } ++ } ++ return align_size_up(size, sizeof(int)); ++} ++ ++void PackageHashtable::serialize(char** top, char* end) { ++ *(int*)(*top) = ClassLoader::_num_entries; ++ *top += sizeof(int); ++ ++ ClassPathEntry* e = ClassLoader::_first_entry; ++ while (e != NULL) { ++ int length = (int)(strlen(e->name()) + 1); ++ memcpy(*top, e->name(), length); ++ *top += length; ++ e = e->next(); ++ } ++ *top = (char*)align_size_up((intptr_t)*top, sizeof(int)); ++ *(int*)(*top) = number_of_entries(); ++ *top += sizeof(int); ++ ++ for (int i = 0; i < table_size(); ++i) { ++ for (PackageInfo* pp = bucket(i); ++ pp != NULL; ++ pp = pp->next()) { ++ *(int*)(*top) = pp->_classpath_index; ++ *top += sizeof(int); ++ int n1 = (int)(strlen(pp->pkgname()) + 1); ++ memcpy(*top, pp->pkgname(), n1); ++ n1 = align_size_up(n1, sizeof(int)); ++ *top += n1; ++ } ++ } ++} ++ ++void PackageHashtable::deserialize(char* start) { ++ int num_entries = *(int*)start; ++ char** class_loader_entries = NEW_C_HEAP_ARRAY(char*, num_entries, mtClass); ++ start += sizeof(int); ++ int entries_len = 0; ++ for (int i = 0, index = 0; i < num_entries; i++) { ++ class_loader_entries[index++] = start + entries_len; ++ entries_len += (int)(strlen(start + entries_len) + 1); ++ } ++ start += align_size_up(entries_len, sizeof(int)); ++ int number_of_entries = *(int*)start; ++ start += sizeof(int); ++ for (int i = 0; i < number_of_entries; i++) { ++ int classpath_index = *(int*)start; ++ start += sizeof(int); ++ char* pkgname = start; ++ const char *cp = strrchr(pkgname, '/'); ++ if (cp != NULL) { ++ int n = cp - pkgname + 1; ++ if (get_entry(pkgname, n) == NULL) { ++ PackageInfo* info = new_entry(pkgname, n, class_loader_entries[classpath_index]); ++ add_entry(info); ++ } ++ } ++ int n1 = (int)(strlen(start) + 1); ++ start += align_size_up(n1, sizeof(int)); ++ } ++ FREE_C_HEAP_ARRAY(char*, class_loader_entries, mtClass); ++} ++ ++void ClassLoader::deserialize_package_hash_table(char* start) { ++ assert(_package_hash_table != NULL, "should have one yet"); ++ _package_hash_table->deserialize(start); ++} + + void ClassLoader::copy_package_info_buckets(char** top, char* end) { + _package_hash_table->copy_buckets(top, end); +@@ -1043,6 +1173,14 @@ void ClassLoader::copy_package_info_buckets(char** top, char* end) { + void ClassLoader::copy_package_info_table(char** top, char* end) { + _package_hash_table->copy_table(top, end, _package_hash_table); + } ++ ++size_t ClassLoader::estimate_size_for_archive() { ++ return _package_hash_table->estimate_size(); ++} ++ ++void ClassLoader::serialize_package_hash_table(char** top, char* end) { ++ return _package_hash_table->serialize(top, end); ++} + #endif + + PackageInfo* ClassLoader::lookup_package(const char *pkgname) { +@@ -1226,8 +1364,8 @@ void ClassLoader::create_package_info_table(HashtableBucket *t, int len + + + void ClassLoader::create_package_info_table() { +- assert(_package_hash_table == NULL, "shouldn't have one yet"); +- _package_hash_table = new PackageHashtable(package_hash_table_size); ++ assert(_package_hash_table == NULL, "shouldn't have one yet"); ++ _package_hash_table = new PackageHashtable(package_hash_table_size); + } + + +diff --git a/hotspot/src/share/vm/classfile/classLoader.hpp b/hotspot/src/share/vm/classfile/classLoader.hpp +index 9514d3bb..cf39ce99 100644 +--- a/hotspot/src/share/vm/classfile/classLoader.hpp ++++ b/hotspot/src/share/vm/classfile/classLoader.hpp +@@ -49,13 +49,18 @@ class MetaIndex: public CHeapObj { + class ClassPathEntry: public CHeapObj { + private: + ClassPathEntry* _next; ++ bool _sys_class; + public: + // Next entry in class path + ClassPathEntry* next() { return _next; } ++ bool sys_class() const { return _sys_class; } + void set_next(ClassPathEntry* next) { + // may have unlocked readers, so write atomically. + OrderAccess::release_store_ptr(&_next, next); + } ++ void set_sys_class(bool isSysClass) { ++ _sys_class = isSysClass; ++ } + virtual bool is_jar_file() = 0; + virtual const char* name() = 0; + virtual bool is_lazy(); +@@ -158,6 +163,7 @@ class ClassLoader: AllStatic { + }; + protected: + friend class LazyClassPathEntry; ++ friend class PackageHashtable; + + // Performance counters + static PerfCounter* _perf_accumulated_time; +@@ -234,7 +240,8 @@ class ClassLoader: AllStatic { + static int crc32(int crc, const char* buf, int len); + static bool update_class_path_entry_list(const char *path, + bool check_for_duplicates, +- bool throw_exception=true); ++ bool throw_exception=true, ++ bool sys_class=false); + static void print_bootclasspath(); + + // Timing +@@ -318,6 +325,9 @@ class ClassLoader: AllStatic { + // Initialization + static void initialize(); + CDS_ONLY(static void initialize_shared_path();) ++ static const char* get_file_name_from_path(const char* path); ++ static const char* get_boot_class_path(const char* shared_path); ++ + static void create_package_info_table(); + static void create_package_info_table(HashtableBucket *t, int length, + int number_of_entries); +@@ -340,6 +350,9 @@ class ClassLoader: AllStatic { + // Sharing dump and restore + static void copy_package_info_buckets(char** top, char* end); + static void copy_package_info_table(char** top, char* end); ++ static size_t estimate_size_for_archive(); ++ static void serialize_package_hash_table(char** top, char* end); ++ static void deserialize_package_hash_table(char* start); + + static void check_shared_classpath(const char *path); + static void finalize_shared_paths_misc_info(); +diff --git a/hotspot/src/share/vm/classfile/classLoaderData.hpp b/hotspot/src/share/vm/classfile/classLoaderData.hpp +index 9b901303..7155257e 100644 +--- a/hotspot/src/share/vm/classfile/classLoaderData.hpp ++++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp +@@ -168,6 +168,7 @@ class ClassLoaderData : public CHeapObj { + friend class ClassLoaderDataGraphMetaspaceIterator; + friend class MetaDataFactory; + friend class Method; ++ friend class VM_PopulateDumpSharedSpace; + + static ClassLoaderData * _the_null_class_loader_data; + +diff --git a/hotspot/src/share/vm/classfile/dictionary.cpp b/hotspot/src/share/vm/classfile/dictionary.cpp +index b9d473b0..d41372ec 100644 +--- a/hotspot/src/share/vm/classfile/dictionary.cpp ++++ b/hotspot/src/share/vm/classfile/dictionary.cpp +@@ -197,7 +197,7 @@ void Dictionary::roots_oops_do(OopClosure* strong, OopClosure* weak) { + } + + void Dictionary::remove_classes_in_error_state() { +- assert(DumpSharedSpaces, "supported only when dumping"); ++ assert(DynamicDumpSharedSpaces || DumpSharedSpaces, "supported only when dumping"); + DictionaryEntry* probe = NULL; + for (int index = 0; index < table_size(); index++) { + for (DictionaryEntry** p = bucket_addr(index); *p != NULL; ) { +diff --git a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp +index 882fed01..b1609e46 100644 +--- a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp ++++ b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp +@@ -26,6 +26,7 @@ + #define SHARE_VM_CLASSFILE_SHAREDPATHSMISCINFO_HPP + + #include "runtime/os.hpp" ++#include "runtime/arguments.hpp" + + // During dumping time, when processing class paths, we build up the dump-time + // classpath. The JAR files that exist are stored in the list ClassLoader::_first_entry. +@@ -111,12 +112,18 @@ public: + add_path(path, REQUIRED); + + struct stat st; +- if (os::stat(path, &st) != 0) { ++ if (!Arguments::get_is_default_jsa() && os::stat(path, &st) != 0) { + assert(0, "sanity"); + ClassLoader::exit_with_path_failure("failed to os::stat(%s)", path); // should not happen + } +- write_time(st.st_mtime); +- write_long(st.st_size); ++ ++ if (Arguments::get_is_default_jsa()) { ++ write_time(0); ++ write_long(0); ++ } else { ++ write_time(st.st_mtime); ++ write_long(st.st_size); ++ } + } + + // The path must exist, and must contain exactly files/dirs +diff --git a/hotspot/src/share/vm/classfile/systemDictionaryShared.cpp b/hotspot/src/share/vm/classfile/systemDictionaryShared.cpp +index 99354cd4..3a601ee3 100644 +--- a/hotspot/src/share/vm/classfile/systemDictionaryShared.cpp ++++ b/hotspot/src/share/vm/classfile/systemDictionaryShared.cpp +@@ -659,7 +659,7 @@ bool SystemDictionaryShared::warn_excluded(InstanceKlass* k, const char* reason) + + bool SystemDictionaryShared::is_jfr_event_class(InstanceKlass *k) { + while (k) { +- if (k->name()->equals("jdk/jfr/Event")) { ++ if (k->name()->equals("jdk/jfr/Event") || k->name()->starts_with("jdk/jfr/event")) { + return true; + } + k = k->java_super(); +diff --git a/hotspot/src/share/vm/memory/filemap.cpp b/hotspot/src/share/vm/memory/filemap.cpp +index 3f410647..5fd62a74 100644 +--- a/hotspot/src/share/vm/memory/filemap.cpp ++++ b/hotspot/src/share/vm/memory/filemap.cpp +@@ -263,7 +263,12 @@ void FileMapInfo::allocate_classpath_entry_table() { + + for (int cur_entry = 0 ; cpe != NULL; cpe = cpe->next(), cur_entry++) { + const char *name = cpe->name(); +- int name_bytes = (int)(strlen(name) + 1); ++ int name_bytes; ++ if (cpe->sys_class()) { ++ name_bytes = (int)(strlen(ClassLoader::get_file_name_from_path(name)) + 1); ++ } else { ++ name_bytes = (int)(strlen(name) + 1); ++ } + + if (pass == 0) { + count ++; +@@ -286,7 +291,13 @@ void FileMapInfo::allocate_classpath_entry_table() { + } + + EXCEPTION_MARK; // The following call should never throw, but would exit VM on error. +- SharedClassUtil::update_shared_classpath(cpe, ent, st.st_mtime, st.st_size, THREAD); ++ if (cpe->sys_class()) { ++ // Jdk boot jar not need validate timestamp for we may copy whole jdk. ++ SharedClassUtil::update_shared_classpath(cpe, ent, 0, st.st_size, THREAD); ++ ent->set_sys_class(true); ++ } else { ++ SharedClassUtil::update_shared_classpath(cpe, ent, st.st_mtime, st.st_size, THREAD); ++ } + } else { + ent->_filesize = -1; + if (!os::dir_is_empty(name)) { +@@ -295,7 +306,11 @@ void FileMapInfo::allocate_classpath_entry_table() { + } + ent->_name = strptr; + if (strptr + name_bytes <= strptr_max) { +- strncpy(strptr, name, (size_t)name_bytes); // name_bytes includes trailing 0. ++ if (cpe->sys_class()) { ++ strncpy(strptr, ClassLoader::get_file_name_from_path(name), (size_t)name_bytes); ++ } else { ++ strncpy(strptr, name, (size_t)name_bytes); // name_bytes includes trailing 0. ++ } + strptr += name_bytes; + } else { + assert(0, "miscalculated buffer size"); +@@ -334,6 +349,14 @@ bool FileMapInfo::validate_classpath_entry_table() { + if (TraceClassPaths || (TraceClassLoading && Verbose)) { + tty->print_cr("[Checking shared classpath entry: %s]", name); + } ++ if (ent->_sys_class) { ++ name = ClassLoader::get_boot_class_path(name); ++ if (name == NULL) { ++ fail_continue("Required classpath entry of system class does not exist"); ++ continue; ++ } ++ } ++ + if (os::stat(name, &st) != 0) { + fail_continue("Required classpath entry does not exist: %s", name); + ok = false; +@@ -343,7 +366,7 @@ bool FileMapInfo::validate_classpath_entry_table() { + ok = false; + } + } else { +- if (ent->_timestamp != st.st_mtime || ++ if ((ent->_timestamp != 0 && ent->_timestamp != st.st_mtime) || + ent->_filesize != st.st_size) { + ok = false; + if (PrintSharedArchiveAndExit) { +@@ -640,6 +663,7 @@ void FileMapInfo::write_space(int i, Metaspace* space, bool read_only) { + size_t used = space->used_bytes_slow(Metaspace::NonClassType); + size_t capacity = space->capacity_bytes_slow(Metaspace::NonClassType); + struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[i]; ++ space->reset_metachunks(); + write_region(i, (char*)space->bottom(), used, capacity, read_only, false); + } + +@@ -967,7 +991,7 @@ bool FileMapInfo::validate_header() { + return DynamicArchive::validate(this); + } + +- if (status) { ++ if (status && !_header->_is_default_jsa) { + if (!ClassLoader::check_shared_paths_misc_info(_paths_misc_info, _header->_paths_misc_info_size)) { + if (!PrintSharedArchiveAndExit) { + fail_continue("shared class paths mismatch (hint: enable -XX:+TraceClassPaths to diagnose the failure)"); +diff --git a/hotspot/src/share/vm/memory/filemap.hpp b/hotspot/src/share/vm/memory/filemap.hpp +index eab9ebcf..36b27f13 100644 +--- a/hotspot/src/share/vm/memory/filemap.hpp ++++ b/hotspot/src/share/vm/memory/filemap.hpp +@@ -52,9 +52,13 @@ public: + const char *_name; + time_t _timestamp; // jar timestamp, 0 if is directory + long _filesize; // jar file size, -1 if is directory ++ bool _sys_class; + bool is_dir() { + return _filesize == -1; + } ++ void set_sys_class(bool isSysClass) { ++ _sys_class = isSysClass; ++ } + }; + + class FileMapInfo : public CHeapObj { +@@ -100,6 +104,7 @@ public: + int _version; // (from enum, above.) + size_t _alignment; // how shared archive should be aligned + int _obj_alignment; // value of ObjectAlignmentInBytes ++ bool _is_default_jsa; // indicates whether is the default jsa file + + struct space_info { + int _crc; // crc checksum of the current space +@@ -264,6 +269,8 @@ public: + bool is_open() { return _file_open; } + bool is_static() const { return _is_static; } + bool is_mapped() const { return _is_mapped; } ++ bool is_default_jsa() const { return _header->_is_default_jsa; } ++ void set_is_default_jsa(bool v) { _header->_is_default_jsa = v; } + void set_is_mapped(bool v) { _is_mapped = v; } + ReservedSpace reserve_shared_memory(); + void set_requested_base(char* b) { dynamic_header()->set_requested_base(b); } +diff --git a/hotspot/src/share/vm/memory/metachunk.hpp b/hotspot/src/share/vm/memory/metachunk.hpp +index e873dc6a..7889b622 100644 +--- a/hotspot/src/share/vm/memory/metachunk.hpp ++++ b/hotspot/src/share/vm/memory/metachunk.hpp +@@ -126,6 +126,8 @@ class Metachunk : public Metabase { + + VirtualSpaceNode* container() const { return _container; } + ++ void reset_container() { _container = NULL; } ++ + MetaWord* bottom() const { return (MetaWord*) this; } + + // Reset top to bottom so chunk can be reused. +diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp +index 7e95b5c0..6c4654b2 100644 +--- a/hotspot/src/share/vm/memory/metaspace.cpp ++++ b/hotspot/src/share/vm/memory/metaspace.cpp +@@ -775,6 +775,7 @@ class SpaceManager : public CHeapObj { + // Notify memory usage to MemoryService. + void track_metaspace_memory_usage(); + ++ void reset_metachunks(); + // debugging support. + + void dump(outputStream* const out) const; +@@ -1923,6 +1924,15 @@ void ChunkManager::print_on(outputStream* out) const { + + // SpaceManager methods + ++void SpaceManager::reset_metachunks() { ++ for (ChunkIndex i = ZeroIndex; i <= HumongousIndex; i = next_chunk_index(i)) { ++ Metachunk* chunks = chunks_in_use(i); ++ if (chunks != NULL) { ++ chunks->reset_container(); ++ } ++ } ++} ++ + size_t SpaceManager::adjust_initial_chunk_size(size_t requested, bool is_class_space) { + size_t chunk_sizes[] = { + specialized_chunk_size(is_class_space), +@@ -3002,6 +3012,10 @@ Metaspace::~Metaspace() { + } + } + ++void Metaspace::reset_metachunks() { ++ vsm()->reset_metachunks(); ++} ++ + VirtualSpaceList* Metaspace::_space_list = NULL; + VirtualSpaceList* Metaspace::_class_space_list = NULL; + +diff --git a/hotspot/src/share/vm/memory/metaspace.hpp b/hotspot/src/share/vm/memory/metaspace.hpp +index 2b06cb62..122dd4bf 100644 +--- a/hotspot/src/share/vm/memory/metaspace.hpp ++++ b/hotspot/src/share/vm/memory/metaspace.hpp +@@ -243,6 +243,8 @@ class Metaspace : public CHeapObj { + MetaWord* expand_and_allocate(size_t size, + MetadataType mdtype); + ++ void reset_metachunks(); ++ + static bool contains(const void* ptr); + + void dump(outputStream* const out) const; +diff --git a/hotspot/src/share/vm/memory/metaspaceShared.cpp b/hotspot/src/share/vm/memory/metaspaceShared.cpp +index 00fb9fe9..b31d0a3f 100644 +--- a/hotspot/src/share/vm/memory/metaspaceShared.cpp ++++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp +@@ -205,6 +205,21 @@ static void patch_klass_vtables(void** vtbl_list, void* new_vtable_start) { + } + } + ++static void patch_deallocate_meta_vtables(void** vtbl_list, void* new_vtable_start, GrowableArray* deallocate_list) { ++ if (deallocate_list == NULL) { ++ return; ++ } ++ for (int i = deallocate_list->length() - 1; i >= 0; i--) { ++ Metadata* m = deallocate_list->at(i); ++ if (!m->on_stack()) { ++ if (m->is_constantPool()) { ++ ((ConstantPool*)m)->remove_unshareable_info(); ++ *(void**)m = find_matching_vtbl_ptr(vtbl_list, new_vtable_start, m); ++ } ++ } ++ } ++} ++ + // Closure for serializing initialization data out to a data area to be + // written to the shared file. + +@@ -591,6 +606,7 @@ void VM_PopulateDumpSharedSpace::doit() { + // Update the vtable pointers in all of the Klass objects in the + // heap. They should point to newly generated vtable. + patch_klass_vtables(vtbl_list, vtable); ++ patch_deallocate_meta_vtables(vtbl_list, vtable, _loader_data->_deallocate_list); + + // dunno what this is for. + char* saved_vtbl = (char*)os::malloc(vtbl_list_size * sizeof(void*), mtClass); +@@ -602,6 +618,9 @@ void VM_PopulateDumpSharedSpace::doit() { + FileMapInfo* mapinfo = new FileMapInfo(); + mapinfo->populate_header(MetaspaceShared::max_alignment()); + ++ if (Arguments::get_is_default_jsa()) { ++ mapinfo->set_is_default_jsa(true); ++ } + // Pass 1 - update file offsets in header. + mapinfo->write_header(); + mapinfo->write_space(MetaspaceShared::ro, _loader_data->ro_metaspace(), true); +@@ -997,6 +1016,8 @@ bool MetaspaceShared::map_shared_spaces(FileMapInfo* mapinfo) { + mapinfo->verify_region_checksum(d_rw) && + (_ro_base = mapinfo->map_region(d_ro)) != NULL && + mapinfo->verify_region_checksum(d_ro) && ++ (_ro_base = mapinfo->map_region(d_md)) != NULL && ++ mapinfo->verify_region_checksum(d_md) && + (image_alignment == (size_t)max_alignment())) { + mapinfo->set_is_mapped(true); + return true; +@@ -1153,6 +1174,7 @@ void MetaspaceShared::initialize_shared_spaces() { + ReadClosure rc(&buffer); + SymbolTable::serialize_shared_table_header(&rc); + SystemDictionaryShared::serialize_dictionary_headers(&rc); ++ ClassLoader::deserialize_package_hash_table(dynamic_mapinfo->region_base(d_md)); + dynamic_mapinfo->close(); + } + +diff --git a/hotspot/src/share/vm/memory/metaspaceShared.hpp b/hotspot/src/share/vm/memory/metaspaceShared.hpp +index a9dadfbb..3eb8b12c 100644 +--- a/hotspot/src/share/vm/memory/metaspaceShared.hpp ++++ b/hotspot/src/share/vm/memory/metaspaceShared.hpp +@@ -90,8 +90,9 @@ class MetaspaceShared : AllStatic { + // core dynamic archive spaces + d_rw = 0, // read-write shared space in the heap + d_ro = 1, // read-only shared space in the heap +- d_bm = 2, // relocation bitmaps (freed after file mapping is finished) +- d_n_regions = 2 // d_rw and d_ro ++ d_md = 2, // miscellaneous data ++ d_bm = 3, // relocation bitmaps (freed after file mapping is finished) ++ d_n_regions = 3 // d_rw, d_ro, d_md + }; + + // Accessor functions to save shared space created for metadata, which has +diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp +index 0d1b1a8d..9276b895 100644 +--- a/hotspot/src/share/vm/oops/instanceKlass.cpp ++++ b/hotspot/src/share/vm/oops/instanceKlass.cpp +@@ -2633,7 +2633,7 @@ void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handl + + // returns true IFF is_in_error_state() has been changed as a result of this call. + bool InstanceKlass::check_sharing_error_state() { +- assert(DumpSharedSpaces, "should only be called during dumping"); ++ assert(DynamicDumpSharedSpaces || DumpSharedSpaces, "should only be called during dumping"); + bool old_state = is_in_error_state(); + + if (!is_in_error_state()) { +@@ -3573,6 +3573,9 @@ void InstanceKlass::verify_on(outputStream* st) { + // Avoid redundant verifies, this really should be in product. + if (_verify_count == Universe::verify_count()) return; + _verify_count = Universe::verify_count(); ++ if (is_in_error_state()) { ++ return; ++ } + #endif + + // Verify Klass +diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp +index 1f603021..5a79ab7e 100644 +--- a/hotspot/src/share/vm/runtime/arguments.cpp ++++ b/hotspot/src/share/vm/runtime/arguments.cpp +@@ -100,6 +100,7 @@ do { \ + } \ + } while(0) + ++bool Arguments::_is_default_jsa = false; + char** Arguments::_jvm_flags_array = NULL; + int Arguments::_num_jvm_flags = 0; + char** Arguments::_jvm_args_array = NULL; +@@ -4041,23 +4042,32 @@ static void force_serial_gc() { + } + #endif // INCLUDE_ALL_GCS + ++char* Arguments::get_default_shared_archive_path() { ++ char *default_archive_path; ++ char jvm_path[JVM_MAXPATHLEN]; ++ os::jvm_path(jvm_path, sizeof(jvm_path)); ++ char *end = strrchr(jvm_path, *os::file_separator()); ++ if (end != NULL) { ++ *end = '\0'; ++ } ++ size_t jvm_path_len = strlen(jvm_path); ++ size_t file_sep_len = strlen(os::file_separator()); ++ const size_t len = jvm_path_len + file_sep_len + 20; ++ default_archive_path = NEW_C_HEAP_ARRAY(char, len, mtInternal); ++ if (default_archive_path != NULL) { ++ jio_snprintf(default_archive_path, len, "%s%sclasses.jsa", ++ jvm_path, os::file_separator()); ++ } ++ Arguments::set_is_default_jsa(true); ++ return default_archive_path; ++} ++ + // Sharing support + // Construct the path to the archive + static char* get_shared_archive_path() { + char *shared_archive_path; + if (SharedArchiveFile == NULL) { +- char jvm_path[JVM_MAXPATHLEN]; +- os::jvm_path(jvm_path, sizeof(jvm_path)); +- char *end = strrchr(jvm_path, *os::file_separator()); +- if (end != NULL) *end = '\0'; +- size_t jvm_path_len = strlen(jvm_path); +- size_t file_sep_len = strlen(os::file_separator()); +- const size_t len = jvm_path_len + file_sep_len + 20; +- shared_archive_path = NEW_C_HEAP_ARRAY(char, len, mtInternal); +- if (shared_archive_path != NULL) { +- jio_snprintf(shared_archive_path, len, "%s%sclasses.jsa", +- jvm_path, os::file_separator()); +- } ++ shared_archive_path = Arguments::get_default_shared_archive_path(); + } else { + shared_archive_path = os::strdup(SharedArchiveFile, mtInternal); + } +diff --git a/hotspot/src/share/vm/runtime/arguments.hpp b/hotspot/src/share/vm/runtime/arguments.hpp +index 19f5cb60..65907eb4 100644 +--- a/hotspot/src/share/vm/runtime/arguments.hpp ++++ b/hotspot/src/share/vm/runtime/arguments.hpp +@@ -240,6 +240,8 @@ class Arguments : AllStatic { + + private: + ++ // Indicates whether the JSA file is the default jsa file. ++ static bool _is_default_jsa; + // an array containing all flags specified in the .hotspotrc file + static char** _jvm_flags_array; + static int _num_jvm_flags; +@@ -487,6 +489,9 @@ class Arguments : AllStatic { + // Return the maximum size a heap with compressed oops can take + static size_t max_heap_for_compressed_oops(); + ++ static void set_is_default_jsa(bool is_default) { _is_default_jsa = is_default; } ++ static bool get_is_default_jsa() { return _is_default_jsa; } ++ + // return a char* array containing all options + static char** jvm_flags_array() { return _jvm_flags_array; } + static char** jvm_args_array() { return _jvm_args_array; } +@@ -622,6 +627,7 @@ class Arguments : AllStatic { + static char* get_ext_dirs() { return _java_ext_dirs->value(); } + static char* get_appclasspath() { return _java_class_path->value(); } + static void fix_appclasspath(); ++ static char* get_default_shared_archive_path(); + + // Operation modi + static Mode mode() { return _mode; } +diff --git a/hotspot/src/share/vm/utilities/hashtable.cpp b/hotspot/src/share/vm/utilities/hashtable.cpp +index 66df8f1f..df290d99 100644 +--- a/hotspot/src/share/vm/utilities/hashtable.cpp ++++ b/hotspot/src/share/vm/utilities/hashtable.cpp +@@ -58,6 +58,7 @@ template BasicHashtableEntry* BasicHashtable::new_entry(unsig + len = 1 << log2_int(len); // round down to power of 2 + assert(len >= _entry_size, ""); + _first_free_entry = NEW_C_HEAP_ARRAY2(char, len, F, CURRENT_PC); ++ memset(_first_free_entry, 0, len); + _end_block = _first_free_entry + len; + } + entry = (BasicHashtableEntry*)_first_free_entry; +diff --git a/hotspot/test/runtime/appcds/TestCommon.java b/hotspot/test/runtime/appcds/TestCommon.java +index 22eef4ed..6a61dc31 100644 +--- a/hotspot/test/runtime/appcds/TestCommon.java ++++ b/hotspot/test/runtime/appcds/TestCommon.java +@@ -54,6 +54,7 @@ public class TestCommon extends CDSTestUtils { + System.getProperty("test.timeout.factor", "1.0"); + + private static String currentArchiveName; ++ private static String topArchiveName; + + // Call this method to start new archive with new unique name + public static void startNewArchiveName() { +@@ -62,6 +63,13 @@ public class TestCommon extends CDSTestUtils { + timeStampFormat.format(new Date()) + ".jsa"; + } + ++ public static String getTopArchiveName() { ++ topArchiveName = System.getProperty("user.dir") + ++ File.separator + "d-appcds-" + timeStampFormat.format(new Date()) + ".jsa"; ++ currentArchiveName = topArchiveName; ++ return topArchiveName; ++ } ++ + // Call this method to get current archive name + public static String getCurrentArchiveName() { + return currentArchiveName; +@@ -90,6 +98,16 @@ public class TestCommon extends CDSTestUtils { + } + } + ++ public static void deletePriorTopArchives() { ++ File dir = new File(System.getProperty("user.dir")); ++ String files[] = dir.list(); ++ for (String name : files) { ++ if (name.startsWith("d-appcds-") && name.endsWith(".jsa")) { ++ if (!(new File(dir, name)).delete()) ++ System.out.println("deletePriorArchives(): delete failed for file " + name); ++ } ++ } ++ } + + // Create AppCDS archive using most common args - convenience method + // Legacy name preserved for compatibility +@@ -132,7 +150,6 @@ public class TestCommon extends CDSTestUtils { + + cmd.add("-Xshare:dump"); + cmd.add("-XX:+UseAppCDS"); +-// cmd.add("-Xlog:cds,cds+hashtables"); comment out because it will be run by jdk1.8 + cmd.add("-XX:ExtraSharedClassListFile=" + classList.getPath()); + + if (opts.archiveName == null) +@@ -147,6 +164,36 @@ public class TestCommon extends CDSTestUtils { + return executeAndLog(pb, "dump"); + } + ++ public static OutputAnalyzer createBaseArchive(String appJar, String appClasses[], String... suffix) ++ throws Exception { ++ return createArchive(appJar, appClasses, suffix); ++ } ++ ++ public static OutputAnalyzer createTopArchive(String appJar, String...suffix) ++ throws Exception { ++ AppCDSOptions opts = new AppCDSOptions(); ++ opts.setAppJar(appJar); ++ opts.addSuffix(suffix); ++ ++ ArrayList cmd = new ArrayList(); ++ cmd.add("-cp"); ++ cmd.add(opts.appJar); ++ ++ String baseArchiveName = getCurrentArchiveName(); ++ deletePriorTopArchives(); ++ String topArchiveNmae = getTopArchiveName(); ++ cmd.add("-XX:+UnlockExperimentalVMOptions"); ++ cmd.add("-Xshare:on"); ++ cmd.add("-XX:SharedArchiveFile=" + baseArchiveName); ++ cmd.add("-XX:ArchiveClassesAtExit=" + topArchiveNmae); ++ cmd.add("-XX:+InfoDynamicCDS"); ++ ++ for (String s : opts.suffix) cmd.add(s); ++ ++ String[] cmdLine = cmd.toArray(new String[cmd.size()]); ++ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, makeCommandLineForAppCDS(cmdLine)); ++ return executeAndLog(pb, "dump"); ++ } + + // Execute JVM using AppCDS archive with specified AppCDSOptions + public static OutputAnalyzer runWithArchive(AppCDSOptions opts) +@@ -156,6 +203,9 @@ public class TestCommon extends CDSTestUtils { + + for (String p : opts.prefix) cmd.add(p); + ++ if (topArchiveName != null) { ++ cmd.add("-XX:+InfoDynamicCDS"); ++ } + cmd.add("-Xshare:" + opts.xShareMode); + cmd.add("-XX:+UseAppCDS"); + cmd.add("-showversion"); +@@ -174,7 +224,6 @@ public class TestCommon extends CDSTestUtils { + return executeAndLog(pb, "exec"); + } + +- + public static OutputAnalyzer execCommon(String... suffix) throws Exception { + AppCDSOptions opts = (new AppCDSOptions()); + opts.addSuffix(suffix); +@@ -261,6 +310,27 @@ public class TestCommon extends CDSTestUtils { + } + + ++ public static OutputAnalyzer testDynamicCDS(String appJar, String appClasses[], String... args) ++ throws Exception { ++ // Create base archive ++ OutputAnalyzer output = createBaseArchive(appJar, appClasses, args); ++ output.shouldContain("Loading classes to share"); ++ output.shouldHaveExitValue(0); ++ ++ // Create top archive ++ output = createTopArchive(appJar, args); ++ output.shouldContain("Written dynamic archive"); ++ output.shouldHaveExitValue(0); ++ ++ // Exec with top archive ++ output = exec(appJar, args); ++ ++ // Check exec result ++ checkMatches(output, "SharedArchivePath", "SharedDynamicArchivePath"); ++ output.shouldHaveExitValue(0); ++ return output; ++ } ++ + public static OutputAnalyzer checkExecReturn(OutputAnalyzer output, int ret, + boolean checkContain, String... matches) throws Exception { + try { +diff --git a/hotspot/test/runtime/appcds/dynamicArchive/DynamicFlag.java b/hotspot/test/runtime/appcds/dynamicArchive/DynamicFlag.java +new file mode 100644 +index 00000000..79f30759 +--- /dev/null ++++ b/hotspot/test/runtime/appcds/dynamicArchive/DynamicFlag.java +@@ -0,0 +1,39 @@ ++/* ++ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. 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 The DynamicDumpShareSpaces flag is internal, setting it at the command line should have no effect. ++ * @library /testlibrary /runtime/appcds /runtime/appcds/test-classes ++ * @compile ../test-classes/Hello.java ++ * @run driver DynamicFlag ++ */ ++ ++public class DynamicFlag { ++ public static void main(String[] args) throws Exception { ++ TestCommon.testDynamicCDS(JarBuilder.getOrCreateHelloJar(), ++ TestCommon.list("Hello"), "-XX:+DynamicDumpSharedSpaces", "Hello"); ++ } ++} +diff --git a/hotspot/test/runtime/appcds/dynamicArchive/DynamicHelloTest.java b/hotspot/test/runtime/appcds/dynamicArchive/DynamicHelloTest.java +new file mode 100644 +index 00000000..48e97cb2 +--- /dev/null ++++ b/hotspot/test/runtime/appcds/dynamicArchive/DynamicHelloTest.java +@@ -0,0 +1,42 @@ ++/* ++ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. 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 Hello World test for dynamic cds ++ * @library /testlibrary /runtime/appcds /runtime/appcds/test-classes ++ * @compile ../test-classes/Hello.java ++ * @run main DynamicHelloTest ++ */ ++ ++public class DynamicHelloTest { ++ public static void main(String[] args) throws Exception { ++ TestCommon.testDynamicCDS(JarBuilder.getOrCreateHelloJar(), ++ null, "Hello"); ++ ++ TestCommon.testDynamicCDS(JarBuilder.getOrCreateHelloJar(), ++ TestCommon.list("Hello"), "Hello"); ++ } ++} +diff --git a/hotspot/test/runtime/appcds/dynamicArchive/VerifyWithDynamicArchive.java b/hotspot/test/runtime/appcds/dynamicArchive/VerifyWithDynamicArchive.java +new file mode 100644 +index 00000000..eacc1aff +--- /dev/null ++++ b/hotspot/test/runtime/appcds/dynamicArchive/VerifyWithDynamicArchive.java +@@ -0,0 +1,42 @@ ++/* ++ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. 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 Hello World test for dynamic cds ++ * @library /testlibrary /runtime/appcds /runtime/appcds/test-classes ++ * @compile ../test-classes/Hello.java ++ * @run main VerifyWithDynamicArchive ++ */ ++ ++public class VerifyWithDynamicArchive { ++ public static void main(String[] args) throws Exception { ++ TestCommon.testDynamicCDS(JarBuilder.getOrCreateHelloJar(), ++ null, "-XX:+VerifySharedSpaces", "Hello"); ++ ++ TestCommon.testDynamicCDS(JarBuilder.getOrCreateHelloJar(), ++ TestCommon.list("Hello"), "-XX:+VerifySharedSpaces", "Hello"); ++ } ++} +diff --git a/jdk/make/BuildJdk.gmk b/jdk/make/BuildJdk.gmk +index 467792fa..bb8ea8a9 100644 +--- a/jdk/make/BuildJdk.gmk ++++ b/jdk/make/BuildJdk.gmk +@@ -103,6 +103,13 @@ images: + ifeq ($(OPENJDK_TARGET_OS), macosx) + +$(MAKE) -f Bundles.gmk + endif ++ ifeq ($(BUILD_CDS_ARCHIVE), true) ++ echo Creating CDS archive for jdk image ++ $(JDK_IMAGE_DIR)/bin/java -Xshare:dump -Xmx128M -Xms128M -XX:ParallelGCThreads=1 -Xint $(LOG_INFO) ++ echo Creating CDS archive for jre image ++ $(JRE_IMAGE_DIR)/bin/java -Xshare:dump -Xmx128M -Xms128M -XX:ParallelGCThreads=1 -Xint $(LOG_INFO) ++ endif ++ + + overlay-images: + +$(MAKE) -f CompileLaunchers.gmk OVERLAY_IMAGES=true diff --git a/openjdk-1.8.0.spec b/openjdk-1.8.0.spec index 7da47f78ebf4b7d33e68e85c90cbb07ac465c0a2..b25b7eb59554f7bc10121b75cfa89192e790effa 100644 --- a/openjdk-1.8.0.spec +++ b/openjdk-1.8.0.spec @@ -916,7 +916,7 @@ Provides: java-%{javaver}-%{origin}-accessibility%{?1} = %{epoch}:%{version}-%{r Name: java-%{javaver}-%{origin} Version: %{javaver}.%{updatever}.%{buildver} -Release: 6 +Release: 7 # java-1.5.0-ibm from jpackage.org set Epoch to 1 for unknown reasons # and this change was brought into RHEL-4. java-1.5.0-ibm packages # also included the epoch in their virtual provides. This created a @@ -1142,6 +1142,7 @@ Patch252: 8290705_fix_StringConcat_validate_mem_flow_asserts_with_unexpected_use Patch253: 8143925-enhancing-CounterMode.crypt-for-AESCrypt.patch Patch254: kae-usability-enhancement.patch Patch255: Dynamic-CDS-Archive.patch +Patch256: 8202951-Support-default-jsa.patch ############################################# # @@ -1624,6 +1625,7 @@ pushd %{top_level_dir_name} %patch253 -p1 %patch254 -p1 %patch255 -p1 +%patch256 -p1 popd # System library fixes @@ -2248,6 +2250,9 @@ cjc.mainProgram(arg) %endif %changelog +* Fri Sep 16 2022 kuenking111 - 1:1.8.0.342-b07.7 +- add 8202951-Support-default-jsa.patch + * Thu Sep 15 2022 kuenking111 - 1:1.8.0.342-b07.6 - add Dynamic-CDS-Archive.patch