speed up `compress` (#5219)
authorAlex Lam S.L <alexlamsl@gmail.com>
Mon, 13 Dec 2021 23:42:47 +0000 (23:42 +0000)
committerGitHub <noreply@github.com>
Mon, 13 Dec 2021 23:42:47 +0000 (07:42 +0800)
lib/compress.js

index b5c67c2..3102d76 100644 (file)
@@ -1818,27 +1818,34 @@ Compressor.prototype.compress = function(node) {
     function tighten_body(statements, compressor) {
         var in_loop, in_try, scope;
         find_loop_scope_try();
-        var CHANGED, max_iter = 10;
+        var changed, last_changed, max_iter = 10;
         do {
-            CHANGED = false;
-            eliminate_spurious_blocks(statements);
+            last_changed = changed;
+            changed = 0;
+            if (eliminate_spurious_blocks(statements)) changed = 1;
+            if (!changed && last_changed == 1) break;
             if (compressor.option("dead_code")) {
-                eliminate_dead_code(statements, compressor);
+                if (eliminate_dead_code(statements, compressor)) changed = 2;
+                if (!changed && last_changed == 2) break;
             }
             if (compressor.option("if_return")) {
-                handle_if_return(statements, compressor);
+                if (handle_if_return(statements, compressor)) changed = 3;
+                if (!changed && last_changed == 3) break;
             }
             if (compressor.sequences_limit > 0) {
-                sequencesize(statements, compressor);
-                sequencesize_2(statements, compressor);
+                if (sequencesize(statements, compressor)) changed = 4;
+                if (!changed && last_changed == 4) break;
+                if (sequencesize_2(statements, compressor)) changed = 5;
+                if (!changed && last_changed == 5) break;
             }
             if (compressor.option("join_vars")) {
-                join_consecutive_vars(statements);
+                if (join_consecutive_vars(statements)) changed = 6;
+                if (!changed && last_changed == 6) break;
             }
             if (compressor.option("collapse_vars")) {
-                collapse(statements, compressor);
+                if (collapse(statements, compressor)) changed = 7;
             }
-        } while (CHANGED && max_iter-- > 0);
+        } while (changed && max_iter-- > 0);
         return statements;
 
         function find_loop_scope_try() {
@@ -1874,10 +1881,11 @@ Compressor.prototype.compress = function(node) {
         // Will not attempt to collapse assignments into or past code blocks
         // which are not sequentially executed, e.g. loops and conditionals.
         function collapse(statements, compressor) {
-            if (scope.pinned()) return statements;
+            if (scope.pinned()) return;
             var args;
             var assignments = new Dictionary();
             var candidates = [];
+            var changed = false;
             var declare_only = new Dictionary();
             var force_single;
             var stat_index = statements.length;
@@ -1924,7 +1932,7 @@ Compressor.prototype.compress = function(node) {
                     } else {
                         replaced++;
                     }
-                    CHANGED = abort = true;
+                    changed = abort = true;
                     AST_Node.info("Collapsing {node} [{file}:{line},{col}]", {
                         node: node,
                         file: node.start.file,
@@ -2137,11 +2145,12 @@ Compressor.prototype.compress = function(node) {
                             && !compressor.exposed(def);
                         value_def.last_ref = false;
                         value_def.single_use = false;
-                        CHANGED = true;
+                        changed = true;
                     }
                     if (replaced && !remove_candidate(candidate)) statements.splice(stat_index, 1);
                 }
             }
+            return changed;
 
             function signal_abort(node) {
                 if (abort) return node;
@@ -3094,12 +3103,12 @@ Compressor.prototype.compress = function(node) {
         }
 
         function eliminate_spurious_blocks(statements) {
-            var seen_dirs = [];
+            var changed = false, seen_dirs = [];
             for (var i = 0; i < statements.length;) {
                 var stat = statements[i];
                 if (stat instanceof AST_BlockStatement) {
                     if (all(stat.body, safe_to_trim)) {
-                        CHANGED = true;
+                        changed = true;
                         eliminate_spurious_blocks(stat.body);
                         [].splice.apply(statements, [i, 1].concat(stat.body));
                         i += stat.body.length;
@@ -3108,22 +3117,24 @@ Compressor.prototype.compress = function(node) {
                 }
                 if (stat instanceof AST_Directive) {
                     if (member(stat.value, seen_dirs)) {
-                        CHANGED = true;
+                        changed = true;
                         statements.splice(i, 1);
                         continue;
                     }
                     seen_dirs.push(stat.value);
                 }
                 if (stat instanceof AST_EmptyStatement) {
-                    CHANGED = true;
+                    changed = true;
                     statements.splice(i, 1);
                     continue;
                 }
                 i++;
             }
+            return changed;
         }
 
         function handle_if_return(statements, compressor) {
+            var changed = false;
             var self = compressor.self();
             var parent = compressor.parent();
             var in_lambda = last_of(function(node) {
@@ -3138,13 +3149,13 @@ Compressor.prototype.compress = function(node) {
 
                 if (in_lambda && !next && stat instanceof AST_Return) {
                     if (!stat.value) {
-                        CHANGED = true;
+                        changed = true;
                         statements.splice(i, 1);
                         continue;
                     }
                     var tail = stat.value.tail_node();
                     if (tail instanceof AST_UnaryPrefix && tail.operator == "void") {
-                        CHANGED = true;
+                        changed = true;
                         var body;
                         if (tail === stat.value) {
                             body = tail.expression;
@@ -3163,7 +3174,7 @@ Compressor.prototype.compress = function(node) {
                     var ab = aborts(stat.body);
                     if (can_merge_flow(ab)) {
                         if (ab.label) remove(ab.label.thedef.references, ab);
-                        CHANGED = true;
+                        changed = true;
                         stat = stat.clone();
                         stat.condition = stat.condition.negate(compressor);
                         var body = as_statement_array_with_return(stat.body, ab);
@@ -3181,7 +3192,7 @@ Compressor.prototype.compress = function(node) {
                     if (ab && !stat.alternative && stat.body instanceof AST_BlockStatement && next instanceof AST_Jump) {
                         var negated = stat.condition.negate(compressor);
                         if (negated.print_to_string().length <= stat.condition.print_to_string().length) {
-                            CHANGED = true;
+                            changed = true;
                             stat = stat.clone();
                             stat.condition = negated;
                             statements[j] = stat.body;
@@ -3195,7 +3206,7 @@ Compressor.prototype.compress = function(node) {
                     var alt = aborts(stat.alternative);
                     if (can_merge_flow(alt)) {
                         if (alt.label) remove(alt.label.thedef.references, alt);
-                        CHANGED = true;
+                        changed = true;
                         stat = stat.clone();
                         stat.body = make_node(AST_BlockStatement, stat.body, {
                             body: as_statement_array(stat.body).concat(extract_functions())
@@ -3231,7 +3242,7 @@ Compressor.prototype.compress = function(node) {
                     // if (foo()) return; return; ---> foo(); return;
                     if (!value && !stat.alternative
                         && (in_lambda && !next || next instanceof AST_Return && !next.value)) {
-                        CHANGED = true;
+                        changed = true;
                         statements[i] = make_node(AST_SimpleStatement, stat.condition, {
                             body: stat.condition
                         });
@@ -3240,7 +3251,7 @@ Compressor.prototype.compress = function(node) {
                     //---
                     // if (foo()) return x; return y; ---> return foo() ? x : y;
                     if (!stat.alternative && next instanceof AST_Return) {
-                        CHANGED = true;
+                        changed = true;
                         stat = stat.clone();
                         stat.alternative = next;
                         statements.splice(i, 1, stat.transform(compressor));
@@ -3250,7 +3261,7 @@ Compressor.prototype.compress = function(node) {
                     //---
                     // if (foo()) return x; [ return ; ] ---> return foo() ? x : undefined;
                     if (!stat.alternative && !next && in_lambda && (in_bool || value && multiple_if_returns)) {
-                        CHANGED = true;
+                        changed = true;
                         stat = stat.clone();
                         stat.alternative = make_node(AST_Return, stat, {
                             value: null
@@ -3268,7 +3279,7 @@ Compressor.prototype.compress = function(node) {
                     if (compressor.option("sequences") && in_lambda && !stat.alternative
                         && (!prev && in_iife || prev instanceof AST_If && prev.body instanceof AST_Return)
                         && next_index(j) == statements.length && next instanceof AST_SimpleStatement) {
-                        CHANGED = true;
+                        changed = true;
                         stat = stat.clone();
                         stat.alternative = make_node(AST_BlockStatement, next, {
                             body: [
@@ -3284,6 +3295,7 @@ Compressor.prototype.compress = function(node) {
                     }
                 }
             }
+            return changed;
 
             function has_multiple_if_returns(statements) {
                 var n = 0;
@@ -3411,7 +3423,7 @@ Compressor.prototype.compress = function(node) {
             if (has_quit) has_quit.forEach(function(stat) {
                 extract_declarations_from_unreachable_code(compressor, stat, statements);
             });
-            CHANGED = statements.length != len;
+            return statements.length != len;
         }
 
         function sequencesize(statements, compressor) {
@@ -3439,7 +3451,7 @@ Compressor.prototype.compress = function(node) {
             }
             push_seq();
             statements.length = n;
-            if (n != len) CHANGED = true;
+            return n != len;
         }
 
         function to_simple_statement(block, decls) {
@@ -3459,13 +3471,7 @@ Compressor.prototype.compress = function(node) {
         }
 
         function sequencesize_2(statements, compressor) {
-            function cons_seq(right) {
-                n--;
-                CHANGED = true;
-                var left = prev.body;
-                return make_sequence(left, [ left, right ]);
-            }
-            var n = 0, prev;
+            var changed = false, n = 0, prev;
             for (var i = 0; i < statements.length; i++) {
                 var stat = statements[i];
                 if (prev) {
@@ -3488,7 +3494,7 @@ Compressor.prototype.compress = function(node) {
                                 else {
                                     stat.init = prev.body;
                                     n--;
-                                    CHANGED = true;
+                                    changed = true;
                                 }
                             }
                         }
@@ -3518,7 +3524,7 @@ Compressor.prototype.compress = function(node) {
                         i += len;
                         n += len + 1;
                         prev = null;
-                        CHANGED = true;
+                        changed = true;
                         continue;
                     }
                 }
@@ -3526,6 +3532,14 @@ Compressor.prototype.compress = function(node) {
                 prev = stat instanceof AST_SimpleStatement ? stat : null;
             }
             statements.length = n;
+            return changed;
+
+            function cons_seq(right) {
+                n--;
+                changed = true;
+                var left = prev.body;
+                return make_sequence(left, [ left, right ]);
+            }
         }
 
         function extract_exprs(body) {
@@ -3680,17 +3694,17 @@ Compressor.prototype.compress = function(node) {
         }
 
         function join_consecutive_vars(statements) {
-            var defs;
+            var changed = false, defs;
             for (var i = 0, j = -1; i < statements.length; i++) {
                 var stat = statements[i];
                 var prev = statements[j];
                 if (stat instanceof AST_Definitions) {
                     if (prev && prev.TYPE == stat.TYPE) {
                         prev.definitions = prev.definitions.concat(stat.definitions);
-                        CHANGED = true;
+                        changed = true;
                     } else if (defs && defs.TYPE == stat.TYPE && declarations_only(stat)) {
                         defs.definitions = defs.definitions.concat(stat.definitions);
-                        CHANGED = true;
+                        changed = true;
                     } else if (stat instanceof AST_Var) {
                         var exprs = merge_assigns(prev, stat);
                         if (exprs) {
@@ -3698,7 +3712,7 @@ Compressor.prototype.compress = function(node) {
                                 prev.body = make_sequence(prev, exprs);
                                 j++;
                             }
-                            CHANGED = true;
+                            changed = true;
                         } else {
                             j++;
                         }
@@ -3712,7 +3726,7 @@ Compressor.prototype.compress = function(node) {
                 } else if (stat instanceof AST_For) {
                     var exprs = join_assigns(prev, stat.init);
                     if (exprs) {
-                        CHANGED = true;
+                        changed = true;
                         stat.init = exprs.length ? make_sequence(stat.init, exprs) : null;
                     } else if (prev instanceof AST_Var && (!stat.init || stat.init.TYPE == prev.TYPE)) {
                         if (stat.init) {
@@ -3720,17 +3734,17 @@ Compressor.prototype.compress = function(node) {
                         }
                         defs = stat.init = prev;
                         statements[j] = merge_defns(stat);
-                        CHANGED = true;
+                        changed = true;
                         continue;
                     } else if (defs && stat.init && defs.TYPE == stat.init.TYPE && declarations_only(stat.init)) {
                         defs.definitions = defs.definitions.concat(stat.init.definitions);
                         stat.init = null;
-                        CHANGED = true;
+                        changed = true;
                     } else if (stat.init instanceof AST_Var) {
                         defs = stat.init;
                         exprs = merge_assigns(prev, stat.init);
                         if (exprs) {
-                            CHANGED = true;
+                            changed = true;
                             if (exprs.length == 0) {
                                 statements[j] = merge_defns(stat);
                                 continue;
@@ -3749,7 +3763,7 @@ Compressor.prototype.compress = function(node) {
                             name.definition().references.push(ref);
                         });
                         defs.definitions = defns;
-                        CHANGED = true;
+                        changed = true;
                     }
                     stat.object = join_assigns_expr(stat.object);
                 } else if (stat instanceof AST_If) {
@@ -3757,7 +3771,7 @@ Compressor.prototype.compress = function(node) {
                 } else if (stat instanceof AST_SimpleStatement) {
                     var exprs = join_assigns(prev, stat.body);
                     if (exprs) {
-                        CHANGED = true;
+                        changed = true;
                         if (!exprs.length) continue;
                         stat.body = make_sequence(stat.body, exprs);
                     }
@@ -3769,11 +3783,12 @@ Compressor.prototype.compress = function(node) {
                 statements[++j] = defs ? merge_defns(stat) : stat;
             }
             statements.length = j + 1;
+            return changed;
 
             function join_assigns_expr(value) {
                 var exprs = join_assigns(prev, value, 1);
                 if (!exprs) return value;
-                CHANGED = true;
+                changed = true;
                 var tail = value.tail_node();
                 if (exprs[exprs.length - 1] !== tail) exprs.push(tail.left);
                 return make_sequence(value, exprs);
@@ -3788,7 +3803,7 @@ Compressor.prototype.compress = function(node) {
                         if (parent instanceof AST_ForEnumeration && parent.init === node) return node;
                         if (!declarations_only(node)) return node;
                         defs.definitions = defs.definitions.concat(node.definitions);
-                        CHANGED = true;
+                        changed = true;
                         if (parent instanceof AST_For && parent.init === node) return null;
                         return in_list ? List.skip : make_node(AST_EmptyStatement, node);
                     }