Title: [231195] trunk
Revision
231195
Author
[email protected]
Date
2018-05-01 08:42:11 -0700 (Tue, 01 May 2018)

Log Message

Add SetCallee as DFG-Operation
https://bugs.webkit.org/show_bug.cgi?id=184582

Patch by Dominik Infuehr <[email protected]> on 2018-05-01
Reviewed by Filip Pizlo.

JSTests:

Added test that runs into infinite loop without updating the callee and
therefore emitting SetCallee in DFG for recursive tail calls.

* stress/closure-recursive-tail-call-infinite-loop.js: Added.
(Foo):
(second):
(first):
(return.closure):
(createClosure):

Source/_javascript_Core:

For recursive tail calls not only the argument count can change but also the
callee. Add SetCallee to DFG that sets the callee slot in the current call frame.
Also update the callee when optimizing a recursive tail call.
Enable recursive tail call optimization also for closures.

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleRecursiveTailCall):
(JSC::DFG::ByteCodeParser::handleCallVariant):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGMayExit.cpp:
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileSetCallee):
* 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::compileSetCallee):

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (231194 => 231195)


--- trunk/JSTests/ChangeLog	2018-05-01 08:47:56 UTC (rev 231194)
+++ trunk/JSTests/ChangeLog	2018-05-01 15:42:11 UTC (rev 231195)
@@ -1,3 +1,20 @@
+2018-05-01  Dominik Infuehr  <[email protected]>
+
+        Add SetCallee as DFG-Operation
+        https://bugs.webkit.org/show_bug.cgi?id=184582
+
+        Reviewed by Filip Pizlo.
+
+        Added test that runs into infinite loop without updating the callee and
+        therefore emitting SetCallee in DFG for recursive tail calls.
+
+        * stress/closure-recursive-tail-call-infinite-loop.js: Added.
+        (Foo):
+        (second):
+        (first):
+        (return.closure):
+        (createClosure):
+
 2018-04-30  Saam Barati  <[email protected]>
 
         ToString constant folds without preserving checks, causing us to break assumptions that the code would OSR exit

Added: trunk/JSTests/stress/closure-recursive-tail-call-infinite-loop.js (0 => 231195)


--- trunk/JSTests/stress/closure-recursive-tail-call-infinite-loop.js	                        (rev 0)
+++ trunk/JSTests/stress/closure-recursive-tail-call-infinite-loop.js	2018-05-01 15:42:11 UTC (rev 231195)
@@ -0,0 +1,29 @@
+"use strict";
+
+function Foo() {}
+
+function second(next, cp) {
+  return 100;
+}
+
+function first(next, cp) {
+  return cp < 60 ? new Foo() : next(cp);
+}
+
+function createClosure(next, strategy) {
+  return function closure(cp) {
+    return strategy(next, cp);
+  };
+}
+
+var tmp = createClosure(null, second);
+var bar = createClosure(tmp, first);
+
+noInline(bar);
+
+for (var i=0; i<50000; i++) {
+  bar(32);
+  bar(32);
+  bar(32);
+  bar(100);
+}

Modified: trunk/Source/_javascript_Core/ChangeLog (231194 => 231195)


--- trunk/Source/_javascript_Core/ChangeLog	2018-05-01 08:47:56 UTC (rev 231194)
+++ trunk/Source/_javascript_Core/ChangeLog	2018-05-01 15:42:11 UTC (rev 231195)
@@ -1,3 +1,44 @@
+2018-05-01  Dominik Infuehr  <[email protected]>
+
+        Add SetCallee as DFG-Operation
+        https://bugs.webkit.org/show_bug.cgi?id=184582
+
+        Reviewed by Filip Pizlo.
+
+        For recursive tail calls not only the argument count can change but also the
+        callee. Add SetCallee to DFG that sets the callee slot in the current call frame.
+        Also update the callee when optimizing a recursive tail call.
+        Enable recursive tail call optimization also for closures.
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleRecursiveTailCall):
+        (JSC::DFG::ByteCodeParser::handleCallVariant):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGMayExit.cpp:
+        * dfg/DFGNodeType.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileSetCallee):
+        * 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::compileSetCallee):
+
 2018-05-01  Oleksandr Skachkov  <[email protected]>
 
         WebAssembly: add support for stream APIs - _javascript_ API

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (231194 => 231195)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2018-05-01 08:47:56 UTC (rev 231194)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2018-05-01 15:42:11 UTC (rev 231195)
@@ -2448,6 +2448,7 @@
         forNode(node).setType(SpecInt32Only);
         break;
 
+    case SetCallee:
     case SetArgumentCountIncludingThis:
         break;
         

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (231194 => 231195)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2018-05-01 08:47:56 UTC (rev 231194)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2018-05-01 15:42:11 UTC (rev 231195)
@@ -156,7 +156,7 @@
     void emitArgumentPhantoms(int registerOffset, int argumentCountIncludingThis);
     Node* getArgumentCount();
     template<typename ChecksFunctor>
-    bool handleRecursiveTailCall(CallVariant, int registerOffset, int argumentCountIncludingThis, const ChecksFunctor& emitFunctionCheckIfNeeded);
+    bool handleRecursiveTailCall(Node* callTargetNode, CallVariant, int registerOffset, int argumentCountIncludingThis, const ChecksFunctor& emitFunctionCheckIfNeeded);
     unsigned inliningCost(CallVariant, int argumentCountIncludingThis, InlineCallFrame::Kind); // Return UINT_MAX if it's not an inlining candidate. By convention, intrinsics have a cost of 1.
     // Handle inlining. Return true if it succeeded, false if we need to plant a call.
     bool handleVarargsInlining(Node* callTargetNode, int resultOperand, const CallLinkStatus&, int registerOffset, VirtualRegister thisArgument, VirtualRegister argumentsArgument, unsigned argumentsOffset, NodeType callOp, InlineCallFrame::Kind);
@@ -1356,16 +1356,11 @@
 }
 
 template<typename ChecksFunctor>
-bool ByteCodeParser::handleRecursiveTailCall(CallVariant callVariant, int registerOffset, int argumentCountIncludingThis, const ChecksFunctor& emitFunctionCheckIfNeeded)
+bool ByteCodeParser::handleRecursiveTailCall(Node* callTargetNode, CallVariant callVariant, int registerOffset, int argumentCountIncludingThis, const ChecksFunctor& emitFunctionCheckIfNeeded)
 {
     if (UNLIKELY(!Options::optimizeRecursiveTailCalls()))
         return false;
 
-    // Currently we cannot do this optimisation for closures. The problem is that "emitFunctionChecks" which we use later is too coarse, only checking the executable
-    // and not the value of captured variables.
-    if (callVariant.isClosureCall())
-        return false;
-
     auto targetExecutable = callVariant.executable();
     InlineStackEntry* stackEntry = m_inlineStackTop;
     do {
@@ -1385,11 +1380,25 @@
                 return false;
         }
 
+        // If an InlineCallFrame is not a closure, it was optimized using a constant callee.
+        // Check if this is the same callee that we try to inline here.
+        if (stackEntry->m_inlineCallFrame && !stackEntry->m_inlineCallFrame->isClosureCall) {
+            if (stackEntry->m_inlineCallFrame->calleeConstant() != callVariant.function())
+                continue;
+        }
+
         // We must add some check that the profiling information was correct and the target of this call is what we thought.
         emitFunctionCheckIfNeeded();
         // We flush everything, as if we were in the backedge of a loop (see treatment of op_jmp in parseBlock).
         flushForTerminal();
 
+        // We must set the callee to the right value
+        if (stackEntry->m_inlineCallFrame) {
+            if (stackEntry->m_inlineCallFrame->isClosureCall)
+                setDirect(stackEntry->remapOperand(VirtualRegister(CallFrameSlot::callee)), callTargetNode, NormalSet);
+        } else
+            addToGraph(SetCallee, callTargetNode);
+
         // We must set the arguments to the right values
         if (!stackEntry->m_inlineCallFrame)
             addToGraph(SetArgumentCountIncludingThis, OpInfo(argumentCountIncludingThis));
@@ -1683,7 +1692,7 @@
         didInsertChecks = true;
     };
 
-    if (kind == InlineCallFrame::TailCall && ByteCodeParser::handleRecursiveTailCall(callee, registerOffset, argumentCountIncludingThis, insertChecksWithAccounting)) {
+    if (kind == InlineCallFrame::TailCall && ByteCodeParser::handleRecursiveTailCall(callTargetNode, callee, registerOffset, argumentCountIncludingThis, insertChecksWithAccounting)) {
         RELEASE_ASSERT(didInsertChecks);
         return CallOptimizationResult::OptimizedToJump;
     }

Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (231194 => 231195)


--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2018-05-01 08:47:56 UTC (rev 231194)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2018-05-01 15:42:11 UTC (rev 231195)
@@ -695,6 +695,10 @@
         read(AbstractHeap(Stack, CallFrameSlot::callee));
         def(HeapLocation(StackLoc, AbstractHeap(Stack, CallFrameSlot::callee)), LazyNode(node));
         return;
+
+    case SetCallee:
+        write(AbstractHeap(Stack, CallFrameSlot::callee));
+        return;
         
     case GetArgumentCountIncludingThis: {
         auto heap = AbstractHeap(Stack, remapOperand(node->argumentsInlineCallFrame(), VirtualRegister(CallFrameSlot::argumentCount)));

Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (231194 => 231195)


--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2018-05-01 08:47:56 UTC (rev 231194)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2018-05-01 15:42:11 UTC (rev 231195)
@@ -51,6 +51,7 @@
     case Identity:
     case IdentityWithProfile:
     case GetCallee:
+    case SetCallee:
     case GetArgumentCountIncludingThis:
     case SetArgumentCountIncludingThis:
     case GetRestLength:

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (231194 => 231195)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2018-05-01 08:47:56 UTC (rev 231194)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2018-05-01 15:42:11 UTC (rev 231195)
@@ -2134,6 +2134,10 @@
             }
             break;
 
+        case SetCallee:
+            fixEdge<CellUse>(node->child1());
+            break;
+
 #if !ASSERT_DISABLED
         // Have these no-op cases here to ensure that nobody forgets to add handlers for new opcodes.
         case SetArgument:

Modified: trunk/Source/_javascript_Core/dfg/DFGMayExit.cpp (231194 => 231195)


--- trunk/Source/_javascript_Core/dfg/DFGMayExit.cpp	2018-05-01 08:47:56 UTC (rev 231194)
+++ trunk/Source/_javascript_Core/dfg/DFGMayExit.cpp	2018-05-01 15:42:11 UTC (rev 231195)
@@ -74,6 +74,7 @@
     case KillStack:
     case GetStack:
     case GetCallee:
+    case SetCallee:
     case GetArgumentCountIncludingThis:
     case SetArgumentCountIncludingThis:
     case GetRestLength:

Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (231194 => 231195)


--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2018-05-01 08:47:56 UTC (rev 231194)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2018-05-01 15:42:11 UTC (rev 231195)
@@ -54,6 +54,7 @@
     macro(ToThis, NodeResultJS) \
     macro(CreateThis, NodeResultJS) /* Note this is not MustGenerate since we're returning it anyway. */ \
     macro(GetCallee, NodeResultJS) \
+    macro(SetCallee, NodeMustGenerate) \
     macro(GetArgumentCountIncludingThis, NodeResultInt32) \
     macro(SetArgumentCountIncludingThis, NodeMustGenerate) \
     \

Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (231194 => 231195)


--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2018-05-01 08:47:56 UTC (rev 231194)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2018-05-01 15:42:11 UTC (rev 231195)
@@ -776,6 +776,7 @@
             break;
         }
 
+        case SetCallee:
         case SetArgumentCountIncludingThis:
             break;
 

Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (231194 => 231195)


--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2018-05-01 08:47:56 UTC (rev 231194)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2018-05-01 15:42:11 UTC (rev 231195)
@@ -172,6 +172,7 @@
     case ToThis:
     case CreateThis:
     case GetCallee:
+    case SetCallee:
     case GetArgumentCountIncludingThis:
     case SetArgumentCountIncludingThis:
     case GetRestLength:

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (231194 => 231195)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2018-05-01 08:47:56 UTC (rev 231194)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2018-05-01 15:42:11 UTC (rev 231195)
@@ -11866,6 +11866,13 @@
     cellResult(result.gpr(), node);
 }
 
+void SpeculativeJIT::compileSetCallee(Node* node)
+{
+    SpeculateCellOperand callee(this, node->child1());
+    m_jit.storeCell(callee.gpr(), JITCompiler::payloadFor(CallFrameSlot::callee));
+    noResult(node);
+}
+
 void SpeculativeJIT::compileGetArgumentCountIncludingThis(Node* node)
 {
     GPRTemporary result(this);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (231194 => 231195)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2018-05-01 08:47:56 UTC (rev 231194)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2018-05-01 15:42:11 UTC (rev 231195)
@@ -1459,6 +1459,7 @@
     void compileGetGetter(Node*);
     void compileGetSetter(Node*);
     void compileGetCallee(Node*);
+    void compileSetCallee(Node*);
     void compileGetArgumentCountIncludingThis(Node*);
     void compileSetArgumentCountIncludingThis(Node*);
     void compileStrCat(Node*);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (231194 => 231195)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2018-05-01 08:47:56 UTC (rev 231194)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2018-05-01 15:42:11 UTC (rev 231195)
@@ -3255,6 +3255,11 @@
         compileGetCallee(node);
         break;
     }
+
+    case SetCallee: {
+        compileSetCallee(node);
+        break;
+    }
         
     case GetArgumentCountIncludingThis: {
         compileGetArgumentCountIncludingThis(node);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (231194 => 231195)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2018-05-01 08:47:56 UTC (rev 231194)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2018-05-01 15:42:11 UTC (rev 231195)
@@ -3476,6 +3476,11 @@
         compileGetCallee(node);
         break;
     }
+
+    case SetCallee: {
+        compileSetCallee(node);
+        break;
+    }
         
     case GetArgumentCountIncludingThis: {
         compileGetArgumentCountIncludingThis(node);

Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (231194 => 231195)


--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2018-05-01 08:47:56 UTC (rev 231194)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2018-05-01 15:42:11 UTC (rev 231195)
@@ -182,6 +182,7 @@
     case GetExecutable:
     case GetScope:
     case GetCallee:
+    case SetCallee:
     case GetArgumentCountIncludingThis:
     case SetArgumentCountIncludingThis:
     case ToNumber:

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (231194 => 231195)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2018-05-01 08:47:56 UTC (rev 231194)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2018-05-01 15:42:11 UTC (rev 231195)
@@ -924,6 +924,9 @@
         case GetCallee:
             compileGetCallee();
             break;
+        case SetCallee:
+            compileSetCallee();
+            break;
         case GetArgumentCountIncludingThis:
             compileGetArgumentCountIncludingThis();
             break;
@@ -6626,6 +6629,12 @@
     {
         setJSValue(m_out.loadPtr(addressFor(CallFrameSlot::callee)));
     }
+
+    void compileSetCallee()
+    {
+        auto callee = lowCell(m_node->child1());
+        m_out.storePtr(callee, payloadFor(CallFrameSlot::callee));
+    }
     
     void compileGetArgumentCountIncludingThis()
     {
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to