From b29fc8b27c7bf4f48ff354ea2b9d55f7f4b69f79 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Mon, 18 Dec 2017 03:00:05 +0800 Subject: [PATCH] improve transversal efficiency in `collapse_vars` (#2611) fixes #2603 --- lib/compress.js | 61 ++++++++++++++++++++++------------ test/compress/collapse_vars.js | 22 ++++++++++++ 2 files changed, 62 insertions(+), 21 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index bccd7630..52c30964 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -905,10 +905,18 @@ merge(Compressor.prototype, { if (abort) return node; // Scan case expressions first in a switch statement if (node instanceof AST_Switch) { + if (!hit) { + if (node !== hit_stack[hit_index]) return node; + hit_index++; + } node.expression = node.expression.transform(scanner); for (var i = 0, len = node.body.length; !abort && i < len; i++) { var branch = node.body[i]; if (branch instanceof AST_Case) { + if (!hit) { + if (branch !== hit_stack[hit_index]) continue; + hit_index++; + } branch.expression = branch.expression.transform(scanner); if (side_effects || !replace_all) break; } @@ -918,13 +926,13 @@ merge(Compressor.prototype, { } // Skip nodes before `candidate` as quickly as possible if (!hit) { - if (node === candidate) { - hit = true; - stop_after = find_stop(node, 0); - if (stop_after === node) abort = true; - return node; - } - return; + if (node !== hit_stack[hit_index]) return node; + hit_index++; + if (hit_index < hit_stack.length) return; + hit = true; + stop_after = find_stop(node, 0); + if (stop_after === node) abort = true; + return node; } // Stop immediately if these node types are encountered var parent = scanner.parent(); @@ -1013,11 +1021,11 @@ merge(Compressor.prototype, { if (abort) return node; // Skip nodes before `candidate` as quickly as possible if (!hit) { - if (node === candidate) { - hit = true; - return node; - } - return; + if (node !== hit_stack[hit_index]) return node; + hit_index++; + if (hit_index < hit_stack.length) return; + hit = true; + return node; } // Replace variable when found if (node instanceof AST_SymbolRef @@ -1038,9 +1046,12 @@ merge(Compressor.prototype, { // var a = x(), b = undefined; if (stat_index == 0 && compressor.option("unused")) extract_args(); // Find collapsible assignments + var hit_stack = []; extract_candidates(statements[stat_index]); while (candidates.length > 0) { - var candidate = candidates.pop(); + hit_stack = candidates.pop(); + var hit_index = 0; + var candidate = hit_stack[hit_stack.length - 1]; var value_def = null; var stop_after = null; var lhs = get_lhs(candidate); @@ -1074,6 +1085,7 @@ merge(Compressor.prototype, { if (abort && def.references.length - def.replaced > replaced) replaced = false; else { abort = false; + hit_index = 0; hit = funarg; for (var i = stat_index; !abort && i < statements.length; i++) { statements[i].transform(multi_replacer); @@ -1124,18 +1136,24 @@ merge(Compressor.prototype, { }); arg.walk(tw); } - if (arg) candidates.unshift(make_node(AST_VarDef, sym, { + if (arg) candidates.unshift([ make_node(AST_VarDef, sym, { name: sym, value: arg - })); + }) ]); } } } function extract_candidates(expr) { - if (expr instanceof AST_Assign && !expr.left.has_side_effects(compressor) - || expr instanceof AST_Unary && (expr.operator == "++" || expr.operator == "--")) { - candidates.push(expr); + hit_stack.push(expr); + if (expr instanceof AST_Assign) { + if (!expr.left.has_side_effects(compressor)) { + candidates.push(hit_stack.slice()); + } + } else if (expr instanceof AST_Unary) { + if (expr.operator == "++" || expr.operator == "--") { + candidates.push(hit_stack.slice()); + } } else if (expr instanceof AST_Call) { extract_candidates(expr.expression); expr.args.forEach(extract_candidates); @@ -1146,9 +1164,7 @@ merge(Compressor.prototype, { extract_candidates(expr.consequent); extract_candidates(expr.alternative); } else if (expr instanceof AST_Definitions) { - expr.definitions.forEach(function(var_def) { - if (var_def.value) candidates.push(var_def); - }); + expr.definitions.forEach(extract_candidates); } else if (expr instanceof AST_Exit) { if (expr.value) extract_candidates(expr.value); } else if (expr instanceof AST_For) { @@ -1162,7 +1178,10 @@ merge(Compressor.prototype, { } else if (expr instanceof AST_Switch) { extract_candidates(expr.expression); expr.body.forEach(extract_candidates); + } else if (expr instanceof AST_VarDef) { + if (expr.value) candidates.push(hit_stack.slice()); } + hit_stack.pop(); } function find_stop(node, level) { diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js index 1a487981..9a20c559 100644 --- a/test/compress/collapse_vars.js +++ b/test/compress/collapse_vars.js @@ -3990,3 +3990,25 @@ cascade_call: { } } } + +replace_all_var: { + options = { + collapse_vars: true, + unused: true, + } + input: { + var a = "PASS"; + (function() { + var b = b || c && c[a = "FAIL"], c = a; + })(); + console.log(a); + } + expect: { + var a = "PASS"; + (function() { + var b = b || c && c[a = "FAIL"], c = a; + })(); + console.log(a); + } + expect_stdout: "PASS" +} -- 2.34.1