improve compression of loop conditions (#2543)
authorAlex Lam S.L <alexlamsl@gmail.com>
Thu, 30 Nov 2017 21:52:33 +0000 (05:52 +0800)
committerGitHub <noreply@github.com>
Thu, 30 Nov 2017 21:52:33 +0000 (05:52 +0800)
lib/compress.js
test/compress/dead-code.js
test/compress/issue-1656.js
test/compress/issue-1833.js
test/compress/loops.js
test/compress/reduce_vars.js

index 206c77f..e6215f6 100644 (file)
@@ -3020,34 +3020,40 @@ merge(Compressor.prototype, {
         return self;
     });
 
-    OPT(AST_DWLoop, function(self, compressor){
+    OPT(AST_While, function(self, compressor){
+        return compressor.option("loops") ? make_node(AST_For, self, self).optimize(compressor) : self;
+    });
+
+    OPT(AST_Do, function(self, compressor){
         if (!compressor.option("loops")) return self;
-        var cond = self.condition.evaluate(compressor);
-        if (cond !== self.condition) {
-            if (cond) {
-                return make_node(AST_For, self, {
-                    body: self.body
-                });
-            }
-            if (compressor.option("dead_code") && self instanceof AST_While) {
-                var a = [];
-                extract_declarations_from_unreachable_code(compressor, self.body, a);
-                return make_node(AST_BlockStatement, self, { body: a }).optimize(compressor);
-            }
-            if (self instanceof AST_Do) {
-                var has_loop_control = false;
-                var tw = new TreeWalker(function(node) {
-                    if (node instanceof AST_Scope || has_loop_control) return true;
-                    if (node instanceof AST_LoopControl && tw.loopcontrol_target(node) === self)
-                        return has_loop_control = true;
-                });
-                var parent = compressor.parent();
-                (parent instanceof AST_LabeledStatement ? parent : self).walk(tw);
-                if (!has_loop_control) return self.body;
-            }
-        }
-        if (self instanceof AST_While) {
-            return make_node(AST_For, self, self).optimize(compressor);
+        var cond = self.condition.tail_node().evaluate(compressor);
+        if (!(cond instanceof AST_Node)) {
+            if (cond) return make_node(AST_For, self, {
+                body: make_node(AST_BlockStatement, self.body, {
+                    body: [
+                        self.body,
+                        make_node(AST_SimpleStatement, self.condition, {
+                            body: self.condition
+                        })
+                    ]
+                })
+            }).optimize(compressor);
+            var has_loop_control = false;
+            var tw = new TreeWalker(function(node) {
+                if (node instanceof AST_Scope || has_loop_control) return true;
+                if (node instanceof AST_LoopControl && tw.loopcontrol_target(node) === self)
+                    return has_loop_control = true;
+            });
+            var parent = compressor.parent();
+            (parent instanceof AST_LabeledStatement ? parent : self).walk(tw);
+            if (!has_loop_control) return make_node(AST_BlockStatement, self.body, {
+                body: [
+                    self.body,
+                    make_node(AST_SimpleStatement, self.condition, {
+                        body: self.condition
+                    })
+                ]
+            }).optimize(compressor);
         }
         return self;
     });
@@ -3101,22 +3107,31 @@ merge(Compressor.prototype, {
         if (!compressor.option("loops")) return self;
         if (self.condition) {
             var cond = self.condition.evaluate(compressor);
-            if (compressor.option("dead_code") && !cond) {
-                var a = [];
-                if (self.init instanceof AST_Statement) {
-                    a.push(self.init);
+            if (!(cond instanceof AST_Node)) {
+                if (cond) self.condition = null;
+                else if (!compressor.option("dead_code")) {
+                    var orig = self.condition;
+                    self.condition = make_node_from_constant(cond, self.condition);
+                    self.condition = best_of_expression(self.condition.transform(compressor), orig);
                 }
-                else if (self.init) {
-                    a.push(make_node(AST_SimpleStatement, self.init, {
-                        body: self.init
+            }
+            if (compressor.option("dead_code")) {
+                if (cond instanceof AST_Node) cond = self.condition.tail_node().evaluate(compressor);
+                if (!cond) {
+                    var body = [];
+                    extract_declarations_from_unreachable_code(compressor, self.body, body);
+                    body.push(make_node(AST_SimpleStatement, self.condition, {
+                        body: self.condition
                     }));
+                    if (self.init instanceof AST_Statement) {
+                        body.push(self.init);
+                    } else if (self.init) {
+                        body.push(make_node(AST_SimpleStatement, self.init, {
+                            body: self.init
+                        }));
+                    }
+                    return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor);
                 }
-                extract_declarations_from_unreachable_code(compressor, self.body, a);
-                return make_node(AST_BlockStatement, self, { body: a }).optimize(compressor);
-            }
-            if (cond !== self.condition) {
-                cond = make_node_from_constant(cond, self.condition).transform(compressor);
-                self.condition = best_of_expression(cond, self.condition);
             }
         }
         if_break_in_loop(self, compressor);
index 9e7f489..e0c3039 100644 (file)
@@ -129,8 +129,8 @@ dead_code_constant_boolean_should_warn_more: {
         function bar() {}
         // nothing for the while
         // as for the for, it should keep:
-        var x = 10, y;
         var moo;
+        var x = 10, y;
         bar();
     }
     expect_stdout: true
@@ -165,8 +165,8 @@ dead_code_constant_boolean_should_warn_more_strict: {
         var foo;
         // nothing for the while
         // as for the for, it should keep:
-        var x = 10, y;
         var moo;
+        var x = 10, y;
         bar();
     }
     expect_stdout: true
index 3971cea..27d8765 100644 (file)
@@ -39,7 +39,7 @@ f7: {
         "var b = 10;",
         "",
         "!function() {",
-        "    for (;b = 100, !1; ) ;",
+        "    b = 100;",
         "}(), console.log(100, b);",
     ]
     expect_stdout: true
index 4ffa9d5..e3c385e 100644 (file)
@@ -134,5 +134,5 @@ label_while: {
             L: while (0) continue L;
         }
     }
-    expect_exact: "function f(){L:;}"
+    expect_exact: "function f(){L:0}"
 }
index bac4049..864276a 100644 (file)
@@ -148,9 +148,11 @@ parse_do_while_without_semicolon: {
 
 evaluate: {
     options = {
-        loops: true,
         dead_code: true,
         evaluate: true,
+        loops: true,
+        passes: 2,
+        side_effects: true,
     };
     input: {
         while (true) {
index a8c151f..bcfa7b3 100644 (file)
@@ -1209,6 +1209,7 @@ toplevel_on_loops_2: {
         loops: true,
         reduce_funcs: true,
         reduce_vars: true,
+        side_effects: true,
         toplevel:true,
         unused: true,
     }