src/hotspot/share/classfile/dictionary.cpp
changeset 53962 2653e078b057
parent 53601 112ad164d26c
child 54623 1126f0607c70
--- a/src/hotspot/share/classfile/dictionary.cpp	Thu Feb 28 22:11:46 2019 +0100
+++ b/src/hotspot/share/classfile/dictionary.cpp	Thu Feb 28 16:30:31 2019 -0500
@@ -24,7 +24,7 @@
 
 #include "precompiled.hpp"
 #include "classfile/classLoaderData.inline.hpp"
-#include "classfile/dictionary.inline.hpp"
+#include "classfile/dictionary.hpp"
 #include "classfile/protectionDomainCache.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "logging/log.hpp"
@@ -35,6 +35,7 @@
 #include "oops/oop.inline.hpp"
 #include "runtime/atomic.hpp"
 #include "runtime/orderAccess.hpp"
+#include "runtime/mutexLocker.hpp"
 #include "runtime/safepointVerifiers.hpp"
 #include "utilities/hashtable.inline.hpp"
 
@@ -80,6 +81,8 @@
 void Dictionary::free_entry(DictionaryEntry* entry) {
   // avoid recursion when deleting linked list
   // pd_set is accessed during a safepoint.
+  // This doesn't require a lock because nothing is reading this
+  // entry anymore.  The ClassLoader is dead.
   while (entry->pd_set() != NULL) {
     ProtectionDomainEntry* to_delete = entry->pd_set();
     entry->set_pd_set(to_delete->next());
@@ -146,11 +149,14 @@
 }
 
 bool DictionaryEntry::contains_protection_domain(oop protection_domain) const {
+  // Lock the pd_set list.  This lock cannot safepoint since the caller holds
+  // a Dictionary entry, which can be moved if the Dictionary is resized.
+  MutexLockerEx ml(ProtectionDomainSet_lock, Mutex::_no_safepoint_check_flag);
 #ifdef ASSERT
   if (oopDesc::equals(protection_domain, instance_klass()->protection_domain())) {
     // Ensure this doesn't show up in the pd_set (invariant)
     bool in_pd_set = false;
-    for (ProtectionDomainEntry* current = pd_set_acquire();
+    for (ProtectionDomainEntry* current = pd_set();
                                 current != NULL;
                                 current = current->next()) {
       if (oopDesc::equals(current->object_no_keepalive(), protection_domain)) {
@@ -170,7 +176,7 @@
     return true;
   }
 
-  for (ProtectionDomainEntry* current = pd_set_acquire();
+  for (ProtectionDomainEntry* current = pd_set();
                               current != NULL;
                               current = current->next()) {
     if (oopDesc::equals(current->object_no_keepalive(), protection_domain)) return true;
@@ -183,13 +189,12 @@
   assert_locked_or_safepoint(SystemDictionary_lock);
   if (!contains_protection_domain(protection_domain())) {
     ProtectionDomainCacheEntry* entry = SystemDictionary::cache_get(protection_domain);
+    // The pd_set in the dictionary entry is protected by a low level lock.
+    // With concurrent PD table cleanup, these links could be broken.
+    MutexLockerEx ml(ProtectionDomainSet_lock, Mutex::_no_safepoint_check_flag);
     ProtectionDomainEntry* new_head =
                 new ProtectionDomainEntry(entry, pd_set());
-    // Warning: Preserve store ordering.  The SystemDictionary is read
-    //          without locks.  The new ProtectionDomainEntry must be
-    //          complete before other threads can be allowed to see it
-    //          via a store to _pd_set.
-    release_set_pd_set(new_head);
+    set_pd_set(new_head);
   }
   LogTarget(Trace, protectiondomain) lt;
   if (lt.is_enabled()) {
@@ -348,6 +353,56 @@
   return entry->is_valid_protection_domain(protection_domain);
 }
 
+// During class loading we may have cached a protection domain that has
+// since been unreferenced, so this entry should be cleared.
+void Dictionary::clean_cached_protection_domains() {
+  assert_locked_or_safepoint(SystemDictionary_lock);
+
+  if (loader_data()->is_the_null_class_loader_data()) {
+    // Classes in the boot loader are not loaded with protection domains
+    return;
+  }
+
+  for (int index = 0; index < table_size(); index++) {
+    for (DictionaryEntry* probe = bucket(index);
+                          probe != NULL;
+                          probe = probe->next()) {
+      Klass* e = probe->instance_klass();
+
+      MutexLockerEx ml(ProtectionDomainSet_lock, Mutex::_no_safepoint_check_flag);
+      ProtectionDomainEntry* current = probe->pd_set();
+      ProtectionDomainEntry* prev = NULL;
+      while (current != NULL) {
+        if (current->object_no_keepalive() == NULL) {
+          LogTarget(Debug, protectiondomain) lt;
+          if (lt.is_enabled()) {
+            ResourceMark rm;
+            // Print out trace information
+            LogStream ls(lt);
+            ls.print_cr("PD in set is not alive:");
+            ls.print("class loader: "); loader_data()->class_loader()->print_value_on(&ls);
+            ls.print(" loading: "); probe->instance_klass()->print_value_on(&ls);
+            ls.cr();
+          }
+          if (probe->pd_set() == current) {
+            probe->set_pd_set(current->next());
+          } else {
+            assert(prev != NULL, "should be set by alive entry");
+            prev->set_next(current->next());
+          }
+          ProtectionDomainEntry* to_delete = current;
+          current = current->next();
+          delete to_delete;
+        } else {
+          prev = current;
+          current = current->next();
+        }
+      }
+    }
+  }
+}
+
+
 SymbolPropertyTable::SymbolPropertyTable(int table_size)
   : Hashtable<Symbol*, mtSymbol>(table_size, sizeof(SymbolPropertyEntry))
 {
@@ -404,6 +459,25 @@
   }
 }
 
+void DictionaryEntry::verify_protection_domain_set() {
+  MutexLockerEx ml(ProtectionDomainSet_lock, Mutex::_no_safepoint_check_flag);
+  for (ProtectionDomainEntry* current = pd_set(); // accessed at a safepoint
+                              current != NULL;
+                              current = current->_next) {
+    guarantee(oopDesc::is_oop_or_null(current->_pd_cache->object_no_keepalive()), "Invalid oop");
+  }
+}
+
+void DictionaryEntry::print_count(outputStream *st) {
+  MutexLockerEx ml(ProtectionDomainSet_lock, Mutex::_no_safepoint_check_flag);
+  int count = 0;
+  for (ProtectionDomainEntry* current = pd_set();  // accessed inside SD lock
+                              current != NULL;
+                              current = current->_next) {
+    count++;
+  }
+  st->print_cr("pd set count = #%d", count);
+}
 
 // ----------------------------------------------------------------------------