From b0df5d7b5574339982eba310c024350390e7fc0f Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Fri, 7 Jan 2022 21:26:49 +0000 Subject: [PATCH] enhance `collapse_vars` & `reduce_vars` (#5275) fixes #5276 --- lib/compress.js | 56 ++++++++++++++++--------- test/compress/collapse_vars.js | 77 ++++++++++++++++++++++++++++++++-- 2 files changed, 109 insertions(+), 24 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index 2784bbe2..01b1845f 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -674,6 +674,16 @@ Compressor.prototype.compress = function(node) { return node; } + function replace_ref(ref, fixed) { + return function() { + var node = make_ref(ref, fixed); + var def = ref.definition(); + def.references.push(node); + def.replaced++; + return node; + }; + } + function ref_once(compressor, def) { return compressor.option("unused") && !def.scope.pinned() @@ -954,6 +964,7 @@ Compressor.prototype.compress = function(node) { }; left.fixed.assigns = !fixed || !fixed.assigns ? [] : fixed.assigns.slice(); left.fixed.assigns.push(node); + left.fixed.to_binary = replace_ref(left, fixed); } else { left.walk(tw); ld.fixed = false; @@ -1397,7 +1408,7 @@ Compressor.prototype.compress = function(node) { operator: node.operator.slice(0, -1), left: make_node(AST_UnaryPrefix, node, { operator: "+", - expression: make_ref(exp, fixed) + expression: make_ref(exp, fixed), }), right: make_node(AST_Number, node, { value: 1 }), }); @@ -1414,6 +1425,7 @@ Compressor.prototype.compress = function(node) { }); }; exp.fixed.assigns = fixed && fixed.assigns; + exp.fixed.to_prefix = replace_ref(exp, d.fixed); } } else { exp.walk(tw); @@ -1960,6 +1972,7 @@ Compressor.prototype.compress = function(node) { col: node.start.col, }); can_replace = false; + lvalues = get_lvalues(lhs); node.right.transform(scanner); clear_write_only(candidate); var folded; @@ -1967,10 +1980,9 @@ Compressor.prototype.compress = function(node) { folded = candidate; } else { abort = true; - lhs.definition().fixed = false; folded = make_node(AST_Binary, candidate, { operator: compound, - left: lhs, + left: lhs.fixed ? lhs.fixed.to_binary() : lhs, right: rvalue, }); } @@ -2026,10 +2038,10 @@ Compressor.prototype.compress = function(node) { alternative: node, }), }); - if (candidate instanceof AST_UnaryPostfix) { - if (lhs instanceof AST_SymbolRef) lhs.definition().fixed = false; - return make_node(AST_UnaryPrefix, candidate, candidate); - } + if (candidate instanceof AST_UnaryPostfix) return make_node(AST_UnaryPrefix, candidate, { + operator: candidate.operator, + expression: lhs.fixed ? lhs.fixed.to_prefix() : lhs, + }); if (candidate instanceof AST_VarDef) { var def = candidate.name.definition(); if (def.references.length - def.replaced == 1 && !compressor.exposed(def)) { @@ -3086,16 +3098,13 @@ Compressor.prototype.compress = function(node) { var value = rvalue === rhs_value ? null : make_sequence(rhs_value, rhs_value.expressions.slice(0, -1)); var index = expr.name_index; if (index >= 0) { - var argname = scope.argnames[index]; + var args, argname = scope.argnames[index]; if (argname instanceof AST_DefaultValue) { + scope.argnames[index] = argname = argname.clone(); argname.value = value || make_node(AST_Number, argname, { value: 0 }); - argname.name.definition().fixed = false; - } else { - var args = compressor.parent().args; - if (args[index]) { - args[index] = value || make_node(AST_Number, args[index], { value: 0 }); - argname.definition().fixed = false; - } + } else if ((args = compressor.parent().args)[index]) { + scope.argnames[index] = argname.clone(); + args[index] = value || make_node(AST_Number, args[index], { value: 0 }); } return; } @@ -6677,7 +6686,7 @@ Compressor.prototype.compress = function(node) { && indexOf_assign(node.expression.definition(), node) < 0) { return make_node(AST_UnaryPrefix, node, { operator: "+", - expression: node.expression + expression: node.expression, }); } } @@ -11946,22 +11955,29 @@ Compressor.prototype.compress = function(node) { } if (compressor.option("assignments")) { if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) { + var ref; // x = expr1 OP expr2 - if (self.right.left instanceof AST_SymbolRef - && self.right.left.name == self.left.name + if ((ref = self.right.left) instanceof AST_SymbolRef + && ref.name == self.left.name && ASSIGN_OPS[self.right.operator]) { // x = x - 2 ---> x -= 2 + if (self.left.fixed) self.left.fixed.to_binary = function() { + return ref; + }; return make_node(AST_Assign, self, { operator: self.right.operator + "=", left: self.left, right: self.right.right, }); } - if (self.right.right instanceof AST_SymbolRef - && self.right.right.name == self.left.name + if ((ref = self.right.right) instanceof AST_SymbolRef + && ref.name == self.left.name && ASSIGN_OPS_COMMUTATIVE[self.right.operator] && !self.right.left.has_side_effects(compressor)) { // x = 2 & x ---> x &= 2 + if (self.left.fixed) self.left.fixed.to_binary = function() { + return ref; + }; return make_node(AST_Assign, self, { operator: self.right.operator + "=", left: self.left, diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js index e3c6468f..40ba3bb2 100644 --- a/test/compress/collapse_vars.js +++ b/test/compress/collapse_vars.js @@ -3032,6 +3032,54 @@ compound_assignment_6: { expect_stdout: "42" } +compound_assignment_7: { + options = { + assignments: true, + collapse_vars: true, + reduce_vars: true, + toplevel: true, + } + input: { + var a = "FA"; + a = a + "I"; + a = a + "L"; + if (console) + a = "PASS"; + console.log(a); + } + expect: { + var a = "FA"; + a = a + "I" + "L"; + if (console) + a = "PASS"; + console.log(a); + } + expect_stdout: "PASS" +} + +compound_assignment_8: { + options = { + assignments: true, + collapse_vars: true, + reduce_vars: true, + toplevel: true, + } + input: { + var a = 2; + a = 3 * a; + a = 7 * a; + console || (a = "FAIL"); + console.log(a); + } + expect: { + var a = 2; + a = a * 3 * 7; + console || (a = "FAIL"); + console.log(a); + } + expect_stdout: "42" +} + issue_2187_1: { options = { collapse_vars: true, @@ -8285,9 +8333,9 @@ issue_3884_1: { console.log(a, b); } expect: { - var a = 100, b = 1; - b <<= ++a; - console.log(a, b); + var a = 100; + ++a; + console.log(a, 32); } expect_stdout: "101 32" } @@ -9715,9 +9763,30 @@ issue_5273: { function f(c, d) { return d; } - b = (b + a) * a, + b = 1100, f, console.log(b); } expect_stdout: "1100" } + +issue_5276: { + options = { + collapse_vars: true, + pure_getters: "strict", + reduce_vars: true, + toplevel: true, + } + input: { + var a = A = "PASS"; + a.p += null; + a.p -= 42; + console.log(a); + } + expect: { + var a = A = "PASS"; + a.p = a.p + null - 42; + console.log(a); + } + expect_stdout: "PASS" +}