From aa0029204ebb7f52db4c70e9579caa1712d1261f Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Wed, 29 Aug 2018 22:14:25 +0800 Subject: [PATCH] fix corner case in `reduce_vars` (#3241) fixes #3240 --- lib/compress.js | 53 ++++++------ test/compress/reduce_vars.js | 157 +++++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+), 27 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index f84409ff..9e4ab315 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -5751,38 +5751,34 @@ merge(Compressor.prototype, { } var parent = compressor.parent(); if (compressor.option("reduce_vars") && is_lhs(self, parent) !== self) { - var d = self.definition(); + var def = self.definition(); var fixed = self.fixed_value(); - var single_use = d.single_use - && !(parent instanceof AST_Call && parent.is_expr_pure(compressor)); + var single_use = def.single_use && !(parent instanceof AST_Call && parent.is_expr_pure(compressor)); if (single_use && fixed instanceof AST_Lambda) { - if (d.scope !== self.scope - && (!compressor.option("reduce_funcs") - || d.escaped == 1 - || fixed.inlined)) { + if (def.scope !== self.scope + && (!compressor.option("reduce_funcs") || def.escaped == 1 || fixed.inlined)) { single_use = false; - } else if (recursive_ref(compressor, d)) { + } else if (recursive_ref(compressor, def)) { single_use = false; - } else if (d.scope !== self.scope || d.orig[0] instanceof AST_SymbolFunarg) { + } else if (def.scope !== self.scope || def.orig[0] instanceof AST_SymbolFunarg) { single_use = fixed.is_constant_expression(self.scope); if (single_use == "f") { var scope = self.scope; - do { - if (scope instanceof AST_Defun || scope instanceof AST_Function) { - scope.inlined = true; - } + do if (scope instanceof AST_Defun || scope instanceof AST_Function) { + scope.inlined = true; } while (scope = scope.parent_scope); } } } if (single_use && fixed) { + def.single_use = false; if (fixed instanceof AST_Defun) { fixed._squeezed = true; fixed = make_node(AST_Function, fixed, fixed); fixed.name = make_node(AST_SymbolLambda, fixed.name, fixed.name); } var value; - if (d.recursive_refs > 0) { + if (def.recursive_refs > 0) { value = fixed.clone(true); var defun_def = value.name.definition(); var lambda_def = value.variables.get(value.name.name); @@ -5794,9 +5790,13 @@ merge(Compressor.prototype, { lambda_def = value.def_function(name); } value.walk(new TreeWalker(function(node) { - if (node instanceof AST_SymbolRef && node.definition() === defun_def) { + if (!(node instanceof AST_SymbolRef)) return; + var def = node.definition(); + if (def === defun_def) { node.thedef = lambda_def; lambda_def.references.push(node); + } else { + def.single_use = false; } })); } else { @@ -5805,13 +5805,12 @@ merge(Compressor.prototype, { } return value; } - if (fixed && d.should_replace === undefined) { + if (fixed && def.should_replace === undefined) { var init; if (fixed instanceof AST_This) { - if (!(d.orig[0] instanceof AST_SymbolFunarg) - && all(d.references, function(ref) { - return d.scope === ref.scope; - })) { + if (!(def.orig[0] instanceof AST_SymbolFunarg) && all(def.references, function(ref) { + return def.scope === ref.scope; + })) { init = fixed; } } else { @@ -5835,18 +5834,18 @@ merge(Compressor.prototype, { return result === init || result === fixed ? result.clone(true) : result; }; } - var name_length = d.name.length; + var name_length = def.name.length; var overhead = 0; - if (compressor.option("unused") && !compressor.exposed(d)) { - overhead = (name_length + 2 + value_length) / (d.references.length - d.assignments); + if (compressor.option("unused") && !compressor.exposed(def)) { + overhead = (name_length + 2 + value_length) / (def.references.length - def.assignments); } - d.should_replace = value_length <= name_length + overhead ? fn : false; + def.should_replace = value_length <= name_length + overhead ? fn : false; } else { - d.should_replace = false; + def.should_replace = false; } } - if (d.should_replace) { - return d.should_replace(); + if (def.should_replace) { + return def.should_replace(); } } return self; diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js index dad8ca3b..b040a3f7 100644 --- a/test/compress/reduce_vars.js +++ b/test/compress/reduce_vars.js @@ -5354,6 +5354,7 @@ issue_2774: { issue_2799_1: { options = { + passes: 2, reduce_funcs: true, reduce_vars: true, unused: true, @@ -6429,3 +6430,159 @@ issue_3140_5: { } expect_stdout: "1" } + +issue_3240_1: { + options = { + reduce_funcs: true, + reduce_vars: true, + unused: true, + } + input: { + (function() { + f(1); + function f(a) { + console.log(a); + var g = function() { + f(a - 1); + }; + if (a) g(); + } + })(); + } + expect: { + (function() { + (function f(a) { + console.log(a); + var g = function() { + f(a - 1); + }; + if (a) g(); + })(1); + })(); + } + expect_stdout: [ + "1", + "0", + ] +} + +issue_3240_2: { + options = { + passes: 2, + reduce_funcs: true, + reduce_vars: true, + unused: true, + } + input: { + (function() { + f(1); + function f(a) { + console.log(a); + var g = function() { + f(a - 1); + }; + if (a) g(); + } + })(); + } + expect: { + (function() { + (function f(a) { + console.log(a); + if (a) (function() { + f(a - 1); + })(); + })(1); + })(); + } + expect_stdout: [ + "1", + "0", + ] +} + +issue_3240_3: { + options = { + reduce_funcs: true, + reduce_vars: true, + unused: true, + } + input: { + (function() { + f(); + function f(b) { + if (!f.a) f.a = 0; + console.log(f.a.toString()); + var g = function() { + (b ? function() {} : function() { + f.a++; + f(1); + })(); + }; + g(); + } + })(); + } + expect: { + (function() { + (function f(b) { + if (!f.a) f.a = 0; + console.log(f.a.toString()); + var g = function() { + (b ? function() {} : function() { + f.a++; + f(1); + })(); + }; + g(); + })(); + })(); + } + expect_stdout: [ + "0", + "1", + ] +} + +issue_3240_4: { + options = { + passes: 2, + reduce_funcs: true, + reduce_vars: true, + unused: true, + } + input: { + (function() { + f(); + function f(b) { + if (!f.a) f.a = 0; + console.log(f.a.toString()); + var g = function() { + (b ? function() {} : function() { + f.a++; + f(1); + })(); + }; + g(); + } + })(); + } + expect: { + (function() { + (function f(b) { + if (!f.a) f.a = 0; + console.log(f.a.toString()); + (function() { + (b ? function() {} : function() { + f.a++; + f(1); + })(); + })(); + })(); + })(); + } + expect_stdout: [ + "0", + "1", + ] +} -- 2.34.1