Assignment to rest param element triggers error T6932 - #3249
Conversation
|
|
Current coverage is
|
|
In function x() {
arguments[0] = 0;
}But that could generate out of bounds This fix bails out of the if (arguments.length > 10) arguments[10] = 0; |
There was a problem hiding this comment.
gotta love the grandpa/grandparentPath
There was a problem hiding this comment.
Ha ha, yeah I didn't even think of grandpa -- that'd be good for brevity, but I'd probably get in trouble with the internet if I used a gender-specific identifier.
|
looks good to fix it and we can revisit it later |
|
What does this currently get transformed to? |
|
In phab: it errors with |
|
do you know what the generated code looks like? |
|
@hzoo @amasad Thanks for reviewing. @amasad To be clear, it errors at compile time, so there is no transformation / generated code. I think you're asking what state is it in when the error occurs? I think it's trying to construct an AST representing something like: (arguments.length <= 0 ? undefined : arguments[0]) = "0";
That's what I was thinking -- just fix it and revisit optimization later, because that's been tricky to get right and I'm not sure if there's a clear win there. |
|
Actually I don't see this as an option:
For example, this should work: (function (...items) {
items[9] = 0;
assert(items.length === 10);
})();The old transformation before this bug wouldn't have worked right there either. On another note, is assigning to |
@jmm Nope. Crankshaft will bailout with a "Bad value context for arguments value". |
|
@vhf Thanks! I'd checked the optimization killers article and it wasn't clear to me from there if "use" Input: (function (...rest) {
rest.length = 2;
assert(rest[2] === undefined);
})(1, 2, 3);Output: (function () {
arguments.length = 2;
assert(arguments[2] === undefined);
})(1, 2, 3);I'm working on additional changes to this transform, including regarding that. |
That is, do not attempt to optimize assignments as opposed to reads. (Failing.)
|
I pushed new commits here with a better home for the fixtures (in an existing file) based on my improved understanding of the transform. The test case here is just a situation where the transform should bail out on optimizing references to rest. As a byproduct it catches this bug that causes transformation to fail altogether.
Actually, that was my mistake -- I accidentally checked that with (function () {
arguments.length = 2;
assert((arguments.length <= 2 ? undefined : arguments[2]) === undefined);
})(1, 2, 3);So the first part is still an issue -- it "optimizes" it so that it assigns to |
|
Hitting this in Meteor's command-line tool code while trying to upgrade to Babel 6: meteor/meteor#6141 |
|
Do you need help with this PR or can I do anything to help @jmm? |
|
Added some new tests that fail even with @jmm's fixes. If he merges my PR, this PR should update, and the new tests should fail here… in theory! |
|
EDIT: oops, wound up with wrong at-mention for some reason (sorry iamolivinius => vhf).
Thanks! I was just hoping to get a couple 👍 from other collaborators. At this point, since it's an obvious bug and there's been no objection, I'd consider merging and pushing a release, but there's a bunch of unreleased stuff already on
Thanks! I need to take a closer look at those -- I'm sure we should bring them in, I just want to see if they should be added to this PR or become a new issue / PR. I wonder if optimizing these references to |
|
Please pull them in, I already got a fix for them. (The expected fixtures On Tue, Feb 2, 2016 at 11:19 PM, Jesse McCarthy [email protected]
|
|
I don't think we're doing the pre-release anymore - probably a release this week though. 👍 for the current stuff |
|
The additional tests are definitely an instance of the same general problem, so they very much belong in this PR. |
|
@vhf @benjamn Yeah, just given that this PR hasn't gotten merged yet and it's been the same for 19 days, I would consider PR'ing other fixes separately in an attempt to incrementally get some of the problems fixed sooner than all of them. Definitely appreciate your efforts in identifying and fixing other cases though!! |
|
Thanks @hzoo. |
|
@vhf The |
I would support a solution that disables the optimization completely. Simple, general, foolproof, reversible in the future if anyone cares to put in the time to do this right, etc. etc. |
Until babel/babel#3249 is fixed properly, it's better simply to disable the rest parameter optimizations.
I'd say let's proceed if it seems like we're close to being able to make it robust, since a lot of work has already gone into it. (I also have performance optimizations of the optimization code and other fixes sitting on local branches waiting on my open PRs to be merged.) If it seems like a bottomless pit of difficult to detect problem cases, I'm open to just removing the optimization. Would like to hear what other collaborators think about that, and would need some agreement on it anyway. Thank you for all of the additional test cases! I'm going to take a look at those. |
|
What's our status on this one? |
Fix assignment to rest param element AST error. Fix T6932.
|
In the meantime, |
|
Why don't we make an option for it, |
I'm with you on all of that. I have fixes coming soon for the failing test cases you provided, but even so that doesn't make me confident that there aren't other problem cases that we haven't thought of lurking. I think for now we should merge those fixes and keep an eye on it to see what happens.
Thanks. I, for one, am interested in feedback from the community on this -- not just bug reports, but whether people even think the optimizations are important, are worth people spending limited time maintaining, etc.
Yeah, we could do that. @benjamn Would you use that right now if it were available? @hzoo Also, something to keep in mind is that there are actually multiple optimizations (referencing arguments instead of making a real array, where to place the loop when you do make an array, etc.) @benjamn I see that in https://github.com/meteor/babel-preset-meteor you have a:
Note sure exactly what that means, but you might be interested in the discussion in #3349. |
I'm obviously completely biased since I'm the one who thought avoiding v8 deoptimization in this module was a good move but here's my take anyway. There are two options: either Babel only compiles from ESx to ESy or Babel compiles and optimizes the code. The second one makes more sense to me. Before v8 got rest and default params, Babel compiled them into what v8 would deoptimize. Babel seemed to care a lot about performances at this time so these optimization (which are more de-deoptimizations) were introduced. Now that v8 has rest and default params, people could just stop using this module/transform when targeting node/chrome... if v8 wasn't deoptimizing them! I really think it makes sense to not only "transpile" but also optimize. That said, I'm all in favor of an option. It would allow people targeting various browsers to have "safe" (but sometimes slow) code, and people targeting node to have faster code. |
|
I'm not sure I see how v8 deoptimization comes into play here. There's nothing optimization-killing about looping over More importantly, safe but slow code is better than buggy but fast code every day of the week. It's not a weighted balance; safety is an absolute requirement. I'm reminded of a professor who gave zero credit on a homework assignment if any of our compiler optimizations were unsound. I got a zero on that assignment, which is maybe why I remember it so well, but she had a point! |
I would use that option! |
|
@vhf Thanks for the feedback. EDIT: FYI, I didn't see @benjamn's latest comments before posting. Reading now. Let me just recap a little to make sure we're all on the same page here. In it's transformation of rest parameters, Babel sometimes loops over
Ok, so when you say that you think Babel should optimize the code, you mean that you think it should perform the Babel
Do you mean that V8 deoptimizes functions with rest parameters? The thing that I'm determined to fix one way or another are the errors in the code that performs the Babel |
|
@benjamn Thanks for the feedback.
Yes...and doing that optimization in a way that avoids V8 deoptimization is what has created some of the complexity that has resulted in the current issues where compilation crashes. There are 3 basic options:
Ok, thanks. |
Yes. I think Babel should avoid copying the
Yes. I mentioned it here: it currently triggers a bailout: "Rest parameters". This will change in the future as TurboFan will most probably be able to optimize all uses of the Regarding the three options you proposed I suggest to have |
|
@vhf Thanks for the feedback.
Ok, so I've skimmed your bailout reasons document a few times previously and thought that's what it said, but don't really understand it. (It's not explained very thoroughly -- like what exactly it means for it to be a "bad idea" -- not that I'd necessarily be able to understand it any better if it were.) Prior to that I thought that was the conventional wisdom on how to handle it, and that's what the optimization killers article advises to do to avoid leaking
Ok, thanks.
Ok, thanks. I really wish we could nail down definitively the repercussions of looping over to create a real array.
So is the premise here that looping over to create a real array is just as bad as directly leaking arguments by e.g. passing it out of / returning it from the function, or assigning to any prop of
Maybe I'll think of more later. |
Currently this is a failing test case forFix T6932.