Skip to content

Commit

Permalink
Reduce JSNI for arrays and internal API cleanup.
Browse files Browse the repository at this point in the history
Change-Id: I9369d704f291768b5c52ed2d20f726fc289a0310
Review-Link: https://gwt-review.googlesource.com/#/c/13241/
  • Loading branch information
gkdn committed Aug 6, 2015
1 parent dde4146 commit 1889200
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 103 deletions.
Expand Up @@ -40,31 +40,10 @@ public final class Array {
private static final int TYPE_PRIMITIVE_NUMBER = 8; private static final int TYPE_PRIMITIVE_NUMBER = 8;
private static final int TYPE_PRIMITIVE_BOOLEAN = 9; private static final int TYPE_PRIMITIVE_BOOLEAN = 9;


/** public static <T> T[] stampJavaTypeInfo(Object array, T[] referenceType) {
* Creates a copy of a subrange of the specified array. initValues(referenceType.getClass(), Util.getCastableTypeMap(referenceType),
*/ Array.getElementTypeId(referenceType), Array.getElementTypeCategory(referenceType), array);
public static <T> T[] cloneSubrange(T[] array, int fromIndex, int toIndex) { return Array.asArray(array);
Object result = arraySlice(array, fromIndex, toIndex);
initValues(array.getClass(), Util.getCastableTypeMap(array), Array.getElementTypeId(array),
Array.getElementTypeCategory(array), result);
// implicit type arg not inferred (as of JDK 1.5.0_07)
return Array.<T> asArray(result);
}

/**
* Creates an empty array of the exact same type as a given array, with the
* specified length.
*/
public static <T> T[] createFrom(T[] array, int length) {
// TODO(rluble): The behaviour here seems erroneous as the array elements will not be
// initialized but left undefined. However the usages seem to be safe and changing here
// might have performace penalty. Maybe rename to createUninitializedFrom(), to make
// the meaning clearer.
Object result = initializeArrayElementsWithDefaults(TYPE_JAVA_OBJECT, length);
initValues(array.getClass(), Util.getCastableTypeMap(array), Array.getElementTypeId(array),
Array.getElementTypeCategory(array), result);
// implicit type arg not inferred (as of JDK 1.5.0_07)
return Array.<T> asArray(result);
} }


/** /**
Expand Down Expand Up @@ -190,10 +169,6 @@ private static boolean canSet(Object array, Object value) {
} }
} }


private static native Object arraySlice(Object array, int fromIndex, int toIndex) /*-{
return array.slice(fromIndex, toIndex);
}-*/;

/** /**
* Use JSNI to effect a castless type change. * Use JSNI to effect a castless type change.
*/ */
Expand Down
62 changes: 40 additions & 22 deletions dev/core/super/javaemul/internal/ArrayHelper.java
Expand Up @@ -16,55 +16,73 @@
package javaemul.internal; package javaemul.internal;


/** /**
* Forwards array operations to GWT's internal array class. * Provides utilities to perform operations on Arrays.
*/ */
public class ArrayHelper { public class ArrayHelper {


public static final int ARRAY_PROCESS_BATCH_SIZE = 10000; public static final int ARRAY_PROCESS_BATCH_SIZE = 10000;


public static native <T> T[] clone(T[] array, int fromIndex, int toIndex) /*-{ public static <T> T[] clone(T[] array, int fromIndex, int toIndex) {
return @com.google.gwt.lang.Array::cloneSubrange(*)(array, fromIndex, toIndex); Object result = unsafeClone(array, fromIndex, toIndex);
return ArrayStamper.stampJavaTypeInfo(result, array);
}

/**
* Unlike clone, this method returns a copy of the array that is not type marked. This is only
* safe for temp arrays as returned array will not do any type checks.
*/
public static native Object unsafeClone(Object array, int fromIndex, int toIndex) /*-{
return array.slice(fromIndex, toIndex);
}-*/;

public static <T> T[] createFrom(T[] array, int length) {
Object result = createNativeArray(length);
return ArrayStamper.stampJavaTypeInfo(result, array);
}

private static native Object createNativeArray(int length)/*-{
return new Array(length);
}-*/; }-*/;


public static native <T> T[] createFrom(T[] array, int length) /*-{ public static native void removeFrom(Object array, int index, int deleteCount) /*-{
return @com.google.gwt.lang.Array::createFrom(*)(array, length); array.splice(index, deleteCount);
}-*/; }-*/;


public static void arrayCopy(Object src, int srcOfs, Object dest, int destOfs, int len) { public static native void insertTo(Object array, int index, Object value) /*-{
arraySplice(src, srcOfs, dest, destOfs, len, true); array.splice(index, 0, value);
}-*/;

public static void insertTo(Object array, int index, Object[] values) {
copy(values, 0, array, index, values.length, false);
} }


public static void arrayInsert(Object src, int srcOfs, Object dest, int destOfs, int len) { public static void copy(Object array, int srcOfs, Object dest, int destOfs, int len) {
arraySplice(src, srcOfs, dest, destOfs, len, false); copy(array, srcOfs, dest, destOfs, len, true);
} }


/** private static void copy(
* 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) { Object src, int srcOfs, Object dest, int destOfs, int len, boolean overwrite) {
/*
* Array.prototype.splice is not used directly to overcome the limits imposed to the number of
* function parameters by browsers.
*/

if (src == dest) { if (src == dest) {
// copying to the same array, make a copy first // copying to the same array, make a copy first
src = nativeArraySlice(src, srcOfs, srcOfs + len); src = unsafeClone(src, srcOfs, srcOfs + len);
srcOfs = 0; srcOfs = 0;
} }
for (int batchStart = srcOfs, end = srcOfs + len; batchStart < end;) { for (int batchStart = srcOfs, end = srcOfs + len; batchStart < end;) {
// increment in block // increment in block
int batchEnd = Math.min(batchStart + ARRAY_PROCESS_BATCH_SIZE, end); int batchEnd = Math.min(batchStart + ARRAY_PROCESS_BATCH_SIZE, end);
len = batchEnd - batchStart; len = batchEnd - batchStart;
nativeArraySplice( applySplice(dest, destOfs, overwrite ? len : 0, unsafeClone(src, batchStart, batchEnd));
dest, destOfs, overwrite ? len : 0, nativeArraySlice(src, batchStart, batchEnd));
batchStart = batchEnd; batchStart = batchEnd;
destOfs += len; destOfs += len;
} }
} }


static native Object nativeArraySlice(Object arrayToSclice, int start, int end) /*-{ private static native void applySplice(Object array, int index, int deleteCount,
return arrayToSclice.slice(start, end);
}-*/;

private static native void nativeArraySplice(Object array, int index, int deleteCount,
Object arrayToAdd) /*-{ Object arrayToAdd) /*-{
Array.prototype.splice.apply(array, [index, deleteCount].concat(arrayToAdd)); Array.prototype.splice.apply(array, [index, deleteCount].concat(arrayToAdd));
}-*/; }-*/;
Expand Down
25 changes: 25 additions & 0 deletions dev/core/super/javaemul/internal/ArrayStamper.java
@@ -0,0 +1,25 @@
/*
* 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;

/**
* A utility to provide array stamping. Provided as a separate class to simplify super-source.
*/
class ArrayStamper {
public static native <T> T[] stampJavaTypeInfo(Object array, T[] referenceType) /*-{
return @com.google.gwt.lang.Array::stampJavaTypeInfo(*)(array, referenceType);
}-*/;
}
3 changes: 1 addition & 2 deletions dev/core/super/javaemul/internal/StringHelper.java
Expand Up @@ -28,8 +28,7 @@ public static String valueOf(char x[], int start, int end) {
String s = ""; String s = "";
for (int batchStart = start; batchStart < end;) { for (int batchStart = start; batchStart < end;) {
int batchEnd = Math.min(batchStart + batchSize, end); int batchEnd = Math.min(batchStart + batchSize, end);
Object slicedArray = ArrayHelper.nativeArraySlice(x, batchStart, batchEnd); s += fromCharCode(ArrayHelper.unsafeClone(x, batchStart, batchEnd));
s += fromCharCode(slicedArray);
batchStart = batchEnd; batchStart = batchEnd;
} }
return s; return s;
Expand Down
16 changes: 10 additions & 6 deletions user/src/com/google/gwt/core/client/impl/StackTraceCreator.java
Expand Up @@ -20,6 +20,8 @@
import com.google.gwt.core.client.JsArray; import com.google.gwt.core.client.JsArray;
import com.google.gwt.core.client.JsArrayString; import com.google.gwt.core.client.JsArrayString;


import javaemul.internal.ArrayHelper;

/** /**
* Encapsulates logic to create a stack trace. This class should only be used in * Encapsulates logic to create a stack trace. This class should only be used in
* Production Mode. * Production Mode.
Expand Down Expand Up @@ -353,13 +355,20 @@ private static StackTraceElement[] dropInternalFrames(StackTraceElement[] stackT
int numberOfFrameToSearch = Math.min(stackTrace.length, DROP_FRAME_LIMIT); int numberOfFrameToSearch = Math.min(stackTrace.length, DROP_FRAME_LIMIT);
for (int i = 0; i < numberOfFrameToSearch; i++) { for (int i = 0; i < numberOfFrameToSearch; i++) {
if (stackTrace[i].getMethodName().equals(dropFrameUntilFnName)) { if (stackTrace[i].getMethodName().equals(dropFrameUntilFnName)) {
return splice(stackTrace, i + 1); splice(stackTrace, i + 1);
break;
} }
} }


return stackTrace; return stackTrace;
} }


private static <T> void splice(Object[] arr, int length) {
if (arr.length >= length) {
ArrayHelper.removeFrom(arr, 0, length);
}
}

// Visible for testing // Visible for testing
static final Collector collector; static final Collector collector;


Expand Down Expand Up @@ -395,9 +404,4 @@ private static native JsArrayString split(Object t) /*-{
var e = t.__gwt$backingJsError; var e = t.__gwt$backingJsError;
return (e && e.stack) ? e.stack.split('\n') : []; return (e && e.stack) ? e.stack.split('\n') : [];
}-*/; }-*/;

private static native <T> T splice(T arr, int length) /*-{
(arr.length >= length) && arr.splice(0, length);
return arr;
}-*/;
} }
2 changes: 1 addition & 1 deletion user/super/com/google/gwt/emul/java/lang/System.java
Expand Up @@ -85,7 +85,7 @@ public static void arraycopy(Object src, int srcOfs, Object dest, int destOfs, i
} }
} }
} else if (len > 0) { } else if (len > 0) {
ArrayHelper.arrayCopy(src, srcOfs, dest, destOfs, len); ArrayHelper.copy(src, srcOfs, dest, destOfs, len);
} }
} }


Expand Down
25 changes: 6 additions & 19 deletions user/super/com/google/gwt/emul/java/util/ArrayList.java
Expand Up @@ -45,19 +45,6 @@
public class ArrayList<E> extends AbstractList<E> implements List<E>, public class ArrayList<E> extends AbstractList<E> implements List<E>,
Cloneable, RandomAccess, Serializable { Cloneable, RandomAccess, Serializable {


private static native void splice(Object[] array, int index, int deleteCount) /*-{
array.splice(index, deleteCount);
}-*/;

private static native void splice(Object[] array, int index, int deleteCount,
Object value) /*-{
array.splice(index, deleteCount, value);
}-*/;

private void insertAt(int index, Object[] values) {
ArrayHelper.arrayInsert(values, 0, array, index, values.length);
}

/** /**
* This field holds a JavaScript array. * This field holds a JavaScript array.
*/ */
Expand All @@ -75,7 +62,7 @@ public ArrayList() {


public ArrayList(Collection<? extends E> c) { public ArrayList(Collection<? extends E> c) {
// Avoid calling overridable methods from constructors // Avoid calling overridable methods from constructors
insertAt(0, c.toArray()); ArrayHelper.insertTo(array, 0, c.toArray());
} }


public ArrayList(int initialCapacity) { public ArrayList(int initialCapacity) {
Expand All @@ -92,7 +79,7 @@ public boolean add(E o) {
@Override @Override
public void add(int index, E o) { public void add(int index, E o) {
checkPositionIndex(index, array.length); checkPositionIndex(index, array.length);
splice(array, index, 0, o); ArrayHelper.insertTo(array, index, o);
} }


@Override @Override
Expand All @@ -102,7 +89,7 @@ public boolean addAll(Collection<? extends E> c) {
if (len == 0) { if (len == 0) {
return false; return false;
} }
insertAt(array.length, cArray); ArrayHelper.insertTo(array, array.length, cArray);
return true; return true;
} }


Expand All @@ -114,7 +101,7 @@ public boolean addAll(int index, Collection<? extends E> c) {
if (len == 0) { if (len == 0) {
return false; return false;
} }
insertAt(index, cArray); ArrayHelper.insertTo(array, index, cArray);
return true; return true;
} }


Expand Down Expand Up @@ -160,7 +147,7 @@ public int lastIndexOf(Object o) {
@Override @Override
public E remove(int index) { public E remove(int index) {
E previous = get(index); E previous = get(index);
splice(array, index, 1); ArrayHelper.removeFrom(array, index, 1);
return previous; return previous;
} }


Expand Down Expand Up @@ -218,7 +205,7 @@ public void trimToSize() {
protected void removeRange(int fromIndex, int endIndex) { protected void removeRange(int fromIndex, int endIndex) {
checkPositionIndexes(fromIndex, endIndex, array.length); checkPositionIndexes(fromIndex, endIndex, array.length);
int count = endIndex - fromIndex; int count = endIndex - fromIndex;
splice(array, fromIndex, count); ArrayHelper.removeFrom(array, fromIndex, count);
} }


/** /**
Expand Down
30 changes: 11 additions & 19 deletions user/super/com/google/gwt/emul/java/util/Arrays.java
Expand Up @@ -1359,20 +1359,17 @@ private static void mergeSort(Object[] temp, Object[] array, int low,
* Sort an entire array of number primitives. * Sort an entire array of number primitives.
*/ */
private static native void nativeLongSort(Object array) /*-{ private static native void nativeLongSort(Object array) /*-{
array.sort(@com.google.gwt.lang.LongLib::compare(Lcom/google/gwt/lang/LongLibBase$LongEmul;Lcom/google/gwt/lang/LongLibBase$LongEmul;)); array.sort(@com.google.gwt.lang.LongLib::compare(*));
}-*/; }-*/;


/** /**
* Sort a subset of an array of number primitives. * Sort a subset of an array of number primitives.
*/ */
private static native void nativeLongSort(Object array, int fromIndex, private static void nativeLongSort(Object array, int fromIndex, int toIndex) {
int toIndex) /*-{ Object temp = ArrayHelper.unsafeClone(array, fromIndex, toIndex);
var temp = array.slice(fromIndex, toIndex); nativeLongSort(temp);
temp.sort(@com.google.gwt.lang.LongLib::compare(Lcom/google/gwt/lang/LongLibBase$LongEmul;Lcom/google/gwt/lang/LongLibBase$LongEmul;)); ArrayHelper.copy(temp, 0, array, fromIndex, toIndex - fromIndex);
var n = toIndex - fromIndex; }
@javaemul.internal.ArrayHelper::arrayCopy(Ljava/lang/Object;ILjava/lang/Object;II)(
temp, 0, array, fromIndex, n)
}-*/;


/** /**
* Sort an entire array of number primitives. * Sort an entire array of number primitives.
Expand All @@ -1386,14 +1383,9 @@ private static native void nativeNumberSort(Object array) /*-{
/** /**
* Sort a subset of an array of number primitives. * Sort a subset of an array of number primitives.
*/ */
private static native void nativeNumberSort(Object array, int fromIndex, private static void nativeNumberSort(Object array, int fromIndex, int toIndex) {
int toIndex) /*-{ Object temp = ArrayHelper.unsafeClone(array, fromIndex, toIndex);
var temp = array.slice(fromIndex, toIndex); nativeNumberSort(temp);
temp.sort(function(a, b) { ArrayHelper.copy(temp, 0, array, fromIndex, toIndex - fromIndex);
return a - b; }
});
var n = toIndex - fromIndex;
@javaemul.internal.ArrayHelper::arrayCopy(Ljava/lang/Object;ILjava/lang/Object;II)(
temp, 0, array, fromIndex, n)
}-*/;
} }
Expand Up @@ -26,6 +26,8 @@
import java.util.InternalJsMapFactory.InternalJsMap; import java.util.InternalJsMapFactory.InternalJsMap;
import java.util.Map.Entry; import java.util.Map.Entry;


import javaemul.internal.ArrayHelper;

/** /**
* A simple wrapper around JavaScriptObject to provide {@link java.util.Map}-like semantics for any * A simple wrapper around JavaScriptObject to provide {@link java.util.Map}-like semantics for any
* key type. * key type.
Expand Down Expand Up @@ -77,7 +79,7 @@ public V remove(Object key) {
backingMap.delete(hashCode); backingMap.delete(hashCode);
} else { } else {
// splice out the entry we're removing // splice out the entry we're removing
splice(chain, i); ArrayHelper.removeFrom(chain, i, 1);
} }
size--; size--;
structureChanged(host); structureChanged(host);
Expand Down Expand Up @@ -176,8 +178,4 @@ private native Entry<K, V>[] unsafeCastToArray(Object arr) /*-{
private int hash(Object key) { private int hash(Object key) {
return key == null ? 0 : host.getHashCode(key); return key == null ? 0 : host.getHashCode(key);
} }

private static native void splice(Object arr, int index) /*-{
arr.splice(index, 1);
}-*/;
} }

0 comments on commit 1889200

Please sign in to comment.