DFG liveness can't skip tail caller inline frames
authorkeith_miller@apple.com <keith_miller@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 14 Mar 2019 17:41:04 +0000 (17:41 +0000)
committerkeith_miller@apple.com <keith_miller@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 14 Mar 2019 17:41:04 +0000 (17:41 +0000)
https://bugs.webkit.org/show_bug.cgi?id=195715
JSTests:

Reviewed by Saam Barati.

* stress/dfg-scan-inlined-tail-caller-frames-liveness.js:
(i.foo):

Source/JavaScriptCore:

<rdar://problem/46221598>

Reviewed by Saam Barati.

In order to simplify OSR exit/DFG bytecode parsing our bytecode
generator always emits an op_ret after any tail call. However, the
DFG when computing the liveness of locals, would skip any tail
caller inline frames. This mean that if we ended up inserting a
Check that would OSR to the op_ret we wouldn't have kept
availability data around for it.

* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::isLiveInBytecode):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::forAllLocalsLiveInBytecode):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@242945 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JSTests/ChangeLog
JSTests/stress/dfg-scan-inlined-tail-caller-frames-liveness.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/dfg/DFGGraph.cpp
Source/JavaScriptCore/dfg/DFGGraph.h

index 1fe6f67..434bebd 100644 (file)
@@ -1,3 +1,13 @@
+2019-03-14  Keith Miller  <keith_miller@apple.com>
+
+        DFG liveness can't skip tail caller inline frames
+        https://bugs.webkit.org/show_bug.cgi?id=195715
+
+        Reviewed by Saam Barati.
+
+        * stress/dfg-scan-inlined-tail-caller-frames-liveness.js:
+        (i.foo):
+
 2019-03-13  Mark Lam  <mark.lam@apple.com>
 
         Gardening: reducing the variants on 2 tests to avoid timing out on JSC Debug queue.
diff --git a/JSTests/stress/dfg-scan-inlined-tail-caller-frames-liveness.js b/JSTests/stress/dfg-scan-inlined-tail-caller-frames-liveness.js
new file mode 100644 (file)
index 0000000..a9f2168
--- /dev/null
@@ -0,0 +1,5 @@
+//@ requireOptions("--jitPolicyScale=0", "--maximumFunctionForCallInlineCandidateInstructionCount=1000", "--validateFTLOSRExitLiveness=1")
+
+for (let i = 0; i < 100000; i++) {
+    (function foo() { [0].concat().indexOf(0) })()
+}
index 71b2021..41a35d2 100644 (file)
@@ -1,3 +1,23 @@
+2019-03-14  Keith Miller  <keith_miller@apple.com>
+
+        DFG liveness can't skip tail caller inline frames
+        https://bugs.webkit.org/show_bug.cgi?id=195715
+        <rdar://problem/46221598>
+
+        Reviewed by Saam Barati.
+
+        In order to simplify OSR exit/DFG bytecode parsing our bytecode
+        generator always emits an op_ret after any tail call. However, the
+        DFG when computing the liveness of locals, would skip any tail
+        caller inline frames. This mean that if we ended up inserting a
+        Check that would OSR to the op_ret we wouldn't have kept
+        availability data around for it.
+
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::isLiveInBytecode):
+        * dfg/DFGGraph.h:
+        (JSC::DFG::Graph::forAllLocalsLiveInBytecode):
+
 2019-03-14  Robin Morisset  <rmorisset@apple.com>
 
         DFG::Worklist can be shrunk by 16 bytes
index 78f3863..344b645 100644 (file)
@@ -1166,15 +1166,10 @@ bool Graph::isLiveInBytecode(VirtualRegister operand, CodeOrigin codeOrigin)
                 dataLog("Argument is live.\n");
             return true;
         }
-        
-        codeOriginPtr = inlineCallFrame->getCallerSkippingTailCalls();
 
-        // The first inline call frame could be an inline tail call
-        if (!codeOriginPtr) {
-            if (verbose)
-                dataLog("Dead because of tail inlining.\n");
-            return false;
-        }
+        // We need to handle tail callers because we may decide to exit to the
+        // the return bytecode following the tail call.
+        codeOriginPtr = &inlineCallFrame->directCaller;
     }
     
     RELEASE_ASSERT_NOT_REACHED();
index c88a113..c08cacc 100644 (file)
@@ -865,12 +865,10 @@ public:
 
             for (VirtualRegister reg = exclusionStart; reg < exclusionEnd; reg += 1)
                 functor(reg);
-            
-            codeOriginPtr = inlineCallFrame->getCallerSkippingTailCalls();
 
-            // The first inline call frame could be an inline tail call
-            if (!codeOriginPtr)
-                break;
+            // We need to handle tail callers because we may decide to exit to the
+            // the return bytecode following the tail call.
+            codeOriginPtr = &inlineCallFrame->directCaller;
         }
     }