improve compression of loop conditions (#2543)

This commit is contained in:
Alex Lam S.L
2017-12-01 05:52:33 +08:00
committed by GitHub
parent 172079a47f
commit b762f2d6f4
6 changed files with 64 additions and 46 deletions

View File

@@ -3020,34 +3020,40 @@ merge(Compressor.prototype, {
return self; return self;
}); });
OPT(AST_DWLoop, function(self, compressor){ OPT(AST_While, function(self, compressor){
return compressor.option("loops") ? make_node(AST_For, self, self).optimize(compressor) : self;
});
OPT(AST_Do, function(self, compressor){
if (!compressor.option("loops")) return self; if (!compressor.option("loops")) return self;
var cond = self.condition.evaluate(compressor); var cond = self.condition.tail_node().evaluate(compressor);
if (cond !== self.condition) { if (!(cond instanceof AST_Node)) {
if (cond) { if (cond) return make_node(AST_For, self, {
return make_node(AST_For, self, { body: make_node(AST_BlockStatement, self.body, {
body: self.body body: [
}); self.body,
} make_node(AST_SimpleStatement, self.condition, {
if (compressor.option("dead_code") && self instanceof AST_While) { body: self.condition
var a = []; })
extract_declarations_from_unreachable_code(compressor, self.body, a); ]
return make_node(AST_BlockStatement, self, { body: a }).optimize(compressor); })
} }).optimize(compressor);
if (self instanceof AST_Do) { var has_loop_control = false;
var has_loop_control = false; var tw = new TreeWalker(function(node) {
var tw = new TreeWalker(function(node) { if (node instanceof AST_Scope || has_loop_control) return true;
if (node instanceof AST_Scope || has_loop_control) return true; if (node instanceof AST_LoopControl && tw.loopcontrol_target(node) === self)
if (node instanceof AST_LoopControl && tw.loopcontrol_target(node) === self) return has_loop_control = true;
return has_loop_control = true; });
}); var parent = compressor.parent();
var parent = compressor.parent(); (parent instanceof AST_LabeledStatement ? parent : self).walk(tw);
(parent instanceof AST_LabeledStatement ? parent : self).walk(tw); if (!has_loop_control) return make_node(AST_BlockStatement, self.body, {
if (!has_loop_control) return self.body; body: [
} self.body,
} make_node(AST_SimpleStatement, self.condition, {
if (self instanceof AST_While) { body: self.condition
return make_node(AST_For, self, self).optimize(compressor); })
]
}).optimize(compressor);
} }
return self; return self;
}); });
@@ -3101,22 +3107,31 @@ merge(Compressor.prototype, {
if (!compressor.option("loops")) return self; if (!compressor.option("loops")) return self;
if (self.condition) { if (self.condition) {
var cond = self.condition.evaluate(compressor); var cond = self.condition.evaluate(compressor);
if (compressor.option("dead_code") && !cond) { if (!(cond instanceof AST_Node)) {
var a = []; if (cond) self.condition = null;
if (self.init instanceof AST_Statement) { else if (!compressor.option("dead_code")) {
a.push(self.init); var orig = self.condition;
self.condition = make_node_from_constant(cond, self.condition);
self.condition = best_of_expression(self.condition.transform(compressor), orig);
} }
else if (self.init) {
a.push(make_node(AST_SimpleStatement, self.init, {
body: self.init
}));
}
extract_declarations_from_unreachable_code(compressor, self.body, a);
return make_node(AST_BlockStatement, self, { body: a }).optimize(compressor);
} }
if (cond !== self.condition) { if (compressor.option("dead_code")) {
cond = make_node_from_constant(cond, self.condition).transform(compressor); if (cond instanceof AST_Node) cond = self.condition.tail_node().evaluate(compressor);
self.condition = best_of_expression(cond, self.condition); if (!cond) {
var body = [];
extract_declarations_from_unreachable_code(compressor, self.body, body);
body.push(make_node(AST_SimpleStatement, self.condition, {
body: self.condition
}));
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
}));
}
return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor);
}
} }
} }
if_break_in_loop(self, compressor); if_break_in_loop(self, compressor);

View File

@@ -129,8 +129,8 @@ dead_code_constant_boolean_should_warn_more: {
function bar() {} function bar() {}
// nothing for the while // nothing for the while
// as for the for, it should keep: // as for the for, it should keep:
var x = 10, y;
var moo; var moo;
var x = 10, y;
bar(); bar();
} }
expect_stdout: true expect_stdout: true
@@ -165,8 +165,8 @@ dead_code_constant_boolean_should_warn_more_strict: {
var foo; var foo;
// nothing for the while // nothing for the while
// as for the for, it should keep: // as for the for, it should keep:
var x = 10, y;
var moo; var moo;
var x = 10, y;
bar(); bar();
} }
expect_stdout: true expect_stdout: true

View File

@@ -39,7 +39,7 @@ f7: {
"var b = 10;", "var b = 10;",
"", "",
"!function() {", "!function() {",
" for (;b = 100, !1; ) ;", " b = 100;",
"}(), console.log(100, b);", "}(), console.log(100, b);",
] ]
expect_stdout: true expect_stdout: true

View File

@@ -134,5 +134,5 @@ label_while: {
L: while (0) continue L; L: while (0) continue L;
} }
} }
expect_exact: "function f(){L:;}" expect_exact: "function f(){L:0}"
} }

View File

@@ -148,9 +148,11 @@ parse_do_while_without_semicolon: {
evaluate: { evaluate: {
options = { options = {
loops: true,
dead_code: true, dead_code: true,
evaluate: true, evaluate: true,
loops: true,
passes: 2,
side_effects: true,
}; };
input: { input: {
while (true) { while (true) {

View File

@@ -1209,6 +1209,7 @@ toplevel_on_loops_2: {
loops: true, loops: true,
reduce_funcs: true, reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true,
toplevel:true, toplevel:true,
unused: true, unused: true,
} }