Bug 171262 - [JSC] Handle PhantomSpread in LoadVarargs as the same to the others
Summary: [JSC] Handle PhantomSpread in LoadVarargs as the same to the others
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: New Bugs (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Yusuke Suzuki
URL:
Keywords:
Depends on: 171057
Blocks:
  Show dependency treegraph
 
Reported: 2017-04-25 00:22 PDT by Yusuke Suzuki
Modified: 2017-04-27 01:59 PDT (History)
6 users (show)

See Also:


Attachments
Patch (11.96 KB, patch)
2017-04-25 00:23 PDT, Yusuke Suzuki
saam: review+
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Yusuke Suzuki 2017-04-25 00:22:10 PDT
[JSC] Handle PhantomSpread in LoadVarargs as the same to the others
Comment 1 Yusuke Suzuki 2017-04-25 00:23:25 PDT
Created attachment 308074 [details]
Patch
Comment 2 Yusuke Suzuki 2017-04-25 05:49:43 PDT
Comment on attachment 308074 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=308074&action=review

> Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp:880
>                          InlineCallFrame* inlineCallFrame = candidate->origin.semantic.inlineCallFrame;

This is buggy part of this patch. But we cannot test it since the following code,

function a(...args)
{
    return b(args);
}

function b(args)
{
    return c(...args);
}

function c(a0, a1, a2, a3, a4)
{
    return a2;
}

a(0, 1, 2, 3, 4, 5);

will emit PutStack for args, and make it usual Spread & CreateRest instead of PhantomSpread.
Thus, we cannot observe this bug fixed in this patch.
Comment 3 Saam Barati 2017-04-25 14:29:43 PDT
Comment on attachment 308074 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=308074&action=review

>> Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp:880
>>                          InlineCallFrame* inlineCallFrame = candidate->origin.semantic.inlineCallFrame;
> 
> This is buggy part of this patch. But we cannot test it since the following code,
> 
> function a(...args)
> {
>     return b(args);
> }
> 
> function b(args)
> {
>     return c(...args);
> }
> 
> function c(a0, a1, a2, a3, a4)
> {
>     return a2;
> }
> 
> a(0, 1, 2, 3, 4, 5);
> 
> will emit PutStack for args, and make it usual Spread & CreateRest instead of PhantomSpread.
> Thus, we cannot observe this bug fixed in this patch.

I'm confused. There exists no test for this? How is that possible?
Comment 4 Yusuke Suzuki 2017-04-26 07:15:04 PDT
Comment on attachment 308074 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=308074&action=review

>>> Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp:880
>>>                          InlineCallFrame* inlineCallFrame = candidate->origin.semantic.inlineCallFrame;
>> 
>> This is buggy part of this patch. But we cannot test it since the following code,
>> 
>> function a(...args)
>> {
>>     return b(args);
>> }
>> 
>> function b(args)
>> {
>>     return c(...args);
>> }
>> 
>> function c(a0, a1, a2, a3, a4)
>> {
>>     return a2;
>> }
>> 
>> a(0, 1, 2, 3, 4, 5);
>> 
>> will emit PutStack for args, and make it usual Spread & CreateRest instead of PhantomSpread.
>> Thus, we cannot observe this bug fixed in this patch.
> 
> I'm confused. There exists no test for this? How is that possible?

The problem is that `spread->child1()->origin.semantic.inlineCallFrame` could be different from `spread->origin.semantic.inlineCallFrame`.
If it happens with LoadVarargs, the observable bug occurs.
However, currently, this case does not occur. This is just because PutStack always escapes the spread in this case. So it is not testable.
But it's not logically correct and it breaks things if this phase is merged into Object Allocation Sinking.
Comment 5 Saam Barati 2017-04-26 12:52:05 PDT
Oh I see, this is because we run putStackSinkingPhase after arguments elimination :(
Comment 6 Saam Barati 2017-04-26 12:54:29 PDT
(In reply to Saam Barati from comment #5)
> Oh I see, this is because we run putStackSinkingPhase after arguments
> elimination :(

I wonder if we should run putStackSinkingPhase first, then run argumentsElimination, and then run putStackSinkingPhase again but only if argumentsElimination did anything.

We should obviously be able to transform your example program to not allocate Createrest/Spread.

Fil, Yusuke, any thoughts on this proposal?
Comment 7 Saam Barati 2017-04-26 12:57:45 PDT
Comment on attachment 308074 [details]
Patch

r=me. I agree with this change even if we have the PutStack issue.
Comment 8 Saam Barati 2017-04-26 13:00:07 PDT
I applied your change locally, along with this change to Plan:

```
        if (Options::usePutStackSinking())
            RUN_PHASE(performPutStackSinking);
        changed = false;
        RUN_PHASE(performArgumentsElimination);
        if (changed && Options::usePutStackSinking())
            RUN_PHASE(performPutStackSinking);
```

And ran this program:
```
"use strict";

function assert(b) {
    if (!b)
        throw new Error("Bad");
}

function foo(...args) {
    return bar(args);
}
noInline(foo);

function bar(args) {
    return baz(...args);
}

function baz(a, b) {
    return a + b;
}

for (let i = 0; i < 10000; ++i) {
    assert(foo(i, i+1) === (i + (i + 1)));
}
```

And your patch fixes the crash.
Comment 9 Filip Pizlo 2017-04-26 13:33:31 PDT
(In reply to Saam Barati from comment #6)
> (In reply to Saam Barati from comment #5)
> > Oh I see, this is because we run putStackSinkingPhase after arguments
> > elimination :(
> 
> I wonder if we should run putStackSinkingPhase first, then run
> argumentsElimination, and then run putStackSinkingPhase again but only if
> argumentsElimination did anything.
> 
> We should obviously be able to transform your example program to not
> allocate Createrest/Spread.
> 
> Fil, Yusuke, any thoughts on this proposal?

I think that we need to combine the PutStack, ArgumentsElimination, and ObjectAllocationSinking phases should in the long term be combined into one phase, that assumes that nothing escapes as its initial bottom result and then builds up from there.

Otherwise trying to fixpoint these phases means we start at top and incremnetally optimize.
Comment 10 Yusuke Suzuki 2017-04-27 01:55:24 PDT
(In reply to Filip Pizlo from comment #9)
> (In reply to Saam Barati from comment #6)
> > (In reply to Saam Barati from comment #5)
> > > Oh I see, this is because we run putStackSinkingPhase after arguments
> > > elimination :(
> > 
> > I wonder if we should run putStackSinkingPhase first, then run
> > argumentsElimination, and then run putStackSinkingPhase again but only if
> > argumentsElimination did anything.
> > 
> > We should obviously be able to transform your example program to not
> > allocate Createrest/Spread.
> > 
> > Fil, Yusuke, any thoughts on this proposal?
> 
> I think that we need to combine the PutStack, ArgumentsElimination, and
> ObjectAllocationSinking phases should in the long term be combined into one
> phase, that assumes that nothing escapes as its initial bottom result and
> then builds up from there.
> 
> Otherwise trying to fixpoint these phases means we start at top and
> incremnetally optimize.

Agreed.
Comment 11 Yusuke Suzuki 2017-04-27 01:57:00 PDT
(In reply to Saam Barati from comment #8)
> I applied your change locally, along with this change to Plan:
> 
> ```
>         if (Options::usePutStackSinking())
>             RUN_PHASE(performPutStackSinking);
>         changed = false;
>         RUN_PHASE(performArgumentsElimination);
>         if (changed && Options::usePutStackSinking())
>             RUN_PHASE(performPutStackSinking);
> ```
> 
> And ran this program:
> ```
> "use strict";
> 
> function assert(b) {
>     if (!b)
>         throw new Error("Bad");
> }
> 
> function foo(...args) {
>     return bar(args);
> }
> noInline(foo);
> 
> function bar(args) {
>     return baz(...args);
> }
> 
> function baz(a, b) {
>     return a + b;
> }
> 
> for (let i = 0; i < 10000; ++i) {
>     assert(foo(i, i+1) === (i + (i + 1)));
> }
> ```
> 
> And your patch fixes the crash.

Yeah. I've added the above code to the test too to ensure this works if PutStack sinking phase is merged.
Comment 12 Yusuke Suzuki 2017-04-27 01:59:19 PDT
Committed r215860: <http://trac.webkit.org/changeset/215860>