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();