src/share/classes/java/util/Hashtable.java

Print this page

        

*** 178,216 **** * Offset of "final" hashSeed field we must set in * readObject() method. */ static final long HASHSEED_OFFSET; static { try { UNSAFE = sun.misc.Unsafe.getUnsafe(); HASHSEED_OFFSET = UNSAFE.objectFieldOffset( Hashtable.class.getDeclaredField("hashSeed")); } catch (NoSuchFieldException | SecurityException e) { throw new InternalError("Failed to record hashSeed offset", e); } } } /** * A randomizing value associated with this instance that is applied to * hash code of keys to make hash collisions harder to find. */ ! transient final int hashSeed = sun.misc.Hashing.randomHashSeed(this); ! private int hash(Object k) { ! if (k instanceof String) { ! return ((String)k).hash32(); } ! int h = hashSeed ^ k.hashCode(); ! ! // This function ensures that hashCodes that differ only by ! // constant multiples at each bit position have a bounded ! // number of collisions (approximately 8 at default load factor). ! h ^= (h >>> 20) ^ (h >>> 12); ! return h ^ (h >>> 7) ^ (h >>> 4); } /** * Constructs a new, empty hashtable with the specified initial * capacity and the specified load factor. --- 178,233 ---- * Offset of "final" hashSeed field we must set in * readObject() method. */ static final long HASHSEED_OFFSET; + static final boolean USE_HASHSEED; + static { + String hashSeedProp = java.security.AccessController.doPrivileged( + new sun.security.action.GetPropertyAction( + "jdk.map.useRandomSeed")); + boolean localBool = (null != hashSeedProp) + ? Boolean.parseBoolean(hashSeedProp) : false; + USE_HASHSEED = localBool; + + if (USE_HASHSEED) { try { UNSAFE = sun.misc.Unsafe.getUnsafe(); HASHSEED_OFFSET = UNSAFE.objectFieldOffset( Hashtable.class.getDeclaredField("hashSeed")); } catch (NoSuchFieldException | SecurityException e) { throw new InternalError("Failed to record hashSeed offset", e); } + } else { + UNSAFE = null; + HASHSEED_OFFSET = 0; + } } } /** * A randomizing value associated with this instance that is applied to * hash code of keys to make hash collisions harder to find. + * + * Non-final so it can be set lazily, but be sure not to set more than once. */ ! transient final int hashSeed; ! /** ! * Return an initial value for the hashSeed, or 0 if the random seed is not ! * enabled. ! */ ! final int initHashSeed() { ! if (sun.misc.VM.isBooted() && Holder.USE_HASHSEED) { ! return sun.misc.Hashing.randomHashSeed(this); ! } ! return 0; } ! private int hash(Object k) { ! return hashSeed ^ k.hashCode(); } /** * Constructs a new, empty hashtable with the specified initial * capacity and the specified load factor.
*** 230,239 **** --- 247,257 ---- if (initialCapacity==0) initialCapacity = 1; this.loadFactor = loadFactor; table = new Entry<?,?>[initialCapacity]; threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1); + hashSeed = initHashSeed(); } /** * Constructs a new, empty hashtable with the specified initial capacity * and default load factor (0.75).
*** 1185,1196 **** --- 1203,1216 ---- { // Read in the length, threshold, and loadfactor s.defaultReadObject(); // set hashMask + if (Holder.USE_HASHSEED) { Holder.UNSAFE.putIntVolatile(this, Holder.HASHSEED_OFFSET, sun.misc.Hashing.randomHashSeed(this)); + } // Read the original length of the array and number of elements int origlength = s.readInt(); int elements = s.readInt();