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; - }-*/; }