Fixed System.identityHashcode for all boxed types.

Also did some general cleanup.

Change-Id: I444b760ed17ce24d60f1d389cbbfd1a5550809b2
diff --git a/user/BUILD b/user/BUILD
index 2fb8d6f..7622b76 100644
--- a/user/BUILD
+++ b/user/BUILD
@@ -67,6 +67,7 @@
         exclude = [
             "src/com/google/gwt/junit/**/*.java",  # see gwt-testing
             "**/EmulatedCharset.java",
+            "**/HashCodes.java", # relies on java8 only APIs
             "**/RunStyleSelenium.java",
         ],
     ),
diff --git a/user/super/com/google/gwt/emul/java/lang/Boolean.java b/user/super/com/google/gwt/emul/java/lang/Boolean.java
index 68bcbc2..2b72e54 100644
--- a/user/super/com/google/gwt/emul/java/lang/Boolean.java
+++ b/user/super/com/google/gwt/emul/java/lang/Boolean.java
@@ -89,13 +89,9 @@
   }
 
   public boolean booleanValue() {
-    return unsafeCast(checkNotNull(this));
+    return JsUtils.unsafeCastToBoolean(checkNotNull(this));
   }
 
-  private static native boolean unsafeCast(Object value) /*-{
-    return value;
-  }-*/;
-
   @Override
   public int compareTo(Boolean b) {
     return compare(booleanValue(), b.booleanValue());
diff --git a/user/super/com/google/gwt/emul/java/lang/Double.java b/user/super/com/google/gwt/emul/java/lang/Double.java
index 2b4c11c..c2b05ca 100644
--- a/user/super/com/google/gwt/emul/java/lang/Double.java
+++ b/user/super/com/google/gwt/emul/java/lang/Double.java
@@ -323,13 +323,9 @@
 
   @Override
   public double doubleValue() {
-    return unsafeCast(checkNotNull(this));
+    return JsUtils.unsafeCastToDouble(checkNotNull(this));
   }
 
-  private static native double unsafeCast(Object instance) /*-{
-    return instance;
-  }-*/;
-
   @Override
   public boolean equals(Object o) {
     return checkNotNull(this) == o;
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 3b28b4e..cfe2586 100644
--- a/user/super/com/google/gwt/emul/java/lang/String.java
+++ b/user/super/com/google/gwt/emul/java/lang/String.java
@@ -458,7 +458,7 @@
 
   @Override
   public int hashCode() {
-    return HashCodes.hashCodeForString(this);
+    return HashCodes.getStringHashCode(this);
   }
 
   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 86c4c76..4abddc5 100644
--- a/user/super/com/google/gwt/emul/javaemul/internal/HashCodes.java
+++ b/user/super/com/google/gwt/emul/javaemul/internal/HashCodes.java
@@ -19,33 +19,24 @@
  * Contains logics for calculating hash codes in JavaScript.
  */
 public class HashCodes {
-
-  private static int sNextHashId = 0;
-  private static final String HASH_CODE_PROPERTY = "$H";
-
-  public static int hashCodeForString(String s) {
-    return StringHashCache.getHashCode(s);
-  }
-
   public static int getIdentityHashCode(Object o) {
-    if (o == null) {
-      return 0;
+    switch (JsUtils.typeOf(o)) {
+      case "string":
+        return getStringHashCode(JsUtils.unsafeCastToString(o));
+      case "number":
+        return Double.hashCode(JsUtils.unsafeCastToDouble(o));
+      case "boolean":
+        return Boolean.hashCode(JsUtils.unsafeCastToBoolean(o));
+      default:
+        return o == null ? 0 : getObjectIdentityHashCode(o);
     }
-    return o instanceof String
-        ?  hashCodeForString(JsUtils.unsafeCastToString(o)) : getObjectIdentityHashCode(o);
   }
 
-  public static native int getObjectIdentityHashCode(Object o) /*-{
-    return o.$H || (o.$H = @HashCodes::getNextHashId()());
-  }-*/;
+  public static int getObjectIdentityHashCode(Object o) {
+    return ObjectHashing.getHashCode(o);
+  }
 
-  /**
-   * 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;
+  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 09bd266..d9fad43 100644
--- a/user/super/com/google/gwt/emul/javaemul/internal/JsUtils.java
+++ b/user/super/com/google/gwt/emul/javaemul/internal/JsUtils.java
@@ -36,11 +36,18 @@
     return value === undefined;
   }-*/;
 
-  // TODO(goktug): replace this with a real cast when the compiler can optimize it.
   public static native String unsafeCastToString(Object string) /*-{
    return string;
   }-*/;
 
+  public static native double unsafeCastToDouble(Object number) /*-{
+   return number;
+  }-*/;
+
+  public static native boolean unsafeCastToBoolean(Object bool) /*-{
+   return bool;
+  }-*/;
+
   public static native <T> T getProperty(Object map, String key) /*-{
     return map[key];
   }-*/;
diff --git a/user/super/com/google/gwt/emul/javaemul/internal/ObjectHashing.java b/user/super/com/google/gwt/emul/javaemul/internal/ObjectHashing.java
new file mode 100644
index 0000000..8821833
--- /dev/null
+++ b/user/super/com/google/gwt/emul/javaemul/internal/ObjectHashing.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2016 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;
+
+/**
+ * Utility class to generate hash code for Objects.
+ */
+class ObjectHashing {
+
+  private static int nextHashId = 0;
+  private static final String HASH_CODE_PROPERTY = "$H";
+
+  public static native int getHashCode(Object o) /*-{
+    return o.$H || (o.$H = @ObjectHashing::getNextHashId()());
+  }-*/;
+
+  /**
+   * 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 ++nextHashId;
+  }
+}
diff --git a/user/test/com/google/gwt/emultest/java/lang/SystemTest.java b/user/test/com/google/gwt/emultest/java/lang/SystemTest.java
index fae4aa7..aaf7f2f 100644
--- a/user/test/com/google/gwt/emultest/java/lang/SystemTest.java
+++ b/user/test/com/google/gwt/emultest/java/lang/SystemTest.java
@@ -297,6 +297,21 @@
     assertEquals('a', charDest[offset + manyNulls.length]);
   }
 
+  public void testIdentityHashCode() {
+    String s = "str";
+    assertEquals(System.identityHashCode(s), System.identityHashCode(s));
+
+    Double d = 42d;
+    assertEquals(System.identityHashCode(d), System.identityHashCode(d));
+
+    Boolean b = true;
+    assertEquals(System.identityHashCode(b), System.identityHashCode(b));
+
+    Object o = new Object();
+    assertEquals(System.identityHashCode(o), System.identityHashCode(o));
+    assertNotSame(System.identityHashCode(o), System.identityHashCode(new Object()));
+  }
+
   @DoNotRunWith(Platform.Devel)
   public void testGetProperty() {
     if (TestUtils.isJvm()) {