Title: [229006] releases/WebKitGTK/webkit-2.20
Revision
229006
Author
[email protected]
Date
2018-02-26 05:14:10 -0800 (Mon, 26 Feb 2018)

Log Message

Merge r228860 - DFG::VarargsForwardingPhase should eliminate getting argument length
https://bugs.webkit.org/show_bug.cgi?id=182959

Reviewed by Keith Miller.

JSTests:

* microbenchmarks/forward-arguments-dont-escape-on-arguments-length.js: Added.

Source/_javascript_Core:

This patch teaches the DFG VarargsForwardingPhase to not treat
length accesses on Cloned/Direct Arguments objects as escapes.
It teaches this phase to materialize the length in the same
way the ArgumentsEliminationPhase does.

This is around a 0.5-1% speedup on ARES6 on my iMac. It speeds
up the ML subtest by 2-4%.

This patch also extends compileGetArgumentCountIncludingThis to take
a parameter that is the inline call frame to load from (in the case
where the inline call frame is a varargs frame). This allows the
the emitCodeToGetArgumentsArrayLength helper function to just emit
a GetArgumentCountIncludingThis node instead of a GetLocal. If we
emitted a GetLocal, we'd need to rerun CPS rethreading.

* dfg/DFGArgumentsEliminationPhase.cpp:
* dfg/DFGArgumentsUtilities.cpp:
(JSC::DFG::emitCodeToGetArgumentsArrayLength):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::getArgumentCount):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGNode.h:
(JSC::DFG::Node::argumentsInlineCallFrame):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileGetArgumentCountIncludingThis):
* dfg/DFGVarargsForwardingPhase.cpp:
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileGetArgumentCountIncludingThis):

Modified Paths

Added Paths

Diff

Modified: releases/WebKitGTK/webkit-2.20/JSTests/ChangeLog (229005 => 229006)


--- releases/WebKitGTK/webkit-2.20/JSTests/ChangeLog	2018-02-26 13:14:00 UTC (rev 229005)
+++ releases/WebKitGTK/webkit-2.20/JSTests/ChangeLog	2018-02-26 13:14:10 UTC (rev 229006)
@@ -1,3 +1,12 @@
+2018-02-20  Saam Barati  <[email protected]>
+
+        DFG::VarargsForwardingPhase should eliminate getting argument length
+        https://bugs.webkit.org/show_bug.cgi?id=182959
+
+        Reviewed by Keith Miller.
+
+        * microbenchmarks/forward-arguments-dont-escape-on-arguments-length.js: Added.
+
 2018-02-14  Yusuke Suzuki  <[email protected]>
 
         [FTL] Support ArrayPush for ArrayStorage

Added: releases/WebKitGTK/webkit-2.20/JSTests/microbenchmarks/forward-arguments-dont-escape-on-arguments-length.js (0 => 229006)


--- releases/WebKitGTK/webkit-2.20/JSTests/microbenchmarks/forward-arguments-dont-escape-on-arguments-length.js	                        (rev 0)
+++ releases/WebKitGTK/webkit-2.20/JSTests/microbenchmarks/forward-arguments-dont-escape-on-arguments-length.js	2018-02-26 13:14:10 UTC (rev 229006)
@@ -0,0 +1,35 @@
+function f1() {
+    'use strict';
+    if (arguments.length === 1)
+        return 25;
+    return 42;
+}
+noFTL(f1);
+noInline(f1);
+
+function f2() {
+    if (arguments.length === 1)
+        return 25;
+    return 42;
+}
+noFTL(f2);
+noInline(f2);
+
+class C {
+    construct() {
+        let x = 1;
+        if (arguments.length === 2)
+            --x;
+        if (x)
+            this.x = x; 
+    }
+}
+noFTL(C);
+noInline(C);
+
+for (let i = 0; i < 1000000; ++i)
+    f1(10, 20);
+for (let i = 0; i < 1000000; ++i)
+    f2(10, 20);
+for (let i = 0; i < 1000000; ++i)
+    new C(10, 20);

Modified: releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/ChangeLog (229005 => 229006)


--- releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/ChangeLog	2018-02-26 13:14:00 UTC (rev 229005)
+++ releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/ChangeLog	2018-02-26 13:14:10 UTC (rev 229006)
@@ -1,3 +1,40 @@
+2018-02-20  Saam Barati  <[email protected]>
+
+        DFG::VarargsForwardingPhase should eliminate getting argument length
+        https://bugs.webkit.org/show_bug.cgi?id=182959
+
+        Reviewed by Keith Miller.
+
+        This patch teaches the DFG VarargsForwardingPhase to not treat
+        length accesses on Cloned/Direct Arguments objects as escapes.
+        It teaches this phase to materialize the length in the same
+        way the ArgumentsEliminationPhase does.
+        
+        This is around a 0.5-1% speedup on ARES6 on my iMac. It speeds
+        up the ML subtest by 2-4%.
+        
+        This patch also extends compileGetArgumentCountIncludingThis to take
+        a parameter that is the inline call frame to load from (in the case
+        where the inline call frame is a varargs frame). This allows the
+        the emitCodeToGetArgumentsArrayLength helper function to just emit
+        a GetArgumentCountIncludingThis node instead of a GetLocal. If we
+        emitted a GetLocal, we'd need to rerun CPS rethreading.
+
+        * dfg/DFGArgumentsEliminationPhase.cpp:
+        * dfg/DFGArgumentsUtilities.cpp:
+        (JSC::DFG::emitCodeToGetArgumentsArrayLength):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::getArgumentCount):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::argumentsInlineCallFrame):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileGetArgumentCountIncludingThis):
+        * dfg/DFGVarargsForwardingPhase.cpp:
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileGetArgumentCountIncludingThis):
+
 2018-02-14  Yusuke Suzuki  <[email protected]>
 
         [FTL] Support ArrayPush for ArrayStorage

Modified: releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/dfg/DFGArgumentsEliminationPhase.cpp (229005 => 229006)


--- releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/dfg/DFGArgumentsEliminationPhase.cpp	2018-02-26 13:14:00 UTC (rev 229005)
+++ releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/dfg/DFGArgumentsEliminationPhase.cpp	2018-02-26 13:14:10 UTC (rev 229006)
@@ -708,6 +708,8 @@
                     if (!isEliminatedAllocation(candidate))
                         break;
 
+                    // FIXME: This should be an assert:
+                    // https://bugs.webkit.org/show_bug.cgi?id=182982
                     if (node->child2()->op() != PhantomClonedArguments)
                         break;
 

Modified: releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/dfg/DFGArgumentsUtilities.cpp (229005 => 229006)


--- releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/dfg/DFGArgumentsUtilities.cpp	2018-02-26 13:14:00 UTC (rev 229005)
+++ releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/dfg/DFGArgumentsUtilities.cpp	2018-02-26 13:14:10 UTC (rev 229006)
@@ -91,16 +91,8 @@
             nodeIndex, origin, jsNumber(argumentsSize));
     }
     
-    Node* argumentCount;
-    if (!inlineCallFrame)
-        argumentCount = insertionSet.insertNode(nodeIndex, SpecInt32Only, GetArgumentCountIncludingThis, origin);
-    else {
-        VirtualRegister argumentCountRegister(inlineCallFrame->stackOffset + CallFrameSlot::argumentCount);
-        
-        argumentCount = insertionSet.insertNode(
-            nodeIndex, SpecInt32Only, GetStack, origin,
-            OpInfo(graph.m_stackAccessData.add(argumentCountRegister, FlushedInt32)));
-    }
+    Node* argumentCount = insertionSet.insertNode(nodeIndex,
+        SpecInt32Only, GetArgumentCountIncludingThis, origin, OpInfo(inlineCallFrame));
 
     Node* result = insertionSet.insertNode(
         nodeIndex, SpecInt32Only, ArithSub, origin, OpInfo(Arith::Unchecked),

Modified: releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (229005 => 229006)


--- releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2018-02-26 13:14:00 UTC (rev 229005)
+++ releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2018-02-26 13:14:10 UTC (rev 229006)
@@ -1352,13 +1352,10 @@
 Node* ByteCodeParser::getArgumentCount()
 {
     Node* argumentCount;
-    if (m_inlineStackTop->m_inlineCallFrame) {
-        if (m_inlineStackTop->m_inlineCallFrame->isVarargs())
-            argumentCount = get(VirtualRegister(CallFrameSlot::argumentCount));
-        else
-            argumentCount = jsConstant(m_graph.freeze(jsNumber(m_inlineStackTop->m_inlineCallFrame->argumentCountIncludingThis))->value());
-    } else
-        argumentCount = addToGraph(GetArgumentCountIncludingThis, OpInfo(0), OpInfo(SpecInt32Only));
+    if (m_inlineStackTop->m_inlineCallFrame && !m_inlineStackTop->m_inlineCallFrame->isVarargs())
+        argumentCount = jsConstant(m_graph.freeze(jsNumber(m_inlineStackTop->m_inlineCallFrame->argumentCountIncludingThis))->value());
+    else
+        argumentCount = addToGraph(GetArgumentCountIncludingThis, OpInfo(m_inlineStackTop->m_inlineCallFrame), OpInfo(SpecInt32Only));
     return argumentCount;
 }
 

Modified: releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/dfg/DFGClobberize.h (229005 => 229006)


--- releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/dfg/DFGClobberize.h	2018-02-26 13:14:00 UTC (rev 229005)
+++ releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/dfg/DFGClobberize.h	2018-02-26 13:14:10 UTC (rev 229006)
@@ -35,6 +35,7 @@
 #include "DFGPureValue.h"
 #include "DOMJITCallDOMGetterSnippet.h"
 #include "DOMJITSignature.h"
+#include "InlineCallFrame.h"
 #include "JSFixedArray.h"
 
 namespace JSC { namespace DFG {
@@ -702,10 +703,12 @@
         def(HeapLocation(StackLoc, AbstractHeap(Stack, CallFrameSlot::callee)), LazyNode(node));
         return;
         
-    case GetArgumentCountIncludingThis:
-        read(AbstractHeap(Stack, CallFrameSlot::argumentCount));
-        def(HeapLocation(StackPayloadLoc, AbstractHeap(Stack, CallFrameSlot::argumentCount)), LazyNode(node));
+    case GetArgumentCountIncludingThis: {
+        auto heap = AbstractHeap(Stack, remapOperand(node->argumentsInlineCallFrame(), VirtualRegister(CallFrameSlot::argumentCount)));
+        read(heap);
+        def(HeapLocation(StackPayloadLoc, heap), LazyNode(node));
         return;
+    }
 
     case SetArgumentCountIncludingThis:
         write(AbstractHeap(Stack, CallFrameSlot::argumentCount));

Modified: releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/dfg/DFGNode.h (229005 => 229006)


--- releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/dfg/DFGNode.h	2018-02-26 13:14:00 UTC (rev 229005)
+++ releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/dfg/DFGNode.h	2018-02-26 13:14:10 UTC (rev 229006)
@@ -1265,6 +1265,12 @@
         return m_opInfo.as<LoadVarargsData*>();
     }
 
+    InlineCallFrame* argumentsInlineCallFrame()
+    {
+        ASSERT(op() == GetArgumentCountIncludingThis);
+        return m_opInfo.as<InlineCallFrame*>();
+    }
+
     bool hasQueriedType()
     {
         return op() == IsCellWithType;

Modified: releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (229005 => 229006)


--- releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2018-02-26 13:14:00 UTC (rev 229005)
+++ releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2018-02-26 13:14:10 UTC (rev 229006)
@@ -11337,7 +11337,12 @@
 void SpeculativeJIT::compileGetArgumentCountIncludingThis(Node* node)
 {
     GPRTemporary result(this);
-    m_jit.load32(JITCompiler::payloadFor(CallFrameSlot::argumentCount), result.gpr());
+    VirtualRegister argumentCountRegister;
+    if (InlineCallFrame* inlineCallFrame = node->argumentsInlineCallFrame())
+        argumentCountRegister = inlineCallFrame->argumentCountRegister;
+    else
+        argumentCountRegister = VirtualRegister(CallFrameSlot::argumentCount);
+    m_jit.load32(JITCompiler::payloadFor(argumentCountRegister), result.gpr());
     int32Result(result.gpr(), node);
 }
 

Modified: releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/dfg/DFGValidate.cpp (229005 => 229006)


--- releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/dfg/DFGValidate.cpp	2018-02-26 13:14:00 UTC (rev 229005)
+++ releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/dfg/DFGValidate.cpp	2018-02-26 13:14:10 UTC (rev 229006)
@@ -346,6 +346,11 @@
                     }
                     break;
                 }
+                case GetArgumentCountIncludingThis: {
+                    if (InlineCallFrame* inlineCallFrame = node->argumentsInlineCallFrame())
+                        VALIDATE((node), inlineCallFrame->isVarargs());
+                    break;
+                }
                 default:
                     break;
                 }

Modified: releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/dfg/DFGVarargsForwardingPhase.cpp (229005 => 229006)


--- releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/dfg/DFGVarargsForwardingPhase.cpp	2018-02-26 13:14:00 UTC (rev 229005)
+++ releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/dfg/DFGVarargsForwardingPhase.cpp	2018-02-26 13:14:10 UTC (rev 229006)
@@ -28,6 +28,7 @@
 
 #if ENABLE(DFG_JIT)
 
+#include "ClonedArguments.h"
 #include "DFGArgumentsUtilities.h"
 #include "DFGClobberize.h"
 #include "DFGForAllKills.h"
@@ -90,6 +91,11 @@
         if (DFGVarargsForwardingPhaseInternal::verbose)
             dataLog("Handling candidate ", candidate, "\n");
         
+        // We eliminate GetButterfly over CreateClonedArguments if the butterfly is only
+        // used by a GetByOffset  that loads the CreateClonedArguments's length. We also
+        // eliminate it if the GetButterfly node is totally unused.
+        Vector<Node*, 1> candidateButterflies; 
+
         // Find the index of the last node in this block to use the candidate, and look for escaping
         // sites.
         unsigned lastUserIndex = candidateNodeIndex;
@@ -96,7 +102,17 @@
         Vector<VirtualRegister, 2> relevantLocals; // This is a set. We expect it to be a small set.
         for (unsigned nodeIndex = candidateNodeIndex + 1; nodeIndex < block->size(); ++nodeIndex) {
             Node* node = block->at(nodeIndex);
-            
+
+            auto defaultEscape = [&] {
+                if (m_graph.uses(node, candidate)) {
+                    if (DFGVarargsForwardingPhaseInternal::verbose)
+                        dataLog("    Escape at ", node, "\n");
+                    return true;
+                }
+                return false;
+            };
+
+            bool validGetByOffset = false;
             switch (node->op()) {
             case MovHint:
                 if (node->child1() != candidate)
@@ -156,15 +172,61 @@
                     return;
                 }
                 break;
-                
+
+            case GetArrayLength: {
+                if (node->arrayMode().type() == Array::DirectArguments && node->child1() == candidate && node->child1()->op() == CreateDirectArguments) {
+                    lastUserIndex = nodeIndex;
+                    break;
+                }
+                if (defaultEscape())
+                    return;
+                break;
+            }
+            
+            case GetButterfly: {
+                if (node->child1() == candidate && candidate->op() == CreateClonedArguments) {
+                    lastUserIndex = nodeIndex;
+                    candidateButterflies.append(node);
+                    break;
+                }
+                if (defaultEscape())
+                    return;
+                break;
+            }
+            
+            case GetByOffset: {
+                if (node->child1()->op() == GetButterfly
+                    && candidateButterflies.contains(node->child1().node())
+                    && node->child2() == candidate
+                    && node->storageAccessData().offset == clonedArgumentsLengthPropertyOffset) {
+                    ASSERT(node->child1()->child1() == candidate);
+                    ASSERT(isOutOfLineOffset(clonedArgumentsLengthPropertyOffset));
+                    // We're good to go. This is getting the length of the arguments.
+                    lastUserIndex = nodeIndex;
+                    validGetByOffset = true;
+                    break;
+                }
+                if (defaultEscape())
+                    return;
+                break;
+            }
+
             default:
-                if (m_graph.uses(node, candidate)) {
-                    if (DFGVarargsForwardingPhaseInternal::verbose)
-                        dataLog("    Escape at ", node, "\n");
+                if (defaultEscape())
                     return;
+                break;
+            }
+
+            if (!validGetByOffset) {
+                for (Node* butterfly : candidateButterflies) {
+                    if (m_graph.uses(node, butterfly)) {
+                        if (DFGVarargsForwardingPhaseInternal::verbose)
+                            dataLog("    Butterfly escaped at ", node, "\n");
+                        return;
+                    }
                 }
             }
-            
+
             forAllKilledOperands(
                 m_graph, node, block->tryAt(nodeIndex + 1),
                 [&] (VirtualRegister reg) {
@@ -261,6 +323,8 @@
             DFG_CRASH(m_graph, candidate, "bad node type");
             break;
         }
+
+        InsertionSet insertionSet(m_graph);
         for (unsigned nodeIndex = candidateNodeIndex + 1; nodeIndex <= lastUserIndex; ++nodeIndex) {
             Node* node = block->at(nodeIndex);
             switch (node->op()) {
@@ -308,7 +372,33 @@
                 // soon, since it has no real users. DCE will surely kill it. If we make it to SSA, then
                 // SSA conversion will kill it.
                 break;
-                
+
+            case GetButterfly: {
+                if (node->child1().node() == candidate) {
+                    ASSERT(candidateButterflies.contains(node));
+                    node->child1() = Edge();
+                    node->remove(m_graph);
+                }
+                break;
+            }
+
+            case GetByOffset: {
+                if (node->child2() == candidate) {
+                    ASSERT(candidateButterflies.contains(node->child1().node())); // It's no longer a GetButterfly node, but it should've been a candidate butterfly.
+                    ASSERT(node->storageAccessData().offset == clonedArgumentsLengthPropertyOffset);
+                    node->convertToIdentityOn(
+                        emitCodeToGetArgumentsArrayLength(insertionSet, candidate, nodeIndex, node->origin));
+                }
+                break;
+            }
+
+            case GetArrayLength:
+                if (node->arrayMode().type() == Array::DirectArguments && node->child1() == candidate) {
+                    node->convertToIdentityOn(
+                        emitCodeToGetArgumentsArrayLength(insertionSet, candidate, nodeIndex, node->origin));
+                }
+                break;
+
             default:
                 if (ASSERT_DISABLED)
                     break;
@@ -320,6 +410,8 @@
                 break;
             }
         }
+
+        insertionSet.execute(block);
     }
     
     bool m_changed;

Modified: releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (229005 => 229006)


--- releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2018-02-26 13:14:00 UTC (rev 229005)
+++ releases/WebKitGTK/webkit-2.20/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2018-02-26 13:14:10 UTC (rev 229006)
@@ -6550,7 +6550,12 @@
     
     void compileGetArgumentCountIncludingThis()
     {
-        setInt32(m_out.load32(payloadFor(CallFrameSlot::argumentCount)));
+        VirtualRegister argumentCountRegister;
+        if (InlineCallFrame* inlineCallFrame = m_node->argumentsInlineCallFrame())
+            argumentCountRegister = inlineCallFrame->argumentCountRegister;
+        else
+            argumentCountRegister = VirtualRegister(CallFrameSlot::argumentCount);
+        setInt32(m_out.load32(payloadFor(argumentCountRegister)));
     }
 
     void compileSetArgumentCountIncludingThis()
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to