Title: [228728] trunk
Revision
228728
Author
utatane....@gmail.com
Date
2018-02-19 21:01:57 -0800 (Mon, 19 Feb 2018)

Log Message

[FTL] Support ArrayPush for ArrayStorage
https://bugs.webkit.org/show_bug.cgi?id=182782

Reviewed by Saam Barati.

JSTests:

Existing array-push-multiple-storage.js covers ArrayPush(ArrayStorage) multiple arguments case.

* stress/array-push-array-storage-beyond-int32.js: Added.
(shouldBe):
(test):
* stress/array-push-array-storage.js: Added.
(shouldBe):
(test):
* stress/array-push-multiple-array-storage-beyond-int32.js: Added.
(shouldBe):
(test):
* stress/array-push-multiple-storage-continuous.js: Added.
(shouldBe):
(test):

Source/_javascript_Core:

This patch adds support for ArrayPush(ArrayStorage). We just port ArrayPush(ArrayStorage) in DFG to FTL.

* ftl/FTLAbstractHeapRepository.h:
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileArrayPush):

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (228727 => 228728)


--- trunk/JSTests/ChangeLog	2018-02-20 04:33:33 UTC (rev 228727)
+++ trunk/JSTests/ChangeLog	2018-02-20 05:01:57 UTC (rev 228728)
@@ -1,5 +1,27 @@
 2018-02-14  Yusuke Suzuki  <utatane....@gmail.com>
 
+        [FTL] Support ArrayPush for ArrayStorage
+        https://bugs.webkit.org/show_bug.cgi?id=182782
+
+        Reviewed by Saam Barati.
+
+        Existing array-push-multiple-storage.js covers ArrayPush(ArrayStorage) multiple arguments case.
+
+        * stress/array-push-array-storage-beyond-int32.js: Added.
+        (shouldBe):
+        (test):
+        * stress/array-push-array-storage.js: Added.
+        (shouldBe):
+        (test):
+        * stress/array-push-multiple-array-storage-beyond-int32.js: Added.
+        (shouldBe):
+        (test):
+        * stress/array-push-multiple-storage-continuous.js: Added.
+        (shouldBe):
+        (test):
+
+2018-02-14  Yusuke Suzuki  <utatane....@gmail.com>
+
         [FTL] Support ArrayPop for ArrayStorage
         https://bugs.webkit.org/show_bug.cgi?id=182783
 

Added: trunk/JSTests/stress/array-push-array-storage-beyond-int32.js (0 => 228728)


--- trunk/JSTests/stress/array-push-array-storage-beyond-int32.js	                        (rev 0)
+++ trunk/JSTests/stress/array-push-array-storage-beyond-int32.js	2018-02-20 05:01:57 UTC (rev 228728)
@@ -0,0 +1,27 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(array, val1)
+{
+    return array.push(val1);
+}
+noInline(test);
+
+for (var i = 0; i < 1e5; ++i) {
+    var array = ["Cocoa"];
+    ensureArrayStorage(array);
+    array.length = 2;
+    shouldBe(test(array, "Cocoa"), 3);
+    shouldBe(array[0], "Cocoa");
+    shouldBe(array[1], undefined);
+    shouldBe(array[2], "Cocoa");
+}
+
+var array = ["Cocoa"];
+ensureArrayStorage(array);
+array.length = 0x7fffffff;
+shouldBe(test(array, "Cocoa"), 0x7fffffff + 1);
+shouldBe(array[0x7fffffff], "Cocoa");

Added: trunk/JSTests/stress/array-push-array-storage.js (0 => 228728)


--- trunk/JSTests/stress/array-push-array-storage.js	                        (rev 0)
+++ trunk/JSTests/stress/array-push-array-storage.js	2018-02-20 05:01:57 UTC (rev 228728)
@@ -0,0 +1,40 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(array, val1)
+{
+    return array.push(val1);
+}
+noInline(test);
+
+for (var i = 0; i < 1e5; ++i) {
+    var array = ["Cocoa"];
+    ensureArrayStorage(array);
+    shouldBe(test(array, "Cocoa"), 2);
+    shouldBe(array[0], "Cocoa");
+    shouldBe(array[1], "Cocoa");
+    shouldBe(array[2], undefined);
+    shouldBe(array[3], undefined);
+    shouldBe(array[4], undefined);
+    shouldBe(test(array, "Cappuccino"), 3);
+    shouldBe(array[0], "Cocoa");
+    shouldBe(array[1], "Cocoa");
+    shouldBe(array[2], "Cappuccino");
+    shouldBe(array[3], undefined);
+    shouldBe(array[4], undefined);
+    shouldBe(test(array, "Matcha"), 4);
+    shouldBe(array[0], "Cocoa");
+    shouldBe(array[1], "Cocoa");
+    shouldBe(array[2], "Cappuccino");
+    shouldBe(array[3], "Matcha");
+    shouldBe(array[4], undefined);
+    shouldBe(test(array, "Matcha"), 5);
+    shouldBe(array[0], "Cocoa");
+    shouldBe(array[1], "Cocoa");
+    shouldBe(array[2], "Cappuccino");
+    shouldBe(array[3], "Matcha");
+    shouldBe(array[4], "Matcha");
+}

Added: trunk/JSTests/stress/array-push-multiple-array-storage-beyond-int32.js (0 => 228728)


--- trunk/JSTests/stress/array-push-multiple-array-storage-beyond-int32.js	                        (rev 0)
+++ trunk/JSTests/stress/array-push-multiple-array-storage-beyond-int32.js	2018-02-20 05:01:57 UTC (rev 228728)
@@ -0,0 +1,29 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(array, val1, val2)
+{
+    return array.push(val1, val2);
+}
+noInline(test);
+
+for (var i = 0; i < 1e5; ++i) {
+    var array = ["Cocoa"];
+    ensureArrayStorage(array);
+    array.length = 2;
+    shouldBe(test(array, "Cocoa", "Cappuccino"), 4);
+    shouldBe(array[0], "Cocoa");
+    shouldBe(array[1], undefined);
+    shouldBe(array[2], "Cocoa");
+    shouldBe(array[3], "Cappuccino");
+}
+
+var array = ["Cocoa"];
+ensureArrayStorage(array);
+array.length = 0x7fffffff - 1;
+shouldBe(test(array, "Cocoa", "Cappuccino"), 0x7fffffff + 1);
+shouldBe(array[0x7fffffff - 1], "Cocoa");
+shouldBe(array[0x7fffffff - 0], "Cappuccino");

Added: trunk/JSTests/stress/array-push-multiple-storage-continuous.js (0 => 228728)


--- trunk/JSTests/stress/array-push-multiple-storage-continuous.js	                        (rev 0)
+++ trunk/JSTests/stress/array-push-multiple-storage-continuous.js	2018-02-20 05:01:57 UTC (rev 228728)
@@ -0,0 +1,31 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(array, val1, val2, val3)
+{
+    return array.push(val1, val2, val3);
+}
+noInline(test);
+
+for (var i = 0; i < 1e5; ++i) {
+    var array = [];
+    ensureArrayStorage(array);
+    shouldBe(test(array, "Cocoa", "Cappuccino", "Matcha"), 3);
+    shouldBe(array[0], "Cocoa");
+    shouldBe(array[1], "Cappuccino");
+    shouldBe(array[2], "Matcha");
+}
+
+var array = [];
+ensureArrayStorage(array);
+for (var i = 0; i < 1e3; ++i) {
+    shouldBe(test(array, "Cocoa", "Cappuccino", "Matcha"), 3 * (i + 1));
+}
+for (var i = 0; i < 1e3; ++i) {
+    shouldBe(array[3 * i + 0], "Cocoa");
+    shouldBe(array[3 * i + 1], "Cappuccino");
+    shouldBe(array[3 * i + 2], "Matcha");
+}

Modified: trunk/Source/_javascript_Core/ChangeLog (228727 => 228728)


--- trunk/Source/_javascript_Core/ChangeLog	2018-02-20 04:33:33 UTC (rev 228727)
+++ trunk/Source/_javascript_Core/ChangeLog	2018-02-20 05:01:57 UTC (rev 228728)
@@ -1,5 +1,20 @@
 2018-02-14  Yusuke Suzuki  <utatane....@gmail.com>
 
+        [FTL] Support ArrayPush for ArrayStorage
+        https://bugs.webkit.org/show_bug.cgi?id=182782
+
+        Reviewed by Saam Barati.
+
+        This patch adds support for ArrayPush(ArrayStorage). We just port ArrayPush(ArrayStorage) in DFG to FTL.
+
+        * ftl/FTLAbstractHeapRepository.h:
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileArrayPush):
+
+2018-02-14  Yusuke Suzuki  <utatane....@gmail.com>
+
         [FTL] Support ArrayPop for ArrayStorage
         https://bugs.webkit.org/show_bug.cgi?id=182783
 

Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (228727 => 228728)


--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2018-02-20 04:33:33 UTC (rev 228727)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2018-02-20 05:01:57 UTC (rev 228728)
@@ -319,6 +319,7 @@
     case ArraySlice:
     case ArrayIndexOf:
     case ArrayPop:
+    case ArrayPush:
     case ParseInt:
     case AtomicsAdd:
     case AtomicsAnd:
@@ -437,16 +438,6 @@
         break;
     case PutByValWithThis:
         break;
-    case ArrayPush:
-        switch (node->arrayMode().type()) {
-        case Array::Int32:
-        case Array::Contiguous:
-        case Array::Double:
-            break;
-        default:
-            return CannotCompile;
-        }
-        break;
     default:
         // Don't know how to handle anything else.
         return CannotCompile;

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (228727 => 228728)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2018-02-20 04:33:33 UTC (rev 228727)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2018-02-20 05:01:57 UTC (rev 228728)
@@ -4475,6 +4475,100 @@
             return;
         }
 
+        case Array::ArrayStorage: {
+            // This ensures that the result of ArrayPush is Int32 in AI.
+            int32_t largestPositiveInt32Length = 0x7fffffff - elementCount;
+
+            LValue prevLength = m_out.load32(storage, m_heaps.Butterfly_publicLength);
+            // Refuse to handle bizarre lengths.
+            speculate(Uncountable, noValue(), nullptr, m_out.above(prevLength, m_out.constInt32(largestPositiveInt32Length)));
+
+            if (elementCount == 1) {
+                Edge& element = m_graph.varArgChild(m_node, elementOffset);
+
+                LValue value = lowJSValue(element);
+
+                LBasicBlock fastPath = m_out.newBlock();
+                LBasicBlock slowPath = m_out.newBlock();
+                LBasicBlock continuation = m_out.newBlock();
+
+                m_out.branch(
+                    m_out.aboveOrEqual(
+                        prevLength, m_out.load32(storage, m_heaps.Butterfly_vectorLength)),
+                    rarely(slowPath), usually(fastPath));
+
+                LBasicBlock lastNext = m_out.appendTo(fastPath, slowPath);
+                m_out.store64(
+                    value, m_out.baseIndex(m_heaps.ArrayStorage_vector, storage, m_out.zeroExtPtr(prevLength)));
+                LValue newLength = m_out.add(prevLength, m_out.int32One);
+                m_out.store32(newLength, storage, m_heaps.Butterfly_publicLength);
+                m_out.store32(
+                    m_out.add(m_out.load32(storage, m_heaps.ArrayStorage_numValuesInVector), m_out.int32One),
+                    storage, m_heaps.ArrayStorage_numValuesInVector);
+
+                ValueFromBlock fastResult = m_out.anchor(boxInt32(newLength));
+                m_out.jump(continuation);
+
+                m_out.appendTo(slowPath, continuation);
+                ValueFromBlock slowResult = m_out.anchor(
+                    vmCall(Int64, m_out.operation(operationArrayPush), m_callFrame, value, base));
+                m_out.jump(continuation);
+
+                m_out.appendTo(continuation, lastNext);
+                setJSValue(m_out.phi(Int64, fastResult, slowResult));
+                return;
+            }
+
+            LValue newLength = m_out.add(prevLength, m_out.constInt32(elementCount));
+
+            LBasicBlock fastPath = m_out.newBlock();
+            LBasicBlock slowPath = m_out.newBlock();
+            LBasicBlock setup = m_out.newBlock();
+            LBasicBlock slowCallPath = m_out.newBlock();
+            LBasicBlock continuation = m_out.newBlock();
+
+            LValue beyondVectorLength = m_out.above(newLength, m_out.load32(storage, m_heaps.Butterfly_vectorLength));
+
+            m_out.branch(beyondVectorLength, rarely(slowPath), usually(fastPath));
+
+            LBasicBlock lastNext = m_out.appendTo(fastPath, slowPath);
+            m_out.store32(newLength, storage, m_heaps.Butterfly_publicLength);
+            m_out.store32(
+                m_out.add(m_out.load32(storage, m_heaps.ArrayStorage_numValuesInVector), m_out.constInt32(elementCount)),
+                storage, m_heaps.ArrayStorage_numValuesInVector);
+            ValueFromBlock fastBufferResult = m_out.anchor(m_out.baseIndex(storage, m_out.zeroExtPtr(prevLength), ScaleEight, ArrayStorage::vectorOffset()));
+            m_out.jump(setup);
+
+            m_out.appendTo(slowPath, setup);
+            size_t scratchSize = sizeof(EncodedJSValue) * elementCount;
+            ASSERT(scratchSize);
+            ScratchBuffer* scratchBuffer = vm().scratchBufferForSize(scratchSize);
+            m_out.storePtr(m_out.constIntPtr(scratchSize), m_out.absolute(scratchBuffer->addressOfActiveLength()));
+            ValueFromBlock slowBufferResult = m_out.anchor(m_out.constIntPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer())));
+            m_out.jump(setup);
+
+            m_out.appendTo(setup, slowCallPath);
+            LValue buffer = m_out.phi(pointerType(), fastBufferResult, slowBufferResult);
+            for (unsigned elementIndex = 0; elementIndex < elementCount; ++elementIndex) {
+                Edge& element = m_graph.varArgChild(m_node, elementIndex + elementOffset);
+
+                LValue value = lowJSValue(element);
+                m_out.store64(value, m_out.baseIndex(m_heaps.variables, buffer, m_out.constInt32(elementIndex), jsNumber(elementIndex)));
+            }
+            ValueFromBlock fastResult = m_out.anchor(boxInt32(newLength));
+
+            m_out.branch(beyondVectorLength, rarely(slowCallPath), usually(continuation));
+
+            m_out.appendTo(slowCallPath, continuation);
+            ValueFromBlock slowResult = m_out.anchor(vmCall(Int64, m_out.operation(operationArrayPushMultiple), m_callFrame, base, buffer, m_out.constInt32(elementCount)));
+            m_out.storePtr(m_out.constIntPtr(0), m_out.absolute(scratchBuffer->addressOfActiveLength()));
+            m_out.jump(continuation);
+
+            m_out.appendTo(continuation, lastNext);
+            setJSValue(m_out.phi(Int64, fastResult, slowResult));
+            return;
+        }
+
         default:
             DFG_CRASH(m_graph, m_node, "Bad array type");
             return;
@@ -14635,7 +14729,7 @@
                     m_out.bitAnd(indexingType, m_out.constInt32(IndexingShapeMask)),
                     m_out.constInt32(ArrayStorageShape)),
                 m_out.constInt32(SlowPutArrayStorageShape - ArrayStorageShape));
-            m_out.branch(isAnArrayStorageShape, usually(checkCase), usually(continuation));
+            m_out.branch(isAnArrayStorageShape, unsure(checkCase), unsure(continuation));
 
             LBasicBlock lastNext = m_out.appendTo(checkCase, trueCase);
             switch (arrayMode.arrayClass()) {
@@ -14646,7 +14740,7 @@
             case Array::Array:
                 m_out.branch(
                     m_out.testNonZero32(indexingType, m_out.constInt32(IsArray)),
-                    usually(trueCase), usually(continuation));
+                    unsure(trueCase), unsure(continuation));
                 break;
 
             case Array::NonArray:
@@ -14653,7 +14747,7 @@
             case Array::OriginalNonArray:
                 m_out.branch(
                     m_out.testIsZero32(indexingType, m_out.constInt32(IsArray)),
-                    usually(trueCase), usually(continuation));
+                    unsure(trueCase), unsure(continuation));
                 break;
 
             case Array::PossiblyArray:
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to