New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Extract for-of iterator handling to a helper #11262
Conversation
2c08b9b
to
40ce663
Compare
// It must be kept for compatibility reasons. | ||
// TODO (Babel 8): Remove this code. | ||
|
||
export default function transformWithoutHelper(loose, path, state) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file contains the old plugin code needed when the helper isn't available. I just copy-pasted it without any edit.
d556229
to
f505349
Compare
|
||
try { | ||
for (var _iterator = nums[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
for (_iteratorHelper.s(); !(_step = _iteratorHelper.n()).done;) { | ||
var i = _step.value; | ||
var x; | ||
var f; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a bug unrelated to this PR: f
and x
should be declared in the _loop
function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think they have to stay here. If we moved the var
inside the _loop
function, they would no longer declare the variable in the function scope (it's not a block let
/const
).
|
||
helpers.createForOfIteratorHelperLoose = helper("7.9.0")` | ||
export default function _createForOfIteratorHelperLoose(o) { | ||
var i = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Don't share the variable here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mostly did it for code size, since this is a runtime helper, and i
could stand both for index
and iterator
😅
|
||
const nodes = builder.build({ | ||
CREATE_ITERATOR_HELPER: state.addHelper(builder.helper), | ||
ITERATOR_HELPER: scope.generateUidIdentifier("iteratorHelper"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit:
ITERATOR_HELPER: scope.generateUidIdentifier("iteratorHelper"), | |
ITERATOR_HELPER: scope.generateUidIdentifier("iterator"), |
// push the rest of the original loop body onto our new body | ||
block.body = block.body.concat(node.body.body); | ||
t.inherits(container[0], node); | ||
t.inherits(container[0].body, node.body); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does container
ever contain more than one element? If not, we can replace the replaceWithMultiple
with replaceWith
and drop the parent.isLabeledStatement()
check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
container
always contains a single node. However:
- We are doing
replaceWithMultiple(nodes)
, and in non-loose modenodes
contains 2 nodes (the var declaration and the try statement) - We can't drop the
parent.isLabeledStatement()
check because in non-loose mode it the label must be moved to the inner loop. If we only didpath.replaceWith()
it would be attached to thetry
statement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we only did path.replaceWith() it would be attached to the try statement.
I think that would actually be equivalent. The finally
block should still fire correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But then, it doesn't work with continue
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ohhh. I was only thinking about break
.
); | ||
|
||
if ( | ||
t.isIdentifier(left) || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: It suffices to check t.isVariableDeclaration
first and assuming it's LVal
in the else branch, because we have validated ForOfStatement.left
even when BABEL_TYPES_8_BREAKING
is not enabled:
return assertNodeType("VariableDeclaration", "LVal"); |
(Oh it is copied from the old codes.)
Dis greatly recudes the code size when for-of is used multiple times across the codebase. Also, makes it easier to read what's happening in a compiled loop.
4173b6c
to
771986f
Compare
This greatly reduces the code size (*) when for-of is used multiple times across the
codebase. Also, makes it easier to read what's happening in a compiled loop.
(*) I tested the difference with 3 for loops before adding the human-friendly error message about the missing
Symbol.iterator
. I didn't usetransform-runtime
orexternal-helpers
, so these numbers include the helper size.These are the minified sizes (with terser):
Since the error message is a bit more than 100 bytes long, the size improvement probably needs 4 loops rather than one now. However, keep in mind that if I added the human-friendly error message to the old implementation it would have added 100 bytes 3 times, making the size improvement even bigger.
Size test code
Part 1/n