Cleans up more JSNI in JRE

Change-Id: I54377284ba524ab66ac2aa8f9a454920fe7cbc48
diff --git a/dev/build.xml b/dev/build.xml
index e138569..acc8422 100755
--- a/dev/build.xml
+++ b/dev/build.xml
@@ -39,7 +39,7 @@
       </classpath>
     </gwt.javac>
     <gwt.javac srcdir="" destdir="${javac.junit.out}"
-               excludes="**/EmulatedCharset.java,**/HashCodes.java,**/ConsoleLogger.java,**/SuperDevModeLogger.java">
+               excludes="**/EmulatedCharset.java,**/HashCodes.java,**/ConsoleLogger.java,**/NativeRegExp.java,**/SuperDevModeLogger.java">
       <src path="${gwt.root}/user/src" />
       <src path="${gwt.root}/user/super/com/google/gwt/emul/javaemul/internal"/>
       <compilerarg value="-Xep:MissingCasesInEnumSwitch:OFF" compiler="com.google.errorprone.ErrorProneAntCompilerAdapter"/>
diff --git a/dev/core/test/com/google/gwt/dev/CompilerTest.java b/dev/core/test/com/google/gwt/dev/CompilerTest.java
index b8b9e8f..a9d6465 100644
--- a/dev/core/test/com/google/gwt/dev/CompilerTest.java
+++ b/dev/core/test/com/google/gwt/dev/CompilerTest.java
@@ -2754,7 +2754,8 @@
         "java.lang.Throwable",
         "java.lang.Throwable$NativeError",
         "java.lang.Throwable$NativeTypeError",
-        "javaemul.internal.NativeRegExp"));
+        "javaemul.internal.NativeRegExp",
+        "javaemul.internal.NativeRegExp$Match"));
     return staleTypeNames;
   }
 
diff --git a/user/BUILD b/user/BUILD
index 591231c..0d38f60 100644
--- a/user/BUILD
+++ b/user/BUILD
@@ -94,6 +94,7 @@
             "**/SuperDevModeLogger.java",  # relies on ConsoleLogger
             "**/EmulatedCharset.java",
             "**/HashCodes.java",  # relies on java8 only APIs
+            "**/NativeRegExp.java",  # has default method
             "**/RunStyleSelenium.java",
         ] + JSINTEROP_SRCS,
     ),
diff --git a/user/build.xml b/user/build.xml
index 738eb86..f8a423b 100755
--- a/user/build.xml
+++ b/user/build.xml
@@ -98,7 +98,7 @@
   <target name="compile" description="Compile all class files"
           unless="compile.complete">
     <mkdir dir="${javac.out}"/>
-    <gwt.javac excludes="**/EmulatedCharset.java,**/HashCodes.java,**/ConsoleLogger.java,**/SuperDevModeLogger.java">
+    <gwt.javac excludes="**/EmulatedCharset.java,**/HashCodes.java,**/ConsoleLogger.java,**/NativeRegExp.java,**/SuperDevModeLogger.java">
       <src path="super/com/google/gwt/emul/javaemul/internal"/>
       <compilerarg value="-Xep:MissingCasesInEnumSwitch:OFF" compiler="com.google.errorprone.ErrorProneAntCompilerAdapter"/>
       <compilerarg value="-Xep:SelfComparison:OFF" compiler="com.google.errorprone.ErrorProneAntCompilerAdapter"/>
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 bb23493..aa09004 100644
--- a/user/super/com/google/gwt/emul/java/lang/String.java
+++ b/user/super/com/google/gwt/emul/java/lang/String.java
@@ -596,10 +596,6 @@
     return asNativeString().replace(jsRegEx, replace);
   }
 
-  private static int getMatchIndex(String[] matchObject) {
-    return JsUtils.getIntProperty(matchObject, "index");
-  }
-
   /**
    * Regular expressions vary from the standard implementation. The
    * <code>regex</code> parameter is interpreted by JavaScript as a JavaScript
@@ -635,14 +631,14 @@
     while (true) {
       // None of the information in the match returned are useful as we have no
       // subgroup handling
-      String[] matchObj = compiled.exec(trail);
+      NativeRegExp.Match matchObj = compiled.exec(trail);
       if (matchObj == null || trail == "" || (count == (maxMatch - 1) && maxMatch > 0)) {
         out[count] = trail;
         break;
       } else {
-        out[count] = trail.substring(0, getMatchIndex(matchObj));
-        trail =
-            trail.substring(getMatchIndex(matchObj) + matchObj[0].length(), trail.length());
+        int matchIndex = matchObj.getIndex();
+        out[count] = trail.substring(0, matchIndex);
+        trail = trail.substring(matchIndex + matchObj.asArray()[0].length(), trail.length());
         // Force the compiled pattern to reset internal state
         compiled.lastIndex = 0;
         // Only one zero length match per character to ensure termination
diff --git a/user/super/com/google/gwt/emul/java/math/MathContext.java b/user/super/com/google/gwt/emul/java/math/MathContext.java
index 4fc5a1f..3522877 100644
--- a/user/super/com/google/gwt/emul/java/math/MathContext.java
+++ b/user/super/com/google/gwt/emul/java/math/MathContext.java
@@ -143,7 +143,7 @@
     checkNotNull(val, "null string");
 
     String[] extractedValues =
-        new NativeRegExp("^precision=(\\d+)\\ roundingMode=(\\w+)$").exec(val);
+        new NativeRegExp("^precision=(\\d+)\\ roundingMode=(\\w+)$").exec(val).asArray();
     if (extractedValues == null || extractedValues.length != 3) {
       throw new IllegalArgumentException("bad string format");
     }
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 8adf867..69c8be4 100644
--- a/user/super/com/google/gwt/emul/java/util/ConcurrentModificationDetector.java
+++ b/user/super/com/google/gwt/emul/java/util/ConcurrentModificationDetector.java
@@ -16,7 +16,10 @@
 package java.util;
 
 import javaemul.internal.InternalPreconditions;
-import javaemul.internal.JsUtils;
+
+import jsinterop.annotations.JsPackage;
+import jsinterop.annotations.JsProperty;
+import jsinterop.annotations.JsType;
 
 /**
  * A helper to detect concurrent modifications to collections. This is implemented as a helper
@@ -26,32 +29,41 @@
 
   private static final boolean API_CHECK = InternalPreconditions.isApiChecked();
 
-  private static final String MOD_COUNT_PROPERTY = "_gwt_modCount";
-
-  public static void structureChanged(Object map) {
+  public static void structureChanged(Object host) {
     if (!API_CHECK) {
       return;
     }
+
+    ModCountable modCountable = (ModCountable) host;
     // Ensure that modCount is initialized if it is not already.
-    int modCount = JsUtils.getIntProperty(map, MOD_COUNT_PROPERTY) | 0;
-    JsUtils.setIntProperty(map, MOD_COUNT_PROPERTY, modCount + 1);
+    int modCount = modCountable.getModCount() | 0;
+    modCountable.setModCount(modCount + 1);
   }
 
   public static void recordLastKnownStructure(Object host, Iterator<?> iterator) {
     if (!API_CHECK) {
       return;
     }
-    int modCount = JsUtils.getIntProperty(host, MOD_COUNT_PROPERTY);
-    JsUtils.setIntProperty(iterator, MOD_COUNT_PROPERTY, modCount);
+
+    ((ModCountable) iterator).setModCount(((ModCountable) host).getModCount());
   }
 
   public static void checkStructuralChange(Object host, Iterator<?> iterator) {
     if (!API_CHECK) {
       return;
     }
-    if (JsUtils.getIntProperty(iterator, MOD_COUNT_PROPERTY)
-        != JsUtils.getIntProperty(host, MOD_COUNT_PROPERTY)) {
+
+    if (((ModCountable) iterator).getModCount() != ((ModCountable) host).getModCount()) {
       throw new ConcurrentModificationException();
     }
   }
+
+  @JsType(isNative = true, name = "*", namespace = JsPackage.GLOBAL)
+  private interface ModCountable {
+    @JsProperty(name = "$modCount")
+    void setModCount(int modCount);
+
+    @JsProperty(name = "$modCount")
+    int getModCount();
+  }
 }
diff --git a/user/super/com/google/gwt/emul/java/util/InternalHashCodeMap.java b/user/super/com/google/gwt/emul/java/util/InternalHashCodeMap.java
index 2f73382..05aca05 100644
--- a/user/super/com/google/gwt/emul/java/util/InternalHashCodeMap.java
+++ b/user/super/com/google/gwt/emul/java/util/InternalHashCodeMap.java
@@ -21,6 +21,8 @@
 import java.util.Map.Entry;
 
 import javaemul.internal.ArrayHelper;
+import javaemul.internal.JsUtils;
+import javaemul.internal.NativeArray;
 
 /**
  * A simple wrapper around JavaScriptObject to provide {@link java.util.Map}-like semantics for any
@@ -117,7 +119,7 @@
         InternalJsMap.IteratorEntry<?> current = chains.next();
         if (!current.isDone()) {
           // Move to the beginning of next chain
-          chain = unsafeCastToArray(current.getValue());
+          chain = JsUtils.uncheckedCast(current.getValue());
           itemIndex = 0;
           return true;
         }
@@ -142,17 +144,13 @@
   }
 
   private Entry<K, V>[] getChainOrEmpty(int hashCode) {
-    Entry<K, V>[] chain = unsafeCastToArray(backingMap.get(hashCode));
+    Entry<K, V>[] chain = JsUtils.uncheckedCast(backingMap.get(hashCode));
     return chain == null ? newEntryChain() : chain;
   }
 
-  private native Entry<K, V>[] newEntryChain() /*-{
-    return [];
-  }-*/;
-
-  private native Entry<K, V>[] unsafeCastToArray(Object arr) /*-{
-    return arr;
-  }-*/;
+  private Entry<K, V>[] newEntryChain() {
+    return JsUtils.uncheckedCast(new NativeArray());
+  }
 
   /**
    * Returns hash code of the key as calculated by {@link AbstractHashMap#getHashCode(Object)} but
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 164f5ff..ad2abff 100644
--- a/user/super/com/google/gwt/emul/javaemul/internal/JsUtils.java
+++ b/user/super/com/google/gwt/emul/javaemul/internal/JsUtils.java
@@ -65,6 +65,10 @@
     return map[key];
   }-*/;
 
+  public static native void setProperty(Object map, String key, Object value) /*-{
+    map[key] = value;
+  }-*/;
+
   public static native void setPropertySafe(Object map, String key, Object value) /*-{
     try {
       // This may throw exception in strict mode.
@@ -72,14 +76,6 @@
     } catch(ignored) { }
   }-*/;
 
-  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;
-  }-*/;
-
   public static native String typeOf(Object o) /*-{
     return typeof o;
   }-*/;
diff --git a/user/super/com/google/gwt/emul/javaemul/internal/NativeRegExp.java b/user/super/com/google/gwt/emul/javaemul/internal/NativeRegExp.java
index 0d3457c..8108437 100644
--- a/user/super/com/google/gwt/emul/javaemul/internal/NativeRegExp.java
+++ b/user/super/com/google/gwt/emul/javaemul/internal/NativeRegExp.java
@@ -15,6 +15,8 @@
  */
 package javaemul.internal;
 
+import jsinterop.annotations.JsOverlay;
+import jsinterop.annotations.JsProperty;
 import jsinterop.annotations.JsType;
 
 /**
@@ -25,6 +27,20 @@
   public int lastIndex;
   public NativeRegExp(String regex) { }
   public NativeRegExp(String regex, String mode) { }
-  public native String[] exec(String value);
+  public native Match exec(String value);
   public native boolean test(String value);
+
+  /**
+   * Contract of the instance returned by {@code RegExp.prototype.exec}.
+   */
+  @JsType(isNative = true, name = "Array", namespace = "<window>")
+  public interface Match {
+    @JsProperty
+    int getIndex();
+
+    @JsOverlay
+    default String[] asArray() {
+      return JsUtils.uncheckedCast(this);
+    }
+  }
 }
diff --git a/user/super/com/google/gwt/emul/javaemul/internal/StringHashCache.java b/user/super/com/google/gwt/emul/javaemul/internal/StringHashCache.java
index d472de9..c803422 100644
--- a/user/super/com/google/gwt/emul/javaemul/internal/StringHashCache.java
+++ b/user/super/com/google/gwt/emul/javaemul/internal/StringHashCache.java
@@ -24,7 +24,7 @@
   /**
    * The "old" cache; it will be dumped when front is full.
    */
-  private static Object back = createNativeObject();
+  private static Object back = new Object();
   /**
    * 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 = createNativeObject();
+  private static Object front = new Object();
   /**
    * Pulled this number out of thin air.
    */
@@ -44,17 +44,17 @@
     String key = ":" + str;
 
     // Check the front store.
-    Object result = getProperty(front, key);
-    if (!JsUtils.isUndefined(result)) {
-      return unsafeCastToInt(result);
+    Double result = JsUtils.getProperty(front, key);
+    if (result != null) {
+      return result.intValue();
     }
     // Check the back store.
-    result = getProperty(back, key);
-    int hashCode = JsUtils.isUndefined(result) ? compute(str) : unsafeCastToInt(result);
+    result = JsUtils.getProperty(back, key);
+    int hashCode = result == null ? compute(str) : result.intValue();
     // Increment can trigger the swap/flush; call after checking back but
     // before writing to front.
     increment();
-    JsUtils.setIntProperty(front, key, hashCode);
+    JsUtils.setProperty(front, key, (double) hashCode);
 
     return hashCode;
   }
@@ -89,21 +89,9 @@
   private static void increment() {
     if (count == MAX_CACHE) {
       back = front;
-      front = createNativeObject();
+      front = new Object();
       count = 0;
     }
     ++count;
   }
-
-  private static native Object getProperty(Object map, String key) /*-{
-    return map[key];
-  }-*/;
-
-  private static native Object createNativeObject() /*-{
-    return {};
-  }-*/;
-
-  private static native int unsafeCastToInt(Object o) /*-{
-    return o;
-  }-*/;
 }