fix corner cases in assignments, reduce_vars & unused (#3950)
fixes #3949 fixes #3951
This commit is contained in:
106
lib/compress.js
106
lib/compress.js
@@ -384,10 +384,10 @@ merge(Compressor.prototype, {
|
||||
reset_def(tw, compressor, def);
|
||||
if (def.fixed === null) {
|
||||
def.safe_ids = tw.safe_ids;
|
||||
mark(tw, def, true);
|
||||
mark(tw, def);
|
||||
} else if (def.fixed) {
|
||||
tw.loop_ids[def.id] = tw.in_loop;
|
||||
mark(tw, def, true);
|
||||
mark(tw, def);
|
||||
}
|
||||
});
|
||||
scope.may_call_this = function() {
|
||||
@@ -446,8 +446,8 @@ merge(Compressor.prototype, {
|
||||
tw.safe_ids = Object.getPrototypeOf(tw.safe_ids);
|
||||
}
|
||||
|
||||
function mark(tw, def, safe) {
|
||||
tw.safe_ids[def.id] = safe && {};
|
||||
function mark(tw, def) {
|
||||
tw.safe_ids[def.id] = {};
|
||||
}
|
||||
|
||||
function push_ref(def, ref) {
|
||||
@@ -459,10 +459,11 @@ merge(Compressor.prototype, {
|
||||
if (def.single_use == "m") return false;
|
||||
var safe = tw.safe_ids[def.id];
|
||||
if (safe) {
|
||||
if (!HOP(tw.safe_ids, def.id)) safe.read = safe.read ? true : tw.safe_ids;
|
||||
if (!HOP(tw.safe_ids, def.id)) safe.read = safe.read && safe.read !== tw.safe_ids ? true : tw.safe_ids;
|
||||
if (def.fixed == null) {
|
||||
if (is_arguments(def)) return false;
|
||||
if (def.global && def.name == "arguments") return false;
|
||||
tw.loop_ids[def.id] = null;
|
||||
def.fixed = make_node(AST_Undefined, def.orig[0]);
|
||||
return true;
|
||||
}
|
||||
@@ -478,20 +479,23 @@ merge(Compressor.prototype, {
|
||||
delete def.safe_ids;
|
||||
return true;
|
||||
}
|
||||
if (def.fixed === false) return false;
|
||||
var safe = tw.safe_ids[def.id];
|
||||
if (!HOP(tw.safe_ids, def.id)) {
|
||||
if (!safe) return false;
|
||||
safe.assign = safe.assign ? true : tw.safe_ids;
|
||||
if (safe.read && def.scope !== tw.find_parent(AST_Scope)) return false;
|
||||
safe.assign = safe.assign && safe.assign !== tw.safe_ids ? true : tw.safe_ids;
|
||||
}
|
||||
if (!safe_to_read(tw, def)) return false;
|
||||
if (def.fixed === false) return false;
|
||||
if (def.fixed != null && safe.read && safe.read !== tw.safe_ids) return false;
|
||||
return all(def.orig, function(sym) {
|
||||
if (def.fixed != null && safe.read) {
|
||||
if (safe.read !== tw.safe_ids) return false;
|
||||
if (tw.loop_ids[def.id] !== tw.in_loop) return false;
|
||||
}
|
||||
return safe_to_read(tw, def) && all(def.orig, function(sym) {
|
||||
return !(sym instanceof AST_SymbolLambda);
|
||||
});
|
||||
}
|
||||
|
||||
function ref_once(tw, compressor, def) {
|
||||
function ref_once(compressor, def) {
|
||||
return compressor.option("unused")
|
||||
&& !def.scope.pinned()
|
||||
&& def.references.length - def.recursive_refs == 1;
|
||||
@@ -568,22 +572,17 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
var d = sym.definition();
|
||||
d.assignments++;
|
||||
var fixed = d.fixed;
|
||||
var eq = node.operator == "=";
|
||||
var value = eq ? node.right : node;
|
||||
if (is_modified(compressor, tw, node, value, 0)) return;
|
||||
var safe = (eq || safe_to_read(tw, d)) && safe_to_assign(tw, d);
|
||||
var fixed = d.fixed;
|
||||
if (safe) {
|
||||
node.right.walk(tw);
|
||||
if ((eq || safe_to_read(tw, d)) && safe_to_assign(tw, d)) {
|
||||
push_ref(d, sym);
|
||||
mark(tw, d, false);
|
||||
node.right.walk(tw);
|
||||
mark(tw, d, true);
|
||||
if (eq) mark_escaped(tw, d, sym.scope, node, value, 0, 1);
|
||||
} else {
|
||||
descend();
|
||||
}
|
||||
if (fixed !== false && d.fixed !== false) {
|
||||
mark(tw, d);
|
||||
if (eq) {
|
||||
tw.loop_ids[d.id] = tw.in_loop;
|
||||
mark_escaped(tw, d, sym.scope, node, value, 0, 1);
|
||||
sym.fixed = d.fixed = function() {
|
||||
return node.right;
|
||||
};
|
||||
@@ -600,6 +599,9 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
sym.fixed.assigns = eq || !fixed.assigns ? [] : fixed.assigns.slice();
|
||||
sym.fixed.assigns.push(node);
|
||||
} else {
|
||||
sym.walk(tw);
|
||||
d.fixed = false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
@@ -739,7 +741,7 @@ merge(Compressor.prototype, {
|
||||
var d = arg.definition();
|
||||
if (d.fixed === undefined && (!fn.uses_arguments || tw.has_directive("use strict"))) {
|
||||
tw.loop_ids[d.id] = tw.in_loop;
|
||||
mark(tw, d, true);
|
||||
mark(tw, d);
|
||||
var value = iife.args[i];
|
||||
d.fixed = function() {
|
||||
var j = fn.argnames.indexOf(arg);
|
||||
@@ -800,7 +802,7 @@ merge(Compressor.prototype, {
|
||||
var recursive = recursive_ref(tw, d);
|
||||
if (recursive) {
|
||||
d.recursive_refs++;
|
||||
} else if (value && ref_once(tw, compressor, d)) {
|
||||
} else if (value && ref_once(compressor, d)) {
|
||||
d.in_loop = tw.loop_ids[d.id] !== tw.in_loop;
|
||||
d.single_use = value instanceof AST_Lambda
|
||||
&& !value.pinned()
|
||||
@@ -864,15 +866,10 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
var d = exp.definition();
|
||||
d.assignments++;
|
||||
var safe = safe_to_read(tw, d) && safe_to_assign(tw, d);
|
||||
var fixed = d.fixed;
|
||||
if (safe) {
|
||||
if (safe_to_read(tw, d) && safe_to_assign(tw, d)) {
|
||||
push_ref(d, exp);
|
||||
mark(tw, d, true);
|
||||
} else {
|
||||
descend();
|
||||
}
|
||||
if (fixed !== false && d.fixed !== false) {
|
||||
mark(tw, d);
|
||||
if (fixed == null) fixed = make_node(AST_Undefined, d.orig[0]);
|
||||
d.fixed = function() {
|
||||
var value = fixed instanceof AST_Node ? fixed : fixed();
|
||||
@@ -901,29 +898,28 @@ merge(Compressor.prototype, {
|
||||
};
|
||||
exp.fixed.assigns = fixed.assigns;
|
||||
}
|
||||
} else {
|
||||
exp.walk(tw);
|
||||
d.fixed = false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
def(AST_VarDef, function(tw, descend) {
|
||||
var node = this;
|
||||
if (!node.value) return;
|
||||
descend();
|
||||
var d = node.name.definition();
|
||||
if (node.value) {
|
||||
if (safe_to_assign(tw, d)) {
|
||||
tw.loop_ids[d.id] = tw.in_loop;
|
||||
mark(tw, d, false);
|
||||
descend();
|
||||
mark(tw, d, true);
|
||||
if (d.fixed !== false) {
|
||||
d.fixed = function() {
|
||||
return node.value;
|
||||
};
|
||||
d.fixed.assigns = [ node ];
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
d.fixed = false;
|
||||
}
|
||||
if (safe_to_assign(tw, d)) {
|
||||
mark(tw, d);
|
||||
tw.loop_ids[d.id] = tw.in_loop;
|
||||
d.fixed = function() {
|
||||
return node.value;
|
||||
};
|
||||
d.fixed.assigns = [ node ];
|
||||
} else {
|
||||
d.fixed = false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
def(AST_While, function(tw, descend) {
|
||||
var saved_loop = tw.in_loop;
|
||||
@@ -4710,7 +4706,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
}
|
||||
}
|
||||
track_assigns(node_def, sym);
|
||||
if (track_assigns(node_def, sym) && is_lhs(sym, node) !== sym) add_assigns(node_def, sym);
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_SymbolRef) {
|
||||
@@ -7885,16 +7881,22 @@ merge(Compressor.prototype, {
|
||||
&& self.right.left.name == self.left.name
|
||||
&& ASSIGN_OPS[self.right.operator]) {
|
||||
// x = x - 2 => x -= 2
|
||||
self.operator = self.right.operator + "=";
|
||||
self.right = self.right.right;
|
||||
return make_node(AST_Assign, self, {
|
||||
operator: self.right.operator + "=",
|
||||
left: self.left,
|
||||
right: self.right.right,
|
||||
}).optimize(compressor);
|
||||
}
|
||||
else if (self.right.right instanceof AST_SymbolRef
|
||||
&& self.right.right.name == self.left.name
|
||||
&& ASSIGN_OPS_COMMUTATIVE[self.right.operator]
|
||||
&& !self.right.left.has_side_effects(compressor)) {
|
||||
// x = 2 & x => x &= 2
|
||||
self.operator = self.right.operator + "=";
|
||||
self.right = self.right.left;
|
||||
return make_node(AST_Assign, self, {
|
||||
operator: self.right.operator + "=",
|
||||
left: self.left,
|
||||
right: self.right.left,
|
||||
}).optimize(compressor);
|
||||
}
|
||||
}
|
||||
if ((self.operator == "-=" || self.operator == "+="
|
||||
|
||||
Reference in New Issue
Block a user