enhance loops (#3633)
This commit is contained in:
@@ -4718,8 +4718,8 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function if_break_in_loop(self, compressor) {
|
function if_break_in_loop(self, compressor) {
|
||||||
var first = self.body instanceof AST_BlockStatement ? self.body.body[0] : self.body;
|
var first = first_statement(self.body);
|
||||||
if (compressor.option("dead_code") && is_break(first)) {
|
if (compressor.option("dead_code") && (breaks(first) || first instanceof AST_Exit)) {
|
||||||
var body = [];
|
var body = [];
|
||||||
if (self.init instanceof AST_Statement) {
|
if (self.init instanceof AST_Statement) {
|
||||||
body.push(self.init);
|
body.push(self.init);
|
||||||
@@ -4728,10 +4728,19 @@ merge(Compressor.prototype, {
|
|||||||
body: self.init
|
body: self.init
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
if (self.condition) {
|
var retain = external_target(first) || first instanceof AST_Exit;
|
||||||
|
if (self.condition && retain) {
|
||||||
|
body.push(make_node(AST_If, self, {
|
||||||
|
condition: self.condition,
|
||||||
|
body: first,
|
||||||
|
alternative: null
|
||||||
|
}));
|
||||||
|
} else if (self.condition) {
|
||||||
body.push(make_node(AST_SimpleStatement, self.condition, {
|
body.push(make_node(AST_SimpleStatement, self.condition, {
|
||||||
body: self.condition
|
body: self.condition
|
||||||
}));
|
}));
|
||||||
|
} else if (retain) {
|
||||||
|
body.push(first);
|
||||||
}
|
}
|
||||||
extract_declarations_from_unreachable_code(self.body, body);
|
extract_declarations_from_unreachable_code(self.body, body);
|
||||||
return make_node(AST_BlockStatement, self, {
|
return make_node(AST_BlockStatement, self, {
|
||||||
@@ -4739,7 +4748,8 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (first instanceof AST_If) {
|
if (first instanceof AST_If) {
|
||||||
if (is_break(first.body)) {
|
var ab = first_statement(first.body);
|
||||||
|
if (breaks(ab)) {
|
||||||
if (self.condition) {
|
if (self.condition) {
|
||||||
self.condition = make_node(AST_Binary, self.condition, {
|
self.condition = make_node(AST_Binary, self.condition, {
|
||||||
left: self.condition,
|
left: self.condition,
|
||||||
@@ -4749,8 +4759,12 @@ merge(Compressor.prototype, {
|
|||||||
} else {
|
} else {
|
||||||
self.condition = first.condition.negate(compressor);
|
self.condition = first.condition.negate(compressor);
|
||||||
}
|
}
|
||||||
drop_it(first.alternative);
|
var body = as_statement_array(first.alternative);
|
||||||
} else if (is_break(first.alternative)) {
|
extract_declarations_from_unreachable_code(first.body, body);
|
||||||
|
return drop_it(body);
|
||||||
|
}
|
||||||
|
ab = first_statement(first.alternative);
|
||||||
|
if (breaks(ab)) {
|
||||||
if (self.condition) {
|
if (self.condition) {
|
||||||
self.condition = make_node(AST_Binary, self.condition, {
|
self.condition = make_node(AST_Binary, self.condition, {
|
||||||
left: self.condition,
|
left: self.condition,
|
||||||
@@ -4760,18 +4774,27 @@ merge(Compressor.prototype, {
|
|||||||
} else {
|
} else {
|
||||||
self.condition = first.condition;
|
self.condition = first.condition;
|
||||||
}
|
}
|
||||||
drop_it(first.body);
|
var body = as_statement_array(first.body);
|
||||||
|
extract_declarations_from_unreachable_code(first.alternative, body);
|
||||||
|
return drop_it(body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
|
|
||||||
function is_break(node) {
|
function first_statement(body) {
|
||||||
|
return body instanceof AST_BlockStatement ? body.body[0] : body;
|
||||||
|
}
|
||||||
|
|
||||||
|
function external_target(node) {
|
||||||
|
return compressor.loopcontrol_target(node) !== compressor.self();
|
||||||
|
}
|
||||||
|
|
||||||
|
function breaks(node) {
|
||||||
return node instanceof AST_Break
|
return node instanceof AST_Break
|
||||||
&& compressor.loopcontrol_target(node) === compressor.self();
|
|| node instanceof AST_Continue && external_target(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
function drop_it(rest) {
|
function drop_it(rest) {
|
||||||
rest = as_statement_array(rest);
|
|
||||||
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));
|
||||||
@@ -4781,7 +4804,7 @@ merge(Compressor.prototype, {
|
|||||||
body: rest
|
body: rest
|
||||||
}).transform(compressor);
|
}).transform(compressor);
|
||||||
}
|
}
|
||||||
self = if_break_in_loop(self, compressor);
|
return if_break_in_loop(self, compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -574,9 +574,11 @@ issue_2740_3: {
|
|||||||
console.log(x, y);
|
console.log(x, y);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
L1: for (var x = 0; x < 3; x++)
|
L1: for (var x = 0; x < 3; x++) {
|
||||||
for (var y = 0; y < 2; y++)
|
var y = 0;
|
||||||
|
if (y < 2)
|
||||||
break L1;
|
break L1;
|
||||||
|
}
|
||||||
console.log(x, y);
|
console.log(x, y);
|
||||||
}
|
}
|
||||||
expect_stdout: "0 0"
|
expect_stdout: "0 0"
|
||||||
@@ -753,3 +755,127 @@ empty_for_in_side_effects: {
|
|||||||
"WARN: Side effects in object of for-in loop [test/compress/loops.js:1,17]",
|
"WARN: Side effects in object of for-in loop [test/compress/loops.js:1,17]",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_3631_1: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
evaluate: true,
|
||||||
|
loops: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var c = 0;
|
||||||
|
L: do {
|
||||||
|
for (;;) continue L;
|
||||||
|
var b = 1;
|
||||||
|
} while (b && c++);
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var c = 0;
|
||||||
|
do {
|
||||||
|
var b;
|
||||||
|
} while (b && c++);
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect_stdout: "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_3631_2: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
evaluate: true,
|
||||||
|
loops: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
L: for (var a = 1; a--; console.log(b)) {
|
||||||
|
for (;;) continue L;
|
||||||
|
var b = "FAIL";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
for (var a = 1; a--; console.log(b))
|
||||||
|
var b;
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
loop_if_break: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
loops: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a, b) {
|
||||||
|
try {
|
||||||
|
while (a) {
|
||||||
|
if (b) {
|
||||||
|
break;
|
||||||
|
var c = 42;
|
||||||
|
console.log(c);
|
||||||
|
} else {
|
||||||
|
var d = false;
|
||||||
|
throw d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log("E:", e);
|
||||||
|
}
|
||||||
|
console.log(a, b, c, d);
|
||||||
|
}
|
||||||
|
f(0, 0);
|
||||||
|
f(0, 1);
|
||||||
|
f(1, 0);
|
||||||
|
f(1, 1);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a, b) {
|
||||||
|
try {
|
||||||
|
for (;a && !b;) {
|
||||||
|
var d = false;
|
||||||
|
throw d;
|
||||||
|
var c;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log("E:", e);
|
||||||
|
}
|
||||||
|
console.log(a, b, c, d);
|
||||||
|
}
|
||||||
|
f(0, 0);
|
||||||
|
f(0, 1);
|
||||||
|
f(1, 0);
|
||||||
|
f(1, 1);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"0 0 undefined undefined",
|
||||||
|
"0 1 undefined undefined",
|
||||||
|
"E: false",
|
||||||
|
"1 0 undefined false",
|
||||||
|
"1 1 undefined undefined",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
loop_return: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
loops: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a) {
|
||||||
|
while (a) return 42;
|
||||||
|
return "foo";
|
||||||
|
}
|
||||||
|
console.log(f(0), f(1));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a) {
|
||||||
|
if (a) return 42;
|
||||||
|
return "foo";
|
||||||
|
}
|
||||||
|
console.log(f(0), f(1));
|
||||||
|
}
|
||||||
|
expect_stdout: "foo 42"
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user