8178336: Unnecessary SystemDictionary walk for Protection domain liveness
authorcoleenp
Thu, 13 Apr 2017 09:42:10 -0400
changeset 46382 5520c435279b
parent 46381 020219e46c86
child 46383 24999171edf9
8178336: Unnecessary SystemDictionary walk for Protection domain liveness Summary: remove system dictionary walk and pass strong closure for !ClassUnloading Reviewed-by: jiangli, iklam
hotspot/src/share/vm/classfile/dictionary.cpp
hotspot/src/share/vm/classfile/dictionary.hpp
hotspot/src/share/vm/classfile/protectionDomainCache.cpp
hotspot/src/share/vm/classfile/protectionDomainCache.hpp
--- a/hotspot/src/share/vm/classfile/dictionary.cpp	Wed Apr 12 17:52:04 2017 -0400
+++ b/hotspot/src/share/vm/classfile/dictionary.cpp	Thu Apr 13 09:42:10 2017 -0400
@@ -26,6 +26,7 @@
 #include "classfile/classLoaderData.inline.hpp"
 #include "classfile/sharedClassUtil.hpp"
 #include "classfile/dictionary.hpp"
+#include "classfile/protectionDomainCache.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "classfile/systemDictionaryShared.hpp"
 #include "memory/iterator.hpp"
@@ -147,7 +148,6 @@
   assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
 
   // Remove unloadable entries and classes from system dictionary
-  // The placeholder array has been handled in always_strong_oops_do.
   DictionaryEntry* probe = NULL;
   for (int index = 0; index < table_size(); index++) {
     for (DictionaryEntry** p = bucket_addr(index); *p != NULL; ) {
@@ -157,7 +157,7 @@
 
       InstanceKlass* ik = InstanceKlass::cast(e);
 
-      // Non-unloadable classes were handled in always_strong_oops_do
+      // Only unload classes that are not strongly reachable
       if (!is_strongly_reachable(loader_data, e)) {
         // Entry was not visited in phase1 (negated test from phase1)
         assert(!loader_data->is_the_null_class_loader_data(), "unloading entry with null class loader");
@@ -202,25 +202,18 @@
 }
 
 void Dictionary::roots_oops_do(OopClosure* strong, OopClosure* weak) {
-  // Skip the strong roots probe marking if the closures are the same.
-  if (strong == weak) {
-    oops_do(strong);
-    return;
+  // Do strong roots marking if the closures are the same.
+  if (strong == weak || !ClassUnloading) {
+    // Only the protection domain oops contain references into the heap. Iterate
+    // over all of them.
+    _pd_cache_table->oops_do(strong);
+  } else {
+   if (weak != NULL) {
+     _pd_cache_table->oops_do(weak);
+   }
   }
+}
 
-  for (int index = 0; index < table_size(); index++) {
-    for (DictionaryEntry *probe = bucket(index);
-                          probe != NULL;
-                          probe = probe->next()) {
-      Klass* e = probe->klass();
-      ClassLoaderData* loader_data = probe->loader_data();
-      if (is_strongly_reachable(loader_data, e)) {
-        probe->set_strongly_reachable();
-      }
-    }
-  }
-  _pd_cache_table->roots_oops_do(strong, weak);
-}
 
 void Dictionary::remove_classes_in_error_state() {
   assert(DumpSharedSpaces, "supported only when dumping");
@@ -245,27 +238,6 @@
   }
 }
 
-void Dictionary::always_strong_oops_do(OopClosure* blk) {
-  // Follow all system classes and temporary placeholders in dictionary; only
-  // protection domain oops contain references into the heap. In a first
-  // pass over the system dictionary determine which need to be treated as
-  // strongly reachable and mark them as such.
-  for (int index = 0; index < table_size(); index++) {
-    for (DictionaryEntry *probe = bucket(index);
-                          probe != NULL;
-                          probe = probe->next()) {
-      Klass* e = probe->klass();
-      ClassLoaderData* loader_data = probe->loader_data();
-      if (is_strongly_reachable(loader_data, e)) {
-        probe->set_strongly_reachable();
-      }
-    }
-  }
-  // Then iterate over the protection domain cache to apply the closure on the
-  // previously marked ones.
-  _pd_cache_table->always_strong_oops_do(blk);
-}
-
 //   Just the classes from defining class loaders
 void Dictionary::classes_do(void f(Klass*)) {
   for (int index = 0; index < table_size(); index++) {
@@ -474,153 +446,6 @@
 }
 
 
-unsigned int ProtectionDomainCacheTable::compute_hash(Handle protection_domain) {
-  // Identity hash can safepoint, so keep protection domain in a Handle.
-  return (unsigned int)(protection_domain->identity_hash());
-}
-
-int ProtectionDomainCacheTable::index_for(Handle protection_domain) {
-  return hash_to_index(compute_hash(protection_domain));
-}
-
-ProtectionDomainCacheTable::ProtectionDomainCacheTable(int table_size)
-  : Hashtable<oop, mtClass>(table_size, sizeof(ProtectionDomainCacheEntry))
-{
-}
-
-void ProtectionDomainCacheTable::unlink(BoolObjectClosure* is_alive) {
-  assert(SafepointSynchronize::is_at_safepoint(), "must be");
-  for (int i = 0; i < table_size(); ++i) {
-    ProtectionDomainCacheEntry** p = bucket_addr(i);
-    ProtectionDomainCacheEntry* entry = bucket(i);
-    while (entry != NULL) {
-      if (is_alive->do_object_b(entry->literal())) {
-        p = entry->next_addr();
-      } else {
-        *p = entry->next();
-        free_entry(entry);
-      }
-      entry = *p;
-    }
-  }
-}
-
-void ProtectionDomainCacheTable::oops_do(OopClosure* f) {
-  for (int index = 0; index < table_size(); index++) {
-    for (ProtectionDomainCacheEntry* probe = bucket(index);
-                                     probe != NULL;
-                                     probe = probe->next()) {
-      probe->oops_do(f);
-    }
-  }
-}
-
-void ProtectionDomainCacheTable::roots_oops_do(OopClosure* strong, OopClosure* weak) {
-  for (int index = 0; index < table_size(); index++) {
-    for (ProtectionDomainCacheEntry* probe = bucket(index);
-                                     probe != NULL;
-                                     probe = probe->next()) {
-      if (probe->is_strongly_reachable()) {
-        probe->reset_strongly_reachable();
-        probe->oops_do(strong);
-      } else {
-        if (weak != NULL) {
-          probe->oops_do(weak);
-        }
-      }
-    }
-  }
-}
-
-uint ProtectionDomainCacheTable::bucket_size() {
-  return sizeof(ProtectionDomainCacheEntry);
-}
-
-#ifndef PRODUCT
-void ProtectionDomainCacheTable::print() {
-  tty->print_cr("Protection domain cache table (table_size=%d, classes=%d)",
-                table_size(), number_of_entries());
-  for (int index = 0; index < table_size(); index++) {
-    for (ProtectionDomainCacheEntry* probe = bucket(index);
-                                     probe != NULL;
-                                     probe = probe->next()) {
-      probe->print();
-    }
-  }
-}
-
-void ProtectionDomainCacheEntry::print() {
-  tty->print_cr("entry " PTR_FORMAT " value " PTR_FORMAT " strongly_reachable %d next " PTR_FORMAT,
-                p2i(this), p2i(literal()), _strongly_reachable, p2i(next()));
-}
-#endif
-
-void ProtectionDomainCacheTable::verify() {
-  int element_count = 0;
-  for (int index = 0; index < table_size(); index++) {
-    for (ProtectionDomainCacheEntry* probe = bucket(index);
-                                     probe != NULL;
-                                     probe = probe->next()) {
-      probe->verify();
-      element_count++;
-    }
-  }
-  guarantee(number_of_entries() == element_count,
-            "Verify of protection domain cache table failed");
-  DEBUG_ONLY(verify_lookup_length((double)number_of_entries() / table_size(), "Domain Cache Table"));
-}
-
-void ProtectionDomainCacheEntry::verify() {
-  guarantee(literal()->is_oop(), "must be an oop");
-}
-
-void ProtectionDomainCacheTable::always_strong_oops_do(OopClosure* f) {
-  // the caller marked the protection domain cache entries that we need to apply
-  // the closure on. Only process them.
-  for (int index = 0; index < table_size(); index++) {
-    for (ProtectionDomainCacheEntry* probe = bucket(index);
-                                     probe != NULL;
-                                     probe = probe->next()) {
-      if (probe->is_strongly_reachable()) {
-        probe->reset_strongly_reachable();
-        probe->oops_do(f);
-      }
-    }
-  }
-}
-
-ProtectionDomainCacheEntry* ProtectionDomainCacheTable::get(Handle protection_domain) {
-  unsigned int hash = compute_hash(protection_domain);
-  int index = hash_to_index(hash);
-
-  ProtectionDomainCacheEntry* entry = find_entry(index, protection_domain);
-  if (entry == NULL) {
-    entry = add_entry(index, hash, protection_domain);
-  }
-  return entry;
-}
-
-ProtectionDomainCacheEntry* ProtectionDomainCacheTable::find_entry(int index, Handle protection_domain) {
-  for (ProtectionDomainCacheEntry* e = bucket(index); e != NULL; e = e->next()) {
-    if (e->protection_domain() == protection_domain()) {
-      return e;
-    }
-  }
-
-  return NULL;
-}
-
-ProtectionDomainCacheEntry* ProtectionDomainCacheTable::add_entry(int index, unsigned int hash, Handle protection_domain) {
-  assert_locked_or_safepoint(SystemDictionary_lock);
-  assert(index == index_for(protection_domain), "incorrect index?");
-  assert(find_entry(index, protection_domain) == NULL, "no double entry");
-
-  ProtectionDomainCacheEntry* p = new_entry(hash, protection_domain);
-  Hashtable<oop, mtClass>::add_entry(index, p);
-  return p;
-}
-
-
 SymbolPropertyTable::SymbolPropertyTable(int table_size)
   : Hashtable<Symbol*, mtSymbol>(table_size, sizeof(SymbolPropertyEntry))
 {
--- a/hotspot/src/share/vm/classfile/dictionary.hpp	Wed Apr 12 17:52:04 2017 -0400
+++ b/hotspot/src/share/vm/classfile/dictionary.hpp	Thu Apr 13 09:42:10 2017 -0400
@@ -25,6 +25,7 @@
 #ifndef SHARE_VM_CLASSFILE_DICTIONARY_HPP
 #define SHARE_VM_CLASSFILE_DICTIONARY_HPP
 
+#include "classfile/protectionDomainCache.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "oops/instanceKlass.hpp"
 #include "oops/oop.hpp"
@@ -32,9 +33,6 @@
 #include "utilities/ostream.hpp"
 
 class DictionaryEntry;
-class PSPromotionManager;
-class ProtectionDomainCacheTable;
-class ProtectionDomainCacheEntry;
 class BoolObjectClosure;
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -89,7 +87,6 @@
 
   // GC support
   void oops_do(OopClosure* f);
-  void always_strong_oops_do(OopClosure* blk);
   void roots_oops_do(OopClosure* strong, OopClosure* weak);
 
   void classes_do(void f(Klass*));
@@ -131,110 +128,6 @@
   void verify();
 };
 
-// The following classes can be in dictionary.cpp, but we need these
-// to be in header file so that SA's vmStructs can access them.
-class ProtectionDomainCacheEntry : public HashtableEntry<oop, mtClass> {
-  friend class VMStructs;
- private:
-  // Flag indicating whether this protection domain entry is strongly reachable.
-  // Used during iterating over the system dictionary to remember oops that need
-  // to be updated.
-  bool _strongly_reachable;
- public:
-  oop protection_domain() { return literal(); }
-
-  void init() {
-    _strongly_reachable = false;
-  }
-
-  ProtectionDomainCacheEntry* next() {
-    return (ProtectionDomainCacheEntry*)HashtableEntry<oop, mtClass>::next();
-  }
-
-  ProtectionDomainCacheEntry** next_addr() {
-    return (ProtectionDomainCacheEntry**)HashtableEntry<oop, mtClass>::next_addr();
-  }
-
-  void oops_do(OopClosure* f) {
-    f->do_oop(literal_addr());
-  }
-
-  void set_strongly_reachable()   { _strongly_reachable = true; }
-  bool is_strongly_reachable()    { return _strongly_reachable; }
-  void reset_strongly_reachable() { _strongly_reachable = false; }
-
-  void print() PRODUCT_RETURN;
-  void verify();
-};
-
-// The ProtectionDomainCacheTable contains all protection domain oops. The system
-// dictionary entries reference its entries instead of having references to oops
-// directly.
-// This is used to speed up system dictionary iteration: the oops in the
-// protection domain are the only ones referring the Java heap. So when there is
-// need to update these, instead of going over every entry of the system dictionary,
-// we only need to iterate over this set.
-// The amount of different protection domains used is typically magnitudes smaller
-// than the number of system dictionary entries (loaded classes).
-class ProtectionDomainCacheTable : public Hashtable<oop, mtClass> {
-  friend class VMStructs;
-private:
-  ProtectionDomainCacheEntry* bucket(int i) {
-    return (ProtectionDomainCacheEntry*) Hashtable<oop, mtClass>::bucket(i);
-  }
-
-  // The following method is not MT-safe and must be done under lock.
-  ProtectionDomainCacheEntry** bucket_addr(int i) {
-    return (ProtectionDomainCacheEntry**) Hashtable<oop, mtClass>::bucket_addr(i);
-  }
-
-  ProtectionDomainCacheEntry* new_entry(unsigned int hash, Handle protection_domain) {
-    ProtectionDomainCacheEntry* entry = (ProtectionDomainCacheEntry*) Hashtable<oop, mtClass>::new_entry(hash, protection_domain());
-    entry->init();
-    return entry;
-  }
-
-  static unsigned int compute_hash(Handle protection_domain);
-
-  int index_for(Handle protection_domain);
-  ProtectionDomainCacheEntry* add_entry(int index, unsigned int hash, Handle protection_domain);
-  ProtectionDomainCacheEntry* find_entry(int index, Handle protection_domain);
-
-public:
-
-  ProtectionDomainCacheTable(int table_size);
-
-  ProtectionDomainCacheEntry* get(Handle protection_domain);
-
-  void unlink(BoolObjectClosure* cl);
-
-  // GC support
-  void oops_do(OopClosure* f);
-  void always_strong_oops_do(OopClosure* f);
-  void roots_oops_do(OopClosure* strong, OopClosure* weak);
-
-  static uint bucket_size();
-
-  void print() PRODUCT_RETURN;
-  void verify();
-};
-
-
-class ProtectionDomainEntry :public CHeapObj<mtClass> {
-  friend class VMStructs;
- public:
-  ProtectionDomainEntry* _next;
-  ProtectionDomainCacheEntry* _pd_cache;
-
-  ProtectionDomainEntry(ProtectionDomainCacheEntry* pd_cache, ProtectionDomainEntry* next) {
-    _pd_cache = pd_cache;
-    _next     = next;
-  }
-
-  ProtectionDomainEntry* next() { return _next; }
-  oop protection_domain() { return _pd_cache->protection_domain(); }
-};
-
 // An entry in the system dictionary, this describes a class as
 // { InstanceKlass*, loader, protection_domain }.
 
@@ -296,14 +189,6 @@
          : contains_protection_domain(protection_domain());
   }
 
-  void set_strongly_reachable() {
-    for (ProtectionDomainEntry* current = _pd_set;
-                                current != NULL;
-                                current = current->_next) {
-      current->_pd_cache->set_strongly_reachable();
-    }
-  }
-
   void verify_protection_domain_set() {
     for (ProtectionDomainEntry* current = _pd_set;
                                 current != NULL;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/classfile/protectionDomainCache.cpp	Thu Apr 13 09:42:10 2017 -0400
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2017, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/protectionDomainCache.hpp"
+#include "classfile/systemDictionary.hpp"
+#include "memory/iterator.hpp"
+#include "memory/resourceArea.hpp"
+#include "oops/oop.inline.hpp"
+#include "utilities/hashtable.inline.hpp"
+
+unsigned int ProtectionDomainCacheTable::compute_hash(Handle protection_domain) {
+  // Identity hash can safepoint, so keep protection domain in a Handle.
+  return (unsigned int)(protection_domain->identity_hash());
+}
+
+int ProtectionDomainCacheTable::index_for(Handle protection_domain) {
+  return hash_to_index(compute_hash(protection_domain));
+}
+
+ProtectionDomainCacheTable::ProtectionDomainCacheTable(int table_size)
+  : Hashtable<oop, mtClass>(table_size, sizeof(ProtectionDomainCacheEntry))
+{
+}
+
+void ProtectionDomainCacheTable::unlink(BoolObjectClosure* is_alive) {
+  assert(SafepointSynchronize::is_at_safepoint(), "must be");
+  for (int i = 0; i < table_size(); ++i) {
+    ProtectionDomainCacheEntry** p = bucket_addr(i);
+    ProtectionDomainCacheEntry* entry = bucket(i);
+    while (entry != NULL) {
+      if (is_alive->do_object_b(entry->literal())) {
+        p = entry->next_addr();
+      } else {
+        if (log_is_enabled(Debug, protectiondomain)) {
+          outputStream* log = Log(protectiondomain)::debug_stream();
+          log->print("protection domain unlinked: ");
+          entry->literal()->print_value_on(log);
+          log->cr();
+        }
+        *p = entry->next();
+        free_entry(entry);
+      }
+      entry = *p;
+    }
+  }
+}
+
+void ProtectionDomainCacheTable::oops_do(OopClosure* f) {
+  for (int index = 0; index < table_size(); index++) {
+    for (ProtectionDomainCacheEntry* probe = bucket(index);
+                                     probe != NULL;
+                                     probe = probe->next()) {
+      probe->oops_do(f);
+    }
+  }
+}
+
+#ifndef PRODUCT
+void ProtectionDomainCacheTable::print() {
+  tty->print_cr("Protection domain cache table (table_size=%d, classes=%d)",
+                table_size(), number_of_entries());
+  for (int index = 0; index < table_size(); index++) {
+    for (ProtectionDomainCacheEntry* probe = bucket(index);
+                                     probe != NULL;
+                                     probe = probe->next()) {
+      probe->print();
+    }
+  }
+}
+
+void ProtectionDomainCacheEntry::print() {
+  tty->print_cr("entry " PTR_FORMAT " value " PTR_FORMAT " next " PTR_FORMAT,
+                p2i(this), p2i(literal()), p2i(next()));
+}
+#endif
+
+void ProtectionDomainCacheTable::verify() {
+  int element_count = 0;
+  for (int index = 0; index < table_size(); index++) {
+    for (ProtectionDomainCacheEntry* probe = bucket(index);
+                                     probe != NULL;
+                                     probe = probe->next()) {
+      probe->verify();
+      element_count++;
+    }
+  }
+  guarantee(number_of_entries() == element_count,
+            "Verify of protection domain cache table failed");
+  DEBUG_ONLY(verify_lookup_length((double)number_of_entries() / table_size(), "Domain Cache Table"));
+}
+
+void ProtectionDomainCacheEntry::verify() {
+  guarantee(literal()->is_oop(), "must be an oop");
+}
+
+ProtectionDomainCacheEntry* ProtectionDomainCacheTable::get(Handle protection_domain) {
+  unsigned int hash = compute_hash(protection_domain);
+  int index = hash_to_index(hash);
+
+  ProtectionDomainCacheEntry* entry = find_entry(index, protection_domain);
+  if (entry == NULL) {
+    entry = add_entry(index, hash, protection_domain);
+  }
+  return entry;
+}
+
+ProtectionDomainCacheEntry* ProtectionDomainCacheTable::find_entry(int index, Handle protection_domain) {
+  for (ProtectionDomainCacheEntry* e = bucket(index); e != NULL; e = e->next()) {
+    if (e->protection_domain() == protection_domain()) {
+      return e;
+    }
+  }
+
+  return NULL;
+}
+
+ProtectionDomainCacheEntry* ProtectionDomainCacheTable::add_entry(int index, unsigned int hash, Handle protection_domain) {
+  assert_locked_or_safepoint(SystemDictionary_lock);
+  assert(index == index_for(protection_domain), "incorrect index?");
+  assert(find_entry(index, protection_domain) == NULL, "no double entry");
+
+  ProtectionDomainCacheEntry* p = new_entry(hash, protection_domain);
+  Hashtable<oop, mtClass>::add_entry(index, p);
+  return p;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/classfile/protectionDomainCache.hpp	Thu Apr 13 09:42:10 2017 -0400
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2017, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_CLASSFILE_PROTECTIONDOMAINCACHE_HPP
+#define SHARE_VM_CLASSFILE_PROTECTIONDOMAINCACHE_HPP
+
+#include "oops/oop.hpp"
+#include "memory/iterator.hpp"
+#include "utilities/hashtable.hpp"
+
+// This class caches the approved protection domains that can access loaded classes.
+// Dictionary entry pd_set point to entries in this hashtable.   Please refer
+// to dictionary.hpp pd_set for more information about how protection domain entries
+// are used.
+// This table is walked during GC, rather than the entire system dictionary
+class ProtectionDomainCacheEntry : public HashtableEntry<oop, mtClass> {
+  friend class VMStructs;
+ public:
+  oop protection_domain() { return literal(); }
+
+  ProtectionDomainCacheEntry* next() {
+    return (ProtectionDomainCacheEntry*)HashtableEntry<oop, mtClass>::next();
+  }
+
+  ProtectionDomainCacheEntry** next_addr() {
+    return (ProtectionDomainCacheEntry**)HashtableEntry<oop, mtClass>::next_addr();
+  }
+
+  void oops_do(OopClosure* f) {
+    f->do_oop(literal_addr());
+  }
+
+  void print() PRODUCT_RETURN;
+  void verify();
+};
+
+// The ProtectionDomainCacheTable contains all protection domain oops. The system
+// dictionary entries reference its entries instead of having references to oops
+// directly.
+// This is used to speed up system dictionary iteration: the oops in the
+// protection domain are the only ones referring the Java heap. So when there is
+// need to update these, instead of going over every entry of the system dictionary,
+// we only need to iterate over this set.
+// The amount of different protection domains used is typically magnitudes smaller
+// than the number of system dictionary entries (loaded classes).
+class ProtectionDomainCacheTable : public Hashtable<oop, mtClass> {
+  friend class VMStructs;
+private:
+  ProtectionDomainCacheEntry* bucket(int i) {
+    return (ProtectionDomainCacheEntry*) Hashtable<oop, mtClass>::bucket(i);
+  }
+
+  // The following method is not MT-safe and must be done under lock.
+  ProtectionDomainCacheEntry** bucket_addr(int i) {
+    return (ProtectionDomainCacheEntry**) Hashtable<oop, mtClass>::bucket_addr(i);
+  }
+
+  ProtectionDomainCacheEntry* new_entry(unsigned int hash, Handle protection_domain) {
+    ProtectionDomainCacheEntry* entry = (ProtectionDomainCacheEntry*) Hashtable<oop, mtClass>::new_entry(hash, protection_domain());
+    return entry;
+  }
+
+  static unsigned int compute_hash(Handle protection_domain);
+
+  int index_for(Handle protection_domain);
+  ProtectionDomainCacheEntry* add_entry(int index, unsigned int hash, Handle protection_domain);
+  ProtectionDomainCacheEntry* find_entry(int index, Handle protection_domain);
+
+public:
+  ProtectionDomainCacheTable(int table_size);
+  ProtectionDomainCacheEntry* get(Handle protection_domain);
+
+  void unlink(BoolObjectClosure* cl);
+
+  // GC support
+  void oops_do(OopClosure* f);
+
+  void print() PRODUCT_RETURN;
+  void verify();
+};
+
+
+class ProtectionDomainEntry :public CHeapObj<mtClass> {
+  friend class VMStructs;
+ public:
+  ProtectionDomainEntry* _next;
+  ProtectionDomainCacheEntry* _pd_cache;
+
+  ProtectionDomainEntry(ProtectionDomainCacheEntry* pd_cache, ProtectionDomainEntry* next) {
+    _pd_cache = pd_cache;
+    _next     = next;
+  }
+
+  ProtectionDomainEntry* next() { return _next; }
+  oop protection_domain() { return _pd_cache->protection_domain(); }
+};
+#endif // SHARE_VM_CLASSFILE_PROTECTIONDOMAINCACHE_HPP