mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-14 15:39:45 +00:00
8176472: Lazily create ModuleEntryTable
Moved the unnamed module out of the ModuleEntryTable and into the ClassLoaderData so that the MET can be lazily created only when other modules are present. Also a smaller PackageTable size. Reviewed-by: gtriantafill, hseigel, lfoltan, coleenp
This commit is contained in:
parent
2327609d91
commit
ca72444bf9
@ -97,6 +97,21 @@ ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous, Depen
|
||||
_next(NULL), _dependencies(dependencies),
|
||||
_metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true,
|
||||
Monitor::_safepoint_check_never)) {
|
||||
|
||||
// A ClassLoaderData created solely for an anonymous class should never have a
|
||||
// ModuleEntryTable or PackageEntryTable created for it. The defining package
|
||||
// and module for an anonymous class will be found in its host class.
|
||||
if (!is_anonymous) {
|
||||
if (h_class_loader.is_null()) {
|
||||
// Create unnamed module for boot loader
|
||||
_unnamed_module = ModuleEntry::create_boot_unnamed_module(this);
|
||||
} else {
|
||||
// Create unnamed module for all other loaders
|
||||
_unnamed_module = ModuleEntry::create_unnamed_module(this);
|
||||
}
|
||||
} else {
|
||||
_unnamed_module = NULL;
|
||||
}
|
||||
TRACE_INIT_ID(this);
|
||||
}
|
||||
|
||||
@ -276,6 +291,9 @@ void ClassLoaderData::classes_do(void f(InstanceKlass*)) {
|
||||
|
||||
void ClassLoaderData::modules_do(void f(ModuleEntry*)) {
|
||||
assert_locked_or_safepoint(Module_lock);
|
||||
if (_unnamed_module != NULL) {
|
||||
f(_unnamed_module);
|
||||
}
|
||||
if (_modules != NULL) {
|
||||
for (int i = 0; i < _modules->table_size(); i++) {
|
||||
for (ModuleEntry* entry = _modules->bucket(i);
|
||||
@ -501,10 +519,6 @@ ModuleEntryTable* ClassLoaderData::modules() {
|
||||
// Check if _modules got allocated while we were waiting for this lock.
|
||||
if ((modules = _modules) == NULL) {
|
||||
modules = new ModuleEntryTable(ModuleEntryTable::_moduletable_entry_size);
|
||||
// Each loader has one unnamed module entry. Create it before
|
||||
// any classes, loaded by this loader, are defined in case
|
||||
// they end up being defined in loader's unnamed module.
|
||||
modules->create_unnamed_module(this);
|
||||
|
||||
{
|
||||
MutexLockerEx m1(metaspace_lock(), Mutex::_no_safepoint_check_flag);
|
||||
@ -529,7 +543,6 @@ bool ClassLoaderData::is_alive(BoolObjectClosure* is_alive_closure) const {
|
||||
return alive;
|
||||
}
|
||||
|
||||
|
||||
ClassLoaderData::~ClassLoaderData() {
|
||||
// Release C heap structures for all the classes.
|
||||
classes_do(InstanceKlass::release_C_heap_structures);
|
||||
@ -548,6 +561,11 @@ ClassLoaderData::~ClassLoaderData() {
|
||||
_modules = NULL;
|
||||
}
|
||||
|
||||
if (_unnamed_module != NULL) {
|
||||
_unnamed_module->delete_unnamed_module();
|
||||
_unnamed_module = NULL;
|
||||
}
|
||||
|
||||
// release the metaspace
|
||||
Metaspace *m = _metaspace;
|
||||
if (m != NULL) {
|
||||
|
||||
@ -221,6 +221,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
||||
|
||||
Klass* volatile _klasses; // The classes defined by the class loader.
|
||||
PackageEntryTable* volatile _packages; // The packages defined by the class loader.
|
||||
ModuleEntry* _unnamed_module; // This class loader's unnamed module.
|
||||
ModuleEntryTable* volatile _modules; // The modules defined by the class loader.
|
||||
|
||||
// These method IDs are created for the class loader and set to NULL when the
|
||||
@ -348,6 +349,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
||||
void init_dependencies(TRAPS);
|
||||
PackageEntryTable* packages();
|
||||
bool packages_defined() { return (_packages != NULL); }
|
||||
ModuleEntry* unnamed_module() { return _unnamed_module; }
|
||||
ModuleEntryTable* modules();
|
||||
bool modules_defined() { return (_modules != NULL); }
|
||||
|
||||
|
||||
@ -2863,7 +2863,7 @@ ModuleEntry* java_lang_reflect_Module::module_entry(oop module, TRAPS) {
|
||||
oop loader = java_lang_reflect_Module::loader(module);
|
||||
Handle h_loader = Handle(THREAD, loader);
|
||||
ClassLoaderData* loader_cld = SystemDictionary::register_loader(h_loader, CHECK_NULL);
|
||||
return loader_cld->modules()->unnamed_module();
|
||||
return loader_cld->unnamed_module();
|
||||
}
|
||||
return module_entry;
|
||||
}
|
||||
|
||||
@ -120,7 +120,7 @@ bool ModuleEntry::can_read(ModuleEntry* m) const {
|
||||
return true; // default read edge
|
||||
}
|
||||
}
|
||||
if (!has_reads()) {
|
||||
if (!has_reads_list()) {
|
||||
return false;
|
||||
} else {
|
||||
return _reads->contains(m);
|
||||
@ -129,6 +129,11 @@ bool ModuleEntry::can_read(ModuleEntry* m) const {
|
||||
|
||||
// Add a new module to this module's reads list
|
||||
void ModuleEntry::add_read(ModuleEntry* m) {
|
||||
// Unnamed module is special cased and can read all modules
|
||||
if (!is_named()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MutexLocker m1(Module_lock);
|
||||
if (m == NULL) {
|
||||
set_can_read_all_unnamed();
|
||||
@ -153,6 +158,7 @@ void ModuleEntry::add_read(ModuleEntry* m) {
|
||||
// safepoint. Modules have the same life cycle as their defining class
|
||||
// loaders and should be removed if dead.
|
||||
void ModuleEntry::set_read_walk_required(ClassLoaderData* m_loader_data) {
|
||||
assert(is_named(), "Cannot call set_read_walk_required on unnamed module");
|
||||
assert_locked_or_safepoint(Module_lock);
|
||||
if (!_must_walk_reads &&
|
||||
loader_data() != m_loader_data &&
|
||||
@ -166,7 +172,9 @@ void ModuleEntry::set_read_walk_required(ClassLoaderData* m_loader_data) {
|
||||
}
|
||||
}
|
||||
|
||||
bool ModuleEntry::has_reads() const {
|
||||
// Returns true if the module has a non-empty reads list. As such, the unnamed
|
||||
// module will return false.
|
||||
bool ModuleEntry::has_reads_list() const {
|
||||
assert_locked_or_safepoint(Module_lock);
|
||||
return ((_reads != NULL) && !_reads->is_empty());
|
||||
}
|
||||
@ -175,7 +183,7 @@ bool ModuleEntry::has_reads() const {
|
||||
void ModuleEntry::purge_reads() {
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
|
||||
|
||||
if (_must_walk_reads && has_reads()) {
|
||||
if (_must_walk_reads && has_reads_list()) {
|
||||
// This module's _must_walk_reads flag will be reset based
|
||||
// on the remaining live modules on the reads list.
|
||||
_must_walk_reads = false;
|
||||
@ -205,7 +213,7 @@ void ModuleEntry::module_reads_do(ModuleClosure* const f) {
|
||||
assert_locked_or_safepoint(Module_lock);
|
||||
assert(f != NULL, "invariant");
|
||||
|
||||
if (has_reads()) {
|
||||
if (has_reads_list()) {
|
||||
int reads_len = _reads->length();
|
||||
for (int i = 0; i < reads_len; ++i) {
|
||||
f->do_module(_reads->at(i));
|
||||
@ -219,8 +227,63 @@ void ModuleEntry::delete_reads() {
|
||||
_reads = NULL;
|
||||
}
|
||||
|
||||
ModuleEntry* ModuleEntry::create_unnamed_module(ClassLoaderData* cld) {
|
||||
// The java.lang.Module for this loader's
|
||||
// corresponding unnamed module can be found in the java.lang.ClassLoader object.
|
||||
oop module = java_lang_ClassLoader::unnamedModule(cld->class_loader());
|
||||
ModuleEntry* unnamed_module = new_unnamed_module_entry(Handle(Thread::current(), module), cld);
|
||||
|
||||
// Store pointer to the ModuleEntry in the unnamed module's java.lang.Module
|
||||
// object.
|
||||
java_lang_reflect_Module::set_module_entry(module, unnamed_module);
|
||||
|
||||
return unnamed_module;
|
||||
}
|
||||
|
||||
ModuleEntry* ModuleEntry::create_boot_unnamed_module(ClassLoaderData* cld) {
|
||||
// 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.
|
||||
ModuleEntry* unnamed_module = new_unnamed_module_entry(Handle(), cld);
|
||||
assert(unnamed_module != NULL, "boot loader unnamed module should not be null");
|
||||
return unnamed_module;
|
||||
}
|
||||
|
||||
// When creating an unnamed module, this is called without holding the Module_lock.
|
||||
// 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 = (ModuleEntry*) NEW_C_HEAP_ARRAY(char, sizeof(ModuleEntry), mtModule);
|
||||
|
||||
// Initialize everything BasicHashtable would
|
||||
entry->set_next(NULL);
|
||||
entry->set_hash(0);
|
||||
entry->set_literal(NULL);
|
||||
|
||||
// Initialize fields specific to a ModuleEntry
|
||||
entry->init();
|
||||
|
||||
// Unnamed modules can read all other unnamed modules.
|
||||
entry->set_can_read_all_unnamed();
|
||||
|
||||
if (!module_handle.is_null()) {
|
||||
entry->set_module(cld->add_handle(module_handle));
|
||||
}
|
||||
|
||||
entry->set_loader_data(cld);
|
||||
|
||||
TRACE_INIT_ID(entry);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
void ModuleEntry::delete_unnamed_module() {
|
||||
// Do not need unlink_entry() since the unnamed module is not in the hashtable
|
||||
FREE_C_HEAP_ARRAY(char, this);
|
||||
}
|
||||
|
||||
ModuleEntryTable::ModuleEntryTable(int table_size)
|
||||
: Hashtable<Symbol*, mtModule>(table_size, sizeof(ModuleEntry)), _unnamed_module(NULL)
|
||||
: Hashtable<Symbol*, mtModule>(table_size, sizeof(ModuleEntry))
|
||||
{
|
||||
}
|
||||
|
||||
@ -261,30 +324,6 @@ ModuleEntryTable::~ModuleEntryTable() {
|
||||
free_buckets();
|
||||
}
|
||||
|
||||
void ModuleEntryTable::create_unnamed_module(ClassLoaderData* loader_data) {
|
||||
assert(Module_lock->owned_by_self(), "should have the Module_lock");
|
||||
|
||||
// Each ModuleEntryTable has exactly one unnamed module
|
||||
if (loader_data->is_the_null_class_loader_data()) {
|
||||
// For the boot loader, the java.lang.reflect.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.
|
||||
_unnamed_module = new_entry(0, Handle(), NULL, NULL, NULL, loader_data);
|
||||
} else {
|
||||
// For all other class loaders the java.lang.reflect.Module for their
|
||||
// corresponding unnamed module can be found in the java.lang.ClassLoader object.
|
||||
oop module = java_lang_ClassLoader::unnamedModule(loader_data->class_loader());
|
||||
_unnamed_module = new_entry(0, Handle(Thread::current(), module), NULL, NULL, NULL, loader_data);
|
||||
|
||||
// Store pointer to the ModuleEntry in the unnamed module's java.lang.reflect.Module
|
||||
// object.
|
||||
java_lang_reflect_Module::set_module_entry(module, _unnamed_module);
|
||||
}
|
||||
|
||||
// Add to bucket 0, no name to hash on
|
||||
add_entry(0, _unnamed_module);
|
||||
}
|
||||
|
||||
ModuleEntry* ModuleEntryTable::new_entry(unsigned int hash, Handle module_handle, Symbol* name,
|
||||
Symbol* version, Symbol* location,
|
||||
ClassLoaderData* loader_data) {
|
||||
@ -351,10 +390,7 @@ ModuleEntry* ModuleEntryTable::locked_create_entry_or_null(Handle module_handle,
|
||||
|
||||
// lookup_only by Symbol* to find a ModuleEntry.
|
||||
ModuleEntry* ModuleEntryTable::lookup_only(Symbol* name) {
|
||||
if (name == NULL) {
|
||||
// Return this table's unnamed module
|
||||
return unnamed_module();
|
||||
}
|
||||
assert(name != NULL, "name cannot be NULL");
|
||||
int index = index_for(name);
|
||||
for (ModuleEntry* m = bucket(index); m != NULL; m = m->next()) {
|
||||
if (m->name()->fast_compare(name) == 0) {
|
||||
|
||||
@ -108,7 +108,7 @@ public:
|
||||
bool is_non_jdk_module();
|
||||
|
||||
bool can_read(ModuleEntry* m) const;
|
||||
bool has_reads() const;
|
||||
bool has_reads_list() const;
|
||||
void add_read(ModuleEntry* m);
|
||||
void set_read_walk_required(ClassLoaderData* m_loader_data);
|
||||
|
||||
@ -158,6 +158,12 @@ public:
|
||||
void purge_reads();
|
||||
void delete_reads();
|
||||
|
||||
// Special handling for unnamed module, one per class loader
|
||||
static ModuleEntry* create_unnamed_module(ClassLoaderData* cld);
|
||||
static ModuleEntry* create_boot_unnamed_module(ClassLoaderData* cld);
|
||||
static ModuleEntry* new_unnamed_module_entry(Handle module_handle, ClassLoaderData* cld);
|
||||
void delete_unnamed_module();
|
||||
|
||||
void print(outputStream* st = tty);
|
||||
void verify();
|
||||
};
|
||||
@ -191,7 +197,6 @@ public:
|
||||
|
||||
private:
|
||||
static ModuleEntry* _javabase_module;
|
||||
ModuleEntry* _unnamed_module;
|
||||
|
||||
ModuleEntry* new_entry(unsigned int hash, Handle module_handle, Symbol* name, Symbol* version,
|
||||
Symbol* location, ClassLoaderData* loader_data);
|
||||
@ -228,10 +233,6 @@ public:
|
||||
// purge dead weak references out of reads list
|
||||
void purge_all_module_reads();
|
||||
|
||||
// Special handling for unnamed module, one per class loader's ModuleEntryTable
|
||||
void create_unnamed_module(ClassLoaderData* loader_data);
|
||||
ModuleEntry* unnamed_module() { return _unnamed_module; }
|
||||
|
||||
// Special handling for java.base
|
||||
static ModuleEntry* javabase_moduleEntry() { return _javabase_module; }
|
||||
static void set_javabase_moduleEntry(ModuleEntry* java_base) { _javabase_module = java_base; }
|
||||
|
||||
@ -478,13 +478,11 @@ void Modules::set_bootloader_unnamed_module(jobject module, TRAPS) {
|
||||
|
||||
log_debug(modules)("set_bootloader_unnamed_module(): recording unnamed module for boot loader");
|
||||
|
||||
// Ensure the boot loader's PackageEntryTable has been created
|
||||
ModuleEntryTable* module_table = get_module_entry_table(h_loader, CHECK);
|
||||
|
||||
// Set java.lang.reflect.Module for the boot loader's unnamed module
|
||||
ModuleEntry* unnamed_module = module_table->unnamed_module();
|
||||
// Set java.lang.Module for the boot loader's unnamed module
|
||||
ClassLoaderData* boot_loader_data = ClassLoaderData::the_null_class_loader_data();
|
||||
ModuleEntry* unnamed_module = boot_loader_data->unnamed_module();
|
||||
assert(unnamed_module != NULL, "boot loader's unnamed ModuleEntry not defined");
|
||||
unnamed_module->set_module(ClassLoaderData::the_null_class_loader_data()->add_handle(module_handle));
|
||||
unnamed_module->set_module(boot_loader_data->add_handle(module_handle));
|
||||
// Store pointer to the ModuleEntry in the unnamed module's java.lang.reflect.Module object.
|
||||
java_lang_reflect_Module::set_module_entry(module_handle(), unnamed_module);
|
||||
}
|
||||
|
||||
@ -211,7 +211,7 @@ class PackageEntryTable : public Hashtable<Symbol*, mtModule> {
|
||||
friend class VMStructs;
|
||||
public:
|
||||
enum Constants {
|
||||
_packagetable_entry_size = 1009 // number of entries in package entry table
|
||||
_packagetable_entry_size = 109 // number of entries in package entry table
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
@ -1292,7 +1292,7 @@ bool SystemDictionary::is_shared_class_visible(Symbol* class_name,
|
||||
pkg_entry == NULL ||
|
||||
pkg_entry->in_unnamed_module()) {
|
||||
assert(mod_entry == NULL ||
|
||||
mod_entry == loader_data->modules()->unnamed_module(),
|
||||
mod_entry == loader_data->unnamed_module(),
|
||||
"the unnamed module is not defined in the classloader");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2257,9 +2257,9 @@ ModuleEntry* InstanceKlass::module() const {
|
||||
}
|
||||
const Klass* host = host_klass();
|
||||
if (host == NULL) {
|
||||
return class_loader_data()->modules()->unnamed_module();
|
||||
return class_loader_data()->unnamed_module();
|
||||
}
|
||||
return host->class_loader_data()->modules()->unnamed_module();
|
||||
return host->class_loader_data()->unnamed_module();
|
||||
}
|
||||
|
||||
void InstanceKlass::set_package(ClassLoaderData* loader_data, TRAPS) {
|
||||
@ -2289,9 +2289,9 @@ void InstanceKlass::set_package(ClassLoaderData* loader_data, TRAPS) {
|
||||
assert(ModuleEntryTable::javabase_moduleEntry() != NULL, JAVA_BASE_NAME " module is NULL");
|
||||
_package_entry = loader_data->packages()->lookup(pkg_name, ModuleEntryTable::javabase_moduleEntry());
|
||||
} else {
|
||||
assert(loader_data->modules()->unnamed_module() != NULL, "unnamed module is NULL");
|
||||
assert(loader_data->unnamed_module() != NULL, "unnamed module is NULL");
|
||||
_package_entry = loader_data->packages()->lookup(pkg_name,
|
||||
loader_data->modules()->unnamed_module());
|
||||
loader_data->unnamed_module());
|
||||
}
|
||||
|
||||
// A package should have been successfully created
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user