[JSC] DFG recursive-tail-call optimization should not emit jump to call-frame with...
authorysuzuki@apple.com <ysuzuki@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 27 Sep 2019 16:56:58 +0000 (16:56 +0000)
committerysuzuki@apple.com <ysuzuki@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 27 Sep 2019 16:56:58 +0000 (16:56 +0000)
commit77fc645fbf5f2f42f6c364809a39e0ca7802dfbd
tree1c94a0031780c5d3ee35dd1be76368ccfbe67a4b
parentc8e58be1e9620e082c0db80b083e2874c5904aa4
[JSC] DFG recursive-tail-call optimization should not emit jump to call-frame with varargs
https://bugs.webkit.org/show_bug.cgi?id=202299
<rdar://problem/52669116>

Reviewed by Saam Barati.

JSTests:

* stress/recursive-tail-call-optimization-should-not-jump-into-call-frame-with-varargs-simple.js: Added.
(foo):
(test):
* stress/recursive-tail-call-optimization-should-not-jump-into-call-frame-with-varargs.js: Added.
(foo):
(C1.prototype.baz):
(C1):
(bar):
(noInline.bar.goo):
(C2.prototype.baz):
(C2):
(test):

Source/JavaScriptCore:

When converting recursive-tail-call to jump to the upper call frame, we picked call-frame which is spread by LoadVarargs.
This is wrong since this call-frame does not know the exact number of arguments. We are using InlineCallFrame::argumentCountIncludingThis,
but this is maximal argumentCountIncludingThis when InlineCallFrame is Varargs call-frame. Let's see the simple example.

    'use strict';
    var count = 0;
    function foo() {
        count--;
        if (count === 0)
            return 30;
        return foo(42, 42); // HERE
    }

    function test() {
        count = 100;
        return foo(...[42, 42]); // THERE
    }
    noInline(test);

In the above case, currently, we convert HERE's foo call to the jump to the prologue of the foo function inlined by "test". But since foo is called
in a varargs form, "test" emits LoadVarargs, and it also emits `SetArgumentMaybe` for 1st and 2nd arguments. Since HERE's foo call is actually passing
two arguments, we emit a Phi node which Upsilon is from SetArgumentMaybe and 42 Constant. This is wrong since SetArgumentMaybe should not be used. Later,
SSA conversion phase emits Upsilon with SetArgumentMaybe, and since SetArgumentMaybe is simply removed in SSA conversion phase, it ends up emitting
Upsilon without a child.

We are currently only performing recursive-tail-call optimization when argument count matches. Given this condition, we should not pick varargs CallFrame
as a jump target.

* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleRecursiveTailCall):
* dfg/DFGSSAConversionPhase.cpp:
(JSC::DFG::SSAConversionPhase::run):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@250430 268f45cc-cd09-0410-ab3c-d52691b4dbfc
JSTests/ChangeLog
JSTests/stress/recursive-tail-call-optimization-should-not-jump-into-call-frame-with-varargs-simple.js [new file with mode: 0644]
JSTests/stress/recursive-tail-call-optimization-should-not-jump-into-call-frame-with-varargs.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp