7133093: Improve system dictionary performance
authorcoleenp
Fri, 28 Jul 2017 10:48:35 -0400
changeset 46729 c62d2e8b2728
parent 46728 a1bee305515d
child 46730 01dc8e9d2da3
child 46743 4d9e00487c62
7133093: Improve system dictionary performance Summary: implement one dictionary per ClassLoaderData for faster lookup and removal during class unloading Reviewed-by: iklam, acorn, jiangli
hotspot/src/jdk.hotspot.agent/doc/jsdb.html
hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/CommandProcessor.java
hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/classfile/ClassLoaderData.java
hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/classfile/ClassLoaderDataGraph.java
hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Dictionary.java
hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/DictionaryEntry.java
hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/LoaderConstraintEntry.java
hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/LoaderConstraintTable.java
hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/PlaceholderEntry.java
hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/PlaceholderTable.java
hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/ProtectionDomainCacheEntry.java
hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/ProtectionDomainEntry.java
hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/SystemDictionary.java
hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Universe.java
hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java
hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java
hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java
hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassDump.java
hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/Hashtable.java
hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java
hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/ReversePtrsAnalysis.java
hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/SystemDictionaryHelper.java
hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/TwoOopHashtable.java
hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaHeap.java
hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/sa.js
hotspot/src/share/vm/classfile/classLoaderData.cpp
hotspot/src/share/vm/classfile/classLoaderData.hpp
hotspot/src/share/vm/classfile/classLoaderData.inline.hpp
hotspot/src/share/vm/classfile/dictionary.cpp
hotspot/src/share/vm/classfile/dictionary.hpp
hotspot/src/share/vm/classfile/loaderConstraints.cpp
hotspot/src/share/vm/classfile/loaderConstraints.hpp
hotspot/src/share/vm/classfile/moduleEntry.cpp
hotspot/src/share/vm/classfile/packageEntry.cpp
hotspot/src/share/vm/classfile/placeholders.cpp
hotspot/src/share/vm/classfile/placeholders.hpp
hotspot/src/share/vm/classfile/protectionDomainCache.cpp
hotspot/src/share/vm/classfile/protectionDomainCache.hpp
hotspot/src/share/vm/classfile/systemDictionary.cpp
hotspot/src/share/vm/classfile/systemDictionary.hpp
hotspot/src/share/vm/classfile/systemDictionaryShared.hpp
hotspot/src/share/vm/memory/universe.cpp
hotspot/src/share/vm/oops/klassVtable.cpp
hotspot/src/share/vm/prims/jvmtiGetLoadedClasses.cpp
hotspot/src/share/vm/runtime/biasedLocking.cpp
hotspot/src/share/vm/runtime/compilationPolicy.cpp
hotspot/src/share/vm/runtime/memprofiler.cpp
hotspot/src/share/vm/runtime/vmStructs.cpp
hotspot/src/share/vm/utilities/globalDefinitions.hpp
hotspot/src/share/vm/utilities/hashtable.cpp
hotspot/src/share/vm/utilities/hashtable.hpp
hotspot/test/runtime/NMT/CheckForProperDetailStackTrace.java
--- a/hotspot/src/jdk.hotspot.agent/doc/jsdb.html	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/jdk.hotspot.agent/doc/jsdb.html	Fri Jul 28 10:48:35 2017 -0400
@@ -1108,11 +1108,6 @@
 calls callback with Klass and initiating loader (Oop) for System dictionary
 entry.
 </dd>
-<dt>forEachPrimArrayKlass(callback)</dt>
-<dd>
-calls callback with Klass and initiating loader (Oop) for each
-primitive array Klass in the system.
-</dd>
 <dt>findInstanceKlass(name)</dt>
 <dd>
 finds the first instance klass with given name from System dictionary
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/CommandProcessor.java	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/CommandProcessor.java	Fri Jul 28 10:48:35 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -48,6 +48,7 @@
 import sun.jvm.hotspot.code.NMethod;
 import sun.jvm.hotspot.debugger.Address;
 import sun.jvm.hotspot.debugger.OopHandle;
+import sun.jvm.hotspot.classfile.ClassLoaderDataGraph;
 import sun.jvm.hotspot.memory.SymbolTable;
 import sun.jvm.hotspot.memory.SystemDictionary;
 import sun.jvm.hotspot.memory.Universe;
@@ -853,8 +854,8 @@
                 } else {
                     String s = t.nextToken();
                     if (s.equals("-a")) {
-                        SystemDictionary sysDict = VM.getVM().getSystemDictionary();
-                        sysDict.allClassesDo(new SystemDictionary.ClassVisitor() {
+                        ClassLoaderDataGraph cldg = VM.getVM().getClassLoaderDataGraph();
+                        cldg.classesDo(new ClassLoaderDataGraph.ClassVisitor() {
                                 public void visit(Klass k) {
                                     if (k instanceof InstanceKlass) {
                                         MethodArray methods = ((InstanceKlass)k).getMethods();
@@ -887,8 +888,8 @@
                 if (t.countTokens() != 0) {
                     usage();
                 } else {
-                    SystemDictionary sysDict = VM.getVM().getSystemDictionary();
-                    sysDict.allClassesDo(new SystemDictionary.ClassVisitor() {
+                    ClassLoaderDataGraph cldg = VM.getVM().getClassLoaderDataGraph();
+                    cldg.classesDo(new ClassLoaderDataGraph.ClassVisitor() {
                             public void visit(Klass k) {
                                 if (k instanceof InstanceKlass && ((InstanceKlass)k).getConstants().getCache() != null) {
                                     MethodArray methods = ((InstanceKlass)k).getMethods();
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/classfile/ClassLoaderData.java	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/classfile/ClassLoaderData.java	Fri Jul 28 10:48:35 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -25,16 +25,16 @@
 package sun.jvm.hotspot.classfile;
 
 import java.io.PrintStream;
-import java.util.*;
 import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.memory.*;
 import sun.jvm.hotspot.runtime.*;
 import sun.jvm.hotspot.oops.*;
 import sun.jvm.hotspot.types.*;
 
 public class ClassLoaderData extends VMObject {
   static {
-    VM.registerVMInitializedObserver(new Observer() {
-        public void update(Observable o, Object data) {
+    VM.registerVMInitializedObserver(new java.util.Observer() {
+        public void update(java.util.Observable o, Object data) {
           initialize(VM.getVM().getTypeDataBase());
         }
       });
@@ -44,19 +44,26 @@
     Type type      = db.lookupType("ClassLoaderData");
     classLoaderField = type.getOopField("_class_loader");
     nextField = type.getAddressField("_next");
-    klassesField = type.getAddressField("_klasses");
+    klassesField = new MetadataField(type.getAddressField("_klasses"), 0);
     isAnonymousField = new CIntField(type.getCIntegerField("_is_anonymous"), 0);
+    dictionaryField = type.getAddressField("_dictionary");
   }
 
   private static sun.jvm.hotspot.types.OopField classLoaderField;
   private static AddressField nextField;
-  private static AddressField klassesField;
+  private static MetadataField  klassesField;
   private static CIntField isAnonymousField;
+  private static AddressField dictionaryField;
 
   public ClassLoaderData(Address addr) {
     super(addr);
   }
 
+  public Dictionary dictionary() {
+      Address tmp = dictionaryField.getValue();
+      return (Dictionary) VMObjectFactory.newObject(Dictionary.class, tmp);
+  }
+
   public static ClassLoaderData instantiateWrapperFor(Address addr) {
     if (addr == null) {
       return null;
@@ -76,7 +83,30 @@
     return instantiateWrapperFor(nextField.getValue(getAddress()));
   }
 
-  public Klass getKlasses() {
-    return (InstanceKlass)Metadata.instantiateWrapperFor(klassesField.getValue(getAddress()));
+  public Klass getKlasses()    { return (Klass)klassesField.getValue(this);  }
+
+  /** Lookup an already loaded class. If not found null is returned. */
+  public Klass find(Symbol className) {
+    for (Klass l = getKlasses(); l != null; l = l.getNextLinkKlass()) {
+        if (className.equals(l.getName())) {
+            return l;
+        }
+    }
+    return null;
+  }
+
+  /** Iterate over all klasses - including object, primitive
+      array klasses */
+  public void classesDo(ClassLoaderDataGraph.ClassVisitor v) {
+      for (Klass l = getKlasses(); l != null; l = l.getNextLinkKlass()) {
+          v.visit(l);
+      }
+  }
+
+  /** Iterate over all klasses in the dictionary, including initiating loader. */
+  public void allEntriesDo(ClassLoaderDataGraph.ClassAndLoaderVisitor v) {
+      for (Klass l = getKlasses(); l != null; l = l.getNextLinkKlass()) {
+          dictionary().allEntriesDo(v, getClassLoader());
+      }
   }
 }
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/classfile/ClassLoaderDataGraph.java	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/classfile/ClassLoaderDataGraph.java	Fri Jul 28 10:48:35 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -27,6 +27,7 @@
 import java.io.PrintStream;
 import java.util.*;
 import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.classfile.*;
 import sun.jvm.hotspot.runtime.*;
 import sun.jvm.hotspot.oops.*;
 import sun.jvm.hotspot.types.*;
@@ -52,21 +53,43 @@
     return ClassLoaderData.instantiateWrapperFor(headField.getValue());
   }
 
-  public static interface KlassVisitor {
+  /** Lookup an already loaded class in any class loader. */
+  public Klass find(String className) {
+    Symbol sym = VM.getVM().getSymbolTable().probe(className);
+    if (sym == null) return null;
+    for (ClassLoaderData cld = getClassLoaderGraphHead(); cld != null; cld = cld.next()) {
+        Klass k = cld.find(sym);
+        if (k != null) {
+            return k;
+        }
+    }
+    return null;
+  }
+
+  /** Interface for iterating through all classes. */
+  public static interface ClassVisitor {
     public void visit(Klass k);
   }
 
-  /** Iterate over all anonymous class loaders and the klasses in those */
-  public void allAnonymousKlassesDo(final KlassVisitor v) {
-    for (ClassLoaderData cl = getClassLoaderGraphHead();
-         cl != null;
-         cl = cl.next()) {
-      if (cl.getIsAnonymous() == true) {
-        for (Klass k = cl.getKlasses(); k != null; k = k.getNextLinkKlass()) {
-          v.visit(k);
-        }
-      }
+  /** Interface for iterating through all classes and their class
+      loaders in dictionary */
+  public static interface ClassAndLoaderVisitor {
+    public void visit(Klass k, Oop loader);
+  }
+
+  /** Iterate over all klasses - including object, primitive
+      array klasses */
+  public void classesDo(ClassVisitor v) {
+    for (ClassLoaderData cld = getClassLoaderGraphHead(); cld != null; cld = cld.next()) {
+        cld.classesDo(v);
     }
   }
 
+  /** Iterate over all klasses - including object, primitive
+      array klasses, pass initiating loader. */
+  public void allEntriesDo(ClassAndLoaderVisitor v) {
+    for (ClassLoaderData cld = getClassLoaderGraphHead(); cld != null; cld = cld.next()) {
+        cld.allEntriesDo(v);
+    }
+  }
 }
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Dictionary.java	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Dictionary.java	Fri Jul 28 10:48:35 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -26,12 +26,13 @@
 
 import java.util.*;
 import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.classfile.*;
 import sun.jvm.hotspot.oops.*;
 import sun.jvm.hotspot.types.*;
 import sun.jvm.hotspot.runtime.*;
 import sun.jvm.hotspot.utilities.*;
 
-public class Dictionary extends TwoOopHashtable {
+public class Dictionary extends sun.jvm.hotspot.utilities.Hashtable {
   static {
     VM.registerVMInitializedObserver(new Observer() {
         public void update(Observable o, Object data) {
@@ -55,56 +56,32 @@
     return DictionaryEntry.class;
   }
 
-  /** Iterate over all klasses in dictionary; just the classes from
-      declaring class loaders */
-  public void classesDo(SystemDictionary.ClassVisitor v) {
-    ObjectHeap heap = VM.getVM().getObjectHeap();
+  /** All classes, and their initiating class loader, passed in. */
+  public void allEntriesDo(ClassLoaderDataGraph.ClassAndLoaderVisitor v, Oop loader) {
     int tblSize = tableSize();
     for (int index = 0; index < tblSize; index++) {
       for (DictionaryEntry probe = (DictionaryEntry) bucket(index); probe != null;
-                                             probe = (DictionaryEntry) probe.next()) {
+                                              probe = (DictionaryEntry) probe.next()) {
         Klass k = probe.klass();
-        if (heap.equal(probe.loader(), ((InstanceKlass) k).getClassLoader())) {
-            v.visit(k);
-        }
+        v.visit(k, loader);
       }
     }
   }
 
-  /** All classes, and their class loaders */
-  public void classesDo(SystemDictionary.ClassAndLoaderVisitor v) {
-    int tblSize = tableSize();
-    for (int index = 0; index < tblSize; index++) {
-      for (DictionaryEntry probe = (DictionaryEntry) bucket(index); probe != null;
-                                             probe = (DictionaryEntry) probe.next()) {
-        Klass k = probe.klass();
-        v.visit(k, probe.loader());
-      }
-    }
-  }
-
-  public Klass find(int index, long hash, Symbol className, Oop classLoader, Oop protectionDomain) {
-    DictionaryEntry entry = getEntry(index, hash, className, classLoader);
-    if (entry != null && entry.isValidProtectionDomain(protectionDomain)) {
-      return entry.klass();
-    }
-    return null;
-  }
-
   // - Internals only below this point
 
-  private DictionaryEntry getEntry(int index, long hash, Symbol className, Oop classLoader) {
+  private DictionaryEntry getEntry(int index, long hash, Symbol className) {
     for (DictionaryEntry entry = (DictionaryEntry) bucket(index); entry != null;
                                     entry = (DictionaryEntry) entry.next()) {
-      if (entry.hash() == hash && entry.equals(className, classLoader)) {
+      if (entry.hash() == hash && entry.equals(className)) {
         return entry;
       }
     }
     return null;
   }
 
-  public boolean contains(Klass c, Oop classLoader) {
-    long hash = computeHash(c.getName(), classLoader);
+  public boolean contains(Klass c) {
+    long hash = computeHash(c.getName());
     int index = hashToIndex(hash);
 
     for (DictionaryEntry entry = (DictionaryEntry) bucket(index); entry != null;
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/DictionaryEntry.java	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/DictionaryEntry.java	Fri Jul 28 10:48:35 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -43,28 +43,6 @@
 
   private static synchronized void initialize(TypeDataBase db) {
     Type type = db.lookupType("DictionaryEntry");
-    pdSetField = type.getAddressField("_pd_set");
-    loaderDataField = type.getAddressField("_loader_data");
-  }
-
-  // Fields
-  private static AddressField pdSetField;
-  private static AddressField loaderDataField;
-
-  // Accessors
-
-  public ProtectionDomainEntry pdSet() {
-    Address tmp = pdSetField.getValue(addr);
-    return (ProtectionDomainEntry) VMObjectFactory.newObject(
-                          ProtectionDomainEntry.class, tmp);
-  }
-
-  public Oop loader() {
-    return loaderData().getClassLoader();
-  }
-
-  public ClassLoaderData loaderData() {
-    return ClassLoaderData.instantiateWrapperFor(loaderDataField.getValue(addr));
   }
 
   public Klass klass() {
@@ -75,38 +53,9 @@
     super(addr);
   }
 
-  public boolean equals(Symbol className, Oop classLoader) {
+  public boolean equals(Symbol className) {
     InstanceKlass ik = (InstanceKlass) klass();
-    Oop loader = loader();
-    if (! ik.getName().equals(className)) {
-      return false;
-    } else {
-      return (loader == null)? (classLoader == null) :
-                               (loader.equals(classLoader));
-    }
-  }
-
-  public boolean isValidProtectionDomain(Oop protectionDomain) {
-    if (protectionDomain == null) {
-      return true;
-    } else {
-      return containsProtectionDomain(protectionDomain);
-    }
-  }
-
-  public boolean containsProtectionDomain(Oop protectionDomain) {
-    InstanceKlass ik = (InstanceKlass) klass();
-    // Currently unimplemented and not used.
-    // if (protectionDomain.equals(ik.getJavaMirror().getProtectionDomain())) {
-    //   return true; // Succeeds trivially
-    // }
-    for (ProtectionDomainEntry current = pdSet(); current != null;
-                                       current = current.next()) {
-      if (protectionDomain.equals(current.protectionDomain())) {
-        return true;
-      }
-    }
-    return false;
+    return ik.getName().equals(className);
   }
 
   /* covariant return type :-(
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/LoaderConstraintEntry.java	Thu Jul 27 17:47:57 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +0,0 @@
-/*
- * Copyright (c) 2003, 2011, 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.
- *
- */
-
-package sun.jvm.hotspot.memory;
-
-import java.util.*;
-import sun.jvm.hotspot.debugger.*;
-import sun.jvm.hotspot.oops.*;
-import sun.jvm.hotspot.types.*;
-import sun.jvm.hotspot.runtime.*;
-import sun.jvm.hotspot.utilities.*;
-
-public class LoaderConstraintEntry extends sun.jvm.hotspot.utilities.HashtableEntry {
-  static {
-    VM.registerVMInitializedObserver(new Observer() {
-        public void update(Observable o, Object data) {
-          initialize(VM.getVM().getTypeDataBase());
-        }
-      });
-  }
-
-  private static synchronized void initialize(TypeDataBase db) {
-    Type type = db.lookupType("LoaderConstraintEntry");
-    nameField = type.getAddressField("_name");
-    numLoadersField = type.getCIntegerField("_num_loaders");
-    maxLoadersField = type.getCIntegerField("_max_loaders");
-    loadersField = type.getAddressField("_loaders");
-  }
-
-  // Fields
-  private static AddressField nameField;
-  private static CIntegerField numLoadersField;
-  private static CIntegerField maxLoadersField;
-  private static AddressField loadersField;
-
-  // Accessors
-
-  public Symbol name() {
-    return Symbol.create(nameField.getValue(addr));
-  }
-
-  public int numLoaders() {
-    return (int) numLoadersField.getValue(addr);
-  }
-
-  public int maxLoaders() {
-    return (int) maxLoadersField.getValue(addr);
-  }
-
-  public Oop initiatingLoader(int i) {
-    if (Assert.ASSERTS_ENABLED) {
-      Assert.that(i >= 0 && i < numLoaders(), "invalid index");
-    }
-    Address loaders = loadersField.getValue(addr);
-    OopHandle loader = loaders.addOffsetToAsOopHandle(i * VM.getVM().getOopSize());
-    return VM.getVM().getObjectHeap().newOop(loader);
-  }
-
-  public LoaderConstraintEntry(Address addr) {
-    super(addr);
-  }
-
-  /* covariant return type :-(
-  public LoaderConstraintEntry next() {
-    return (LoaderConstraintEntry) super.next();
-  }
-  For now, let the caller cast it ..
-  */
-}
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/LoaderConstraintTable.java	Thu Jul 27 17:47:57 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2003, 2012, 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.
- *
- */
-
-package sun.jvm.hotspot.memory;
-
-import java.util.*;
-import sun.jvm.hotspot.debugger.*;
-import sun.jvm.hotspot.oops.*;
-import sun.jvm.hotspot.types.*;
-import sun.jvm.hotspot.runtime.*;
-import sun.jvm.hotspot.utilities.*;
-
-public class LoaderConstraintTable extends TwoOopHashtable {
-  static {
-    VM.registerVMInitializedObserver(new Observer() {
-        public void update(Observable o, Object data) {
-          initialize(VM.getVM().getTypeDataBase());
-        }
-      });
-  }
-
-  private static synchronized void initialize(TypeDataBase db) {
-    Type type = db.lookupType("LoaderConstraintTable");
-  }
-
-  public LoaderConstraintTable(Address addr) {
-    super(addr);
-  }
-
-  // this is overriden here so that Hashtable.bucket will return
-  // object of LoaderConstraintEntry.class
-  protected Class getHashtableEntryClass() {
-    return LoaderConstraintEntry.class;
-  }
-}
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/PlaceholderEntry.java	Thu Jul 27 17:47:57 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
-/*
- * Copyright (c) 2003, 2012, 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.
- *
- */
-
-package sun.jvm.hotspot.memory;
-
-import java.util.*;
-import sun.jvm.hotspot.classfile.ClassLoaderData;
-import sun.jvm.hotspot.debugger.*;
-import sun.jvm.hotspot.oops.*;
-import sun.jvm.hotspot.types.*;
-import sun.jvm.hotspot.runtime.*;
-import sun.jvm.hotspot.utilities.*;
-
-public class PlaceholderEntry extends sun.jvm.hotspot.utilities.HashtableEntry {
-  static {
-    VM.registerVMInitializedObserver(new Observer() {
-        public void update(Observable o, Object data) {
-          initialize(VM.getVM().getTypeDataBase());
-        }
-      });
-  }
-
-  private static synchronized void initialize(TypeDataBase db) {
-    Type type = db.lookupType("PlaceholderEntry");
-    loaderDataField = type.getAddressField("_loader_data");
-  }
-
-  // Field
-  private static AddressField loaderDataField;
-
-  // Accessor
-  public Oop loader() {
-    return loaderData().getClassLoader();
-  }
-
-  public ClassLoaderData loaderData() {
-    return ClassLoaderData.instantiateWrapperFor(loaderDataField.getValue(addr));
-  }
-
-  public PlaceholderEntry(Address addr) {
-    super(addr);
-  }
-
-  public Symbol klass() {
-    return Symbol.create(literalValue());
-  }
-
-  /* covariant return type :-(
-  public PlaceholderEntry next() {
-    return (PlaceholderEntry) super.next();
-  }
-  For now, let the caller cast it ..
-  */
-}
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/PlaceholderTable.java	Thu Jul 27 17:47:57 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2003, 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.
- *
- */
-
-package sun.jvm.hotspot.memory;
-
-import sun.jvm.hotspot.debugger.*;
-import sun.jvm.hotspot.oops.*;
-import sun.jvm.hotspot.runtime.*;
-import sun.jvm.hotspot.utilities.*;
-
-public class PlaceholderTable extends TwoOopHashtable {
-  public PlaceholderTable(Address addr) {
-    super(addr);
-  }
-
-  // this is overriden here so that Hashtable.bucket will return
-  // object of PlacholderEntry.class
-  protected Class getHashtableEntryClass() {
-    return PlaceholderEntry.class;
-  }
-
-  /** All array classes of primitive type, and their class loaders */
-  public void primArrayClassesDo(SystemDictionary.ClassAndLoaderVisitor v) {
-    ObjectHeap heap = VM.getVM().getObjectHeap();
-    int tblSize = tableSize();
-    for (int index = 0; index < tblSize; index++) {
-      for (PlaceholderEntry probe = (PlaceholderEntry) bucket(index); probe != null;
-                                          probe = (PlaceholderEntry) probe.next()) {
-        Symbol sym = probe.klass();
-        // array of primitive arrays are stored in system dictionary as placeholders
-        FieldType ft = new FieldType(sym);
-        if (ft.isArray()) {
-          FieldType.ArrayInfo info = ft.getArrayInfo();
-          if (info.elementBasicType() != BasicType.getTObject()) {
-            Klass arrayKlass = heap.typeArrayKlassObj(info.elementBasicType());
-            arrayKlass = arrayKlass.arrayKlassOrNull(info.dimension());
-            v.visit(arrayKlass, probe.loader());
-          }
-        }
-      }
-    }
-  }
-}
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/ProtectionDomainCacheEntry.java	Thu Jul 27 17:47:57 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2001, 2013, 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.
- *
- */
-
-package sun.jvm.hotspot.memory;
-
-import java.util.*;
-import sun.jvm.hotspot.debugger.*;
-import sun.jvm.hotspot.oops.*;
-import sun.jvm.hotspot.runtime.*;
-import sun.jvm.hotspot.types.*;
-
-public class ProtectionDomainCacheEntry extends VMObject {
-  private static sun.jvm.hotspot.types.OopField protectionDomainField;
-
-  static {
-    VM.registerVMInitializedObserver(new Observer() {
-        public void update(Observable o, Object data) {
-          initialize(VM.getVM().getTypeDataBase());
-        }
-      });
-  }
-
-  private static synchronized void initialize(TypeDataBase db) {
-    Type type = db.lookupType("ProtectionDomainCacheEntry");
-    protectionDomainField = type.getOopField("_literal");
-  }
-
-  public ProtectionDomainCacheEntry(Address addr) {
-    super(addr);
-  }
-
-  public Oop protectionDomain() {
-    return VM.getVM().getObjectHeap().newOop(protectionDomainField.getValue(addr));
-  }
-}
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/ProtectionDomainEntry.java	Thu Jul 27 17:47:57 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 2001, 2013, 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.
- *
- */
-
-package sun.jvm.hotspot.memory;
-
-import java.util.*;
-import sun.jvm.hotspot.debugger.*;
-import sun.jvm.hotspot.oops.*;
-import sun.jvm.hotspot.runtime.*;
-import sun.jvm.hotspot.types.*;
-
-public class ProtectionDomainEntry extends VMObject {
-  private static AddressField nextField;
-  private static AddressField pdCacheField;
-
-  static {
-    VM.registerVMInitializedObserver(new Observer() {
-        public void update(Observable o, Object data) {
-          initialize(VM.getVM().getTypeDataBase());
-        }
-      });
-  }
-
-  private static synchronized void initialize(TypeDataBase db) {
-    Type type = db.lookupType("ProtectionDomainEntry");
-
-    nextField = type.getAddressField("_next");
-    pdCacheField = type.getAddressField("_pd_cache");
-  }
-
-  public ProtectionDomainEntry(Address addr) {
-    super(addr);
-  }
-
-  public ProtectionDomainEntry next() {
-    return (ProtectionDomainEntry) VMObjectFactory.newObject(ProtectionDomainEntry.class, nextField.getValue(addr));
-  }
-
-  public Oop protectionDomain() {
-    ProtectionDomainCacheEntry pd_cache = (ProtectionDomainCacheEntry)
-      VMObjectFactory.newObject(ProtectionDomainCacheEntry.class, pdCacheField.getValue(addr));
-    return pd_cache.protectionDomain();
-  }
-}
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/SystemDictionary.java	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/SystemDictionary.java	Fri Jul 28 10:48:35 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 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
@@ -26,15 +26,13 @@
 
 import java.util.*;
 import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.classfile.*;
 import sun.jvm.hotspot.oops.*;
 import sun.jvm.hotspot.runtime.*;
 import sun.jvm.hotspot.types.*;
 
 public class SystemDictionary {
-  private static AddressField dictionaryField;
   private static AddressField sharedDictionaryField;
-  private static AddressField placeholdersField;
-  private static AddressField loaderConstraintTableField;
   private static sun.jvm.hotspot.types.OopField javaSystemLoaderField;
 
   private static AddressField objectKlassField;
@@ -56,10 +54,7 @@
   private static synchronized void initialize(TypeDataBase db) {
     Type type = db.lookupType("SystemDictionary");
 
-    dictionaryField = type.getAddressField("_dictionary");
     sharedDictionaryField = type.getAddressField("_shared_dictionary");
-    placeholdersField = type.getAddressField("_placeholders");
-    loaderConstraintTableField = type.getAddressField("_loader_constraints");
     javaSystemLoaderField = type.getOopField("_java_system_loader");
 
     objectKlassField = type.getAddressField(WK_KLASS("Object_klass"));
@@ -81,26 +76,11 @@
       return (kname+"_knum");
   }
 
-  public Dictionary dictionary() {
-    Address tmp = dictionaryField.getValue();
-    return (Dictionary) VMObjectFactory.newObject(Dictionary.class, tmp);
-  }
-
   public Dictionary sharedDictionary() {
     Address tmp = sharedDictionaryField.getValue();
     return (Dictionary) VMObjectFactory.newObject(Dictionary.class, tmp);
   }
 
-  public PlaceholderTable placeholders() {
-    Address tmp = placeholdersField.getValue();
-    return (PlaceholderTable) VMObjectFactory.newObject(PlaceholderTable.class, tmp);
-  }
-
-  public LoaderConstraintTable constraints() {
-    Address tmp = placeholdersField.getValue();
-    return (LoaderConstraintTable) VMObjectFactory.newObject(LoaderConstraintTable.class, tmp);
-  }
-
   // few well known classes -- not all are added here.
   // add more if needed.
   public static InstanceKlass getThreadKlass() {
@@ -132,8 +112,8 @@
   }
 
   public InstanceKlass getAbstractOwnableSynchronizerKlass() {
-    return (InstanceKlass) find("java/util/concurrent/locks/AbstractOwnableSynchronizer",
-                                null, null);
+    ClassLoaderDataGraph cldg = VM.getVM().getClassLoaderDataGraph();
+    return (InstanceKlass) cldg.find("java/util/concurrent/locks/AbstractOwnableSynchronizer");
   }
 
   public static Oop javaSystemLoader() {
@@ -143,60 +123,4 @@
   private static Oop newOop(OopHandle handle) {
     return VM.getVM().getObjectHeap().newOop(handle);
   }
-
-  /** Lookup an already loaded class. If not found null is returned. */
-  public Klass find(String className, Oop classLoader, Oop protectionDomain) {
-    Symbol sym = VM.getVM().getSymbolTable().probe(className);
-    if (sym == null) return null;
-    return find(sym, classLoader, protectionDomain);
-  }
-
-  /** Lookup an already loaded class. If not found null is returned. */
-  public Klass find(Symbol className, Oop classLoader, Oop protectionDomain) {
-    Dictionary dict = dictionary();
-    long hash = dict.computeHash(className, classLoader);
-    int index = dict.hashToIndex(hash);
-    return dict.find(index, hash, className, classLoader, protectionDomain);
-  }
-
-  /** Interface for iterating through all classes in dictionary */
-  public static interface ClassVisitor {
-    public void visit(Klass k);
-  }
-
-  /** Interface for iterating through all classes and their class
-      loaders in dictionary */
-  public static interface ClassAndLoaderVisitor {
-    public void visit(Klass k, Oop loader);
-  }
-
-  /** Iterate over all klasses - including object, primitive
-      array klasses */
-  public void allClassesDo(final ClassVisitor v) {
-    ClassVisitor visitor = new ClassVisitor() {
-      public void visit(Klass k) {
-        for (Klass l = k; l != null; l = l.arrayKlassOrNull()) {
-          v.visit(l);
-        }
-      }
-    };
-    classesDo(visitor);
-    VM.getVM().getUniverse().basicTypeClassesDo(visitor);
-  }
-
-  /** Iterate over all klasses in dictionary; just the classes from
-      declaring class loaders */
-  public void classesDo(ClassVisitor v) {
-    dictionary().classesDo(v);
-  }
-
-  /** All classes, and their class loaders */
-  public void classesDo(ClassAndLoaderVisitor v) {
-    dictionary().classesDo(v);
-  }
-
-  /** All array classes of primitive type, and their class loaders */
-  public void primArrayClassesDo(ClassAndLoaderVisitor v) {
-    placeholders().primArrayClassesDo(v);
-  }
 }
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Universe.java	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Universe.java	Fri Jul 28 10:48:35 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -164,18 +164,6 @@
     return newOop(systemThreadGroupField.getValue());
   }
 
-  // iterate through the single dimensional primitive array klasses
-  // refer to basic_type_classes_do(void f(Klass*)) in universe.cpp
-  public void basicTypeClassesDo(SystemDictionary.ClassVisitor visitor) {
-    visitor.visit(new TypeArrayKlass(boolArrayKlassField.getValue()));
-    visitor.visit(new TypeArrayKlass(byteArrayKlassField.getValue()));
-    visitor.visit(new TypeArrayKlass(charArrayKlassField.getValue()));
-    visitor.visit(new TypeArrayKlass(intArrayKlassField.getValue()));
-    visitor.visit(new TypeArrayKlass(shortArrayKlassField.getValue()));
-    visitor.visit(new TypeArrayKlass(longArrayKlassField.getValue()));
-    visitor.visit(new TypeArrayKlass(singleArrayKlassField.getValue()));
-    visitor.visit(new TypeArrayKlass(doubleArrayKlassField.getValue()));
-  }
 
   public void print() { printOn(System.out); }
   public void printOn(PrintStream tty) {
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java	Fri Jul 28 10:48:35 2017 -0400
@@ -91,7 +91,6 @@
     fields               = type.getAddressField("_fields");
     javaFieldsCount      = new CIntField(type.getCIntegerField("_java_fields_count"), 0);
     constants            = new MetadataField(type.getAddressField("_constants"), 0);
-    classLoaderData      = type.getAddressField("_class_loader_data");
     sourceDebugExtension = type.getAddressField("_source_debug_extension");
     innerClasses         = type.getAddressField("_inner_classes");
     sourceFileNameIndex  = new CIntField(type.getCIntegerField("_source_file_name_index"), 0);
@@ -166,7 +165,6 @@
   private static AddressField fields;
   private static CIntField javaFieldsCount;
   private static MetadataField constants;
-  private static AddressField  classLoaderData;
   private static AddressField  sourceDebugExtension;
   private static AddressField  innerClasses;
   private static CIntField sourceFileNameIndex;
@@ -328,7 +326,7 @@
       // MetaspaceObj in the CDS shared archive.
       Dictionary sharedDictionary = vm.getSystemDictionary().sharedDictionary();
       if (sharedDictionary != null) {
-        if (sharedDictionary.contains(this, null)) {
+        if (sharedDictionary.contains(this)) {
           return true;
         }
       }
@@ -448,8 +446,6 @@
     return allFieldsCount;
   }
   public ConstantPool getConstants()        { return (ConstantPool) constants.getValue(this); }
-  public ClassLoaderData getClassLoaderData() { return                ClassLoaderData.instantiateWrapperFor(classLoaderData.getValue(getAddress())); }
-  public Oop       getClassLoader()         { return                getClassLoaderData().getClassLoader(); }
   public Symbol    getSourceFileName()      { return                getConstants().getSymbolAt(sourceFileNameIndex.getValue(this)); }
   public String    getSourceDebugExtension(){ return                CStringUtilities.getString(sourceDebugExtension.getValue(getAddress())); }
   public long      getNonstaticFieldSize()  { return                nonstaticFieldSize.getValue(this); }
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java	Fri Jul 28 10:48:35 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -27,6 +27,7 @@
 import java.io.*;
 import java.util.*;
 import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.classfile.*;
 import sun.jvm.hotspot.runtime.*;
 import sun.jvm.hotspot.types.*;
 
@@ -63,6 +64,7 @@
     nextSibling  = new MetadataField(type.getAddressField("_next_sibling"), 0);
     nextLink     = new MetadataField(type.getAddressField("_next_link"), 0);
     vtableLen    = new CIntField(type.getCIntegerField("_vtable_len"), 0);
+    classLoaderData = type.getAddressField("_class_loader_data");
 
     LH_INSTANCE_SLOW_PATH_BIT  = db.lookupIntConstant("Klass::_lh_instance_slow_path_bit").intValue();
     LH_LOG2_ELEMENT_SIZE_SHIFT = db.lookupIntConstant("Klass::_lh_log2_element_size_shift").intValue();
@@ -96,6 +98,7 @@
   private static MetadataField  nextLink;
   private static sun.jvm.hotspot.types.Field traceIDField;
   private static CIntField vtableLen;
+  private static AddressField classLoaderData;
 
   private Address getValue(AddressField field) {
     return addr.getAddressAt(field.getOffset());
@@ -110,7 +113,7 @@
   public Klass    getSuper()            { return (Klass)    superField.getValue(this);   }
   public Klass    getJavaSuper()        { return null;  }
   public int      getLayoutHelper()     { return (int)           layoutHelper.getValue(this); }
-  public Symbol   getName()             { return getSymbol(name); }
+  public Symbol   getName()             { return            getSymbol(name); }
   public long     getAccessFlags()      { return            accessFlags.getValue(this);  }
   // Convenience routine
   public AccessFlags getAccessFlagsObj(){ return new AccessFlags(getAccessFlags());      }
@@ -119,6 +122,9 @@
   public Klass    getNextLinkKlass()    { return (Klass)    nextLink.getValue(this);  }
   public long     getVtableLen()        { return            vtableLen.getValue(this); }
 
+  public ClassLoaderData getClassLoaderData() { return ClassLoaderData.instantiateWrapperFor(classLoaderData.getValue(getAddress())); }
+  public Oop             getClassLoader()     { return   getClassLoaderData().getClassLoader(); }
+
   public long traceID() {
     if (traceIDField == null) return 0;
     return traceIDField.getJLong(addr);
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java	Fri Jul 28 10:48:35 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -28,6 +28,7 @@
 import java.util.*;
 
 import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.classfile.*;
 import sun.jvm.hotspot.memory.*;
 import sun.jvm.hotspot.oops.*;
 import sun.jvm.hotspot.runtime.*;
@@ -106,8 +107,8 @@
          err.print("computing per loader stat ..");
       }
 
-      SystemDictionary dict = VM.getVM().getSystemDictionary();
-      dict.classesDo(new SystemDictionary.ClassVisitor() {
+      ClassLoaderDataGraph cldg = VM.getVM().getClassLoaderDataGraph();
+      cldg.classesDo(new ClassLoaderDataGraph.ClassVisitor() {
                         public void visit(Klass k) {
                            if (! (k instanceof InstanceKlass)) {
                               return;
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassDump.java	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassDump.java	Fri Jul 28 10:48:35 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 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
@@ -29,6 +29,7 @@
 import java.util.jar.JarOutputStream;
 import java.util.jar.JarEntry;
 import java.util.jar.Manifest;
+import sun.jvm.hotspot.classfile.*;
 import sun.jvm.hotspot.memory.*;
 import sun.jvm.hotspot.oops.*;
 import sun.jvm.hotspot.debugger.*;
@@ -100,9 +101,9 @@
                 setOutputDirectory(dirName);
             }
 
-            // walk through the system dictionary
-            SystemDictionary dict = VM.getVM().getSystemDictionary();
-            dict.classesDo(new SystemDictionary.ClassVisitor() {
+            // walk through the loaded classes
+            ClassLoaderDataGraph cldg = VM.getVM().getClassLoaderDataGraph();
+            cldg.classesDo(new ClassLoaderDataGraph.ClassVisitor() {
                     public void visit(Klass k) {
                         if (k instanceof InstanceKlass) {
                             try {
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/Hashtable.java	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/Hashtable.java	Fri Jul 28 10:48:35 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -27,6 +27,7 @@
 import java.util.*;
 import sun.jvm.hotspot.debugger.*;
 import sun.jvm.hotspot.types.*;
+import sun.jvm.hotspot.oops.*;
 import sun.jvm.hotspot.runtime.*;
 
 public class Hashtable extends BasicHashtable {
@@ -48,6 +49,10 @@
     return HashtableEntry.class;
   }
 
+  public int computeHash(Symbol name) {
+    return (int) name.identityHash();
+  }
+
   public int hashToIndex(long fullHash) {
     return (int) (fullHash % tableSize());
   }
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java	Fri Jul 28 10:48:35 2017 -0400
@@ -586,23 +586,9 @@
     }
 
     private void writeClassDumpRecords() throws IOException {
-        SystemDictionary sysDict = VM.getVM().getSystemDictionary();
         ClassLoaderDataGraph cldGraph = VM.getVM().getClassLoaderDataGraph();
         try {
-            sysDict.allClassesDo(new SystemDictionary.ClassVisitor() {
-                            public void visit(Klass k) {
-                                try {
-                                    writeHeapRecordPrologue();
-                                    writeClassDumpRecord(k);
-                                    writeHeapRecordEpilogue();
-                                } catch (IOException e) {
-                                    throw new RuntimeException(e);
-                                }
-                            }
-                        });
-             // Add the anonymous classes also which are not present in the
-             // System Dictionary
-             cldGraph.allAnonymousKlassesDo(new ClassLoaderDataGraph.KlassVisitor() {
+             cldGraph.classesDo(new ClassLoaderDataGraph.ClassVisitor() {
                             public void visit(Klass k) {
                                 try {
                                     writeHeapRecordPrologue();
@@ -1088,26 +1074,9 @@
 
     private void writeClasses() throws IOException {
         // write class list (id, name) association
-        SystemDictionary sysDict = VM.getVM().getSystemDictionary();
         ClassLoaderDataGraph cldGraph = VM.getVM().getClassLoaderDataGraph();
         try {
-            sysDict.allClassesDo(new SystemDictionary.ClassVisitor() {
-                public void visit(Klass k) {
-                    try {
-                        Instance clazz = k.getJavaMirror();
-                        writeHeader(HPROF_LOAD_CLASS, 2 * (OBJ_ID_SIZE + 4));
-                        out.writeInt(serialNum);
-                        writeObjectID(clazz);
-                        KlassMap.add(serialNum - 1, k);
-                        out.writeInt(DUMMY_STACK_TRACE_ID);
-                        writeSymbolID(k.getName());
-                        serialNum++;
-                    } catch (IOException exp) {
-                        throw new RuntimeException(exp);
-                    }
-                }
-            });
-            cldGraph.allAnonymousKlassesDo(new ClassLoaderDataGraph.KlassVisitor() {
+            cldGraph.classesDo(new ClassLoaderDataGraph.ClassVisitor() {
                 public void visit(Klass k) {
                     try {
                         Instance clazz = k.getJavaMirror();
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/ReversePtrsAnalysis.java	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/ReversePtrsAnalysis.java	Fri Jul 28 10:48:35 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 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
@@ -27,6 +27,7 @@
 import java.io.*;
 import java.util.*;
 import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.classfile.*;
 import sun.jvm.hotspot.gc.shared.*;
 import sun.jvm.hotspot.memory.*;
 import sun.jvm.hotspot.oops.*;
@@ -113,8 +114,8 @@
                      new RootVisitor("Weak global JNI handle root"));
 
     // Do Java-level static fields
-    SystemDictionary sysDict = VM.getVM().getSystemDictionary();
-    sysDict.allClassesDo(new SystemDictionary.ClassVisitor() {
+    ClassLoaderDataGraph cldg = VM.getVM().getClassLoaderDataGraph();
+    cldg.classesDo(new ClassLoaderDataGraph.ClassVisitor() {
 
             public void visit(Klass k) {
                 if (k instanceof InstanceKlass) {
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/SystemDictionaryHelper.java	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/SystemDictionaryHelper.java	Fri Jul 28 10:48:35 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 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
@@ -25,6 +25,7 @@
 package sun.jvm.hotspot.utilities;
 
 import java.util.*;
+import sun.jvm.hotspot.classfile.*;
 import sun.jvm.hotspot.oops.*;
 import sun.jvm.hotspot.memory.*;
 import sun.jvm.hotspot.runtime.*;
@@ -52,8 +53,8 @@
       }
 
       final Vector tmp = new Vector();
-      SystemDictionary dict = VM.getVM().getSystemDictionary();
-      dict.classesDo(new SystemDictionary.ClassVisitor() {
+      ClassLoaderDataGraph cldg = VM.getVM().getClassLoaderDataGraph();
+      cldg.classesDo(new ClassLoaderDataGraph.ClassVisitor() {
                         public void visit(Klass k) {
                            if (k instanceof InstanceKlass) {
                               InstanceKlass ik = (InstanceKlass) k;
@@ -100,42 +101,15 @@
    public static InstanceKlass findInstanceKlass(String className) {
       // convert to internal name
       className = className.replace('.', '/');
-      SystemDictionary sysDict = VM.getVM().getSystemDictionary();
-
-      // check whether we have a bootstrap class of given name
-      Klass klass = sysDict.find(className, null, null);
-      if (klass != null) {
-         return (InstanceKlass) klass;
-      }
-
-      // check whether we have a system class of given name
-      klass = sysDict.find(className, sysDict.javaSystemLoader(), null);
-      if (klass != null) {
-         return (InstanceKlass) klass;
-      }
+      ClassLoaderDataGraph cldg = VM.getVM().getClassLoaderDataGraph();
 
-      // didn't find bootstrap or system class of given name.
-      // search through the entire dictionary..
-      InstanceKlass[] tmpKlasses = getAllInstanceKlasses();
-      // instance klass array is sorted by name. do binary search
-      int low = 0;
-      int high = tmpKlasses.length-1;
-
-      int mid = -1;
-      while (low <= high) {
-         mid = (low + high) >> 1;
-         InstanceKlass midVal = tmpKlasses[mid];
-         int cmp = midVal.getName().asString().compareTo(className);
-
-         if (cmp < 0) {
-             low = mid + 1;
-         } else if (cmp > 0) {
-             high = mid - 1;
-         } else { // match found
-             return tmpKlasses[mid];
-         }
+      // check whether we have a class of given name
+      Klass klass = cldg.find(className);
+      if (klass != null && klass instanceof InstanceKlass) {
+         return (InstanceKlass) klass;
+      } else {
+        // no match ..
+        return null;
       }
-      // no match ..
-      return null;
    }
 }
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/TwoOopHashtable.java	Thu Jul 27 17:47:57 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2003, 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.
- *
- */
-
-package sun.jvm.hotspot.utilities;
-
-import sun.jvm.hotspot.debugger.*;
-import sun.jvm.hotspot.oops.*;
-
-public class TwoOopHashtable extends Hashtable {
-  public TwoOopHashtable(Address addr) {
-    super(addr);
-  }
-
-  public long computeHash(Symbol name, Oop loader) {
-    return ((int) name.identityHash()
-        ^  (int) (loader == null ? 0 : loader.identityHash())) & 0xFFFFFFFFL;
-  }
-
-  public int indexFor(Symbol name, Oop loader) {
-    return hashToIndex(computeHash(name, loader));
-  }
-}
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaHeap.java	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaHeap.java	Fri Jul 28 10:48:35 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 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
@@ -27,6 +27,7 @@
 import java.util.*;
 import javax.script.ScriptException;
 import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.classfile.*;
 import sun.jvm.hotspot.memory.*;
 import sun.jvm.hotspot.oops.*;
 import sun.jvm.hotspot.runtime.*;
@@ -166,11 +167,12 @@
         }
 
       final Callable finalFunc = func;
-        SystemDictionary sysDict = VM.getVM().getSystemDictionary();
+        ClassLoaderDataGraph cldg = VM.getVM().getClassLoaderDataGraph();
         if (withLoader) {
-            sysDict.classesDo(new SystemDictionary.ClassAndLoaderVisitor() {
-                    public void visit(Klass kls, Oop loader) {
+            cldg.classesDo(new ClassLoaderDataGraph.ClassVisitor() {
+                    public void visit(Klass kls) {
                         JSJavaKlass  jk = factory.newJSJavaKlass(kls);
+                        Oop loader = kls.getClassLoader();
                         if (jk == null) {
                             return;
                         }
@@ -189,7 +191,7 @@
                 });
 
         } else {
-            sysDict.classesDo(new SystemDictionary.ClassVisitor() {
+            cldg.classesDo(new ClassLoaderDataGraph.ClassVisitor() {
                     public void visit(Klass kls) {
                         JSJavaKlass jk = factory.newJSJavaKlass(kls);
                         if (jk == null) {
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/sa.js	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/sa.js	Fri Jul 28 10:48:35 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 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
@@ -513,24 +513,18 @@
    return sa.sysDict.javaSystemLoader();
 }
 
-// iterate system dictionary for each 'Klass' 
+// iterate class loader data for each 'Klass' 
 function forEachKlass(callback) {
-   var VisitorClass = sapkg.memory.SystemDictionary.ClassVisitor;
+   var VisitorClass = sapkg.classfile.ClassLoaderDataGraph.ClassVisitor;
    var visitor = new VisitorClass() { visit: callback };
-   sa.sysDict["classesDo(sun.jvm.hotspot.memory.SystemDictionary.ClassVisitor)"](visitor);
+   sa.sysDict["classesDo(sun.jvm.hotspot.classfile.ClassLoaderDataGraph.ClassVisitor)"](visitor);
 }
 
 // iterate system dictionary for each 'Klass' and initiating loader
 function forEachKlassAndLoader(callback) {
-   var VisitorClass = sapkg.memory.SystemDictionary.ClassAndLoaderVisitor;
+   var VisitorClass = sapkg.classfile.ClassLoaderDataGraph.ClassAndLoaderVisitor;
    var visitor = new VisitorClass() { visit: callback };
-   sa.sysDict["classesDo(sun.jvm.hotspot.memory.SystemDictionary.ClassAndLoaderVisitor)"](visitor);
-}
-
-// iterate system dictionary for each primitive array klass
-function forEachPrimArrayKlass(callback) {
-   var VisitorClass = sapkg.memory.SystemDictionary.ClassAndLoaderVisitor;
-   sa.sysDict.primArrayClassesDo(new VisitorClass() { visit: callback });
+   sa.sysDict["allEntriesDo(sun.jvm.hotspot.classfile.ClassLoaderDataGraph.ClassAndLoaderVisitor)"](visitor);
 }
 
 // 'oop' to higher-level java object wrapper in which for(i in o) 
--- a/hotspot/src/share/vm/classfile/classLoaderData.cpp	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp	Fri Jul 28 10:48:35 2017 -0400
@@ -1,4 +1,4 @@
-/*
+ /*
  * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -49,6 +49,7 @@
 #include "precompiled.hpp"
 #include "classfile/classLoaderData.hpp"
 #include "classfile/classLoaderData.inline.hpp"
+#include "classfile/dictionary.hpp"
 #include "classfile/javaClasses.hpp"
 #include "classfile/metadataOnStackMark.hpp"
 #include "classfile/moduleEntry.hpp"
@@ -114,6 +115,12 @@
   } else {
     _unnamed_module = NULL;
   }
+
+  if (!is_anonymous) {
+    _dictionary = create_dictionary();
+  } else {
+    _dictionary = NULL;
+  }
   TRACE_INIT_ID(this);
 }
 
@@ -450,10 +457,82 @@
   }
 }
 
+// Class iterator used by the compiler.  It gets some number of classes at
+// a safepoint to decay invocation counters on the methods.
+class ClassLoaderDataGraphKlassIteratorStatic {
+  ClassLoaderData* _current_loader_data;
+  Klass*           _current_class_entry;
+ public:
+
+  ClassLoaderDataGraphKlassIteratorStatic() : _current_loader_data(NULL), _current_class_entry(NULL) {}
+
+  InstanceKlass* try_get_next_class() {
+    assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
+    int max_classes = InstanceKlass::number_of_instance_classes();
+    for (int i = 0; i < max_classes; i++) {
+
+      if (_current_class_entry != NULL) {
+        Klass* k = _current_class_entry;
+        _current_class_entry = _current_class_entry->next_link();
+
+        if (k->is_instance_klass()) {
+          InstanceKlass* ik = InstanceKlass::cast(k);
+          // Only return loaded classes
+          if (ik->is_loaded()) {
+            return ik;
+          }
+        }
+      } else {
+        // Go to next CLD
+        if (_current_loader_data != NULL) {
+          _current_loader_data = _current_loader_data->next();
+        }
+        // Start at the beginning
+        if (_current_loader_data == NULL) {
+          _current_loader_data = ClassLoaderDataGraph::_head;
+        }
+
+        _current_class_entry = _current_loader_data->klasses();
+      }
+    }
+    // should never be reached: an InstanceKlass should be returned above
+    ShouldNotReachHere();
+    return NULL;   // Object_klass not even loaded?
+  }
+
+  // If the current class for the static iterator is a class being unloaded or
+  // deallocated, adjust the current class.
+  void adjust_saved_class(ClassLoaderData* cld) {
+    if (_current_loader_data == cld) {
+      _current_loader_data = cld->next();
+      if (_current_loader_data != NULL) {
+        _current_class_entry = _current_loader_data->klasses();
+      }  // else try_get_next_class will start at the head
+    }
+  }
+
+  void adjust_saved_class(Klass* klass) {
+    if (_current_class_entry == klass) {
+      _current_class_entry = klass->next_link();
+    }
+  }
+};
+
+static ClassLoaderDataGraphKlassIteratorStatic static_klass_iterator;
+
+InstanceKlass* ClassLoaderDataGraph::try_get_next_class() {
+  return static_klass_iterator.try_get_next_class();
+}
+
+
 // Remove a klass from the _klasses list for scratch_class during redefinition
 // or parsed class in the case of an error.
 void ClassLoaderData::remove_class(Klass* scratch_class) {
   assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
+
+  // Adjust global class iterator.
+  static_klass_iterator.adjust_saved_class(scratch_class);
+
   Klass* prev = NULL;
   for (Klass* k = _klasses; k != NULL; k = k->next_link()) {
     if (k == scratch_class) {
@@ -493,6 +572,9 @@
   // In some rare cases items added to this list will not be freed elsewhere.
   // To keep it simple, just free everything in it here.
   free_deallocate_list();
+
+  // Clean up global class iterator for compiler
+  static_klass_iterator.adjust_saved_class(this);
 }
 
 ModuleEntryTable* ClassLoaderData::modules() {
@@ -515,6 +597,45 @@
   return modules;
 }
 
+const int _boot_loader_dictionary_size    = 1009;
+const int _default_loader_dictionary_size = 107;
+const int _prime_array_size         = 8;                       // array of primes for system dictionary size
+const int _average_depth_goal       = 3;                       // goal for lookup length
+const int _primelist[_prime_array_size] = {107, 1009, 2017, 4049, 5051, 10103, 20201, 40423};
+
+// Calculate a "good" dictionary size based
+// on predicted or current loaded classes count.
+static int calculate_dictionary_size(int classcount) {
+  int newsize = _primelist[0];
+  if (classcount > 0 && !DumpSharedSpaces) {
+    int index = 0;
+    int desiredsize = classcount/_average_depth_goal;
+    for (newsize = _primelist[index]; index < _prime_array_size -1;
+         newsize = _primelist[++index]) {
+      if (desiredsize <=  newsize) {
+        break;
+      }
+    }
+  }
+  return newsize;
+}
+
+Dictionary* ClassLoaderData::create_dictionary() {
+  assert(!is_anonymous(), "anonymous class loader data do not have a dictionary");
+  int size;
+  if (_the_null_class_loader_data == NULL) {
+    size = _boot_loader_dictionary_size;
+  } else if (class_loader()->is_a(SystemDictionary::reflect_DelegatingClassLoader_klass())) {
+    size = 1;  // there's only one class in relection class loader and no initiated classes
+  } else if (is_system_class_loader_data()) {
+    size = calculate_dictionary_size(PredictedLoadedClassCount);
+  } else {
+    size = _default_loader_dictionary_size;
+  }
+  return new Dictionary(this, size);
+}
+
+// Unloading support
 oop ClassLoaderData::keep_alive_object() const {
   assert_locked_or_safepoint(_metaspace_lock);
   assert(!keep_alive(), "Don't use with CLDs that are artificially kept alive");
@@ -546,6 +667,13 @@
     _modules = NULL;
   }
 
+  // Release C heap allocated hashtable for the dictionary
+  if (_dictionary != NULL) {
+    // Destroy the table itself
+    delete _dictionary;
+    _dictionary = NULL;
+  }
+
   if (_unnamed_module != NULL) {
     _unnamed_module->delete_unnamed_module();
     _unnamed_module = NULL;
@@ -974,6 +1102,46 @@
   }
 }
 
+#define FOR_ALL_DICTIONARY(X) for (ClassLoaderData* X = _head; X != NULL; X = X->next()) \
+                                if (X->dictionary() != NULL)
+
+// Walk classes in the loaded class dictionaries in various forms.
+// Only walks the classes defined in this class loader.
+void ClassLoaderDataGraph::dictionary_classes_do(void f(InstanceKlass*)) {
+  FOR_ALL_DICTIONARY(cld) {
+    cld->dictionary()->classes_do(f);
+  }
+}
+
+// Only walks the classes defined in this class loader.
+void ClassLoaderDataGraph::dictionary_classes_do(void f(InstanceKlass*, TRAPS), TRAPS) {
+  FOR_ALL_DICTIONARY(cld) {
+    cld->dictionary()->classes_do(f, CHECK);
+  }
+}
+
+// Walks all entries in the dictionary including entries initiated by this class loader.
+void ClassLoaderDataGraph::dictionary_all_entries_do(void f(InstanceKlass*, ClassLoaderData*)) {
+  FOR_ALL_DICTIONARY(cld) {
+    cld->dictionary()->all_entries_do(f);
+  }
+}
+
+void ClassLoaderDataGraph::verify_dictionary() {
+  FOR_ALL_DICTIONARY(cld) {
+    cld->dictionary()->verify();
+  }
+}
+
+void ClassLoaderDataGraph::print_dictionary(bool details) {
+  FOR_ALL_DICTIONARY(cld) {
+    tty->print("Dictionary for class loader ");
+    cld->print_value();
+    tty->cr();
+    cld->dictionary()->print(details);
+  }
+}
+
 GrowableArray<ClassLoaderData*>* ClassLoaderDataGraph::new_clds() {
   assert(_head == NULL || _saved_head != NULL, "remember_new_clds(true) not called?");
 
@@ -1074,14 +1242,19 @@
   }
 
   if (seen_dead_loader) {
-    // 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.
     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();
       }
@@ -1253,6 +1426,15 @@
   }
 }
 
+void ClassLoaderData::print_on(outputStream* out) const {
+  if (class_loader() == NULL) {
+    out->print("NULL class_loader");
+  } else {
+    out->print("class loader " INTPTR_FORMAT " ", p2i(this));
+    class_loader()->print_on(out);
+  }
+}
+
 #if INCLUDE_TRACE
 
 Ticks ClassLoaderDataGraph::_class_unload_time;
--- a/hotspot/src/share/vm/classfile/classLoaderData.hpp	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp	Fri Jul 28 10:48:35 2017 -0400
@@ -46,9 +46,8 @@
 // used by the dynamic linker to allocate the runtime representation of all
 // the types it defines.
 //
-// ClassLoaderData are stored in the runtime representation of classes and the
-// system dictionary, are roots of garbage collection, and provides iterators
-// for root tracing and other GC operations.
+// ClassLoaderData are stored in the runtime representation of classes,
+// and provides iterators for root tracing and other GC operations.
 
 class ClassLoaderData;
 class JNIMethodBlock;
@@ -57,6 +56,8 @@
 class PackageEntry;
 class ModuleEntryTable;
 class PackageEntryTable;
+class DictionaryEntry;
+class Dictionary;
 
 // GC root for walking class loader data created
 
@@ -64,6 +65,7 @@
   friend class ClassLoaderData;
   friend class ClassLoaderDataGraphMetaspaceIterator;
   friend class ClassLoaderDataGraphKlassIteratorAtomic;
+  friend class ClassLoaderDataGraphKlassIteratorStatic;
   friend class VMStructs;
  private:
   // All CLDs (except the null CLD) can be reached by walking _head->_next->...
@@ -109,6 +111,22 @@
   static void classes_unloading_do(void f(Klass* const));
   static bool do_unloading(BoolObjectClosure* is_alive, bool clean_previous_versions);
 
+  // dictionary do
+  // Iterate over all klasses in dictionary, but
+  // just the classes from defining class loaders.
+  static void dictionary_classes_do(void f(InstanceKlass*));
+  // Added for initialize_itable_for_klass to handle exceptions.
+  static void dictionary_classes_do(void f(InstanceKlass*, TRAPS), TRAPS);
+
+  // Iterate all classes and their class loaders, including initiating class loaders.
+  static void dictionary_all_entries_do(void f(InstanceKlass*, ClassLoaderData*));
+
+  // VM_CounterDecay iteration support
+  static InstanceKlass* try_get_next_class();
+
+  static void verify_dictionary();
+  static void print_dictionary(bool details);
+
   // CMS support.
   static void remember_new_clds(bool remember) { _saved_head = (remember ? _head : NULL); }
   static GrowableArray<ClassLoaderData*>* new_clds();
@@ -193,6 +211,7 @@
 
   friend class ClassLoaderDataGraph;
   friend class ClassLoaderDataGraphKlassIteratorAtomic;
+  friend class ClassLoaderDataGraphKlassIteratorStatic;
   friend class ClassLoaderDataGraphMetaspaceIterator;
   friend class MetaDataFactory;
   friend class Method;
@@ -221,8 +240,9 @@
 
   Klass* volatile _klasses;              // The classes defined by the class loader.
   PackageEntryTable* volatile _packages; // The packages defined by the class loader.
+  ModuleEntryTable*  volatile _modules;  // The modules defined by the class loader.
   ModuleEntry* _unnamed_module;          // This class loader's unnamed module.
-  ModuleEntryTable* volatile _modules;   // The modules defined by the class loader.
+  Dictionary*  _dictionary;              // The loaded InstanceKlasses, including initiated by this class loader
 
   // These method IDs are created for the class loader and set to NULL when the
   // class loader is unloaded.  They are rarely freed, only for redefine classes
@@ -269,6 +289,7 @@
   // Allocate out of this class loader data
   MetaWord* allocate(size_t size);
 
+  Dictionary* create_dictionary();
  public:
 
   bool is_alive(BoolObjectClosure* is_alive_closure) const;
@@ -324,17 +345,20 @@
   void inc_keep_alive();
   void dec_keep_alive();
 
-  inline unsigned int identity_hash() const;
+  inline unsigned int identity_hash() const { return (unsigned int)(((intptr_t)this) >> 3); }
 
   // Used when tracing from klasses.
   void oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim);
 
   void classes_do(KlassClosure* klass_closure);
+  Klass* klasses() { return _klasses; }
 
   JNIMethodBlock* jmethod_ids() const              { return _jmethod_ids; }
   void set_jmethod_ids(JNIMethodBlock* new_block)  { _jmethod_ids = new_block; }
 
-  void print_value() { print_value_on(tty); }
+  void print()                                     { print_on(tty); }
+  void print_on(outputStream* out) const;
+  void print_value()                               { print_value_on(tty); }
   void print_value_on(outputStream* out) const;
   void dump(outputStream * const out) PRODUCT_RETURN;
   void verify();
@@ -352,6 +376,9 @@
   ModuleEntryTable* modules();
   bool modules_defined() { return (_modules != NULL); }
 
+  // Loaded class dictionary
+  Dictionary* dictionary() const { return _dictionary; }
+
   void add_to_deallocate_list(Metadata* m);
 
   static ClassLoaderData* class_loader_data(oop loader);
--- a/hotspot/src/share/vm/classfile/classLoaderData.inline.hpp	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/share/vm/classfile/classLoaderData.inline.hpp	Fri Jul 28 10:48:35 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -26,10 +26,6 @@
 #include "classfile/javaClasses.hpp"
 #include "oops/oop.inline.hpp"
 
-unsigned int ClassLoaderData::identity_hash() const {
-  return _class_loader == NULL ? 0 : _class_loader->identity_hash();
-}
-
 inline ClassLoaderData* ClassLoaderData::class_loader_data_or_null(oop loader) {
   if (loader == NULL) {
     return ClassLoaderData::the_null_class_loader_data();
--- a/hotspot/src/share/vm/classfile/dictionary.cpp	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/share/vm/classfile/dictionary.cpp	Fri Jul 28 10:48:35 2017 -0400
@@ -34,12 +34,10 @@
 #include "memory/iterator.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/oop.inline.hpp"
+#include "runtime/atomic.hpp"
 #include "runtime/orderAccess.inline.hpp"
 #include "utilities/hashtable.inline.hpp"
 
-DictionaryEntry*  Dictionary::_current_class_entry = NULL;
-int               Dictionary::_current_class_index =    0;
-
 size_t Dictionary::entry_size() {
   if (DumpSharedSpaces) {
     return SystemDictionaryShared::dictionary_entry_size();
@@ -48,30 +46,33 @@
   }
 }
 
-Dictionary::Dictionary(int table_size)
-  : TwoOopHashtable<InstanceKlass*, mtClass>(table_size, (int)entry_size()) {
-  _current_class_index = 0;
-  _current_class_entry = NULL;
-  _pd_cache_table = new ProtectionDomainCacheTable(defaultProtectionDomainCacheSize);
+Dictionary::Dictionary(ClassLoaderData* loader_data, int table_size)
+  : _loader_data(loader_data), Hashtable<InstanceKlass*, mtClass>(table_size, (int)entry_size()) {
 };
 
 
-Dictionary::Dictionary(int table_size, HashtableBucket<mtClass>* t,
+Dictionary::Dictionary(ClassLoaderData* loader_data,
+                       int table_size, HashtableBucket<mtClass>* t,
                        int number_of_entries)
-  : TwoOopHashtable<InstanceKlass*, mtClass>(table_size, (int)entry_size(), t, number_of_entries) {
-  _current_class_index = 0;
-  _current_class_entry = NULL;
-  _pd_cache_table = new ProtectionDomainCacheTable(defaultProtectionDomainCacheSize);
+  : _loader_data(loader_data), Hashtable<InstanceKlass*, mtClass>(table_size, (int)entry_size(), t, number_of_entries) {
 };
 
-ProtectionDomainCacheEntry* Dictionary::cache_get(Handle protection_domain) {
-  return _pd_cache_table->get(protection_domain);
+Dictionary::~Dictionary() {
+  DictionaryEntry* probe = NULL;
+  for (int index = 0; index < table_size(); index++) {
+    for (DictionaryEntry** p = bucket_addr(index); *p != NULL; ) {
+      probe = *p;
+      *p = probe->next();
+      free_entry(probe);
+    }
+  }
+  assert(number_of_entries() == 0, "should have removed all entries");
+  assert(new_entry_free_list() == NULL, "entry present on Dictionary's free list");
+  free_buckets();
 }
 
-DictionaryEntry* Dictionary::new_entry(unsigned int hash, InstanceKlass* klass,
-                                       ClassLoaderData* loader_data) {
-  DictionaryEntry* entry = (DictionaryEntry*)Hashtable<InstanceKlass*, mtClass>::new_entry(hash, klass);
-  entry->set_loader_data(loader_data);
+DictionaryEntry* Dictionary::new_entry(unsigned int hash, InstanceKlass* klass) {
+  DictionaryEntry* entry = (DictionaryEntry*)Hashtable<InstanceKlass*, mtClass>::allocate_new_entry(hash, klass);
   entry->set_pd_set(NULL);
   assert(klass->is_instance_klass(), "Must be");
   if (DumpSharedSpaces) {
@@ -88,13 +89,15 @@
     entry->set_pd_set(to_delete->next());
     delete to_delete;
   }
-  Hashtable<InstanceKlass*, mtClass>::free_entry(entry);
+  // Unlink from the Hashtable prior to freeing
+  unlink_entry(entry);
+  FREE_C_HEAP_ARRAY(char, entry);
 }
 
 
 bool DictionaryEntry::contains_protection_domain(oop protection_domain) const {
 #ifdef ASSERT
-  if (protection_domain == klass()->protection_domain()) {
+  if (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;
@@ -112,7 +115,7 @@
   }
 #endif /* ASSERT */
 
-  if (protection_domain == klass()->protection_domain()) {
+  if (protection_domain == instance_klass()->protection_domain()) {
     // Succeeds trivially
     return true;
   }
@@ -129,7 +132,7 @@
 void DictionaryEntry::add_protection_domain(Dictionary* dict, Handle protection_domain) {
   assert_locked_or_safepoint(SystemDictionary_lock);
   if (!contains_protection_domain(protection_domain())) {
-    ProtectionDomainCacheEntry* entry = dict->cache_get(protection_domain);
+    ProtectionDomainCacheEntry* entry = SystemDictionary::cache_get(protection_domain);
     ProtectionDomainEntry* new_head =
                 new ProtectionDomainEntry(entry, _pd_set);
     // Warning: Preserve store ordering.  The SystemDictionary is read
@@ -149,86 +152,43 @@
 void Dictionary::do_unloading() {
   assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
 
-  // Remove unloadable entries and classes from system dictionary
+  // The NULL class loader doesn't initiate loading classes from other class loaders
+  if (loader_data() == ClassLoaderData::the_null_class_loader_data()) {
+    return;
+  }
+
+  // Remove unloaded entries and classes from this dictionary
   DictionaryEntry* probe = NULL;
   for (int index = 0; index < table_size(); index++) {
     for (DictionaryEntry** p = bucket_addr(index); *p != NULL; ) {
       probe = *p;
-      Klass* e = probe->klass();
-      ClassLoaderData* loader_data = probe->loader_data();
-
-      InstanceKlass* ik = InstanceKlass::cast(e);
-
-      // 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");
-        ClassLoaderData* k_def_class_loader_data = ik->class_loader_data();
-
-        // Do we need to delete this system dictionary entry?
-        bool purge_entry = false;
+      InstanceKlass* ik = probe->instance_klass();
+      ClassLoaderData* k_def_class_loader_data = ik->class_loader_data();
 
-        // Do we need to delete this system dictionary entry?
-        if (loader_data->is_unloading()) {
-          // If the loader is not live this entry should always be
-          // removed (will never be looked up again).
-          purge_entry = true;
-        } else {
-          // The loader in this entry is alive. If the klass is dead,
-          // (determined by checking the defining class loader)
-          // the loader must be an initiating loader (rather than the
-          // defining loader). Remove this entry.
-          if (k_def_class_loader_data->is_unloading()) {
-            // If we get here, the class_loader_data must not be the defining
-            // loader, it must be an initiating one.
-            assert(k_def_class_loader_data != loader_data,
-                   "cannot have live defining loader and unreachable klass");
-            // Loader is live, but class and its defining loader are dead.
-            // Remove the entry. The class is going away.
-            purge_entry = true;
-          }
-        }
-
-        if (purge_entry) {
-          *p = probe->next();
-          if (probe == _current_class_entry) {
-            _current_class_entry = NULL;
-          }
-          free_entry(probe);
-          continue;
-        }
+      // If the klass that this loader initiated is dead,
+      // (determined by checking the defining class loader)
+      // remove this entry.
+      if (k_def_class_loader_data->is_unloading()) {
+        assert(k_def_class_loader_data != loader_data(),
+               "cannot have live defining loader and unreachable klass");
+        *p = probe->next();
+        free_entry(probe);
+        continue;
       }
       p = probe->next_addr();
     }
   }
 }
 
-void Dictionary::roots_oops_do(OopClosure* strong, OopClosure* weak) {
-  // 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);
-   }
-  }
-}
-
-
 void Dictionary::remove_classes_in_error_state() {
   assert(DumpSharedSpaces, "supported only when dumping");
   DictionaryEntry* probe = NULL;
   for (int index = 0; index < table_size(); index++) {
     for (DictionaryEntry** p = bucket_addr(index); *p != NULL; ) {
       probe = *p;
-      InstanceKlass* ik = InstanceKlass::cast(probe->klass());
+      InstanceKlass* ik = probe->instance_klass();
       if (ik->is_in_error_state()) { // purge this entry
         *p = probe->next();
-        if (probe == _current_class_entry) {
-          _current_class_entry = NULL;
-        }
         free_entry(probe);
         ResourceMark rm;
         tty->print_cr("Preload Warning: Removed error class: %s", ik->external_name());
@@ -241,13 +201,13 @@
 }
 
 //   Just the classes from defining class loaders
-void Dictionary::classes_do(void f(Klass*)) {
+void Dictionary::classes_do(void f(InstanceKlass*)) {
   for (int index = 0; index < table_size(); index++) {
     for (DictionaryEntry* probe = bucket(index);
                           probe != NULL;
                           probe = probe->next()) {
-      Klass* k = probe->klass();
-      if (probe->loader_data() == k->class_loader_data()) {
+      InstanceKlass* k = probe->instance_klass();
+      if (loader_data() == k->class_loader_data()) {
         f(k);
       }
     }
@@ -256,78 +216,50 @@
 
 // Added for initialize_itable_for_klass to handle exceptions
 //   Just the classes from defining class loaders
-void Dictionary::classes_do(void f(Klass*, TRAPS), TRAPS) {
+void Dictionary::classes_do(void f(InstanceKlass*, TRAPS), TRAPS) {
   for (int index = 0; index < table_size(); index++) {
     for (DictionaryEntry* probe = bucket(index);
                           probe != NULL;
                           probe = probe->next()) {
-      Klass* k = probe->klass();
-      if (probe->loader_data() == k->class_loader_data()) {
+      InstanceKlass* k = probe->instance_klass();
+      if (loader_data() == k->class_loader_data()) {
         f(k, CHECK);
       }
     }
   }
 }
 
-//   All classes, and their class loaders
-// Don't iterate over placeholders
-void Dictionary::classes_do(void f(Klass*, ClassLoaderData*)) {
+// All classes, and their class loaders, including initiating class loaders
+void Dictionary::all_entries_do(void f(InstanceKlass*, ClassLoaderData*)) {
   for (int index = 0; index < table_size(); index++) {
     for (DictionaryEntry* probe = bucket(index);
                           probe != NULL;
                           probe = probe->next()) {
-      Klass* k = probe->klass();
-      f(k, probe->loader_data());
+      InstanceKlass* k = probe->instance_klass();
+      f(k, loader_data());
     }
   }
 }
 
-void Dictionary::oops_do(OopClosure* f) {
-  // Only the protection domain oops contain references into the heap. Iterate
-  // over all of them.
-  _pd_cache_table->oops_do(f);
-}
 
-void Dictionary::unlink(BoolObjectClosure* is_alive) {
-  // Only the protection domain cache table may contain references to the heap
-  // that need to be unlinked.
-  _pd_cache_table->unlink(is_alive);
-}
-
-InstanceKlass* Dictionary::try_get_next_class() {
-  while (true) {
-    if (_current_class_entry != NULL) {
-      InstanceKlass* k = _current_class_entry->klass();
-      _current_class_entry = _current_class_entry->next();
-      return k;
-    }
-    _current_class_index = (_current_class_index + 1) % table_size();
-    _current_class_entry = bucket(_current_class_index);
-  }
-  // never reached
-}
-
-// Add a loaded class to the system dictionary.
+// Add a loaded class to the dictionary.
 // Readers of the SystemDictionary aren't always locked, so _buckets
 // is volatile. The store of the next field in the constructor is
 // also cast to volatile;  we do this to ensure store order is maintained
 // by the compilers.
 
-void Dictionary::add_klass(Symbol* class_name, ClassLoaderData* loader_data,
+void Dictionary::add_klass(int index, unsigned int hash, Symbol* class_name,
                            InstanceKlass* obj) {
   assert_locked_or_safepoint(SystemDictionary_lock);
   assert(obj != NULL, "adding NULL obj");
   assert(obj->name() == class_name, "sanity check on name");
-  assert(loader_data != NULL, "Must be non-NULL");
 
-  unsigned int hash = compute_hash(class_name, loader_data);
-  int index = hash_to_index(hash);
-  DictionaryEntry* entry = new_entry(hash, obj, loader_data);
+  DictionaryEntry* entry = new_entry(hash, obj);
   add_entry(index, entry);
 }
 
 
-// This routine does not lock the system dictionary.
+// This routine does not lock the dictionary.
 //
 // Since readers don't hold a lock, we must make sure that system
 // dictionary entries are only removed at a safepoint (when only one
@@ -337,13 +269,14 @@
 // Callers should be aware that an entry could be added just after
 // _buckets[index] is read here, so the caller will not see the new entry.
 DictionaryEntry* Dictionary::get_entry(int index, unsigned int hash,
-                                       Symbol* class_name,
-                                       ClassLoaderData* loader_data) {
+                                       Symbol* class_name) {
   for (DictionaryEntry* entry = bucket(index);
                         entry != NULL;
                         entry = entry->next()) {
-    if (entry->hash() == hash && entry->equals(class_name, loader_data)) {
-      return entry;
+    if (entry->hash() == hash && entry->equals(class_name)) {
+      if (!DumpSharedSpaces || SystemDictionaryShared::is_builtin(entry)) {
+        return entry;
+      }
     }
   }
   return NULL;
@@ -351,10 +284,10 @@
 
 
 InstanceKlass* Dictionary::find(int index, unsigned int hash, Symbol* name,
-                                ClassLoaderData* loader_data, Handle protection_domain, TRAPS) {
-  DictionaryEntry* entry = get_entry(index, hash, name, loader_data);
+                                Handle protection_domain) {
+  DictionaryEntry* entry = get_entry(index, hash, name);
   if (entry != NULL && entry->is_valid_protection_domain(protection_domain)) {
-    return entry->klass();
+    return entry->instance_klass();
   } else {
     return NULL;
   }
@@ -362,12 +295,12 @@
 
 
 InstanceKlass* Dictionary::find_class(int index, unsigned int hash,
-                                      Symbol* name, ClassLoaderData* loader_data) {
+                                      Symbol* name) {
   assert_locked_or_safepoint(SystemDictionary_lock);
-  assert (index == index_for(name, loader_data), "incorrect index?");
+  assert (index == index_for(name), "incorrect index?");
 
-  DictionaryEntry* entry = get_entry(index, hash, name, loader_data);
-  return (entry != NULL) ? entry->klass() : NULL;
+  DictionaryEntry* entry = get_entry(index, hash, name);
+  return (entry != NULL) ? entry->instance_klass() : NULL;
 }
 
 
@@ -376,19 +309,19 @@
 
 InstanceKlass* Dictionary::find_shared_class(int index, unsigned int hash,
                                              Symbol* name) {
-  assert (index == index_for(name, NULL), "incorrect index?");
+  assert (index == index_for(name), "incorrect index?");
 
-  DictionaryEntry* entry = get_entry(index, hash, name, NULL);
-  return (entry != NULL) ? entry->klass() : NULL;
+  DictionaryEntry* entry = get_entry(index, hash, name);
+  return (entry != NULL) ? entry->instance_klass() : NULL;
 }
 
 
 void Dictionary::add_protection_domain(int index, unsigned int hash,
                                        InstanceKlass* klass,
-                                       ClassLoaderData* loader_data, Handle protection_domain,
+                                       Handle protection_domain,
                                        TRAPS) {
   Symbol*  klass_name = klass->name();
-  DictionaryEntry* entry = get_entry(index, hash, klass_name, loader_data);
+  DictionaryEntry* entry = get_entry(index, hash, klass_name);
 
   assert(entry != NULL,"entry must be present, we just created it");
   assert(protection_domain() != NULL,
@@ -403,9 +336,8 @@
 
 bool Dictionary::is_valid_protection_domain(int index, unsigned int hash,
                                             Symbol* name,
-                                            ClassLoaderData* loader_data,
                                             Handle protection_domain) {
-  DictionaryEntry* entry = get_entry(index, hash, name, loader_data);
+  DictionaryEntry* entry = get_entry(index, hash, name);
   return entry->is_valid_protection_domain(protection_domain);
 }
 
@@ -432,13 +364,12 @@
     DictionaryEntry* p = master_list;
     master_list = master_list->next();
     p->set_next(NULL);
-    Symbol* class_name = p->klass()->name();
+    Symbol* class_name = p->instance_klass()->name();
     // Since the null class loader data isn't copied to the CDS archive,
     // compute the hash with NULL for loader data.
-    unsigned int hash = compute_hash(class_name, NULL);
+    unsigned int hash = compute_hash(class_name);
     int index = hash_to_index(hash);
     p->set_hash(hash);
-    p->set_loader_data(NULL);   // loader_data isn't copied to CDS
     p->set_next(bucket(index));
     set_entry(index, p);
   }
@@ -507,8 +438,9 @@
 void Dictionary::print(bool details) {
   ResourceMark rm;
 
+  assert(loader_data() != NULL, "loader data should not be null");
   if (details) {
-    tty->print_cr("Java system dictionary (table_size=%d, classes=%d)",
+    tty->print_cr("Java dictionary (table_size=%d, classes=%d)",
                    table_size(), number_of_entries());
     tty->print_cr("^ indicates that initiating loader is different from "
                   "defining loader");
@@ -518,10 +450,9 @@
     for (DictionaryEntry* probe = bucket(index);
                           probe != NULL;
                           probe = probe->next()) {
-      Klass* e = probe->klass();
-      ClassLoaderData* loader_data =  probe->loader_data();
+      Klass* e = probe->instance_klass();
       bool is_defining_class =
-         (loader_data == e->class_loader_data());
+         (loader_data() == e->class_loader_data());
       if (details) {
         tty->print("%4d: ", index);
       }
@@ -530,41 +461,36 @@
 
       if (details) {
         tty->print(", loader ");
-        if (loader_data != NULL) {
-          loader_data->print_value();
-        } else {
-          tty->print("NULL");
-        }
+        e->class_loader_data()->print_value();
       }
       tty->cr();
     }
   }
-
-  if (details) {
-    tty->cr();
-    _pd_cache_table->print();
-  }
   tty->cr();
 }
 
 void DictionaryEntry::verify() {
-  Klass* e = klass();
+  Klass* e = instance_klass();
+  guarantee(e->is_instance_klass(),
+                          "Verify of dictionary failed");
+  e->verify();
+  verify_protection_domain_set();
+}
+
+void Dictionary::verify() {
+  guarantee(number_of_entries() >= 0, "Verify of dictionary failed");
+
   ClassLoaderData* cld = loader_data();
-  guarantee(e->is_instance_klass(),
-                          "Verify of system dictionary failed");
   // class loader must be present;  a null class loader is the
   // boostrap loader
   guarantee(cld != NULL || DumpSharedSpaces ||
             cld->class_loader() == NULL ||
             cld->class_loader()->is_instance(),
             "checking type of class_loader");
-  e->verify();
-  verify_protection_domain_set();
+
+  ResourceMark rm;
+  stringStream tempst;
+  tempst.print("System Dictionary for %s", cld->loader_name());
+  verify_table<DictionaryEntry>(tempst.as_string());
 }
 
-void Dictionary::verify() {
-  guarantee(number_of_entries() >= 0, "Verify of system dictionary failed");
-  verify_table<DictionaryEntry>("System Dictionary");
-  _pd_cache_table->verify();
-}
-
--- a/hotspot/src/share/vm/classfile/dictionary.hpp	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/share/vm/classfile/dictionary.hpp	Fri Jul 28 10:48:35 2017 -0400
@@ -36,21 +36,16 @@
 class BoolObjectClosure;
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// The data structure for the system dictionary (and the shared system
+// The data structure for the class loader data dictionaries (and the shared system
 // dictionary).
 
-class Dictionary : public TwoOopHashtable<InstanceKlass*, mtClass> {
+class Dictionary : public Hashtable<InstanceKlass*, mtClass> {
   friend class VMStructs;
-private:
-  // current iteration index.
-  static int                    _current_class_index;
-  // pointer to the current hash table entry.
-  static DictionaryEntry*       _current_class_entry;
 
-  ProtectionDomainCacheTable*   _pd_cache_table;
+  ClassLoaderData* _loader_data;  // backpointer to owning loader
+  ClassLoaderData* loader_data() const { return _loader_data; }
 
-  DictionaryEntry* get_entry(int index, unsigned int hash,
-                             Symbol* name, ClassLoaderData* loader_data);
+  DictionaryEntry* get_entry(int index, unsigned int hash, Symbol* name);
 
 protected:
   DictionaryEntry* bucket(int i) const {
@@ -66,61 +61,48 @@
     Hashtable<InstanceKlass*, mtClass>::add_entry(index, (HashtableEntry<InstanceKlass*, mtClass>*)new_entry);
   }
 
-  static size_t entry_size();
-public:
-  Dictionary(int table_size);
-  Dictionary(int table_size, HashtableBucket<mtClass>* t, int number_of_entries);
-
-  DictionaryEntry* new_entry(unsigned int hash, InstanceKlass* klass, ClassLoaderData* loader_data);
-
   void free_entry(DictionaryEntry* entry);
 
-  void add_klass(Symbol* class_name, ClassLoaderData* loader_data, InstanceKlass* obj);
+  static size_t entry_size();
+public:
+  Dictionary(ClassLoaderData* loader_data, int table_size);
+  Dictionary(ClassLoaderData* loader_data, int table_size, HashtableBucket<mtClass>* t, int number_of_entries);
+  ~Dictionary();
 
-  InstanceKlass* find_class(int index, unsigned int hash,
-                            Symbol* name, ClassLoaderData* loader_data);
+  DictionaryEntry* new_entry(unsigned int hash, InstanceKlass* klass);
+
+  void add_klass(int index, unsigned int hash, Symbol* class_name, InstanceKlass* obj);
+
+  InstanceKlass* find_class(int index, unsigned int hash, Symbol* name);
 
   InstanceKlass* find_shared_class(int index, unsigned int hash, Symbol* name);
 
-  // Compiler support
-  InstanceKlass* try_get_next_class();
-
   // GC support
   void oops_do(OopClosure* f);
   void roots_oops_do(OopClosure* strong, OopClosure* weak);
 
-  void classes_do(void f(Klass*));
-  void classes_do(void f(Klass*, TRAPS), TRAPS);
-  void classes_do(void f(Klass*, ClassLoaderData*));
+  void classes_do(void f(InstanceKlass*));
+  void classes_do(void f(InstanceKlass*, TRAPS), TRAPS);
+  void all_entries_do(void f(InstanceKlass*, ClassLoaderData*));
 
   void unlink(BoolObjectClosure* is_alive);
   void remove_classes_in_error_state();
 
-  // Classes loaded by the bootstrap loader are always strongly reachable.
-  // If we're not doing class unloading, all classes are strongly reachable.
-  static bool is_strongly_reachable(ClassLoaderData* loader_data, Klass* klass) {
-    assert (klass != NULL, "should have non-null klass");
-    return (loader_data->is_the_null_class_loader_data() || !ClassUnloading);
-  }
-
-  // Unload (that is, break root links to) all unmarked classes and loaders.
+  // Unload classes whose defining loaders are unloaded
   void do_unloading();
 
   // Protection domains
-  InstanceKlass* find(int index, unsigned int hash, Symbol* name,
-                      ClassLoaderData* loader_data, Handle protection_domain, TRAPS);
+  InstanceKlass* find(int index, unsigned int hash, Symbol* name, Handle protection_domain);
   bool is_valid_protection_domain(int index, unsigned int hash,
-                                  Symbol* name, ClassLoaderData* loader_data,
+                                  Symbol* name,
                                   Handle protection_domain);
   void add_protection_domain(int index, unsigned int hash,
-                             InstanceKlass* klass, ClassLoaderData* loader_data,
+                             InstanceKlass* klass,
                              Handle protection_domain, TRAPS);
 
   // Sharing support
   void reorder_dictionary();
 
-  ProtectionDomainCacheEntry* cache_get(Handle protection_domain);
-
   void print(bool details = true);
 #ifdef ASSERT
   void printPerformanceInfoDetails();
@@ -128,14 +110,14 @@
   void verify();
 };
 
-// An entry in the system dictionary, this describes a class as
-// { InstanceKlass*, loader, protection_domain }.
+// An entry in the class loader data dictionaries, this describes a class as
+// { InstanceKlass*, protection_domain }.
 
 class DictionaryEntry : public HashtableEntry<InstanceKlass*, mtClass> {
   friend class VMStructs;
  private:
   // Contains the set of approved protection domains that can access
-  // this system dictionary entry.
+  // this dictionary entry.
   //
   // This protection domain set is a set of tuples:
   //
@@ -155,7 +137,6 @@
   // ClassLoader.checkPackageAccess().
   //
   ProtectionDomainEntry* _pd_set;
-  ClassLoaderData*       _loader_data;
 
  public:
   // Tells whether a protection is in the approved set.
@@ -163,7 +144,7 @@
   // Adds a protection domain to the approved set.
   void add_protection_domain(Dictionary* dict, Handle protection_domain);
 
-  InstanceKlass* klass() const { return (InstanceKlass*)literal(); }
+  InstanceKlass* instance_klass() const { return literal(); }
 
   DictionaryEntry* next() const {
     return (DictionaryEntry*)HashtableEntry<InstanceKlass*, mtClass>::next();
@@ -173,13 +154,10 @@
     return (DictionaryEntry**)HashtableEntry<InstanceKlass*, mtClass>::next_addr();
   }
 
-  ClassLoaderData* loader_data() const { return _loader_data; }
-  void set_loader_data(ClassLoaderData* loader_data) { _loader_data = loader_data; }
-
   ProtectionDomainEntry* pd_set() const { return _pd_set; }
   void set_pd_set(ProtectionDomainEntry* pd_set) { _pd_set = pd_set; }
 
-  // Tells whether the initiating class' protection can access the this _klass
+  // Tells whether the initiating class' protection domain can access the klass in this entry
   bool is_valid_protection_domain(Handle protection_domain) {
     if (!ProtectionDomainVerification) return true;
     if (!SystemDictionary::has_checkPackageAccess()) return true;
@@ -197,9 +175,9 @@
     }
   }
 
-  bool equals(const Symbol* class_name, ClassLoaderData* loader_data) const {
+  bool equals(const Symbol* class_name) const {
     InstanceKlass* klass = (InstanceKlass*)literal();
-    return (klass->name() == class_name && _loader_data == loader_data);
+    return (klass->name() == class_name);
   }
 
   void print_count(outputStream *st) {
--- a/hotspot/src/share/vm/classfile/loaderConstraints.cpp	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/share/vm/classfile/loaderConstraints.cpp	Fri Jul 28 10:48:35 2017 -0400
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "classfile/dictionary.hpp"
 #include "classfile/classLoaderData.inline.hpp"
 #include "classfile/loaderConstraints.hpp"
 #include "logging/log.hpp"
@@ -36,8 +37,8 @@
   set_loader_data(i, ClassLoaderData::class_loader_data(p));
 }
 
-LoaderConstraintTable::LoaderConstraintTable(int nof_buckets)
-  : Hashtable<InstanceKlass*, mtClass>(nof_buckets, sizeof(LoaderConstraintEntry)) {};
+LoaderConstraintTable::LoaderConstraintTable(int table_size)
+  : Hashtable<InstanceKlass*, mtClass>(table_size, sizeof(LoaderConstraintEntry)) {};
 
 
 LoaderConstraintEntry* LoaderConstraintTable::new_entry(
@@ -425,10 +426,9 @@
 }
 
 
-void LoaderConstraintTable::verify(Dictionary* dictionary,
-                                   PlaceholderTable* placeholders) {
+void LoaderConstraintTable::verify(PlaceholderTable* placeholders) {
   Thread *thread = Thread::current();
-  for (int cindex = 0; cindex < _loader_constraint_size; cindex++) {
+  for (int cindex = 0; cindex < table_size(); cindex++) {
     for (LoaderConstraintEntry* probe = bucket(cindex);
                                 probe != NULL;
                                 probe = probe->next()) {
@@ -437,17 +437,18 @@
         guarantee(ik->name() == probe->name(), "name should match");
         Symbol* name = ik->name();
         ClassLoaderData* loader_data = ik->class_loader_data();
-        unsigned int d_hash = dictionary->compute_hash(name, loader_data);
+        Dictionary* dictionary = loader_data->dictionary();
+        unsigned int d_hash = dictionary->compute_hash(name);
         int d_index = dictionary->hash_to_index(d_hash);
-        InstanceKlass* k = dictionary->find_class(d_index, d_hash, name, loader_data);
+        InstanceKlass* k = dictionary->find_class(d_index, d_hash, name);
         if (k != NULL) {
-          // We found the class in the system dictionary, so we should
+          // We found the class in the dictionary, so we should
           // make sure that the Klass* matches what we already have.
           guarantee(k == probe->klass(), "klass should be in dictionary");
         } else {
-          // If we don't find the class in the system dictionary, it
+          // If we don't find the class in the dictionary, it
           // has to be in the placeholders table.
-          unsigned int p_hash = placeholders->compute_hash(name, loader_data);
+          unsigned int p_hash = placeholders->compute_hash(name);
           int p_index = placeholders->hash_to_index(p_hash);
           PlaceholderEntry* entry = placeholders->get_entry(p_index, p_hash,
                                                             name, loader_data);
@@ -471,8 +472,9 @@
 void LoaderConstraintTable::print() {
   ResourceMark rm;
   assert_locked_or_safepoint(SystemDictionary_lock);
-  tty->print_cr("Java loader constraints (entries=%d)", _loader_constraint_size);
-  for (int cindex = 0; cindex < _loader_constraint_size; cindex++) {
+  tty->print_cr("Java loader constraints (entries=%d, constraints=%d)",
+                table_size(), number_of_entries());
+  for (int cindex = 0; cindex < table_size(); cindex++) {
     for (LoaderConstraintEntry* probe = bucket(cindex);
                                 probe != NULL;
                                 probe = probe->next()) {
--- a/hotspot/src/share/vm/classfile/loaderConstraints.hpp	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/share/vm/classfile/loaderConstraints.hpp	Fri Jul 28 10:48:35 2017 -0400
@@ -25,28 +25,22 @@
 #ifndef SHARE_VM_CLASSFILE_LOADERCONSTRAINTS_HPP
 #define SHARE_VM_CLASSFILE_LOADERCONSTRAINTS_HPP
 
-#include "classfile/dictionary.hpp"
 #include "classfile/placeholders.hpp"
 #include "utilities/hashtable.hpp"
 
+class ClassLoaderData;
 class LoaderConstraintEntry;
 class Symbol;
 
 class LoaderConstraintTable : public Hashtable<InstanceKlass*, mtClass> {
-  friend class VMStructs;
+
 private:
-
-  enum Constants {
-    _loader_constraint_size = 107,                     // number of entries in constraint table
-    _nof_buckets            = 1009                     // number of buckets in hash table
-  };
-
   LoaderConstraintEntry** find_loader_constraint(Symbol* name,
                                                  Handle loader);
 
 public:
 
-  LoaderConstraintTable(int nof_buckets);
+  LoaderConstraintTable(int table_size);
 
   LoaderConstraintEntry* new_entry(unsigned int hash, Symbol* name,
                                    InstanceKlass* klass, int num_loaders,
@@ -84,14 +78,13 @@
 
   void purge_loader_constraints();
 
-  void verify(Dictionary* dictionary, PlaceholderTable* placeholders);
+  void verify(PlaceholderTable* placeholders);
 #ifndef PRODUCT
   void print();
 #endif
 };
 
 class LoaderConstraintEntry : public HashtableEntry<InstanceKlass*, mtClass> {
-  friend class VMStructs;
 private:
   Symbol*                _name;                   // class name
   int                    _num_loaders;
--- a/hotspot/src/share/vm/classfile/moduleEntry.cpp	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/share/vm/classfile/moduleEntry.cpp	Fri Jul 28 10:48:35 2017 -0400
@@ -339,12 +339,7 @@
                                          Symbol* version, Symbol* location,
                                          ClassLoaderData* loader_data) {
   assert(Module_lock->owned_by_self(), "should have the Module_lock");
-  ModuleEntry* entry = (ModuleEntry*) NEW_C_HEAP_ARRAY(char, entry_size(), mtModule);
-
-  // Initialize everything BasicHashtable would
-  entry->set_next(NULL);
-  entry->set_hash(hash);
-  entry->set_literal(name);
+  ModuleEntry* entry = (ModuleEntry*)Hashtable<Symbol*, mtModule>::allocate_new_entry(hash, name);
 
   // Initialize fields specific to a ModuleEntry
   entry->init();
--- a/hotspot/src/share/vm/classfile/packageEntry.cpp	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/share/vm/classfile/packageEntry.cpp	Fri Jul 28 10:48:35 2017 -0400
@@ -198,12 +198,7 @@
 
 PackageEntry* PackageEntryTable::new_entry(unsigned int hash, Symbol* name, ModuleEntry* module) {
   assert(Module_lock->owned_by_self(), "should have the Module_lock");
-  PackageEntry* entry = (PackageEntry*) NEW_C_HEAP_ARRAY(char, entry_size(), mtModule);
-
-  // Initialize everything BasicHashtable would
-  entry->set_next(NULL);
-  entry->set_hash(hash);
-  entry->set_literal(name);
+  PackageEntry* entry = (PackageEntry*)Hashtable<Symbol*, mtModule>::allocate_new_entry(hash, name);
 
   TRACE_INIT_ID(entry);
 
--- a/hotspot/src/share/vm/classfile/placeholders.cpp	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/share/vm/classfile/placeholders.cpp	Fri Jul 28 10:48:35 2017 -0400
@@ -172,7 +172,7 @@
   }
 
 PlaceholderTable::PlaceholderTable(int table_size)
-    : TwoOopHashtable<Symbol*, mtClass>(table_size, sizeof(PlaceholderEntry)) {
+    : Hashtable<Symbol*, mtClass>(table_size, sizeof(PlaceholderEntry)) {
 }
 
 #ifndef PRODUCT
--- a/hotspot/src/share/vm/classfile/placeholders.hpp	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/share/vm/classfile/placeholders.hpp	Fri Jul 28 10:48:35 2017 -0400
@@ -34,8 +34,7 @@
 // being loaded, as well as arrays of primitives.
 //
 
-class PlaceholderTable : public TwoOopHashtable<Symbol*, mtClass> {
-  friend class VMStructs;
+class PlaceholderTable : public Hashtable<Symbol*, mtClass> {
 
 public:
   PlaceholderTable(int table_size);
@@ -149,8 +148,6 @@
 // The system dictionary is the only user of this class.
 
 class PlaceholderEntry : public HashtableEntry<Symbol*, mtClass> {
-  friend class VMStructs;
-
 
  private:
   ClassLoaderData*  _loader_data;   // initiating loader
--- a/hotspot/src/share/vm/classfile/protectionDomainCache.cpp	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/share/vm/classfile/protectionDomainCache.cpp	Fri Jul 28 10:48:35 2017 -0400
@@ -88,14 +88,14 @@
     for (ProtectionDomainCacheEntry* probe = bucket(index);
                                      probe != NULL;
                                      probe = probe->next()) {
+      tty->print("%4d: ", index);
       probe->print();
     }
   }
 }
 
 void ProtectionDomainCacheEntry::print() {
-  tty->print_cr("entry " PTR_FORMAT " value " PTR_FORMAT " next " PTR_FORMAT,
-                p2i(this), p2i(literal()), p2i(next()));
+  tty->print_cr("protection_domain: " PTR_FORMAT, p2i(literal()));
 }
 #endif
 
--- a/hotspot/src/share/vm/classfile/protectionDomainCache.hpp	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/share/vm/classfile/protectionDomainCache.hpp	Fri Jul 28 10:48:35 2017 -0400
@@ -33,7 +33,7 @@
 // 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
+// This table is walked during GC, rather than the class loader data graph dictionaries.
 class ProtectionDomainCacheEntry : public HashtableEntry<oop, mtClass> {
   friend class VMStructs;
  public:
@@ -55,7 +55,7 @@
   void verify();
 };
 
-// The ProtectionDomainCacheTable contains all protection domain oops. The system
+// The ProtectionDomainCacheTable contains all protection domain oops. The
 // 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
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp	Fri Jul 28 10:48:35 2017 -0400
@@ -35,6 +35,7 @@
 #include "classfile/loaderConstraints.hpp"
 #include "classfile/packageEntry.hpp"
 #include "classfile/placeholders.hpp"
+#include "classfile/protectionDomainCache.hpp"
 #include "classfile/resolutionErrors.hpp"
 #include "classfile/stringTable.hpp"
 #include "classfile/systemDictionary.hpp"
@@ -88,19 +89,14 @@
 #include "trace/tracing.hpp"
 #endif
 
-Dictionary*            SystemDictionary::_dictionary          = NULL;
 PlaceholderTable*      SystemDictionary::_placeholders        = NULL;
 Dictionary*            SystemDictionary::_shared_dictionary   = NULL;
 LoaderConstraintTable* SystemDictionary::_loader_constraints  = NULL;
 ResolutionErrorTable*  SystemDictionary::_resolution_errors   = NULL;
 SymbolPropertyTable*   SystemDictionary::_invoke_method_table = NULL;
-
+ProtectionDomainCacheTable*   SystemDictionary::_pd_cache_table = NULL;
 
 int         SystemDictionary::_number_of_modifications = 0;
-int         SystemDictionary::_sdgeneration               = 0;
-const int   SystemDictionary::_primelist[_prime_array_size] = {1009,2017,4049,5051,10103,
-              20201,40423,99991};
-
 oop         SystemDictionary::_system_loader_lock_obj     =  NULL;
 
 InstanceKlass*      SystemDictionary::_well_known_klasses[SystemDictionary::WKID_LIMIT]
@@ -116,6 +112,10 @@
 // lazily initialized klass variables
 InstanceKlass* volatile SystemDictionary::_abstract_ownable_synchronizer_klass = NULL;
 
+// Default ProtectionDomainCacheSize value
+
+const int defaultProtectionDomainCacheSize = 1009;
+
 
 // ----------------------------------------------------------------------------
 // Java-level SystemLoader
@@ -343,32 +343,32 @@
 #endif // INCLUDE_CDS
 
   // Double-check, if child class is already loaded, just return super-class,interface
-  // Don't add a placedholder if already loaded, i.e. already in system dictionary
+  // Don't add a placedholder if already loaded, i.e. already in appropriate class loader
+  // dictionary.
   // Make sure there's a placeholder for the *child* before resolving.
   // Used as a claim that this thread is currently loading superclass/classloader
   // Used here for ClassCircularity checks and also for heap verification
-  // (every InstanceKlass in the heap needs to be in the system dictionary
-  // or have a placeholder).
-  // Must check ClassCircularity before checking if super class is already loaded
+  // (every InstanceKlass needs to be in its class loader dictionary or have a placeholder).
+  // Must check ClassCircularity before checking if super class is already loaded.
   //
   // We might not already have a placeholder if this child_name was
   // first seen via resolve_from_stream (jni_DefineClass or JVM_DefineClass);
   // the name of the class might not be known until the stream is actually
   // parsed.
   // Bugs 4643874, 4715493
-  // compute_hash can have a safepoint
 
   ClassLoaderData* loader_data = class_loader_data(class_loader);
-  unsigned int d_hash = dictionary()->compute_hash(child_name, loader_data);
-  int d_index = dictionary()->hash_to_index(d_hash);
-  unsigned int p_hash = placeholders()->compute_hash(child_name, loader_data);
+  Dictionary* dictionary = loader_data->dictionary();
+  unsigned int d_hash = dictionary->compute_hash(child_name);
+  int d_index = dictionary->hash_to_index(d_hash);
+  unsigned int p_hash = placeholders()->compute_hash(child_name);
   int p_index = placeholders()->hash_to_index(p_hash);
   // can't throw error holding a lock
   bool child_already_loaded = false;
   bool throw_circularity_error = false;
   {
     MutexLocker mu(SystemDictionary_lock, THREAD);
-    Klass* childk = find_class(d_index, d_hash, child_name, loader_data);
+    Klass* childk = find_class(d_index, d_hash, child_name, dictionary);
     Klass* quicksuperk;
     // to support // loading: if child done loading, just return superclass
     // if class_name, & class_loader don't match:
@@ -445,13 +445,18 @@
     ls.cr();
   }
 
+  // This handle and the class_loader handle passed in keeps this class from
+  // being unloaded through several GC points.
+  // The class_loader handle passed in is the initiating loader.
+  Handle mirror(THREAD, klass->java_mirror());
+
   InstanceKlass* system_loader = SystemDictionary::ClassLoader_klass();
   JavaCalls::call_special(&result,
                          class_loader,
                          system_loader,
                          vmSymbols::checkPackageAccess_name(),
                          vmSymbols::class_protectiondomain_signature(),
-                         Handle(THREAD, klass->java_mirror()),
+                         mirror,
                          protection_domain,
                          THREAD);
 
@@ -466,27 +471,16 @@
   // If no exception has been thrown, we have validated the protection domain
   // Insert the protection domain of the initiating class into the set.
   {
-    // We recalculate the entry here -- we've called out to java since
-    // the last time it was calculated.
     ClassLoaderData* loader_data = class_loader_data(class_loader);
+    Dictionary* dictionary = loader_data->dictionary();
 
     Symbol*  kn = klass->name();
-    unsigned int d_hash = dictionary()->compute_hash(kn, loader_data);
-    int d_index = dictionary()->hash_to_index(d_hash);
+    unsigned int d_hash = dictionary->compute_hash(kn);
+    int d_index = dictionary->hash_to_index(d_hash);
 
     MutexLocker mu(SystemDictionary_lock, THREAD);
-    {
-      // Note that we have an entry, and entries can be deleted only during GC,
-      // so we cannot allow GC to occur while we're holding this entry.
-
-      // We're using a NoSafepointVerifier to catch any place where we
-      // might potentially do a GC at all.
-      // Dictionary::do_unloading() asserts that classes in SD are only
-      // unloaded at a safepoint. Anonymous classes are not in SD.
-      NoSafepointVerifier nosafepoint;
-      dictionary()->add_protection_domain(d_index, d_hash, klass, loader_data,
-                                          protection_domain, THREAD);
-    }
+    dictionary->add_protection_domain(d_index, d_hash, klass,
+                                      protection_domain, THREAD);
   }
 }
 
@@ -548,9 +542,10 @@
     Handle protection_domain, Handle lockObject, TRAPS) {
 
   ClassLoaderData* loader_data = class_loader_data(class_loader);
-  unsigned int d_hash = dictionary()->compute_hash(name, loader_data);
-  int d_index = dictionary()->hash_to_index(d_hash);
-  unsigned int p_hash = placeholders()->compute_hash(name, loader_data);
+  Dictionary* dictionary = loader_data->dictionary();
+  unsigned int d_hash = dictionary->compute_hash(name);
+  int d_index = dictionary->hash_to_index(d_hash);
+  unsigned int p_hash = placeholders()->compute_hash(name);
   int p_index = placeholders()->hash_to_index(p_hash);
 
   // superk is not used, resolve_super called for circularity check only
@@ -573,7 +568,7 @@
  if (!class_loader.is_null() && is_parallelCapable(class_loader)) {
     MutexLocker mu(SystemDictionary_lock, THREAD);
     // Check if classloading completed while we were loading superclass or waiting
-    return find_class(d_index, d_hash, name, loader_data);
+    return find_class(d_index, d_hash, name, dictionary);
   }
 
   // must loop to both handle other placeholder updates
@@ -583,7 +578,7 @@
   while (super_load_in_progress) {
     MutexLocker mu(SystemDictionary_lock, THREAD);
     // Check if classloading completed while we were loading superclass or waiting
-    InstanceKlass* check = find_class(d_index, d_hash, name, loader_data);
+    InstanceKlass* check = find_class(d_index, d_hash, name, dictionary);
     if (check != NULL) {
       // Klass is already loaded, so just return it
       return check;
@@ -663,6 +658,7 @@
   // Fix for 4474172; see evaluation for more details
   class_loader = Handle(THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader()));
   ClassLoaderData *loader_data = register_loader(class_loader, CHECK_NULL);
+  Dictionary* dictionary = loader_data->dictionary();
 
   // Do lookup to see if class already exist and the protection domain
   // has the right access
@@ -670,10 +666,9 @@
   // All subsequent calls use find_class, and set has_loaded_class so that
   // before we return a result we call out to java to check for valid protection domain
   // to allow returning the Klass* and add it to the pd_set if it is valid
-  unsigned int d_hash = dictionary()->compute_hash(name, loader_data);
-  int d_index = dictionary()->hash_to_index(d_hash);
-  Klass* probe = dictionary()->find(d_index, d_hash, name, loader_data,
-                                      protection_domain, THREAD);
+  unsigned int d_hash = dictionary->compute_hash(name);
+  int d_index = dictionary->hash_to_index(d_hash);
+  Klass* probe = dictionary->find(d_index, d_hash, name, protection_domain);
   if (probe != NULL) return probe;
 
 
@@ -691,7 +686,7 @@
     DoObjectLock = false;
   }
 
-  unsigned int p_hash = placeholders()->compute_hash(name, loader_data);
+  unsigned int p_hash = placeholders()->compute_hash(name);
   int p_index = placeholders()->hash_to_index(p_hash);
 
   // Class is not in SystemDictionary so we have to do loading.
@@ -710,7 +705,7 @@
 
   {
     MutexLocker mu(SystemDictionary_lock, THREAD);
-    InstanceKlass* check = find_class(d_index, d_hash, name, loader_data);
+    InstanceKlass* check = find_class(d_index, d_hash, name, dictionary);
     if (check != NULL) {
       // Klass is already loaded, so just return it
       class_has_been_loaded = true;
@@ -794,7 +789,7 @@
                 double_lock_wait(lockObject, THREAD);
               }
               // Check if classloading completed while we were waiting
-              InstanceKlass* check = find_class(d_index, d_hash, name, loader_data);
+              InstanceKlass* check = find_class(d_index, d_hash, name, dictionary);
               if (check != NULL) {
                 // Klass is already loaded, so just return it
                 k = check;
@@ -819,7 +814,7 @@
         // i.e. now that we hold the LOAD_INSTANCE token on loading this class/CL
         // one final check if the load has already completed
         // class loaders holding the ObjectLock shouldn't find the class here
-        InstanceKlass* check = find_class(d_index, d_hash, name, loader_data);
+        InstanceKlass* check = find_class(d_index, d_hash, name, dictionary);
         if (check != NULL) {
         // Klass is already loaded, so return it after checking/adding protection domain
           k = check;
@@ -852,7 +847,7 @@
         if (k == NULL && HAS_PENDING_EXCEPTION
           && PENDING_EXCEPTION->is_a(SystemDictionary::LinkageError_klass())) {
           MutexLocker mu(SystemDictionary_lock, THREAD);
-          InstanceKlass* check = find_class(d_index, d_hash, name, loader_data);
+          InstanceKlass* check = find_class(d_index, d_hash, name, dictionary);
           if (check != NULL) {
             // Klass is already loaded, so just use it
             k = check;
@@ -886,7 +881,7 @@
           }
         }
       }
-    } // load_instance_class loop
+    } // load_instance_class
 
     if (load_instance_added == true) {
       // clean up placeholder entries for LOAD_INSTANCE success or error
@@ -919,16 +914,8 @@
   // Check the protection domain has the right access
   {
     MutexLocker mu(SystemDictionary_lock, THREAD);
-    // Note that we have an entry, and entries can be deleted only during GC,
-    // so we cannot allow GC to occur while we're holding this entry.
-    // We're using a NoSafepointVerifier to catch any place where we
-    // might potentially do a GC at all.
-    // Dictionary::do_unloading() asserts that classes in SD are only
-    // unloaded at a safepoint. Anonymous classes are not in SD.
-    NoSafepointVerifier nosafepoint;
-    if (dictionary()->is_valid_protection_domain(d_index, d_hash, name,
-                                                 loader_data,
-                                                 protection_domain)) {
+    if (dictionary->is_valid_protection_domain(d_index, d_hash, name,
+                                               protection_domain)) {
       return k;
     }
   }
@@ -968,20 +955,11 @@
     return NULL;
   }
 
-  unsigned int d_hash = dictionary()->compute_hash(class_name, loader_data);
-  int d_index = dictionary()->hash_to_index(d_hash);
-
-  {
-    // Note that we have an entry, and entries can be deleted only during GC,
-    // so we cannot allow GC to occur while we're holding this entry.
-    // We're using a NoSafepointVerifier to catch any place where we
-    // might potentially do a GC at all.
-    // Dictionary::do_unloading() asserts that classes in SD are only
-    // unloaded at a safepoint. Anonymous classes are not in SD.
-    NoSafepointVerifier nosafepoint;
-    return dictionary()->find(d_index, d_hash, class_name, loader_data,
-                              protection_domain, THREAD);
-  }
+  Dictionary* dictionary = loader_data->dictionary();
+  unsigned int d_hash = dictionary->compute_hash(class_name);
+  int d_index = dictionary->hash_to_index(d_hash);
+  return dictionary->find(d_index, d_hash, class_name,
+                          protection_domain);
 }
 
 
@@ -1035,7 +1013,6 @@
     guarantee(host_klass->class_loader() == class_loader(), "should be the same");
     guarantee(!DumpSharedSpaces, "must not create anonymous classes when dumping");
     loader_data = ClassLoaderData::anonymous_class_loader_data(class_loader(), CHECK_NULL);
-    loader_data->record_dependency(host_klass, CHECK_NULL);
   } else {
     loader_data = ClassLoaderData::class_loader_data(class_loader());
   }
@@ -1066,7 +1043,7 @@
       // deoptimizations.
       add_to_hierarchy(k, CHECK_NULL); // No exception, but can block
 
-      // But, do not add to system dictionary.
+      // But, do not add to dictionary.
 
       // compiled code dependencies need to be validated anyway
       notice_modification();
@@ -1189,9 +1166,10 @@
 #if INCLUDE_CDS
 void SystemDictionary::set_shared_dictionary(HashtableBucket<mtClass>* t, int length,
                                              int number_of_entries) {
-  assert(length == _nof_buckets * sizeof(HashtableBucket<mtClass>),
+  assert(length == _shared_dictionary_size * sizeof(HashtableBucket<mtClass>),
          "bad shared dictionary size.");
-  _shared_dictionary = new Dictionary(_nof_buckets, t, number_of_entries);
+  _shared_dictionary = new Dictionary(ClassLoaderData::the_null_class_loader_data(),
+                                      _shared_dictionary_size, t, number_of_entries);
 }
 
 
@@ -1200,7 +1178,7 @@
 
 InstanceKlass* SystemDictionary::find_shared_class(Symbol* class_name) {
   if (shared_dictionary() != NULL) {
-    unsigned int d_hash = shared_dictionary()->compute_hash(class_name, NULL);
+    unsigned int d_hash = shared_dictionary()->compute_hash(class_name);
     int d_index = shared_dictionary()->hash_to_index(d_hash);
 
     return shared_dictionary()->find_shared_class(d_index, d_hash, class_name);
@@ -1626,8 +1604,9 @@
   // Parallel classloaders will call find_or_define_instance_class
   // which will require a token to perform the define class
   Symbol*  name_h = k->name();
-  unsigned int d_hash = dictionary()->compute_hash(name_h, loader_data);
-  int d_index = dictionary()->hash_to_index(d_hash);
+  Dictionary* dictionary = loader_data->dictionary();
+  unsigned int d_hash = dictionary->compute_hash(name_h);
+  int d_index = dictionary->hash_to_index(d_hash);
   check_constraints(d_index, d_hash, k, class_loader_h, true, CHECK);
 
   // Register class just loaded with class loader (placed in Vector)
@@ -1645,7 +1624,7 @@
 
   // Add the new class. We need recompile lock during update of CHA.
   {
-    unsigned int p_hash = placeholders()->compute_hash(name_h, loader_data);
+    unsigned int p_hash = placeholders()->compute_hash(name_h);
     int p_index = placeholders()->hash_to_index(p_hash);
 
     MutexLocker mu_r(Compile_lock, THREAD);
@@ -1695,12 +1674,13 @@
 
   Symbol*  name_h = k->name(); // passed in class_name may be null
   ClassLoaderData* loader_data = class_loader_data(class_loader);
+  Dictionary* dictionary = loader_data->dictionary();
 
-  unsigned int d_hash = dictionary()->compute_hash(name_h, loader_data);
-  int d_index = dictionary()->hash_to_index(d_hash);
+  unsigned int d_hash = dictionary->compute_hash(name_h);
+  int d_index = dictionary->hash_to_index(d_hash);
 
   // Hold SD lock around find_class and placeholder creation for DEFINE_CLASS
-  unsigned int p_hash = placeholders()->compute_hash(name_h, loader_data);
+  unsigned int p_hash = placeholders()->compute_hash(name_h);
   int p_index = placeholders()->hash_to_index(p_hash);
   PlaceholderEntry* probe;
 
@@ -1708,7 +1688,7 @@
     MutexLocker mu(SystemDictionary_lock, THREAD);
     // First check if class already defined
     if (UnsyncloadClass || (is_parallelDefine(class_loader))) {
-      InstanceKlass* check = find_class(d_index, d_hash, name_h, loader_data);
+      InstanceKlass* check = find_class(d_index, d_hash, name_h, dictionary);
       if (check != NULL) {
         return check;
       }
@@ -1730,7 +1710,7 @@
         placeholders()->find_and_remove(p_index, p_hash, name_h, loader_data, PlaceholderTable::DEFINE_CLASS, THREAD);
         SystemDictionary_lock->notify_all();
 #ifdef ASSERT
-        InstanceKlass* check = find_class(d_index, d_hash, name_h, loader_data);
+        InstanceKlass* check = find_class(d_index, d_hash, name_h, dictionary);
         assert(check != NULL, "definer missed recording success");
 #endif
         return probe->instance_klass();
@@ -1769,6 +1749,7 @@
 
   return k;
 }
+
 Handle SystemDictionary::compute_loader_lock_object(Handle class_loader, TRAPS) {
   // If class_loader is NULL we synchronize on _system_loader_lock_obj
   if (class_loader.is_null()) {
@@ -1806,12 +1787,9 @@
 
 InstanceKlass* SystemDictionary::find_class(int index, unsigned int hash,
                                             Symbol* class_name,
-                                            ClassLoaderData* loader_data) {
+                                            Dictionary* dictionary) {
   assert_locked_or_safepoint(SystemDictionary_lock);
-  assert (index == dictionary()->index_for(class_name, loader_data),
-          "incorrect index?");
-
-  return dictionary()->find_class(index, hash, class_name, loader_data);
+  return dictionary->find_class(index, hash, class_name);
 }
 
 
@@ -1819,14 +1797,17 @@
 Symbol* SystemDictionary::find_placeholder(Symbol* class_name,
                                            ClassLoaderData* loader_data) {
   assert_locked_or_safepoint(SystemDictionary_lock);
-  unsigned int p_hash = placeholders()->compute_hash(class_name, loader_data);
+  unsigned int p_hash = placeholders()->compute_hash(class_name);
   int p_index = placeholders()->hash_to_index(p_hash);
   return placeholders()->find_entry(p_index, p_hash, class_name, loader_data);
 }
 
 
 // Used for assertions and verification only
+// Precalculating the hash and index is an optimization because there are many lookups
+// before adding the class.
 InstanceKlass* SystemDictionary::find_class(Symbol* class_name, ClassLoaderData* loader_data) {
+  assert_locked_or_safepoint(SystemDictionary_lock);
   #ifndef ASSERT
   guarantee(VerifyBeforeGC      ||
             VerifyDuringGC      ||
@@ -1834,18 +1815,11 @@
             VerifyDuringStartup ||
             VerifyAfterGC, "too expensive");
   #endif
-  assert_locked_or_safepoint(SystemDictionary_lock);
 
-  // First look in the loaded class array
-  unsigned int d_hash = dictionary()->compute_hash(class_name, loader_data);
-  int d_index = dictionary()->hash_to_index(d_hash);
-  return find_class(d_index, d_hash, class_name, loader_data);
-}
-
-
-// Get the next class in the dictionary.
-Klass* SystemDictionary::try_get_next_class() {
-  return dictionary()->try_get_next_class();
+  Dictionary* dictionary = loader_data->dictionary();
+  unsigned int d_hash = dictionary->compute_hash(class_name);
+  int d_index = dictionary->hash_to_index(d_hash);
+  return find_class(d_index, d_hash, class_name, dictionary);
 }
 
 
@@ -1872,33 +1846,10 @@
 // ----------------------------------------------------------------------------
 // GC support
 
-// Following roots during mark-sweep is separated in two phases.
-//
-// The first phase follows preloaded classes and all other system
-// classes, since these will never get unloaded anyway.
-//
-// The second phase removes (unloads) unreachable classes from the
-// system dictionary and follows the remaining classes' contents.
-
 void SystemDictionary::always_strong_oops_do(OopClosure* blk) {
   roots_oops_do(blk, NULL);
 }
 
-// Calculate a "good" systemdictionary size based
-// on predicted or current loaded classes count
-int SystemDictionary::calculate_systemdictionary_size(int classcount) {
-  int newsize = _old_default_sdsize;
-  if ((classcount > 0)  && !DumpSharedSpaces) {
-    int desiredsize = classcount/_average_depth_goal;
-    for (newsize = _primelist[_sdgeneration]; _sdgeneration < _prime_array_size -1;
-         newsize = _primelist[++_sdgeneration]) {
-      if (desiredsize <=  newsize) {
-        break;
-      }
-    }
-  }
-  return newsize;
-}
 
 #ifdef ASSERT
 class VerifySDReachableAndLiveClosure : public OopClosure {
@@ -1907,7 +1858,7 @@
 
   template <class T> void do_oop_work(T* p) {
     oop obj = oopDesc::load_decode_heap_oop(p);
-    guarantee(_is_alive->do_object_b(obj), "Oop in system dictionary must be live");
+    guarantee(_is_alive->do_object_b(obj), "Oop in protection domain cache table must be live");
   }
 
 public:
@@ -1936,20 +1887,20 @@
 
   if (unloading_occurred) {
     GCTraceTime(Debug, gc, phases) t("Dictionary", gc_timer);
-    dictionary()->do_unloading();
     constraints()->purge_loader_constraints();
     resolution_errors()->purge_resolution_errors();
   }
 
   {
     GCTraceTime(Debug, gc, phases) t("ProtectionDomainCacheTable", gc_timer);
-    // Oops referenced by the system dictionary may get unreachable independently
+    // Oops referenced by the protection domain cache table may get unreachable independently
     // of the class loader (eg. cached protection domain oops). So we need to
-    // explicitly unlink them here instead of in Dictionary::do_unloading.
-    dictionary()->unlink(is_alive);
+    // explicitly unlink them here.
+    _pd_cache_table->unlink(is_alive);
+
 #ifdef ASSERT
     VerifySDReachableAndLiveClosure cl(is_alive);
-    dictionary()->oops_do(&cl);
+    _pd_cache_table->oops_do(&cl);
 #endif
   }
 
@@ -1966,8 +1917,16 @@
   strong->do_oop(&_system_loader_lock_obj);
   CDS_ONLY(SystemDictionaryShared::roots_oops_do(strong);)
 
-  // Adjust dictionary
-  dictionary()->roots_oops_do(strong, weak);
+  // 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);
+   }
+  }
 
   // Visit extra methods
   invoke_method_table()->oops_do(strong);
@@ -1982,8 +1941,9 @@
   f->do_oop(&_system_loader_lock_obj);
   CDS_ONLY(SystemDictionaryShared::oops_do(f);)
 
-  // Adjust dictionary
-  dictionary()->oops_do(f);
+  // Only the protection domain oops contain references into the heap. Iterate
+  // over all of them.
+  _pd_cache_table->oops_do(f);
 
   // Visit extra methods
   invoke_method_table()->oops_do(f);
@@ -1991,25 +1951,6 @@
   ResolvedMethodTable::oops_do(f);
 }
 
-// Just the classes from defining class loaders
-// Don't iterate over placeholders
-void SystemDictionary::classes_do(void f(Klass*)) {
-  dictionary()->classes_do(f);
-}
-
-// Added for initialize_itable_for_klass
-//   Just the classes from defining class loaders
-// Don't iterate over placeholders
-void SystemDictionary::classes_do(void f(Klass*, TRAPS), TRAPS) {
-  dictionary()->classes_do(f, CHECK);
-}
-
-//   All classes, and their class loaders
-// Don't iterate over placeholders
-void SystemDictionary::classes_do(void f(Klass*, ClassLoaderData*)) {
-  dictionary()->classes_do(f);
-}
-
 void SystemDictionary::methods_do(void f(Method*)) {
   // Walk methods in loaded classes
   ClassLoaderDataGraph::methods_do(f);
@@ -2018,7 +1959,7 @@
 }
 
 void SystemDictionary::remove_classes_in_error_state() {
-  dictionary()->remove_classes_in_error_state();
+  ClassLoaderData::the_null_class_loader_data()->dictionary()->remove_classes_in_error_state();
 }
 
 // ----------------------------------------------------------------------------
@@ -2042,15 +1983,12 @@
 
 void SystemDictionary::initialize(TRAPS) {
   // Allocate arrays
-  assert(dictionary() == NULL,
-         "SystemDictionary should only be initialized once");
-  _sdgeneration        = 0;
-  _dictionary          = new Dictionary(calculate_systemdictionary_size(PredictedLoadedClassCount));
-  _placeholders        = new PlaceholderTable(_nof_buckets);
+  _placeholders        = new PlaceholderTable(_placeholder_table_size);
   _number_of_modifications = 0;
   _loader_constraints  = new LoaderConstraintTable(_loader_constraint_size);
   _resolution_errors   = new ResolutionErrorTable(_resolution_error_size);
   _invoke_method_table = new SymbolPropertyTable(_invoke_method_size);
+  _pd_cache_table = new ProtectionDomainCacheTable(defaultProtectionDomainCacheSize);
 
   // Allocate private object used as system class loader lock
   _system_loader_lock_obj = oopFactory::new_intArray(0, CHECK);
@@ -2204,9 +2142,9 @@
 // Constraints on class loaders. The details of the algorithm can be
 // found in the OOPSLA'98 paper "Dynamic Class Loading in the Java
 // Virtual Machine" by Sheng Liang and Gilad Bracha.  The basic idea is
-// that the system dictionary needs to maintain a set of contraints that
+// that the dictionary needs to maintain a set of contraints that
 // must be satisfied by all classes in the dictionary.
-// if defining is true, then LinkageError if already in systemDictionary
+// if defining is true, then LinkageError if already in dictionary
 // if initiating loader, then ok if InstanceKlass matches existing entry
 
 void SystemDictionary::check_constraints(int d_index, unsigned int d_hash,
@@ -2221,12 +2159,12 @@
 
     MutexLocker mu(SystemDictionary_lock, THREAD);
 
-    InstanceKlass* check = find_class(d_index, d_hash, name, loader_data);
+    InstanceKlass* check = find_class(d_index, d_hash, name, loader_data->dictionary());
     if (check != NULL) {
       // if different InstanceKlass - duplicate class definition,
       // else - ok, class loaded by a different thread in parallel,
       // we should only have found it if it was done loading and ok to use
-      // system dictionary only holds instance classes, placeholders
+      // dictionary only holds instance classes, placeholders
       // also holds array classes
 
       assert(check->is_instance_klass(), "noninstance in systemdictionary");
@@ -2267,7 +2205,7 @@
 }
 
 
-// Update system dictionary - done after check_constraint and add_to_hierachy
+// Update class loader data dictionary - done after check_constraint and add_to_hierachy
 // have been called.
 void SystemDictionary::update_dictionary(int d_index, unsigned int d_hash,
                                          int p_index, unsigned int p_hash,
@@ -2280,40 +2218,41 @@
   ClassLoaderData *loader_data = class_loader_data(class_loader);
 
   {
-  MutexLocker mu1(SystemDictionary_lock, THREAD);
+    MutexLocker mu1(SystemDictionary_lock, THREAD);
 
-  // See whether biased locking is enabled and if so set it for this
-  // klass.
-  // Note that this must be done past the last potential blocking
-  // point / safepoint. We enable biased locking lazily using a
-  // VM_Operation to iterate the SystemDictionary and installing the
-  // biasable mark word into each InstanceKlass's prototype header.
-  // To avoid race conditions where we accidentally miss enabling the
-  // optimization for one class in the process of being added to the
-  // dictionary, we must not safepoint after the test of
-  // BiasedLocking::enabled().
-  if (UseBiasedLocking && BiasedLocking::enabled()) {
-    // Set biased locking bit for all loaded classes; it will be
-    // cleared if revocation occurs too often for this type
-    // NOTE that we must only do this when the class is initally
-    // defined, not each time it is referenced from a new class loader
-    if (k->class_loader() == class_loader()) {
-      k->set_prototype_header(markOopDesc::biased_locking_prototype());
+    // See whether biased locking is enabled and if so set it for this
+    // klass.
+    // Note that this must be done past the last potential blocking
+    // point / safepoint. We enable biased locking lazily using a
+    // VM_Operation to iterate the SystemDictionary and installing the
+    // biasable mark word into each InstanceKlass's prototype header.
+    // To avoid race conditions where we accidentally miss enabling the
+    // optimization for one class in the process of being added to the
+    // dictionary, we must not safepoint after the test of
+    // BiasedLocking::enabled().
+    if (UseBiasedLocking && BiasedLocking::enabled()) {
+      // Set biased locking bit for all loaded classes; it will be
+      // cleared if revocation occurs too often for this type
+      // NOTE that we must only do this when the class is initally
+      // defined, not each time it is referenced from a new class loader
+      if (k->class_loader() == class_loader()) {
+        k->set_prototype_header(markOopDesc::biased_locking_prototype());
+      }
     }
-  }
 
-  // Make a new system dictionary entry.
-  InstanceKlass* sd_check = find_class(d_index, d_hash, name, loader_data);
-  if (sd_check == NULL) {
-    dictionary()->add_klass(name, loader_data, k);
-    notice_modification();
-  }
-#ifdef ASSERT
-  sd_check = find_class(d_index, d_hash, name, loader_data);
-  assert (sd_check != NULL, "should have entry in system dictionary");
-  // Note: there may be a placeholder entry: for circularity testing
-  // or for parallel defines
-#endif
+    // Make a new dictionary entry.
+    Dictionary* dictionary = loader_data->dictionary();
+    InstanceKlass* sd_check = find_class(d_index, d_hash, name, dictionary);
+    if (sd_check == NULL) {
+      dictionary->add_klass(d_index, d_hash, name, k);
+      notice_modification();
+    }
+  #ifdef ASSERT
+    sd_check = find_class(d_index, d_hash, name, dictionary);
+    assert (sd_check != NULL, "should have entry in dictionary");
+    // Note: there may be a placeholder entry: for circularity testing
+    // or for parallel defines
+  #endif
     SystemDictionary_lock->notify_all();
   }
 }
@@ -2383,21 +2322,21 @@
       constraint_name = fd.object_key();
     }
   }
-  unsigned int d_hash1 = dictionary()->compute_hash(constraint_name, loader_data1);
-  int d_index1 = dictionary()->hash_to_index(d_hash1);
 
-  unsigned int d_hash2 = dictionary()->compute_hash(constraint_name, loader_data2);
-  int d_index2 = dictionary()->hash_to_index(d_hash2);
-  {
-  MutexLocker mu_s(SystemDictionary_lock, THREAD);
+  Dictionary* dictionary1 = loader_data1->dictionary();
+  unsigned int d_hash1 = dictionary1->compute_hash(constraint_name);
+  int d_index1 = dictionary1->hash_to_index(d_hash1);
 
-  // Better never do a GC while we're holding these oops
-  NoSafepointVerifier nosafepoint;
+  Dictionary* dictionary2 = loader_data2->dictionary();
+  unsigned int d_hash2 = dictionary2->compute_hash(constraint_name);
+  int d_index2 = dictionary2->hash_to_index(d_hash2);
 
-  InstanceKlass* klass1 = find_class(d_index1, d_hash1, constraint_name, loader_data1);
-  InstanceKlass* klass2 = find_class(d_index2, d_hash2, constraint_name, loader_data2);
-  return constraints()->add_entry(constraint_name, klass1, class_loader1,
-                                  klass2, class_loader2);
+  {
+    MutexLocker mu_s(SystemDictionary_lock, THREAD);
+    InstanceKlass* klass1 = find_class(d_index1, d_hash1, constraint_name, dictionary1);
+    InstanceKlass* klass2 = find_class(d_index2, d_hash2, constraint_name, dictionary2);
+    return constraints()->add_entry(constraint_name, klass1, class_loader1,
+                                    klass2, class_loader2);
   }
 }
 
@@ -2847,64 +2786,73 @@
   return unpack_method_and_appendix(mname, caller, appendix_box, appendix_result, THREAD);
 }
 
-// Since the identity hash code for symbols changes when the symbols are
-// moved from the regular perm gen (hash in the mark word) to the shared
-// spaces (hash is the address), the classes loaded into the dictionary
-// may be in the wrong buckets.
+// Protection domain cache table handling
+
+ProtectionDomainCacheEntry* SystemDictionary::cache_get(Handle protection_domain) {
+  return _pd_cache_table->get(protection_domain);
+}
+
 
 void SystemDictionary::reorder_dictionary() {
-  dictionary()->reorder_dictionary();
+  ClassLoaderData::the_null_class_loader_data()->dictionary()->reorder_dictionary();
 }
 
 
 void SystemDictionary::copy_buckets(char** top, char* end) {
-  dictionary()->copy_buckets(top, end);
+  ClassLoaderData::the_null_class_loader_data()->dictionary()->copy_buckets(top, end);
 }
 
 
 void SystemDictionary::copy_table(char** top, char* end) {
-  dictionary()->copy_table(top, end);
+  ClassLoaderData::the_null_class_loader_data()->dictionary()->copy_table(top, end);
 }
 
-int SystemDictionary::number_of_classes() {
-  return dictionary()->number_of_entries();
-}
-
-
 // ----------------------------------------------------------------------------
 void SystemDictionary::print_shared(bool details) {
   shared_dictionary()->print(details);
 }
 
 void SystemDictionary::print(bool details) {
-  dictionary()->print(details);
+  if (shared_dictionary() != NULL) {
+    tty->print_cr("Shared Dictionary");
+    shared_dictionary()->print(details);
+  }
+
+  GCMutexLocker mu(SystemDictionary_lock);
+
+  ClassLoaderDataGraph::print_dictionary(details);
 
   // Placeholders
-  GCMutexLocker mu(SystemDictionary_lock);
   placeholders()->print();
+  tty->cr();
 
   // loader constraints - print under SD_lock
   constraints()->print();
+  tty->cr();
+
+  _pd_cache_table->print();
+  tty->cr();
 }
 
 
 void SystemDictionary::verify() {
-  guarantee(dictionary() != NULL, "Verify of system dictionary failed");
   guarantee(constraints() != NULL,
             "Verify of loader constraints failed");
-  guarantee(dictionary()->number_of_entries() >= 0 &&
-            placeholders()->number_of_entries() >= 0,
-            "Verify of system dictionary failed");
+  guarantee(placeholders()->number_of_entries() >= 0,
+            "Verify of placeholders failed");
+
+  GCMutexLocker mu(SystemDictionary_lock);
 
   // Verify dictionary
-  dictionary()->verify();
+  ClassLoaderDataGraph::verify_dictionary();
 
-  GCMutexLocker mu(SystemDictionary_lock);
   placeholders()->verify();
 
   // Verify constraint table
   guarantee(constraints() != NULL, "Verify of loader constraints failed");
-  constraints()->verify(dictionary(), placeholders());
+  constraints()->verify(placeholders());
+
+  _pd_cache_table->verify();
 }
 
 // caller needs ResourceMark
--- a/hotspot/src/share/vm/classfile/systemDictionary.hpp	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp	Fri Jul 28 10:48:35 2017 -0400
@@ -35,31 +35,34 @@
 #include "utilities/hashtable.hpp"
 #include "utilities/hashtable.inline.hpp"
 
-// The system dictionary stores all loaded classes and maps:
+// The dictionary in each ClassLoaderData stores all loaded classes, either
+// initiatied by its class loader or defined by its class loader:
 //
-//   [class name,class loader] -> class   i.e.  [Symbol*,oop] -> Klass*
+//   class loader -> ClassLoaderData -> [class, protection domain set]
 //
 // Classes are loaded lazily. The default VM class loader is
 // represented as NULL.
 
-// The underlying data structure is an open hash table with a fixed number
-// of buckets. During loading the loader object is locked, (for the VM loader
-// a private lock object is used). Class loading can thus be done concurrently,
-// but only by different loaders.
+// The underlying data structure is an open hash table (Dictionary) per
+// ClassLoaderData with a fixed number of buckets. During loading the
+// class loader object is locked, (for the VM loader a private lock object is used).
+// The global SystemDictionary_lock is held for all additions into the ClassLoaderData
+// dictionaries.  TODO: fix lock granularity so that class loading can
+// be done concurrently, but only by different loaders.
 //
 // During loading a placeholder (name, loader) is temporarily placed in
 // a side data structure, and is used to detect ClassCircularityErrors
 // and to perform verification during GC.  A GC can occur in the midst
 // of class loading, as we call out to Java, have to take locks, etc.
 //
-// When class loading is finished, a new entry is added to the system
-// dictionary and the place holder is removed. Note that the protection
-// domain field of the system dictionary has not yet been filled in when
-// the "real" system dictionary entry is created.
+// When class loading is finished, a new entry is added to the dictionary
+// of the class loader and the placeholder is removed. Note that the protection
+// domain field of the dictionary entry has not yet been filled in when
+// the "real" dictionary entry is created.
 //
 // Clients of this class who are interested in finding if a class has
 // been completely loaded -- not classes in the process of being loaded --
-// can read the SystemDictionary unlocked. This is safe because
+// can read the dictionary unlocked. This is safe because
 //    - entries are only deleted at safepoints
 //    - readers cannot come to a safepoint while actively examining
 //         an entry  (an entry cannot be deleted from under a reader)
@@ -78,6 +81,8 @@
 template <MEMFLAGS F> class HashtableBucket;
 class ResolutionErrorTable;
 class SymbolPropertyTable;
+class ProtectionDomainCacheTable;
+class ProtectionDomainCacheEntry;
 class GCTimer;
 
 // Certain classes are preloaded, such as java.lang.Object and java.lang.String.
@@ -281,7 +286,7 @@
                                       bool is_superclass,
                                       TRAPS);
 
-  // Parse new stream. This won't update the system dictionary or
+  // Parse new stream. This won't update the dictionary or
   // class hierarchy, simply parse the stream. Used by JVMTI RedefineClasses.
   // Also used by Unsafe_DefineAnonymousClass
   static InstanceKlass* parse_stream(Symbol* class_name,
@@ -348,14 +353,6 @@
                                                            Handle class_loader,
                                                            TRAPS);
 
-  // Iterate over all klasses in dictionary
-  // Just the classes from defining class loaders
-  static void classes_do(void f(Klass*));
-  // Added for initialize_itable_for_klass to handle exceptions
-  static void classes_do(void f(Klass*, TRAPS), TRAPS);
-  // All classes, and their class loaders, including initiating class loaders
-  static void classes_do(void f(Klass*, ClassLoaderData*));
-
   // Iterate over all methods in all klasses
   static void methods_do(void f(Method*));
 
@@ -394,11 +391,6 @@
   static void print(bool details = true);
   static void print_shared(bool details = true);
 
-  // Number of contained klasses
-  // This is both fully loaded classes and classes in the process
-  // of being loaded
-  static int number_of_classes();
-
   // Monotonically increasing counter which grows as classes are
   // loaded or modifications such as hot-swapping or setting/removing
   // of breakpoints are performed
@@ -558,28 +550,21 @@
   static Symbol* find_resolution_error(const constantPoolHandle& pool, int which,
                                        Symbol** message);
 
+
+  static ProtectionDomainCacheEntry* cache_get(Handle protection_domain);
+
  protected:
 
   enum Constants {
     _loader_constraint_size = 107,                     // number of entries in constraint table
     _resolution_error_size  = 107,                     // number of entries in resolution error table
     _invoke_method_size     = 139,                     // number of entries in invoke method table
-    _nof_buckets            = 1009,                    // number of buckets in hash table for placeholders
-    _old_default_sdsize     = 1009,                    // backward compat for system dictionary size
-    _prime_array_size       = 8,                       // array of primes for system dictionary size
-    _average_depth_goal     = 3                        // goal for lookup length
+    _shared_dictionary_size = 1009,                    // number of entries in shared dictionary
+    _placeholder_table_size = 1009                     // number of entries in hash table for placeholders
   };
 
 
-  // Static variables
-
-  // hashtable sizes for system dictionary to allow growth
-  // prime numbers for system dictionary size
-  static int                     _sdgeneration;
-  static const int               _primelist[_prime_array_size];
-
-  // Hashtable holding loaded classes.
-  static Dictionary*            _dictionary;
+  // Static tables owned by the SystemDictionary
 
   // Hashtable holding placeholders for classes being loaded.
   static PlaceholderTable*       _placeholders;
@@ -588,7 +573,7 @@
   static Dictionary*             _shared_dictionary;
 
   // Monotonically increasing counter which grows with
-  // _number_of_classes as well as hot-swapping and breakpoint setting
+  // loading classes as well as hot-swapping and breakpoint setting
   // and removal.
   static int                     _number_of_modifications;
 
@@ -604,10 +589,8 @@
   // Invoke methods (JSR 292)
   static SymbolPropertyTable*    _invoke_method_table;
 
-public:
-  // for VM_CounterDecay iteration support
-  friend class CounterDecay;
-  static Klass* try_get_next_class();
+  // ProtectionDomain cache
+  static ProtectionDomainCacheTable*   _pd_cache_table;
 
 protected:
   static void validate_protection_domain(InstanceKlass* klass,
@@ -616,7 +599,6 @@
 
   friend class VM_PopulateDumpSharedSpace;
   friend class TraversePlaceholdersClosure;
-  static Dictionary*         dictionary() { return _dictionary; }
   static Dictionary*         shared_dictionary() { return _shared_dictionary; }
   static PlaceholderTable*   placeholders() { return _placeholders; }
   static LoaderConstraintTable* constraints() { return _loader_constraints; }
@@ -666,7 +648,7 @@
 
   // Basic find on loaded classes
   static InstanceKlass* find_class(int index, unsigned int hash,
-                                   Symbol* name, ClassLoaderData* loader_data);
+                                   Symbol* name, Dictionary* dictionary);
   static InstanceKlass* find_class(Symbol* class_name, ClassLoaderData* loader_data);
 
   // Basic find on classes in the midst of being loaded
--- a/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp	Fri Jul 28 10:48:35 2017 -0400
@@ -69,6 +69,7 @@
   }
 
   static void init_shared_dictionary_entry(Klass* k, DictionaryEntry* entry) {}
+  static bool is_builtin(DictionaryEntry* entry) { return true; }
 
   static InstanceKlass* lookup_from_stream(Symbol* class_name,
                                            Handle class_loader,
--- a/hotspot/src/share/vm/memory/universe.cpp	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/share/vm/memory/universe.cpp	Fri Jul 28 10:48:35 2017 -0400
@@ -548,14 +548,13 @@
 }
 
 
-void initialize_itable_for_klass(Klass* k, TRAPS) {
-  InstanceKlass::cast(k)->itable().initialize_itable(false, CHECK);
+void initialize_itable_for_klass(InstanceKlass* k, TRAPS) {
+  k->itable().initialize_itable(false, CHECK);
 }
 
 
 void Universe::reinitialize_itables(TRAPS) {
-  SystemDictionary::classes_do(initialize_itable_for_klass, CHECK);
-
+  ClassLoaderDataGraph::dictionary_classes_do(initialize_itable_for_klass, CHECK);
 }
 
 
--- a/hotspot/src/share/vm/oops/klassVtable.cpp	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/share/vm/oops/klassVtable.cpp	Fri Jul 28 10:48:35 2017 -0400
@@ -1569,7 +1569,7 @@
   }
 
   static void compute() {
-    SystemDictionary::classes_do(do_class);
+    ClassLoaderDataGraph::classes_do(do_class);
     fixed  = no_klasses * oopSize;      // vtable length
     // filler size is a conservative approximation
     filler = oopSize * (no_klasses - no_instance_klasses) * (sizeof(InstanceKlass) - sizeof(ArrayKlass) - 1);
--- a/hotspot/src/share/vm/prims/jvmtiGetLoadedClasses.cpp	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/share/vm/prims/jvmtiGetLoadedClasses.cpp	Fri Jul 28 10:48:35 2017 -0400
@@ -70,7 +70,7 @@
 
 // The closure for GetClassLoaderClasses
 class JvmtiGetLoadedClassesClosure : public StackObj {
-  // Since the SystemDictionary::classes_do callback
+  // Since the ClassLoaderDataGraph::dictionary_all_entries_do callback
   // doesn't pass a closureData pointer,
   // we use a thread-local slot to hold a pointer to
   // a stack allocated instance of this structure.
@@ -203,7 +203,7 @@
     }
   }
 
-  static void increment_with_loader(Klass* k, ClassLoaderData* loader_data) {
+  static void increment_with_loader(InstanceKlass* k, ClassLoaderData* loader_data) {
     JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this();
     oop class_loader = loader_data->class_loader();
     if (class_loader == JNIHandles::resolve(that->get_initiatingLoader())) {
@@ -213,7 +213,7 @@
     }
   }
 
-  static void add_with_loader(Klass* k, ClassLoaderData* loader_data) {
+  static void add_with_loader(InstanceKlass* k, ClassLoaderData* loader_data) {
     JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this();
     if (that->available()) {
       oop class_loader = loader_data->class_loader();
@@ -285,26 +285,26 @@
 jvmtiError
 JvmtiGetLoadedClasses::getClassLoaderClasses(JvmtiEnv *env, jobject initiatingLoader,
                                              jint* classCountPtr, jclass** classesPtr) {
-  // Since SystemDictionary::classes_do only takes a function pointer
+  // Since ClassLoaderDataGraph::dictionary_all_entries_do only takes a function pointer
   // and doesn't call back with a closure data pointer,
   // we can only pass static methods.
   JvmtiGetLoadedClassesClosure closure(initiatingLoader);
   {
     // To get a consistent list of classes we need MultiArray_lock to ensure
     // array classes aren't created, and SystemDictionary_lock to ensure that
-    // classes aren't added to the system dictionary,
+    // classes aren't added to the class loader data dictionaries.
     MutexLocker ma(MultiArray_lock);
     MutexLocker sd(SystemDictionary_lock);
-    // First, count the classes in the system dictionary which have this loader recorded
+    // First, count the classes in the class loader data dictionaries which have this loader recorded
     // as an initiating loader. For basic type arrays this information is not recorded
     // so GetClassLoaderClasses will return all of the basic type arrays. This is okay
     // because the defining loader for basic type arrays is always the boot class loader
     // and these classes are "visible" to all loaders.
-    SystemDictionary::classes_do(&JvmtiGetLoadedClassesClosure::increment_with_loader);
+    ClassLoaderDataGraph::dictionary_all_entries_do(&JvmtiGetLoadedClassesClosure::increment_with_loader);
     Universe::basic_type_classes_do(&JvmtiGetLoadedClassesClosure::increment_for_basic_type_arrays);
     // Next, fill in the classes
     closure.allocate();
-    SystemDictionary::classes_do(&JvmtiGetLoadedClassesClosure::add_with_loader);
+    ClassLoaderDataGraph::dictionary_all_entries_do(&JvmtiGetLoadedClassesClosure::add_with_loader);
     Universe::basic_type_classes_do(&JvmtiGetLoadedClassesClosure::add_for_basic_type_arrays);
     // Drop the SystemDictionary_lock, so the results could be wrong from here,
     // but we still have a snapshot.
--- a/hotspot/src/share/vm/runtime/biasedLocking.cpp	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/share/vm/runtime/biasedLocking.cpp	Fri Jul 28 10:48:35 2017 -0400
@@ -42,7 +42,7 @@
 static GrowableArray<Handle>*  _preserved_oop_stack  = NULL;
 static GrowableArray<markOop>* _preserved_mark_stack = NULL;
 
-static void enable_biased_locking(Klass* k) {
+static void enable_biased_locking(InstanceKlass* k) {
   k->set_prototype_header(markOopDesc::biased_locking_prototype());
 }
 
@@ -56,9 +56,9 @@
   bool is_cheap_allocated() const { return _is_cheap_allocated; }
 
   void doit() {
-    // Iterate the system dictionary enabling biased locking for all
-    // currently loaded classes
-    SystemDictionary::classes_do(enable_biased_locking);
+    // Iterate the class loader data dictionaries enabling biased locking for all
+    // currently loaded classes.
+    ClassLoaderDataGraph::dictionary_classes_do(enable_biased_locking);
     // Indicate that future instances should enable it as well
     _biased_locking_enabled = true;
 
--- a/hotspot/src/share/vm/runtime/compilationPolicy.cpp	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/share/vm/runtime/compilationPolicy.cpp	Fri Jul 28 10:48:35 2017 -0400
@@ -312,13 +312,13 @@
   // and hence GC's will not be going on, all Java mutators are suspended
   // at this point and hence SystemDictionary_lock is also not needed.
   assert(SafepointSynchronize::is_at_safepoint(), "can only be executed at a safepoint");
-  int nclasses = SystemDictionary::number_of_classes();
+  int nclasses = InstanceKlass::number_of_instance_classes();
   double classes_per_tick = nclasses * (CounterDecayMinIntervalLength * 1e-3 /
                                         CounterHalfLifeTime);
   for (int i = 0; i < classes_per_tick; i++) {
-    Klass* k = SystemDictionary::try_get_next_class();
-    if (k != NULL && k->is_instance_klass()) {
-      InstanceKlass::cast(k)->methods_do(do_method);
+    InstanceKlass* k = ClassLoaderDataGraph::try_get_next_class();
+    if (k != NULL) {
+      k->methods_do(do_method);
     }
   }
 }
--- a/hotspot/src/share/vm/runtime/memprofiler.cpp	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/share/vm/runtime/memprofiler.cpp	Fri Jul 28 10:48:35 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 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
@@ -120,7 +120,7 @@
   fprintf(_log_fp, "%6.1f,%5d,%5d," UINTX_FORMAT_W(6) "," UINTX_FORMAT_W(6) ",",
           os::elapsedTime(),
           Threads::number_of_threads(),
-          SystemDictionary::number_of_classes(),
+          InstanceKlass::number_of_instance_classes(),
           Universe::heap()->used() / K,
           Universe::heap()->capacity() / K);
 
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp	Fri Jul 28 10:48:35 2017 -0400
@@ -31,8 +31,6 @@
 #include "classfile/compactHashtable.hpp"
 #include "classfile/dictionary.hpp"
 #include "classfile/javaClasses.hpp"
-#include "classfile/loaderConstraints.hpp"
-#include "classfile/placeholders.hpp"
 #include "classfile/stringTable.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "code/codeBlob.hpp"
@@ -193,10 +191,8 @@
 typedef Hashtable<Symbol*, mtSymbol>          SymbolHashtable;
 typedef HashtableEntry<Symbol*, mtClass>      SymbolHashtableEntry;
 typedef Hashtable<oop, mtSymbol>              StringHashtable;
-typedef TwoOopHashtable<InstanceKlass*, mtClass> KlassTwoOopHashtable;
 typedef Hashtable<InstanceKlass*, mtClass>       KlassHashtable;
 typedef HashtableEntry<InstanceKlass*, mtClass>  KlassHashtableEntry;
-typedef TwoOopHashtable<Symbol*, mtClass>     SymbolTwoOopHashtable;
 typedef CompactHashtable<Symbol*, char>       SymbolCompactHashTable;
 typedef RehashableHashtable<Symbol*, mtSymbol>   RehashableSymbolHashtable;
 
@@ -250,7 +246,6 @@
   nonstatic_field(InstanceKlass,               _fields,                                       Array<u2>*)                            \
   nonstatic_field(InstanceKlass,               _java_fields_count,                            u2)                                    \
   nonstatic_field(InstanceKlass,               _constants,                                    ConstantPool*)                         \
-  nonstatic_field(InstanceKlass,               _class_loader_data,                            ClassLoaderData*)                      \
   nonstatic_field(InstanceKlass,               _source_file_name_index,                       u2)                                    \
   nonstatic_field(InstanceKlass,               _source_debug_extension,                       const char*)                           \
   nonstatic_field(InstanceKlass,               _inner_classes,                                Array<jushort>*)                       \
@@ -291,6 +286,7 @@
   nonstatic_field(Klass,                       _next_sibling,                                 Klass*)                                \
   nonstatic_field(Klass,                       _next_link,                                    Klass*)                                \
   nonstatic_field(Klass,                       _vtable_len,                                   int)                                   \
+  nonstatic_field(Klass,                       _class_loader_data,                            ClassLoaderData*)                      \
   nonstatic_field(vtableEntry,                 _method,                                       Method*)                               \
   nonstatic_field(MethodData,                  _size,                                         int)                                   \
   nonstatic_field(MethodData,                  _method,                                       Method*)                               \
@@ -607,46 +603,16 @@
   /* SystemDictionary */                                                                                                             \
   /********************/                                                                                                             \
                                                                                                                                      \
-     static_field(SystemDictionary,            _dictionary,                                   Dictionary*)                           \
-     static_field(SystemDictionary,            _placeholders,                                 PlaceholderTable*)                     \
      static_field(SystemDictionary,            _shared_dictionary,                            Dictionary*)                           \
      static_field(SystemDictionary,            _system_loader_lock_obj,                       oop)                                   \
-     static_field(SystemDictionary,            _loader_constraints,                           LoaderConstraintTable*)                \
      static_field(SystemDictionary,            WK_KLASS(Object_klass),                        InstanceKlass*)                        \
      static_field(SystemDictionary,            WK_KLASS(String_klass),                        InstanceKlass*)                        \
      static_field(SystemDictionary,            WK_KLASS(Class_klass),                         InstanceKlass*)                        \
-     static_field(SystemDictionary,            WK_KLASS(Cloneable_klass),                     InstanceKlass*)                        \
      static_field(SystemDictionary,            WK_KLASS(ClassLoader_klass),                   InstanceKlass*)                        \
-     static_field(SystemDictionary,            WK_KLASS(Serializable_klass),                  InstanceKlass*)                        \
      static_field(SystemDictionary,            WK_KLASS(System_klass),                        InstanceKlass*)                        \
-     static_field(SystemDictionary,            WK_KLASS(Throwable_klass),                     InstanceKlass*)                        \
-     static_field(SystemDictionary,            WK_KLASS(ThreadDeath_klass),                   InstanceKlass*)                        \
-     static_field(SystemDictionary,            WK_KLASS(Error_klass),                         InstanceKlass*)                        \
-     static_field(SystemDictionary,            WK_KLASS(Exception_klass),                     InstanceKlass*)                        \
-     static_field(SystemDictionary,            WK_KLASS(RuntimeException_klass),              InstanceKlass*)                        \
-     static_field(SystemDictionary,            WK_KLASS(ClassNotFoundException_klass),        InstanceKlass*)                        \
-     static_field(SystemDictionary,            WK_KLASS(NoClassDefFoundError_klass),          InstanceKlass*)                        \
-     static_field(SystemDictionary,            WK_KLASS(LinkageError_klass),                  InstanceKlass*)                        \
-     static_field(SystemDictionary,            WK_KLASS(ClassCastException_klass),            InstanceKlass*)                        \
-     static_field(SystemDictionary,            WK_KLASS(ArrayStoreException_klass),           InstanceKlass*)                        \
-     static_field(SystemDictionary,            WK_KLASS(VirtualMachineError_klass),           InstanceKlass*)                        \
-     static_field(SystemDictionary,            WK_KLASS(OutOfMemoryError_klass),              InstanceKlass*)                        \
-     static_field(SystemDictionary,            WK_KLASS(StackOverflowError_klass),            InstanceKlass*)                        \
-     static_field(SystemDictionary,            WK_KLASS(ProtectionDomain_klass),              InstanceKlass*)                        \
-     static_field(SystemDictionary,            WK_KLASS(AccessControlContext_klass),          InstanceKlass*)                        \
-     static_field(SystemDictionary,            WK_KLASS(SecureClassLoader_klass),             InstanceKlass*)                        \
-     static_field(SystemDictionary,            WK_KLASS(Reference_klass),                     InstanceKlass*)                        \
-     static_field(SystemDictionary,            WK_KLASS(SoftReference_klass),                 InstanceKlass*)                        \
-     static_field(SystemDictionary,            WK_KLASS(WeakReference_klass),                 InstanceKlass*)                        \
-     static_field(SystemDictionary,            WK_KLASS(FinalReference_klass),                InstanceKlass*)                        \
-     static_field(SystemDictionary,            WK_KLASS(PhantomReference_klass),              InstanceKlass*)                        \
-     static_field(SystemDictionary,            WK_KLASS(Finalizer_klass),                     InstanceKlass*)                        \
      static_field(SystemDictionary,            WK_KLASS(Thread_klass),                        InstanceKlass*)                        \
      static_field(SystemDictionary,            WK_KLASS(ThreadGroup_klass),                   InstanceKlass*)                        \
-     static_field(SystemDictionary,            WK_KLASS(Properties_klass),                    InstanceKlass*)                        \
-     static_field(SystemDictionary,            WK_KLASS(StringBuffer_klass),                  InstanceKlass*)                        \
      static_field(SystemDictionary,            WK_KLASS(MethodHandle_klass),                  InstanceKlass*)                        \
-     static_field(SystemDictionary,            _box_klasses[0],                               InstanceKlass*)                        \
      static_field(SystemDictionary,            _java_system_loader,                           oop)                                   \
                                                                                                                                      \
   /*************/                                                                                                                    \
@@ -681,42 +647,13 @@
   nonstatic_field(BasicHashtable<mtInternal>,  _entry_size,                                   int)                                   \
                                                                                                                                      \
   /*******************/                                                                                                              \
-  /* DictionaryEntry */                                                                                                              \
+  /* ClassLoaderData */                                                                                                              \
   /*******************/                                                                                                              \
-                                                                                                                                     \
-  nonstatic_field(DictionaryEntry,             _loader_data,                                  ClassLoaderData*)                      \
-  nonstatic_field(DictionaryEntry,             _pd_set,                                       ProtectionDomainEntry*)                \
-                                                                                                                                     \
-  /********************/                                                                                                             \
-                                                                                                                                     \
-  nonstatic_field(PlaceholderEntry,            _loader_data,                                  ClassLoaderData*)                      \
-                                                                                                                                     \
-  /**************************/                                                                                                       \
-  /* ProtectionDomainEntry  */                                                                                                       \
-  /**************************/                                                                                                       \
-                                                                                                                                     \
-  nonstatic_field(ProtectionDomainEntry,       _next,                                         ProtectionDomainEntry*)                \
-  nonstatic_field(ProtectionDomainEntry,       _pd_cache,                                     ProtectionDomainCacheEntry*)           \
-                                                                                                                                     \
-  /*******************************/                                                                                                  \
-  /* ProtectionDomainCacheEntry  */                                                                                                  \
-  /*******************************/                                                                                                  \
-                                                                                                                                     \
-  nonstatic_field(ProtectionDomainCacheEntry,  _literal,                                      oop)                                   \
-                                                                                                                                     \
-  /*************************/                                                                                                        \
-  /* LoaderConstraintEntry */                                                                                                        \
-  /*************************/                                                                                                        \
-                                                                                                                                     \
-  nonstatic_field(LoaderConstraintEntry,       _name,                                         Symbol*)                               \
-  nonstatic_field(LoaderConstraintEntry,       _num_loaders,                                  int)                                   \
-  nonstatic_field(LoaderConstraintEntry,       _max_loaders,                                  int)                                   \
-  nonstatic_field(LoaderConstraintEntry,       _loaders,                                      ClassLoaderData**)                     \
-                                                                                                                                     \
   nonstatic_field(ClassLoaderData,             _class_loader,                                 oop)                                   \
   nonstatic_field(ClassLoaderData,             _next,                                         ClassLoaderData*)                      \
   volatile_nonstatic_field(ClassLoaderData,    _klasses,                                      Klass*)                                \
   nonstatic_field(ClassLoaderData,             _is_anonymous,                                 bool)                                  \
+  volatile_nonstatic_field(ClassLoaderData,    _dictionary,                                   Dictionary*)                           \
                                                                                                                                      \
      static_field(ClassLoaderDataGraph,        _head,                                         ClassLoaderData*)                      \
                                                                                                                                      \
@@ -1610,20 +1547,13 @@
     declare_type(RehashableSymbolHashtable, BasicHashtable<mtSymbol>)     \
   declare_type(SymbolTable, SymbolHashtable)                              \
   declare_type(StringTable, StringHashtable)                              \
-    declare_type(LoaderConstraintTable, KlassHashtable)                   \
-    declare_type(KlassTwoOopHashtable, KlassHashtable)                    \
-    declare_type(Dictionary, KlassTwoOopHashtable)                        \
-    declare_type(PlaceholderTable, SymbolTwoOopHashtable)                 \
+    declare_type(Dictionary, KlassHashtable)                              \
   declare_toplevel_type(BasicHashtableEntry<mtInternal>)                  \
   declare_type(IntptrHashtableEntry, BasicHashtableEntry<mtInternal>)     \
     declare_type(DictionaryEntry, KlassHashtableEntry)                    \
-    declare_type(PlaceholderEntry, SymbolHashtableEntry)                  \
-    declare_type(LoaderConstraintEntry, KlassHashtableEntry)              \
   declare_toplevel_type(HashtableBucket<mtInternal>)                      \
   declare_toplevel_type(SystemDictionary)                                 \
   declare_toplevel_type(vmSymbols)                                        \
-  declare_toplevel_type(ProtectionDomainEntry)                            \
-  declare_toplevel_type(ProtectionDomainCacheEntry)                       \
                                                                           \
   declare_toplevel_type(GenericGrowableArray)                             \
   declare_toplevel_type(GrowableArray<int>)                               \
@@ -2355,12 +2285,6 @@
   declare_preprocessor_constant("PERFDATA_BIG_ENDIAN", PERFDATA_BIG_ENDIAN)       \
   declare_preprocessor_constant("PERFDATA_LITTLE_ENDIAN", PERFDATA_LITTLE_ENDIAN) \
                                                                           \
-  /***********************************/                                   \
-  /* LoaderConstraintTable constants */                                   \
-  /***********************************/                                   \
-                                                                          \
-  declare_constant(LoaderConstraintTable::_loader_constraint_size)        \
-  declare_constant(LoaderConstraintTable::_nof_buckets)                   \
                                                                           \
   /************************************************************/          \
   /* HotSpot specific JVM_ACC constants from global anon enum */          \
--- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp	Fri Jul 28 10:48:35 2017 -0400
@@ -417,10 +417,6 @@
 
 const int max_method_code_size = 64*K - 1;  // JVM spec, 2nd ed. section 4.8.1 (p.134)
 
-// Default ProtectionDomainCacheSize values
-
-const int defaultProtectionDomainCacheSize = NOT_LP64(137) LP64_ONLY(2017);
-
 //----------------------------------------------------------------------------------------------------
 // Default and minimum StringTableSize values
 
--- a/hotspot/src/share/vm/utilities/hashtable.cpp	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/share/vm/utilities/hashtable.cpp	Fri Jul 28 10:48:35 2017 -0400
@@ -84,6 +84,17 @@
   return entry;
 }
 
+// Version of hashtable entry allocation that allocates in the C heap directly.
+// The allocator in blocks is preferable but doesn't have free semantics.
+template <class T, MEMFLAGS F> HashtableEntry<T, F>* Hashtable<T, F>::allocate_new_entry(unsigned int hashValue, T obj) {
+  HashtableEntry<T, F>* entry = (HashtableEntry<T, F>*) NEW_C_HEAP_ARRAY(char, this->entry_size(), F);
+
+  entry->set_hash(hashValue);
+  entry->set_literal(obj);
+  entry->set_next(NULL);
+  return entry;
+}
+
 // Check to see if the hashtable is unbalanced.  The caller set a flag to
 // rehash at the next safepoint.  If this bucket is 60 times greater than the
 // expected average bucket length, it's an unbalanced hashtable.
@@ -357,6 +368,7 @@
 template class Hashtable<Klass*, mtClass>;
 template class Hashtable<InstanceKlass*, mtClass>;
 template class Hashtable<oop, mtClass>;
+template class Hashtable<Symbol*, mtModule>;
 #if defined(SOLARIS) || defined(CHECK_UNHANDLED_OOPS)
 template class Hashtable<oop, mtSymbol>;
 template class RehashableHashtable<oop, mtSymbol>;
--- a/hotspot/src/share/vm/utilities/hashtable.hpp	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/src/share/vm/utilities/hashtable.hpp	Fri Jul 28 10:48:35 2017 -0400
@@ -253,18 +253,20 @@
   // Debugging
   void print()               PRODUCT_RETURN;
 
-protected:
-
-  unsigned int compute_hash(Symbol* name) {
+  unsigned int compute_hash(const Symbol* name) const {
     return (unsigned int) name->identity_hash();
   }
 
-  int index_for(Symbol* name) {
+  int index_for(const Symbol* name) const {
     return this->hash_to_index(compute_hash(name));
   }
 
+protected:
+
   // Table entry management
   HashtableEntry<T, F>* new_entry(unsigned int hashValue, T obj);
+  // Don't create and use freelist of HashtableEntry.
+  HashtableEntry<T, F>* allocate_new_entry(unsigned int hashValue, T obj);
 
   // The following method is MT-safe and may be used with caution.
   HashtableEntry<T, F>* bucket(int i) const {
@@ -324,31 +326,4 @@
 template <class T, MEMFLAGS F> juint RehashableHashtable<T, F>::seed() { return _seed; };
 template <class T, MEMFLAGS F> bool  RehashableHashtable<T, F>::use_alternate_hashcode() { return _seed != 0; };
 
-// Versions of hashtable where two handles are used to compute the index.
-
-template <class T, MEMFLAGS F> class TwoOopHashtable : public Hashtable<T, F> {
-  friend class VMStructs;
-protected:
-  TwoOopHashtable(int table_size, int entry_size)
-    : Hashtable<T, F>(table_size, entry_size) {}
-
-  TwoOopHashtable(int table_size, int entry_size, HashtableBucket<F>* t,
-                  int number_of_entries)
-    : Hashtable<T, F>(table_size, entry_size, t, number_of_entries) {}
-
-public:
-  unsigned int compute_hash(const Symbol* name, const ClassLoaderData* loader_data) const {
-    unsigned int name_hash = name->identity_hash();
-    // loader is null with CDS
-    assert(loader_data != NULL || UseSharedSpaces || DumpSharedSpaces,
-           "only allowed with shared spaces");
-    unsigned int loader_hash = loader_data == NULL ? 0 : loader_data->identity_hash();
-    return name_hash ^ loader_hash;
-  }
-
-  int index_for(Symbol* name, ClassLoaderData* loader_data) {
-    return this->hash_to_index(compute_hash(name, loader_data));
-  }
-};
-
 #endif // SHARE_VM_UTILITIES_HASHTABLE_HPP
--- a/hotspot/test/runtime/NMT/CheckForProperDetailStackTrace.java	Thu Jul 27 17:47:57 2017 -0700
+++ b/hotspot/test/runtime/NMT/CheckForProperDetailStackTrace.java	Fri Jul 28 10:48:35 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -40,10 +40,10 @@
     /* The stack trace we look for by default. Note that :: has been replaced by .*
        to make sure it maches even if the symbol is not unmangled. */
     public static String stackTraceDefault =
+        ".*Hashtable.*allocate_new_entry.*\n" +
         ".*ModuleEntryTable.*new_entry.*\n" +
         ".*ModuleEntryTable.*locked_create_entry_or_null.*\n" +
-        ".*Modules.*define_module.*\n" +
-        ".*JVM_DefineModule.*\n";
+        ".*Modules.*define_module.*\n";
 
     /* The stack trace we look for on Solaris and Windows slowdebug builds. For some
        reason ALWAYSINLINE for AllocateHeap is ignored, so it appears in the stack strace. */