Merge branch 'master' into harmony-v2.8.22
This commit is contained in:
330
lib/compress.js
330
lib/compress.js
@@ -72,7 +72,7 @@ function Compressor(options, false_by_default) {
|
||||
negate_iife : !false_by_default,
|
||||
passes : 1,
|
||||
properties : !false_by_default,
|
||||
pure_getters : false,
|
||||
pure_getters : !false_by_default && "strict",
|
||||
pure_funcs : null,
|
||||
reduce_vars : !false_by_default,
|
||||
screw_ie8 : true,
|
||||
@@ -252,9 +252,7 @@ merge(Compressor.prototype, {
|
||||
AST_Node.DEFMETHOD("reset_opt_flags", function(compressor, rescan){
|
||||
var reduce_vars = rescan && compressor.option("reduce_vars");
|
||||
var toplevel = compressor.option("toplevel");
|
||||
var ie8 = !compressor.option("screw_ie8");
|
||||
var safe_ids = [];
|
||||
push();
|
||||
var safe_ids = Object.create(null);
|
||||
var suppressor = new TreeWalker(function(node) {
|
||||
if (node instanceof AST_Symbol) {
|
||||
var d = node.definition();
|
||||
@@ -263,10 +261,8 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
});
|
||||
var tw = new TreeWalker(function(node, descend){
|
||||
if (!(node instanceof AST_Directive || node instanceof AST_Constant)) {
|
||||
node._squeezed = false;
|
||||
node._optimized = false;
|
||||
}
|
||||
node._squeezed = false;
|
||||
node._optimized = false;
|
||||
if (reduce_vars) {
|
||||
if (node instanceof AST_Toplevel) node.globals.each(reset_def);
|
||||
if (node instanceof AST_Scope) node.variables.each(reset_def);
|
||||
@@ -274,11 +270,11 @@ merge(Compressor.prototype, {
|
||||
var d = node.definition();
|
||||
d.references.push(node);
|
||||
if (d.fixed === undefined || !is_safe(d)
|
||||
|| is_modified(node, 0, d.fixed instanceof AST_Lambda)) {
|
||||
|| is_modified(node, 0, node.fixed_value() instanceof AST_Lambda)) {
|
||||
d.fixed = false;
|
||||
}
|
||||
}
|
||||
if (ie8 && node instanceof AST_SymbolCatch) {
|
||||
if (node instanceof AST_SymbolCatch) {
|
||||
node.definition().fixed = false;
|
||||
}
|
||||
if (node instanceof AST_VarDef) {
|
||||
@@ -287,8 +283,17 @@ merge(Compressor.prototype, {
|
||||
} else {
|
||||
var d = node.name.definition();
|
||||
if (d.fixed == null) {
|
||||
d.fixed = node.value;
|
||||
mark_as_safe(d);
|
||||
if (node.value) {
|
||||
d.fixed = function() {
|
||||
return node.value;
|
||||
};
|
||||
mark(d, false);
|
||||
descend();
|
||||
} else {
|
||||
d.fixed = null;
|
||||
}
|
||||
mark(d, true);
|
||||
return true;
|
||||
} else if (node.value) {
|
||||
d.fixed = false;
|
||||
}
|
||||
@@ -300,11 +305,10 @@ merge(Compressor.prototype, {
|
||||
d.fixed = false;
|
||||
} else {
|
||||
d.fixed = node;
|
||||
mark_as_safe(d);
|
||||
mark(d, true);
|
||||
}
|
||||
var save_ids = safe_ids;
|
||||
safe_ids = [];
|
||||
push();
|
||||
safe_ids = Object.create(null);
|
||||
descend();
|
||||
safe_ids = save_ids;
|
||||
return true;
|
||||
@@ -319,8 +323,10 @@ merge(Compressor.prototype, {
|
||||
// So existing transformation rules can work on them.
|
||||
node.argnames.forEach(function(arg, i) {
|
||||
var d = arg.definition();
|
||||
d.fixed = iife.args[i] || make_node(AST_Undefined, iife);
|
||||
mark_as_safe(d);
|
||||
d.fixed = function() {
|
||||
return iife.args[i] || make_node(AST_Undefined, iife);
|
||||
};
|
||||
mark(d, true);
|
||||
});
|
||||
}
|
||||
if (node instanceof AST_If || node instanceof AST_DWLoop) {
|
||||
@@ -368,29 +374,27 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
this.walk(tw);
|
||||
|
||||
function mark_as_safe(def) {
|
||||
safe_ids[safe_ids.length - 1][def.id] = true;
|
||||
function mark(def, safe) {
|
||||
safe_ids[def.id] = safe;
|
||||
}
|
||||
|
||||
function is_safe(def) {
|
||||
for (var i = safe_ids.length, id = def.id; --i >= 0;) {
|
||||
if (safe_ids[i][id]) {
|
||||
if (def.fixed == null) {
|
||||
var orig = def.orig[0];
|
||||
if (orig instanceof AST_SymbolFunarg || orig.name == "arguments") return false;
|
||||
def.fixed = make_node(AST_Undefined, orig);
|
||||
}
|
||||
return true;
|
||||
if (safe_ids[def.id]) {
|
||||
if (def.fixed == null) {
|
||||
var orig = def.orig[0];
|
||||
if (orig instanceof AST_SymbolFunarg || orig.name == "arguments") return false;
|
||||
def.fixed = make_node(AST_Undefined, orig);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function push() {
|
||||
safe_ids.push(Object.create(null));
|
||||
safe_ids = Object.create(safe_ids);
|
||||
}
|
||||
|
||||
function pop() {
|
||||
safe_ids.pop();
|
||||
safe_ids = Object.getPrototypeOf(safe_ids);
|
||||
}
|
||||
|
||||
function reset_def(def) {
|
||||
@@ -405,7 +409,7 @@ merge(Compressor.prototype, {
|
||||
|
||||
function is_modified(node, level, func) {
|
||||
var parent = tw.parent(level);
|
||||
if (isLHS(node, parent)
|
||||
if (is_lhs(node, parent)
|
||||
|| !func && parent instanceof AST_Call && parent.expression === node) {
|
||||
return true;
|
||||
} else if (parent instanceof AST_PropAccess && parent.expression === node) {
|
||||
@@ -414,6 +418,12 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
});
|
||||
|
||||
AST_SymbolRef.DEFMETHOD("fixed_value", function() {
|
||||
var fixed = this.definition().fixed;
|
||||
if (!fixed || fixed instanceof AST_Node) return fixed;
|
||||
return fixed();
|
||||
});
|
||||
|
||||
function find_variable(compressor, name) {
|
||||
var scope, i = 0;
|
||||
while (scope = compressor.parent(i++)) {
|
||||
@@ -474,15 +484,15 @@ merge(Compressor.prototype, {
|
||||
// func(something) because that changes the meaning of
|
||||
// the func (becomes lexical instead of global).
|
||||
function maintain_this_binding(parent, orig, val) {
|
||||
if (parent instanceof AST_Call && parent.expression === orig) {
|
||||
if (val instanceof AST_PropAccess || val instanceof AST_SymbolRef && val.name === "eval") {
|
||||
return make_node(AST_Seq, orig, {
|
||||
car: make_node(AST_Number, orig, {
|
||||
value: 0
|
||||
}),
|
||||
cdr: val
|
||||
});
|
||||
}
|
||||
if (parent instanceof AST_UnaryPrefix && parent.operator == "delete"
|
||||
|| parent instanceof AST_Call && parent.expression === orig
|
||||
&& (val instanceof AST_PropAccess || val instanceof AST_SymbolRef && val.name == "eval")) {
|
||||
return make_node(AST_Seq, orig, {
|
||||
car: make_node(AST_Number, orig, {
|
||||
value: 0
|
||||
}),
|
||||
cdr: val
|
||||
});
|
||||
}
|
||||
return val;
|
||||
}
|
||||
@@ -702,7 +712,7 @@ merge(Compressor.prototype, {
|
||||
return statements;
|
||||
|
||||
function is_lvalue(node, parent) {
|
||||
return node instanceof AST_SymbolRef && isLHS(node, parent);
|
||||
return node instanceof AST_SymbolRef && is_lhs(node, parent);
|
||||
}
|
||||
function replace_var(node, parent, is_constant) {
|
||||
if (is_lvalue(node, parent)) return node;
|
||||
@@ -916,7 +926,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
|
||||
var ab = aborts(stat.body);
|
||||
var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab.label) : null;
|
||||
var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab) : null;
|
||||
if (ab && ((ab instanceof AST_Return && !ab.value && in_lambda)
|
||||
|| (ab instanceof AST_Continue && self === loop_body(lct))
|
||||
|| (ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct))) {
|
||||
@@ -938,7 +948,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
|
||||
var ab = aborts(stat.alternative);
|
||||
var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab.label) : null;
|
||||
var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab) : null;
|
||||
if (ab && ((ab instanceof AST_Return && !ab.value && in_lambda)
|
||||
|| (ab instanceof AST_Continue && self === loop_body(lct))
|
||||
|| (ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct))) {
|
||||
@@ -987,7 +997,7 @@ merge(Compressor.prototype, {
|
||||
extract_declarations_from_unreachable_code(compressor, stat, a);
|
||||
} else {
|
||||
if (stat instanceof AST_LoopControl) {
|
||||
var lct = compressor.loopcontrol_target(stat.label);
|
||||
var lct = compressor.loopcontrol_target(stat);
|
||||
if ((stat instanceof AST_Break
|
||||
&& !(lct instanceof AST_IterationStatement)
|
||||
&& loop_body(lct) === self) || (stat instanceof AST_Continue
|
||||
@@ -1173,6 +1183,61 @@ merge(Compressor.prototype, {
|
||||
&& !node.expression.has_side_effects(compressor);
|
||||
}
|
||||
|
||||
// may_eq_null()
|
||||
// returns true if this node may evaluate to null or undefined
|
||||
(function(def) {
|
||||
AST_Node.DEFMETHOD("may_eq_null", function(compressor) {
|
||||
var pure_getters = compressor.option("pure_getters");
|
||||
return !pure_getters || this._eq_null(pure_getters);
|
||||
});
|
||||
|
||||
function is_strict(pure_getters) {
|
||||
return /strict/.test(pure_getters);
|
||||
}
|
||||
|
||||
def(AST_Node, is_strict);
|
||||
def(AST_Null, return_true);
|
||||
def(AST_Undefined, return_true);
|
||||
def(AST_Constant, return_false);
|
||||
def(AST_Array, return_false);
|
||||
def(AST_Object, return_false);
|
||||
def(AST_Function, return_false);
|
||||
def(AST_UnaryPostfix, return_false);
|
||||
def(AST_UnaryPrefix, function() {
|
||||
return this.operator == "void";
|
||||
});
|
||||
def(AST_Binary, function(pure_getters) {
|
||||
switch (this.operator) {
|
||||
case "&&":
|
||||
return this.left._eq_null(pure_getters);
|
||||
case "||":
|
||||
return this.left._eq_null(pure_getters)
|
||||
&& this.right._eq_null(pure_getters);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
})
|
||||
def(AST_Assign, function(pure_getters) {
|
||||
return this.operator == "="
|
||||
&& this.right._eq_null(pure_getters);
|
||||
})
|
||||
def(AST_Conditional, function(pure_getters) {
|
||||
return this.consequent._eq_null(pure_getters)
|
||||
|| this.alternative._eq_null(pure_getters);
|
||||
})
|
||||
def(AST_Seq, function(pure_getters) {
|
||||
return this.cdr._eq_null(pure_getters);
|
||||
});
|
||||
def(AST_SymbolRef, function(pure_getters) {
|
||||
if (this.is_undefined) return true;
|
||||
if (!is_strict(pure_getters)) return false;
|
||||
var fixed = this.fixed_value();
|
||||
return !fixed || fixed._eq_null(pure_getters);
|
||||
});
|
||||
})(function(node, func) {
|
||||
node.DEFMETHOD("_eq_null", func);
|
||||
});
|
||||
|
||||
/* -----[ boolean/negation helpers ]----- */
|
||||
|
||||
// methods to determine whether an expression has a boolean result type
|
||||
@@ -1260,9 +1325,9 @@ merge(Compressor.prototype, {
|
||||
|
||||
var unary_side_effects = makePredicate("delete ++ --");
|
||||
|
||||
function isLHS(node, parent) {
|
||||
return parent instanceof AST_Unary && unary_side_effects(parent.operator)
|
||||
|| parent instanceof AST_Assign && parent.left === node;
|
||||
function is_lhs(node, parent) {
|
||||
if (parent instanceof AST_Unary && unary_side_effects(parent.operator)) return parent.expression;
|
||||
if (parent instanceof AST_Assign && parent.left === node) return node;
|
||||
}
|
||||
|
||||
(function (def){
|
||||
@@ -1275,7 +1340,7 @@ merge(Compressor.prototype, {
|
||||
node = parent;
|
||||
parent = compressor.parent(level++);
|
||||
} while (parent instanceof AST_PropAccess && parent.expression === node);
|
||||
if (isLHS(node, parent)) {
|
||||
if (is_lhs(node, parent)) {
|
||||
compressor.warn('global_defs ' + this.print_to_string() + ' redefined [{file}:{line},{col}]', this.start);
|
||||
} else {
|
||||
return def;
|
||||
@@ -1305,7 +1370,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
def(AST_Node, noop);
|
||||
def(AST_Dot, function(compressor, suffix){
|
||||
return this.expression._find_defs(compressor, suffix + "." + this.property);
|
||||
return this.expression._find_defs(compressor, "." + this.property + suffix);
|
||||
});
|
||||
def(AST_SymbolRef, function(compressor, suffix){
|
||||
if (!this.global()) return;
|
||||
@@ -1525,15 +1590,15 @@ merge(Compressor.prototype, {
|
||||
if (this._evaluating) throw def;
|
||||
this._evaluating = true;
|
||||
try {
|
||||
var d = this.definition();
|
||||
if (compressor.option("reduce_vars") && d.fixed) {
|
||||
var fixed = this.fixed_value();
|
||||
if (compressor.option("reduce_vars") && fixed) {
|
||||
if (compressor.option("unsafe")) {
|
||||
if (!HOP(d.fixed, "_evaluated")) {
|
||||
d.fixed._evaluated = ev(d.fixed, compressor);
|
||||
if (!HOP(fixed, "_evaluated")) {
|
||||
fixed._evaluated = ev(fixed, compressor);
|
||||
}
|
||||
return d.fixed._evaluated;
|
||||
return fixed._evaluated;
|
||||
}
|
||||
return ev(d.fixed, compressor);
|
||||
return ev(fixed, compressor);
|
||||
}
|
||||
} finally {
|
||||
this._evaluating = false;
|
||||
@@ -1718,7 +1783,7 @@ merge(Compressor.prototype, {
|
||||
|| this.expression.has_side_effects(compressor);
|
||||
});
|
||||
def(AST_SymbolRef, function(compressor){
|
||||
return this.global() && this.undeclared();
|
||||
return this.undeclared();
|
||||
});
|
||||
def(AST_Object, function(compressor){
|
||||
return any(this.properties, compressor);
|
||||
@@ -1733,17 +1798,14 @@ merge(Compressor.prototype, {
|
||||
return any(this.elements, compressor);
|
||||
});
|
||||
def(AST_Dot, function(compressor){
|
||||
if (!compressor.option("pure_getters")) return true;
|
||||
return this.expression.has_side_effects(compressor);
|
||||
return this.expression.may_eq_null(compressor)
|
||||
|| this.expression.has_side_effects(compressor);
|
||||
});
|
||||
def(AST_Sub, function(compressor){
|
||||
if (!compressor.option("pure_getters")) return true;
|
||||
return this.expression.has_side_effects(compressor)
|
||||
return this.expression.may_eq_null(compressor)
|
||||
|| this.expression.has_side_effects(compressor)
|
||||
|| this.property.has_side_effects(compressor);
|
||||
});
|
||||
def(AST_PropAccess, function(compressor){
|
||||
return !compressor.option("pure_getters");
|
||||
});
|
||||
def(AST_Seq, function(compressor){
|
||||
return this.car.has_side_effects(compressor)
|
||||
|| this.cdr.has_side_effects(compressor);
|
||||
@@ -1790,7 +1852,7 @@ merge(Compressor.prototype, {
|
||||
|
||||
OPT(AST_LabeledStatement, function(self, compressor){
|
||||
if (self.body instanceof AST_Break
|
||||
&& compressor.loopcontrol_target(self.body.label) === self.body) {
|
||||
&& compressor.loopcontrol_target(self.body) === self.body) {
|
||||
return make_node(AST_EmptyStatement, self);
|
||||
}
|
||||
return self.label.references.length == 0 ? self.body : self;
|
||||
@@ -2388,11 +2450,11 @@ merge(Compressor.prototype, {
|
||||
return values && AST_Seq.from_array(values);
|
||||
});
|
||||
def(AST_Dot, function(compressor, first_in_statement){
|
||||
if (!compressor.option("pure_getters")) return this;
|
||||
if (this.expression.may_eq_null(compressor)) return this;
|
||||
return this.expression.drop_side_effect_free(compressor, first_in_statement);
|
||||
});
|
||||
def(AST_Sub, function(compressor, first_in_statement){
|
||||
if (!compressor.option("pure_getters")) return this;
|
||||
if (this.expression.may_eq_null(compressor)) return this;
|
||||
var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
|
||||
if (!expression) return this.property.drop_side_effect_free(compressor, first_in_statement);
|
||||
var property = this.property.drop_side_effect_free(compressor);
|
||||
@@ -2438,13 +2500,21 @@ merge(Compressor.prototype, {
|
||||
return make_node(AST_For, self, {
|
||||
body: self.body
|
||||
});
|
||||
} else if (compressor.option("dead_code") && self instanceof AST_While) {
|
||||
}
|
||||
if (compressor.option("dead_code") && self instanceof AST_While) {
|
||||
var a = [];
|
||||
extract_declarations_from_unreachable_code(compressor, self.body, a);
|
||||
return make_node(AST_BlockStatement, self, { body: a });
|
||||
} else {
|
||||
cond = make_node_from_constant(cond, self.condition).transform(compressor);
|
||||
self.condition = best_of_expression(cond, self.condition);
|
||||
}
|
||||
if (self instanceof AST_Do) {
|
||||
var has_loop_control = false;
|
||||
var tw = new TreeWalker(function(node) {
|
||||
if (node instanceof AST_Scope || has_loop_control) return true;
|
||||
if (node instanceof AST_LoopControl && tw.loopcontrol_target(node) === self)
|
||||
return has_loop_control = true;
|
||||
});
|
||||
self.walk(tw);
|
||||
if (!has_loop_control) return self.body;
|
||||
}
|
||||
}
|
||||
if (self instanceof AST_While) {
|
||||
@@ -2470,7 +2540,7 @@ merge(Compressor.prototype, {
|
||||
var first = self.body instanceof AST_BlockStatement ? self.body.body[0] : self.body;
|
||||
if (first instanceof AST_If) {
|
||||
if (first.body instanceof AST_Break
|
||||
&& compressor.loopcontrol_target(first.body.label) === compressor.self()) {
|
||||
&& compressor.loopcontrol_target(first.body) === compressor.self()) {
|
||||
if (self.condition) {
|
||||
self.condition = make_node(AST_Binary, self.condition, {
|
||||
left: self.condition,
|
||||
@@ -2483,7 +2553,7 @@ merge(Compressor.prototype, {
|
||||
drop_it(first.alternative);
|
||||
}
|
||||
else if (first.alternative instanceof AST_Break
|
||||
&& compressor.loopcontrol_target(first.alternative.label) === compressor.self()) {
|
||||
&& compressor.loopcontrol_target(first.alternative) === compressor.self()) {
|
||||
if (self.condition) {
|
||||
self.condition = make_node(AST_Binary, self.condition, {
|
||||
left: self.condition,
|
||||
@@ -2714,7 +2784,7 @@ merge(Compressor.prototype, {
|
||||
self.body = body;
|
||||
while (branch = body[body.length - 1]) {
|
||||
var stat = branch.body[branch.body.length - 1];
|
||||
if (stat instanceof AST_Break && compressor.loopcontrol_target(stat.label) === self)
|
||||
if (stat instanceof AST_Break && compressor.loopcontrol_target(stat) === self)
|
||||
branch.body.pop();
|
||||
if (branch.body.length || branch instanceof AST_Case
|
||||
&& (default_branch || branch.expression.has_side_effects(compressor))) break;
|
||||
@@ -2733,7 +2803,7 @@ merge(Compressor.prototype, {
|
||||
if (has_break
|
||||
|| node instanceof AST_Lambda
|
||||
|| node instanceof AST_SimpleStatement) return true;
|
||||
if (node instanceof AST_Break && tw.loopcontrol_target(node.label) === self)
|
||||
if (node instanceof AST_Break && tw.loopcontrol_target(node) === self)
|
||||
has_break = true;
|
||||
});
|
||||
self.walk(tw);
|
||||
@@ -2819,11 +2889,12 @@ merge(Compressor.prototype, {
|
||||
if (compressor.option("reduce_vars")
|
||||
&& exp instanceof AST_SymbolRef) {
|
||||
var def = exp.definition();
|
||||
if (def.fixed instanceof AST_Defun) {
|
||||
def.fixed = make_node(AST_Function, def.fixed, def.fixed).clone(true);
|
||||
var fixed = exp.fixed_value();
|
||||
if (fixed instanceof AST_Defun) {
|
||||
def.fixed = fixed = make_node(AST_Function, fixed, fixed).clone(true);
|
||||
}
|
||||
if (def.fixed instanceof AST_Function) {
|
||||
exp = def.fixed;
|
||||
if (fixed instanceof AST_Function) {
|
||||
exp = fixed;
|
||||
if (compressor.option("unused")
|
||||
&& def.references.length == 1
|
||||
&& !(def.scope.uses_arguments
|
||||
@@ -3158,8 +3229,9 @@ merge(Compressor.prototype, {
|
||||
if (this.expression instanceof AST_Seq) {
|
||||
var seq = this.expression;
|
||||
var x = seq.to_array();
|
||||
this.expression = x.pop();
|
||||
x.push(this);
|
||||
var e = this.clone();
|
||||
e.expression = x.pop();
|
||||
x.push(e);
|
||||
seq = AST_Seq.from_array(x).transform(compressor);
|
||||
return seq;
|
||||
}
|
||||
@@ -3172,11 +3244,27 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
|
||||
OPT(AST_UnaryPrefix, function(self, compressor){
|
||||
var e = self.expression;
|
||||
if (self.operator == "delete"
|
||||
&& !(e instanceof AST_SymbolRef
|
||||
|| e instanceof AST_PropAccess
|
||||
|| e instanceof AST_NaN
|
||||
|| e instanceof AST_Infinity
|
||||
|| e instanceof AST_Undefined)) {
|
||||
if (e instanceof AST_Seq) {
|
||||
e = e.to_array();
|
||||
e.push(make_node(AST_True, self));
|
||||
return AST_Seq.from_array(e).optimize(compressor);
|
||||
}
|
||||
return make_node(AST_Seq, self, {
|
||||
car: e,
|
||||
cdr: make_node(AST_True, self)
|
||||
}).optimize(compressor);
|
||||
}
|
||||
var seq = self.lift_sequences(compressor);
|
||||
if (seq !== self) {
|
||||
return seq;
|
||||
}
|
||||
var e = self.expression;
|
||||
if (compressor.option("side_effects") && self.operator == "void") {
|
||||
e = e.drop_side_effect_free(compressor);
|
||||
if (e) {
|
||||
@@ -3213,9 +3301,14 @@ merge(Compressor.prototype, {
|
||||
if (e instanceof AST_Binary
|
||||
&& (self.operator == "+" || self.operator == "-")
|
||||
&& (e.operator == "*" || e.operator == "/" || e.operator == "%")) {
|
||||
self.expression = e.left;
|
||||
e.left = self;
|
||||
return e.optimize(compressor);
|
||||
return make_node(AST_Binary, self, {
|
||||
operator: e.operator,
|
||||
left: make_node(AST_UnaryPrefix, e.left, {
|
||||
operator: self.operator,
|
||||
expression: e.left
|
||||
}),
|
||||
right: e.right
|
||||
});
|
||||
}
|
||||
// avoids infinite recursion of numerals
|
||||
if (self.operator != "-"
|
||||
@@ -3234,23 +3327,25 @@ merge(Compressor.prototype, {
|
||||
if (this.left instanceof AST_Seq) {
|
||||
var seq = this.left;
|
||||
var x = seq.to_array();
|
||||
this.left = x.pop();
|
||||
x.push(this);
|
||||
var e = this.clone();
|
||||
e.left = x.pop();
|
||||
x.push(e);
|
||||
return AST_Seq.from_array(x).optimize(compressor);
|
||||
}
|
||||
if (this.right instanceof AST_Seq && !this.left.has_side_effects(compressor)) {
|
||||
var assign = this.operator == "=" && this.left instanceof AST_SymbolRef;
|
||||
var root = this.right;
|
||||
var root = this.right.clone();
|
||||
var cursor, seq = root;
|
||||
while (assign || !seq.car.has_side_effects(compressor)) {
|
||||
cursor = seq;
|
||||
if (seq.cdr instanceof AST_Seq) {
|
||||
seq = seq.cdr;
|
||||
seq = seq.cdr = seq.cdr.clone();
|
||||
} else break;
|
||||
}
|
||||
if (cursor) {
|
||||
this.right = cursor.cdr;
|
||||
cursor.cdr = this;
|
||||
var e = this.clone();
|
||||
e.right = cursor.cdr;
|
||||
cursor.cdr = e;
|
||||
return root.optimize(compressor);
|
||||
}
|
||||
}
|
||||
@@ -3628,12 +3723,11 @@ merge(Compressor.prototype, {
|
||||
OPT(AST_SymbolRef, function(self, compressor){
|
||||
var def = self.resolve_defines(compressor);
|
||||
if (def) {
|
||||
return def;
|
||||
return def.optimize(compressor);
|
||||
}
|
||||
// testing against !self.scope.uses_with first is an optimization
|
||||
if (compressor.option("screw_ie8")
|
||||
&& self.undeclared()
|
||||
&& !isLHS(self, compressor.parent())
|
||||
&& (!self.scope.uses_with || !compressor.find_parent(AST_With))) {
|
||||
switch (self.name) {
|
||||
case "undefined":
|
||||
@@ -3646,13 +3740,13 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
if (compressor.option("evaluate") && compressor.option("reduce_vars")) {
|
||||
var d = self.definition();
|
||||
if (d.fixed) {
|
||||
var fixed = self.fixed_value();
|
||||
if (fixed) {
|
||||
if (d.should_replace === undefined) {
|
||||
var init = d.fixed.evaluate(compressor);
|
||||
if (init !== d.fixed) {
|
||||
init = make_node_from_constant(init, d.fixed).optimize(compressor);
|
||||
init = best_of_expression(init, d.fixed);
|
||||
var value = init.print_to_string().length;
|
||||
var init = fixed.evaluate(compressor);
|
||||
if (init !== fixed) {
|
||||
init = make_node_from_constant(init, fixed);
|
||||
var value = best_of_expression(init.optimize(compressor), fixed).print_to_string().length;
|
||||
var name = d.name.length;
|
||||
var freq = d.references.length;
|
||||
var overhead = d.global || !freq ? 0 : (name + 2 + value) / freq;
|
||||
@@ -3662,13 +3756,17 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
}
|
||||
if (d.should_replace) {
|
||||
return d.should_replace.clone(true);
|
||||
return best_of_expression(d.should_replace.optimize(compressor), fixed).clone(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
return self;
|
||||
});
|
||||
|
||||
function is_atomic(lhs, self) {
|
||||
return lhs instanceof AST_SymbolRef || lhs.TYPE === self.TYPE;
|
||||
}
|
||||
|
||||
OPT(AST_Undefined, function(self, compressor){
|
||||
if (compressor.option("unsafe")) {
|
||||
var undef = find_variable(compressor, "undefined");
|
||||
@@ -3682,6 +3780,8 @@ merge(Compressor.prototype, {
|
||||
return ref;
|
||||
}
|
||||
}
|
||||
var lhs = is_lhs(compressor.self(), compressor.parent());
|
||||
if (lhs && is_atomic(lhs, self)) return self;
|
||||
return make_node(AST_UnaryPrefix, self, {
|
||||
operator: "void",
|
||||
expression: make_node(AST_Number, self, {
|
||||
@@ -3691,8 +3791,13 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
|
||||
OPT(AST_Infinity, function(self, compressor){
|
||||
var retain = compressor.option("keep_infinity") && !find_variable(compressor, "Infinity");
|
||||
return retain ? self : make_node(AST_Binary, self, {
|
||||
var lhs = is_lhs(compressor.self(), compressor.parent());
|
||||
if (lhs && is_atomic(lhs, self)) return self;
|
||||
if (compressor.option("keep_infinity")
|
||||
&& !(lhs && !is_atomic(lhs, self))
|
||||
&& !find_variable(compressor, "Infinity"))
|
||||
return self;
|
||||
return make_node(AST_Binary, self, {
|
||||
operator: "/",
|
||||
left: make_node(AST_Number, self, {
|
||||
value: 1
|
||||
@@ -3704,15 +3809,20 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
|
||||
OPT(AST_NaN, function(self, compressor){
|
||||
return find_variable(compressor, "NaN") ? make_node(AST_Binary, self, {
|
||||
operator: "/",
|
||||
left: make_node(AST_Number, self, {
|
||||
value: 0
|
||||
}),
|
||||
right: make_node(AST_Number, self, {
|
||||
value: 0
|
||||
})
|
||||
}) : self;
|
||||
var lhs = is_lhs(compressor.self(), compressor.parent());
|
||||
if (lhs && !is_atomic(lhs, self)
|
||||
|| find_variable(compressor, "NaN")) {
|
||||
return make_node(AST_Binary, self, {
|
||||
operator: "/",
|
||||
left: make_node(AST_Number, self, {
|
||||
value: 0
|
||||
}),
|
||||
right: make_node(AST_Number, self, {
|
||||
value: 0
|
||||
})
|
||||
});
|
||||
}
|
||||
return self;
|
||||
});
|
||||
|
||||
var ASSIGN_OPS = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ];
|
||||
@@ -3975,7 +4085,7 @@ merge(Compressor.prototype, {
|
||||
OPT(AST_Dot, function(self, compressor){
|
||||
var def = self.resolve_defines(compressor);
|
||||
if (def) {
|
||||
return def;
|
||||
return def.optimize(compressor);
|
||||
}
|
||||
var prop = self.property;
|
||||
if (RESERVED_WORDS(prop) && !compressor.option("screw_ie8")) {
|
||||
|
||||
Reference in New Issue
Block a user