From 615ae37ca3a659df2ed304d7d30a43704fdd43ab Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Mon, 18 Mar 2019 21:28:41 +0800 Subject: [PATCH] introduce `assignments` (#3345) --- README.md | 2 ++ lib/compress.js | 34 +++++++++++++++++----- test/compress/asm.js | 1 + test/compress/assignment.js | 53 ++++++++++++++++++++++++++++++++++ test/compress/collapse_vars.js | 2 +- test/compress/conditionals.js | 1 + test/compress/evaluate.js | 35 +++++++++++++++++++++- test/compress/functions.js | 5 ++++ 8 files changed, 124 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 5d6b89b6..1be2d2e8 100644 --- a/README.md +++ b/README.md @@ -605,6 +605,8 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u - `arguments` (default: `true`) -- replace `arguments[index]` with function parameter name whenever possible. +- `assignments` (default: `true`) -- apply optimizations to assignment expressions. + - `booleans` (default: `true`) -- various optimizations for boolean context, for example `!!a ? b : c → a ? b : c` diff --git a/lib/compress.js b/lib/compress.js index 707982d8..a31ce865 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -49,6 +49,7 @@ function Compressor(options, false_by_default) { TreeTransformer.call(this, this.before, this.after); this.options = defaults(options, { arguments : !false_by_default, + assignments : !false_by_default, booleans : !false_by_default, collapse_vars : !false_by_default, comparisons : !false_by_default, @@ -2415,6 +2416,10 @@ merge(Compressor.prototype, { def(AST_Sequence, function(compressor) { return this.tail_node().is_number(compressor); }); + def(AST_SymbolRef, function(compressor) { + var fixed = this.fixed_value(); + return fixed && fixed.is_number(compressor); + }); var unary = makePredicate("+ - ~ ++ --"); def(AST_Unary, function() { return unary[this.operator]; @@ -2426,22 +2431,26 @@ merge(Compressor.prototype, { // methods to determine if an expression has a string result type (function(def) { def(AST_Node, return_false); - def(AST_String, return_true); - def(AST_UnaryPrefix, function() { - return this.operator == "typeof"; + def(AST_Assign, function(compressor) { + return (this.operator == "=" || this.operator == "+=") && this.right.is_string(compressor); }); def(AST_Binary, function(compressor) { return this.operator == "+" && (this.left.is_string(compressor) || this.right.is_string(compressor)); }); - def(AST_Assign, function(compressor) { - return (this.operator == "=" || this.operator == "+=") && this.right.is_string(compressor); + def(AST_Conditional, function(compressor) { + return this.consequent.is_string(compressor) && this.alternative.is_string(compressor); }); def(AST_Sequence, function(compressor) { return this.tail_node().is_string(compressor); }); - def(AST_Conditional, function(compressor) { - return this.consequent.is_string(compressor) && this.alternative.is_string(compressor); + def(AST_String, return_true); + def(AST_SymbolRef, function(compressor) { + var fixed = this.fixed_value(); + return fixed && fixed.is_string(compressor); + }); + def(AST_UnaryPrefix, function() { + return this.operator == "typeof"; }); })(function(node, func) { node.DEFMETHOD("is_string", func); @@ -6010,6 +6019,7 @@ merge(Compressor.prototype, { || parent instanceof AST_Sequence && parent.tail_node() === node); } self = self.lift_sequences(compressor); + if (!compressor.option("assignments")) return self; if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) { // x = expr1 OP expr2 if (self.right.left instanceof AST_SymbolRef @@ -6028,6 +6038,16 @@ merge(Compressor.prototype, { self.right = self.right.left; } } + if ((self.operator == "+=" || self.operator == "-=") + && self.left.is_number(compressor) + && self.right instanceof AST_Number + && self.right.getValue() === 1) { + var op = self.operator.slice(0, -1); + return make_node(AST_UnaryPrefix, self, { + operator: op + op, + expression: self.left + }); + } return self; function in_try(level, node) { diff --git a/test/compress/asm.js b/test/compress/asm.js index d7b1b62b..cebe6838 100644 --- a/test/compress/asm.js +++ b/test/compress/asm.js @@ -1,5 +1,6 @@ asm_mixed: { options = { + assignments: true, booleans: true, comparisons: true, conditionals: true, diff --git a/test/compress/assignment.js b/test/compress/assignment.js index 903380a9..ba412583 100644 --- a/test/compress/assignment.js +++ b/test/compress/assignment.js @@ -1,5 +1,6 @@ op_equals_left_local_var: { options = { + assignments: true, evaluate: true, } input: { @@ -60,6 +61,7 @@ op_equals_left_local_var: { op_equals_right_local_var: { options = { + assignments: true, evaluate: true, } input: { @@ -123,6 +125,7 @@ op_equals_right_local_var: { } op_equals_left_global_var: { options = { + assignments: true, evaluate: true, } input: { @@ -179,6 +182,7 @@ op_equals_left_global_var: { op_equals_right_global_var: { options = { + assignments: true, evaluate: true, } input: { @@ -236,3 +240,52 @@ op_equals_right_global_var: { x = g() & x; } } + +increment_decrement_1: { + options = { + assignments: true, + reduce_vars: true, + } + input: { + console.log(function(a) { + a += 1; + a -= 1; + return a; + }(42)); + } + expect: { + console.log(function(a){ + ++a; + --a; + return a; + }(42)); + } + expect_stdout: "42" +} + +increment_decrement_2: { + options = { + assignments: true, + passes: 2, + reduce_vars: true, + } + input: { + console.log(function(a) { + a = a + 1; + a = a - 1; + a += 1; + a -= 1; + return a; + }(42)); + } + expect: { + console.log(function(a){ + ++a; + --a; + ++a; + --a; + return a; + }(42)); + } + expect_stdout: "42" +} diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js index 6c867123..a858e000 100644 --- a/test/compress/collapse_vars.js +++ b/test/compress/collapse_vars.js @@ -944,7 +944,7 @@ collapse_vars_misc1: { function f5(x) { var z = foo(); return (5 - window.x) / z } function f6() { return window.a * window.z && zap() } function f7() { var b = window.a * window.z; return b + b } - function f8() { var b = window.a * window.z; return b + (b + 5) } + function f8() { var b = window.a * window.z; return b + (5 + b) } function f9() { var b = window.a * window.z; return bar() || b } function f10(x) { var a = 5; return a += 3; } function f11(x) { var a = 5; return a += 2; } diff --git a/test/compress/conditionals.js b/test/compress/conditionals.js index d6d47c41..78c0ca24 100644 --- a/test/compress/conditionals.js +++ b/test/compress/conditionals.js @@ -1367,6 +1367,7 @@ cond_seq_assign_2: { cond_seq_assign_3: { options = { + assignments: true, conditionals: true, } input: { diff --git a/test/compress/evaluate.js b/test/compress/evaluate.js index 23785284..a740cd82 100644 --- a/test/compress/evaluate.js +++ b/test/compress/evaluate.js @@ -1540,7 +1540,7 @@ issue_2926_2: { expect_stdout: "function" } -issue_2968: { +issue_2968_1: { options = { collapse_vars: true, evaluate: true, @@ -1571,6 +1571,39 @@ issue_2968: { expect_stdout: "PASS" } +issue_2968_2: { + options = { + assignments: true, + collapse_vars: true, + evaluate: true, + inline: true, + passes: 2, + reduce_vars: true, + side_effects: true, + unused: true, + } + input: { + var c = "FAIL"; + (function() { + (function(a, b) { + a <<= 0; + a && (a[(c = "PASS", 0 >>> (b += 1))] = 0); + })(42, -42); + })(); + console.log(c); + } + expect: { + var c = "FAIL"; + (function() { + a = 42, + ((a <<= 0) && (a[(c = "PASS", 0)] = 0)); + var a; + })(); + console.log(c); + } + expect_stdout: "PASS" +} + truthy_conditionals: { options = { conditionals: true, diff --git a/test/compress/functions.js b/test/compress/functions.js index 4d243a81..a52796c2 100644 --- a/test/compress/functions.js +++ b/test/compress/functions.js @@ -358,6 +358,7 @@ inner_ref: { issue_2107: { options = { + assignments: true, collapse_vars: true, inline: true, passes: 3, @@ -387,6 +388,7 @@ issue_2107: { issue_2114_1: { options = { + assignments: true, collapse_vars: true, if_return: true, inline: true, @@ -419,6 +421,7 @@ issue_2114_1: { issue_2114_2: { options = { + assignments: true, collapse_vars: true, if_return: true, inline: true, @@ -1223,6 +1226,7 @@ issue_2630_1: { issue_2630_2: { options = { + assignments: true, collapse_vars: true, inline: true, passes: 2, @@ -1320,6 +1324,7 @@ issue_2630_4: { issue_2630_5: { options = { + assignments: true, collapse_vars: true, inline: true, reduce_vars: true, -- 2.34.1