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
This commit is contained in:
142
lib/compress.js
142
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 (def.value) {
|
||||
initializations.add(def.name.name, def.value);
|
||||
if (def.value.has_side_effects(compressor)) {
|
||||
def.value.walk(tw);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user