From 99b2e00d33c7190be0458357e7cc85e756ffddd0 Mon Sep 17 00:00:00 2001 From: Ondrej Kraus Date: Wed, 25 Feb 2015 01:38:51 +0100 Subject: [PATCH 01/18] add rest parameters optimization --- .../transformers/es6/parameters.rest.js | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/src/babel/transformation/transformers/es6/parameters.rest.js b/src/babel/transformation/transformers/es6/parameters.rest.js index cda2b09175..2c2937bf2c 100644 --- a/src/babel/transformation/transformers/es6/parameters.rest.js +++ b/src/babel/transformation/transformers/es6/parameters.rest.js @@ -3,6 +3,64 @@ var t = require("../../../types"); exports.check = t.isRestElement; +var memberExpressionVisitor = { + enter: function (node, parent, scope, state) { + var localDeclar = scope.getBindingIdentifier(state.name); + if (localDeclar !== state.outerDeclar) return; + + if (t.isFunctionDeclaration(node) || t.isFunctionExpression(node)) { + state.isOptimizable = false; + this.skip(); + return; + } + + if (!t.isReferencedIdentifier(node, parent, { name: state.name })) return; + + if (parent.type === 'MemberExpression') { + var prop = parent.property; + if (typeof prop.value === 'number' || + prop.type === 'UnaryExpression' || + prop.type === 'BinaryExpression') { + state.candidates.push({ node: node, parent: parent }); + return; + } + } + + state.isOptimizable = false; + this.stop(); + } +}; + +function optimizeMemberExpression(node, parent, offset) { + var newExpr; + + var prop = parent.property; + switch (prop.type) { + case 'Literal': + node.name = 'arguments'; + prop.value += offset; + prop.raw = String(prop.value); + break; + case 'UnaryExpression': { + node.name = 'arguments'; + newExpr = t.binaryExpression('+', prop, t.literal(offset)); + parent.property = newExpr; + break; + } + case 'BinaryExpression': { + node.name = 'arguments'; + newExpr = t.binaryExpression('+', prop, t.literal(offset)); + parent.property = newExpr; + break; + } + default: + throw new Error('Unsupported property type'); + } +} + +function optimizeCandidates(candidates) { +} + var hasRest = function (node) { return t.isRestElement(node.params[node.params.length - 1]); }; @@ -17,6 +75,24 @@ exports.Function = function (node, parent, scope) { // otherwise `arguments` will be remapped in arrow functions argsId._ignoreAliasFunctions = true; + // 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 (var i = 0, count = state.candidates.length; i < count; ++i) { + var candidate = state.candidates[i]; + optimizeMemberExpression(candidate.node, candidate.parent, node.params.length); + } + return; + } + var start = t.literal(node.params.length); var key = scope.generateUidIdentifier("key"); var len = scope.generateUidIdentifier("len"); From f2981b7e95c50296790b909818a45cfe5efd1562 Mon Sep 17 00:00:00 2001 From: Ondrej Kraus Date: Wed, 25 Feb 2015 03:02:48 +0100 Subject: [PATCH 02/18] replace direct node type checking with helper functions --- .../transformers/es6/parameters.rest.js | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/babel/transformation/transformers/es6/parameters.rest.js b/src/babel/transformation/transformers/es6/parameters.rest.js index 2c2937bf2c..12be9d2bd3 100644 --- a/src/babel/transformation/transformers/es6/parameters.rest.js +++ b/src/babel/transformation/transformers/es6/parameters.rest.js @@ -16,11 +16,11 @@ var memberExpressionVisitor = { if (!t.isReferencedIdentifier(node, parent, { name: state.name })) return; - if (parent.type === 'MemberExpression') { + if (t.isMemberExpression(parent)) { var prop = parent.property; if (typeof prop.value === 'number' || - prop.type === 'UnaryExpression' || - prop.type === 'BinaryExpression') { + t.isUnaryExpression(prop) || + t.isBinaryExpression(prop)) { state.candidates.push({ node: node, parent: parent }); return; } @@ -35,26 +35,18 @@ function optimizeMemberExpression(node, parent, offset) { var newExpr; var prop = parent.property; - switch (prop.type) { - case 'Literal': + if (t.isLiteral(prop)) { node.name = 'arguments'; prop.value += offset; prop.raw = String(prop.value); - break; - case 'UnaryExpression': { + } else if (t.isUnaryExpression(prop)) { node.name = 'arguments'; newExpr = t.binaryExpression('+', prop, t.literal(offset)); parent.property = newExpr; - break; - } - case 'BinaryExpression': { + } else if (t.isBinaryExpression(prop)) { node.name = 'arguments'; newExpr = t.binaryExpression('+', prop, t.literal(offset)); parent.property = newExpr; - break; - } - default: - throw new Error('Unsupported property type'); } } From 81ae6563588fa3f660a3d7d8d0f06d0001e063d9 Mon Sep 17 00:00:00 2001 From: Ondrej Kraus Date: Wed, 25 Feb 2015 03:05:57 +0100 Subject: [PATCH 03/18] remove unused function --- src/babel/transformation/transformers/es6/parameters.rest.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/babel/transformation/transformers/es6/parameters.rest.js b/src/babel/transformation/transformers/es6/parameters.rest.js index 12be9d2bd3..85b636d11b 100644 --- a/src/babel/transformation/transformers/es6/parameters.rest.js +++ b/src/babel/transformation/transformers/es6/parameters.rest.js @@ -50,9 +50,6 @@ function optimizeMemberExpression(node, parent, offset) { } } -function optimizeCandidates(candidates) { -} - var hasRest = function (node) { return t.isRestElement(node.params[node.params.length - 1]); }; From 8ca854156a3764a6f46df42f74d274fb64281202 Mon Sep 17 00:00:00 2001 From: Ondrej Kraus Date: Wed, 25 Feb 2015 03:33:36 +0100 Subject: [PATCH 04/18] simplify and optimize local binding handling --- .../transformation/transformers/es6/parameters.rest.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/babel/transformation/transformers/es6/parameters.rest.js b/src/babel/transformation/transformers/es6/parameters.rest.js index 85b636d11b..09e8fdd960 100644 --- a/src/babel/transformation/transformers/es6/parameters.rest.js +++ b/src/babel/transformation/transformers/es6/parameters.rest.js @@ -5,13 +5,13 @@ exports.check = t.isRestElement; var memberExpressionVisitor = { enter: function (node, parent, scope, state) { - var localDeclar = scope.getBindingIdentifier(state.name); - if (localDeclar !== state.outerDeclar) return; + if (t.isScope(node, parent) && !scope.bindingIdentifierEquals(state.name, state.outerDeclar)) { + return this.skip(); + } if (t.isFunctionDeclaration(node) || t.isFunctionExpression(node)) { state.isOptimizable = false; - this.skip(); - return; + return this.skip(); } if (!t.isReferencedIdentifier(node, parent, { name: state.name })) return; From e677c72d583d553c46f7ec1aeb52bbb1234c1d71 Mon Sep 17 00:00:00 2001 From: Ondrej Kraus Date: Wed, 25 Feb 2015 04:30:17 +0100 Subject: [PATCH 05/18] add patterns support --- .../transformers/es6/parameters.rest.js | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/src/babel/transformation/transformers/es6/parameters.rest.js b/src/babel/transformation/transformers/es6/parameters.rest.js index 09e8fdd960..7559619db5 100644 --- a/src/babel/transformation/transformers/es6/parameters.rest.js +++ b/src/babel/transformation/transformers/es6/parameters.rest.js @@ -64,6 +64,17 @@ 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)); + 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 = { @@ -107,22 +118,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", { From 1265bc5a9282be3e807ce9794fe562488f1a3a4b Mon Sep 17 00:00:00 2001 From: Ondrej Kraus Date: Wed, 25 Feb 2015 12:01:10 +0100 Subject: [PATCH 06/18] add better optimization when strictMode transformer is enabled --- .../transformers/es6/parameters.rest.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/babel/transformation/transformers/es6/parameters.rest.js b/src/babel/transformation/transformers/es6/parameters.rest.js index 7559619db5..e76a1744ef 100644 --- a/src/babel/transformation/transformers/es6/parameters.rest.js +++ b/src/babel/transformation/transformers/es6/parameters.rest.js @@ -18,7 +18,8 @@ var memberExpressionVisitor = { if (t.isMemberExpression(parent)) { var prop = parent.property; - if (typeof prop.value === 'number' || + if (state.strictMode || + typeof prop.value === 'number' || t.isUnaryExpression(prop) || t.isBinaryExpression(prop)) { state.candidates.push({ node: node, parent: parent }); @@ -50,11 +51,17 @@ function optimizeMemberExpression(node, parent, offset) { } } +function optimizeMemberExpressionStrict(node, parent, offset) { + var prop = parent.property; + node.name = 'arguments'; + parent.property = t.binaryExpression('+', prop, t.literal(offset)); +} + var hasRest = function (node) { return t.isRestElement(node.params[node.params.length - 1]); }; -exports.Function = function (node, parent, scope) { +exports.Function = function (node, parent, scope, file) { if (!hasRest(node)) return; var rest = node.params.pop().argument; @@ -81,14 +88,16 @@ exports.Function = function (node, parent, scope) { name: rest.name, outerDeclar: restOuterDeclar, isOptimizable: true, - candidates: [] + candidates: [], + strictMode: file.transformers.useStrict.canRun() }; scope.traverse(node, memberExpressionVisitor, state); if (state.isOptimizable) { + var optimize = state.strictMode ? optimizeMemberExpressionStrict : optimizeMemberExpression; for (var i = 0, count = state.candidates.length; i < count; ++i) { var candidate = state.candidates[i]; - optimizeMemberExpression(candidate.node, candidate.parent, node.params.length); + optimize(candidate.node, candidate.parent, node.params.length); } return; } From 8f540dfff328aa3ffe3ba36673dd4a52b6ef37a5 Mon Sep 17 00:00:00 2001 From: Ondrej Kraus Date: Wed, 25 Feb 2015 12:07:46 +0100 Subject: [PATCH 07/18] call non-strict mode optimizer before strict mode one to simplify literals --- src/babel/transformation/transformers/es6/parameters.rest.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/babel/transformation/transformers/es6/parameters.rest.js b/src/babel/transformation/transformers/es6/parameters.rest.js index e76a1744ef..6f9cc0ecfc 100644 --- a/src/babel/transformation/transformers/es6/parameters.rest.js +++ b/src/babel/transformation/transformers/es6/parameters.rest.js @@ -52,6 +52,10 @@ function optimizeMemberExpression(node, parent, offset) { } function optimizeMemberExpressionStrict(node, parent, offset) { + // handle basic expressions specially (especially literals) + optimizeMemberExpression(node, parent, offset); + if (node.name === 'arguments') return; + var prop = parent.property; node.name = 'arguments'; parent.property = t.binaryExpression('+', prop, t.literal(offset)); From 662bddbacab8a46cddc7c9462b60b8f8bfc3dce2 Mon Sep 17 00:00:00 2001 From: Ondrej Kraus Date: Wed, 25 Feb 2015 12:14:53 +0100 Subject: [PATCH 08/18] simplify optimization code --- .../transformers/es6/parameters.rest.js | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/babel/transformation/transformers/es6/parameters.rest.js b/src/babel/transformation/transformers/es6/parameters.rest.js index 6f9cc0ecfc..a179e0d7f2 100644 --- a/src/babel/transformation/transformers/es6/parameters.rest.js +++ b/src/babel/transformation/transformers/es6/parameters.rest.js @@ -32,10 +32,10 @@ var memberExpressionVisitor = { } }; -function optimizeMemberExpression(node, parent, offset) { +function optimizeMemberExpression(node, parent, offset, strictMode) { var newExpr; - var prop = parent.property; + if (t.isLiteral(prop)) { node.name = 'arguments'; prop.value += offset; @@ -49,16 +49,11 @@ function optimizeMemberExpression(node, parent, offset) { newExpr = t.binaryExpression('+', prop, t.literal(offset)); parent.property = newExpr; } -} -function optimizeMemberExpressionStrict(node, parent, offset) { - // handle basic expressions specially (especially literals) - optimizeMemberExpression(node, parent, offset); - if (node.name === 'arguments') return; - - var prop = parent.property; - node.name = 'arguments'; - parent.property = t.binaryExpression('+', prop, t.literal(offset)); + if (strictMode && node.name !== 'arguments') { + node.name = 'arguments'; + parent.property = t.binaryExpression('+', prop, t.literal(offset)); + } } var hasRest = function (node) { @@ -98,10 +93,9 @@ exports.Function = function (node, parent, scope, file) { scope.traverse(node, memberExpressionVisitor, state); if (state.isOptimizable) { - var optimize = state.strictMode ? optimizeMemberExpressionStrict : optimizeMemberExpression; for (var i = 0, count = state.candidates.length; i < count; ++i) { var candidate = state.candidates[i]; - optimize(candidate.node, candidate.parent, node.params.length); + optimizeMemberExpression(candidate.node, candidate.parent, node.params.length, state.strictMode); } return; } From c5913564f8c1a3591a5323c63a77925a3e5942af Mon Sep 17 00:00:00 2001 From: Ondrej Kraus Date: Wed, 25 Feb 2015 12:16:41 +0100 Subject: [PATCH 09/18] replace quotes to conform to coding style --- .../transformers/es6/parameters.rest.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/babel/transformation/transformers/es6/parameters.rest.js b/src/babel/transformation/transformers/es6/parameters.rest.js index a179e0d7f2..a464e996dd 100644 --- a/src/babel/transformation/transformers/es6/parameters.rest.js +++ b/src/babel/transformation/transformers/es6/parameters.rest.js @@ -19,7 +19,7 @@ var memberExpressionVisitor = { if (t.isMemberExpression(parent)) { var prop = parent.property; if (state.strictMode || - typeof prop.value === 'number' || + typeof prop.value === "number" || t.isUnaryExpression(prop) || t.isBinaryExpression(prop)) { state.candidates.push({ node: node, parent: parent }); @@ -37,22 +37,22 @@ function optimizeMemberExpression(node, parent, offset, strictMode) { var prop = parent.property; if (t.isLiteral(prop)) { - node.name = 'arguments'; + node.name = "arguments"; prop.value += offset; prop.raw = String(prop.value); } else if (t.isUnaryExpression(prop)) { - node.name = 'arguments'; - newExpr = t.binaryExpression('+', prop, t.literal(offset)); + node.name = "arguments"; + newExpr = t.binaryExpression("+", prop, t.literal(offset)); parent.property = newExpr; } else if (t.isBinaryExpression(prop)) { - node.name = 'arguments'; - newExpr = t.binaryExpression('+', prop, t.literal(offset)); + node.name = "arguments"; + newExpr = t.binaryExpression("+", prop, t.literal(offset)); parent.property = newExpr; } - if (strictMode && node.name !== 'arguments') { - node.name = 'arguments'; - parent.property = t.binaryExpression('+', prop, t.literal(offset)); + if (strictMode && node.name !== "arguments") { + node.name = "arguments"; + parent.property = t.binaryExpression("+", prop, t.literal(offset)); } } From e8741daee317346cc454140f93a463ebb0de08b5 Mon Sep 17 00:00:00 2001 From: Ondrej Kraus Date: Wed, 25 Feb 2015 14:13:15 +0100 Subject: [PATCH 10/18] use some ES6 to simplify code --- .../transformation/transformers/es6/parameters.rest.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/babel/transformation/transformers/es6/parameters.rest.js b/src/babel/transformation/transformers/es6/parameters.rest.js index a464e996dd..34e5e52c6f 100644 --- a/src/babel/transformation/transformers/es6/parameters.rest.js +++ b/src/babel/transformation/transformers/es6/parameters.rest.js @@ -4,7 +4,7 @@ var t = require("../../../types"); exports.check = t.isRestElement; var memberExpressionVisitor = { - enter: function (node, parent, scope, state) { + enter(node, parent, scope, state) { if (t.isScope(node, parent) && !scope.bindingIdentifierEquals(state.name, state.outerDeclar)) { return this.skip(); } @@ -22,7 +22,7 @@ var memberExpressionVisitor = { typeof prop.value === "number" || t.isUnaryExpression(prop) || t.isBinaryExpression(prop)) { - state.candidates.push({ node: node, parent: parent }); + state.candidates.push({ node, parent }); return; } } @@ -93,8 +93,7 @@ exports.Function = function (node, parent, scope, file) { scope.traverse(node, memberExpressionVisitor, state); if (state.isOptimizable) { - for (var i = 0, count = state.candidates.length; i < count; ++i) { - var candidate = state.candidates[i]; + for (let candidate of state.candidates) { optimizeMemberExpression(candidate.node, candidate.parent, node.params.length, state.strictMode); } return; From edb880f87c7f4a5d466c4648db70a53ea71bf101 Mon Sep 17 00:00:00 2001 From: Ondrej Kraus Date: Wed, 25 Feb 2015 14:26:28 +0100 Subject: [PATCH 11/18] add tests --- .../arrow-functions/actual.js | 3 ++- .../arrow-functions/expected.js | 7 ++--- .../es6-parameters.rest/deopt/actual.js | 15 +++++++++++ .../es6-parameters.rest/deopt/expected.js | 26 +++++++++++++++++++ .../es6-parameters.rest/multiple/actual.js | 8 ++++-- .../es6-parameters.rest/multiple/expected.js | 13 +++++----- .../es6-parameters.rest/pattern/actual.js | 1 - .../es6-parameters.rest/pattern/expected.js | 9 +++---- .../es6-parameters.rest/single/actual.js | 6 +++-- .../es6-parameters.rest/single/expected.js | 11 ++++---- 10 files changed, 72 insertions(+), 27 deletions(-) create mode 100644 test/fixtures/transformation/es6-parameters.rest/deopt/actual.js create mode 100644 test/fixtures/transformation/es6-parameters.rest/deopt/expected.js 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..be0fc35ff7 --- /dev/null +++ b/test/fixtures/transformation/es6-parameters.rest/deopt/actual.js @@ -0,0 +1,15 @@ +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; + }; +}; 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..28492a1560 --- /dev/null +++ b/test/fixtures/transformation/es6-parameters.rest/deopt/expected.js @@ -0,0 +1,26 @@ +"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; + }; +}; + 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]; } + From c3f4091b6d1c443a53a6c9a6458569e42e7e1153 Mon Sep 17 00:00:00 2001 From: Ondrej Kraus Date: Wed, 25 Feb 2015 14:41:20 +0100 Subject: [PATCH 12/18] replace for-of with with for for performance reasons --- src/babel/transformation/transformers/es6/parameters.rest.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/babel/transformation/transformers/es6/parameters.rest.js b/src/babel/transformation/transformers/es6/parameters.rest.js index 34e5e52c6f..88ff4733dd 100644 --- a/src/babel/transformation/transformers/es6/parameters.rest.js +++ b/src/babel/transformation/transformers/es6/parameters.rest.js @@ -93,7 +93,8 @@ exports.Function = function (node, parent, scope, file) { scope.traverse(node, memberExpressionVisitor, state); if (state.isOptimizable) { - for (let candidate of state.candidates) { + 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; From a808742c1909bf3db76cd251a121cd3582c5e0aa Mon Sep 17 00:00:00 2001 From: Ondrej Kraus Date: Wed, 25 Feb 2015 15:24:45 +0100 Subject: [PATCH 13/18] remove strict-mode specific optimizations due to unsolvable ambiguities --- .../transformers/es6/parameters.rest.js | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/src/babel/transformation/transformers/es6/parameters.rest.js b/src/babel/transformation/transformers/es6/parameters.rest.js index 88ff4733dd..0c72a42529 100644 --- a/src/babel/transformation/transformers/es6/parameters.rest.js +++ b/src/babel/transformation/transformers/es6/parameters.rest.js @@ -18,8 +18,7 @@ var memberExpressionVisitor = { if (t.isMemberExpression(parent)) { var prop = parent.property; - if (state.strictMode || - typeof prop.value === "number" || + if (typeof prop.value === "number" || t.isUnaryExpression(prop) || t.isBinaryExpression(prop)) { state.candidates.push({ node, parent }); @@ -32,7 +31,7 @@ var memberExpressionVisitor = { } }; -function optimizeMemberExpression(node, parent, offset, strictMode) { +function optimizeMemberExpression(node, parent, offset) { var newExpr; var prop = parent.property; @@ -40,19 +39,10 @@ function optimizeMemberExpression(node, parent, offset, strictMode) { node.name = "arguments"; prop.value += offset; prop.raw = String(prop.value); - } else if (t.isUnaryExpression(prop)) { + } else { node.name = "arguments"; newExpr = t.binaryExpression("+", prop, t.literal(offset)); parent.property = newExpr; - } else if (t.isBinaryExpression(prop)) { - node.name = "arguments"; - newExpr = t.binaryExpression("+", prop, t.literal(offset)); - parent.property = newExpr; - } - - if (strictMode && node.name !== "arguments") { - node.name = "arguments"; - parent.property = t.binaryExpression("+", prop, t.literal(offset)); } } @@ -87,8 +77,7 @@ exports.Function = function (node, parent, scope, file) { name: rest.name, outerDeclar: restOuterDeclar, isOptimizable: true, - candidates: [], - strictMode: file.transformers.useStrict.canRun() + candidates: [] }; scope.traverse(node, memberExpressionVisitor, state); From e6855b974b23367d24f703345fe01104fd61cd24 Mon Sep 17 00:00:00 2001 From: Ondrej Kraus Date: Wed, 25 Feb 2015 15:30:22 +0100 Subject: [PATCH 14/18] update tests --- .../es6-parameters.rest/deopt/actual.js | 9 ++++ .../es6-parameters.rest/deopt/expected.js | 43 +++++++++++++------ 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/test/fixtures/transformation/es6-parameters.rest/deopt/actual.js b/test/fixtures/transformation/es6-parameters.rest/deopt/actual.js index be0fc35ff7..f7eab07df8 100644 --- a/test/fixtures/transformation/es6-parameters.rest/deopt/actual.js +++ b/test/fixtures/transformation/es6-parameters.rest/deopt/actual.js @@ -13,3 +13,12 @@ var z = function (foo, ...bar) { 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 index 28492a1560..389762d336 100644 --- a/test/fixtures/transformation/es6-parameters.rest/deopt/expected.js +++ b/test/fixtures/transformation/es6-parameters.rest/deopt/expected.js @@ -1,26 +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]; - } + 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); + console.log(bar); }; var y = function y(foo) { - var x = function z(bar) { - bar[1] = 5; - }; + 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]; - } + 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 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]; }; From 687b0f31809fd1a450739a3e564f72a7a88f1b67 Mon Sep 17 00:00:00 2001 From: Ondrej Kraus Date: Wed, 25 Feb 2015 15:38:32 +0100 Subject: [PATCH 15/18] remove unused function argument --- src/babel/transformation/transformers/es6/parameters.rest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/babel/transformation/transformers/es6/parameters.rest.js b/src/babel/transformation/transformers/es6/parameters.rest.js index 0c72a42529..5954904f26 100644 --- a/src/babel/transformation/transformers/es6/parameters.rest.js +++ b/src/babel/transformation/transformers/es6/parameters.rest.js @@ -50,7 +50,7 @@ var hasRest = function (node) { return t.isRestElement(node.params[node.params.length - 1]); }; -exports.Function = function (node, parent, scope, file) { +exports.Function = function (node, parent, scope) { if (!hasRest(node)) return; var rest = node.params.pop().argument; From 24ace3c8c2508bb375ee364e069758f6bbb214c8 Mon Sep 17 00:00:00 2001 From: Jamund Ferguson Date: Wed, 25 Feb 2015 13:51:26 -0800 Subject: [PATCH 16/18] feat(6to5/register) don't override uncaughtException handler Maybe we could do this by default or even make it configurable? --- src/babel/api/register/node.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/babel/api/register/node.js b/src/babel/api/register/node.js index b89c6544b9..ec603c1dcd 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) { From 5d83638583f89b735824010e20c20418ce3c69a2 Mon Sep 17 00:00:00 2001 From: Ondrej Kraus Date: Thu, 26 Feb 2015 01:22:00 +0100 Subject: [PATCH 17/18] set literal MemberExpression as computed in rest array destructuring --- src/babel/transformation/transformers/es6/parameters.rest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/babel/transformation/transformers/es6/parameters.rest.js b/src/babel/transformation/transformers/es6/parameters.rest.js index 5954904f26..2c0d73827d 100644 --- a/src/babel/transformation/transformers/es6/parameters.rest.js +++ b/src/babel/transformation/transformers/es6/parameters.rest.js @@ -65,7 +65,7 @@ exports.Function = function (node, parent, scope) { 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)); + var accessExpr = t.memberExpression(rest, t.literal(index), true); return t.variableDeclarator(elem, accessExpr); })); node.body.body.unshift(declar); From b5f3c3f4ccdb70d846f92925e4cc31b67d078c4b Mon Sep 17 00:00:00 2001 From: Ondrej Kraus Date: Thu, 26 Feb 2015 02:05:26 +0100 Subject: [PATCH 18/18] stop traversal when it is clear that optimization is impossible --- src/babel/transformation/transformers/es6/parameters.rest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/babel/transformation/transformers/es6/parameters.rest.js b/src/babel/transformation/transformers/es6/parameters.rest.js index 2c0d73827d..230f429a03 100644 --- a/src/babel/transformation/transformers/es6/parameters.rest.js +++ b/src/babel/transformation/transformers/es6/parameters.rest.js @@ -11,7 +11,7 @@ var memberExpressionVisitor = { if (t.isFunctionDeclaration(node) || t.isFunctionExpression(node)) { state.isOptimizable = false; - return this.skip(); + return this.stop(); } if (!t.isReferencedIdentifier(node, parent, { name: state.name })) return;