changeset 46387:c46632622b17

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
author rprotacio
date Tue, 18 Apr 2017 13:19:42 -0400
parents 742f8b16d00c
children d7a164ad6b7f d55896236dfd d497d892ab11
files hotspot/src/share/vm/classfile/classLoaderData.cpp hotspot/src/share/vm/classfile/classLoaderData.hpp hotspot/src/share/vm/classfile/javaClasses.cpp hotspot/src/share/vm/classfile/moduleEntry.cpp hotspot/src/share/vm/classfile/moduleEntry.hpp hotspot/src/share/vm/classfile/modules.cpp hotspot/src/share/vm/classfile/packageEntry.hpp hotspot/src/share/vm/classfile/systemDictionary.cpp hotspot/src/share/vm/oops/instanceKlass.cpp
diffstat 9 files changed, 112 insertions(+), 57 deletions(-) [+]
line wrap: on
line diff
--- 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) {
--- 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); }
 
--- 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;
 }
--- 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<Symbol*, mtModule>(table_size, sizeof(ModuleEntry)), _unnamed_module(NULL)
+  : Hashtable<Symbol*, mtModule>(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) {
--- 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; }
--- 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);
 }
--- 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:
--- 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;
       }
--- 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