diff --git a/src/babel/api/register/node.js b/src/babel/api/register/node.js index d494272a91..9af300ce82 100644 --- a/src/babel/api/register/node.js +++ b/src/babel/api/register/node.js @@ -10,6 +10,7 @@ var util = require("../../util"); var fs = require("fs"); sourceMapSupport.install({ + handleUncaughtExceptions: false, retrieveSourceMap(source) { var map = maps && maps[source]; if (map) { diff --git a/src/babel/transformation/transformers/es6/parameters.rest.js b/src/babel/transformation/transformers/es6/parameters.rest.js index cda2b09175..230f429a03 100644 --- a/src/babel/transformation/transformers/es6/parameters.rest.js +++ b/src/babel/transformation/transformers/es6/parameters.rest.js @@ -3,6 +3,49 @@ var t = require("../../../types"); exports.check = t.isRestElement; +var memberExpressionVisitor = { + enter(node, parent, scope, state) { + if (t.isScope(node, parent) && !scope.bindingIdentifierEquals(state.name, state.outerDeclar)) { + return this.skip(); + } + + if (t.isFunctionDeclaration(node) || t.isFunctionExpression(node)) { + state.isOptimizable = false; + return this.stop(); + } + + if (!t.isReferencedIdentifier(node, parent, { name: state.name })) return; + + if (t.isMemberExpression(parent)) { + var prop = parent.property; + if (typeof prop.value === "number" || + t.isUnaryExpression(prop) || + t.isBinaryExpression(prop)) { + state.candidates.push({ node, parent }); + return; + } + } + + state.isOptimizable = false; + this.stop(); + } +}; + +function optimizeMemberExpression(node, parent, offset) { + var newExpr; + var prop = parent.property; + + if (t.isLiteral(prop)) { + node.name = "arguments"; + prop.value += offset; + prop.raw = String(prop.value); + } else { + node.name = "arguments"; + newExpr = t.binaryExpression("+", prop, t.literal(offset)); + parent.property = newExpr; + } +} + var hasRest = function (node) { return t.isRestElement(node.params[node.params.length - 1]); }; @@ -17,6 +60,35 @@ exports.Function = function (node, parent, scope) { // otherwise `arguments` will be remapped in arrow functions argsId._ignoreAliasFunctions = true; + // support patterns + if (t.isPattern(rest)) { + var pattern = rest; + rest = scope.generateUidIdentifier("ref"); + var declar = t.variableDeclaration("var", pattern.elements.map(function (elem, index) { + var accessExpr = t.memberExpression(rest, t.literal(index), true); + return t.variableDeclarator(elem, accessExpr); + })); + node.body.body.unshift(declar); + } + + // check if rest is used only in member expressions + var restOuterDeclar = scope.getBindingIdentifier(rest.name); + var state = { + name: rest.name, + outerDeclar: restOuterDeclar, + isOptimizable: true, + candidates: [] + }; + scope.traverse(node, memberExpressionVisitor, state); + + if (state.isOptimizable) { + for (let i = 0, count = state.candidates.length; i < count; ++i) { + let candidate = state.candidates[i]; + optimizeMemberExpression(candidate.node, candidate.parent, node.params.length, state.strictMode); + } + return; + } + var start = t.literal(node.params.length); var key = scope.generateUidIdentifier("key"); var len = scope.generateUidIdentifier("len"); @@ -42,22 +114,6 @@ exports.Function = function (node, parent, scope) { ); } - // support patterns - if (t.isPattern(rest)) { - var pattern = rest; - rest = scope.generateUidIdentifier("ref"); - - // let the destructuring transformer handle this - var restDeclar = t.variableDeclaration("var", [ - t.variableDeclarator(pattern, rest) - ]); - - // retain evaluation position - restDeclar._blockHoist = node.params.length + 1; - - node.body.body.unshift(restDeclar); - } - scope.assignTypeGeneric(rest.name, "Array"); var loop = util.template("rest", { diff --git a/test/fixtures/transformation/es6-parameters.rest/arrow-functions/actual.js b/test/fixtures/transformation/es6-parameters.rest/arrow-functions/actual.js index 4a130fad8d..854274b1e6 100644 --- a/test/fixtures/transformation/es6-parameters.rest/arrow-functions/actual.js +++ b/test/fixtures/transformation/es6-parameters.rest/arrow-functions/actual.js @@ -1,3 +1,4 @@ var concat = (...arrs) => { - + var x = arrs[0]; + var y = arrs[1]; }; diff --git a/test/fixtures/transformation/es6-parameters.rest/arrow-functions/expected.js b/test/fixtures/transformation/es6-parameters.rest/arrow-functions/expected.js index 4b72d8d4cf..96e011a7fc 100644 --- a/test/fixtures/transformation/es6-parameters.rest/arrow-functions/expected.js +++ b/test/fixtures/transformation/es6-parameters.rest/arrow-functions/expected.js @@ -1,7 +1,8 @@ "use strict"; +var _arguments = arguments; var concat = function () { - for (var _len = arguments.length, arrs = Array(_len), _key = 0; _key < _len; _key++) { - arrs[_key] = arguments[_key]; - } + var x = _arguments[0]; + var y = _arguments[1]; }; + diff --git a/test/fixtures/transformation/es6-parameters.rest/deopt/actual.js b/test/fixtures/transformation/es6-parameters.rest/deopt/actual.js new file mode 100644 index 0000000000..f7eab07df8 --- /dev/null +++ b/test/fixtures/transformation/es6-parameters.rest/deopt/actual.js @@ -0,0 +1,24 @@ +var x = function (foo, ...bar) { + console.log(bar); +}; + +var y = function (foo, ...bar) { + var x = function z(bar) { + bar[1] = 5; + }; +}; + +var z = function (foo, ...bar) { + var x = function () { + bar[1] = 5; + }; +}; + +var a = function (foo, ...bar) { + return bar.join(','); +}; + +var b = function (foo, ...bar) { + var join = "join"; + return bar[join]; +}; diff --git a/test/fixtures/transformation/es6-parameters.rest/deopt/expected.js b/test/fixtures/transformation/es6-parameters.rest/deopt/expected.js new file mode 100644 index 0000000000..389762d336 --- /dev/null +++ b/test/fixtures/transformation/es6-parameters.rest/deopt/expected.js @@ -0,0 +1,43 @@ +"use strict"; + +var x = function x(foo) { + for (var _len = arguments.length, bar = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + bar[_key - 1] = arguments[_key]; + } + + console.log(bar); +}; + +var y = function y(foo) { + var x = function z(bar) { + bar[1] = 5; + }; +}; + +var z = function z(foo) { + for (var _len = arguments.length, bar = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + bar[_key - 1] = arguments[_key]; + } + + var x = function x() { + bar[1] = 5; + }; +}; + +var a = function a(foo) { + for (var _len = arguments.length, bar = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + bar[_key - 1] = arguments[_key]; + } + + return bar.join(","); +}; + +var b = function b(foo) { + for (var _len = arguments.length, bar = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + bar[_key - 1] = arguments[_key]; + } + + var join = "join"; + return bar[join]; +}; + diff --git a/test/fixtures/transformation/es6-parameters.rest/multiple/actual.js b/test/fixtures/transformation/es6-parameters.rest/multiple/actual.js index 49d78b919e..59f2c222f8 100644 --- a/test/fixtures/transformation/es6-parameters.rest/multiple/actual.js +++ b/test/fixtures/transformation/es6-parameters.rest/multiple/actual.js @@ -1,7 +1,11 @@ var t = function (f, ...items) { - + var x = f; + x = items[0]; + x = items[1]; }; function t(f, ...items) { - + var x = f; + x = items[0]; + x = items[1]; } diff --git a/test/fixtures/transformation/es6-parameters.rest/multiple/expected.js b/test/fixtures/transformation/es6-parameters.rest/multiple/expected.js index 470cd17396..18fc23f505 100644 --- a/test/fixtures/transformation/es6-parameters.rest/multiple/expected.js +++ b/test/fixtures/transformation/es6-parameters.rest/multiple/expected.js @@ -1,13 +1,14 @@ "use strict"; var t = function t(f) { - for (var _len = arguments.length, items = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { - items[_key - 1] = arguments[_key]; - } + var x = f; + x = arguments[1]; + x = arguments[2]; }; function t(f) { - for (var _len = arguments.length, items = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { - items[_key - 1] = arguments[_key]; - } + var x = f; + x = arguments[1]; + x = arguments[2]; } + diff --git a/test/fixtures/transformation/es6-parameters.rest/pattern/actual.js b/test/fixtures/transformation/es6-parameters.rest/pattern/actual.js index 020ad4f8f7..d26dae5716 100644 --- a/test/fixtures/transformation/es6-parameters.rest/pattern/actual.js +++ b/test/fixtures/transformation/es6-parameters.rest/pattern/actual.js @@ -1,3 +1,2 @@ var foo = function (...[a, b]) { - }; diff --git a/test/fixtures/transformation/es6-parameters.rest/pattern/expected.js b/test/fixtures/transformation/es6-parameters.rest/pattern/expected.js index b3f2634c07..a52993a722 100644 --- a/test/fixtures/transformation/es6-parameters.rest/pattern/expected.js +++ b/test/fixtures/transformation/es6-parameters.rest/pattern/expected.js @@ -1,10 +1,7 @@ "use strict"; var foo = function foo() { - for (var _len = arguments.length, _ref = Array(_len), _key = 0; _key < _len; _key++) { - _ref[_key] = arguments[_key]; - } - - var a = _ref[0]; - var b = _ref[1]; + var a = arguments[0], + b = arguments[1]; }; + diff --git a/test/fixtures/transformation/es6-parameters.rest/single/actual.js b/test/fixtures/transformation/es6-parameters.rest/single/actual.js index dc9fbe391a..8e81076ecc 100644 --- a/test/fixtures/transformation/es6-parameters.rest/single/actual.js +++ b/test/fixtures/transformation/es6-parameters.rest/single/actual.js @@ -1,7 +1,9 @@ var t = function (...items) { - + var x = items[0]; + var y = items[1]; } function t(...items) { - + var x = items[0]; + var y = items[1]; } diff --git a/test/fixtures/transformation/es6-parameters.rest/single/expected.js b/test/fixtures/transformation/es6-parameters.rest/single/expected.js index 101e2f256c..add403243b 100644 --- a/test/fixtures/transformation/es6-parameters.rest/single/expected.js +++ b/test/fixtures/transformation/es6-parameters.rest/single/expected.js @@ -1,13 +1,12 @@ "use strict"; var t = function t() { - for (var _len = arguments.length, items = Array(_len), _key = 0; _key < _len; _key++) { - items[_key] = arguments[_key]; - } + var x = arguments[0]; + var y = arguments[1]; }; function t() { - for (var _len = arguments.length, items = Array(_len), _key = 0; _key < _len; _key++) { - items[_key] = arguments[_key]; - } + var x = arguments[0]; + var y = arguments[1]; } +