8298601: Refactor archiving of java.lang.Module objects

Reviewed-by: coleenp, ccheung
This commit is contained in:
Ioi Lam 2023-01-04 04:03:43 +00:00
parent 77ff197746
commit 82deb5ca61
8 changed files with 144 additions and 63 deletions

View File

@ -30,9 +30,8 @@
#include "cds/heapShared.hpp"
#include "cds/metaspaceShared.hpp"
#include "classfile/classLoaderData.hpp"
#include "classfile/classLoaderDataShared.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/moduleEntry.hpp"
#include "classfile/modules.hpp"
#include "classfile/stringTable.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
@ -554,7 +553,7 @@ void HeapShared::copy_open_objects(GrowableArray<MemRegion>* open_regions) {
archive_object_subgraphs(fmg_open_archive_subgraph_entry_fields,
false /* is_closed_archive */,
true /* is_full_module_graph */);
ClassLoaderDataShared::init_archived_oops();
Modules::verify_archived_modules();
}
copy_roots();
@ -1189,25 +1188,6 @@ void HeapShared::check_closed_region_object(InstanceKlass* k) {
}
}
void HeapShared::check_module_oop(oop orig_module_obj) {
assert(DumpSharedSpaces, "must be");
assert(java_lang_Module::is_instance(orig_module_obj), "must be");
ModuleEntry* orig_module_ent = java_lang_Module::module_entry_raw(orig_module_obj);
if (orig_module_ent == NULL) {
// These special Module objects are created in Java code. They are not
// defined via Modules::define_module(), so they don't have a ModuleEntry:
// java.lang.Module::ALL_UNNAMED_MODULE
// java.lang.Module::EVERYONE_MODULE
// jdk.internal.loader.ClassLoaders$BootClassLoader::unnamedModule
assert(java_lang_Module::name(orig_module_obj) == NULL, "must be unnamed");
log_info(cds, heap)("Module oop with No ModuleEntry* @[" PTR_FORMAT "]", p2i(orig_module_obj));
} else {
ClassLoaderData* loader_data = orig_module_ent->loader_data();
assert(loader_data->is_builtin_class_loader_data(), "must be");
}
}
// (1) If orig_obj has not been archived yet, archive it.
// (2) If orig_obj has not been seen yet (since start_recording_subgraph() was called),
// trace all objects that are reachable from it, and make sure these objects are archived.
@ -1276,9 +1256,10 @@ oop HeapShared::archive_reachable_objects_from(int level,
}
if (java_lang_Module::is_instance(orig_obj)) {
check_module_oop(orig_obj);
if (Modules::check_module_oop(orig_obj)) {
Modules::update_oops_in_archived_module(orig_obj, append_root(archived_obj));
}
java_lang_Module::set_module_entry(archived_obj, NULL);
java_lang_Module::set_loader(archived_obj, NULL);
} else if (java_lang_ClassLoader::is_instance(orig_obj)) {
// class_data will be restored explicitly at run time.
guarantee(orig_obj == SystemDictionary::java_platform_loader() ||

View File

@ -301,7 +301,6 @@ private:
static bool has_been_seen_during_subgraph_recording(oop obj);
static void set_has_been_seen_during_subgraph_recording(oop obj);
static void check_module_oop(oop orig_module_obj);
static void copy_roots();
static void resolve_classes_for_subgraphs(JavaThread* current, ArchivableStaticFieldInfo fields[]);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2022, 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
@ -54,7 +54,6 @@ public:
void iterate_symbols(ClassLoaderData* loader_data, MetaspaceClosure* closure);
void allocate(ClassLoaderData* loader_data);
void init_archived_entries(ClassLoaderData* loader_data);
void init_archived_oops(ClassLoaderData* loader_data);
void serialize(SerializeClosure* f) {
f->do_ptr((void**)&_packages);
@ -101,14 +100,6 @@ void ArchivedClassLoaderData::init_archived_entries(ClassLoaderData* loader_data
}
}
void ArchivedClassLoaderData::init_archived_oops(ClassLoaderData* loader_data) {
assert(DumpSharedSpaces, "must be");
assert_valid(loader_data);
if (loader_data != NULL) {
loader_data->modules()->init_archived_oops(_modules);
}
}
void ArchivedClassLoaderData::restore(ClassLoaderData* loader_data, bool do_entries, bool do_oops) {
assert(UseSharedSpaces, "must be");
assert_valid(loader_data);
@ -174,13 +165,6 @@ void ClassLoaderDataShared::init_archived_tables() {
_archived_javabase_moduleEntry = ModuleEntry::get_archived_entry(ModuleEntryTable::javabase_moduleEntry());
}
void ClassLoaderDataShared::init_archived_oops() {
assert(DumpSharedSpaces && MetaspaceShared::use_full_module_graph(), "must be");
_archived_boot_loader_data.init_archived_oops (null_class_loader_data());
_archived_platform_loader_data.init_archived_oops(java_platform_loader_data_or_null());
_archived_system_loader_data.init_archived_oops (java_system_loader_data_or_null());
}
void ClassLoaderDataShared::serialize(SerializeClosure* f) {
_archived_boot_loader_data.serialize(f);
_archived_platform_loader_data.serialize(f);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2022, 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
@ -38,7 +38,6 @@ public:
static void allocate_archived_tables();
static void iterate_symbols(MetaspaceClosure* closure);
static void init_archived_tables();
static void init_archived_oops();
static void serialize(SerializeClosure* f);
static void clear_archived_oops();
static oop restore_archived_oops_for_null_class_loader_data();

View File

@ -31,8 +31,10 @@
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/moduleEntry.hpp"
#include "classfile/systemDictionary.hpp"
#include "jni.h"
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "oops/oopHandle.inline.hpp"
@ -386,20 +388,38 @@ typedef ResourceHashtable<
AnyObj::C_HEAP> ArchivedModuleEntries;
static ArchivedModuleEntries* _archive_modules_entries = NULL;
#ifndef PRODUCT
static int _num_archived_module_entries = 0;
static int _num_inited_module_entries = 0;
#endif
ModuleEntry* ModuleEntry::allocate_archived_entry() const {
assert(is_named(), "unnamed packages/modules are not archived");
ModuleEntry* archived_entry = (ModuleEntry*)ArchiveBuilder::rw_region_alloc(sizeof(ModuleEntry));
memcpy((void*)archived_entry, (void*)this, sizeof(ModuleEntry));
archived_entry->_archived_module_index = -1;
if (_archive_modules_entries == NULL) {
_archive_modules_entries = new (mtClass)ArchivedModuleEntries();
}
assert(_archive_modules_entries->get(this) == NULL, "Each ModuleEntry must not be shared across ModuleEntryTables");
_archive_modules_entries->put(this, archived_entry);
DEBUG_ONLY(_num_archived_module_entries++);
if (log_is_enabled(Info, cds, module)) {
ResourceMark rm;
LogStream ls(Log(cds, module)::info());
ls.print("Stored in archive: ");
archived_entry->print(&ls);
}
return archived_entry;
}
bool ModuleEntry::has_been_archived() {
assert(!ArchiveBuilder::current()->is_in_buffer_space(this), "must be called on original ModuleEntry");
return _archive_modules_entries->contains(this);
}
ModuleEntry* ModuleEntry::get_archived_entry(ModuleEntry* orig_entry) {
ModuleEntry** ptr = _archive_modules_entries->get(orig_entry);
assert(ptr != NULL && *ptr != NULL, "must have been allocated");
@ -467,27 +487,39 @@ void ModuleEntry::init_as_archived_entry() {
ArchivePtrMarker::mark_pointer((address*)&_location);
}
void ModuleEntry::init_archived_oops() {
void ModuleEntry::update_oops_in_archived_module(int root_oop_index) {
assert(DumpSharedSpaces, "static dump only");
oop module_obj = module();
if (module_obj != NULL) {
oop m = HeapShared::find_archived_heap_object(module_obj);
assert(m != NULL, "sanity");
_archived_module_index = HeapShared::append_root(m);
}
assert(_archived_module_index == -1, "must be set exactly once");
assert(root_oop_index >= 0, "sanity");
_archived_module_index = root_oop_index;
assert(shared_protection_domain() == NULL, "never set during -Xshare:dump");
// Clear handles and restore at run time. Handles cannot be archived.
OopHandle null_handle;
_module = null_handle;
// For verify_archived_module_entries()
DEBUG_ONLY(_num_inited_module_entries++);
}
#ifndef PRODUCT
void ModuleEntry::verify_archived_module_entries() {
assert(_num_archived_module_entries == _num_inited_module_entries,
"%d ModuleEntries have been archived but %d of them have been properly initialized with archived java.lang.Module objects",
_num_archived_module_entries, _num_inited_module_entries);
}
#endif // PRODUCT
void ModuleEntry::load_from_archive(ClassLoaderData* loader_data) {
assert(UseSharedSpaces, "runtime only");
set_loader_data(loader_data);
_reads = restore_growable_array((Array<ModuleEntry*>*)_reads);
JFR_ONLY(INIT_ID(this);)
}
void ModuleEntry::restore_archived_oops(ClassLoaderData* loader_data) {
assert(UseSharedSpaces, "runtime only");
Handle module_handle(Thread::current(), HeapShared::get_root(_archived_module_index, /*clear=*/true));
assert(module_handle.not_null(), "huh");
set_module(loader_data->add_handle(module_handle));
@ -496,12 +528,19 @@ void ModuleEntry::restore_archived_oops(ClassLoaderData* loader_data) {
// because it may be affected by archive relocation.
java_lang_Module::set_module_entry(module_handle(), this);
if (loader_data->class_loader() != NULL) {
java_lang_Module::set_loader(module_handle(), loader_data->class_loader());
assert(java_lang_Module::loader(module_handle()) == loader_data->class_loader(),
"must be set in dump time");
if (log_is_enabled(Info, cds, module)) {
ResourceMark rm;
LogStream ls(Log(cds, module)::info());
ls.print("Restored from archive: ");
print(&ls);
}
}
void ModuleEntry::clear_archived_oops() {
assert(UseSharedSpaces, "runtime only");
HeapShared::clear_root(_archived_module_index);
}
@ -544,14 +583,6 @@ void ModuleEntryTable::init_archived_entries(Array<ModuleEntry*>* archived_modul
}
}
void ModuleEntryTable::init_archived_oops(Array<ModuleEntry*>* archived_modules) {
assert(DumpSharedSpaces, "dump time only");
for (int i = 0; i < archived_modules->length(); i++) {
ModuleEntry* archived_entry = archived_modules->at(i);
archived_entry->init_archived_oops();
}
}
void ModuleEntryTable::load_archived_entries(ClassLoaderData* loader_data,
Array<ModuleEntry*>* archived_modules) {
assert(UseSharedSpaces, "runtime only");

View File

@ -175,13 +175,15 @@ public:
void iterate_symbols(MetaspaceClosure* closure);
ModuleEntry* allocate_archived_entry() const;
void init_as_archived_entry();
void init_archived_oops();
static ModuleEntry* get_archived_entry(ModuleEntry* orig_entry);
bool has_been_archived();
static Array<ModuleEntry*>* write_growable_array(GrowableArray<ModuleEntry*>* array);
static GrowableArray<ModuleEntry*>* restore_growable_array(Array<ModuleEntry*>* archived_array);
void load_from_archive(ClassLoaderData* loader_data);
void restore_archived_oops(ClassLoaderData* loader_data);
void clear_archived_oops();
void update_oops_in_archived_module(int root_oop_index);
static void verify_archived_module_entries() PRODUCT_RETURN;
#endif
};
@ -250,7 +252,6 @@ public:
void iterate_symbols(MetaspaceClosure* closure);
Array<ModuleEntry*>* allocate_archived_entries();
void init_archived_entries(Array<ModuleEntry*>* archived_modules);
void init_archived_oops(Array<ModuleEntry*>* archived_modules);
void load_archived_entries(ClassLoaderData* loader_data,
Array<ModuleEntry*>* archived_modules);
void restore_archived_oops(ClassLoaderData* loader_data,

View File

@ -477,6 +477,88 @@ void Modules::define_module(Handle module, jboolean is_open, jstring version,
}
#if INCLUDE_CDS_JAVA_HEAP
static bool _seen_platform_unnamed_module = false;
static bool _seen_system_unnamed_module = false;
// Validate the states of an java.lang.Module oop to be archived.
//
// Returns true iff the oop has an archived ModuleEntry.
bool Modules::check_module_oop(oop orig_module_obj) {
assert(DumpSharedSpaces, "must be");
assert(MetaspaceShared::use_full_module_graph(), "must be");
assert(java_lang_Module::is_instance(orig_module_obj), "must be");
ModuleEntry* orig_module_ent = java_lang_Module::module_entry_raw(orig_module_obj);
if (orig_module_ent == nullptr) {
// These special java.lang.Module oops are created in Java code. They are not
// defined via Modules::define_module(), so they don't have a ModuleEntry:
// java.lang.Module::ALL_UNNAMED_MODULE
// java.lang.Module::EVERYONE_MODULE
// jdk.internal.loader.ClassLoaders$BootClassLoader::unnamedModule
log_info(cds, module)("Archived java.lang.Module oop " PTR_FORMAT " with no ModuleEntry*", p2i(orig_module_obj));
assert(java_lang_Module::name(orig_module_obj) == nullptr, "must be unnamed");
return false;
} else {
// This java.lang.Module oop has an ModuleEntry*. Check if the latter is archived.
if (log_is_enabled(Info, cds, module)) {
ResourceMark rm;
LogStream ls(Log(cds, module)::info());
ls.print("Archived java.lang.Module oop " PTR_FORMAT " for ", p2i(orig_module_obj));
orig_module_ent->print(&ls);
}
// We only archive the default module graph, which should contain only java.lang.Module oops
// for the 3 built-in loaders (boot/platform/system)
ClassLoaderData* loader_data = orig_module_ent->loader_data();
assert(loader_data->is_builtin_class_loader_data(), "must be");
if (orig_module_ent->name() != nullptr) {
// For each named module, we archive both the java.lang.Module oop and the ModuleEntry.
assert(orig_module_ent->has_been_archived(), "sanity");
return true;
} else {
// We only archive two unnamed module oops (for platform and system loaders). These do NOT have an archived
// ModuleEntry.
//
// At runtime, these oops are fetched from java_lang_ClassLoader::unnamedModule(loader) and
// are initialized in ClassLoaderData::ClassLoaderData() => ModuleEntry::create_unnamed_module(), where
// a new ModuleEntry is allocated.
assert(!loader_data->is_boot_class_loader_data(), "unnamed module for boot loader should be not archived");
assert(!orig_module_ent->has_been_archived(), "sanity");
if (SystemDictionary::is_platform_class_loader(loader_data->class_loader())) {
assert(!_seen_platform_unnamed_module, "only once");
_seen_platform_unnamed_module = true;
} else if (SystemDictionary::is_system_class_loader(loader_data->class_loader())) {
assert(!_seen_system_unnamed_module, "only once");
_seen_system_unnamed_module = true;
} else {
// The java.lang.Module oop and ModuleEntry of the unnamed module of the boot loader are
// not in the archived module graph. These are always allocated at runtime.
ShouldNotReachHere();
}
return false;
}
}
}
void Modules::update_oops_in_archived_module(oop orig_module_obj, int archived_module_root_index) {
// This java.lang.Module oop must have an archived ModuleEntry
assert(check_module_oop(orig_module_obj) == true, "sanity");
// We remember the oop inside the ModuleEntry::_archived_module_index. At runtime, we use
// this index to reinitialize the ModuleEntry inside ModuleEntry::restore_archived_oops().
//
// ModuleEntry::verify_archived_module_entries(), called below, ensures that every archived
// ModuleEntry has been assigned an _archived_module_index.
ModuleEntry* orig_module_ent = java_lang_Module::module_entry_raw(orig_module_obj);
ModuleEntry::get_archived_entry(orig_module_ent)->update_oops_in_archived_module(archived_module_root_index);
}
void Modules::verify_archived_modules() {
ModuleEntry::verify_archived_module_entries();
}
void Modules::define_archived_modules(Handle h_platform_loader, Handle h_system_loader, TRAPS) {
assert(UseSharedSpaces && MetaspaceShared::use_full_module_graph(), "must be");

View File

@ -53,8 +53,12 @@ public:
static void define_module(Handle module, jboolean is_open, jstring version,
jstring location, jobjectArray packages, TRAPS);
static bool check_module_oop(oop orig_module_obj) NOT_CDS_JAVA_HEAP_RETURN_(false);
static void update_oops_in_archived_module(oop orig_module_obj, int archived_module_root_index)
NOT_CDS_JAVA_HEAP_RETURN;
static void define_archived_modules(Handle h_platform_loader, Handle h_system_loader,
TRAPS) NOT_CDS_JAVA_HEAP_RETURN;
static void verify_archived_modules() NOT_CDS_JAVA_HEAP_RETURN;
// Provides the java.lang.Module for the unnamed module defined
// to the boot loader.