--- old/src/share/classes/java/lang/String.java 2013-06-11 13:06:17.000000000 -0700 +++ new/src/share/classes/java/lang/String.java 2013-06-11 13:06:16.000000000 -0700 @@ -3156,101 +3156,4 @@ * guaranteed to be from a pool of unique strings. */ public native String intern(); - - /** - * Seed value used for each alternative hash calculated. - */ - private static final int HASHING_SEED; - - static { - long nanos = System.nanoTime(); - long now = System.currentTimeMillis(); - int SEED_MATERIAL[] = { - System.identityHashCode(String.class), - System.identityHashCode(System.class), - (int) (nanos >>> 32), - (int) nanos, - (int) (now >>> 32), - (int) now, - (int) (System.nanoTime() >>> 2) - }; - - // Use murmur3 to scramble the seeding material. - // Inline implementation to avoid loading classes - int h1 = 0; - - // body - for(int k1 : SEED_MATERIAL) { - k1 *= 0xcc9e2d51; - k1 = (k1 << 15) | (k1 >>> 17); - k1 *= 0x1b873593; - - h1 ^= k1; - h1 = (h1 << 13) | (h1 >>> 19); - h1 = h1 * 5 + 0xe6546b64; - } - - // tail (always empty, as body is always 32-bit chunks) - - // finalization - - h1 ^= SEED_MATERIAL.length * 4; - - // finalization mix force all bits of a hash block to avalanche - h1 ^= h1 >>> 16; - h1 *= 0x85ebca6b; - h1 ^= h1 >>> 13; - h1 *= 0xc2b2ae35; - h1 ^= h1 >>> 16; - - HASHING_SEED = h1; - } - - /** - * Cached value of the hashing algorithm result - */ - private transient int hash32 = 0; - - /** - * Return a 32-bit hash code value for this object. - *

- * The general contract of {@code hash32} is: - *

- * - * The hash value will never be zero. - * - * @return a hash code value for this object. - * @see java.lang.Object#equals(java.lang.Object) - */ - public int hash32() { - int h = hash32; - if (0 == h) { - // harmless data race on hash32 here. - h = sun.misc.Hashing.murmur3_32(HASHING_SEED, value, 0, value.length); - - // ensure result is not zero to avoid recalcing - h = (0 != h) ? h : 1; - - hash32 = h; - } - - return h; - } - } --- old/src/share/classes/java/util/HashMap.java 2013-06-11 13:06:18.000000000 -0700 +++ new/src/share/classes/java/util/HashMap.java 2013-06-11 13:06:17.000000000 -0700 @@ -28,6 +28,7 @@ import java.io.*; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.util.concurrent.ThreadLocalRandom; import java.util.function.Consumer; import java.util.function.BiFunction; import java.util.function.Function; @@ -912,7 +913,8 @@ */ final int initHashSeed() { if (sun.misc.VM.isBooted() && Holder.USE_HASHSEED) { - return sun.misc.Hashing.randomHashSeed(this); + int seed = ThreadLocalRandom.current().nextInt(); + return (0 != seed) ? seed : 1; } return 0; } @@ -2572,8 +2574,9 @@ // set other fields that need values if (Holder.USE_HASHSEED) { + int seed = ThreadLocalRandom.current().nextInt(); Holder.UNSAFE.putIntVolatile(this, Holder.HASHSEED_OFFSET, - sun.misc.Hashing.randomHashSeed(this)); + 0 != seed ? seed : 1); } table = EMPTY_TABLE; --- old/src/share/classes/java/util/Hashtable.java 2013-06-11 13:06:19.000000000 -0700 +++ new/src/share/classes/java/util/Hashtable.java 2013-06-11 13:06:18.000000000 -0700 @@ -26,6 +26,7 @@ package java.util; import java.io.*; +import java.util.concurrent.ThreadLocalRandom; import java.util.function.BiConsumer; import java.util.function.Function; import java.util.function.BiFunction; @@ -219,7 +220,8 @@ */ final int initHashSeed() { if (sun.misc.VM.isBooted() && Holder.USE_HASHSEED) { - return sun.misc.Hashing.randomHashSeed(this); + int seed = ThreadLocalRandom.current().nextInt(); + return (0 != seed) ? seed : 1; } return 0; } @@ -1205,9 +1207,10 @@ s.defaultReadObject(); // set hashMask - if (Holder.USE_HASHSEED) { + if (Holder.USE_HASHSEED) { + int seed = ThreadLocalRandom.current().nextInt(); Holder.UNSAFE.putIntVolatile(this, Holder.HASHSEED_OFFSET, - sun.misc.Hashing.randomHashSeed(this)); + 0 != seed ? seed : 1); } // Read the original length of the array and number of elements --- old/src/share/classes/java/util/WeakHashMap.java 2013-06-11 13:06:19.000000000 -0700 +++ new/src/share/classes/java/util/WeakHashMap.java 2013-06-11 13:06:19.000000000 -0700 @@ -27,6 +27,7 @@ import java.lang.ref.WeakReference; import java.lang.ref.ReferenceQueue; +import java.util.concurrent.ThreadLocalRandom; import java.util.function.Consumer; @@ -215,7 +216,8 @@ if (sun.misc.VM.isBooted() && Holder.USE_HASHSEED) { // Do not set hashSeed more than once! // assert hashSeed == 0; - hashSeed = sun.misc.Hashing.randomHashSeed(this); + int seed = ThreadLocalRandom.current().nextInt(); + hashSeed = (0 != seed) ? seed : 1; } } --- old/src/share/classes/sun/misc/Hashing.java 2013-06-11 13:06:20.000000000 -0700 +++ /dev/null 2013-06-11 13:06:20.000000000 -0700 @@ -1,239 +0,0 @@ -/* - * Copyright (c) 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.misc; - -import java.util.concurrent.ThreadLocalRandom; - -/** - * Hashing utilities. - * - * Little endian implementations of Murmur3 hashing. - */ -public class Hashing { - - /** - * Static utility methods only. - */ - private Hashing() { - throw new Error("No instances"); - } - - public static int murmur3_32(byte[] data) { - return murmur3_32(0, data, 0, data.length); - } - - public static int murmur3_32(int seed, byte[] data) { - return murmur3_32(seed, data, 0, data.length); - } - - @SuppressWarnings("fallthrough") - public static int murmur3_32(int seed, byte[] data, int offset, int len) { - int h1 = seed; - int count = len; - - // body - while (count >= 4) { - int k1 = (data[offset] & 0x0FF) - | (data[offset + 1] & 0x0FF) << 8 - | (data[offset + 2] & 0x0FF) << 16 - | data[offset + 3] << 24; - - count -= 4; - offset += 4; - - k1 *= 0xcc9e2d51; - k1 = Integer.rotateLeft(k1, 15); - k1 *= 0x1b873593; - - h1 ^= k1; - h1 = Integer.rotateLeft(h1, 13); - h1 = h1 * 5 + 0xe6546b64; - } - - // tail - - if (count > 0) { - int k1 = 0; - - switch (count) { - case 3: - k1 ^= (data[offset + 2] & 0xff) << 16; - // fall through - case 2: - k1 ^= (data[offset + 1] & 0xff) << 8; - // fall through - case 1: - k1 ^= (data[offset] & 0xff); - // fall through - default: - k1 *= 0xcc9e2d51; - k1 = Integer.rotateLeft(k1, 15); - k1 *= 0x1b873593; - h1 ^= k1; - } - } - - // finalization - - h1 ^= len; - - // finalization mix force all bits of a hash block to avalanche - h1 ^= h1 >>> 16; - h1 *= 0x85ebca6b; - h1 ^= h1 >>> 13; - h1 *= 0xc2b2ae35; - h1 ^= h1 >>> 16; - - return h1; - } - - public static int murmur3_32(char[] data) { - return murmur3_32(0, data, 0, data.length); - } - - public static int murmur3_32(int seed, char[] data) { - return murmur3_32(seed, data, 0, data.length); - } - - public static int murmur3_32(int seed, char[] data, int offset, int len) { - int h1 = seed; - - int off = offset; - int count = len; - - // body - while (count >= 2) { - int k1 = (data[off++] & 0xFFFF) | (data[off++] << 16); - - count -= 2; - - k1 *= 0xcc9e2d51; - k1 = Integer.rotateLeft(k1, 15); - k1 *= 0x1b873593; - - h1 ^= k1; - h1 = Integer.rotateLeft(h1, 13); - h1 = h1 * 5 + 0xe6546b64; - } - - // tail - - if (count > 0) { - int k1 = data[off]; - - k1 *= 0xcc9e2d51; - k1 = Integer.rotateLeft(k1, 15); - k1 *= 0x1b873593; - h1 ^= k1; - } - - // finalization - - h1 ^= len * (Character.SIZE / Byte.SIZE); - - // finalization mix force all bits of a hash block to avalanche - h1 ^= h1 >>> 16; - h1 *= 0x85ebca6b; - h1 ^= h1 >>> 13; - h1 *= 0xc2b2ae35; - h1 ^= h1 >>> 16; - - return h1; - } - - public static int murmur3_32(int[] data) { - return murmur3_32(0, data, 0, data.length); - } - - public static int murmur3_32(int seed, int[] data) { - return murmur3_32(seed, data, 0, data.length); - } - - public static int murmur3_32(int seed, int[] data, int offset, int len) { - int h1 = seed; - - int off = offset; - int end = offset + len; - - // body - while (off < end) { - int k1 = data[off++]; - - k1 *= 0xcc9e2d51; - k1 = Integer.rotateLeft(k1, 15); - k1 *= 0x1b873593; - - h1 ^= k1; - h1 = Integer.rotateLeft(h1, 13); - h1 = h1 * 5 + 0xe6546b64; - } - - // tail (always empty, as body is always 32-bit chunks) - - // finalization - - h1 ^= len * (Integer.SIZE / Byte.SIZE); - - // finalization mix force all bits of a hash block to avalanche - h1 ^= h1 >>> 16; - h1 *= 0x85ebca6b; - h1 ^= h1 >>> 13; - h1 *= 0xc2b2ae35; - h1 ^= h1 >>> 16; - - return h1; - } - - /** - * Return a non-zero 32-bit pseudo random value. The {@code instance} object - * may be used as part of the value. - * - * @param instance an object to use if desired in choosing value. - * @return a non-zero 32-bit pseudo random value. - */ - public static int randomHashSeed(Object instance) { - int seed; - if (sun.misc.VM.isBooted()) { - seed = ThreadLocalRandom.current().nextInt(); - } else { - // lower quality "random" seed value--still better than zero and not - // not practically reversible. - int hashing_seed[] = { - System.identityHashCode(Hashing.class), - System.identityHashCode(instance), - System.identityHashCode(Thread.currentThread()), - (int) Thread.currentThread().getId(), - (int) (System.currentTimeMillis() >>> 2), // resolution is poor - (int) (System.nanoTime() >>> 5), // resolution is poor - (int) (Runtime.getRuntime().freeMemory() >>> 4) // alloc min - }; - - seed = murmur3_32(hashing_seed); - } - - // force to non-zero. - return (0 != seed) ? seed : 1; - } -} --- old/test/sun/misc/Hashing.java 2013-06-11 13:06:21.000000000 -0700 +++ /dev/null 2013-06-11 13:06:21.000000000 -0700 @@ -1,127 +0,0 @@ -/* - * Copyright (c) 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. - */ - -/* - * @test @summary Ensure that Murmur3 hash performs according to specification. - * @compile -XDignore.symbol.file Hashing.java - */ -public class Hashing { - - static final byte ONE_BYTE[] = { - (byte) 0x80}; - static final byte TWO_BYTE[] = { - (byte) 0x80, (byte) 0x81}; - static final char ONE_CHAR[] = { - (char) 0x8180}; - static final byte THREE_BYTE[] = { - (byte) 0x80, (byte) 0x81, (byte) 0x82}; - static final byte FOUR_BYTE[] = { - (byte) 0x80, (byte) 0x81, (byte) 0x82, (byte) 0x83}; - static final char TWO_CHAR[] = { - (char) 0x8180, (char) 0x8382}; - static final int ONE_INT[] = { - 0x83828180}; - static final byte SIX_BYTE[] = { - (byte) 0x80, (byte) 0x81, (byte) 0x82, - (byte) 0x83, (byte) 0x84, (byte) 0x85}; - static final char THREE_CHAR[] = { - (char) 0x8180, (char) 0x8382, (char) 0x8584}; - static final byte EIGHT_BYTE[] = { - (byte) 0x80, (byte) 0x81, (byte) 0x82, - (byte) 0x83, (byte) 0x84, (byte) 0x85, - (byte) 0x86, (byte) 0x87}; - static final char FOUR_CHAR[] = { - (char) 0x8180, (char) 0x8382, - (char) 0x8584, (char) 0x8786}; - static final int TWO_INT[] = { - 0x83828180, 0x87868584}; - // per http://code.google.com/p/smhasher/source/browse/trunk/main.cpp, line:72 - static final int MURMUR3_32_X86_CHECK_VALUE = 0xB0F57EE3; - - public static void testMurmur3_32_ByteArray() { - System.out.println("testMurmur3_32_ByteArray"); - - byte[] vector = new byte[256]; - byte[] hashes = new byte[4 * 256]; - - for (int i = 0; i < 256; i++) { - vector[i] = (byte) i; - } - - // Hash subranges {}, {0}, {0,1}, {0,1,2}, ..., {0,...,255} - for (int i = 0; i < 256; i++) { - int hash = sun.misc.Hashing.murmur3_32(256 - i, vector, 0, i); - - hashes[i * 4] = (byte) hash; - hashes[i * 4 + 1] = (byte) (hash >>> 8); - hashes[i * 4 + 2] = (byte) (hash >>> 16); - hashes[i * 4 + 3] = (byte) (hash >>> 24); - } - - // hash to get final result. - int final_hash = sun.misc.Hashing.murmur3_32(0, hashes); - - if (MURMUR3_32_X86_CHECK_VALUE != final_hash) { - throw new RuntimeException( - String.format("Calculated hash result not as expected. Expected %08X got %08X", - MURMUR3_32_X86_CHECK_VALUE, - final_hash)); - } - } - - public static void testEquivalentHashes() { - int bytes, chars, ints; - - System.out.println("testEquivalentHashes"); - - bytes = sun.misc.Hashing.murmur3_32(TWO_BYTE); - chars = sun.misc.Hashing.murmur3_32(ONE_CHAR); - if (bytes != chars) { - throw new RuntimeException(String.format("Hashes did not match. b:%08x != c:%08x", bytes, chars)); - } - - bytes = sun.misc.Hashing.murmur3_32(FOUR_BYTE); - chars = sun.misc.Hashing.murmur3_32(TWO_CHAR); - ints = sun.misc.Hashing.murmur3_32(ONE_INT); - if ((bytes != chars) || (bytes != ints)) { - throw new RuntimeException(String.format("Hashes did not match. b:%08x != c:%08x != i:%08x", bytes, chars, ints)); - } - bytes = sun.misc.Hashing.murmur3_32(SIX_BYTE); - chars = sun.misc.Hashing.murmur3_32(THREE_CHAR); - if (bytes != chars) { - throw new RuntimeException(String.format("Hashes did not match. b:%08x != c:%08x", bytes, chars)); - } - - bytes = sun.misc.Hashing.murmur3_32(EIGHT_BYTE); - chars = sun.misc.Hashing.murmur3_32(FOUR_CHAR); - ints = sun.misc.Hashing.murmur3_32(TWO_INT); - if ((bytes != chars) || (bytes != ints)) { - throw new RuntimeException(String.format("Hashes did not match. b:%08x != c:%08x != i:%08x", bytes, chars, ints)); - } - } - - public static void main(String[] args) { - testMurmur3_32_ByteArray(); - testEquivalentHashes(); - } -}