From ecc9f6b77093758d78a693a5ac4b6bcaf75e9a3f Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Tue, 28 Nov 2017 13:08:40 +0800 Subject: [PATCH] drop assignment in `AST_VarDef.value` (#2522) fixes #2516 --- lib/compress.js | 59 ++++++++++++------------- test/compress/collapse_vars.js | 16 ++++--- test/compress/drop-unused.js | 80 ++++++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+), 37 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index 22415f4d..b51fdfc7 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -1088,6 +1088,7 @@ merge(Compressor.prototype, { function get_lhs(expr) { if (expr instanceof AST_VarDef) { var def = expr.name.definition(); + if (!member(expr.name, def.orig)) return; var declared = def.orig.length - def.eliminated; var referenced = def.references.length - def.replaced; if (declared > 1 && !(expr.name instanceof AST_SymbolFunarg) @@ -2434,47 +2435,18 @@ merge(Compressor.prototype, { }); return true; } - var sym; - if (scope === self - && (sym = assign_as_unused(node)) instanceof AST_SymbolRef - && self.variables.get(sym.name) === sym.definition()) { - if (node instanceof AST_Assign) node.right.walk(tw); - return true; - } - if (node instanceof AST_SymbolRef) { - var node_def = node.definition(); - if (!(node_def.id in in_use_ids)) { - in_use_ids[node_def.id] = true; - in_use.push(node_def); - } - return true; - } - if (node instanceof AST_Scope) { - var save_scope = scope; - scope = node; - descend(); - scope = save_scope; - return true; - } + return scan_ref_scoped(node, descend); }); self.walk(tw); // pass 2: for every used symbol we need to walk its // initialization code to figure out if it uses other // symbols (that may not be in_use). + tw = new TreeWalker(scan_ref_scoped); for (var i = 0; i < in_use.length; ++i) { in_use[i].orig.forEach(function(decl){ // undeclared globals will be instanceof AST_SymbolRef var init = initializations.get(decl.name); if (init) init.forEach(function(init){ - var tw = new TreeWalker(function(node){ - if (node instanceof AST_SymbolRef) { - var node_def = node.definition(); - if (!(node_def.id in in_use_ids)) { - in_use_ids[node_def.id] = true; - in_use.push(node_def); - } - } - }); init.walk(tw); }); }); @@ -2663,6 +2635,31 @@ merge(Compressor.prototype, { } ); self.transform(tt); + + function scan_ref_scoped(node, descend) { + var sym; + if (scope === self + && (sym = assign_as_unused(node)) instanceof AST_SymbolRef + && self.variables.get(sym.name) === sym.definition()) { + if (node instanceof AST_Assign) node.right.walk(tw); + return true; + } + if (node instanceof AST_SymbolRef) { + var node_def = node.definition(); + if (!(node_def.id in in_use_ids)) { + in_use_ids[node_def.id] = true; + in_use.push(node_def); + } + return true; + } + if (node instanceof AST_Scope) { + var save_scope = scope; + scope = node; + descend(); + scope = save_scope; + return true; + } + } }); AST_Scope.DEFMETHOD("hoist_declarations", function(compressor){ diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js index 844d5b0f..f968ff20 100644 --- a/test/compress/collapse_vars.js +++ b/test/compress/collapse_vars.js @@ -705,7 +705,7 @@ collapse_vars_lvalues_drop_assign: { function f2(x) { var z = x, a = ++z; return z += a; } function f3(x) { var a = (x -= 3); return x + a; } function f4(x) { var a = (x -= 3); return x + a; } - function f5(x) { e1(); var v = e2(), c = v = --x; return x - c; } + function f5(x) { e1(), e2(); var c = --x; return x - c; } function f6(x) { e1(), e2(); return --x - x; } function f7(x) { e1(); return x - (e2() - x); } function f8(x) { e1(); return x - (e2() - x); } @@ -2386,6 +2386,7 @@ duplicate_argname: { issue_2298: { options = { collapse_vars: true, + passes: 2, reduce_funcs: true, reduce_vars: true, unused: true, @@ -3087,13 +3088,14 @@ issue_2437: { } expect: { !function() { - if (xhrDesc) - return result = !!(req = new XMLHttpRequest()).onreadystatechange, - Object.defineProperty(XMLHttpRequest.prototype, "onreadystatechange", xhrDesc || {}), + if (xhrDesc) { + var result = !!(req = new XMLHttpRequest()).onreadystatechange; + return Object.defineProperty(XMLHttpRequest.prototype, "onreadystatechange", xhrDesc || {}), result; + } var req = new XMLHttpRequest(), detectFunc = function() {}; - req.onreadystatechange = detectFunc; - var result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc; + req.onreadystatechange = detectFunc, + result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc, req.onreadystatechange = null; }(); } @@ -3522,6 +3524,7 @@ issue_2436_12: { issue_2436_13: { options = { collapse_vars: true, + passes: 2, reduce_vars: true, unused: true, } @@ -3622,6 +3625,7 @@ issue_2497: { issue_2506: { options = { collapse_vars: true, + passes: 2, reduce_vars: true, unused: true, } diff --git a/test/compress/drop-unused.js b/test/compress/drop-unused.js index 33241d67..eb6f9df4 100644 --- a/test/compress/drop-unused.js +++ b/test/compress/drop-unused.js @@ -1299,3 +1299,83 @@ issue_2288: { } } } + +issue_2516_1: { + options = { + collapse_vars: true, + reduce_funcs: true, + reduce_vars: true, + unused: true, + } + input: { + function foo() { + function qux(x) { + bar.call(null, x); + } + function bar(x) { + var FOUR = 4; + var trouble = x || never_called(); + var value = (FOUR - 1) * trouble; + console.log(value == 6 ? "PASS" : value); + } + Baz = qux; + } + var Baz; + foo(); + Baz(2); + } + expect: { + function foo() { + Baz = function(x) { + (function(x) { + var trouble = x || never_called(); + var value = (4 - 1) * trouble; + console.log(6 == value ? "PASS" : value); + }).call(null, x); + }; + } + var Baz; + foo(); + Baz(2); + } +} + +issue_2516_2: { + options = { + collapse_vars: true, + reduce_funcs: true, + reduce_vars: true, + passes: 2, + unused: true, + } + input: { + function foo() { + function qux(x) { + bar.call(null, x); + } + function bar(x) { + var FOUR = 4; + var trouble = x || never_called(); + var value = (FOUR - 1) * trouble; + console.log(value == 6 ? "PASS" : value); + } + Baz = qux; + } + var Baz; + foo(); + Baz(2); + } + expect: { + function foo() { + Baz = function(x) { + (function(x) { + var value = (4 - 1) * (x || never_called()); + console.log(6 == value ? "PASS" : value); + }).call(null, x); + }; + } + var Baz; + foo(); + Baz(2); + } +} -- 2.34.1