8207778: Add locking to ModuleEntry and PackageEntry tables
authorhseigel
Fri, 10 Aug 2018 09:30:26 -0400
changeset 51375 b812a85b3aa4
parent 51374 7be0084191ed
child 51376 181e6a03249b
8207778: Add locking to ModuleEntry and PackageEntry tables Summary: Restructure ClassLoaderDataGraph code to simplify using locks in SystemDictionary::do_unloading() Reviewed-by: lfoltan, coleenp
src/hotspot/share/classfile/classLoaderData.cpp
src/hotspot/share/classfile/classLoaderData.hpp
src/hotspot/share/classfile/loaderConstraints.cpp
src/hotspot/share/classfile/moduleEntry.cpp
src/hotspot/share/classfile/packageEntry.cpp
src/hotspot/share/classfile/resolutionErrors.cpp
src/hotspot/share/classfile/systemDictionary.cpp
--- a/src/hotspot/share/classfile/classLoaderData.cpp	Fri Aug 10 14:22:49 2018 +0300
+++ b/src/hotspot/share/classfile/classLoaderData.cpp	Fri Aug 10 09:30:26 2018 -0400
@@ -1418,27 +1418,6 @@
   }
 
   if (seen_dead_loader) {
-    data = _head;
-    while (data != NULL) {
-      // Remove entries in the dictionary of live class loader that have
-      // initiated loading classes in a dead class loader.
-      if (data->dictionary() != NULL) {
-        data->dictionary()->do_unloading();
-      }
-      // Walk a ModuleEntry's reads, and a PackageEntry's exports
-      // lists to determine if there are modules on those lists that are now
-      // dead and should be removed.  A module's life cycle is equivalent
-      // to its defining class loader's life cycle.  Since a module is
-      // considered dead if its class loader is dead, these walks must
-      // occur after each class loader's aliveness is determined.
-      if (data->packages() != NULL) {
-        data->packages()->purge_all_package_exports();
-      }
-      if (data->modules_defined()) {
-        data->modules()->purge_all_module_reads();
-      }
-      data = data->next();
-    }
     JFR_ONLY(post_class_unload_events();)
   }
 
@@ -1447,6 +1426,32 @@
   return seen_dead_loader;
 }
 
+// There's at least one dead class loader.  Purge refererences of healthy module
+// reads lists and package export lists to modules belonging to dead loaders.
+void ClassLoaderDataGraph::clean_module_and_package_info() {
+  ClassLoaderData* data = _head;
+  while (data != NULL) {
+    // Remove entries in the dictionary of live class loader that have
+    // initiated loading classes in a dead class loader.
+    if (data->dictionary() != NULL) {
+      data->dictionary()->do_unloading();
+    }
+    // Walk a ModuleEntry's reads, and a PackageEntry's exports
+    // lists to determine if there are modules on those lists that are now
+    // dead and should be removed.  A module's life cycle is equivalent
+    // to its defining class loader's life cycle.  Since a module is
+    // considered dead if its class loader is dead, these walks must
+    // occur after each class loader's aliveness is determined.
+    if (data->packages() != NULL) {
+      data->packages()->purge_all_package_exports();
+    }
+    if (data->modules_defined()) {
+      data->modules()->purge_all_module_reads();
+    }
+    data = data->next();
+  }
+}
+
 void ClassLoaderDataGraph::purge() {
   assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
   ClassLoaderData* list = _unloading;
--- a/src/hotspot/share/classfile/classLoaderData.hpp	Fri Aug 10 14:22:49 2018 +0300
+++ b/src/hotspot/share/classfile/classLoaderData.hpp	Fri Aug 10 09:30:26 2018 -0400
@@ -97,6 +97,7 @@
 
  public:
   static ClassLoaderData* find_or_create(Handle class_loader);
+  static void clean_module_and_package_info();
   static void purge();
   static void clear_claimed_marks();
   // oops do
--- a/src/hotspot/share/classfile/loaderConstraints.cpp	Fri Aug 10 14:22:49 2018 +0300
+++ b/src/hotspot/share/classfile/loaderConstraints.cpp	Fri Aug 10 09:30:26 2018 -0400
@@ -65,7 +65,7 @@
 
 LoaderConstraintEntry** LoaderConstraintTable::find_loader_constraint(
                                     Symbol* name, Handle loader) {
-
+  assert_lock_strong(SystemDictionary_lock);
   unsigned int hash = compute_hash(name);
   int index = hash_to_index(hash);
   LoaderConstraintEntry** pp = bucket_addr(index);
@@ -89,7 +89,7 @@
 
 
 void LoaderConstraintTable::purge_loader_constraints() {
-  assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
+  assert_locked_or_safepoint(SystemDictionary_lock);
   LogTarget(Info, class, loader, constraints) lt;
   // Remove unloaded entries from constraint table
   for (int index = 0; index < table_size(); index++) {
--- a/src/hotspot/share/classfile/moduleEntry.cpp	Fri Aug 10 14:22:49 2018 +0300
+++ b/src/hotspot/share/classfile/moduleEntry.cpp	Fri Aug 10 09:30:26 2018 -0400
@@ -436,7 +436,7 @@
 // Remove dead modules from all other alive modules' reads list.
 // This should only occur at class unloading.
 void ModuleEntryTable::purge_all_module_reads() {
-  assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
+  assert_locked_or_safepoint(Module_lock);
   for (int i = 0; i < table_size(); i++) {
     for (ModuleEntry* entry = bucket(i);
                       entry != NULL;
--- a/src/hotspot/share/classfile/packageEntry.cpp	Fri Aug 10 14:22:49 2018 +0300
+++ b/src/hotspot/share/classfile/packageEntry.cpp	Fri Aug 10 09:30:26 2018 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, 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
@@ -302,7 +302,7 @@
 
 // Remove dead entries from all packages' exported list
 void PackageEntryTable::purge_all_package_exports() {
-  assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
+  assert_locked_or_safepoint(Module_lock);
   for (int i = 0; i < table_size(); i++) {
     for (PackageEntry* entry = bucket(i);
                        entry != NULL;
--- a/src/hotspot/share/classfile/resolutionErrors.cpp	Fri Aug 10 14:22:49 2018 +0300
+++ b/src/hotspot/share/classfile/resolutionErrors.cpp	Fri Aug 10 09:30:26 2018 -0400
@@ -100,7 +100,7 @@
 // RedefineClasses support - remove matching entry of a
 // constant pool that is going away
 void ResolutionErrorTable::delete_entry(ConstantPool* c) {
-  assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
+  assert_locked_or_safepoint(SystemDictionary_lock);
   for (int i = 0; i < table_size(); i++) {
     for (ResolutionErrorEntry** p = bucket_addr(i); *p != NULL; ) {
       ResolutionErrorEntry* entry = *p;
@@ -118,7 +118,7 @@
 
 // Remove unloaded entries from the table
 void ResolutionErrorTable::purge_resolution_errors() {
-  assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
+  assert_locked_or_safepoint(SystemDictionary_lock);
   for (int i = 0; i < table_size(); i++) {
     for (ResolutionErrorEntry** p = bucket_addr(i); *p != NULL; ) {
       ResolutionErrorEntry* entry = *p;
--- a/src/hotspot/share/classfile/systemDictionary.cpp	Fri Aug 10 14:22:49 2018 +0300
+++ b/src/hotspot/share/classfile/systemDictionary.cpp	Fri Aug 10 09:30:26 2018 -0400
@@ -1853,6 +1853,9 @@
 
     // First, mark for unload all ClassLoaderData referencing a dead class loader.
     unloading_occurred = ClassLoaderDataGraph::do_unloading(do_cleaning);
+    if (unloading_occurred) {
+      ClassLoaderDataGraph::clean_module_and_package_info();
+    }
   }
 
   if (unloading_occurred) {