drop unused assignment based on reduce_vars (#2709)
This commit is contained in:
@@ -311,6 +311,7 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Node, noop);
|
def(AST_Node, noop);
|
||||||
|
|
||||||
function reset_def(compressor, def) {
|
function reset_def(compressor, def) {
|
||||||
|
def.assignments = 0;
|
||||||
def.direct_access = false;
|
def.direct_access = false;
|
||||||
def.escaped = false;
|
def.escaped = false;
|
||||||
if (def.scope.uses_eval || def.scope.uses_with) {
|
if (def.scope.uses_eval || def.scope.uses_with) {
|
||||||
@@ -364,6 +365,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function safe_to_assign(tw, def, value) {
|
function safe_to_assign(tw, def, value) {
|
||||||
|
if (def.fixed === undefined) return true;
|
||||||
if (def.fixed === null && def.safe_ids) {
|
if (def.fixed === null && def.safe_ids) {
|
||||||
def.safe_ids[def.id] = false;
|
def.safe_ids[def.id] = false;
|
||||||
delete def.safe_ids;
|
delete def.safe_ids;
|
||||||
@@ -372,7 +374,7 @@ merge(Compressor.prototype, {
|
|||||||
if (!HOP(tw.safe_ids, def.id)) return false;
|
if (!HOP(tw.safe_ids, def.id)) return false;
|
||||||
if (!safe_to_read(tw, def)) return false;
|
if (!safe_to_read(tw, def)) return false;
|
||||||
if (def.fixed === false) return false;
|
if (def.fixed === false) return false;
|
||||||
if (def.fixed != null && (!value || def.references.length > 0)) return false;
|
if (def.fixed != null && (!value || def.references.length > def.assignments)) return false;
|
||||||
return all(def.orig, function(sym) {
|
return all(def.orig, function(sym) {
|
||||||
return !(sym instanceof AST_SymbolDefun
|
return !(sym instanceof AST_SymbolDefun
|
||||||
|| sym instanceof AST_SymbolLambda);
|
|| sym instanceof AST_SymbolLambda);
|
||||||
@@ -477,6 +479,7 @@ merge(Compressor.prototype, {
|
|||||||
var d = node.left.definition();
|
var d = node.left.definition();
|
||||||
if (safe_to_assign(tw, d, node.right)) {
|
if (safe_to_assign(tw, d, node.right)) {
|
||||||
d.references.push(node.left);
|
d.references.push(node.left);
|
||||||
|
d.assignments++;
|
||||||
d.fixed = function() {
|
d.fixed = function() {
|
||||||
return node.right;
|
return node.right;
|
||||||
};
|
};
|
||||||
@@ -662,7 +665,7 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_VarDef, function(tw, descend) {
|
def(AST_VarDef, function(tw, descend) {
|
||||||
var node = this;
|
var node = this;
|
||||||
var d = node.name.definition();
|
var d = node.name.definition();
|
||||||
if (d.fixed === undefined || safe_to_assign(tw, d, node.value)) {
|
if (safe_to_assign(tw, d, node.value)) {
|
||||||
if (node.value) {
|
if (node.value) {
|
||||||
d.fixed = function() {
|
d.fixed = function() {
|
||||||
return node.value;
|
return node.value;
|
||||||
@@ -2717,6 +2720,7 @@ merge(Compressor.prototype, {
|
|||||||
};
|
};
|
||||||
var in_use = [];
|
var in_use = [];
|
||||||
var in_use_ids = Object.create(null); // avoid expensive linear scans of in_use
|
var in_use_ids = Object.create(null); // avoid expensive linear scans of in_use
|
||||||
|
var fixed_ids = Object.create(null);
|
||||||
if (self instanceof AST_Toplevel && compressor.top_retain) {
|
if (self instanceof AST_Toplevel && compressor.top_retain) {
|
||||||
self.variables.each(function(def) {
|
self.variables.each(function(def) {
|
||||||
if (compressor.top_retain(def) && !(def.id in in_use_ids)) {
|
if (compressor.top_retain(def) && !(def.id in in_use_ids)) {
|
||||||
@@ -2763,6 +2767,9 @@ merge(Compressor.prototype, {
|
|||||||
if (def.value.has_side_effects(compressor)) {
|
if (def.value.has_side_effects(compressor)) {
|
||||||
def.value.walk(tw);
|
def.value.walk(tw);
|
||||||
}
|
}
|
||||||
|
if (def.name.fixed_value() === def.value) {
|
||||||
|
fixed_ids[node_def.id] = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
@@ -2786,12 +2793,16 @@ merge(Compressor.prototype, {
|
|||||||
var parent = tt.parent();
|
var parent = tt.parent();
|
||||||
if (drop_vars) {
|
if (drop_vars) {
|
||||||
var sym = assign_as_unused(node);
|
var sym = assign_as_unused(node);
|
||||||
if (sym instanceof AST_SymbolRef
|
if (sym instanceof AST_SymbolRef) {
|
||||||
&& !(sym.definition().id in in_use_ids)) {
|
var def = sym.definition();
|
||||||
|
var in_use = def.id in in_use_ids;
|
||||||
if (node instanceof AST_Assign) {
|
if (node instanceof AST_Assign) {
|
||||||
return maintain_this_binding(parent, node, node.right.transform(tt));
|
if (!in_use
|
||||||
}
|
|| def.id in fixed_ids
|
||||||
return make_node(AST_Number, node, {
|
&& node.left.fixed_value() !== node.right) {
|
||||||
|
return maintain_this_binding(parent, node, node.right.transform(tt));
|
||||||
|
}
|
||||||
|
} else if (!in_use) return make_node(AST_Number, node, {
|
||||||
value: 0
|
value: 0
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -2851,13 +2862,16 @@ merge(Compressor.prototype, {
|
|||||||
operator: "=",
|
operator: "=",
|
||||||
left: make_node(AST_SymbolRef, def.name, def.name),
|
left: make_node(AST_SymbolRef, def.name, def.name),
|
||||||
right: def.value
|
right: def.value
|
||||||
}));
|
}).transform(tt));
|
||||||
}
|
}
|
||||||
remove(var_defs, def);
|
remove(var_defs, def);
|
||||||
sym.eliminated++;
|
sym.eliminated++;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (def.value && sym.id in fixed_ids && def.name.fixed_value() !== def.value) {
|
||||||
|
def.value = def.value.drop_side_effect_free(compressor);
|
||||||
|
}
|
||||||
if (def.value) {
|
if (def.value) {
|
||||||
if (side_effects.length > 0) {
|
if (side_effects.length > 0) {
|
||||||
if (tail.length > 0) {
|
if (tail.length > 0) {
|
||||||
@@ -2962,14 +2976,19 @@ merge(Compressor.prototype, {
|
|||||||
self.transform(tt);
|
self.transform(tt);
|
||||||
|
|
||||||
function scan_ref_scoped(node, descend) {
|
function scan_ref_scoped(node, descend) {
|
||||||
var sym;
|
var node_def, sym = assign_as_unused(node);
|
||||||
if ((sym = assign_as_unused(node)) instanceof AST_SymbolRef
|
if (sym instanceof AST_SymbolRef
|
||||||
&& self.variables.get(sym.name) === sym.definition()) {
|
&& self.variables.get(sym.name) === (node_def = sym.definition())) {
|
||||||
if (node instanceof AST_Assign) node.right.walk(tw);
|
if (node instanceof AST_Assign) {
|
||||||
|
node.right.walk(tw);
|
||||||
|
if (node.left.fixed_value() === node.right) {
|
||||||
|
fixed_ids[node_def.id] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
var node_def = node.definition();
|
node_def = node.definition();
|
||||||
if (!(node_def.id in in_use_ids)) {
|
if (!(node_def.id in in_use_ids)) {
|
||||||
in_use_ids[node_def.id] = true;
|
in_use_ids[node_def.id] = true;
|
||||||
in_use.push(node_def);
|
in_use.push(node_def);
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
node.references = [];
|
node.references = [];
|
||||||
}
|
}
|
||||||
if (node instanceof AST_SymbolLambda) {
|
if (node instanceof AST_SymbolLambda) {
|
||||||
defun.def_function(node);
|
defun.def_function(node, defun);
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_SymbolDefun) {
|
else if (node instanceof AST_SymbolDefun) {
|
||||||
// Careful here, the scope where this should be defined is
|
// Careful here, the scope where this should be defined is
|
||||||
@@ -318,6 +318,9 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol, init){
|
|||||||
var def = this.variables.get(symbol.name);
|
var def = this.variables.get(symbol.name);
|
||||||
if (def) {
|
if (def) {
|
||||||
def.orig.push(symbol);
|
def.orig.push(symbol);
|
||||||
|
if (def.init && (def.scope !== symbol.scope || def.init instanceof AST_Function)) {
|
||||||
|
def.init = init;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
def = new SymbolDef(this, symbol, init);
|
def = new SymbolDef(this, symbol, init);
|
||||||
this.variables.set(symbol.name, def);
|
this.variables.set(symbol.name, def);
|
||||||
|
|||||||
@@ -1522,3 +1522,125 @@ issue_2665: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "-1"
|
expect_stdout: "-1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double_assign_1: {
|
||||||
|
options = {
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f1() {
|
||||||
|
var a = {};
|
||||||
|
var a = [];
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
function f2() {
|
||||||
|
var a = {};
|
||||||
|
a = [];
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
function f3() {
|
||||||
|
a = {};
|
||||||
|
var a = [];
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
function f4(a) {
|
||||||
|
a = {};
|
||||||
|
a = [];
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
function f5(a) {
|
||||||
|
var a = {};
|
||||||
|
a = [];
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
function f6(a) {
|
||||||
|
a = {};
|
||||||
|
var a = [];
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
console.log(f1(), f2(), f3(), f4(), f5(), f6());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f1() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
function f2() {
|
||||||
|
var a;
|
||||||
|
a = [];
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
function f3() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
function f4(a) {
|
||||||
|
a = [];
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
function f5(a) {
|
||||||
|
a = [];
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
function f6(a) {
|
||||||
|
a = [];
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
console.log(f1(), f2(), f3(), f4(), f5(), f6());
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
double_assign_2: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
for (var i = 0; i < 2; i++)
|
||||||
|
a = void 0, a = {}, console.log(a);
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
for (var i = 0; i < 2; i++)
|
||||||
|
void 0, a = {}, console.log(a);
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double_assign_3: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
for (var i = 0; i < 2; i++)
|
||||||
|
a = void 0, a = { a: a }, console.log(a);
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
for (var i = 0; i < 2; i++)
|
||||||
|
a = void 0, a = { a: a }, console.log(a);
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cascade_drop_assign: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a, b = a = "PASS";
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var b = "PASS";
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -299,7 +299,7 @@ unsafe_evaluate_modified: {
|
|||||||
console.log(function(){ var o={p:1}; o.p++; console.log(o.p); return o.p; }());
|
console.log(function(){ var o={p:1}; o.p++; console.log(o.p); return o.p; }());
|
||||||
console.log(function(){ var o={p:2}; --o.p; console.log(o.p); return o.p; }());
|
console.log(function(){ var o={p:2}; --o.p; console.log(o.p); return o.p; }());
|
||||||
console.log(function(){ var o={p:3}; o.p += ""; console.log(o.p); return o.p; }());
|
console.log(function(){ var o={p:3}; o.p += ""; console.log(o.p); return o.p; }());
|
||||||
console.log(function(){ var o={p:4}; o = {}; console.log(o.p); return o.p; }());
|
console.log(function(){ var o; o = {}; console.log(o.p); return o.p; }());
|
||||||
console.log(function(){ var o={p:5}; o.p = -9; console.log(o.p); return o.p; }());
|
console.log(function(){ var o={p:5}; o.p = -9; console.log(o.p); return o.p; }());
|
||||||
function inc() { this.p++; }
|
function inc() { this.p++; }
|
||||||
console.log(function(){ var o={p:6}; inc.call(o); console.log(o.p); return o.p; }());
|
console.log(function(){ var o={p:6}; inc.call(o); console.log(o.p); return o.p; }());
|
||||||
@@ -5237,3 +5237,42 @@ defun_catch_6: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "42"
|
expect_stdout: "42"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
duplicate_lambda_defun_name_1: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function f(a) {
|
||||||
|
function f() {}
|
||||||
|
return f.length;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function f(a) {
|
||||||
|
function f() {}
|
||||||
|
return f.length;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
duplicate_lambda_defun_name_2: {
|
||||||
|
options = {
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function f(a) {
|
||||||
|
function f() {}
|
||||||
|
return f.length;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a) {
|
||||||
|
return function() {}.length;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "0"
|
||||||
|
}
|
||||||
|
|||||||
@@ -138,3 +138,43 @@ typeof_defun_2: {
|
|||||||
"2",
|
"2",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
duplicate_defun_arg_name: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
typeofs: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function long_name(long_name) {
|
||||||
|
return typeof long_name;
|
||||||
|
}
|
||||||
|
console.log(typeof long_name, long_name());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function long_name(long_name) {
|
||||||
|
return typeof long_name;
|
||||||
|
}
|
||||||
|
console.log(typeof long_name, long_name());
|
||||||
|
}
|
||||||
|
expect_stdout: "function undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
duplicate_lambda_arg_name: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
typeofs: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function long_name(long_name) {
|
||||||
|
return typeof long_name;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function long_name(long_name) {
|
||||||
|
return typeof long_name;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user