Title: [229742] trunk
Revision
229742
Author
utatane....@gmail.com
Date
2018-03-20 00:12:56 -0700 (Tue, 20 Mar 2018)

Log Message

[DFG][FTL] Make ArraySlice(0) code tight
https://bugs.webkit.org/show_bug.cgi?id=183590

Reviewed by Saam Barati.

JSTests:

* stress/array-slice-with-zero.js: Added.
(shouldBe):
(test):
(test2):
* stress/array-slice-zero-args.js: Added.
(shouldBe):
(test):

Source/_javascript_Core:

This patch tightens ArraySlice code, in particular, startIndex = 0 case.

1. We support array.slice() call. This is a well-used way to clone array.
For example, underscore.js uses this technique.

2. We remove several checks if the given index value is a proven constant.

* dfg/DFGBackwardsPropagationPhase.cpp:
(JSC::DFG::BackwardsPropagationPhase::propagate):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsicCall):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::emitPopulateSliceIndex):
(JSC::DFG::SpeculativeJIT::compileArraySlice):
We can skip some of checks if the given value is a proven constant.

* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileArraySlice):
Change below to belowOrEqual. It does not change meaning in the code. But it allows us
to fold BelowEqual(0, x) to true.

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (229741 => 229742)


--- trunk/JSTests/ChangeLog	2018-03-20 06:26:36 UTC (rev 229741)
+++ trunk/JSTests/ChangeLog	2018-03-20 07:12:56 UTC (rev 229742)
@@ -1,3 +1,18 @@
+2018-03-13  Yusuke Suzuki  <utatane....@gmail.com>
+
+        [DFG][FTL] Make ArraySlice(0) code tight
+        https://bugs.webkit.org/show_bug.cgi?id=183590
+
+        Reviewed by Saam Barati.
+
+        * stress/array-slice-with-zero.js: Added.
+        (shouldBe):
+        (test):
+        (test2):
+        * stress/array-slice-zero-args.js: Added.
+        (shouldBe):
+        (test):
+
 2018-03-14  Caitlin Potter  <ca...@igalia.com>
 
         [JSC] fix order of evaluation for ClassDefinitionEvaluation

Added: trunk/JSTests/stress/array-slice-with-zero.js (0 => 229742)


--- trunk/JSTests/stress/array-slice-with-zero.js	                        (rev 0)
+++ trunk/JSTests/stress/array-slice-with-zero.js	2018-03-20 07:12:56 UTC (rev 229742)
@@ -0,0 +1,34 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(array)
+{
+    return array.slice(0);
+}
+noInline(test);
+
+for (var i = 0; i < 1e5; ++i) {
+    var array = [i, i, i];
+    var result = test(array);
+    shouldBe(array !== result, true);
+    shouldBe(result.length, 3);
+    for (var j = 0; j < 3; ++j)
+        shouldBe(result[j], i);
+}
+
+function test2(array, i)
+{
+    return array.slice(0, i);
+}
+noInline(test2);
+
+for (var i = 0; i < 1e5; ++i) {
+    var array = [i, i, i];
+    var result = test2(array, 2);
+    shouldBe(array !== result, true);
+    shouldBe(result.length, 2);
+    for (var j = 0; j < 2; ++j)
+        shouldBe(result[j], i);
+}

Added: trunk/JSTests/stress/array-slice-zero-args.js (0 => 229742)


--- trunk/JSTests/stress/array-slice-zero-args.js	                        (rev 0)
+++ trunk/JSTests/stress/array-slice-zero-args.js	2018-03-20 07:12:56 UTC (rev 229742)
@@ -0,0 +1,19 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test(array)
+{
+    return array.slice();
+}
+noInline(test);
+
+for (var i = 0; i < 1e6; ++i) {
+    var array = [i, i, i];
+    var result = test(array);
+    shouldBe(array !== result, true);
+    shouldBe(result.length, 3);
+    for (var j = 0; j < 3; ++j)
+        shouldBe(result[j], i);
+}

Modified: trunk/Source/_javascript_Core/ChangeLog (229741 => 229742)


--- trunk/Source/_javascript_Core/ChangeLog	2018-03-20 06:26:36 UTC (rev 229741)
+++ trunk/Source/_javascript_Core/ChangeLog	2018-03-20 07:12:56 UTC (rev 229742)
@@ -1,3 +1,33 @@
+2018-03-13  Yusuke Suzuki  <utatane....@gmail.com>
+
+        [DFG][FTL] Make ArraySlice(0) code tight
+        https://bugs.webkit.org/show_bug.cgi?id=183590
+
+        Reviewed by Saam Barati.
+
+        This patch tightens ArraySlice code, in particular, startIndex = 0 case.
+
+        1. We support array.slice() call. This is a well-used way to clone array.
+        For example, underscore.js uses this technique.
+
+        2. We remove several checks if the given index value is a proven constant.
+
+        * dfg/DFGBackwardsPropagationPhase.cpp:
+        (JSC::DFG::BackwardsPropagationPhase::propagate):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::emitPopulateSliceIndex):
+        (JSC::DFG::SpeculativeJIT::compileArraySlice):
+        We can skip some of checks if the given value is a proven constant.
+
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileArraySlice):
+        Change below to belowOrEqual. It does not change meaning in the code. But it allows us
+        to fold BelowEqual(0, x) to true.
+
 2018-03-19  Yusuke Suzuki  <utatane....@gmail.com>
 
         Drop s_exceptionInstructions static initializer

Modified: trunk/Source/_javascript_Core/dfg/DFGBackwardsPropagationPhase.cpp (229741 => 229742)


--- trunk/Source/_javascript_Core/dfg/DFGBackwardsPropagationPhase.cpp	2018-03-20 06:26:36 UTC (rev 229741)
+++ trunk/Source/_javascript_Core/dfg/DFGBackwardsPropagationPhase.cpp	2018-03-20 07:12:56 UTC (rev 229742)
@@ -238,10 +238,14 @@
 
         case ArraySlice: {
             m_graph.varArgChild(node, 0)->mergeFlags(NodeBytecodeUsesAsValue);
-            m_graph.varArgChild(node, 1)->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
-            if (node->numChildren() == 3)
+
+            if (node->numChildren() == 2)
+                m_graph.varArgChild(node, 1)->mergeFlags(NodeBytecodeUsesAsValue);
+            else if (node->numChildren() == 3) {
+                m_graph.varArgChild(node, 1)->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
                 m_graph.varArgChild(node, 2)->mergeFlags(NodeBytecodeUsesAsValue);
-            else {
+            } else if (node->numChildren() == 4) {
+                m_graph.varArgChild(node, 1)->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
                 m_graph.varArgChild(node, 2)->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
                 m_graph.varArgChild(node, 3)->mergeFlags(NodeBytecodeUsesAsValue);
             }

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (229741 => 229742)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2018-03-20 06:26:36 UTC (rev 229741)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2018-03-20 07:12:56 UTC (rev 229742)
@@ -2241,7 +2241,7 @@
             return false;
         }
 #endif
-        if (argumentCountIncludingThis < 2)
+        if (argumentCountIncludingThis < 1)
             return false;
 
         if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadConstantCache)
@@ -2303,7 +2303,8 @@
                 addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(structureSet)), array);
 
                 addVarArgChild(array);
-                addVarArgChild(get(virtualRegisterForArgument(1, registerOffset))); // Start index.
+                if (argumentCountIncludingThis >= 2)
+                    addVarArgChild(get(virtualRegisterForArgument(1, registerOffset))); // Start index.
                 if (argumentCountIncludingThis >= 3)
                     addVarArgChild(get(virtualRegisterForArgument(2, registerOffset))); // End index.
                 addVarArgChild(addToGraph(GetButterfly, array));

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (229741 => 229742)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2018-03-20 06:26:36 UTC (rev 229741)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2018-03-20 07:12:56 UTC (rev 229742)
@@ -1075,9 +1075,11 @@
 
         case ArraySlice: {
             fixEdge<KnownCellUse>(m_graph.varArgChild(node, 0));
-            fixEdge<Int32Use>(m_graph.varArgChild(node, 1));
-            if (node->numChildren() == 4)
-                fixEdge<Int32Use>(m_graph.varArgChild(node, 2));
+            if (node->numChildren() >= 3) {
+                fixEdge<Int32Use>(m_graph.varArgChild(node, 1));
+                if (node->numChildren() == 4)
+                    fixEdge<Int32Use>(m_graph.varArgChild(node, 2));
+            }
             break;
         }
 

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (229741 => 229742)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2018-03-20 06:26:36 UTC (rev 229741)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2018-03-20 07:12:56 UTC (rev 229742)
@@ -7619,9 +7619,32 @@
 
 void SpeculativeJIT::emitPopulateSliceIndex(Edge& target, GPRReg length, GPRReg result)
 {
+    if (target->isInt32Constant()) {
+        int32_t value = target->asInt32();
+        if (value == 0) {
+            m_jit.move(TrustedImm32(0), result);
+            return;
+        }
+
+        MacroAssembler::JumpList done;
+        if (value > 0) {
+            m_jit.move(TrustedImm32(value), result);
+            done.append(m_jit.branch32(MacroAssembler::BelowOrEqual, result, length));
+            m_jit.move(length, result);
+        } else {
+            ASSERT(value != 0);
+            m_jit.move(length, result);
+            done.append(m_jit.branchAdd32(MacroAssembler::PositiveOrZero, TrustedImm32(value), result));
+            m_jit.move(TrustedImm32(0), result);
+        }
+        done.link(&m_jit);
+        return;
+    }
+
     SpeculateInt32Operand index(this, target);
     GPRReg indexGPR = index.gpr();
     MacroAssembler::JumpList done;
+
     auto isPositive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, indexGPR, TrustedImm32(0));
     m_jit.move(length, result);
     done.append(m_jit.branchAdd32(MacroAssembler::PositiveOrZero, indexGPR, result));
@@ -7643,7 +7666,7 @@
     JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
 
     GPRTemporary temp(this);
-    StorageOperand storage(this, node->numChildren() == 3 ? m_jit.graph().varArgChild(node, 2) : m_jit.graph().varArgChild(node, 3));
+    StorageOperand storage(this, m_jit.graph().varArgChild(node, node->numChildren() - 1));
     GPRTemporary result(this);
     
     GPRReg storageGPR = storage.gpr();
@@ -7650,7 +7673,10 @@
     GPRReg resultGPR = result.gpr();
     GPRReg tempGPR = temp.gpr();
 
-    {
+    if (node->numChildren() == 2)
+        m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), tempGPR);
+    else {
+        ASSERT(node->numChildren() == 3 || node->numChildren() == 4);
         GPRTemporary tempLength(this);
         GPRReg lengthGPR = tempLength.gpr();
         m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), lengthGPR);
@@ -7660,17 +7686,22 @@
         else
             m_jit.move(lengthGPR, tempGPR);
 
-        GPRTemporary tempStartIndex(this);
-        GPRReg startGPR = tempStartIndex.gpr();
-        emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 1), lengthGPR, startGPR);
+        if (m_jit.graph().varArgChild(node, 1)->isInt32Constant() && m_jit.graph().varArgChild(node, 1)->asInt32() == 0) {
+            // Do nothing for array.slice(0, end) or array.slice(0) cases.
+            // `tempGPR` already points to the size of a newly created array.
+        } else {
+            GPRTemporary tempStartIndex(this);
+            GPRReg startGPR = tempStartIndex.gpr();
+            emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 1), lengthGPR, startGPR);
 
-        auto tooBig = m_jit.branch32(MacroAssembler::Above, startGPR, tempGPR);
-        m_jit.sub32(startGPR, tempGPR); // the size of the array we'll make.
-        auto done = m_jit.jump();
+            auto tooBig = m_jit.branch32(MacroAssembler::Above, startGPR, tempGPR);
+            m_jit.sub32(startGPR, tempGPR); // the size of the array we'll make.
+            auto done = m_jit.jump();
 
-        tooBig.link(&m_jit);
-        m_jit.move(TrustedImm32(0), tempGPR);
-        done.link(&m_jit);
+            tooBig.link(&m_jit);
+            m_jit.move(TrustedImm32(0), tempGPR);
+            done.link(&m_jit);
+        }
     }
 
 
@@ -7757,12 +7788,17 @@
     GPRTemporary temp4(this);
     GPRReg loadIndex = temp4.gpr();
 
-    m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), tempValue);
-    if (node->numChildren() == 4)
-        emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 2), tempValue, tempGPR);
-    else
-        m_jit.move(tempValue, tempGPR);
-    emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 1), tempValue, loadIndex);
+    if (node->numChildren() == 2) {
+        m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), tempGPR);
+        m_jit.move(TrustedImm32(0), loadIndex);
+    } else {
+        m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), tempValue);
+        if (node->numChildren() == 4)
+            emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 2), tempValue, tempGPR);
+        else
+            m_jit.move(tempValue, tempGPR);
+        emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 1), tempValue, loadIndex);
+    }
 
     GPRTemporary temp5(this);
     GPRReg storeIndex = temp5.gpr();

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (229741 => 229742)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2018-03-20 06:26:36 UTC (rev 229741)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2018-03-20 07:12:56 UTC (rev 229742)
@@ -4690,21 +4690,29 @@
     {
         JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
 
-        LValue sourceStorage = lowStorage(m_node->numChildren() == 3 ? m_graph.varArgChild(m_node, 2) : m_graph.varArgChild(m_node, 3));
+        LValue sourceStorage = lowStorage(m_graph.varArgChild(m_node, m_node->numChildren() - 1));
         LValue inputLength = m_out.load32(sourceStorage, m_heaps.Butterfly_publicLength);
-        LValue start = lowInt32(m_graph.varArgChild(m_node, 1));
-        LValue end = nullptr;
-        if (m_node->numChildren() != 3)
-            end = lowInt32(m_graph.varArgChild(m_node, 2));
 
-        auto range = populateSliceRange(start, end, inputLength);
-        LValue startIndex = range.first;
-        LValue endBoundary = range.second;
+        LValue startIndex = nullptr;
+        LValue resultLength = nullptr;
+        if (m_node->numChildren() == 2) {
+            startIndex = m_out.constInt32(0);
+            resultLength = inputLength;
+        } else {
+            LValue start = lowInt32(m_graph.varArgChild(m_node, 1));
+            LValue end = nullptr;
+            if (m_node->numChildren() != 3)
+                end = lowInt32(m_graph.varArgChild(m_node, 2));
 
-        LValue resultLength = m_out.select(m_out.below(startIndex, endBoundary),
-            m_out.sub(endBoundary, startIndex),
-            m_out.constInt32(0));
+            auto range = populateSliceRange(start, end, inputLength);
+            startIndex = range.first;
+            LValue endBoundary = range.second;
 
+            resultLength = m_out.select(m_out.belowOrEqual(startIndex, endBoundary),
+                m_out.sub(endBoundary, startIndex),
+                m_out.constInt32(0));
+        }
+
         ArrayValues arrayResult;
         {
             LValue indexingType = m_out.load8ZeroExt32(lowCell(m_graph.varArgChild(m_node, 0)), m_heaps.JSCell_indexingTypeAndMisc);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to