Title: [227410] trunk
Revision
227410
Author
[email protected]
Date
2018-01-23 06:28:10 -0800 (Tue, 23 Jan 2018)

Log Message

Update the argument count in DFGByteCodeParser::handleRecursiveCall
https://bugs.webkit.org/show_bug.cgi?id=181739
<rdar://problem/36627662>

Reviewed by Saam Barati.

JSTests:

* stress/recursive-tail-call-with-different-argument-count.js: Added.
(foo):
(bar):

Source/_javascript_Core:

When calling a function, its number of arguments is set on the stack. When we turn a recursive tail call
into a jump, we should update that stack slot as there is no guarantee that the function was originally
called with the same number of arguments. Forgetting to do this is observable through 'arguments.length'.

It required adding a new DFG node: 'SetArgumentCountIncludingThis', that takes an unsigned int
as its first OpInfo field, and stores it to the stack at the right place.

We must be a bit careful in where we put this new node, as it ClobbersExit.
We must also fix DFGArgumentsEliminationPhase and DFGPutStackSinkingPhase as they assumed that any node that writes to the stack must write to either an argument or a local.

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGArgumentsEliminationPhase.cpp:
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleRecursiveTailCall):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGMayExit.cpp:
* dfg/DFGNode.h:
(JSC::DFG::Node::argumentCountIncludingThis):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGPutStackSinkingPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileSetArgumentCountIncludingThis):
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileSetArgumentCountIncludingThis):

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (227409 => 227410)


--- trunk/JSTests/ChangeLog	2018-01-23 12:07:42 UTC (rev 227409)
+++ trunk/JSTests/ChangeLog	2018-01-23 14:28:10 UTC (rev 227410)
@@ -1,3 +1,15 @@
+2018-01-23  Robin Morisset  <[email protected]>
+
+        Update the argument count in DFGByteCodeParser::handleRecursiveCall
+        https://bugs.webkit.org/show_bug.cgi?id=181739
+        <rdar://problem/36627662>
+
+        Reviewed by Saam Barati.
+
+        * stress/recursive-tail-call-with-different-argument-count.js: Added.
+        (foo):
+        (bar):
+
 2018-01-22  Michael Saboff  <[email protected]>
 
         DFG abstract interpreter needs to properly model effects of some Math ops

Added: trunk/JSTests/stress/recursive-tail-call-with-different-argument-count.js (0 => 227410)


--- trunk/JSTests/stress/recursive-tail-call-with-different-argument-count.js	                        (rev 0)
+++ trunk/JSTests/stress/recursive-tail-call-with-different-argument-count.js	2018-01-23 14:28:10 UTC (rev 227410)
@@ -0,0 +1,25 @@
+"use strict";
+function foo(x, y)
+{
+    if (arguments.length >= 2)
+        return foo(x+y)
+    return x;
+}
+noInline(foo);
+
+function bar(x)
+{
+    if (arguments.length >= 2)
+        return bar(arguments[0] + arguments[1])
+    return x;
+}
+noInline(bar);
+
+for (var i = 0; i < 10000; ++i) {
+    var result = foo(40, 2);
+    if (result !== 42)
+        throw "Wrong result for foo, expected 42, got " + result;
+    result = bar(40, 2);
+    if (result !== 42)
+        throw "Wrong result for bar, expected 42, got " + result;
+}

Modified: trunk/Source/_javascript_Core/ChangeLog (227409 => 227410)


--- trunk/Source/_javascript_Core/ChangeLog	2018-01-23 12:07:42 UTC (rev 227409)
+++ trunk/Source/_javascript_Core/ChangeLog	2018-01-23 14:28:10 UTC (rev 227410)
@@ -1,3 +1,53 @@
+2018-01-23  Robin Morisset  <[email protected]>
+
+        Update the argument count in DFGByteCodeParser::handleRecursiveCall
+        https://bugs.webkit.org/show_bug.cgi?id=181739
+        <rdar://problem/36627662>
+
+        Reviewed by Saam Barati.
+
+        When calling a function, its number of arguments is set on the stack. When we turn a recursive tail call
+        into a jump, we should update that stack slot as there is no guarantee that the function was originally
+        called with the same number of arguments. Forgetting to do this is observable through 'arguments.length'.
+
+        It required adding a new DFG node: 'SetArgumentCountIncludingThis', that takes an unsigned int
+        as its first OpInfo field, and stores it to the stack at the right place.
+
+        We must be a bit careful in where we put this new node, as it ClobbersExit.
+        We must also fix DFGArgumentsEliminationPhase and DFGPutStackSinkingPhase as they assumed that any node that writes to the stack must write to either an argument or a local.
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGArgumentsEliminationPhase.cpp:
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleRecursiveTailCall):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGMayExit.cpp:
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::argumentCountIncludingThis):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGPutStackSinkingPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileSetArgumentCountIncludingThis):
+        * dfg/DFGSpeculativeJIT.h:
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileSetArgumentCountIncludingThis):
+
 2018-01-22  Michael Saboff  <[email protected]>
 
         DFG abstract interpreter needs to properly model effects of some Math ops

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (227409 => 227410)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2018-01-23 12:07:42 UTC (rev 227409)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2018-01-23 14:28:10 UTC (rev 227410)
@@ -2345,6 +2345,9 @@
     case GetArgumentCountIncludingThis:
         forNode(node).setType(SpecInt32Only);
         break;
+
+    case SetArgumentCountIncludingThis:
+        break;
         
     case GetRestLength:
         forNode(node).setType(SpecInt32Only);

Modified: trunk/Source/_javascript_Core/dfg/DFGArgumentsEliminationPhase.cpp (227409 => 227410)


--- trunk/Source/_javascript_Core/dfg/DFGArgumentsEliminationPhase.cpp	2018-01-23 12:07:42 UTC (rev 227409)
+++ trunk/Source/_javascript_Core/dfg/DFGArgumentsEliminationPhase.cpp	2018-01-23 14:28:10 UTC (rev 227410)
@@ -484,7 +484,9 @@
                         }
                         ASSERT(!heap.payload().isTop());
                         VirtualRegister reg(heap.payload().value32());
-                        clobberedByThisBlock.operand(reg) = true;
+                        // The register may not point to an argument or local, for example if we are looking at SetArgumentCountIncludingThis.
+                        if (!reg.isHeader())
+                            clobberedByThisBlock.operand(reg) = true;
                     },
                     NoOpClobberize());
             }

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (227409 => 227410)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2018-01-23 12:07:42 UTC (rev 227409)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2018-01-23 14:28:10 UTC (rev 227410)
@@ -1403,6 +1403,8 @@
         flushForTerminal();
 
         // We must set the arguments to the right values
+        if (!stackEntry->m_inlineCallFrame)
+            addToGraph(SetArgumentCountIncludingThis, OpInfo(argumentCountIncludingThis));
         int argIndex = 0;
         for (; argIndex < argumentCountIncludingThis; ++argIndex) {
             Node* value = get(virtualRegisterForArgument(argIndex, registerOffset));

Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (227409 => 227410)


--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2018-01-23 12:07:42 UTC (rev 227409)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2018-01-23 14:28:10 UTC (rev 227410)
@@ -706,6 +706,10 @@
         def(HeapLocation(StackPayloadLoc, AbstractHeap(Stack, CallFrameSlot::argumentCount)), LazyNode(node));
         return;
 
+    case SetArgumentCountIncludingThis:
+        write(AbstractHeap(Stack, CallFrameSlot::argumentCount));
+        return;
+
     case GetRestLength:
         read(Stack);
         return;

Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (227409 => 227410)


--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2018-01-23 12:07:42 UTC (rev 227409)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2018-01-23 14:28:10 UTC (rev 227410)
@@ -52,6 +52,7 @@
     case IdentityWithProfile:
     case GetCallee:
     case GetArgumentCountIncludingThis:
+    case SetArgumentCountIncludingThis:
     case GetRestLength:
     case GetLocal:
     case SetLocal:

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (227409 => 227410)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2018-01-23 12:07:42 UTC (rev 227409)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2018-01-23 14:28:10 UTC (rev 227410)
@@ -2099,6 +2099,7 @@
         case GetLocal:
         case GetCallee:
         case GetArgumentCountIncludingThis:
+        case SetArgumentCountIncludingThis:
         case GetRestLength:
         case GetArgument:
         case Flush:

Modified: trunk/Source/_javascript_Core/dfg/DFGMayExit.cpp (227409 => 227410)


--- trunk/Source/_javascript_Core/dfg/DFGMayExit.cpp	2018-01-23 12:07:42 UTC (rev 227409)
+++ trunk/Source/_javascript_Core/dfg/DFGMayExit.cpp	2018-01-23 14:28:10 UTC (rev 227410)
@@ -74,6 +74,7 @@
     case GetStack:
     case GetCallee:
     case GetArgumentCountIncludingThis:
+    case SetArgumentCountIncludingThis:
     case GetRestLength:
     case GetScope:
     case PhantomLocal:

Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (227409 => 227410)


--- trunk/Source/_javascript_Core/dfg/DFGNode.h	2018-01-23 12:07:42 UTC (rev 227409)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h	2018-01-23 14:28:10 UTC (rev 227410)
@@ -971,6 +971,12 @@
         ASSERT(hasStackAccessData());
         return m_opInfo.as<StackAccessData*>();
     }
+
+    unsigned argumentCountIncludingThis()
+    {
+        ASSERT(op() == SetArgumentCountIncludingThis);
+        return m_opInfo.as<unsigned>();
+    }
     
     bool hasPhi()
     {

Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (227409 => 227410)


--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2018-01-23 12:07:42 UTC (rev 227409)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2018-01-23 14:28:10 UTC (rev 227410)
@@ -55,6 +55,7 @@
     macro(CreateThis, NodeResultJS) /* Note this is not MustGenerate since we're returning it anyway. */ \
     macro(GetCallee, NodeResultJS) \
     macro(GetArgumentCountIncludingThis, NodeResultInt32) \
+    macro(SetArgumentCountIncludingThis, NodeMustGenerate) \
     \
     /* Nodes for local variable access. These nodes are linked together using Phi nodes. */\
     /* Any two nodes that are part of the same Phi graph will share the same */\

Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (227409 => 227410)


--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2018-01-23 12:07:42 UTC (rev 227409)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2018-01-23 14:28:10 UTC (rev 227410)
@@ -768,6 +768,9 @@
             break;
         }
 
+        case SetArgumentCountIncludingThis:
+            break;
+
         case MapHash:
             setPrediction(SpecInt32Only);
             break;

Modified: trunk/Source/_javascript_Core/dfg/DFGPutStackSinkingPhase.cpp (227409 => 227410)


--- trunk/Source/_javascript_Core/dfg/DFGPutStackSinkingPhase.cpp	2018-01-23 12:07:42 UTC (rev 227409)
+++ trunk/Source/_javascript_Core/dfg/DFGPutStackSinkingPhase.cpp	2018-01-23 14:28:10 UTC (rev 227410)
@@ -121,6 +121,8 @@
                     };
 
                     auto writeHandler = [&] (VirtualRegister operand) {
+                        if (operand.isHeader())
+                            return;
                         RELEASE_ASSERT(node->op() == PutStack || node->op() == LoadVarargs || node->op() == ForwardVarargs);
                         writes.append(operand);
                     };
@@ -288,6 +290,8 @@
                     };
 
                     auto writeHandler = [&] (VirtualRegister operand) {
+                        if (operand.isHeader())
+                            return;
                         RELEASE_ASSERT(node->op() == LoadVarargs || node->op() == ForwardVarargs);
                         deferred.operand(operand) = DeadFlush;
                     };
@@ -501,6 +505,8 @@
                     };
 
                     auto writeHandler = [&] (VirtualRegister operand) {
+                        if (operand.isHeader())
+                            return;
                         // LoadVarargs and ForwardVarargs are unconditional writes to the stack
                         // locations they claim to write to. They do not read from the stack 
                         // locations they write to. This makes those stack locations dead right 

Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (227409 => 227410)


--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2018-01-23 12:07:42 UTC (rev 227409)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2018-01-23 14:28:10 UTC (rev 227410)
@@ -172,6 +172,7 @@
     case CreateThis:
     case GetCallee:
     case GetArgumentCountIncludingThis:
+    case SetArgumentCountIncludingThis:
     case GetRestLength:
     case GetLocal:
     case SetLocal:

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (227409 => 227410)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2018-01-23 12:07:42 UTC (rev 227409)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2018-01-23 14:28:10 UTC (rev 227410)
@@ -11324,6 +11324,12 @@
     int32Result(result.gpr(), node);
 }
 
+void SpeculativeJIT::compileSetArgumentCountIncludingThis(Node* node)
+{
+    m_jit.store32(TrustedImm32(node->argumentCountIncludingThis()), JITCompiler::payloadFor(CallFrameSlot::argumentCount));
+    noResult(node);
+}
+
 void SpeculativeJIT::compileStrCat(Node* node)
 {
     JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (227409 => 227410)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2018-01-23 12:07:42 UTC (rev 227409)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2018-01-23 14:28:10 UTC (rev 227410)
@@ -3125,6 +3125,7 @@
     void compileGetSetter(Node*);
     void compileGetCallee(Node*);
     void compileGetArgumentCountIncludingThis(Node*);
+    void compileSetArgumentCountIncludingThis(Node*);
     void compileStrCat(Node*);
     void compileNewArrayWithSize(Node*);
     void compileNewTypedArray(Node*);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (227409 => 227410)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2018-01-23 12:07:42 UTC (rev 227409)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2018-01-23 14:28:10 UTC (rev 227410)
@@ -3808,6 +3808,10 @@
         compileGetArgumentCountIncludingThis(node);
         break;
     }
+
+    case SetArgumentCountIncludingThis:
+        compileSetArgumentCountIncludingThis(node);
+        break;
         
     case GetScope:
         compileGetScope(node);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (227409 => 227410)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2018-01-23 12:07:42 UTC (rev 227409)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2018-01-23 14:28:10 UTC (rev 227410)
@@ -4016,6 +4016,10 @@
         break;
     }
 
+    case SetArgumentCountIncludingThis:
+        compileSetArgumentCountIncludingThis(node);
+        break;
+
     case GetRestLength: {
         compileGetRestLength(node);
         break;

Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (227409 => 227410)


--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2018-01-23 12:07:42 UTC (rev 227409)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2018-01-23 14:28:10 UTC (rev 227410)
@@ -180,6 +180,7 @@
     case GetScope:
     case GetCallee:
     case GetArgumentCountIncludingThis:
+    case SetArgumentCountIncludingThis:
     case ToNumber:
     case ToString:
     case ToObject:

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (227409 => 227410)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2018-01-23 12:07:42 UTC (rev 227409)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2018-01-23 14:28:10 UTC (rev 227410)
@@ -918,6 +918,9 @@
         case GetArgumentCountIncludingThis:
             compileGetArgumentCountIncludingThis();
             break;
+        case SetArgumentCountIncludingThis:
+            compileSetArgumentCountIncludingThis();
+            break;
         case GetScope:
             compileGetScope();
             break;
@@ -6343,6 +6346,11 @@
     {
         setInt32(m_out.load32(payloadFor(CallFrameSlot::argumentCount)));
     }
+
+    void compileSetArgumentCountIncludingThis()
+    {
+        m_out.store32(m_out.constInt32(m_node->argumentCountIncludingThis()), payloadFor(CallFrameSlot::argumentCount));
+    }
     
     void compileGetScope()
     {
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to