typeOfDoubleSum is wrong for when NaN can be produced
authorsbarati@apple.com <sbarati@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 21 Mar 2019 05:41:21 +0000 (05:41 +0000)
committersbarati@apple.com <sbarati@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 21 Mar 2019 05:41:21 +0000 (05:41 +0000)
https://bugs.webkit.org/show_bug.cgi?id=196030

Reviewed by Filip Pizlo.

JSTests:

* stress/double-add-sub-mul-can-produce-nan.js: Added.
(assert):
(noInline.sub):
(noInline):
(assert.mul):
(assert.add):

Source/JavaScriptCore:

We were using typeOfDoubleSum(SpeculatedType, SpeculatedType) for add/sub/mul.
It assumed that the only way the resulting type could be NaN is if one of
the inputs were NaN. However, this is wrong. NaN can be produced in at least
these cases:
  Infinity - Infinity
  Infinity + (-Infinity)
  Infinity * 0

* bytecode/SpeculatedType.cpp:
(JSC::typeOfDoubleSumOrDifferenceOrProduct):
(JSC::typeOfDoubleSum):
(JSC::typeOfDoubleDifference):
(JSC::typeOfDoubleProduct):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@243277 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JSTests/ChangeLog
JSTests/stress/double-add-sub-mul-can-produce-nan.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/SpeculatedType.cpp

index de15dd7..c381164 100644 (file)
@@ -1,3 +1,17 @@
+2019-03-20  Saam Barati  <sbarati@apple.com>
+
+        typeOfDoubleSum is wrong for when NaN can be produced
+        https://bugs.webkit.org/show_bug.cgi?id=196030
+
+        Reviewed by Filip Pizlo.
+
+        * stress/double-add-sub-mul-can-produce-nan.js: Added.
+        (assert):
+        (noInline.sub):
+        (noInline):
+        (assert.mul):
+        (assert.add):
+
 2019-03-20  Yusuke Suzuki  <ysuzuki@apple.com>
 
         Update the test to ensure OutOfMemoryError is thrown as intended
diff --git a/JSTests/stress/double-add-sub-mul-can-produce-nan.js b/JSTests/stress/double-add-sub-mul-can-produce-nan.js
new file mode 100644 (file)
index 0000000..3024ae5
--- /dev/null
@@ -0,0 +1,77 @@
+"use strict";
+
+function assert(b) {
+    if (!b)
+        throw new Error;
+}
+noInline(assert);
+
+{
+    function sub(arr, b, c) {
+        let x = b - c;
+        arr[0] = x;
+    }
+    noInline(sub);
+
+
+    for (let i = 0; i < 10000; ++i) {
+        let arr = [];
+        arr.length = 2;
+        arr[1] = 10.5;
+        sub(arr, 10.5, 20.5);
+        assert(0 in arr);
+    }
+
+    let arr = [];
+    arr.length = 2;
+    arr[1] = 10.5;
+    sub(arr, Infinity, Infinity);
+    assert(typeof arr[0] === "number" && isNaN(arr[0]));
+    assert(0 in arr);
+}
+
+{
+    function mul(arr, b, c) {
+        let x = b * c;
+        arr[0] = x;
+    }
+    noInline(mul);
+
+    for (let i = 0; i < 10000; ++i) {
+        let arr = [];
+        arr.length = 2;
+        arr[1] = 10.5;
+        mul(arr, 10.5, 20.5);
+        assert(0 in arr);
+    }
+
+    let arr = [];
+    arr.length = 2;
+    arr[1] = 10.5;
+    mul(arr, Infinity, 0);
+    assert(typeof arr[0] === "number" && isNaN(arr[0]));
+    assert(0 in arr);
+}
+
+{
+    function add(arr, b, c) {
+        let x = b + c;
+        arr[0] = x;
+    }
+    noInline(add);
+
+    for (let i = 0; i < 10000; ++i) {
+        let arr = [];
+        arr.length = 2;
+        arr[1] = 10.5;
+        add(arr, 10.5, 20.5);
+        assert(0 in arr);
+    }
+
+    let arr = [];
+    arr.length = 2;
+    arr[1] = 10.5;
+    add(arr, Infinity, -Infinity);
+    assert(typeof arr[0] === "number" && isNaN(arr[0]));
+    assert(0 in arr);
+}
index fe6f249..f658d2a 100644 (file)
@@ -1,3 +1,24 @@
+2019-03-20  Saam Barati  <sbarati@apple.com>
+
+        typeOfDoubleSum is wrong for when NaN can be produced
+        https://bugs.webkit.org/show_bug.cgi?id=196030
+
+        Reviewed by Filip Pizlo.
+
+        We were using typeOfDoubleSum(SpeculatedType, SpeculatedType) for add/sub/mul.
+        It assumed that the only way the resulting type could be NaN is if one of
+        the inputs were NaN. However, this is wrong. NaN can be produced in at least
+        these cases:
+          Infinity - Infinity
+          Infinity + (-Infinity)
+          Infinity * 0
+
+        * bytecode/SpeculatedType.cpp:
+        (JSC::typeOfDoubleSumOrDifferenceOrProduct):
+        (JSC::typeOfDoubleSum):
+        (JSC::typeOfDoubleDifference):
+        (JSC::typeOfDoubleProduct):
+
 2019-03-20  Simon Fraser  <simon.fraser@apple.com>
 
         Rename ENABLE_ACCELERATED_OVERFLOW_SCROLLING macro to ENABLE_OVERFLOW_SCROLLING_TOUCH
index 47529b1..b2c4a3a 100644 (file)
@@ -612,9 +612,18 @@ bool valuesCouldBeEqual(SpeculatedType a, SpeculatedType b)
     return !!(a & b);
 }
 
-SpeculatedType typeOfDoubleSum(SpeculatedType a, SpeculatedType b)
+static SpeculatedType typeOfDoubleSumOrDifferenceOrProduct(SpeculatedType a, SpeculatedType b)
 {
     SpeculatedType result = a | b;
+
+    if (result & SpecNonIntAsDouble) {
+        // NaN can be produced by:
+        // Infinity - Infinity
+        // Infinity + (-Infinity)
+        // Infinity * 0
+        result |= SpecDoublePureNaN;
+    }
+
     // Impure NaN could become pure NaN during addition because addition may clear bits.
     if (result & SpecDoubleImpureNaN)
         result |= SpecDoublePureNaN;
@@ -624,14 +633,19 @@ SpeculatedType typeOfDoubleSum(SpeculatedType a, SpeculatedType b)
     return result;
 }
 
+SpeculatedType typeOfDoubleSum(SpeculatedType a, SpeculatedType b)
+{
+    return typeOfDoubleSumOrDifferenceOrProduct(a, b);
+}
+
 SpeculatedType typeOfDoubleDifference(SpeculatedType a, SpeculatedType b)
 {
-    return typeOfDoubleSum(a, b);
+    return typeOfDoubleSumOrDifferenceOrProduct(a, b);
 }
 
 SpeculatedType typeOfDoubleProduct(SpeculatedType a, SpeculatedType b)
 {
-    return typeOfDoubleSum(a, b);
+    return typeOfDoubleSumOrDifferenceOrProduct(a, b);
 }
 
 static SpeculatedType polluteDouble(SpeculatedType value)