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

Print this page

        

@@ -178,39 +178,56 @@
          * 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 = sun.misc.Hashing.randomHashSeed(this);
+    transient final int hashSeed;
 
-    private int hash(Object k) {
-        if (k instanceof String) {
-            return ((String)k).hash32();
+    /**
+     * 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;
         }
 
-        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);
+    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,10 +247,11 @@
         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,12 +1203,14 @@
     {
         // 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();