--- old/src/hotspot/share/classfile/packageEntry.cpp 2020-08-12 15:00:48.472213904 -0700 +++ new/src/hotspot/share/classfile/packageEntry.cpp 2020-08-12 15:00:48.244205321 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2020, Oracle and/or its affiliates. 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 @@ -26,13 +26,18 @@ #include "classfile/moduleEntry.hpp" #include "classfile/packageEntry.hpp" #include "logging/log.hpp" +#include "memory/archiveUtils.hpp" +#include "memory/metaspaceShared.hpp" #include "memory/resourceArea.hpp" +#include "oops/array.hpp" #include "oops/symbol.hpp" #include "runtime/handles.inline.hpp" #include "utilities/events.hpp" #include "utilities/growableArray.hpp" #include "utilities/hashtable.inline.hpp" #include "utilities/ostream.hpp" +#include "utilities/quickSort.hpp" +#include "utilities/resourceHash.hpp" // Returns true if this package specifies m as a qualified export, including through an unnamed export bool PackageEntry::is_qexported_to(ModuleEntry* m) const { @@ -188,6 +193,113 @@ assert(new_entry_free_list() == NULL, "entry present on PackageEntryTable's free list"); } +#if INCLUDE_CDS_JAVA_HEAP +typedef ResourceHashtable< + const PackageEntry*, + PackageEntry*, + primitive_hash, + primitive_equals, + 557, // prime number + ResourceObj::C_HEAP> ArchivedPackageEntries; +static ArchivedPackageEntries* _archived_packages_entries = NULL; + +PackageEntry* PackageEntry::allocate_archived_entry() const { + assert(!in_unnamed_module(), "unnamed packages/modules are not archived"); + PackageEntry* archived_entry = (PackageEntry*)MetaspaceShared::read_write_space_alloc(sizeof(PackageEntry)); + memcpy((void*)archived_entry, (void*)this, sizeof(PackageEntry)); + + if (_archived_packages_entries == NULL) { + _archived_packages_entries = new (ResourceObj::C_HEAP, mtClass)ArchivedPackageEntries(); + } + assert(_archived_packages_entries->get(this) == NULL, "Each PackageEntry must not be shared across PackageEntryTables"); + _archived_packages_entries->put(this, archived_entry); + + return archived_entry; +} + +PackageEntry* PackageEntry::get_archived_entry(PackageEntry* orig_entry) { + PackageEntry** ptr = _archived_packages_entries->get(orig_entry); + assert(ptr != NULL && *ptr != NULL, "must have been allocated"); + return *ptr; +} + +void PackageEntry::init_as_archived_entry() { + Array* archived_qualified_exports = ModuleEntry::write_archived_entry_array(_qualified_exports); + + set_next(NULL); + set_literal(MetaspaceShared::get_relocated_symbol(literal())); + set_hash(0x0); // re-init at runtime + _module = ModuleEntry::get_archived_entry(_module); + _qualified_exports = (GrowableArray*)archived_qualified_exports; + _defined_by_cds_in_class_path = 0; + + ArchivePtrMarker::mark_pointer((address*)literal_addr()); + ArchivePtrMarker::mark_pointer((address*)&_module); + ArchivePtrMarker::mark_pointer((address*)&_qualified_exports); +} + +void PackageEntry::load_from_archive() { + _qualified_exports = ModuleEntry::read_archived_entry_array((Array*)_qualified_exports); + JFR_ONLY(INIT_ID(this);) +} + +static int compare_package_by_name(PackageEntry* a, PackageEntry* b) { + return a->name()->fast_compare(b->name()); +} + +Array* PackageEntryTable::allocate_archived_entries() { + // First count the packages in named modules + int n, i; + for (n = 0, i = 0; i < table_size(); ++i) { + for (PackageEntry* p = bucket(i); p != NULL; p = p->next()) { + if (p->module()->name() != NULL) { + n++; + } + } + } + + Array* archived_packages = MetaspaceShared::new_rw_array(n); + for (n = 0, i = 0; i < table_size(); ++i) { + for (PackageEntry* p = bucket(i); p != NULL; p = p->next()) { + if (p->module()->name() != NULL) { + // We don't archive unnamed modules, or packages in unnamed modules. They will be + // created on-demand at runtime as classes in such packages are loaded. + archived_packages->at_put(n++, p); + } + } + } + if (n > 1) { + QuickSort::sort(archived_packages->data(), n, (_sort_Fn)compare_package_by_name, true); + } + for (i = 0; i < n; i++) { + archived_packages->at_put(i, archived_packages->at(i)->allocate_archived_entry()); + ArchivePtrMarker::mark_pointer((address*)archived_packages->adr_at(i)); + } + return archived_packages; +} + +void PackageEntryTable::init_archived_entries(Array* archived_packages) { + for (int i = 0; i < archived_packages->length(); i++) { + PackageEntry* archived_entry = archived_packages->at(i); + archived_entry->init_as_archived_entry(); + } +} + +void PackageEntryTable::load_archived_entries(Array* archived_packages) { + assert(UseSharedSpaces, "runtime only"); + + for (int i = 0; i < archived_packages->length(); i++) { + PackageEntry* archived_entry = archived_packages->at(i); + archived_entry->load_from_archive(); + + unsigned int hash = compute_hash(archived_entry->name()); + archived_entry->set_hash(hash); + add_entry(hash_to_index(hash), archived_entry); + } +} + +#endif // INCLUDE_CDS_JAVA_HEAP + PackageEntry* PackageEntryTable::new_entry(unsigned int hash, Symbol* name, ModuleEntry* module) { assert(Module_lock->owned_by_self(), "should have the Module_lock"); PackageEntry* entry = (PackageEntry*)Hashtable::allocate_new_entry(hash, name); @@ -273,7 +385,6 @@ } } } - } // iteration of qualified exports