# HG changeset patch # User rprotacio # Date 1492535982 14400 # Node ID c46632622b17c023b683645e3d37787e12bcba9d # Parent 742f8b16d00c92a06ff73d5e8ed62db557e94e63 8176472: Lazily create ModuleEntryTable Summary: 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 diff -r 742f8b16d00c -r c46632622b17 hotspot/src/share/vm/classfile/classLoaderData.cpp --- a/hotspot/src/share/vm/classfile/classLoaderData.cpp Fri Mar 24 16:35:37 2017 +0100 +++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp Tue Apr 18 13:19:42 2017 -0400 @@ -97,6 +97,21 @@ _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::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 @@ // 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 @@ return alive; } - ClassLoaderData::~ClassLoaderData() { // Release C heap structures for all the classes. classes_do(InstanceKlass::release_C_heap_structures); @@ -548,6 +561,11 @@ _modules = NULL; } + if (_unnamed_module != NULL) { + _unnamed_module->delete_unnamed_module(); + _unnamed_module = NULL; + } + // release the metaspace Metaspace *m = _metaspace; if (m != NULL) { diff -r 742f8b16d00c -r c46632622b17 hotspot/src/share/vm/classfile/classLoaderData.hpp --- a/hotspot/src/share/vm/classfile/classLoaderData.hpp Fri Mar 24 16:35:37 2017 +0100 +++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp Tue Apr 18 13:19:42 2017 -0400 @@ -221,6 +221,7 @@ 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 @@ 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); } diff -r 742f8b16d00c -r c46632622b17 hotspot/src/share/vm/classfile/javaClasses.cpp --- a/hotspot/src/share/vm/classfile/javaClasses.cpp Fri Mar 24 16:35:37 2017 +0100 +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp Tue Apr 18 13:19:42 2017 -0400 @@ -2863,7 +2863,7 @@ 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; } diff -r 742f8b16d00c -r c46632622b17 hotspot/src/share/vm/classfile/moduleEntry.cpp --- a/hotspot/src/share/vm/classfile/moduleEntry.cpp Fri Mar 24 16:35:37 2017 +0100 +++ b/hotspot/src/share/vm/classfile/moduleEntry.cpp Tue Apr 18 13:19:42 2017 -0400 @@ -120,7 +120,7 @@ return true; // default read edge } } - if (!has_reads()) { + if (!has_reads_list()) { return false; } else { return _reads->contains(m); @@ -129,6 +129,11 @@ // 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 @@ // 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 @@ } } -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 @@ 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 @@ 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 @@ _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(table_size, sizeof(ModuleEntry)), _unnamed_module(NULL) + : Hashtable(table_size, sizeof(ModuleEntry)) { } @@ -261,30 +324,6 @@ 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 @@ // 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) { diff -r 742f8b16d00c -r c46632622b17 hotspot/src/share/vm/classfile/moduleEntry.hpp --- a/hotspot/src/share/vm/classfile/moduleEntry.hpp Fri Mar 24 16:35:37 2017 +0100 +++ b/hotspot/src/share/vm/classfile/moduleEntry.hpp Tue Apr 18 13:19:42 2017 -0400 @@ -108,7 +108,7 @@ 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 @@ 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 @@ 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 @@ // 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; } diff -r 742f8b16d00c -r c46632622b17 hotspot/src/share/vm/classfile/modules.cpp --- a/hotspot/src/share/vm/classfile/modules.cpp Fri Mar 24 16:35:37 2017 +0100 +++ b/hotspot/src/share/vm/classfile/modules.cpp Tue Apr 18 13:19:42 2017 -0400 @@ -478,13 +478,11 @@ 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); } diff -r 742f8b16d00c -r c46632622b17 hotspot/src/share/vm/classfile/packageEntry.hpp --- a/hotspot/src/share/vm/classfile/packageEntry.hpp Fri Mar 24 16:35:37 2017 +0100 +++ b/hotspot/src/share/vm/classfile/packageEntry.hpp Tue Apr 18 13:19:42 2017 -0400 @@ -211,7 +211,7 @@ 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: diff -r 742f8b16d00c -r c46632622b17 hotspot/src/share/vm/classfile/systemDictionary.cpp --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Fri Mar 24 16:35:37 2017 +0100 +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Tue Apr 18 13:19:42 2017 -0400 @@ -1292,7 +1292,7 @@ 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; } diff -r 742f8b16d00c -r c46632622b17 hotspot/src/share/vm/oops/instanceKlass.cpp --- a/hotspot/src/share/vm/oops/instanceKlass.cpp Fri Mar 24 16:35:37 2017 +0100 +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Tue Apr 18 13:19:42 2017 -0400 @@ -2257,9 +2257,9 @@ } 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 @@ 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