From 766a4147d4891a093b550e958268c48104330b52 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Thu, 21 Jun 2018 14:10:37 +0800 Subject: enhance `arguments` (#3193) fixes #3192 --- lib/compress.js | 85 ++++++++++++++++++++++++++++++++++----------------------- lib/utils.js | 4 +-- 2 files changed, 52 insertions(+), 37 deletions(-) (limited to 'lib') diff --git a/lib/compress.js b/lib/compress.js index 56c8fc47..0268e07f 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -518,14 +518,15 @@ merge(Compressor.prototype, { var sym = node.left; if (!(sym instanceof AST_SymbolRef)) return; var d = sym.definition(); + var safe = safe_to_assign(tw, d, sym.scope, node.right); + d.assignments++; + if (!safe) return; var fixed = d.fixed; if (!fixed && node.operator != "=") return; - if (!safe_to_assign(tw, d, sym.scope, node.right)) return; var eq = node.operator == "="; var value = eq ? node.right : node; if (is_modified(compressor, tw, node, value, 0)) return; d.references.push(sym); - d.assignments++; if (!eq) d.chained = true; d.fixed = eq ? function() { return node.right; @@ -657,7 +658,7 @@ merge(Compressor.prototype, { // So existing transformation rules can work on them. node.argnames.forEach(function(arg, i) { var d = arg.definition(); - if (!node.uses_arguments && d.fixed === undefined) { + if (d.fixed === undefined && (!node.uses_arguments || tw.has_directive("use strict"))) { d.fixed = function() { return iife.args[i] || make_node(AST_Undefined, iife); }; @@ -760,11 +761,12 @@ merge(Compressor.prototype, { var exp = node.expression; if (!(exp instanceof AST_SymbolRef)) return; var d = exp.definition(); + var safe = safe_to_assign(tw, d, exp.scope, true); + d.assignments++; + if (!safe) return; var fixed = d.fixed; if (!fixed) return; - if (!safe_to_assign(tw, d, exp.scope, true)) return; d.references.push(exp); - d.assignments++; d.chained = true; d.fixed = function() { return make_node(AST_Binary, node, { @@ -3289,6 +3291,15 @@ merge(Compressor.prototype, { // this scope (not in nested scopes). var scope = this; var tw = new TreeWalker(function(node, descend) { + if (node instanceof AST_Lambda && node.uses_arguments && !tw.has_directive("use strict")) { + node.argnames.forEach(function(argname) { + var def = argname.definition(); + if (!(def.id in in_use_ids)) { + in_use_ids[def.id] = true; + in_use.push(def); + } + }); + } if (node === self) return; if (node instanceof AST_Defun) { var node_def = node.name.definition(); @@ -3376,8 +3387,7 @@ merge(Compressor.prototype, { // any declarations with same name will overshadow // name of this anonymous function and can therefore // never be used anywhere - if (!(def.id in in_use_ids) || def.orig.length > 1) - node.name = null; + if (!(def.id in in_use_ids) || def.orig.length > 1) node.name = null; } if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) { var trim = !compressor.option("keep_fargs"); @@ -3389,8 +3399,7 @@ merge(Compressor.prototype, { a.pop(); compressor[sym.unreferenced() ? "warn" : "info"]("Dropping unused function argument {name} [{file}:{line},{col}]", template(sym)); } - } - else { + } else { trim = false; } } @@ -6208,6 +6217,39 @@ merge(Compressor.prototype, { } } } + var fn; + if (compressor.option("arguments") + && expr instanceof AST_SymbolRef + && expr.name == "arguments" + && expr.definition().orig.length == 1 + && (fn = expr.scope) instanceof AST_Lambda + && prop instanceof AST_Number) { + var index = prop.getValue(); + var argname = fn.argnames[index]; + if (argname && compressor.has_directive("use strict")) { + var def = argname.definition(); + if (!compressor.option("reduce_vars") || def.assignments || def.orig.length > 1) { + argname = null; + } + } else if (!argname && !compressor.option("keep_fargs") && index < fn.argnames.length + 5) { + while (index >= fn.argnames.length) { + argname = make_node(AST_SymbolFunarg, fn, { + name: fn.make_var_name("argument_" + fn.argnames.length), + scope: fn + }); + fn.argnames.push(argname); + fn.enclosed.push(fn.def_variable(argname)); + } + } + if (argname && find_if(function(node) { + return node.name === argname.name; + }, fn.argnames) === argname) { + var sym = make_node(AST_SymbolRef, self, argname); + sym.reference({}); + delete argname.__unused; + return sym; + } + } if (is_lhs(self, compressor.parent())) return self; if (key !== prop) { var sub = self.flatten_object(property, compressor); @@ -6251,31 +6293,6 @@ merge(Compressor.prototype, { }); } } - var fn; - if (compressor.option("arguments") - && expr instanceof AST_SymbolRef - && expr.name == "arguments" - && expr.definition().orig.length == 1 - && (fn = expr.scope) instanceof AST_Lambda - && prop instanceof AST_Number) { - var index = prop.getValue(); - var argname = fn.argnames[index]; - if (!argname && !compressor.option("keep_fargs")) { - while (index >= fn.argnames.length) { - argname = make_node(AST_SymbolFunarg, fn, { - name: fn.make_var_name("argument_" + fn.argnames.length), - scope: fn - }); - fn.argnames.push(argname); - fn.enclosed.push(fn.def_variable(argname)); - } - } - if (argname) { - var sym = make_node(AST_SymbolRef, self, argname); - sym.reference({}); - return sym; - } - } var ev = self.evaluate(compressor); if (ev !== self) { ev = make_node_from_constant(ev, self).optimize(compressor); diff --git a/lib/utils.js b/lib/utils.js index ca4b2d4b..7a51fb80 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -52,9 +52,7 @@ function member(name, array) { } function find_if(func, array) { - for (var i = 0, n = array.length; i < n; ++i) { - if (func(array[i])) return array[i]; - } + for (var i = array.length; --i >= 0;) if (func(array[i])) return array[i]; } function repeat_string(str, i) { -- cgit v1.2.3