Merge branch 'master' into harmony-v3.3.6
This commit is contained in:
167
lib/compress.js
167
lib/compress.js
@@ -489,8 +489,9 @@ merge(Compressor.prototype, {
|
||||
if (node instanceof AST_SymbolRef) d.references.push(node);
|
||||
d.fixed = false;
|
||||
});
|
||||
def(AST_Accessor, function(tw, descend) {
|
||||
def(AST_Accessor, function(tw, descend, compressor) {
|
||||
push(tw);
|
||||
reset_variables(tw, compressor, this);
|
||||
descend();
|
||||
pop(tw);
|
||||
return true;
|
||||
@@ -947,6 +948,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
|
||||
function tighten_body(statements, compressor) {
|
||||
var scope = compressor.find_parent(AST_Scope).get_defun_scope();
|
||||
var CHANGED, max_iter = 10;
|
||||
do {
|
||||
CHANGED = false;
|
||||
@@ -978,7 +980,6 @@ merge(Compressor.prototype, {
|
||||
// Will not attempt to collapse assignments into or past code blocks
|
||||
// which are not sequentially executed, e.g. loops and conditionals.
|
||||
function collapse(statements, compressor) {
|
||||
var scope = compressor.find_parent(AST_Scope).get_defun_scope();
|
||||
if (scope.uses_eval || scope.uses_with) return statements;
|
||||
var args;
|
||||
var candidates = [];
|
||||
@@ -1640,7 +1641,7 @@ merge(Compressor.prototype, {
|
||||
function next_index(i) {
|
||||
for (var j = i + 1, len = statements.length; j < len; j++) {
|
||||
var stat = statements[j];
|
||||
if (!(stat instanceof AST_Definitions && declarations_only(stat))) {
|
||||
if (!(stat instanceof AST_Var && declarations_only(stat))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1650,7 +1651,7 @@ merge(Compressor.prototype, {
|
||||
function prev_index(i) {
|
||||
for (var j = i; --j >= 0;) {
|
||||
var stat = statements[j];
|
||||
if (!(stat instanceof AST_Definitions && declarations_only(stat))) {
|
||||
if (!(stat instanceof AST_Var && declarations_only(stat))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1813,6 +1814,41 @@ merge(Compressor.prototype, {
|
||||
statements.length = n;
|
||||
}
|
||||
|
||||
function join_object_assignments(defn, body) {
|
||||
if (!(defn instanceof AST_Definitions)) return;
|
||||
var def = defn.definitions[defn.definitions.length - 1];
|
||||
if (!(def.value instanceof AST_Object)) return;
|
||||
var exprs;
|
||||
if (body instanceof AST_Assign) {
|
||||
exprs = [ body ];
|
||||
} else if (body instanceof AST_Sequence) {
|
||||
exprs = body.expressions.slice();
|
||||
}
|
||||
if (!exprs) return;
|
||||
var trimmed = false;
|
||||
do {
|
||||
var node = exprs[0];
|
||||
if (!(node instanceof AST_Assign)) break;
|
||||
if (!(node.left instanceof AST_PropAccess)) break;
|
||||
var sym = node.left.expression;
|
||||
if (!(sym instanceof AST_SymbolRef)) break;
|
||||
if (def.name.name != sym.name) break;
|
||||
if (!node.right.is_constant_expression(scope)) break;
|
||||
var prop = node.left.property;
|
||||
if (prop instanceof AST_Node) {
|
||||
prop = prop.evaluate(compressor);
|
||||
}
|
||||
if (prop instanceof AST_Node) break;
|
||||
def.value.properties.push(make_node(AST_ObjectKeyVal, node, {
|
||||
key: prop,
|
||||
value: node.right
|
||||
}));
|
||||
exprs.shift();
|
||||
trimmed = true;
|
||||
} while (exprs.length);
|
||||
return trimmed && exprs;
|
||||
}
|
||||
|
||||
function join_consecutive_vars(statements, compressor) {
|
||||
var defs;
|
||||
for (var i = 0, j = -1, len = statements.length; i < len; i++) {
|
||||
@@ -1845,6 +1881,14 @@ merge(Compressor.prototype, {
|
||||
} else {
|
||||
statements[++j] = stat;
|
||||
}
|
||||
} else if (stat instanceof AST_SimpleStatement) {
|
||||
var exprs = join_object_assignments(prev, stat.body);
|
||||
if (exprs) {
|
||||
CHANGED = true;
|
||||
if (!exprs.length) continue;
|
||||
stat.body = make_sequence(stat.body, exprs);
|
||||
}
|
||||
statements[++j] = stat;
|
||||
} else {
|
||||
statements[++j] = stat;
|
||||
}
|
||||
@@ -2952,7 +2996,7 @@ merge(Compressor.prototype, {
|
||||
var node_def = def.name.definition();;
|
||||
initializations.add(node_def.id, def.value);
|
||||
if (def.name.fixed_value() === def.value) {
|
||||
fixed_ids[node_def.id] = true;
|
||||
fixed_ids[node_def.id] = def;
|
||||
}
|
||||
}
|
||||
if (def.value.has_side_effects(compressor)) {
|
||||
@@ -2988,9 +3032,7 @@ merge(Compressor.prototype, {
|
||||
var def = sym.definition();
|
||||
var in_use = def.id in in_use_ids;
|
||||
if (node instanceof AST_Assign) {
|
||||
if (!in_use
|
||||
|| def.id in fixed_ids
|
||||
&& node.left.fixed_value() !== node.right) {
|
||||
if (!in_use || def.id in fixed_ids && fixed_ids[def.id] !== node) {
|
||||
return maintain_this_binding(parent, node, node.right.transform(tt));
|
||||
}
|
||||
} else if (!in_use) return make_node(AST_Number, node, {
|
||||
@@ -3059,25 +3101,29 @@ merge(Compressor.prototype, {
|
||||
var sym = def.name.definition();
|
||||
if (drop_block && sym.global) return tail.push(def);
|
||||
if (!(drop_vars || drop_block) || sym.id in in_use_ids) {
|
||||
if (def.value && sym.id in fixed_ids && fixed_ids[sym.id] !== def) {
|
||||
def.value = def.value.drop_side_effect_free(compressor);
|
||||
}
|
||||
if (def.name instanceof AST_SymbolVar) {
|
||||
var var_defs = var_defs_by_id.get(sym.id);
|
||||
if (var_defs.length > 1 && (!def.value || sym.orig.indexOf(def.name) > sym.eliminated)) {
|
||||
compressor.warn("Dropping duplicated definition of variable {name} [{file}:{line},{col}]", template(def.name));
|
||||
if (def.value) {
|
||||
side_effects.push(make_node(AST_Assign, def, {
|
||||
var assign = make_node(AST_Assign, def, {
|
||||
operator: "=",
|
||||
left: make_node(AST_SymbolRef, def.name, def.name),
|
||||
right: def.value
|
||||
}).transform(tt));
|
||||
});
|
||||
if (fixed_ids[sym.id] === def) {
|
||||
fixed_ids[sym.id] = assign;
|
||||
}
|
||||
side_effects.push(assign.transform(tt));
|
||||
}
|
||||
remove(var_defs, def);
|
||||
sym.eliminated++;
|
||||
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 (side_effects.length > 0) {
|
||||
if (tail.length > 0) {
|
||||
@@ -3196,7 +3242,7 @@ merge(Compressor.prototype, {
|
||||
if (node instanceof AST_Assign) {
|
||||
node.right.walk(tw);
|
||||
if (node.left.fixed_value() === node.right) {
|
||||
fixed_ids[node_def.id] = true;
|
||||
fixed_ids[node_def.id] = node;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -3648,23 +3694,28 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
|
||||
function if_break_in_loop(self, compressor) {
|
||||
function drop_it(rest) {
|
||||
rest = as_statement_array(rest);
|
||||
if (self.body instanceof AST_BlockStatement) {
|
||||
self.body = self.body.clone();
|
||||
self.body.body = rest.concat(self.body.body.slice(1));
|
||||
self.body = self.body.transform(compressor);
|
||||
} else {
|
||||
self.body = make_node(AST_BlockStatement, self.body, {
|
||||
body: rest
|
||||
}).transform(compressor);
|
||||
}
|
||||
if_break_in_loop(self, compressor);
|
||||
}
|
||||
var first = self.body instanceof AST_BlockStatement ? self.body.body[0] : self.body;
|
||||
if (compressor.option("dead_code") && is_break(first)) {
|
||||
var body = [];
|
||||
if (self.init instanceof AST_Statement) {
|
||||
body.push(self.init);
|
||||
} else if (self.init) {
|
||||
body.push(make_node(AST_SimpleStatement, self.init, {
|
||||
body: self.init
|
||||
}));
|
||||
}
|
||||
if (self.condition) {
|
||||
body.push(make_node(AST_SimpleStatement, self.condition, {
|
||||
body: self.condition
|
||||
}));
|
||||
}
|
||||
extract_declarations_from_unreachable_code(compressor, self.body, body);
|
||||
return make_node(AST_BlockStatement, self, {
|
||||
body: body
|
||||
});
|
||||
}
|
||||
if (first instanceof AST_If) {
|
||||
if (first.body instanceof AST_Break
|
||||
&& compressor.loopcontrol_target(first.body) === compressor.self()) {
|
||||
if (is_break(first.body)) {
|
||||
if (self.condition) {
|
||||
self.condition = make_node(AST_Binary, self.condition, {
|
||||
left: self.condition,
|
||||
@@ -3675,9 +3726,7 @@ merge(Compressor.prototype, {
|
||||
self.condition = first.condition.negate(compressor);
|
||||
}
|
||||
drop_it(first.alternative);
|
||||
}
|
||||
else if (first.alternative instanceof AST_Break
|
||||
&& compressor.loopcontrol_target(first.alternative) === compressor.self()) {
|
||||
} else if (is_break(first.alternative)) {
|
||||
if (self.condition) {
|
||||
self.condition = make_node(AST_Binary, self.condition, {
|
||||
left: self.condition,
|
||||
@@ -3690,7 +3739,27 @@ merge(Compressor.prototype, {
|
||||
drop_it(first.body);
|
||||
}
|
||||
}
|
||||
};
|
||||
return self;
|
||||
|
||||
function is_break(node) {
|
||||
return node instanceof AST_Break
|
||||
&& compressor.loopcontrol_target(node) === compressor.self();
|
||||
}
|
||||
|
||||
function drop_it(rest) {
|
||||
rest = as_statement_array(rest);
|
||||
if (self.body instanceof AST_BlockStatement) {
|
||||
self.body = self.body.clone();
|
||||
self.body.body = rest.concat(self.body.body.slice(1));
|
||||
self.body = self.body.transform(compressor);
|
||||
} else {
|
||||
self.body = make_node(AST_BlockStatement, self.body, {
|
||||
body: rest
|
||||
}).transform(compressor);
|
||||
}
|
||||
self = if_break_in_loop(self, compressor);
|
||||
}
|
||||
}
|
||||
|
||||
OPT(AST_For, function(self, compressor){
|
||||
if (!compressor.option("loops")) return self;
|
||||
@@ -3726,8 +3795,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
}
|
||||
}
|
||||
if_break_in_loop(self, compressor);
|
||||
return self;
|
||||
return if_break_in_loop(self, compressor);
|
||||
});
|
||||
|
||||
OPT(AST_If, function(self, compressor){
|
||||
@@ -3983,9 +4051,20 @@ merge(Compressor.prototype, {
|
||||
OPT(AST_Try, function(self, compressor){
|
||||
tighten_body(self.body, compressor);
|
||||
if (self.bcatch && self.bfinally && all(self.bfinally.body, is_empty)) self.bfinally = null;
|
||||
if (all(self.body, is_empty)) {
|
||||
if (compressor.option("dead_code") && all(self.body, is_empty)) {
|
||||
var body = [];
|
||||
if (self.bcatch) extract_declarations_from_unreachable_code(compressor, self.bcatch, body);
|
||||
if (self.bcatch) {
|
||||
extract_declarations_from_unreachable_code(compressor, self.bcatch, body);
|
||||
body.forEach(function(stat) {
|
||||
if (!(stat instanceof AST_Definitions)) return;
|
||||
stat.definitions.forEach(function(var_def) {
|
||||
var def = var_def.name.definition().redefined();
|
||||
if (!def) return;
|
||||
var_def.name = var_def.name.clone();
|
||||
var_def.name.thedef = def;
|
||||
});
|
||||
});
|
||||
}
|
||||
if (self.bfinally) body = body.concat(self.bfinally.body);
|
||||
return make_node(AST_BlockStatement, self, {
|
||||
body: body
|
||||
@@ -5576,6 +5655,20 @@ merge(Compressor.prototype, {
|
||||
consequent
|
||||
]).optimize(compressor);
|
||||
}
|
||||
// x ? y || z : z --> x && y || z
|
||||
if (consequent instanceof AST_Binary
|
||||
&& consequent.operator == "||"
|
||||
&& consequent.right.equivalent_to(alternative)) {
|
||||
return make_node(AST_Binary, self, {
|
||||
operator: "||",
|
||||
left: make_node(AST_Binary, self, {
|
||||
operator: "&&",
|
||||
left: self.condition,
|
||||
right: consequent.left
|
||||
}),
|
||||
right: alternative
|
||||
}).optimize(compressor);
|
||||
}
|
||||
var in_bool = compressor.in_boolean_context();
|
||||
if (is_true(self.consequent)) {
|
||||
if (is_false(self.alternative)) {
|
||||
|
||||
Reference in New Issue
Block a user