Skip to content

8360555: Archive all unnamed modules in CDS full module graph #26082

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/hotspot/share/cds/cdsHeapVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,13 @@ CDSHeapVerifier::CDSHeapVerifier() : _archived_objs(0), _problems(0)

ADD_EXCL("java/lang/System", "bootLayer"); // A

ADD_EXCL("java/util/Collections", "EMPTY_LIST"); // E
ADD_EXCL("java/util/Collections", "EMPTY_LIST"); // E

// A dummy object used by HashSet. The value doesn't matter and it's never
// tested for equality.
ADD_EXCL("java/util/HashSet", "PRESENT"); // E

ADD_EXCL("jdk/internal/loader/BootLoader", "UNNAMED_MODULE"); // A
ADD_EXCL("jdk/internal/loader/BuiltinClassLoader", "packageToModule"); // A
ADD_EXCL("jdk/internal/loader/ClassLoaders", "BOOT_LOADER", // A
"APP_LOADER", // A
Expand Down
1 change: 0 additions & 1 deletion src/hotspot/share/cds/cdsProtectionDomain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ PackageEntry* CDSProtectionDomain::get_package_entry_from_class(InstanceKlass* i
if (CDSConfig::is_using_full_module_graph() && ik->is_shared() && pkg_entry != nullptr) {
assert(MetaspaceShared::is_in_shared_metaspace(pkg_entry), "must be");
assert(!ik->defined_by_other_loaders(), "unexpected archived package entry for an unregistered class");
assert(ik->module()->is_named(), "unexpected archived package entry for a class in an unnamed module");
return pkg_entry;
}
TempNewSymbol pkg_name = ClassLoader::package_from_class_name(ik->name());
Expand Down
72 changes: 65 additions & 7 deletions src/hotspot/share/classfile/classLoaderDataShared.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

#include "cds/aotLogging.hpp"
#include "cds/cdsConfig.hpp"
#include "cds/heapShared.hpp"
#include "cds/serializeClosure.hpp"
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/classLoaderDataShared.hpp"
Expand All @@ -42,6 +43,7 @@ bool ClassLoaderDataShared::_full_module_graph_loaded = false;
class ArchivedClassLoaderData {
Array<PackageEntry*>* _packages;
Array<ModuleEntry*>* _modules;
ModuleEntry* _unnamed_module;

void assert_valid(ClassLoaderData* loader_data) {
// loader_data may be null if the boot layer has loaded no modules for the platform or
Expand All @@ -52,15 +54,19 @@ class ArchivedClassLoaderData {
}
}
public:
ArchivedClassLoaderData() : _packages(nullptr), _modules(nullptr) {}
ArchivedClassLoaderData() : _packages(nullptr), _modules(nullptr), _unnamed_module(nullptr) {}

void iterate_symbols(ClassLoaderData* loader_data, MetaspaceClosure* closure);
void allocate(ClassLoaderData* loader_data);
void init_archived_entries(ClassLoaderData* loader_data);
ModuleEntry* unnamed_module() {
return _unnamed_module;
}

void serialize(SerializeClosure* f) {
f->do_ptr(&_packages);
f->do_ptr(&_modules);
f->do_ptr(&_unnamed_module);
}

void restore(ClassLoaderData* loader_data, bool do_entries, bool do_oops);
Expand All @@ -71,13 +77,16 @@ static ArchivedClassLoaderData _archived_boot_loader_data;
static ArchivedClassLoaderData _archived_platform_loader_data;
static ArchivedClassLoaderData _archived_system_loader_data;
static ModuleEntry* _archived_javabase_moduleEntry = nullptr;
static int _platform_loader_root_index = -1;
static int _system_loader_root_index = -1;

void ArchivedClassLoaderData::iterate_symbols(ClassLoaderData* loader_data, MetaspaceClosure* closure) {
assert(CDSConfig::is_dumping_full_module_graph(), "must be");
assert_valid(loader_data);
if (loader_data != nullptr) {
loader_data->packages()->iterate_symbols(closure);
loader_data->modules() ->iterate_symbols(closure);
loader_data->unnamed_module()->iterate_symbols(closure);
}
}

Expand All @@ -91,6 +100,7 @@ void ArchivedClassLoaderData::allocate(ClassLoaderData* loader_data) {
// the hashtables using these arrays.
_packages = loader_data->packages()->allocate_archived_entries();
_modules = loader_data->modules() ->allocate_archived_entries();
_unnamed_module = loader_data->unnamed_module()->allocate_archived_entry();
}
}

Expand All @@ -100,6 +110,7 @@ void ArchivedClassLoaderData::init_archived_entries(ClassLoaderData* loader_data
if (loader_data != nullptr) {
loader_data->packages()->init_archived_entries(_packages);
loader_data->modules() ->init_archived_entries(_modules);
_unnamed_module->init_as_archived_entry();
}
}

Expand All @@ -117,6 +128,12 @@ void ArchivedClassLoaderData::restore(ClassLoaderData* loader_data, bool do_entr
}
if (do_oops) {
modules->restore_archived_oops(loader_data, _modules);
if (_unnamed_module != nullptr) {
oop module_oop = _unnamed_module->module_oop();
assert(module_oop != nullptr, "must be already set");
assert(_unnamed_module == java_lang_Module::module_entry(module_oop), "must be already set");
assert(loader_data->class_loader() == java_lang_Module::loader(module_oop), "must be set in dump time");
}
}
}
}
Expand All @@ -127,6 +144,9 @@ void ArchivedClassLoaderData::clear_archived_oops() {
for (int i = 0; i < _modules->length(); i++) {
_modules->at(i)->clear_archived_oops();
}
if (_unnamed_module != nullptr) {
_unnamed_module->clear_archived_oops();
}
}
}

Expand Down Expand Up @@ -177,32 +197,70 @@ void ClassLoaderDataShared::allocate_archived_tables() {

void ClassLoaderDataShared::init_archived_tables() {
assert(CDSConfig::is_dumping_full_module_graph(), "must be");

_archived_boot_loader_data.init_archived_entries (null_class_loader_data());
_archived_platform_loader_data.init_archived_entries(java_platform_loader_data_or_null());
_archived_system_loader_data.init_archived_entries (java_system_loader_data_or_null());

_archived_javabase_moduleEntry = ModuleEntry::get_archived_entry(ModuleEntryTable::javabase_moduleEntry());

_platform_loader_root_index = HeapShared::append_root(SystemDictionary::java_platform_loader());
_system_loader_root_index = HeapShared::append_root(SystemDictionary::java_system_loader());
}

void ClassLoaderDataShared::serialize(SerializeClosure* f) {
_archived_boot_loader_data.serialize(f);
_archived_platform_loader_data.serialize(f);
_archived_system_loader_data.serialize(f);
f->do_ptr(&_archived_javabase_moduleEntry);
f->do_int(&_platform_loader_root_index);
f->do_int(&_system_loader_root_index);
}

if (f->reading() && CDSConfig::is_using_full_module_graph()) {
// Must be done before ClassLoader::create_javabase()
_archived_boot_loader_data.restore(null_class_loader_data(), true, false);
ModuleEntryTable::set_javabase_moduleEntry(_archived_javabase_moduleEntry);
aot_log_info(aot)("use_full_module_graph = true; java.base = " INTPTR_FORMAT,
p2i(_archived_javabase_moduleEntry));
ModuleEntry* ClassLoaderDataShared::archived_boot_unnamed_module() {
if (CDSConfig::is_using_full_module_graph()) {
return _archived_boot_loader_data.unnamed_module();
} else {
return nullptr;
}
}

ModuleEntry* ClassLoaderDataShared::archived_unnamed_module(ClassLoaderData* loader_data) {
ModuleEntry* archived_module = nullptr;

if (!Universe::is_module_initialized() && CDSConfig::is_using_full_module_graph()) {
precond(_platform_loader_root_index >= 0);
precond(_system_loader_root_index >= 0);

if (loader_data->class_loader() == HeapShared::get_root(_platform_loader_root_index)) {
archived_module = _archived_platform_loader_data.unnamed_module();
} else if (loader_data->class_loader() == HeapShared::get_root(_system_loader_root_index)) {
archived_module = _archived_system_loader_data.unnamed_module();
}
}

return archived_module;
}


void ClassLoaderDataShared::clear_archived_oops() {
assert(!CDSConfig::is_using_full_module_graph(), "must be");
_archived_boot_loader_data.clear_archived_oops();
_archived_platform_loader_data.clear_archived_oops();
_archived_system_loader_data.clear_archived_oops();
if (_platform_loader_root_index >= 0) {
HeapShared::clear_root(_platform_loader_root_index);
HeapShared::clear_root(_system_loader_root_index);
}
}

// Must be done before ClassLoader::create_javabase()
void ClassLoaderDataShared::restore_archived_entries_for_null_class_loader_data() {
precond(CDSConfig::is_using_full_module_graph());
_archived_boot_loader_data.restore(null_class_loader_data(), true, false);
ModuleEntryTable::set_javabase_moduleEntry(_archived_javabase_moduleEntry);
aot_log_info(aot)("use_full_module_graph = true; java.base = " INTPTR_FORMAT,
p2i(_archived_javabase_moduleEntry));
}

oop ClassLoaderDataShared::restore_archived_oops_for_null_class_loader_data() {
Expand Down
4 changes: 4 additions & 0 deletions src/hotspot/share/classfile/classLoaderDataShared.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

class ClassLoaderData;
class MetaspaceClosure;
class ModuleEntry;
class SerializeClosure;

class ClassLoaderDataShared : AllStatic {
Expand All @@ -42,9 +43,12 @@ class ClassLoaderDataShared : AllStatic {
static void init_archived_tables();
static void serialize(SerializeClosure* f);
static void clear_archived_oops();
static void restore_archived_entries_for_null_class_loader_data();
static oop restore_archived_oops_for_null_class_loader_data();
static void restore_java_platform_loader_from_archive(ClassLoaderData* loader_data);
static void restore_java_system_loader_from_archive(ClassLoaderData* loader_data);
static ModuleEntry* archived_boot_unnamed_module();
static ModuleEntry* archived_unnamed_module(ClassLoaderData* loader_data);
static bool is_full_module_graph_loaded() { return _full_module_graph_loaded; }
};

Expand Down
44 changes: 34 additions & 10 deletions src/hotspot/share/classfile/moduleEntry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,11 @@
#include "cds/heapShared.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/classLoaderDataShared.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/moduleEntry.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/systemDictionaryShared.hpp"
#include "jni.h"
#include "logging/log.hpp"
#include "logging/logStream.hpp"
Expand Down Expand Up @@ -317,6 +319,15 @@ ModuleEntry* ModuleEntry::create_unnamed_module(ClassLoaderData* cld) {
// corresponding unnamed module can be found in the java.lang.ClassLoader object.
oop module = java_lang_ClassLoader::unnamedModule(cld->class_loader());

#if INCLUDE_CDS_JAVA_HEAP
ModuleEntry* archived_unnamed_module = ClassLoaderDataShared::archived_unnamed_module(cld);
if (archived_unnamed_module != nullptr) {
archived_unnamed_module->load_from_archive(cld);
archived_unnamed_module->restore_archived_oops(cld);
return archived_unnamed_module;
}
#endif

// Ensure that the unnamed module was correctly set when the class loader was constructed.
// Guarantee will cause a recognizable crash if the user code has circumvented calling the ClassLoader constructor.
ResourceMark rm;
Expand All @@ -333,6 +344,16 @@ ModuleEntry* ModuleEntry::create_unnamed_module(ClassLoaderData* cld) {
}

ModuleEntry* ModuleEntry::create_boot_unnamed_module(ClassLoaderData* cld) {
#if INCLUDE_CDS_JAVA_HEAP
ModuleEntry* archived_unnamed_module = ClassLoaderDataShared::archived_boot_unnamed_module();
if (archived_unnamed_module != nullptr) {
archived_unnamed_module->load_from_archive(cld);
// It's too early to call archived_unnamed_module->restore_archived_oops(cld).
// We will do it inside Modules::set_bootloader_unnamed_module()
return archived_unnamed_module;
}
#endif

// For the boot loader, the java.lang.Module for the unnamed module
// is not known until a call to JVM_SetBootLoaderUnnamedModule is made. At
// this point initially create the ModuleEntry for the unnamed module.
Expand All @@ -345,7 +366,6 @@ ModuleEntry* ModuleEntry::create_boot_unnamed_module(ClassLoaderData* cld) {
// This is okay because the unnamed module gets created before the ClassLoaderData
// is available to other threads.
ModuleEntry* ModuleEntry::new_unnamed_module_entry(Handle module_handle, ClassLoaderData* cld) {

ModuleEntry* entry = new ModuleEntry(module_handle, /*is_open*/true, /*name*/nullptr,
/*version*/ nullptr, /*location*/ nullptr,
cld);
Expand Down Expand Up @@ -395,17 +415,17 @@ static int _num_archived_module_entries = 0;
static int _num_inited_module_entries = 0;
#endif

bool ModuleEntry::should_be_archived() const {
return SystemDictionaryShared::is_builtin_loader(loader_data());
}

ModuleEntry* ModuleEntry::allocate_archived_entry() const {
assert(is_named(), "unnamed packages/modules are not archived");
precond(should_be_archived());
precond(CDSConfig::is_dumping_full_module_graph());
ModuleEntry* archived_entry = (ModuleEntry*)ArchiveBuilder::rw_region_alloc(sizeof(ModuleEntry));
memcpy((void*)archived_entry, (void*)this, sizeof(ModuleEntry));

if (CDSConfig::is_dumping_full_module_graph()) {
archived_entry->_archived_module_index = HeapShared::append_root(module_oop());
} else {
archived_entry->_archived_module_index = -1;
}

archived_entry->_archived_module_index = HeapShared::append_root(module_oop());
if (_archive_modules_entries == nullptr) {
_archive_modules_entries = new (mtClass)ArchivedModuleEntries();
}
Expand Down Expand Up @@ -489,10 +509,14 @@ void ModuleEntry::init_as_archived_entry() {
set_archived_reads(write_growable_array(reads()));

_loader_data = nullptr; // re-init at runtime
_shared_path_index = AOTClassLocationConfig::dumptime()->get_module_shared_path_index(_location);
if (name() != nullptr) {
_shared_path_index = AOTClassLocationConfig::dumptime()->get_module_shared_path_index(_location);
_name = ArchiveBuilder::get_buffered_symbol(_name);
ArchivePtrMarker::mark_pointer((address*)&_name);
} else {
// _shared_path_index is used only by SystemDictionary::is_shared_class_visible_impl()
// for checking classes in named modules.
_shared_path_index = -1;
}
if (_version != nullptr) {
_version = ArchiveBuilder::get_buffered_symbol(_version);
Expand Down Expand Up @@ -741,7 +765,7 @@ void ModuleEntryTable::modules_do(ModuleClosure* closure) {
_table.iterate_all(do_f);
}

void ModuleEntry::print(outputStream* st) {
void ModuleEntry::print(outputStream* st) const {
st->print_cr("entry " PTR_FORMAT " name %s module " PTR_FORMAT " loader %s version %s location %s strict %s",
p2i(this),
name_as_C_string(),
Expand Down
5 changes: 3 additions & 2 deletions src/hotspot/share/classfile/moduleEntry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,17 +186,18 @@ class ModuleEntry : public CHeapObj<mtModule> {
static ModuleEntry* new_unnamed_module_entry(Handle module_handle, ClassLoaderData* cld);

// Note caller requires ResourceMark
const char* name_as_C_string() {
const char* name_as_C_string() const {
return is_named() ? name()->as_C_string() : UNNAMED_MODULE;
}
void print(outputStream* st = tty);
void print(outputStream* st = tty) const;
void verify();

CDS_ONLY(int shared_path_index() { return _shared_path_index;})

JFR_ONLY(DEFINE_TRACE_ID_METHODS;)

#if INCLUDE_CDS_JAVA_HEAP
bool should_be_archived() const;
void iterate_symbols(MetaspaceClosure* closure);
ModuleEntry* allocate_archived_entry() const;
void init_as_archived_entry();
Expand Down
Loading