Skip to content

Commit

Permalink
enhance loops (#3633)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexlamsl committed Dec 10, 2019
1 parent 18c2b18 commit 036bca9
Show file tree
Hide file tree
Showing 2 changed files with 162 additions and 13 deletions.
45 changes: 34 additions & 11 deletions lib/compress.js
Expand Up @@ -4718,8 +4718,8 @@ merge(Compressor.prototype, {
});

function 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 first = first_statement(self.body);
if (compressor.option("dead_code") && (breaks(first) || first instanceof AST_Exit)) {
var body = [];
if (self.init instanceof AST_Statement) {
body.push(self.init);
Expand All @@ -4728,18 +4728,28 @@ merge(Compressor.prototype, {
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: self.condition
}));
} else if (retain) {
body.push(first);
}
extract_declarations_from_unreachable_code(self.body, body);
return make_node(AST_BlockStatement, self, {
body: body
});
}
if (first instanceof AST_If) {
if (is_break(first.body)) {
var ab = first_statement(first.body);
if (breaks(ab)) {
if (self.condition) {
self.condition = make_node(AST_Binary, self.condition, {
left: self.condition,
Expand All @@ -4749,8 +4759,12 @@ merge(Compressor.prototype, {
} else {
self.condition = first.condition.negate(compressor);
}
drop_it(first.alternative);
} else if (is_break(first.alternative)) {
var body = as_statement_array(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) {
self.condition = make_node(AST_Binary, self.condition, {
left: self.condition,
Expand All @@ -4760,18 +4774,27 @@ merge(Compressor.prototype, {
} else {
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;

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
&& compressor.loopcontrol_target(node) === compressor.self();
|| node instanceof AST_Continue && external_target(node);
}

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));
Expand All @@ -4781,7 +4804,7 @@ merge(Compressor.prototype, {
body: rest
}).transform(compressor);
}
self = if_break_in_loop(self, compressor);
return if_break_in_loop(self, compressor);
}
}

Expand Down
130 changes: 128 additions & 2 deletions test/compress/loops.js
Expand Up @@ -574,9 +574,11 @@ issue_2740_3: {
console.log(x, y);
}
expect: {
L1: for (var x = 0; x < 3; x++)
for (var y = 0; y < 2; y++)
L1: for (var x = 0; x < 3; x++) {
var y = 0;
if (y < 2)
break L1;
}
console.log(x, y);
}
expect_stdout: "0 0"
Expand Down Expand Up @@ -753,3 +755,127 @@ empty_for_in_side_effects: {
"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"
}

0 comments on commit 036bca9

Please sign in to comment.