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&lt;String, String&gt; loadMethodsJava() {
    *   Map&lt;String, String&gt; result = new HashMap&lt;String, String&gt;();
@@ -521,7 +521,7 @@
 
   /**
    * Writes a method to produce a native map of type string -> handler funcs.
-   * 
+   *
    * <pre>
    * private static native MethodMap loadMethodsNative() /&#42;-{
    *     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&lt;String, String&gt; 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 {};
+  }-*/;
+}
+