Remove caching for String.hashcode
String hashcode is no longer used in HashMap and it is only used if it is directly called and it doesn't have a predictable performance. I don't see much value in keeping it around any longer.
PiperOrigin-RevId: 339796010
Change-Id: I51c45621bea02c48a5b5df316d11a7113643c048
diff --git a/user/super/com/google/gwt/emul/java/lang/String.java b/user/super/com/google/gwt/emul/java/lang/String.java
index 45ddd0e..3aba0d3 100644
--- a/user/super/com/google/gwt/emul/java/lang/String.java
+++ b/user/super/com/google/gwt/emul/java/lang/String.java
@@ -29,8 +29,8 @@
import java.util.Locale;
import java.util.StringJoiner;
import javaemul.internal.ArrayHelper;
+import javaemul.internal.Coercions;
import javaemul.internal.EmulatedCharset;
-import javaemul.internal.HashCodes;
import javaemul.internal.JsUtils;
import javaemul.internal.NativeRegExp;
import javaemul.internal.annotations.DoNotInline;
@@ -454,7 +454,12 @@
@Override
public int hashCode() {
- return HashCodes.getStringHashCode(this);
+ int h = 0;
+ for (int i = 0; i < length(); i++) {
+ // Following is the common hash function '(31 * h + x)' as '(x << 5) - x' equal to '31 * x'.
+ h = Coercions.ensureInt((h << 5) - h + charAt(i));
+ }
+ return h;
}
public int indexOf(int codePoint) {
diff --git a/user/super/com/google/gwt/emul/javaemul/internal/HashCodes.java b/user/super/com/google/gwt/emul/javaemul/internal/HashCodes.java
index 0a50eac..fa7cb68 100644
--- a/user/super/com/google/gwt/emul/javaemul/internal/HashCodes.java
+++ b/user/super/com/google/gwt/emul/javaemul/internal/HashCodes.java
@@ -22,7 +22,7 @@
public static int getIdentityHashCode(Object o) {
switch (JsUtils.typeOf(o)) {
case "string":
- return getStringHashCode(JsUtils.uncheckedCast(o));
+ return JsUtils.<String>uncheckedCast(o).hashCode();
case "number":
return Double.hashCode(JsUtils.unsafeCastToDouble(o));
case "boolean":
@@ -35,8 +35,4 @@
public static int getObjectIdentityHashCode(Object o) {
return ObjectHashing.getHashCode(o);
}
-
- public static int getStringHashCode(String s) {
- return StringHashCache.getHashCode(s);
- }
}
diff --git a/user/super/com/google/gwt/emul/javaemul/internal/JsUtils.java b/user/super/com/google/gwt/emul/javaemul/internal/JsUtils.java
index fa2dca9..efd46f1 100644
--- a/user/super/com/google/gwt/emul/javaemul/internal/JsUtils.java
+++ b/user/super/com/google/gwt/emul/javaemul/internal/JsUtils.java
@@ -55,9 +55,5 @@
public static native <T> T getProperty(Object map, String key) /*-{
return map[key];
}-*/;
-
- public static native void setProperty(Object map, String key, Object value) /*-{
- map[key] = value;
- }-*/;
}
diff --git a/user/super/com/google/gwt/emul/javaemul/internal/StringHashCache.java b/user/super/com/google/gwt/emul/javaemul/internal/StringHashCache.java
deleted file mode 100644
index c803422..0000000
--- a/user/super/com/google/gwt/emul/javaemul/internal/StringHashCache.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package javaemul.internal;
-
-import static javaemul.internal.Coercions.ensureInt;
-
-/**
- * Hashcode caching for strings.
- */
-class StringHashCache {
- /**
- * The "old" cache; it will be dumped when front is full.
- */
- private static Object back = new Object();
- /**
- * Tracks the number of entries in front.
- */
- private static int count = 0;
- /**
- * The "new" cache; it will become back when it becomes full.
- */
- private static Object front = new Object();
- /**
- * Pulled this number out of thin air.
- */
- private static final int MAX_CACHE = 256;
-
- public static int getHashCode(String str) {
- // Accesses must to be prefixed with ':' to prevent conflict with built-in
- // JavaScript properties.
- String key = ":" + str;
-
- // Check the front store.
- Double result = JsUtils.getProperty(front, key);
- if (result != null) {
- return result.intValue();
- }
- // Check the back store.
- result = JsUtils.getProperty(back, key);
- int hashCode = result == null ? compute(str) : result.intValue();
- // Increment can trigger the swap/flush; call after checking back but
- // before writing to front.
- increment();
- JsUtils.setProperty(front, key, (double) hashCode);
-
- return hashCode;
- }
-
- private static int compute(String str) {
- int hashCode = 0;
- int n = str.length();
- int nBatch = n - 4;
- int i = 0;
-
- // Process batches of 4 characters at a time and add them to the hash coercing to 32 bits
- while (i < nBatch) {
- hashCode = str.charAt(i + 3)
- + 31 * (str.charAt(i + 2)
- + 31 * (str.charAt(i + 1)
- + 31 * (str.charAt(i)
- + 31 * hashCode)));
-
- hashCode = ensureInt(hashCode); // make sure we don't overflow
- i += 4;
- }
-
- // Now process the leftovers
- while (i < n) {
- hashCode = hashCode * 31 + str.charAt(i++);
- }
- hashCode = ensureInt(hashCode); // make sure we don't overflow
-
- return hashCode;
- }
-
- private static void increment() {
- if (count == MAX_CACHE) {
- back = front;
- front = new Object();
- count = 0;
- }
- ++count;
- }
-}