Remove dep on Impl & cleanup System.java.
- Move StringHashCache out of String into javaemul
- Introduce HashCodes class
Change-Id: I4e6ef7394e2f364cfc174cbd3fba74227b588236
diff --git a/user/src/com/google/gwt/core/client/JavaScriptObject.java b/user/src/com/google/gwt/core/client/JavaScriptObject.java
index 1097eaa..332bc7d 100644
--- a/user/src/com/google/gwt/core/client/JavaScriptObject.java
+++ b/user/src/com/google/gwt/core/client/JavaScriptObject.java
@@ -15,8 +15,6 @@
*/
package com.google.gwt.core.client;
-import com.google.gwt.core.client.impl.Impl;
-
/**
* An opaque handle to a native JavaScript object. A
* <code>JavaScriptObject</code> cannot be created directly.
@@ -147,9 +145,9 @@
* @return the hash code of the object
*/
@Override
- public final int hashCode() {
- return Impl.getHashCode(this);
- }
+ public final native int hashCode() /*-{
+ return @javaemul.internal.HashCodes::getObjectIdentityHashCode(*)(this);
+ }-*/;
/**
* Call the toSource() on the JSO.
diff --git a/user/src/com/google/gwt/core/client/impl/Impl.java b/user/src/com/google/gwt/core/client/impl/Impl.java
index 1aa1cb0..0626b19 100644
--- a/user/src/com/google/gwt/core/client/impl/Impl.java
+++ b/user/src/com/google/gwt/core/client/impl/Impl.java
@@ -1,12 +1,12 @@
/*
* Copyright 2008 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
@@ -33,7 +33,6 @@
* Used by {@link #entry0(Object, Object)} to handle reentrancy.
*/
private static int entryDepth = 0;
- private static int sNextHashId = 0;
/**
* TimeStamp indicating last scheduling of the entry depth watchdog.
@@ -81,19 +80,6 @@
};
}-*/;
- /**
- * Gets an identity-based hash code on the passed-in Object by adding an
- * expando. This method should not be used with <code>null</code> or any
- * String. The former will crash and the later will produce unstable results
- * when called repeatedly with a String primitive.
- * <p>
- * The sequence of hashcodes generated by this method are a
- * monotonically-increasing sequence.
- */
- public static native int getHashCode(Object o) /*-{
- return o.$H || (o.$H = @Impl::getNextHashId()());
- }-*/;
-
public static native String getHostPageBaseURL() /*-{
var s = $doc.location.href;
@@ -335,16 +321,6 @@
}
}
- /**
- * Called from JSNI. Do not change this implementation without updating:
- * <ul>
- * <li>{@link com.google.gwt.user.client.rpc.impl.SerializerBase}</li>
- * </ul>
- */
- private static int getNextHashId() {
- return ++sNextHashId;
- }
-
private static native Object undefined() /*-{
// Intentionally not returning a value
return;
diff --git a/user/src/com/google/gwt/user/client/rpc/impl/SerializerBase.java b/user/src/com/google/gwt/user/client/rpc/impl/SerializerBase.java
index e6d894a..93830c3 100644
--- a/user/src/com/google/gwt/user/client/rpc/impl/SerializerBase.java
+++ b/user/src/com/google/gwt/user/client/rpc/impl/SerializerBase.java
@@ -29,7 +29,7 @@
/**
* Maps class literals to type signatures and type signatures to serialization
* methods. Relies on monotonic behavior of hashcodes in Production Mode defined
- * in {@link com.google.gwt.core.client.impl.Impl#getHashCode(Object)} In hosted
+ * in {@link javaemul.internal.HashCodes#getObjectIdentityHashcode(Object)} In hosted
* mode, we map the underlying signature JsArray onto a proper IdentityHashMap.
*/
public abstract class SerializerBase implements Serializer {
diff --git a/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java b/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java
index 8aa3df1..00b0dfe 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java
@@ -1,12 +1,12 @@
/*
* Copyright 2008 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
@@ -68,10 +68,10 @@
* Default number of types to split createMethodMap entries into. Zero means
* no sharding occurs. Stored as a string since it is used as a default
* property value.
- *
+ *
* Note that the inliner will likely reassemble the shards if it is used in
* Production Mode, but it isn't needed there anyway.
- *
+ *
* TODO: remove this (and related code) when it is no longer needed.
*/
private static final String DEFAULT_CREATEMETHODMAP_SHARD_SIZE = "0";
@@ -413,7 +413,7 @@
/**
* Writes constructor.
- *
+ *
* <pre>
* public SchoolCalendarService_TypeSerializer() {
* super(methodMapJava, methodMapNative, signatureMapJava, signatureMapNative);
@@ -435,7 +435,7 @@
* Writes a method to produce a map of type string -> class name of
* {@link TypeHandler} for Java. We are forced to use repeated helper methods to populate the map
* because of the limit on Java method size.
- *
+ *
* <pre>
* private static Map<String, String> loadMethodsJava() {
* Map<String, String> result = new HashMap<String, String>();
@@ -521,7 +521,7 @@
/**
* Writes a method to produce a native map of type string -> handler funcs.
- *
+ *
* <pre>
* private static native MethodMap loadMethodsNative() /*-{
* var result = {};
@@ -682,7 +682,7 @@
/**
* Writes a method to produce a native map of system hash code to type string.
- *
+ *
* <pre>
* private static native JsArrayString loadSignaturesNative() /*-{
* var result = [];
@@ -720,7 +720,7 @@
}
srcWriter
- .println("result[@com.google.gwt.core.client.impl.Impl::getHashCode(Ljava/lang/Object;)(@"
+ .println("result[@javaemul.internal.HashCodes::getObjectIdentityHashCode(*)(@"
+ type.getQualifiedSourceName() + "::class)] = \"" + typeString + "\";");
}
@@ -736,7 +736,7 @@
/**
* Writes the class's static fields.
- *
+ *
* <pre>
* private static final Map<String, String> methodMapJava;
* private static final MethodMap methodMapNative;
@@ -757,7 +757,7 @@
/**
* Statically initializes the class fields either for script or JVM.
- *
+ *
* <pre>
* static {
* if (GWT.isScript()) {
@@ -791,7 +791,7 @@
/**
* Write an entry in the methodMapNative for one type.
- *
+ *
* @param type type to generate entry for
*/
private void writeTypeMethodsNative(JType type) {
diff --git a/user/super/com/google/gwt/emul/java/lang/Object.java b/user/super/com/google/gwt/emul/java/lang/Object.java
index 63717d2..717f250 100644
--- a/user/super/com/google/gwt/emul/java/lang/Object.java
+++ b/user/super/com/google/gwt/emul/java/lang/Object.java
@@ -1,12 +1,12 @@
/*
* Copyright 2008 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
@@ -16,7 +16,8 @@
package java.lang;
import com.google.gwt.core.client.JavaScriptObject;
-import com.google.gwt.core.client.impl.Impl;
+
+import javaemul.internal.HashCodes;
/**
* The superclass of all other types. The GWT emulation library supports a
@@ -36,7 +37,7 @@
/**
* Used by {@link com.google.gwt.core.client.impl.WeakMapping} in web mode
* to store an expando containing a String -> Object mapping.
- *
+ *
* @skip
*/
@SuppressWarnings("unused")
@@ -44,7 +45,7 @@
/**
* A JavaScript Json map for looking up castability between types.
- *
+ *
* @skip
*/
@SuppressWarnings("unused")
@@ -55,9 +56,9 @@
* is used for distinguishing whether an object is a Java object or a
* JavaScriptObject. It is also used to differentiate our own Java objects
* from foreign objects in a different module on the same page.
- *
+ *
* @see com.google.gwt.lang.Cast
- *
+ *
* @skip
*/
@SuppressWarnings("unused")
@@ -76,7 +77,7 @@
}
public int hashCode() {
- return Impl.getHashCode(this);
+ return HashCodes.getObjectIdentityHashCode(this);
}
public String toString() {
@@ -85,7 +86,7 @@
/**
* Never called; here for JRE compatibility.
- *
+ *
* @skip
*/
protected void finalize() throws Throwable {
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 aa14cf7..77d3d2e 100644
--- a/user/super/com/google/gwt/emul/java/lang/String.java
+++ b/user/super/com/google/gwt/emul/java/lang/String.java
@@ -16,9 +16,6 @@
package java.lang;
-import static com.google.gwt.core.client.impl.Coercions.ensureInt;
-
-import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.impl.DoNotInline;
import java.io.Serializable;
@@ -26,6 +23,8 @@
import java.util.Comparator;
import java.util.Locale;
+import javaemul.internal.HashCodes;
+
/**
* Intrinsic string class.
*/
@@ -84,88 +83,6 @@
* IMPORTANT NOTE: if newer JREs add new interfaces to String, please update
* {@link Devirtualizer} and {@link JavaResourceBase}
*/
-
- /**
- * Hashcode caching for strings.
- */
- static final class HashCache {
- /**
- * The "old" cache; it will be dumped when front is full.
- */
- static JavaScriptObject back = JavaScriptObject.createObject();
- /**
- * Tracks the number of entries in front.
- */
- static int count = 0;
- /**
- * The "new" cache; it will become back when it becomes full.
- */
- static JavaScriptObject front = JavaScriptObject.createObject();
- /**
- * Pulled this number out of thin air.
- */
- static final int MAX_CACHE = 256;
-
- public static native int getHashCode(String str) /*-{
- // Accesses must to be prefixed with ':' to prevent conflict with built-in
- // JavaScript properties.
- var key = ':' + str;
-
- // Check the front store.
- var result = @java.lang.String.HashCache::front[key];
- if (result != null) {
- return result;
- }
-
- // Check the back store.
- result = @java.lang.String.HashCache::back[key];
- if (result == null) {
- // Compute the value.
- result = @java.lang.String.HashCache::compute(Ljava/lang/String;)(str);
- }
- // Increment can trigger the swap/flush; call after checking back but
- // before writing to front.
- @java.lang.String.HashCache::increment()();
- return @java.lang.String.HashCache::front[key] = result;
- }-*/;
-
- 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;
- }
-
- static void increment() {
- if (count == MAX_CACHE) {
- back = front;
- front = JavaScriptObject.createObject();
- count = 0;
- }
- ++count;
- }
- }
-
public static final Comparator<String> CASE_INSENSITIVE_ORDER = new Comparator<String>() {
@Override
public int compare(String a, String b) {
@@ -716,7 +633,7 @@
@Override
public int hashCode() {
- return HashCache.getHashCode(this);
+ return HashCodes.hashCodeForString(this);
}
public int indexOf(int codePoint) {
diff --git a/user/super/com/google/gwt/emul/java/lang/System.java b/user/super/com/google/gwt/emul/java/lang/System.java
index 4a1e705..42fcd0e 100644
--- a/user/super/com/google/gwt/emul/java/lang/System.java
+++ b/user/super/com/google/gwt/emul/java/lang/System.java
@@ -19,11 +19,12 @@
import static java.internal.InternalPreconditions.checkNotNull;
import com.google.gwt.core.client.JsDate;
-import com.google.gwt.core.client.impl.Impl;
import java.internal.ArrayHelper;
import java.io.PrintStream;
+import javaemul.internal.HashCodes;
+
/**
* General-purpose low-level utility methods. GWT only supports a limited subset
* of these methods due to browser limitations. Only the documented methods are
@@ -35,13 +36,13 @@
* Does nothing in web mode. To get output in web mode, subclass PrintStream
* and call {@link #setErr(PrintStream)}.
*/
- public static final PrintStream err = new PrintStream(null);
+ public static PrintStream err = new PrintStream(null);
/**
* Does nothing in web mode. To get output in web mode, subclass
* {@link PrintStream} and call {@link #setOut(PrintStream)}.
*/
- public static final PrintStream out = new PrintStream(null);
+ public static PrintStream out = new PrintStream(null);
public static void arraycopy(Object src, int srcOfs, Object dest, int destOfs, int len) {
checkNotNull(src, "src");
@@ -116,22 +117,16 @@
}
public static int identityHashCode(Object o) {
- return (o == null) ? 0 : (!(o instanceof String)) ? Impl.getHashCode(o)
- : String.HashCache.getHashCode(unsafeCast(o));
+ return HashCodes.getIdentityHashCode(o);
}
- // TODO(goktug): replace unsafeCast with a real cast when the compiler can optimize it.
- private static native String unsafeCast(Object string) /*-{
- return string;
- }-*/;
+ public static void setErr(PrintStream err) {
+ System.err = err;
+ }
- public static native void setErr(PrintStream err) /*-{
- @java.lang.System::err = err;
- }-*/;
-
- public static native void setOut(PrintStream out) /*-{
- @java.lang.System::out = out;
- }-*/;
+ public static void setOut(PrintStream out) {
+ System.out = out;
+ }
private static boolean arrayTypeMatch(Class<?> srcComp, Class<?> destComp) {
if (srcComp.isPrimitive()) {
diff --git a/user/super/com/google/gwt/emul/java/util/IdentityHashMap.java b/user/super/com/google/gwt/emul/java/util/IdentityHashMap.java
index 4320297..1f424a0 100644
--- a/user/super/com/google/gwt/emul/java/util/IdentityHashMap.java
+++ b/user/super/com/google/gwt/emul/java/util/IdentityHashMap.java
@@ -1,12 +1,12 @@
/*
* Copyright 2011 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
@@ -15,15 +15,15 @@
*/
package java.util;
-import com.google.gwt.core.client.impl.Impl;
-
import java.io.Serializable;
+import javaemul.internal.HashCodes;
+
/**
* Map using reference equality on keys. <a
* href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/IdentityHashMap.html">[Sun
* docs]</a>
- *
+ *
* @param <K> key type
* @param <V> value type
*/
@@ -102,6 +102,6 @@
@Override
int getHashCode(Object key) {
- return Impl.getHashCode(key);
+ return HashCodes.getObjectIdentityHashCode(key);
}
}
diff --git a/user/super/com/google/gwt/emul/javaemul/internal/HashCodes.java b/user/super/com/google/gwt/emul/javaemul/internal/HashCodes.java
new file mode 100644
index 0000000..eebce72
--- /dev/null
+++ b/user/super/com/google/gwt/emul/javaemul/internal/HashCodes.java
@@ -0,0 +1,55 @@
+/*
+ * 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;
+
+/**
+ * Contains logics for calculating hash codes in JavaScript.
+ */
+public class HashCodes {
+
+ private static int sNextHashId = 0;
+
+ public static int hashCodeForString(String s) {
+ return StringHashCache.getHashCode(s);
+ }
+
+ public static int getIdentityHashCode(Object o) {
+ if (o == null) {
+ return 0;
+ }
+ return o instanceof String
+ ? hashCodeForString(unsafeCast(o)) : getObjectIdentityHashCode(o);
+ }
+
+ public static native int getObjectIdentityHashCode(Object o) /*-{
+ return o.$H || (o.$H = @HashCodes::getNextHashId()());
+ }-*/;
+
+ // TODO(goktug): replace unsafeCast with a real cast when the compiler can optimize it.
+ private static native String unsafeCast(Object string) /*-{
+ return string;
+ }-*/;
+
+ /**
+ * Called from JSNI. Do not change this implementation without updating:
+ * <ul>
+ * <li>{@link com.google.gwt.user.client.rpc.impl.SerializerBase}</li>
+ * </ul>
+ */
+ private static int getNextHashId() {
+ return ++sNextHashId;
+ }
+}
diff --git a/user/super/com/google/gwt/emul/javaemul/internal/StringHashCache.java b/user/super/com/google/gwt/emul/javaemul/internal/StringHashCache.java
new file mode 100644
index 0000000..99721c1
--- /dev/null
+++ b/user/super/com/google/gwt/emul/javaemul/internal/StringHashCache.java
@@ -0,0 +1,119 @@
+/*
+ * 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 com.google.gwt.core.client.impl.Coercions.ensureInt;
+
+/**
+ * Hashcode caching for strings.
+ */
+class StringHashCache {
+ /**
+ * The "old" cache; it will be dumped when front is full.
+ */
+ private static Object back = createMap();
+ /**
+ * 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 = createMap();
+ /**
+ * 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.
+ Object result = get(front, key);
+ if (!isUndefined(result)) {
+ return cast(result);
+ }
+ // Check the back store.
+ result = get(back, key);
+ int hashCode = isUndefined(result) ? compute(str) : cast(result);
+ // Increment can trigger the swap/flush; call after checking back but
+ // before writing to front.
+ increment();
+ set(front, key, 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 = createMap();
+ count = 0;
+ }
+ ++count;
+ }
+
+ private static native Object get(Object map, String key) /*-{
+ return map[key];
+ }-*/;
+
+ private static native Object set(Object map, String key, int value) /*-{
+ map[key] = value;
+ }-*/;
+
+ // Note: we are explicitly checking for undefined since '0 == null' equals true in JavaScript
+ private static native boolean isUndefined(Object o) /*-{
+ return o === undefined;
+ }-*/;
+
+ private static native int cast(Object o) /*-{
+ return o;
+ }-*/;
+
+ private static native Object createMap() /*-{
+ return {};
+ }-*/;
+}
+