Cleanup JSNI methods.

Introduce a new JsUtils which contains relevant JSNI methods
and make JRE use it mostly.

Change-Id: Ib5ba3d5deac0222b8f24da8d422f98bbb45a78cc
Review-Link: https://gwt-review.googlesource.com/#/c/13362/
diff --git a/dev/core/super/javaemul/internal/ArrayHelper.java b/dev/core/super/javaemul/internal/ArrayHelper.java
index aed00fc..9f466f3 100644
--- a/dev/core/super/javaemul/internal/ArrayHelper.java
+++ b/dev/core/super/javaemul/internal/ArrayHelper.java
@@ -44,6 +44,10 @@
     return new Array(length);
   }-*/;
 
+  public static native int getLength(Object array) /*-{
+    return array.length;
+  }-*/;
+
   public static native void setLength(Object array, int length)/*-{
     array.length = length;
   }-*/;
diff --git a/dev/core/super/javaemul/internal/HashCodes.java b/dev/core/super/javaemul/internal/HashCodes.java
index eebce72..86c4c76 100644
--- a/dev/core/super/javaemul/internal/HashCodes.java
+++ b/dev/core/super/javaemul/internal/HashCodes.java
@@ -21,6 +21,7 @@
 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);
@@ -31,18 +32,13 @@
       return 0;
     }
     return o instanceof String
-        ?  hashCodeForString(unsafeCast(o)) : getObjectIdentityHashCode(o);
+        ?  hashCodeForString(JsUtils.unsafeCastToString(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>
diff --git a/dev/core/super/javaemul/internal/JsUtils.java b/dev/core/super/javaemul/internal/JsUtils.java
new file mode 100644
index 0000000..6d4e74e
--- /dev/null
+++ b/dev/core/super/javaemul/internal/JsUtils.java
@@ -0,0 +1,48 @@
+/*
+ * 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;
+
+/**
+ * Provides an interface for simple JavaScript idioms that can not be expressed in Java.
+ */
+public class JsUtils {
+
+  public static native double getInfinity() /*-{
+    return Infinity;
+  }-*/;
+
+  public static native int parseInt(String s, int radix) /*-{
+    return parseInt(s, radix);
+  }-*/;
+
+  public static native boolean isUndefined(Object value) /*-{
+    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 int getIntProperty(Object map, String key) /*-{
+    return map[key];
+  }-*/;
+
+  public static native void setIntProperty(Object map, String key, int value) /*-{
+    map[key] = value;
+  }-*/;
+}
+
diff --git a/dev/core/super/javaemul/internal/StringHashCache.java b/dev/core/super/javaemul/internal/StringHashCache.java
index be5b03c..d472de9 100644
--- a/dev/core/super/javaemul/internal/StringHashCache.java
+++ b/dev/core/super/javaemul/internal/StringHashCache.java
@@ -24,7 +24,7 @@
   /**
    * The "old" cache; it will be dumped when front is full.
    */
-  private static Object back = createMap();
+  private static Object back = createNativeObject();
   /**
    * Tracks the number of entries in front.
    */
@@ -32,7 +32,7 @@
   /**
    * The "new" cache; it will become back when it becomes full.
    */
-  private static Object front = createMap();
+  private static Object front = createNativeObject();
   /**
    * Pulled this number out of thin air.
    */
@@ -44,17 +44,17 @@
     String key = ":" + str;
 
     // Check the front store.
-    Object result = get(front, key);
-    if (!isUndefined(result)) {
-      return cast(result);
+    Object result = getProperty(front, key);
+    if (!JsUtils.isUndefined(result)) {
+      return unsafeCastToInt(result);
     }
     // Check the back store.
-    result = get(back, key);
-    int hashCode = isUndefined(result) ? compute(str) : cast(result);
+    result = getProperty(back, key);
+    int hashCode = JsUtils.isUndefined(result) ? compute(str) : unsafeCastToInt(result);
     // Increment can trigger the swap/flush; call after checking back but
     // before writing to front.
     increment();
-    set(front, key, hashCode);
+    JsUtils.setIntProperty(front, key, hashCode);
 
     return hashCode;
   }
@@ -89,31 +89,21 @@
   private static void increment() {
     if (count == MAX_CACHE) {
       back = front;
-      front = createMap();
+      front = createNativeObject();
       count = 0;
     }
     ++count;
   }
 
-  private static native Object get(Object map, String key) /*-{
+  private static native Object getProperty(Object map, String key) /*-{
     return map[key];
   }-*/;
 
-  private static native void 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() /*-{
+  private static native Object createNativeObject() /*-{
     return {};
   }-*/;
-}
 
+  private static native int unsafeCastToInt(Object o) /*-{
+    return o;
+  }-*/;
+}
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 e1514d3..f75e195 100644
--- a/user/super/com/google/gwt/emul/java/lang/Double.java
+++ b/user/super/com/google/gwt/emul/java/lang/Double.java
@@ -15,6 +15,8 @@
  */
 package java.lang;
 
+import javaemul.internal.JsUtils;
+
 /**
  * Wraps a primitive <code>double</code> as an object.
  */
@@ -193,9 +195,9 @@
     return (int) d;
   }
 
-  public static native boolean isInfinite(double x) /*-{
-    return !isFinite(x) && !isNaN(x);
-  }-*/;
+  public static boolean isInfinite(double x) {
+    return x == JsUtils.getInfinity() || x == -JsUtils.getInfinity();
+  }
 
   public static native boolean isNaN(double x) /*-{
     return isNaN(x);
diff --git a/user/super/com/google/gwt/emul/java/lang/Float.java b/user/super/com/google/gwt/emul/java/lang/Float.java
index c1242ce..5d3647b 100644
--- a/user/super/com/google/gwt/emul/java/lang/Float.java
+++ b/user/super/com/google/gwt/emul/java/lang/Float.java
@@ -31,7 +31,6 @@
   public static final Class<Float> TYPE = float.class;
 
   private static final long POWER_31_INT = 2147483648L;
-  private static final long POWER_32_INT = 4294967296L;
 
   public static int compare(float x, float y) {
     return Double.compare(x, y);
@@ -131,13 +130,13 @@
     return (float) Double.longBitsToDouble(bits64);
   }
 
-  public static native boolean isInfinite(float x) /*-{
-    return !isFinite(x) && !isNaN(x);
-  }-*/;
+  public static boolean isInfinite(float x) {
+    return Double.isInfinite(x);
+  }
 
-  public static native boolean isNaN(float x) /*-{
-    return isNaN(x);
-  }-*/;
+  public static boolean isNaN(float x) {
+    return Double.isNaN(x);
+  }
 
   public static float parseFloat(String s) throws NumberFormatException {
     double doubleValue = __parseAndValidateDouble(s);
diff --git a/user/super/com/google/gwt/emul/java/lang/Integer.java b/user/super/com/google/gwt/emul/java/lang/Integer.java
index bf834cf..948bf75 100644
--- a/user/super/com/google/gwt/emul/java/lang/Integer.java
+++ b/user/super/com/google/gwt/emul/java/lang/Integer.java
@@ -265,6 +265,7 @@
     return (byte) value;
   }
 
+  @Override
   public int compareTo(Integer b) {
     return compare(value, b.value);
   }
diff --git a/user/super/com/google/gwt/emul/java/lang/Long.java b/user/super/com/google/gwt/emul/java/lang/Long.java
index e83bd2d..77a3fd3 100644
--- a/user/super/com/google/gwt/emul/java/lang/Long.java
+++ b/user/super/com/google/gwt/emul/java/lang/Long.java
@@ -249,6 +249,7 @@
     return (byte) value;
   }
 
+  @Override
   public int compareTo(Long b) {
     return compare(value, b.value);
   }
diff --git a/user/super/com/google/gwt/emul/java/lang/Math.java b/user/super/com/google/gwt/emul/java/lang/Math.java
index f351858..620e617 100644
--- a/user/super/com/google/gwt/emul/java/lang/Math.java
+++ b/user/super/com/google/gwt/emul/java/lang/Math.java
@@ -15,6 +15,8 @@
  */
 package java.lang;
 
+import javaemul.internal.JsUtils;
+
 /**
  * Math utility methods and constants.
  */
@@ -100,9 +102,9 @@
     return Math.cos(x);
   }-*/;
 
-  public static native double cosh(double x) /*-{
+  public static double cosh(double x) {
     return (Math.exp(x) + Math.exp(-x)) / 2.0;
-  }-*/;
+  }
 
   public static native double exp(double x) /*-{
     return Math.exp(x);
@@ -197,8 +199,13 @@
     return (long) round0(x);
   }
 
-  public static native int round(float x) /*-{
-    return Math.round(x);
+  public static int round(float x) {
+    double roundedValue = round0(x);
+    return unsafeCastToInt(roundedValue);
+  }
+
+  private static native int unsafeCastToInt(double d) /*-{
+    return d;
   }-*/;
 
   public static double scalb(double d, int scaleFactor) {
@@ -249,9 +256,9 @@
     return Math.sin(x);
   }-*/;
 
-  public static native double sinh(double x) /*-{
-    return (Math.exp(x) - Math.exp(-x)) / 2.0;
-  }-*/;
+  public static double sinh(double x) {
+    return (Math.exp(x) - Math.exp(-x)) / 2.0d;
+  }
 
   public static native double sqrt(double x) /*-{
     return Math.sqrt(x);
@@ -261,13 +268,16 @@
     return Math.tan(x);
   }-*/;
 
-  public static native double tanh(double x) /*-{
-    if (x == Infinity) {
-      return 1.0;
+  public static double tanh(double x) {
+    if (x == JsUtils.getInfinity()) {
+      return 1.0d;
+    } else if (x == -JsUtils.getInfinity()) {
+      return -1.0d;
     }
-    var e2x = Math.exp(2.0 * x);
+
+    double e2x = Math.exp(2.0 * x);
     return (e2x - 1) / (e2x + 1);
-  }-*/;
+  }
 
   public static double toDegrees(double x) {
     return x * PI_UNDER_180;
diff --git a/user/super/com/google/gwt/emul/java/lang/Number.java b/user/super/com/google/gwt/emul/java/lang/Number.java
index 4277725..b406810 100644
--- a/user/super/com/google/gwt/emul/java/lang/Number.java
+++ b/user/super/com/google/gwt/emul/java/lang/Number.java
@@ -17,6 +17,8 @@
 
 import java.io.Serializable;
 
+import javaemul.internal.JsUtils;
+
 /**
  * Abstract base class for numeric wrapper classes.
  */
@@ -178,9 +180,13 @@
     if (!__isValidDouble(s)) {
       throw NumberFormatException.forInputString(s);
     }
-    return __parseDouble(s);
+    return parseFloat(s);
   }
 
+  private static native double parseFloat(String str) /*-{
+    return parseFloat(str);
+  }-*/;
+
   /**
    * @skip
    *
@@ -205,11 +211,11 @@
       }
     }
 
-    int toReturn = __parseInt(s, radix);
+    int toReturn = JsUtils.parseInt(s, radix);
     // isTooLow is separated into its own variable to avoid a bug in BlackBerry OS 7. See
     // https://code.google.com/p/google-web-toolkit/issues/detail?id=7291.
     boolean isTooLow = toReturn < lowerBound;
-    if (__isNaN(toReturn)) {
+    if (Double.isNaN(toReturn)) {
       throw NumberFormatException.forInputString(s);
     } else if (isTooLow || toReturn > upperBound) {
       throw NumberFormatException.forInputString(s);
@@ -277,14 +283,14 @@
     if (head > 0) {
       // accumulate negative numbers, as -Long.MAX_VALUE == Long.MIN_VALUE + 1
       // (in other words, -Long.MIN_VALUE overflows, see issue 7308)
-      toReturn = - __parseInt(s.substring(0, head), radix);
+      toReturn = - JsUtils.parseInt(s.substring(0, head), radix);
       s = s.substring(head);
       length -= head;
       firstTime = false;
     }
 
     while (length >= maxDigits) {
-      head = __parseInt(s.substring(0, maxDigits), radix);
+      head = JsUtils.parseInt(s.substring(0, maxDigits), radix);
       s = s.substring(maxDigits);
       length -= maxDigits;
       if (!firstTime) {
@@ -316,22 +322,15 @@
 
   /**
    * @skip
-   */
-  private static native boolean __isNaN(double x) /*-{
-    return isNaN(x);
-  }-*/;
-
-  /**
-   * @skip
    *
    * @param str
    * @return {@code true} if the string matches the float format, {@code false} otherwise
    */
   private static boolean __isValidDouble(String str) {
-      if (floatRegex == null) {
-        floatRegex = createFloatRegex();
-      }
-      return regexTest(floatRegex, str);
+    if (floatRegex == null) {
+      floatRegex = createFloatRegex();
+    }
+    return regexTest(floatRegex, str);
   }
 
   private static native Object createFloatRegex() /*-{
@@ -342,24 +341,6 @@
     return regex.test(value);
   }-*/;
 
-  /**
-   * @skip
-   *
-   * @return The floating-point representation of <code>str</code>.
-   */
-  private static native double __parseDouble(String str) /*-{
-    return parseFloat(str);
-  }-*/;
-
-  /**
-   * @skip
-   *
-   * Invokes the global JS function <code>parseInt()</code>.
-   */
-  private static native int __parseInt(String s, int radix) /*-{
-    return parseInt(s, radix);
-  }-*/;
-
   // CHECKSTYLE_ON
 
   public byte byteValue() {
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 0c46af0..9682b6c 100644
--- a/user/super/com/google/gwt/emul/java/lang/System.java
+++ b/user/super/com/google/gwt/emul/java/lang/System.java
@@ -56,8 +56,8 @@
     Class<?> destComp = destType.getComponentType();
     checkArrayType(arrayTypeMatch(srcComp, destComp), "Array types don't match");
 
-    int srclen = getArrayLength(src);
-    int destlen = getArrayLength(dest);
+    int srclen = ArrayHelper.getLength(src);
+    int destlen = ArrayHelper.getLength(dest);
     if (srcOfs < 0 || destOfs < 0 || len < 0 || srcOfs + len > srclen || destOfs + len > destlen) {
       throw new IndexOutOfBoundsException();
     }
@@ -134,11 +134,4 @@
       return !destComp.isPrimitive();
     }
   }
-
-  /**
-   * Returns the length of an array via Javascript.
-   */
-  private static native int getArrayLength(Object array) /*-{
-    return array.length;
-  }-*/;
 }
diff --git a/user/super/com/google/gwt/emul/java/math/BigDecimal.java b/user/super/com/google/gwt/emul/java/math/BigDecimal.java
index 6b2e125..a18d2f4 100644
--- a/user/super/com/google/gwt/emul/java/math/BigDecimal.java
+++ b/user/super/com/google/gwt/emul/java/math/BigDecimal.java
@@ -38,6 +38,8 @@
 
 import java.io.Serializable;
 
+import javaemul.internal.JsUtils;
+
 /**
  * This class represents immutable arbitrary precision decimal numbers. Each
  * {@code BigDecimal} instance is represented with a unscaled arbitrary
@@ -406,10 +408,6 @@
     return regexTest(unscaledRegex, str);
   }
 
-  public static native double parseInt(String value, int base) /*-{
-    return parseInt(value, base);
-  }-*/;
-
   private static native Object createBigDecimalUnscaledRegex() /*-{
     return /^[+-]?\d*$/i;
   }-*/;
@@ -419,7 +417,7 @@
   }-*/;
 
   private static double parseUnscaled(String str) {
-    return isValidBigUnscaledDecimal(str) ? parseInt(str, 10) : Double.NaN;
+    return isValidBigUnscaledDecimal(str) ? JsUtils.parseInt(str, 10) : Double.NaN;
   }
 
   /**
diff --git a/user/super/com/google/gwt/emul/java/util/AbstractHashMap.java b/user/super/com/google/gwt/emul/java/util/AbstractHashMap.java
index e66b3b0..1d27463 100644
--- a/user/super/com/google/gwt/emul/java/util/AbstractHashMap.java
+++ b/user/super/com/google/gwt/emul/java/util/AbstractHashMap.java
@@ -23,6 +23,7 @@
 import static javaemul.internal.InternalPreconditions.checkElement;
 import static javaemul.internal.InternalPreconditions.checkState;
 
+import javaemul.internal.JsUtils;
 import javaemul.internal.annotations.SpecializeMethod;
 
 /**
@@ -161,7 +162,8 @@
   @SpecializeMethod(params = {String.class}, target = "hasStringValue")
   @Override
   public boolean containsKey(Object key) {
-    return key instanceof String ? hasStringValue(unsafeCast(key)) : hasHashValue(key);
+    return key instanceof String
+        ? hasStringValue(JsUtils.unsafeCastToString(key)) : hasHashValue(key);
   }
 
   @Override
@@ -186,19 +188,22 @@
   @SpecializeMethod(params = {String.class}, target = "getStringValue")
   @Override
   public V get(Object key) {
-    return key instanceof String ? getStringValue(unsafeCast(key)) : getHashValue(key);
+    return key instanceof String
+        ? getStringValue(JsUtils.unsafeCastToString(key)) : getHashValue(key);
   }
 
   @SpecializeMethod(params = {String.class, Object.class}, target = "putStringValue")
   @Override
   public V put(K key, V value) {
-    return key instanceof String ? putStringValue(unsafeCast(key), value) : putHashValue(key, value);
+    return key instanceof String
+        ? putStringValue(JsUtils.unsafeCastToString(key), value) : putHashValue(key, value);
   }
 
   @SpecializeMethod(params = {String.class}, target = "removeStringValue")
   @Override
   public V remove(Object key) {
-    return key instanceof String ? removeStringValue(unsafeCast(key)) : removeHashValue(key);
+    return key instanceof String
+        ? removeStringValue(JsUtils.unsafeCastToString(key)) : removeHashValue(key);
   }
 
   @Override
@@ -288,9 +293,4 @@
   private V removeStringValue(String key) {
     return key == null ? removeHashValue(null) : stringMap.remove(key);
   }
-
-  // TODO(goktug): replace unsafeCast with a real cast when the compiler can optimize it.
-  private static native String unsafeCast(Object string) /*-{
-    return string;
-  }-*/;
 }
diff --git a/user/super/com/google/gwt/emul/java/util/ConcurrentModificationDetector.java b/user/super/com/google/gwt/emul/java/util/ConcurrentModificationDetector.java
index 2aa0a47..11d9ba7 100644
--- a/user/super/com/google/gwt/emul/java/util/ConcurrentModificationDetector.java
+++ b/user/super/com/google/gwt/emul/java/util/ConcurrentModificationDetector.java
@@ -15,33 +15,31 @@
  */
 package java.util;
 
+import javaemul.internal.JsUtils;
+
 /**
  * A helper to detect concurrent modifications to collections. This is implemented as a helper
  * utility so that we could remove the checks easily by a flag.
  */
 class ConcurrentModificationDetector {
 
+  private static final String MOD_COUNT_PROPERTY = "_gwt_modCount";
+
   public static void structureChanged(Object map) {
     // Ensure that modCount is initialized if it is not already.
-    int modCount = getModCount(map) | 0;
-    setModCount(map, modCount + 1);
+    int modCount = JsUtils.getIntProperty(map, MOD_COUNT_PROPERTY) | 0;
+    JsUtils.setIntProperty(map, MOD_COUNT_PROPERTY, modCount + 1);
   }
 
   public static void recordLastKnownStructure(Object host, Iterator<?> iterator) {
-    setModCount(iterator, getModCount(host));
+    int modCount = JsUtils.getIntProperty(host, MOD_COUNT_PROPERTY);
+    JsUtils.setIntProperty(iterator, MOD_COUNT_PROPERTY, modCount);
   }
-  
+
   public static void checkStructuralChange(Object host, Iterator<?> iterator) {
-    if (getModCount(iterator) != getModCount(host)) {
+    if (JsUtils.getIntProperty(iterator, MOD_COUNT_PROPERTY)
+        != JsUtils.getIntProperty(host, MOD_COUNT_PROPERTY)) {
       throw new ConcurrentModificationException();
     }
   }
-
-  private static native void setModCount(Object o, int modCount) /*-{
-    o._gwt_modCount = modCount;
-  }-*/;
-
-  private static native int getModCount(Object o) /*-{
-    return o._gwt_modCount;
-  }-*/;
 }
diff --git a/user/super/com/google/gwt/emul/java/util/InternalStringMap.java b/user/super/com/google/gwt/emul/java/util/InternalStringMap.java
index 10929b2..443d225 100644
--- a/user/super/com/google/gwt/emul/java/util/InternalStringMap.java
+++ b/user/super/com/google/gwt/emul/java/util/InternalStringMap.java
@@ -25,6 +25,8 @@
 import java.util.InternalJsMapFactory.InternalJsMap;
 import java.util.Map.Entry;
 
+import javaemul.internal.JsUtils;
+
 /**
  * A simple wrapper around JavaScript Map for key type is string.
  */
@@ -47,7 +49,7 @@
   }
 
   public boolean contains(String key) {
-    return !isUndefined(backingMap.get(key));
+    return !JsUtils.isUndefined(backingMap.get(key));
   }
 
   public V get(String key) {
@@ -58,7 +60,7 @@
     V oldValue = backingMap.get(key);
     backingMap.set(key, toNullIfUndefined(value));
 
-    if (isUndefined(oldValue)) {
+    if (JsUtils.isUndefined(oldValue)) {
       size++;
       structureChanged(host);
     } else {
@@ -69,7 +71,7 @@
 
   public V remove(String key) {
     V value = backingMap.get(key);
-    if (!isUndefined(value)) {
+    if (!JsUtils.isUndefined(value)) {
       backingMap.delete(key);
       size--;
       structureChanged(host);
@@ -136,10 +138,6 @@
   }
 
   private static <T> T toNullIfUndefined(T value) {
-    return isUndefined(value) ? null : value;
+    return JsUtils.isUndefined(value) ? null : value;
   }
-
-  private static native boolean isUndefined(Object value) /*-{
-    return value === undefined;
-  }-*/;
 }