--- old/src/jdk.hotspot.agent/doc/jsdb.html 2017-07-18 22:50:40.732214321 -0400 +++ new/src/jdk.hotspot.agent/doc/jsdb.html 2017-07-18 22:50:40.120419519 -0400 @@ -1108,11 +1108,6 @@ calls callback with Klass and initiating loader (Oop) for System dictionary entry. -
forEachPrimArrayKlass(callback)
-
-calls callback with Klass and initiating loader (Oop) for each -primitive array Klass in the system. -
findInstanceKlass(name)
finds the first instance klass with given name from System dictionary --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/CommandProcessor.java 2017-07-18 22:50:52.000913715 -0400 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/CommandProcessor.java 2017-07-18 22:50:51.621610268 -0400 @@ -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(); --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/classfile/ClassLoaderData.java 2017-07-18 22:51:00.799864165 -0400 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/classfile/ClassLoaderData.java 2017-07-18 22:51:00.469540227 -0400 @@ -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()); + } } } --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/classfile/ClassLoaderDataGraph.java 2017-07-18 22:51:09.845949298 -0400 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/classfile/ClassLoaderDataGraph.java 2017-07-18 22:51:09.475705821 -0400 @@ -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); + } + } } --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Dictionary.java 2017-07-18 22:51:18.773354417 -0400 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Dictionary.java 2017-07-18 22:51:18.435865252 -0400 @@ -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; --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/DictionaryEntry.java 2017-07-18 22:51:28.013005545 -0400 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/DictionaryEntry.java 2017-07-18 22:51:27.776287779 -0400 @@ -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) { - 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) { + public boolean equals(Symbol className) { 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 :-( --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/SystemDictionary.java 2017-07-18 22:51:36.693100092 -0400 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/SystemDictionary.java 2017-07-18 22:51:36.244108379 -0400 @@ -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); - } } --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Universe.java 2017-07-18 22:51:45.176315010 -0400 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Universe.java 2017-07-18 22:51:44.906763935 -0400 @@ -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) { --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java 2017-07-18 22:51:54.367613604 -0400 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java 2017-07-18 22:51:53.946929129 -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); } --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java 2017-07-18 22:52:03.240947951 -0400 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java 2017-07-18 22:52:02.989835886 -0400 @@ -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); --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java 2017-07-18 22:52:12.328144807 -0400 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java 2017-07-18 22:52:11.998542499 -0400 @@ -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; --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassDump.java 2017-07-18 22:52:21.997686562 -0400 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassDump.java 2017-07-18 22:52:21.671303936 -0400 @@ -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 { --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/Hashtable.java 2017-07-18 22:52:31.066661905 -0400 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/Hashtable.java 2017-07-18 22:52:30.734659120 -0400 @@ -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()); } --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java 2017-07-18 22:52:39.674316715 -0400 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java 2017-07-18 22:52:39.414288486 -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(); --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/ReversePtrsAnalysis.java 2017-07-18 22:52:48.223368257 -0400 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/ReversePtrsAnalysis.java 2017-07-18 22:52:47.982488851 -0400 @@ -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) { --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/SystemDictionaryHelper.java 2017-07-18 22:52:57.365592374 -0400 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/SystemDictionaryHelper.java 2017-07-18 22:52:57.118267440 -0400 @@ -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(); + ClassLoaderDataGraph cldg = VM.getVM().getClassLoaderDataGraph(); - // check whether we have a bootstrap class of given name - Klass klass = sysDict.find(className, null, null); - if (klass != null) { + // 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; } - - // check whether we have a system class of given name - klass = sysDict.find(className, sysDict.javaSystemLoader(), null); - if (klass != null) { - return (InstanceKlass) klass; - } - - // 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]; - } - } - // no match .. - return null; } } --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaHeap.java 2017-07-18 22:53:06.560502778 -0400 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaHeap.java 2017-07-18 22:53:06.141979434 -0400 @@ -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) { --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/sa.js 2017-07-18 22:53:16.214621868 -0400 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/sa.js 2017-07-18 22:53:15.708390476 -0400 @@ -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) --- old/src/share/vm/classfile/classLoaderData.cpp 2017-07-18 22:53:25.706109958 -0400 +++ new/src/share/vm/classfile/classLoaderData.cpp 2017-07-18 22:53:25.371092325 -0400 @@ -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" @@ -113,6 +114,12 @@ } else { _unnamed_module = NULL; } + + if (!is_anonymous) { + _dictionary = create_dictionary(); + } else { + _dictionary = NULL; + } TRACE_INIT_ID(this); } @@ -449,10 +456,79 @@ } } +// 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"); + while (true) { + + 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(); + } + } + // never reached: an InstanceKlass should be returned above + } + + // 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) { @@ -491,6 +567,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() { @@ -513,6 +592,48 @@ return modules; } +const int _boot_loader_dictionary_size = 1009; +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 *per class loader* +// This size will be used for all class loaders if specified, +// except boot loader and reflection class loaders +static int calculate_dictionary_size(int classcount) { + static int newsize = 0; // only calculate once + if (newsize != 0) { + return newsize; + } + 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 { + size = calculate_dictionary_size(PredictedLoadedClassCount); + } + 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"); @@ -544,6 +665,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; @@ -971,6 +1099,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* ClassLoaderDataGraph::new_clds() { assert(_head == NULL || _saved_head != NULL, "remember_new_clds(true) not called?"); @@ -1071,14 +1239,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(); } @@ -1250,6 +1423,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; --- old/src/share/vm/classfile/classLoaderData.hpp 2017-07-18 22:53:34.126462489 -0400 +++ new/src/share/vm/classfile/classLoaderData.hpp 2017-07-18 22:53:33.881079502 -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* 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); --- old/src/share/vm/classfile/classLoaderData.inline.hpp 2017-07-18 22:53:42.482873760 -0400 +++ new/src/share/vm/classfile/classLoaderData.inline.hpp 2017-07-18 22:53:42.203156672 -0400 @@ -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(); --- old/src/share/vm/classfile/dictionary.cpp 2017-07-18 22:53:50.436346404 -0400 +++ new/src/share/vm/classfile/dictionary.cpp 2017-07-18 22:53:50.197239361 -0400 @@ -32,12 +32,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(); @@ -46,30 +44,33 @@ } } -Dictionary::Dictionary(int table_size) - : TwoOopHashtable(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(table_size, (int)entry_size()) { }; -Dictionary::Dictionary(int table_size, HashtableBucket* t, +Dictionary::Dictionary(ClassLoaderData* loader_data, + int table_size, HashtableBucket* t, int number_of_entries) - : TwoOopHashtable(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(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::new_entry(hash, klass); - entry->set_loader_data(loader_data); +DictionaryEntry* Dictionary::new_entry(unsigned int hash, InstanceKlass* klass) { + DictionaryEntry* entry = (DictionaryEntry*)Hashtable::allocate_new_entry(hash, klass); entry->set_pd_set(NULL); assert(klass->is_instance_klass(), "Must be"); if (DumpSharedSpaces) { @@ -86,13 +87,15 @@ entry->set_pd_set(to_delete->next()); delete to_delete; } - Hashtable::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; @@ -110,7 +113,7 @@ } #endif /* ASSERT */ - if (protection_domain == klass()->protection_domain()) { + if (protection_domain == instance_klass()->protection_domain()) { // Succeeds trivially return true; } @@ -127,7 +130,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 @@ -147,86 +150,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 = probe->instance_klass(); + ClassLoaderData* k_def_class_loader_data = ik->class_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; - - // 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()); @@ -239,13 +199,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); } } @@ -254,78 +214,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 @@ -335,13 +267,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; @@ -349,10 +282,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; } @@ -360,12 +293,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; } @@ -374,19 +307,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, @@ -401,9 +334,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); } @@ -430,13 +362,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); } @@ -505,8 +436,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"); @@ -516,10 +448,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); } @@ -528,41 +459,37 @@ 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(); - ClassLoaderData* cld = loader_data(); + Klass* e = instance_klass(); guarantee(e->is_instance_klass(), - "Verify of system dictionary failed"); + "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(); // 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(); -} -void Dictionary::verify() { - guarantee(number_of_entries() >= 0, "Verify of system dictionary failed"); - verify_table("System Dictionary"); - _pd_cache_table->verify(); + ResourceMark rm; + + stringStream tempst; + tempst.print("System Dictionary for %s", cld->loader_name()); + verify_table(tempst.as_string()); } --- old/src/share/vm/classfile/dictionary.hpp 2017-07-18 22:53:58.822054308 -0400 +++ new/src/share/vm/classfile/dictionary.hpp 2017-07-18 22:53:58.586764836 -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 { +class Dictionary : public Hashtable { 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::add_entry(index, (HashtableEntry*)new_entry); } + void free_entry(DictionaryEntry* entry); + static size_t entry_size(); public: - Dictionary(int table_size); - Dictionary(int table_size, HashtableBucket* t, int number_of_entries); + Dictionary(ClassLoaderData* loader_data, int table_size); + Dictionary(ClassLoaderData* loader_data, int table_size, HashtableBucket* t, int number_of_entries); + ~Dictionary(); - DictionaryEntry* new_entry(unsigned int hash, InstanceKlass* klass, ClassLoaderData* loader_data); + DictionaryEntry* new_entry(unsigned int hash, InstanceKlass* klass); - void free_entry(DictionaryEntry* entry); - - void add_klass(Symbol* class_name, ClassLoaderData* loader_data, InstanceKlass* obj); + void add_klass(int index, unsigned int hash, Symbol* class_name, InstanceKlass* obj); - InstanceKlass* find_class(int index, unsigned int hash, - Symbol* name, ClassLoaderData* loader_data); + 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 { 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 (InstanceKlass*)literal(); } DictionaryEntry* next() const { return (DictionaryEntry*)HashtableEntry::next(); @@ -173,13 +154,10 @@ return (DictionaryEntry**)HashtableEntry::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) { --- old/src/share/vm/classfile/loaderConstraints.cpp 2017-07-18 22:54:07.295275486 -0400 +++ new/src/share/vm/classfile/loaderConstraints.cpp 2017-07-18 22:54:07.056165745 -0400 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/dictionary.hpp" #include "classfile/classLoaderData.inline.hpp" #include "classfile/loaderConstraints.hpp" #include "memory/resourceArea.hpp" @@ -35,8 +36,8 @@ set_loader_data(i, ClassLoaderData::class_loader_data(p)); } -LoaderConstraintTable::LoaderConstraintTable(int nof_buckets) - : Hashtable(nof_buckets, sizeof(LoaderConstraintEntry)) {}; +LoaderConstraintTable::LoaderConstraintTable(int table_size) + : Hashtable(table_size, sizeof(LoaderConstraintEntry)) {}; LoaderConstraintEntry* LoaderConstraintTable::new_entry( @@ -429,10 +430,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()) { @@ -441,17 +441,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); @@ -475,8 +476,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()) { --- old/src/share/vm/classfile/loaderConstraints.hpp 2017-07-18 22:54:15.378698976 -0400 +++ new/src/share/vm/classfile/loaderConstraints.hpp 2017-07-18 22:54:15.142120004 -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 { - 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 - }; +private: 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 { - friend class VMStructs; private: Symbol* _name; // class name int _num_loaders; --- old/src/share/vm/classfile/moduleEntry.cpp 2017-07-18 22:54:23.324288624 -0400 +++ new/src/share/vm/classfile/moduleEntry.cpp 2017-07-18 22:54:23.084399855 -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::allocate_new_entry(hash, name); // Initialize fields specific to a ModuleEntry entry->init(); --- old/src/share/vm/classfile/packageEntry.cpp 2017-07-18 22:54:31.468714453 -0400 +++ new/src/share/vm/classfile/packageEntry.cpp 2017-07-18 22:54:31.226790554 -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::allocate_new_entry(hash, name); TRACE_INIT_ID(entry); --- old/src/share/vm/classfile/placeholders.cpp 2017-07-18 22:54:39.454266797 -0400 +++ new/src/share/vm/classfile/placeholders.cpp 2017-07-18 22:54:39.212751969 -0400 @@ -172,7 +172,7 @@ } PlaceholderTable::PlaceholderTable(int table_size) - : TwoOopHashtable(table_size, sizeof(PlaceholderEntry)) { + : Hashtable(table_size, sizeof(PlaceholderEntry)) { } #ifndef PRODUCT --- old/src/share/vm/classfile/placeholders.hpp 2017-07-18 22:54:47.548207720 -0400 +++ new/src/share/vm/classfile/placeholders.hpp 2017-07-18 22:54:47.300403917 -0400 @@ -34,8 +34,7 @@ // being loaded, as well as arrays of primitives. // -class PlaceholderTable : public TwoOopHashtable { - friend class VMStructs; +class PlaceholderTable : public Hashtable { public: PlaceholderTable(int table_size); @@ -149,8 +148,6 @@ // The system dictionary is the only user of this class. class PlaceholderEntry : public HashtableEntry { - friend class VMStructs; - private: ClassLoaderData* _loader_data; // initiating loader --- old/src/share/vm/classfile/protectionDomainCache.cpp 2017-07-18 22:54:55.789046891 -0400 +++ new/src/share/vm/classfile/protectionDomainCache.cpp 2017-07-18 22:54:55.466106988 -0400 @@ -85,14 +85,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 --- old/src/share/vm/classfile/protectionDomainCache.hpp 2017-07-18 22:55:04.105307548 -0400 +++ new/src/share/vm/classfile/protectionDomainCache.hpp 2017-07-18 22:55:03.866337831 -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 { 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 --- old/src/share/vm/classfile/systemDictionary.cpp 2017-07-18 22:55:12.330444403 -0400 +++ new/src/share/vm/classfile/systemDictionary.cpp 2017-07-18 22:55:11.997805358 -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" @@ -87,19 +88,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] @@ -115,6 +111,10 @@ // lazily initialized klass variables InstanceKlass* volatile SystemDictionary::_abstract_ownable_synchronizer_klass = NULL; +// Default ProtectionDomainCacheSize value + +const int defaultProtectionDomainCacheSize = 1009; + // ---------------------------------------------------------------------------- // Java-level SystemLoader @@ -342,32 +342,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: @@ -443,13 +443,18 @@ log->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); @@ -464,27 +469,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); } } @@ -546,9 +540,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 @@ -571,7 +566,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 @@ -581,7 +576,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; @@ -661,6 +656,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 @@ -668,10 +664,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; @@ -689,7 +684,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. @@ -708,7 +703,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; @@ -792,7 +787,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; @@ -817,7 +812,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; @@ -850,7 +845,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; @@ -884,7 +879,7 @@ } } } - } // load_instance_class loop + } // load_instance_class if (load_instance_added == true) { // clean up placeholder entries for LOAD_INSTANCE success or error @@ -917,16 +912,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; } } @@ -966,20 +953,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); } @@ -1033,7 +1011,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()); } @@ -1064,7 +1041,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(); @@ -1187,9 +1164,10 @@ #if INCLUDE_CDS void SystemDictionary::set_shared_dictionary(HashtableBucket* t, int length, int number_of_entries) { - assert(length == _nof_buckets * sizeof(HashtableBucket), + assert(length == _shared_dictionary_size * sizeof(HashtableBucket), "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); } @@ -1198,7 +1176,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); @@ -1624,8 +1602,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) @@ -1643,7 +1622,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); @@ -1693,12 +1672,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; @@ -1706,7 +1686,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; } @@ -1728,7 +1708,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(); @@ -1767,6 +1747,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()) { @@ -1804,12 +1785,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); } @@ -1817,14 +1795,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 || @@ -1832,18 +1813,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); } @@ -1870,33 +1844,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 { @@ -1905,7 +1856,7 @@ template 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: @@ -1934,20 +1885,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 } @@ -1964,8 +1915,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); @@ -1980,8 +1939,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); @@ -1989,25 +1949,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); @@ -2016,7 +1957,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(); } // ---------------------------------------------------------------------------- @@ -2040,15 +1981,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); @@ -2199,9 +2137,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, @@ -2216,12 +2154,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"); @@ -2262,7 +2200,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, @@ -2275,40 +2213,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(); } } @@ -2378,21 +2317,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); + Dictionary* dictionary1 = loader_data1->dictionary(); + unsigned int d_hash1 = dictionary1->compute_hash(constraint_name); + int d_index1 = dictionary1->hash_to_index(d_hash1); + + Dictionary* dictionary2 = loader_data2->dictionary(); + unsigned int d_hash2 = dictionary2->compute_hash(constraint_name); + int d_index2 = dictionary2->hash_to_index(d_hash2); + { - MutexLocker mu_s(SystemDictionary_lock, THREAD); - - // Better never do a GC while we're holding these oops - NoSafepointVerifier nosafepoint; - - 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); } } @@ -2842,64 +2781,72 @@ 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); + } - // Placeholders GCMutexLocker mu(SystemDictionary_lock); + + ClassLoaderDataGraph::print_dictionary(details); + + // Placeholders 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"); // 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 --- old/src/share/vm/classfile/systemDictionary.hpp 2017-07-18 22:55:20.492061859 -0400 +++ new/src/share/vm/classfile/systemDictionary.hpp 2017-07-18 22:55:20.238694217 -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 place holder 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 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 --- old/src/share/vm/classfile/systemDictionaryShared.hpp 2017-07-18 22:55:28.559685565 -0400 +++ new/src/share/vm/classfile/systemDictionaryShared.hpp 2017-07-18 22:55:28.281947264 -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, --- old/src/share/vm/memory/universe.cpp 2017-07-18 22:55:36.857921787 -0400 +++ new/src/share/vm/memory/universe.cpp 2017-07-18 22:55:36.481379127 -0400 @@ -541,14 +541,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); } --- old/src/share/vm/oops/klassVtable.cpp 2017-07-18 22:55:45.259055161 -0400 +++ new/src/share/vm/oops/klassVtable.cpp 2017-07-18 22:55:44.872912283 -0400 @@ -1562,7 +1562,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); --- old/src/share/vm/prims/jvmtiGetLoadedClasses.cpp 2017-07-18 22:55:53.490240574 -0400 +++ new/src/share/vm/prims/jvmtiGetLoadedClasses.cpp 2017-07-18 22:55:53.168811902 -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. --- old/src/share/vm/runtime/biasedLocking.cpp 2017-07-18 22:56:02.014778954 -0400 +++ new/src/share/vm/runtime/biasedLocking.cpp 2017-07-18 22:56:01.685327276 -0400 @@ -42,7 +42,7 @@ static GrowableArray* _preserved_oop_stack = NULL; static GrowableArray* _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 + // Iterate the class loader data dictionaries enabling biased locking for all // currently loaded classes - SystemDictionary::classes_do(enable_biased_locking); + ClassLoaderDataGraph::dictionary_classes_do(enable_biased_locking); // Indicate that future instances should enable it as well _biased_locking_enabled = true; --- old/src/share/vm/runtime/compilationPolicy.cpp 2017-07-18 22:56:10.371565151 -0400 +++ new/src/share/vm/runtime/compilationPolicy.cpp 2017-07-18 22:56:10.141654788 -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); } } } --- old/src/share/vm/runtime/memprofiler.cpp 2017-07-18 22:56:18.344668283 -0400 +++ new/src/share/vm/runtime/memprofiler.cpp 2017-07-18 22:56:18.115276155 -0400 @@ -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); --- old/src/share/vm/runtime/vmStructs.cpp 2017-07-18 22:56:26.391136617 -0400 +++ new/src/share/vm/runtime/vmStructs.cpp 2017-07-18 22:56:26.084899986 -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 SymbolHashtable; typedef HashtableEntry SymbolHashtableEntry; typedef Hashtable StringHashtable; -typedef TwoOopHashtable KlassTwoOopHashtable; typedef Hashtable KlassHashtable; typedef HashtableEntry KlassHashtableEntry; -typedef TwoOopHashtable SymbolTwoOopHashtable; typedef CompactHashtable SymbolCompactHashTable; typedef RehashableHashtable RehashableSymbolHashtable; @@ -250,7 +246,6 @@ nonstatic_field(InstanceKlass, _fields, Array*) \ 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*) \ @@ -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, _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) \ 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) \ declare_type(IntptrHashtableEntry, BasicHashtableEntry) \ declare_type(DictionaryEntry, KlassHashtableEntry) \ - declare_type(PlaceholderEntry, SymbolHashtableEntry) \ - declare_type(LoaderConstraintEntry, KlassHashtableEntry) \ declare_toplevel_type(HashtableBucket) \ declare_toplevel_type(SystemDictionary) \ declare_toplevel_type(vmSymbols) \ - declare_toplevel_type(ProtectionDomainEntry) \ - declare_toplevel_type(ProtectionDomainCacheEntry) \ \ declare_toplevel_type(GenericGrowableArray) \ declare_toplevel_type(GrowableArray) \ @@ -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 */ \ --- old/src/share/vm/utilities/globalDefinitions.hpp 2017-07-18 22:56:34.744978054 -0400 +++ new/src/share/vm/utilities/globalDefinitions.hpp 2017-07-18 22:56:34.408971995 -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 --- old/src/share/vm/utilities/hashtable.cpp 2017-07-18 22:56:42.977480792 -0400 +++ new/src/share/vm/utilities/hashtable.cpp 2017-07-18 22:56:42.722013771 -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 HashtableEntry* Hashtable::allocate_new_entry(unsigned int hashValue, T obj) { + HashtableEntry* entry = (HashtableEntry*) 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; template class Hashtable; template class Hashtable; +template class Hashtable; #if defined(SOLARIS) || defined(CHECK_UNHANDLED_OOPS) template class Hashtable; template class RehashableHashtable; --- old/src/share/vm/utilities/hashtable.hpp 2017-07-18 22:56:51.009534667 -0400 +++ new/src/share/vm/utilities/hashtable.hpp 2017-07-18 22:56:50.769472562 -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* new_entry(unsigned int hashValue, T obj); + // Don't create and use freelist of HashtableEntry. + HashtableEntry* allocate_new_entry(unsigned int hashValue, T obj); // The following method is MT-safe and may be used with caution. HashtableEntry* bucket(int i) const { @@ -324,31 +326,4 @@ template juint RehashableHashtable::seed() { return _seed; }; template bool RehashableHashtable::use_alternate_hashcode() { return _seed != 0; }; -// Versions of hashtable where two handles are used to compute the index. - -template class TwoOopHashtable : public Hashtable { - friend class VMStructs; -protected: - TwoOopHashtable(int table_size, int entry_size) - : Hashtable(table_size, entry_size) {} - - TwoOopHashtable(int table_size, int entry_size, HashtableBucket* t, - int number_of_entries) - : Hashtable(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 --- old/test/runtime/NMT/CheckForProperDetailStackTrace.java 2017-07-18 22:57:00.186541251 -0400 +++ new/test/runtime/NMT/CheckForProperDetailStackTrace.java 2017-07-18 22:56:59.854546824 -0400 @@ -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. */ --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/LoaderConstraintEntry.java 2017-07-18 22:57:09.837552486 -0400 +++ /dev/null 2017-06-11 15:38:07.778000227 -0400 @@ -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 .. - */ -} --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/LoaderConstraintTable.java 2017-07-18 22:57:14.014399623 -0400 +++ /dev/null 2017-06-11 15:38:07.778000227 -0400 @@ -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; - } -} --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/PlaceholderEntry.java 2017-07-18 22:57:18.043786215 -0400 +++ /dev/null 2017-06-11 15:38:07.778000227 -0400 @@ -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 .. - */ -} --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/PlaceholderTable.java 2017-07-18 22:57:22.134964109 -0400 +++ /dev/null 2017-06-11 15:38:07.778000227 -0400 @@ -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()); - } - } - } - } - } -} --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/ProtectionDomainCacheEntry.java 2017-07-18 22:57:26.167542460 -0400 +++ /dev/null 2017-06-11 15:38:07.778000227 -0400 @@ -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)); - } -} --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/ProtectionDomainEntry.java 2017-07-18 22:57:30.378562486 -0400 +++ /dev/null 2017-06-11 15:38:07.778000227 -0400 @@ -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(); - } -} --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/TwoOopHashtable.java 2017-07-18 22:57:34.550722489 -0400 +++ /dev/null 2017-06-11 15:38:07.778000227 -0400 @@ -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)); - } -}