8298601: Refactor archiving of java.lang.Module objects
Reviewed-by: coleenp, ccheung
This commit is contained in:
parent
77ff197746
commit
82deb5ca61
@ -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() ||
|
||||
|
@ -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[]);
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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");
|
||||
|
@ -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,
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user