Reduce JSNI around JsUtils helper.

Change-Id: I06476bea7113ed89afd78872e462685756a034f4
Review-Link: https://gwt-review.googlesource.com/#/c/18400/
diff --git a/dev/core/test/com/google/gwt/dev/CompilerTest.java b/dev/core/test/com/google/gwt/dev/CompilerTest.java
index 1e56f38..b8b9e8f 100644
--- a/dev/core/test/com/google/gwt/dev/CompilerTest.java
+++ b/dev/core/test/com/google/gwt/dev/CompilerTest.java
@@ -2745,6 +2745,8 @@
         "java.lang.CharSequence",
         "java.lang.Comparable",
         "java.lang.Double",
+        "java.lang.HasCharSequenceTypeMarker",
+        "java.lang.HasComparableTypeMarker",
         "java.lang.Number",
         "java.lang.String",
         "java.lang.String$NativeFunction",
diff --git a/user/super/com/google/gwt/emul/java/lang/CharSequence.java b/user/super/com/google/gwt/emul/java/lang/CharSequence.java
index 302b0c3..dc76d00 100644
--- a/user/super/com/google/gwt/emul/java/lang/CharSequence.java
+++ b/user/super/com/google/gwt/emul/java/lang/CharSequence.java
@@ -62,12 +62,12 @@
 
   // CHECKSTYLE_OFF: Utility methods.
   @JsMethod
-  static boolean $isInstance(Object instance) {
+  static boolean $isInstance(HasCharSequenceTypeMarker instance) {
     if (JsUtils.typeOf(instance).equals("string")) {
       return true;
     }
 
-    return instance != null && JsUtils.hasCharSequenceTypeMarker(instance);
+    return instance != null && instance.getTypeMarker() == true;
   }
   // CHECKSTYLE_ON: end utility methods
 }
diff --git a/user/super/com/google/gwt/emul/java/lang/Comparable.java b/user/super/com/google/gwt/emul/java/lang/Comparable.java
index 8e92784..73191d0 100644
--- a/user/super/com/google/gwt/emul/java/lang/Comparable.java
+++ b/user/super/com/google/gwt/emul/java/lang/Comparable.java
@@ -31,13 +31,13 @@
 
   // CHECKSTYLE_OFF: Utility methods.
   @JsMethod
-  static boolean $isInstance(Object instance) {
+  static boolean $isInstance(HasComparableTypeMarker instance) {
     String type = JsUtils.typeOf(instance);
     if (type.equals("boolean") || type.equals("number") || type.equals("string")) {
       return true;
     }
 
-    return instance != null && JsUtils.hasComparableTypeMarker(instance);
+    return instance != null && instance.getTypeMarker() == true;
   }
   // CHECKSTYLE_ON: end utility methods
 }
diff --git a/user/super/com/google/gwt/emul/java/lang/HasCharSequenceTypeMarker.java b/user/super/com/google/gwt/emul/java/lang/HasCharSequenceTypeMarker.java
new file mode 100644
index 0000000..ed2855c
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/lang/HasCharSequenceTypeMarker.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2017 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 java.lang;
+
+import jsinterop.annotations.JsPackage;
+import jsinterop.annotations.JsProperty;
+import jsinterop.annotations.JsType;
+
+@JsType(isNative = true, name = "*", namespace = JsPackage.GLOBAL)
+interface HasCharSequenceTypeMarker {
+  @JsProperty(name = "$implements__java_lang_CharSequence")
+  boolean getTypeMarker();
+}
diff --git a/user/super/com/google/gwt/emul/java/lang/HasComparableTypeMarker.java b/user/super/com/google/gwt/emul/java/lang/HasComparableTypeMarker.java
new file mode 100644
index 0000000..d060b49
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/lang/HasComparableTypeMarker.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2017 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 java.lang;
+
+import jsinterop.annotations.JsPackage;
+import jsinterop.annotations.JsProperty;
+import jsinterop.annotations.JsType;
+
+@JsType(isNative = true, name = "*", namespace = JsPackage.GLOBAL)
+interface HasComparableTypeMarker {
+  @JsProperty(name = "$implements__java_lang_Comparable")
+  boolean getTypeMarker();
+}
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 4c927f1..0fe193a 100644
--- a/user/super/com/google/gwt/emul/java/lang/String.java
+++ b/user/super/com/google/gwt/emul/java/lang/String.java
@@ -371,7 +371,11 @@
 
   @Override
   public int compareTo(String other) {
-    return JsUtils.compare(checkNotNull(this), checkNotNull(other));
+    // Trick compiler into thinking that these are double so what we could do arithmetic comparison
+    // which is supported on underlying JavaScript strings.
+    double a = JsUtils.unsafeCastToDouble(checkNotNull(this));
+    double b = JsUtils.unsafeCastToDouble(checkNotNull(other));
+    return a == b ? 0 : (a < b ? -1 : 1);
   }
 
   public int compareToIgnoreCase(String other) {
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 1d96828..d3ffe81 100644
--- a/user/super/com/google/gwt/emul/java/util/AbstractHashMap.java
+++ b/user/super/com/google/gwt/emul/java/util/AbstractHashMap.java
@@ -173,7 +173,7 @@
   @Override
   public boolean containsKey(Object key) {
     return key instanceof String
-        ? hasStringValue(JsUtils.unsafeCastToString(key)) : hasHashValue(key);
+        ? hasStringValue(JsUtils.uncheckedCast(key)) : hasHashValue(key);
   }
 
   @Override
@@ -199,21 +199,21 @@
   @Override
   public V get(Object key) {
     return key instanceof String
-        ? getStringValue(JsUtils.unsafeCastToString(key)) : getHashValue(key);
+        ? getStringValue(JsUtils.uncheckedCast(key)) : getHashValue(key);
   }
 
   @SpecializeMethod(params = {String.class, Object.class}, target = "putStringValue")
   @Override
   public V put(K key, V value) {
     return key instanceof String
-        ? putStringValue(JsUtils.unsafeCastToString(key), value) : putHashValue(key, value);
+        ? putStringValue(JsUtils.uncheckedCast(key), value) : putHashValue(key, value);
   }
 
   @SpecializeMethod(params = {String.class}, target = "removeStringValue")
   @Override
   public V remove(Object key) {
     return key instanceof String
-        ? removeStringValue(JsUtils.unsafeCastToString(key)) : removeHashValue(key);
+        ? removeStringValue(JsUtils.uncheckedCast(key)) : removeHashValue(key);
   }
 
   @Override
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 4abddc5..0a50eac 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.unsafeCastToString(o));
+        return getStringHashCode(JsUtils.uncheckedCast(o));
       case "number":
         return Double.hashCode(JsUtils.unsafeCastToDouble(o));
       case "boolean":
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 b2f128c..21a1d5a 100644
--- a/user/super/com/google/gwt/emul/javaemul/internal/JsUtils.java
+++ b/user/super/com/google/gwt/emul/javaemul/internal/JsUtils.java
@@ -16,6 +16,8 @@
 package javaemul.internal;
 
 import javaemul.internal.annotations.UncheckedCast;
+import jsinterop.annotations.JsMethod;
+import jsinterop.annotations.JsProperty;
 
 /**
  * Provides an interface for simple JavaScript idioms that can not be expressed in Java.
@@ -26,25 +28,25 @@
     return a == b ? 0 : (a < b ? -1 : 1);
   }-*/;
 
-  public static native boolean isFinite(double d) /*-{
-    return isFinite(d);
-  }-*/;
+  @JsMethod(namespace = "<window>")
+  public static native boolean isFinite(double d);
 
-  public static native boolean isNaN(double d) /*-{
-    return isNaN(d);
-  }-*/;
+  @JsMethod(namespace = "<window>")
+  public static native boolean isNaN(double d);
 
-  public static native int parseInt(String s, int radix) /*-{
-    return parseInt(s, radix);
-  }-*/;
+  @JsMethod(namespace = "<window>")
+  public static native int parseInt(String s, int radix);
 
-  public static native boolean isUndefined(Object value) /*-{
-    return value === undefined;
-  }-*/;
+  @JsProperty(namespace = "<window>")
+  public static native Object getUndefined();
 
-  public static native String unsafeCastToString(Object string) /*-{
-   return string;
-  }-*/;
+  public static boolean isUndefined(Object value) {
+    return isSame(value, getUndefined());
+  }
+
+  public static native boolean isSame(Object x, Object y) /*-{
+    return x === y;
+   }-*/;
 
   public static native double unsafeCastToDouble(Object number) /*-{
    return number;
@@ -82,13 +84,5 @@
   public static native String typeOf(Object o) /*-{
     return typeof o;
   }-*/;
-
-  public static native boolean hasComparableTypeMarker(Object o) /*-{
-    return o.$implements__java_lang_Comparable;
-  }-*/;
-
-  public static native boolean hasCharSequenceTypeMarker(Object o) /*-{
-    return o.$implements__java_lang_CharSequence;
-  }-*/;
 }