diff options
author | Alex Lam S.L <alexlamsl@gmail.com> | 2017-11-06 14:25:10 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-11-06 14:25:10 +0800 |
commit | 6c4510187066555c77003f03fd26e2cf5ff47491 (patch) | |
tree | 6539b4a00e243ed46b60c6b0387a1ec987a291e0 /lib | |
parent | 2c2fd89e343626f8d7dc83812a6476b0ab99b784 (diff) | |
download | tracifyjs-6c4510187066555c77003f03fd26e2cf5ff47491.tar.gz tracifyjs-6c4510187066555c77003f03fd26e2cf5ff47491.zip |
consolidate & enhance `unused` (#2439)
- defer declaration removal in `collapse_vars`
- account for `AST_SymbolFunarg` in deduplication
- private accounting for `collapse_vars`
- avoid issues with identity reference due to deep cloning
fixes #2437
Diffstat (limited to 'lib')
-rw-r--r-- | lib/compress.js | 142 |
1 files changed, 74 insertions, 68 deletions
diff --git a/lib/compress.js b/lib/compress.js index ba7c10f4..d8482337 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -788,6 +788,14 @@ merge(Compressor.prototype, { || compressor.option("unsafe") && global_names(this.name); }); + function drop_decl(def) { + def._eliminiated = (def._eliminiated || 0) + 1; + if (def.orig.length == def._eliminiated) { + def.scope.functions.del(def.name); + def.scope.variables.del(def.name); + } + } + function tighten_body(statements, compressor) { var CHANGED, max_iter = 10; do { @@ -1000,7 +1008,8 @@ merge(Compressor.prototype, { function get_lhs(expr) { if (expr instanceof AST_VarDef) { var def = expr.name.definition(); - if (def.orig.length > 1 && !(expr.name instanceof AST_SymbolFunarg) + if (def.orig.length - (def._eliminiated || 0) > 1 + && !(expr.name instanceof AST_SymbolFunarg) || def.references.length == 1 && !compressor.exposed(def)) { return make_node(AST_SymbolRef, expr.name, expr.name); } @@ -1009,6 +1018,10 @@ merge(Compressor.prototype, { } } + function get_rvalue(expr) { + return expr[expr instanceof AST_Assign ? "right" : "value"]; + } + function get_lvalues(expr) { var lvalues = Object.create(null); if (expr instanceof AST_Unary) return lvalues; @@ -1019,7 +1032,7 @@ merge(Compressor.prototype, { lvalues[sym.name] = lvalues[sym.name] || is_lhs(node, tw.parent()); } }); - expr[expr instanceof AST_Assign ? "right" : "value"].walk(tw); + get_rvalue(expr).walk(tw); return lvalues; } @@ -1043,7 +1056,9 @@ merge(Compressor.prototype, { if (node === expr) { found = true; if (node instanceof AST_VarDef) { - remove(node.name.definition().orig, node.name); + drop_decl(node.name.definition()); + node.value = null; + return node; } return in_list ? MAP.skip : null; } @@ -1052,16 +1067,13 @@ merge(Compressor.prototype, { case 0: return null; case 1: return node.expressions[0]; } - if (node instanceof AST_Definitions && node.definitions.length == 0 - || node instanceof AST_SimpleStatement && !node.body) { - return null; - } + if (node instanceof AST_SimpleStatement && !node.body) return null; })); } function value_has_side_effects(expr) { if (expr instanceof AST_Unary) return false; - return expr[expr instanceof AST_Assign ? "right" : "value"].has_side_effects(compressor); + return get_rvalue(expr).has_side_effects(compressor); } function references_in_scope(def) { @@ -2303,61 +2315,63 @@ merge(Compressor.prototype, { // this scope (not in nested scopes). var scope = this; var tw = new TreeWalker(function(node, descend){ - if (node !== self) { - if (node instanceof AST_Defun) { - if (!drop_funcs && scope === self) { - var node_def = node.name.definition(); + if (node === self) return; + if (node instanceof AST_Defun) { + if (!drop_funcs && scope === self) { + var node_def = node.name.definition(); + if (!(node_def.id in in_use_ids)) { + in_use_ids[node_def.id] = true; + in_use.push(node_def); + } + } + initializations.add(node.name.name, node); + return true; // don't go in nested scopes + } + if (node instanceof AST_SymbolFunarg && scope === self) { + var_defs_by_id.add(node.definition().id, node); + } + if (node instanceof AST_Definitions && scope === self) { + node.definitions.forEach(function(def){ + var node_def = def.name.definition(); + if (def.name instanceof AST_SymbolVar) { + var_defs_by_id.add(node_def.id, def); + } + if (!drop_vars) { if (!(node_def.id in in_use_ids)) { in_use_ids[node_def.id] = true; in_use.push(node_def); } } - initializations.add(node.name.name, node); - return true; // don't go in nested scopes - } - if (node instanceof AST_Definitions && scope === self) { - node.definitions.forEach(function(def){ - var node_def = def.name.definition(); - if (def.name instanceof AST_SymbolVar) { - var_defs_by_id.add(node_def.id, def); - } - if (!drop_vars) { - if (!(node_def.id in in_use_ids)) { - in_use_ids[node_def.id] = true; - in_use.push(node_def); - } + if (def.value) { + initializations.add(def.name.name, def.value); + if (def.value.has_side_effects(compressor)) { + def.value.walk(tw); } - if (def.value) { - initializations.add(def.name.name, def.value); - if (def.value.has_side_effects(compressor)) { - def.value.walk(tw); - } - } - }); - return true; - } - var sym; - if (scope === self - && (sym = assign_as_unused(node)) instanceof AST_SymbolRef - && self.variables.get(sym.name) === sym.definition()) { - if (node instanceof AST_Assign) node.right.walk(tw); - return true; - } - if (node instanceof AST_SymbolRef) { - var node_def = node.definition(); - if (!(node_def.id in in_use_ids)) { - in_use_ids[node_def.id] = true; - in_use.push(node_def); } - return true; - } - if (node instanceof AST_Scope) { - var save_scope = scope; - scope = node; - descend(); - scope = save_scope; - return true; + }); + return true; + } + var sym; + if (scope === self + && (sym = assign_as_unused(node)) instanceof AST_SymbolRef + && self.variables.get(sym.name) === sym.definition()) { + if (node instanceof AST_Assign) node.right.walk(tw); + return true; + } + if (node instanceof AST_SymbolRef) { + var node_def = node.definition(); + if (!(node_def.id in in_use_ids)) { + in_use_ids[node_def.id] = true; + in_use.push(node_def); } + return true; + } + if (node instanceof AST_Scope) { + var save_scope = scope; + scope = node; + descend(); + scope = save_scope; + return true; } }); self.walk(tw); @@ -2415,7 +2429,7 @@ merge(Compressor.prototype, { var def = node.name.definition(); if (!(def.id in in_use_ids)) { compressor[node.name.unreferenced() ? "warn" : "info"]("Dropping unused function {name} [{file}:{line},{col}]", template(node.name)); - drop_decl(def, node.name); + drop_decl(def); return make_node(AST_EmptyStatement, node); } return node; @@ -2437,7 +2451,7 @@ merge(Compressor.prototype, { if (var_defs.length > 1 && !def.value) { compressor.warn("Dropping duplicated definition of variable {name} [{file}:{line},{col}]", template(def.name)); remove(var_defs, def); - drop_decl(sym, def.name); + drop_decl(sym); return; } } @@ -2470,7 +2484,7 @@ merge(Compressor.prototype, { } else { compressor[def.name.unreferenced() ? "warn" : "info"]("Dropping unused variable {name} [{file}:{line},{col}]", template(def.name)); } - drop_decl(sym, def.name); + drop_decl(sym); } }); if (head.length == 0 && tail.length == 1 && tail[0].name instanceof AST_SymbolVar) { @@ -2479,7 +2493,7 @@ merge(Compressor.prototype, { var def = tail.pop(); compressor.warn("Converting duplicated definition of variable {name} to assignment [{file}:{line},{col}]", template(def.name)); remove(var_defs, def); - drop_decl(def.name.definition(), def.name); + drop_decl(def.name.definition()); side_effects.unshift(make_node(AST_Assign, def, { operator: "=", left: make_node(AST_SymbolRef, def.name, def.name), @@ -2561,14 +2575,6 @@ merge(Compressor.prototype, { col : sym.start.col }; } - - function drop_decl(def, decl) { - remove(def.orig, decl); - if (!def.orig.length) { - def.scope.functions.del(def.name); - def.scope.variables.del(def.name); - } - } } ); self.transform(tt); @@ -3288,7 +3294,7 @@ merge(Compressor.prototype, { })); if (reduce_vars) name.definition().fixed = false; } - remove(def.name.definition().orig, def.name); + drop_decl(def.name.definition()); return a; }, []); if (assignments.length == 0) return null; |