improve compression of loop conditions (#2543)
This commit is contained in:
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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}"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user