Modifed checks for extracting float values from JavaScript code in hosted
mode. The basic problem was that the value could be slightly changed by
the JavaScript code as a double, which meant that it would no longer compare
equal to the original value and might be slightly outside the range of the
check.
This was fixed by first looking for differences between MIN_VALUE and the
passed value to be too small to represent in a float -- if that is the case,
Float.MIN_VALUE is used instead of the returned value. Second, instead of
doing range checking we simply let the JVM do the work by casting to float.
After the cast, we check to see if the double value was not infinite and the
float value is, which means that an overflow occurred and a value larger
than Float.MAX_VALUE was changed to infinity by the cast. We treat this as
an error since data was lost, and throw HostedModeException to signal that
behavior could be different in web mode.
Review by: mmendez
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@665 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/shell/JsValueGlue.java b/dev/core/src/com/google/gwt/dev/shell/JsValueGlue.java
index 4fcf2c8..b183cd1 100644
--- a/dev/core/src/com/google/gwt/dev/shell/JsValueGlue.java
+++ b/dev/core/src/com/google/gwt/dev/shell/JsValueGlue.java
@@ -150,11 +150,27 @@
+ value.getTypeString() + ", expected float");
}
doubleVal = value.getNumber();
- if (doubleVal < Float.MIN_VALUE || doubleVal > Float.MAX_VALUE) {
+
+ // Check for small changes near MIN_VALUE and replace with the
+ // actual endpoint value, in case it is being used as a sentinel
+ // value. This test works by the subtraction result rounding off to
+ // zero if the delta is not representable in a float.
+ // TODO(jat): add similar test for MAX_VALUE if we have a JS
+ // platform that munges the value while converting to/from strings.
+ if ((float)(doubleVal - Float.MIN_VALUE) == 0.0f) {
+ doubleVal = Float.MIN_VALUE;
+ }
+
+ float floatVal = (float)doubleVal;
+ if (Float.isInfinite(floatVal) && !Double.isInfinite(doubleVal)) {
+ // in this case we had overflow from the double value which was
+ // outside the range of supported float values, and the cast
+ // converted it to infinity. Since this lost data, we treat this
+ // as an error in hosted mode.
throw new HostedModeException(msgPrefix + ": JS value " + doubleVal
+ " out of range for a float");
}
- return new Float((float) doubleVal);
+ return new Float(floatVal);
case TypeInfo.TYPE_WRAP_INT:
case TypeInfo.TYPE_PRIM_INT:
diff --git a/user/test/com/google/gwt/dev/jjs/test/HostedTest.java b/user/test/com/google/gwt/dev/jjs/test/HostedTest.java
index 5a74bc6..5deb0d1 100644
--- a/user/test/com/google/gwt/dev/jjs/test/HostedTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/HostedTest.java
@@ -89,6 +89,18 @@
return "test";
}-*/;
+ private static native void storeFloat(float f) /*-{
+ myFloatValue = f;
+ }-*/;
+
+ private static native float getFloat() /*-{
+ return myFloatValue;
+ }-*/;
+
+ private static native float getFloatString() /*-{
+ return Number(myFloatValue.toString());
+ }-*/;
+
private static native JavaScriptObject getsFooFunc() /*-{
return @com.google.gwt.dev.jjs.test.HostedTest::sFoo(Ljava/lang/String;);
}-*/;
@@ -177,6 +189,19 @@
jsniL();
}
+ public void testFloat() {
+ storeFloat(Float.MIN_VALUE);
+ float f = getFloat();
+ assertTrue(f == Float.MIN_VALUE);
+ f = getFloatString();
+ assertTrue(f == Float.MIN_VALUE);
+ storeFloat(Float.MAX_VALUE);
+ f = getFloat();
+ assertTrue(f == Float.MAX_VALUE);
+ f = getFloatString();
+ assertTrue(f == Float.MAX_VALUE);
+ }
+
public void testLocalJsni() {
class Foo {