8010325: Remove hash32() method and hash32 int field from java.lang.String
authorbchristi
Wed, 12 Jun 2013 11:11:59 -0700
changeset 18166 a24e00a7c5ae
parent 18165 4000e5ca7aa0
child 18167 fb6a6363109c
child 18561 3286e2e1da31
8010325: Remove hash32() method and hash32 int field from java.lang.String Reviewed-by: alanb, mduigou
jdk/src/share/classes/java/lang/String.java
jdk/src/share/classes/java/util/HashMap.java
jdk/src/share/classes/java/util/Hashtable.java
jdk/src/share/classes/java/util/WeakHashMap.java
jdk/src/share/classes/sun/misc/Hashing.java
jdk/test/sun/misc/Hashing.java
--- a/jdk/src/share/classes/java/lang/String.java	Wed Jun 12 09:44:34 2013 +0100
+++ b/jdk/src/share/classes/java/lang/String.java	Wed Jun 12 11:11:59 2013 -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.
-    * <p>
-    * The general contract of {@code hash32} is:
-    * <ul>
-    * <li>Whenever it is invoked on the same object more than once during
-    *     an execution of a Java application, the {@code hash32} method
-    *     must consistently return the same integer, provided no information
-    *     used in {@code equals} comparisons on the object is modified.
-    *     This integer need not remain consistent from one execution of an
-    *     application to another execution of the same application.
-    * <li>If two objects are equal according to the {@code equals(Object)}
-    *     method, then calling the {@code hash32} method on each of
-    *     the two objects must produce the same integer result.
-    * <li>It is <em>not</em> required that if two objects are unequal
-    *     according to the {@link java.lang.Object#equals(java.lang.Object)}
-    *     method, then calling the {@code hash32} method on each of the
-    *     two objects must produce distinct integer results.  However, the
-    *     programmer should be aware that producing distinct integer results
-    *     for unequal objects may improve the performance of hash tables.
-    * </ul>
-    *
-    * 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;
-    }
-
 }
--- a/jdk/src/share/classes/java/util/HashMap.java	Wed Jun 12 09:44:34 2013 +0100
+++ b/jdk/src/share/classes/java/util/HashMap.java	Wed Jun 12 11:11:59 2013 -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 (seed != 0) ? 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));
+                                         (seed != 0) ? seed : 1);
         }
         table = EMPTY_TABLE;
 
--- a/jdk/src/share/classes/java/util/Hashtable.java	Wed Jun 12 09:44:34 2013 +0100
+++ b/jdk/src/share/classes/java/util/Hashtable.java	Wed Jun 12 11:11:59 2013 -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 (seed != 0) ? seed : 1;
         }
         return 0;
     }
@@ -1206,8 +1208,9 @@
 
         // set hashMask
         if (Holder.USE_HASHSEED) {
+            int seed = ThreadLocalRandom.current().nextInt();
             Holder.UNSAFE.putIntVolatile(this, Holder.HASHSEED_OFFSET,
-                    sun.misc.Hashing.randomHashSeed(this));
+                                         (seed != 0) ? seed : 1);
         }
 
         // Read the original length of the array and number of elements
--- a/jdk/src/share/classes/java/util/WeakHashMap.java	Wed Jun 12 09:44:34 2013 +0100
+++ b/jdk/src/share/classes/java/util/WeakHashMap.java	Wed Jun 12 11:11:59 2013 -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 = (seed != 0) ? seed : 1;
         }
     }
 
--- a/jdk/src/share/classes/sun/misc/Hashing.java	Wed Jun 12 09:44:34 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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;
-    }
-}
--- a/jdk/test/sun/misc/Hashing.java	Wed Jun 12 09:44:34 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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();
-    }
-}