Merge pull request #3214 from fabiomcosta/fix_rest_args_length_multiple_params
[T6891][fix][babel-plugin-transform-es2015-parameters] arguments.length optimization bugfix
This commit is contained in:
commit
181e9b5957
@ -60,7 +60,7 @@ let memberExpressionOptimisationVisitor = {
|
|||||||
// we can safely optimise it
|
// we can safely optimise it
|
||||||
let prop = parentPath.get("property");
|
let prop = parentPath.get("property");
|
||||||
if (prop.isBaseType("number")) {
|
if (prop.isBaseType("number")) {
|
||||||
state.candidates.push(path);
|
state.candidates.push({cause: "indexGetter", path});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,8 +69,7 @@ let memberExpressionOptimisationVisitor = {
|
|||||||
if (parentPath.isMemberExpression({ computed: false, object: node })) {
|
if (parentPath.isMemberExpression({ computed: false, object: node })) {
|
||||||
let prop = parentPath.get("property");
|
let prop = parentPath.get("property");
|
||||||
if (prop.node.name === "length") {
|
if (prop.node.name === "length") {
|
||||||
state.replaceOnly = true;
|
state.candidates.push({cause: "lengthGetter", path});
|
||||||
state.candidates.push(path);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,7 +81,7 @@ let memberExpressionOptimisationVisitor = {
|
|||||||
if (state.offset === 0 && parentPath.isSpreadElement()) {
|
if (state.offset === 0 && parentPath.isSpreadElement()) {
|
||||||
let call = parentPath.parentPath;
|
let call = parentPath.parentPath;
|
||||||
if (call.isCallExpression() && call.node.arguments.length === 1) {
|
if (call.isCallExpression() && call.node.arguments.length === 1) {
|
||||||
state.candidates.push(path);
|
state.candidates.push({cause: "argSpread", path});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,33 +102,47 @@ let memberExpressionOptimisationVisitor = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function hasRest(node) {
|
function hasRest(node) {
|
||||||
return t.isRestElement(node.params[node.params.length - 1]);
|
return t.isRestElement(node.params[node.params.length - 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function optimiseIndexGetter(path, argsId, offset) {
|
||||||
|
path.parentPath.replaceWith(loadRest({
|
||||||
|
ARGUMENTS: argsId,
|
||||||
|
INDEX: t.numericLiteral(path.parent.property.value + offset)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function optimiseLengthGetter(path, argsLengthExpression, argsId, offset) {
|
||||||
|
if (offset) {
|
||||||
|
path.parentPath.replaceWith(
|
||||||
|
t.binaryExpression(
|
||||||
|
"-",
|
||||||
|
argsLengthExpression,
|
||||||
|
t.numericLiteral(offset),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
path.replaceWith(argsId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export let visitor = {
|
export let visitor = {
|
||||||
Function(path) {
|
Function(path) {
|
||||||
let { node, scope } = path;
|
let { node, scope } = path;
|
||||||
if (!hasRest(node)) return;
|
if (!hasRest(node)) return;
|
||||||
|
|
||||||
let restParam = node.params.pop();
|
let rest = node.params.pop().argument;
|
||||||
let rest = restParam.argument;
|
|
||||||
|
|
||||||
let argsId = t.identifier("arguments");
|
let argsId = t.identifier("arguments");
|
||||||
|
let argsLengthExpression = t.memberExpression(
|
||||||
|
argsId,
|
||||||
|
t.identifier("length"),
|
||||||
|
);
|
||||||
|
|
||||||
// otherwise `arguments` will be remapped in arrow functions
|
// otherwise `arguments` will be remapped in arrow functions
|
||||||
argsId._shadowedFunctionLiteral = path;
|
argsId._shadowedFunctionLiteral = path;
|
||||||
|
|
||||||
function optimiseCandidate(parent, parentPath, offset) {
|
|
||||||
if (parent.property) {
|
|
||||||
parentPath.replaceWith(loadRest({
|
|
||||||
ARGUMENTS: argsId,
|
|
||||||
INDEX: t.numericLiteral(parent.property.value + offset)
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check and optimise for extremely common cases
|
// check and optimise for extremely common cases
|
||||||
let state = {
|
let state = {
|
||||||
references: [],
|
references: [],
|
||||||
@ -146,9 +159,6 @@ export let visitor = {
|
|||||||
|
|
||||||
// whether any references to the rest parameter were made in a function
|
// whether any references to the rest parameter were made in a function
|
||||||
deopted: false,
|
deopted: false,
|
||||||
|
|
||||||
// whether all we need to do is replace rest parameter identifier with 'arguments'
|
|
||||||
replaceOnly: false
|
|
||||||
};
|
};
|
||||||
|
|
||||||
path.traverse(memberExpressionOptimisationVisitor, state);
|
path.traverse(memberExpressionOptimisationVisitor, state);
|
||||||
@ -156,16 +166,24 @@ export let visitor = {
|
|||||||
if (!state.deopted && !state.references.length) {
|
if (!state.deopted && !state.references.length) {
|
||||||
// we only have shorthands and there are no other references
|
// we only have shorthands and there are no other references
|
||||||
if (state.candidates.length) {
|
if (state.candidates.length) {
|
||||||
for (let candidate of (state.candidates: Array)) {
|
for (let {path, cause} of (state.candidates: Array)) {
|
||||||
candidate.replaceWith(argsId);
|
switch (cause) {
|
||||||
if (!state.replaceOnly) {
|
case "indexGetter":
|
||||||
optimiseCandidate(candidate.parent, candidate.parentPath, state.offset);
|
optimiseIndexGetter(path, argsId, state.offset);
|
||||||
|
break;
|
||||||
|
case "lengthGetter":
|
||||||
|
optimiseLengthGetter(path, argsLengthExpression, argsId, state.offset);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
path.replaceWith(argsId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
state.references = state.references.concat(state.candidates);
|
state.references = state.references.concat(
|
||||||
|
state.candidates.map(({path}) => path)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// deopt shadowed functions as transforms like regenerator may try touch the allocation loop
|
// deopt shadowed functions as transforms like regenerator may try touch the allocation loop
|
||||||
|
|||||||
@ -32,3 +32,11 @@ var b = function (foo, ...bar) {
|
|||||||
var b = function (...bar) {
|
var b = function (...bar) {
|
||||||
return bar.len;
|
return bar.len;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var b = function (foo, ...bar) {
|
||||||
|
return bar.length * 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
var b = function (foo, baz, ...bar) {
|
||||||
|
return bar.length;
|
||||||
|
};
|
||||||
|
|||||||
@ -61,3 +61,11 @@ var b = function () {
|
|||||||
|
|
||||||
return bar.len;
|
return bar.len;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var b = function (foo) {
|
||||||
|
return (arguments.length - 1) * 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
var b = function (foo, baz) {
|
||||||
|
return arguments.length - 2;
|
||||||
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user