--- old/agent/src/share/classes/sun/jvm/hotspot/memory/SymbolTable.java 2015-01-30 17:15:01.995509993 -0500 +++ new/agent/src/share/classes/sun/jvm/hotspot/memory/SymbolTable.java 2015-01-30 17:15:01.091457495 -0500 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, 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 @@ -44,15 +44,22 @@ private static synchronized void initialize(TypeDataBase db) { Type type = db.lookupType("SymbolTable"); theTableField = type.getAddressField("_the_table"); + sharedTableField = type.getAddressField("_shared_table"); } // Fields private static AddressField theTableField; + private static AddressField sharedTableField; + + private CompactHashTable sharedTable; // Accessors public static SymbolTable getTheTable() { Address tmp = theTableField.getValue(); - return (SymbolTable) VMObjectFactory.newObject(SymbolTable.class, tmp); + SymbolTable table = (SymbolTable) VMObjectFactory.newObject(SymbolTable.class, tmp); + Address shared = sharedTableField.getStaticFieldAddress(); + table.sharedTable = (CompactHashTable)VMObjectFactory.newObject(CompactHashTable.class, shared); + return table; } public SymbolTable(Address addr) { @@ -73,8 +80,9 @@ /** Clone of VM's "temporary" probe routine, as the SA currently does not support mutation so lookup() would have no effect - anyway. Returns null if the given string is not in the symbol - table. */ + anyway. Searches the regular symbol table and the shared symbol + table. Null is returned if the given string is not in the symbol + tables. */ public Symbol probe(byte[] name) { long hashValue = hashSymbol(name); for (HashtableEntry e = (HashtableEntry) bucket(hashToIndex(hashValue)); e != null; e = (HashtableEntry) e.next()) { @@ -85,7 +93,8 @@ } } } - return null; + + return sharedTable.probe(name, hashValue); } public interface SymbolVisitor { --- old/src/share/vm/classfile/compactHashtable.hpp 2015-01-30 17:15:04.703667253 -0500 +++ new/src/share/vm/classfile/compactHashtable.hpp 2015-01-30 17:15:03.823616148 -0500 @@ -188,6 +188,7 @@ // dump time. // template class CompactHashtable VALUE_OBJ_CLASS_SPEC { + friend class VMStructs; uintx _base_address; juint _entry_count; juint _bucket_count; --- old/src/share/vm/runtime/vmStructs.cpp 2015-01-30 17:15:07.663839146 -0500 +++ new/src/share/vm/runtime/vmStructs.cpp 2015-01-30 17:15:06.755786415 -0500 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ #include "classfile/javaClasses.hpp" #include "classfile/loaderConstraints.hpp" #include "classfile/placeholders.hpp" +#include "classfile/compactHashtable.hpp" #include "classfile/stringTable.hpp" #include "classfile/systemDictionary.hpp" #include "ci/ciField.hpp" @@ -243,6 +244,7 @@ typedef Hashtable KlassHashtable; typedef HashtableEntry KlassHashtableEntry; typedef TwoOopHashtable SymbolTwoOopHashtable; +typedef CompactHashtable SymbolCompactHashTable; //-------------------------------------------------------------------------------- // VM_STRUCTS @@ -617,6 +619,7 @@ /***************/ \ \ static_field(SymbolTable, _the_table, SymbolTable*) \ + static_field(SymbolTable, _shared_table, SymbolCompactHashTable) \ \ /***************/ \ /* StringTable */ \ @@ -625,6 +628,16 @@ static_field(StringTable, _the_table, StringTable*) \ \ /********************/ \ + /* CompactHashTable */ \ + /********************/ \ + \ + nonstatic_field(SymbolCompactHashTable, _base_address, uintx) \ + nonstatic_field(SymbolCompactHashTable, _entry_count, juint) \ + nonstatic_field(SymbolCompactHashTable, _bucket_count, juint) \ + nonstatic_field(SymbolCompactHashTable, _table_end_offset, juint) \ + nonstatic_field(SymbolCompactHashTable, _buckets, juint*) \ + \ + /********************/ \ /* SystemDictionary */ \ /********************/ \ \ @@ -1572,6 +1585,8 @@ declare_type(ResourceArea, Arena) \ declare_toplevel_type(Chunk) \ \ + declare_toplevel_type(SymbolCompactHashTable) \ + \ /***********************************************************/ \ /* Thread hierarchy (needed for run-time type information) */ \ /***********************************************************/ \ @@ -2940,7 +2955,7 @@ }; VMTypeEntry VMStructs::localHotSpotVMTypes[] = { - + VM_TYPES(GENERATE_VM_TYPE_ENTRY, GENERATE_TOPLEVEL_VM_TYPE_ENTRY, GENERATE_OOP_VM_TYPE_ENTRY, --- /dev/null 2014-12-13 10:35:39.117184000 -0500 +++ new/agent/src/share/classes/sun/jvm/hotspot/utilities/CompactHashTable.java 2015-01-30 17:15:09.759960864 -0500 @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2015, 2015, 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 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 CompactHashTable extends VMObject { + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { + Type type = db.lookupType("SymbolCompactHashTable"); + baseAddressField = type.getAddressField("_base_address"); + bucketCountField = type.getCIntegerField("_bucket_count"); + tableEndOffsetField = type.getCIntegerField("_table_end_offset"); + bucketsField = type.getAddressField("_buckets"); + uintSize = db.lookupType("juint").getSize(); + } + + // Fields + private static CIntegerField bucketCountField; + private static CIntegerField tableEndOffsetField; + private static AddressField baseAddressField; + private static AddressField bucketsField; + private static long uintSize; + private static long uintxSize; + + private static int BUCKET_OFFSET_MASK = 0x3FFFFFFF; + private static int BUCKET_TYPE_SHIFT = 30; + private static int COMPACT_BUCKET_TYPE = 1; + + public CompactHashTable(Address addr) { + super(addr); + } + + private int bucketCount() { + return (int)bucketCountField.getValue(addr); + } + + private int tableEndOffset() { + return (int)tableEndOffsetField.getValue(addr); + } + + private boolean isCompactBucket(int bucket_info) { + return (bucket_info >> BUCKET_TYPE_SHIFT) == COMPACT_BUCKET_TYPE; + } + + private int bucketOffset(int bucket_info) { + return bucket_info & BUCKET_OFFSET_MASK; + } + + public Symbol probe(byte[] name, long hash) { + long symOffset; + Symbol sym; + Address baseAddress = baseAddressField.getValue(addr); + Address bucket = bucketsField.getValue(addr); + Address bucketEnd = bucket; + long index = hash % bucketCount(); + int bucketInfo = (int)bucket.getCIntegerAt(index * uintSize, uintSize, true); + int bucketOffset = bucketOffset(bucketInfo); + int nextBucketInfo = (int)bucket.getCIntegerAt((index+1) * uintSize, uintSize, true); + int nextBucketOffset = bucketOffset(nextBucketInfo); + + bucket = bucket.addOffsetTo(bucketOffset * uintSize); + + if (isCompactBucket(bucketInfo)) { + symOffset = bucket.getCIntegerAt(0, uintSize, true); + sym = Symbol.create(baseAddress.addOffsetTo(symOffset)); + if (sym.equals(name)) { + return sym; + } + } else { + bucketEnd = bucket.addOffsetTo(nextBucketOffset * uintSize); + while (bucket.lessThan(bucketEnd)) { + long symHash = bucket.getCIntegerAt(0, uintSize, true); + if (symHash == hash) { + symOffset = bucket.getCIntegerAt(uintSize, uintSize, true); + Address symAddr = baseAddress.addOffsetTo(symOffset); + sym = Symbol.create(symAddr); + if (sym.equals(name)) { + return sym; + } + } + bucket = bucket.addOffsetTo(2 * uintSize); + } + } + return null; + } +}