[JSC] When inserting a NaN into a Int32 array, we convert it to DoubleArray then...
authorbenjamin@webkit.org <benjamin@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 24 Apr 2015 23:29:32 +0000 (23:29 +0000)
committerbenjamin@webkit.org <benjamin@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 24 Apr 2015 23:29:32 +0000 (23:29 +0000)
https://bugs.webkit.org/show_bug.cgi?id=144169

Patch by Benjamin Poulain <bpoulain@apple.com> on 2015-04-24
Reviewed by Geoffrey Garen.

* runtime/JSObject.cpp:
(JSC::JSObject::convertInt32ForValue):
DoubleArray do not store NaN, they are used for holes.
What happened was:
1) We fail to insert the NaN in the Int32 array because it is a double.
2) We were converting the array to DoubleArray.
3) We were trying to insert the value again. We would fail again because
   DoubleArray does not store NaN.
4) We would convert the DoubleArrayt to Contiguous Array, converting the values
   to boxed values.

* tests/stress/int32array-transition-on-nan.js: Added.
The behavior is not really observable. This only test nothing crashes in those
cases.

(insertNaNWhileFilling):
(testInsertNaNWhileFilling):
(insertNaNAfterFilling):
(testInsertNaNAfterFilling):
(pushNaNWhileFilling):
(testPushNaNWhileFilling):

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

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/JSObject.cpp
Source/JavaScriptCore/tests/stress/int32array-transition-on-nan.js [new file with mode: 0644]

index a014421..3229f99 100644 (file)
@@ -1,3 +1,32 @@
+2015-04-24  Benjamin Poulain  <bpoulain@apple.com>
+
+        [JSC] When inserting a NaN into a Int32 array, we convert it to DoubleArray then to ContiguousArray
+        https://bugs.webkit.org/show_bug.cgi?id=144169
+
+        Reviewed by Geoffrey Garen.
+
+        * runtime/JSObject.cpp:
+        (JSC::JSObject::convertInt32ForValue):
+        DoubleArray do not store NaN, they are used for holes.
+        What happened was:
+        1) We fail to insert the NaN in the Int32 array because it is a double.
+        2) We were converting the array to DoubleArray.
+        3) We were trying to insert the value again. We would fail again because
+           DoubleArray does not store NaN.
+        4) We would convert the DoubleArrayt to Contiguous Array, converting the values
+           to boxed values.
+
+        * tests/stress/int32array-transition-on-nan.js: Added.
+        The behavior is not really observable. This only test nothing crashes in those
+        cases.
+
+        (insertNaNWhileFilling):
+        (testInsertNaNWhileFilling):
+        (insertNaNAfterFilling):
+        (testInsertNaNAfterFilling):
+        (pushNaNWhileFilling):
+        (testPushNaNWhileFilling):
+
 2015-04-21  Geoffrey Garen  <ggaren@apple.com>
 
         It shouldn't take 1846 lines of code and 5 FIXMEs to sort an array.
index c173ca3..1ed5b0f 100644 (file)
@@ -969,7 +969,7 @@ void JSObject::convertInt32ForValue(VM& vm, JSValue value)
 {
     ASSERT(!value.isInt32());
     
-    if (value.isDouble()) {
+    if (value.isDouble() && !std::isnan(value.asDouble())) {
         convertInt32ToDouble(vm);
         return;
     }
diff --git a/Source/JavaScriptCore/tests/stress/int32array-transition-on-nan.js b/Source/JavaScriptCore/tests/stress/int32array-transition-on-nan.js
new file mode 100644 (file)
index 0000000..5db2a66
--- /dev/null
@@ -0,0 +1,88 @@
+function insertNaNWhileFilling()
+{
+    var array = new Array(6);
+    for (var i = 0; i < 4; ++i)
+        array[i] = i;
+    array[5] = NaN;
+    return array;
+}
+noInline(insertNaNWhileFilling);
+
+function testInsertNaNWhileFilling()
+{
+    var array = insertNaNWhileFilling();
+    for (var i = 0; i < 4; ++i) {
+        var value = array[i];
+        if (value !== i) {
+            throw "Failed testInsertNaNWhileFilling, value = " + value + " instead of " + i;
+        }
+    }
+    var nan = array[5];
+    if (!Number.isNaN(nan))
+        throw "Failed testInsertNaNWhileFilling, array[5] is " + nan + " instead of NaN";
+}
+noInline(testInsertNaNWhileFilling);
+
+for (var i = 0; i < 1e4; ++i) {
+    testInsertNaNWhileFilling();
+}
+
+
+function insertNaNAfterFilling()
+{
+    var array = new Array(6);
+    for (var i = 0; i < 5; ++i)
+        array[i] = i;
+    array[5] = NaN;
+    return array;
+}
+noInline(insertNaNAfterFilling);
+
+function testInsertNaNAfterFilling()
+{
+    var array = insertNaNAfterFilling();
+    for (var i = 0; i < 4; ++i) {
+        var value = array[i];
+        if (value !== i) {
+            throw "Failed testInsertNaNAfterFilling, value = " + value + " instead of " + i;
+        }
+    }
+    var nan = array[5];
+    if (!Number.isNaN(nan))
+        throw "Failed testInsertNaNAfterFilling, array[5] is " + nan + " instead of NaN";
+}
+noInline(testInsertNaNAfterFilling);
+
+for (var i = 0; i < 1e4; ++i) {
+    testInsertNaNAfterFilling();
+}
+
+
+function pushNaNWhileFilling()
+{
+    var array = [];
+    for (var i = 0; i < 5; ++i)
+        array.push(i);
+    array.push(NaN);
+    return array;
+}
+noInline(pushNaNWhileFilling);
+
+function testPushNaNWhileFilling()
+{
+    var array = pushNaNWhileFilling();
+    for (var i = 0; i < 4; ++i) {
+        var value = array[i];
+        if (value !== i) {
+            throw "Failed testPushNaNWhileFilling, value = " + value + " instead of " + i;
+        }
+    }
+    var nan = array[5];
+    if (!Number.isNaN(nan))
+        throw "Failed testPushNaNWhileFilling, array[5] is " + nan + " instead of NaN";
+}
+noInline(testPushNaNWhileFilling);
+
+for (var i = 0; i < 1e4; ++i) {
+    testPushNaNWhileFilling();
+}
\ No newline at end of file