simplify optimisation loops

This commit is contained in:
alexlamsl 2017-03-12 16:55:24 +08:00
parent 7550c53fd6
commit 06f17bd0ec
2 changed files with 119 additions and 112 deletions

View File

@ -984,8 +984,8 @@ TreeWalker.prototype = {
push: function (node) { push: function (node) {
if (node instanceof AST_Lambda) { if (node instanceof AST_Lambda) {
this.directives = Object.create(this.directives); this.directives = Object.create(this.directives);
} else if (node instanceof AST_Directive) { } else if (node instanceof AST_Directive && !this.directives[node.value]) {
this.directives[node.value] = this.directives[node.value] ? "up" : true; this.directives[node.value] = node;
} }
this.stack.push(node); this.stack.push(node);
}, },
@ -1013,7 +1013,7 @@ TreeWalker.prototype = {
for (var i = 0; i < node.body.length; ++i) { for (var i = 0; i < node.body.length; ++i) {
var st = node.body[i]; var st = node.body[i];
if (!(st instanceof AST_Directive)) break; if (!(st instanceof AST_Directive)) break;
if (st.value == type) return true; if (st.value == type) return st;
} }
} }
}, },

View File

@ -121,8 +121,8 @@ merge(Compressor.prototype, {
node = node.process_expression(true); node = node.process_expression(true);
} }
var passes = +this.options.passes || 1; var passes = +this.options.passes || 1;
for (var pass = 0; pass < passes && pass < 3; ++pass) { for (var pass = 0; pass < passes; ++pass) {
if (pass > 0 || this.option("reduce_vars")) if (this.option("reduce_vars"))
node.reset_opt_flags(this, true); node.reset_opt_flags(this, true);
node = node.transform(this); node = node.transform(this);
} }
@ -145,7 +145,6 @@ merge(Compressor.prototype, {
this.warnings_produced = {}; this.warnings_produced = {};
}, },
before: function(node, descend, in_list) { before: function(node, descend, in_list) {
if (node._squeezed) return node;
var was_scope = false; var was_scope = false;
if (node instanceof AST_Scope) { if (node instanceof AST_Scope) {
node = node.hoist_declarations(this); node = node.hoist_declarations(this);
@ -157,7 +156,6 @@ merge(Compressor.prototype, {
node.drop_unused(this); node.drop_unused(this);
descend(node, this); descend(node, this);
} }
node._squeezed = true;
return node; return node;
} }
}); });
@ -167,12 +165,9 @@ merge(Compressor.prototype, {
function OPT(node, optimizer) { function OPT(node, optimizer) {
node.DEFMETHOD("optimize", function(compressor){ node.DEFMETHOD("optimize", function(compressor){
var self = this; var self = this;
if (self._optimized) return self;
if (compressor.has_directive("use asm")) return self; if (compressor.has_directive("use asm")) return self;
var opt = optimizer(self, compressor); var opt = optimizer(self, compressor);
opt._optimized = true; return opt;
if (opt === self) return opt;
return opt.transform(compressor);
}); });
}; };
@ -235,10 +230,6 @@ merge(Compressor.prototype, {
} }
}); });
var tw = new TreeWalker(function(node, descend){ var tw = new TreeWalker(function(node, descend){
if (!(node instanceof AST_Directive || node instanceof AST_Constant)) {
node._squeezed = false;
node._optimized = false;
}
if (reduce_vars) { if (reduce_vars) {
if (node instanceof AST_Toplevel) node.globals.each(reset_def); if (node instanceof AST_Toplevel) node.globals.each(reset_def);
if (node instanceof AST_Scope) node.variables.each(reset_def); if (node instanceof AST_Scope) node.variables.each(reset_def);
@ -424,15 +415,17 @@ merge(Compressor.prototype, {
// func(something) because that changes the meaning of // func(something) because that changes the meaning of
// the func (becomes lexical instead of global). // the func (becomes lexical instead of global).
function maintain_this_binding(parent, orig, val) { function maintain_this_binding(parent, orig, val) {
if (parent instanceof AST_Call && parent.expression === orig) { if (parent instanceof AST_Call && parent.expression === orig
if (val instanceof AST_PropAccess || val instanceof AST_SymbolRef && val.name === "eval") { && (val instanceof AST_PropAccess
return make_node(AST_Seq, orig, { || val instanceof AST_SymbolRef && val.name === "eval")) {
car: make_node(AST_Number, orig, { return orig instanceof AST_Seq
value: 0 && orig.car instanceof AST_Number
}), && orig.car.value == 0 ? orig : make_node(AST_Seq, orig, {
cdr: val car: make_node(AST_Number, orig, {
}); value: 0
} }),
cdr: val
});
} }
return val; return val;
} }
@ -649,8 +642,6 @@ merge(Compressor.prototype, {
statements[prev_stat_index] = make_node(AST_EmptyStatement, self); statements[prev_stat_index] = make_node(AST_EmptyStatement, self);
var_defs_removed = true; var_defs_removed = true;
} }
// Further optimize statement after substitution.
stat.reset_opt_flags(compressor);
compressor.warn("Collapsing " + (is_constant ? "constant" : "variable") + compressor.warn("Collapsing " + (is_constant ? "constant" : "variable") +
" " + var_name + " [{file}:{line},{col}]", node.start); " " + var_name + " [{file}:{line},{col}]", node.start);
@ -817,7 +808,7 @@ merge(Compressor.prototype, {
body: body body: body
}); });
stat.alternative = null; stat.alternative = null;
ret = funs.concat([ stat.transform(compressor) ]); ret = funs.concat([ stat ]);
continue loop; continue loop;
} }
@ -834,7 +825,7 @@ merge(Compressor.prototype, {
CHANGED = true; CHANGED = true;
ret.push(make_node(AST_Return, ret[0], { ret.push(make_node(AST_Return, ret[0], {
value: null value: null
}).transform(compressor)); }));
ret.unshift(stat); ret.unshift(stat);
continue loop; continue loop;
} }
@ -858,7 +849,7 @@ merge(Compressor.prototype, {
stat.alternative = make_node(AST_BlockStatement, stat, { stat.alternative = make_node(AST_BlockStatement, stat, {
body: body body: body
}); });
ret = [ stat.transform(compressor) ]; ret = [ stat ];
continue loop; continue loop;
} }
@ -878,7 +869,7 @@ merge(Compressor.prototype, {
stat.alternative = make_node(AST_BlockStatement, stat.alternative, { stat.alternative = make_node(AST_BlockStatement, stat.alternative, {
body: as_statement_array(stat.alternative).slice(0, -1) body: as_statement_array(stat.alternative).slice(0, -1)
}); });
ret = [ stat.transform(compressor) ]; ret = [ stat ];
continue loop; continue loop;
} }
@ -982,7 +973,7 @@ merge(Compressor.prototype, {
} else { } else {
left = AST_Seq.cons(left, right); left = AST_Seq.cons(left, right);
} }
return left.transform(compressor); return left;
}; };
var ret = [], prev = null; var ret = [], prev = null;
statements.forEach(function(stat){ statements.forEach(function(stat){
@ -1261,6 +1252,14 @@ merge(Compressor.prototype, {
return (first_in_statement(compressor) ? best_of_statement : best_of_expression)(ast1, ast2); return (first_in_statement(compressor) ? best_of_statement : best_of_expression)(ast1, ast2);
} }
function best_of_constant(compressor, ev, ast) {
var self = compressor.self();
compressor.pop();
ev = ev.transform(compressor);
compressor.push(self);
return best_of(compressor, ev, ast);
}
// methods to evaluate a constant expression // methods to evaluate a constant expression
(function (def){ (function (def){
// The evaluate method returns an array with one or two // The evaluate method returns an array with one or two
@ -1289,8 +1288,8 @@ merge(Compressor.prototype, {
}); });
AST_Node.DEFMETHOD("evaluate_self", function(compressor){ AST_Node.DEFMETHOD("evaluate_self", function(compressor){
var ev = this.evaluate(compressor); var ev = this.evaluate(compressor);
if (ev.length > 1 && !ev[0].equivalent_to(this)) { if (ev.length > 1) {
return best_of(compressor, ev[0].optimize(compressor), this); return best_of_constant(compressor, ev[0], this);
} }
return this; return this;
}); });
@ -1675,7 +1674,7 @@ merge(Compressor.prototype, {
/* -----[ optimizers ]----- */ /* -----[ optimizers ]----- */
OPT(AST_Directive, function(self, compressor){ OPT(AST_Directive, function(self, compressor){
if (compressor.has_directive(self.value) === "up") { if (compressor.has_directive(self.value) !== self) {
return make_node(AST_EmptyStatement, self); return make_node(AST_EmptyStatement, self);
} }
return self; return self;
@ -2120,9 +2119,12 @@ merge(Compressor.prototype, {
if (!this.has_pure_annotation(compressor) && compressor.pure_funcs(this)) { if (!this.has_pure_annotation(compressor) && compressor.pure_funcs(this)) {
if (this.expression instanceof AST_Function if (this.expression instanceof AST_Function
&& (!this.expression.name || !this.expression.name.definition().references.length)) { && (!this.expression.name || !this.expression.name.definition().references.length)) {
var node = this.clone(); var expression = this.expression.process_expression(false);
node.expression = node.expression.process_expression(false); if (!this.expression.equivalent_to(expression)) {
return node; var node = this.clone();
node.expression = expression;
return node;
}
} }
return this; return this;
} }
@ -2140,6 +2142,7 @@ merge(Compressor.prototype, {
switch (this.operator) { switch (this.operator) {
case "&&": case "&&":
case "||": case "||":
if (right === this.right) return this;
var node = this.clone(); var node = this.clone();
node.right = right; node.right = right;
return node; return node;
@ -2254,7 +2257,7 @@ merge(Compressor.prototype, {
OPT(AST_DWLoop, function(self, compressor){ OPT(AST_DWLoop, function(self, compressor){
var cond = self.condition.evaluate(compressor); var cond = self.condition.evaluate(compressor);
if (cond.length > 1) { if (cond.length > 1) {
self.condition = best_of_expression(cond[0].transform(compressor), self.condition); self.condition = best_of_constant(compressor, cond[0], self.condition);
} }
if (!compressor.option("loops")) return self; if (!compressor.option("loops")) return self;
if (cond.length > 1) { if (cond.length > 1) {
@ -2274,7 +2277,7 @@ merge(Compressor.prototype, {
} }
} }
if (self instanceof AST_While) { if (self instanceof AST_While) {
return make_node(AST_For, self, self).optimize(compressor); return make_node(AST_For, self, self);
} }
return self; return self;
}); });
@ -2285,11 +2288,10 @@ merge(Compressor.prototype, {
if (self.body instanceof AST_BlockStatement) { if (self.body instanceof AST_BlockStatement) {
self.body = self.body.clone(); self.body = self.body.clone();
self.body.body = rest.concat(self.body.body.slice(1)); self.body.body = rest.concat(self.body.body.slice(1));
self.body = self.body.transform(compressor);
} else { } else {
self.body = make_node(AST_BlockStatement, self.body, { self.body = make_node(AST_BlockStatement, self.body, {
body: rest body: rest
}).transform(compressor); });
} }
if_break_in_loop(self, compressor); if_break_in_loop(self, compressor);
} }
@ -2329,7 +2331,7 @@ merge(Compressor.prototype, {
if (cond) { if (cond) {
cond = cond.evaluate(compressor); cond = cond.evaluate(compressor);
if (cond.length > 1) { if (cond.length > 1) {
self.condition = best_of_expression(cond[0].transform(compressor), self.condition); self.condition = best_of_constant(compressor, cond[0], self.condition);
} }
} }
if (!compressor.option("loops")) return self; if (!compressor.option("loops")) return self;
@ -2372,7 +2374,7 @@ merge(Compressor.prototype, {
extract_declarations_from_unreachable_code(compressor, self.alternative, a); extract_declarations_from_unreachable_code(compressor, self.alternative, a);
} }
a.push(self.body); a.push(self.body);
return make_node(AST_BlockStatement, self, { body: a }).optimize(compressor); return make_node(AST_BlockStatement, self, { body: a });
} }
} else { } else {
compressor.warn("Condition always false [{file}:{line},{col}]", self.condition.start); compressor.warn("Condition always false [{file}:{line},{col}]", self.condition.start);
@ -2380,10 +2382,10 @@ merge(Compressor.prototype, {
var a = []; var a = [];
extract_declarations_from_unreachable_code(compressor, self.body, a); extract_declarations_from_unreachable_code(compressor, self.body, a);
if (self.alternative) a.push(self.alternative); if (self.alternative) a.push(self.alternative);
return make_node(AST_BlockStatement, self, { body: a }).optimize(compressor); return make_node(AST_BlockStatement, self, { body: a });
} }
} }
self.condition = best_of_expression(cond[0].transform(compressor), self.condition); self.condition = best_of_constant(compressor, cond[0], self.condition);
} }
var negated = self.condition.negate(compressor); var negated = self.condition.negate(compressor);
var self_condition_length = self.condition.print_to_string().length; var self_condition_length = self.condition.print_to_string().length;
@ -2401,7 +2403,7 @@ merge(Compressor.prototype, {
if (is_empty(self.body) && is_empty(self.alternative)) { if (is_empty(self.body) && is_empty(self.alternative)) {
return make_node(AST_SimpleStatement, self.condition, { return make_node(AST_SimpleStatement, self.condition, {
body: self.condition body: self.condition
}).optimize(compressor); });
} }
if (self.body instanceof AST_SimpleStatement if (self.body instanceof AST_SimpleStatement
&& self.alternative instanceof AST_SimpleStatement) { && self.alternative instanceof AST_SimpleStatement) {
@ -2411,7 +2413,7 @@ merge(Compressor.prototype, {
consequent : statement_to_expression(self.body), consequent : statement_to_expression(self.body),
alternative : statement_to_expression(self.alternative) alternative : statement_to_expression(self.alternative)
}) })
}).optimize(compressor); });
} }
if (is_empty(self.alternative) && self.body instanceof AST_SimpleStatement) { if (is_empty(self.alternative) && self.body instanceof AST_SimpleStatement) {
if (self_condition_length === negated_length && !negated_is_best if (self_condition_length === negated_length && !negated_is_best
@ -2427,14 +2429,14 @@ merge(Compressor.prototype, {
left : negated, left : negated,
right : statement_to_expression(self.body) right : statement_to_expression(self.body)
}) })
}).optimize(compressor); });
return make_node(AST_SimpleStatement, self, { return make_node(AST_SimpleStatement, self, {
body: make_node(AST_Binary, self, { body: make_node(AST_Binary, self, {
operator : "&&", operator : "&&",
left : self.condition, left : self.condition,
right : statement_to_expression(self.body) right : statement_to_expression(self.body)
}) })
}).optimize(compressor); });
} }
if (self.body instanceof AST_EmptyStatement if (self.body instanceof AST_EmptyStatement
&& self.alternative && self.alternative
@ -2445,7 +2447,7 @@ merge(Compressor.prototype, {
left : self.condition, left : self.condition,
right : statement_to_expression(self.alternative) right : statement_to_expression(self.alternative)
}) })
}).optimize(compressor); });
} }
if (self.body instanceof AST_Exit if (self.body instanceof AST_Exit
&& self.alternative instanceof AST_Exit && self.alternative instanceof AST_Exit
@ -2456,7 +2458,7 @@ merge(Compressor.prototype, {
consequent : self.body.value || make_node(AST_Undefined, self.body), consequent : self.body.value || make_node(AST_Undefined, self.body),
alternative : self.alternative.value || make_node(AST_Undefined, self.alternative) alternative : self.alternative.value || make_node(AST_Undefined, self.alternative)
}) })
}).optimize(compressor); });
} }
if (self.body instanceof AST_If if (self.body instanceof AST_If
&& !self.body.alternative && !self.body.alternative
@ -2465,7 +2467,7 @@ merge(Compressor.prototype, {
operator: "&&", operator: "&&",
left: self.condition, left: self.condition,
right: self.body.condition right: self.body.condition
}).transform(compressor); });
self.body = self.body.body; self.body = self.body.body;
} }
if (aborts(self.body)) { if (aborts(self.body)) {
@ -2474,7 +2476,7 @@ merge(Compressor.prototype, {
self.alternative = null; self.alternative = null;
return make_node(AST_BlockStatement, self, { return make_node(AST_BlockStatement, self, {
body: [ self, alt ] body: [ self, alt ]
}).optimize(compressor); });
} }
} }
if (aborts(self.alternative)) { if (aborts(self.alternative)) {
@ -2484,7 +2486,7 @@ merge(Compressor.prototype, {
self.alternative = null; self.alternative = null;
return make_node(AST_BlockStatement, self, { return make_node(AST_BlockStatement, self, {
body: [ self, body ] body: [ self, body ]
}).optimize(compressor); });
} }
return self; return self;
}); });
@ -2493,7 +2495,7 @@ merge(Compressor.prototype, {
if (self.body.length == 0 && compressor.option("conditionals")) { if (self.body.length == 0 && compressor.option("conditionals")) {
return make_node(AST_SimpleStatement, self, { return make_node(AST_SimpleStatement, self, {
body: self.expression body: self.expression
}).optimize(compressor); });
} }
for(;;) { for(;;) {
var last_branch = self.body[self.body.length - 1]; var last_branch = self.body[self.body.length - 1];
@ -2511,7 +2513,7 @@ merge(Compressor.prototype, {
var exp = self.expression.evaluate(compressor); var exp = self.expression.evaluate(compressor);
out: if (exp.length == 2) try { out: if (exp.length == 2) try {
// constant expression // constant expression
self.expression = best_of_expression(exp[0].transform(compressor), self.expression); self.expression = best_of_constant(compressor, exp[0], self.expression);
if (!compressor.option("dead_code")) break out; if (!compressor.option("dead_code")) break out;
var value = exp[1]; var value = exp[1];
var in_if = false; var in_if = false;
@ -2531,7 +2533,7 @@ merge(Compressor.prototype, {
body: node.body.reduce(function(a, branch){ body: node.body.reduce(function(a, branch){
return a.concat(branch.body); return a.concat(branch.body);
}, []) }, [])
}).optimize(compressor); });
} }
else if (node instanceof AST_If || node instanceof AST_Try) { else if (node instanceof AST_If || node instanceof AST_Try) {
var save = in_if; var save = in_if;
@ -2671,7 +2673,7 @@ merge(Compressor.prototype, {
if (self.args.length != 1) { if (self.args.length != 1) {
return make_node(AST_Array, self, { return make_node(AST_Array, self, {
elements: self.args elements: self.args
}).optimize(compressor); });
} }
break; break;
case "Object": case "Object":
@ -2689,7 +2691,7 @@ merge(Compressor.prototype, {
left: self.args[0], left: self.args[0],
operator: "+", operator: "+",
right: make_node(AST_String, self, { value: "" }) right: make_node(AST_String, self, { value: "" })
}).optimize(compressor); });
break; break;
case "Number": case "Number":
if (self.args.length == 0) return make_node(AST_Number, self, { if (self.args.length == 0) return make_node(AST_Number, self, {
@ -2698,7 +2700,7 @@ merge(Compressor.prototype, {
if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, { if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, {
expression: self.args[0], expression: self.args[0],
operator: "+" operator: "+"
}).optimize(compressor); });
case "Boolean": case "Boolean":
if (self.args.length == 0) return make_node(AST_False, self); if (self.args.length == 0) return make_node(AST_False, self);
if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, { if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, {
@ -2707,7 +2709,7 @@ merge(Compressor.prototype, {
operator: "!" operator: "!"
}), }),
operator: "!" operator: "!"
}).optimize(compressor); });
break; break;
case "Function": case "Function":
// new Function() => function(){} // new Function() => function(){}
@ -2772,7 +2774,7 @@ merge(Compressor.prototype, {
left: make_node(AST_String, self, { value: "" }), left: make_node(AST_String, self, { value: "" }),
operator: "+", operator: "+",
right: exp.expression right: exp.expression
}).optimize(compressor); });
} }
else if (exp instanceof AST_Dot && exp.expression instanceof AST_Array && exp.property == "join") EXIT: { else if (exp instanceof AST_Dot && exp.expression instanceof AST_Array && exp.property == "join") EXIT: {
var separator; var separator;
@ -2827,7 +2829,7 @@ merge(Compressor.prototype, {
left : prev, left : prev,
right : el right : el
}); });
}, first).optimize(compressor); }, first);
} }
// need this awkward cloning to not affect original element // need this awkward cloning to not affect original element
// best_of_expression will decide which one to get through. // best_of_expression will decide which one to get through.
@ -2843,13 +2845,13 @@ merge(Compressor.prototype, {
var value = exp.body[0].value; var value = exp.body[0].value;
if (!value || value.is_constant()) { if (!value || value.is_constant()) {
var args = self.args.concat(value || make_node(AST_Undefined, self)); var args = self.args.concat(value || make_node(AST_Undefined, self));
return AST_Seq.from_array(args).optimize(compressor); return AST_Seq.from_array(args);
} }
} }
if (compressor.option("side_effects")) { if (compressor.option("side_effects")) {
if (!AST_Block.prototype.has_side_effects.call(exp, compressor)) { if (!AST_Block.prototype.has_side_effects.call(exp, compressor)) {
var args = self.args.concat(make_node(AST_Undefined, self)); var args = self.args.concat(make_node(AST_Undefined, self));
return AST_Seq.from_array(args).optimize(compressor); return AST_Seq.from_array(args);
} }
} }
} }
@ -2862,7 +2864,7 @@ merge(Compressor.prototype, {
if (name instanceof AST_SymbolRef if (name instanceof AST_SymbolRef
&& name.name == "console" && name.name == "console"
&& name.undeclared()) { && name.undeclared()) {
return make_node(AST_Undefined, self).optimize(compressor); return make_node(AST_Undefined, self);
} }
} }
} }
@ -2884,7 +2886,7 @@ merge(Compressor.prototype, {
case "Function": case "Function":
case "Error": case "Error":
case "Array": case "Array":
return make_node(AST_Call, self, self).optimize(compressor); return make_node(AST_Call, self, self);
} }
} }
} }
@ -2894,8 +2896,12 @@ merge(Compressor.prototype, {
OPT(AST_Seq, function(self, compressor){ OPT(AST_Seq, function(self, compressor){
if (!compressor.option("side_effects")) if (!compressor.option("side_effects"))
return self; return self;
self.car = self.car.drop_side_effect_free(compressor, first_in_statement(compressor)); var car = self.car.drop_side_effect_free(compressor, first_in_statement(compressor));
if (!self.car) return maintain_this_binding(compressor.parent(), self, self.cdr); if (car) {
self.car = car;
} else {
return maintain_this_binding(compressor.parent(), self, self.cdr);
}
if (compressor.option("cascade")) { if (compressor.option("cascade")) {
var left; var left;
if (self.car instanceof AST_Assign if (self.car instanceof AST_Assign
@ -2955,15 +2961,12 @@ merge(Compressor.prototype, {
}); });
OPT(AST_UnaryPostfix, function(self, compressor){ OPT(AST_UnaryPostfix, function(self, compressor){
var seq = self.lift_sequences(compressor); return self.lift_sequences(compressor);
return seq !== self ? seq.optimize(compressor) : self;
}); });
OPT(AST_UnaryPrefix, function(self, compressor){ OPT(AST_UnaryPrefix, function(self, compressor){
var seq = self.lift_sequences(compressor); var seq = self.lift_sequences(compressor);
if (seq !== self) { if (seq !== self) return seq;
return seq.optimize(compressor);
}
var e = self.expression; var e = self.expression;
if (compressor.option("side_effects") && self.operator == "void") { if (compressor.option("side_effects") && self.operator == "void") {
e = e.drop_side_effect_free(compressor); e = e.drop_side_effect_free(compressor);
@ -2971,7 +2974,7 @@ merge(Compressor.prototype, {
self.expression = e; self.expression = e;
return self; return self;
} else { } else {
return make_node(AST_Undefined, self).optimize(compressor); return make_node(AST_Undefined, self);
} }
} }
if (compressor.option("booleans") && compressor.in_boolean_context()) { if (compressor.option("booleans") && compressor.in_boolean_context()) {
@ -2992,9 +2995,18 @@ merge(Compressor.prototype, {
return make_node(AST_Seq, self, { return make_node(AST_Seq, self, {
car: e, car: e,
cdr: make_node(AST_True, self) cdr: make_node(AST_True, self)
}).optimize(compressor); });
} }
} }
if (e instanceof AST_Infinity && self.operator == "-") {
self.expression = e.transform(compressor);
return self;
} else if (e instanceof AST_Number
&& (self.operator == "-"
|| self.operator == "!"
&& (e.value == 0 || e.value == 1))) {
return self;
}
return self.evaluate_self(compressor); return self.evaluate_self(compressor);
}); });
@ -3087,9 +3099,7 @@ merge(Compressor.prototype, {
} }
} }
var seq = self.lift_sequences(compressor); var seq = self.lift_sequences(compressor);
if (seq !== self) { if (seq !== self) return seq;
return seq.optimize(compressor);
}
if (compressor.option("comparisons")) switch (self.operator) { if (compressor.option("comparisons")) switch (self.operator) {
case "===": case "===":
case "!==": case "!==":
@ -3110,7 +3120,7 @@ merge(Compressor.prototype, {
if (expr instanceof AST_SymbolRef ? !expr.undeclared() if (expr instanceof AST_SymbolRef ? !expr.undeclared()
: !(expr instanceof AST_PropAccess) || compressor.option("screw_ie8")) { : !(expr instanceof AST_PropAccess) || compressor.option("screw_ie8")) {
self.right = expr; self.right = expr;
self.left = make_node(AST_Undefined, self.left).transform(compressor); self.left = make_node(AST_Undefined, self.left);
if (self.operator.length == 2) self.operator += "="; if (self.operator.length == 2) self.operator += "=";
} }
} }
@ -3123,15 +3133,15 @@ merge(Compressor.prototype, {
if ((ll.length > 1 && !ll[1]) || (rr.length > 1 && !rr[1])) { if ((ll.length > 1 && !ll[1]) || (rr.length > 1 && !rr[1])) {
compressor.warn("Boolean && always false [{file}:{line},{col}]", self.start); compressor.warn("Boolean && always false [{file}:{line},{col}]", self.start);
return make_node(AST_Seq, self, { return make_node(AST_Seq, self, {
car: self.left.transform(compressor), car: self.left,
cdr: make_node(AST_False, self).transform(compressor) cdr: make_node(AST_False, self)
}).optimize(compressor); });
} }
if (ll.length > 1 && ll[1]) { if (ll.length > 1 && ll[1]) {
return best_of(compressor, rr[0].optimize(compressor), self.right); return best_of_constant(compressor, rr[0], self.right);
} }
if (rr.length > 1 && rr[1]) { if (rr.length > 1 && rr[1]) {
return best_of(compressor, ll[0].optimize(compressor), self.left); return best_of_constant(compressor, ll[0], self.left);
} }
break; break;
case "||": case "||":
@ -3140,15 +3150,15 @@ merge(Compressor.prototype, {
if ((ll.length > 1 && ll[1]) || (rr.length > 1 && rr[1])) { if ((ll.length > 1 && ll[1]) || (rr.length > 1 && rr[1])) {
compressor.warn("Boolean || always true [{file}:{line},{col}]", self.start); compressor.warn("Boolean || always true [{file}:{line},{col}]", self.start);
return make_node(AST_Seq, self, { return make_node(AST_Seq, self, {
car: self.left.transform(compressor), car: self.left,
cdr: make_node(AST_True, self).transform(compressor) cdr: make_node(AST_True, self)
}).optimize(compressor); });
} }
if (ll.length > 1 && !ll[1]) { if (ll.length > 1 && !ll[1]) {
return best_of(compressor, rr[0].optimize(compressor), self.right); return best_of_constant(compressor, rr[0], self.right);
} }
if (rr.length > 1 && !rr[1]) { if (rr.length > 1 && !rr[1]) {
return best_of(compressor, ll[0].optimize(compressor), self.left); return best_of_constant(compressor, ll[0], self.left);
} }
break; break;
case "+": case "+":
@ -3157,16 +3167,16 @@ merge(Compressor.prototype, {
if (ll.length > 1 && ll[0] instanceof AST_String && ll[1]) { if (ll.length > 1 && ll[0] instanceof AST_String && ll[1]) {
compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start); compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);
return make_node(AST_Seq, self, { return make_node(AST_Seq, self, {
car: self.right.transform(compressor), car: self.right,
cdr: make_node(AST_True, self).transform(compressor) cdr: make_node(AST_True, self)
}).optimize(compressor); });
} }
if (rr.length > 1 && rr[0] instanceof AST_String && rr[1]) { if (rr.length > 1 && rr[0] instanceof AST_String && rr[1]) {
compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start); compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);
return make_node(AST_Seq, self, { return make_node(AST_Seq, self, {
car: self.left.transform(compressor), car: self.left,
cdr: make_node(AST_True, self).transform(compressor) cdr: make_node(AST_True, self)
}).optimize(compressor); });
} }
break; break;
} }
@ -3203,7 +3213,7 @@ merge(Compressor.prototype, {
&& self.left.left.getValue() == "" && self.left.left.getValue() == ""
&& self.right.is_string(compressor)) { && self.right.is_string(compressor)) {
self.left = self.left.right; self.left = self.left.right;
return self.optimize(compressor); return self;
} }
} }
if (compressor.option("evaluate")) { if (compressor.option("evaluate")) {
@ -3424,8 +3434,8 @@ merge(Compressor.prototype, {
operator : self.operator, operator : self.operator,
left : self.left, left : self.left,
right : self.right.left right : self.right.left
}).transform(compressor); });
self.right = self.right.right.transform(compressor); self.right = self.right.right;
} }
return self.evaluate_self(compressor); return self.evaluate_self(compressor);
}); });
@ -3442,11 +3452,11 @@ merge(Compressor.prototype, {
&& (!self.scope.uses_with || !compressor.find_parent(AST_With))) { && (!self.scope.uses_with || !compressor.find_parent(AST_With))) {
switch (self.name) { switch (self.name) {
case "undefined": case "undefined":
return make_node(AST_Undefined, self).optimize(compressor); return make_node(AST_Undefined, self);
case "NaN": case "NaN":
return make_node(AST_NaN, self).optimize(compressor); return make_node(AST_NaN, self);
case "Infinity": case "Infinity":
return make_node(AST_Infinity, self).optimize(compressor); return make_node(AST_Infinity, self);
} }
} }
if (compressor.option("evaluate") && compressor.option("reduce_vars")) { if (compressor.option("evaluate") && compressor.option("reduce_vars")) {
@ -3455,7 +3465,7 @@ merge(Compressor.prototype, {
if (d.should_replace === undefined) { if (d.should_replace === undefined) {
var init = d.fixed.evaluate(compressor); var init = d.fixed.evaluate(compressor);
if (init.length > 1) { if (init.length > 1) {
init = best_of(compressor, init[0].optimize(compressor), d.fixed); init = best_of_constant(compressor, init[0], d.fixed);
var value = init.print_to_string().length; var value = init.print_to_string().length;
var name = d.name.length; var name = d.name.length;
var freq = d.references.length; var freq = d.references.length;
@ -3502,9 +3512,7 @@ merge(Compressor.prototype, {
var ASSIGN_OPS_COMMUTATIVE = [ '*', '|', '^', '&' ]; var ASSIGN_OPS_COMMUTATIVE = [ '*', '|', '^', '&' ];
OPT(AST_Assign, function(self, compressor){ OPT(AST_Assign, function(self, compressor){
var seq = self.lift_sequences(compressor); var seq = self.lift_sequences(compressor);
if (seq !== self) { if (seq !== self) return seq;
return seq.optimize(compressor);
}
if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) { if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) {
// x = expr1 OP expr2 // x = expr1 OP expr2
if (self.right.left instanceof AST_SymbolRef if (self.right.left instanceof AST_SymbolRef
@ -3542,7 +3550,6 @@ merge(Compressor.prototype, {
compressor.warn("Condition always false [{file}:{line},{col}]", self.start); compressor.warn("Condition always false [{file}:{line},{col}]", self.start);
return maintain_this_binding(compressor.parent(), self, self.alternative); return maintain_this_binding(compressor.parent(), self, self.alternative);
} }
self.condition = best_of(compressor, cond[0].transform(compressor), self.condition);
} }
var negated = self.condition.negate(compressor, first_in_statement(compressor)); var negated = self.condition.negate(compressor, first_in_statement(compressor));
if (best_of(compressor, self.condition, negated) === negated) { if (best_of(compressor, self.condition, negated) === negated) {
@ -3609,7 +3616,7 @@ merge(Compressor.prototype, {
return make_node(AST_Seq, self, { return make_node(AST_Seq, self, {
car: self.condition, car: self.condition,
cdr: consequent cdr: consequent
}).optimize(compressor); });
} }
if (is_true(self.consequent)) { if (is_true(self.consequent)) {
@ -3716,7 +3723,7 @@ merge(Compressor.prototype, {
return make_node(AST_Dot, self, { return make_node(AST_Dot, self, {
expression : self.expression, expression : self.expression,
property : prop property : prop
}).optimize(compressor); });
} }
var v = parseFloat(prop); var v = parseFloat(prop);
if (!isNaN(v) && v.toString() == prop) { if (!isNaN(v) && v.toString() == prop) {
@ -3740,7 +3747,7 @@ merge(Compressor.prototype, {
property : make_node(AST_String, self, { property : make_node(AST_String, self, {
value: prop value: prop
}) })
}).optimize(compressor); });
} }
if (compressor.option("unsafe_proto") if (compressor.option("unsafe_proto")
&& self.expression instanceof AST_Dot && self.expression instanceof AST_Dot
@ -3769,10 +3776,10 @@ merge(Compressor.prototype, {
function literals_in_boolean_context(self, compressor) { function literals_in_boolean_context(self, compressor) {
if (compressor.option("booleans") && compressor.in_boolean_context()) { if (compressor.option("booleans") && compressor.in_boolean_context()) {
return best_of(compressor, self, make_node(AST_Seq, self, { return best_of_constant(compressor, make_node(AST_Seq, self, {
car: self, car: self,
cdr: make_node(AST_True, self) cdr: make_node(AST_True, self)
}).optimize(compressor)); }), self);
} }
return self; return self;
}; };