Add extra array helper class.

Change-Id: Ifa07e71e0b16ce063282138d6a499fabab9f3786
diff --git a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java
index 4900e39..5e4aacc 100644
--- a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java
+++ b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java
@@ -38,15 +38,6 @@
   private static final int TYPE_PRIMITIVE_NUMBER = 7;
   private static final int TYPE_PRIMITIVE_BOOLEAN = 8;
 
-  private static final int ARRAY_PROCESS_BATCH_SIZE = 10000;
-
-  /**
-   * Creates a copy of the specified array.
-   */
-  public static <T> T[] clone(T[] array) {
-    return cloneSubrange(array, 0, array.length);
-  }
-
   /**
    * Creates a copy of a subrange of the specified array.
    */
@@ -59,13 +50,6 @@
   }
 
   /**
-   * Creates a new array of the exact same type and length as a given array.
-   */
-  public static <T> T[] createFrom(T[] array) {
-    return createFrom(array, array.length);
-  }
-
-  /**
    * Creates an empty array of the exact same type as a given array, with the
    * specified length.
    */
@@ -158,61 +142,6 @@
   }
 
   /**
-   * Copy an array using native Javascript. The destination array must be a real
-   * Java array (ie, already has the GWT type info on it). No error checking is performed -- the
-   * caller is expected to have verified everything first.
-   *
-   * @param src source array for copy
-   * @param srcOfs offset into source array
-   * @param dest destination array for copy
-   * @param destOfs offset into destination array
-   * @param len number of elements to copy
-   */
-  public static void nativeArraycopy(Object src, int srcOfs, Object dest, int destOfs, int len) {
-    nativeArraySplice(src, srcOfs, dest, destOfs, len, true);
-  }
-
-  /**
-   * Insert one array into another native Javascript. The destination array must be a real
-   * Java array (ie, already has the GWT type info on it). No error checking is performed -- the
-   * caller is expected to have verified everything first.
-   *
-   * @param src source array where the data is taken from
-   * @param srcOfs offset into source array
-   * @param dest destination array for the data to be inserted
-   * @param destOfs offset into destination array
-   * @param len number of elements to insert
-   */
-  public static void nativeArrayInsert(Object src, int srcOfs, Object dest, int destOfs,
-      int len) {
-    nativeArraySplice(src, srcOfs, dest, destOfs, len, false);
-  }
-
-  /**
-   * A replacement for Array.prototype.splice to overcome the limits imposed to the number of
-   * function parameters by browsers.
-   */
-  private static native void nativeArraySplice(
-      Object src, int srcOfs, Object dest, int destOfs, int len, boolean overwrite) /*-{
-    // Work around function.prototype.apply call stack size limits:
-    // https://code.google.com/p/v8/issues/detail?id=2896
-    // Performance: http://jsperf.com/java-system-arraycopy/2
-    if (src === dest) {
-      // copying to the same array, make a copy first
-      src = src.slice(srcOfs, srcOfs + len);
-      srcOfs = 0;
-    }
-    for (var batchStart = srcOfs, end = srcOfs + len; batchStart < end;) { // increment in block
-      var batchEnd = Math.min(batchStart + @Array::ARRAY_PROCESS_BATCH_SIZE, end);
-      len = batchEnd - batchStart;
-      Array.prototype.splice.apply(dest, [destOfs, overwrite ? len : 0]
-          .concat(src.slice(batchStart, batchEnd)));
-      batchStart = batchEnd;
-      destOfs += len;
-    }
-  }-*/;
-
-  /**
    * Performs an array assignment, after validating the type of the value being
    * stored. The form of the type check depends on the value of elementTypeId and
    * elementTypeCategory as follows:
diff --git a/user/super/com/google/gwt/emul/java/internal/ArrayHelper.java b/user/super/com/google/gwt/emul/java/internal/ArrayHelper.java
new file mode 100644
index 0000000..657e185
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/internal/ArrayHelper.java
@@ -0,0 +1,72 @@
+/*
+ * 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 java.internal;
+
+/**
+ * Forwards array operations to GWT's internal array class.
+ */
+public class ArrayHelper {
+
+  private static final int ARRAY_PROCESS_BATCH_SIZE = 10000;
+
+  public static native <T> T[] clone(T[] array, int fromIndex, int toIndex) /*-{
+    return @com.google.gwt.lang.Array::cloneSubrange(*)(array, fromIndex, toIndex);
+  }-*/;
+
+  public static native <T> T[] createFrom(T[] array, int length) /*-{
+    return @com.google.gwt.lang.Array::createFrom(*)(array, length);
+  }-*/;
+
+  public static void arrayCopy(Object src, int srcOfs, Object dest, int destOfs, int len) {
+    arraySplice(src, srcOfs, dest, destOfs, len, true);
+  }
+
+  public static void arrayInsert(Object src, int srcOfs, Object dest, int destOfs, int len) {
+    arraySplice(src, srcOfs, dest, destOfs, len, false);
+  }
+
+  /**
+   * A replacement for Array.prototype.splice to overcome the limits imposed to the number of
+   * function parameters by browsers.
+   */
+  private static void arraySplice(
+      Object src, int srcOfs, Object dest, int destOfs, int len, boolean overwrite) {
+    if (src == dest) {
+      // copying to the same array, make a copy first
+      src = nativeArraySlice(src, srcOfs, srcOfs + len);
+      srcOfs = 0;
+    }
+    for (int batchStart = srcOfs, end = srcOfs + len; batchStart < end;) {
+      // increment in block
+      int batchEnd = Math.min(batchStart + ARRAY_PROCESS_BATCH_SIZE, end);
+      len = batchEnd - batchStart;
+      nativeArraySplice(
+          dest, destOfs, overwrite ? len : 0, nativeArraySlice(src, batchStart, batchEnd));
+      batchStart = batchEnd;
+      destOfs += len;
+    }
+  }
+
+  private static native Object nativeArraySlice(Object arrayToSclice, int start, int end) /*-{
+    return arrayToSclice.slice(start, end);
+  }-*/;
+
+  private static native Object nativeArraySplice(Object array, int index, int deleteCount,
+      Object arrayToAdd) /*-{
+    Array.prototype.splice.apply(array, [index, deleteCount].concat(arrayToAdd));
+  }-*/;
+}
+
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 54c67e7..aa14cf7 100644
--- a/user/super/com/google/gwt/emul/java/lang/String.java
+++ b/user/super/com/google/gwt/emul/java/lang/String.java
@@ -282,7 +282,7 @@
     // Work around function.prototype.apply call stack size limits:
     // https://code.google.com/p/v8/issues/detail?id=2896
     // Performance: http://jsperf.com/string-fromcharcode-test/13
-    var batchSize = @com.google.gwt.lang.Array::ARRAY_PROCESS_BATCH_SIZE;
+    var batchSize = @java.internal.ArrayHelper::ARRAY_PROCESS_BATCH_SIZE;
     var s = "";
     for (var batchStart = start; batchStart < end;) { // increment in block
       var batchEnd = Math.min(batchStart + batchSize, end);
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 3b42bf6..4a1e705 100644
--- a/user/super/com/google/gwt/emul/java/lang/System.java
+++ b/user/super/com/google/gwt/emul/java/lang/System.java
@@ -15,13 +15,13 @@
  */
 package java.lang;
 
-import com.google.gwt.core.client.JsDate;
-import com.google.gwt.core.client.impl.Impl;
-import com.google.gwt.lang.Array;
-
 import static java.internal.InternalPreconditions.checkArrayType;
 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;
 
 /**
@@ -85,7 +85,7 @@
         }
       }
     } else if (len > 0) {
-      Array.nativeArraycopy(src, srcOfs, dest, destOfs, len);
+      ArrayHelper.arrayCopy(src, srcOfs, dest, destOfs, len);
     }
   }
 
diff --git a/user/super/com/google/gwt/emul/java/util/AbstractCollection.java b/user/super/com/google/gwt/emul/java/util/AbstractCollection.java
index aa305d8..02df96e 100644
--- a/user/super/com/google/gwt/emul/java/util/AbstractCollection.java
+++ b/user/super/com/google/gwt/emul/java/util/AbstractCollection.java
@@ -15,10 +15,10 @@
  */
 package java.util;
 
-import com.google.gwt.lang.Array;
-
 import static java.internal.InternalPreconditions.checkNotNull;
 
+import java.internal.ArrayHelper;
+
 /**
  * Skeletal implementation of the Collection interface. <a
  * href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/AbstractCollection.html">[Sun
@@ -128,7 +128,7 @@
   public <T> T[] toArray(T[] a) {
     int size = size();
     if (a.length < size) {
-      a = Array.createFrom(a, size);
+      a = ArrayHelper.createFrom(a, size);
     }
     Object[] result = a;
     Iterator<E> it = iterator();
diff --git a/user/super/com/google/gwt/emul/java/util/ArrayList.java b/user/super/com/google/gwt/emul/java/util/ArrayList.java
index a82f932..8a57804 100644
--- a/user/super/com/google/gwt/emul/java/util/ArrayList.java
+++ b/user/super/com/google/gwt/emul/java/util/ArrayList.java
@@ -15,13 +15,12 @@
  */
 package java.util;
 
-import com.google.gwt.lang.Array;
-
 import static java.internal.InternalPreconditions.checkArgument;
 import static java.internal.InternalPreconditions.checkElementIndex;
 import static java.internal.InternalPreconditions.checkPositionIndex;
 import static java.internal.InternalPreconditions.checkPositionIndexes;
 
+import java.internal.ArrayHelper;
 import java.io.Serializable;
 
 /**
@@ -55,7 +54,7 @@
   }-*/;
 
   private void insertAt(int index, Object[] values) {
-    Array.nativeArrayInsert(values, 0, array, index, values.length);
+    ArrayHelper.arrayInsert(values, 0, array, index, values.length);
   }
 
   /**
@@ -188,7 +187,7 @@
 
   @Override
   public Object[] toArray() {
-    return Array.cloneSubrange(array, 0, array.length);
+    return ArrayHelper.clone(array, 0, array.length);
   }
 
   /*
@@ -199,7 +198,7 @@
   public <T> T[] toArray(T[] out) {
     int size = array.length;
     if (out.length < size) {
-      out = Array.createFrom(out, size);
+      out = ArrayHelper.createFrom(out, size);
     }
     for (int i = 0; i < size; ++i) {
       out[i] = (T) array[i];
diff --git a/user/super/com/google/gwt/emul/java/util/Arrays.java b/user/super/com/google/gwt/emul/java/util/Arrays.java
index 64a39b9..e212dca 100644
--- a/user/super/com/google/gwt/emul/java/util/Arrays.java
+++ b/user/super/com/google/gwt/emul/java/util/Arrays.java
@@ -18,15 +18,15 @@
 
 import static com.google.gwt.core.client.impl.Coercions.ensureInt;
 
-import com.google.gwt.core.client.JavaScriptObject;
-import com.google.gwt.core.client.UnsafeNativeLong;
-import com.google.gwt.lang.Array;
-
 import static java.internal.InternalPreconditions.checkArgument;
 import static java.internal.InternalPreconditions.checkArraySize;
 import static java.internal.InternalPreconditions.checkElementIndex;
 import static java.internal.InternalPreconditions.checkPositionIndexes;
 
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.UnsafeNativeLong;
+
+import java.internal.ArrayHelper;
 import java.io.Serializable;
 
 /**
@@ -78,7 +78,7 @@
      */
     @Override
     public Object[] toArray() {
-      return Array.clone(array);
+      return ArrayHelper.clone(array, 0, array.length);
     }
 
     /*
@@ -89,7 +89,7 @@
     public <T> T[] toArray(T[] out) {
       int size = size();
       if (out.length < size) {
-        out = Array.createFrom(out, size);
+        out = ArrayHelper.createFrom(out, size);
       }
       for (int i = 0; i < size; ++i) {
         out[i] = (T) array[i];
@@ -502,7 +502,7 @@
 
   public static <T> T[] copyOfRange(T[] original, int from, int to) {
     int newLength = getLengthFromRange(from, to);
-    T[] copy = Array.createFrom(original, newLength);
+    T[] copy = ArrayHelper.createFrom(original, newLength);
     System.arraycopy(original, from, copy, 0,
         Math.min(original.length - from, newLength));
     return copy;
@@ -1428,7 +1428,7 @@
     var temp = array.slice(fromIndex, toIndex);
     temp.sort(@com.google.gwt.lang.LongLib::compare(Lcom/google/gwt/lang/LongLibBase$LongEmul;Lcom/google/gwt/lang/LongLibBase$LongEmul;));
     var n = toIndex - fromIndex;
-    @com.google.gwt.lang.Array::nativeArraycopy(Ljava/lang/Object;ILjava/lang/Object;II)(
+    @java.internal.ArrayHelper::arrayCopy(Ljava/lang/Object;ILjava/lang/Object;II)(
         temp, 0, array, fromIndex, n)
   }-*/;
 
@@ -1451,7 +1451,7 @@
       return a - b;
     });
     var n = toIndex - fromIndex;
-    @com.google.gwt.lang.Array::nativeArraycopy(Ljava/lang/Object;ILjava/lang/Object;II)(
+    @java.internal.ArrayHelper::arrayCopy(Ljava/lang/Object;ILjava/lang/Object;II)(
         temp, 0, array, fromIndex, n)
   }-*/;
 
diff --git a/user/super/com/google/gwt/emul/java/util/EnumMap.java b/user/super/com/google/gwt/emul/java/util/EnumMap.java
index 6f01e71..bcc64bb 100644
--- a/user/super/com/google/gwt/emul/java/util/EnumMap.java
+++ b/user/super/com/google/gwt/emul/java/util/EnumMap.java
@@ -15,11 +15,11 @@
  */
 package java.util;
 
-import com.google.gwt.lang.Array;
-
 import static java.internal.InternalPreconditions.checkArgument;
 import static java.internal.InternalPreconditions.checkState;
 
+import java.internal.ArrayHelper;
+
 /**
  * A {@link java.util.Map} of {@link Enum}s. <a
  * href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/EnumMap.html">[Sun
@@ -210,7 +210,7 @@
 
   private void init(EnumMap<K, ? extends V> m) {
     keySet = m.keySet.clone();
-    values = Array.clone(m.values);
+    values = ArrayHelper.clone(m.values, 0, m.values.length);
   }
 
   private V set(int ordinal, V value) {
diff --git a/user/super/com/google/gwt/emul/java/util/EnumSet.java b/user/super/com/google/gwt/emul/java/util/EnumSet.java
index f006811..3efa777 100644
--- a/user/super/com/google/gwt/emul/java/util/EnumSet.java
+++ b/user/super/com/google/gwt/emul/java/util/EnumSet.java
@@ -15,14 +15,15 @@
  */
 package java.util;
 
-import com.google.gwt.core.client.impl.SpecializeMethod;
-import com.google.gwt.lang.Array;
-
 import static java.internal.InternalPreconditions.checkArgument;
 import static java.internal.InternalPreconditions.checkElement;
 import static java.internal.InternalPreconditions.checkNotNull;
 import static java.internal.InternalPreconditions.checkState;
 
+import com.google.gwt.core.client.impl.SpecializeMethod;
+
+import java.internal.ArrayHelper;
+
 /**
  * A {@link java.util.Set} of {@link Enum}s. <a
  * href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/EnumSet.html">[Sun
@@ -129,7 +130,7 @@
 
     @Override
     public EnumSet<E> clone() {
-      E[] clonedSet = Array.clone(set);
+      E[] clonedSet = ArrayHelper.clone(set, 0, set.length);
       return new EnumSetImpl<E>(all, clonedSet, size);
     }
 
@@ -176,7 +177,7 @@
 
   public static <E extends Enum<E>> EnumSet<E> allOf(Class<E> elementType) {
     E[] all = elementType.getEnumConstants();
-    E[] set = Array.clone(all);
+    E[] set = ArrayHelper.clone(all, 0, all.length);
     return new EnumSetImpl<E>(all, set, all.length);
   }
 
@@ -184,7 +185,7 @@
     EnumSetImpl<E> s = (EnumSetImpl<E>) other;
     E[] all = s.all;
     E[] oldSet = s.set;
-    E[] newSet = Array.createFrom(oldSet);
+    E[] newSet = ArrayHelper.createFrom(oldSet, oldSet.length);
     for (int i = 0, c = oldSet.length; i < c; ++i) {
       if (oldSet[i] == null) {
         newSet[i] = all[i];
@@ -216,7 +217,7 @@
 
   public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
     E[] all = elementType.getEnumConstants();
-    return new EnumSetImpl<E>(all, Array.createFrom(all), 0);
+    return new EnumSetImpl<E>(all, ArrayHelper.createFrom(all, all.length), 0);
   }
 
   public static <E extends Enum<E>> EnumSet<E> of(E first) {
@@ -235,7 +236,7 @@
     checkArgument(from.compareTo(to) <= 0, "%s > %s", from, to);
 
     E[] all = from.getDeclaringClass().getEnumConstants();
-    E[] set = Array.createFrom(all);
+    E[] set = ArrayHelper.createFrom(all, all.length);
 
     // Inclusive
     int start = from.ordinal();
diff --git a/user/test/com/google/gwt/emultest/java/lang/C.java b/user/test/com/google/gwt/emultest/java/lang/C.java
index 1f657f6..af83bba 100644
--- a/user/test/com/google/gwt/emultest/java/lang/C.java
+++ b/user/test/com/google/gwt/emultest/java/lang/C.java
@@ -1,12 +1,12 @@
 /*
  * Copyright 2007 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
@@ -60,6 +60,6 @@
   }
 
   private static native int numberOfCopies() /*-{
-    return @com.google.gwt.lang.Array::ARRAY_PROCESS_BATCH_SIZE * 3;
+    return @java.internal.ArrayHelper::ARRAY_PROCESS_BATCH_SIZE * 3;
   }-*/;
 }