From ce27bcd69a0a66bf145ee2f14927a3cfec9b0202 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Mon, 8 Jan 2018 14:30:18 +0800 Subject: [PATCH] compress loops with immediate `break` (#2746) fixes #2740 --- lib/compress.js | 62 ++++++++++++++-------- test/compress/loops.js | 113 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+), 20 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index 011bb1b4..70163656 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -3417,23 +3417,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); + 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 + })); } - if_break_in_loop(self, compressor); + extract_declarations_from_unreachable_code(compressor, self.body, body); + return make_node(AST_BlockStatement, self, { + body: body + }); } - var first = self.body instanceof AST_BlockStatement ? self.body.body[0] : self.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, @@ -3444,9 +3449,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, @@ -3459,7 +3462,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; @@ -3495,8 +3518,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){ diff --git a/test/compress/loops.js b/test/compress/loops.js index 3538c221..a6ebd359 100644 --- a/test/compress/loops.js +++ b/test/compress/loops.js @@ -492,3 +492,116 @@ dead_code_condition: { } expect_stdout: "1" } + +issue_2740_1: { + options = { + dead_code: true, + loops: true, + } + input: { + for (; ; ) break; + for (a(); ; ) break; + for (; b(); ) break; + for (c(); d(); ) break; + for (; ; e()) break; + for (f(); ; g()) break; + for (; h(); i()) break; + for (j(); k(); l()) break; + } + expect: { + a(); + b(); + c(); + d(); + f(); + h(); + j(); + k(); + } +} + +issue_2740_2: { + options = { + dead_code: true, + loops: true, + passes: 2, + } + input: { + L1: while (x()) { + break L1; + } + } + expect: { + x(); + } +} + +issue_2740_3: { + options = { + dead_code: true, + loops: true, + } + input: { + L1: for (var x = 0; x < 3; x++) { + L2: for (var y = 0; y < 2; y++) { + break L1; + } + } + console.log(x, y); + } + expect: { + L1: for (var x = 0; x < 3; x++) + for (var y = 0; y < 2; y++) + break L1; + console.log(x, y); + } + expect_stdout: "0 0" +} + +issue_2740_4: { + options = { + dead_code: true, + loops: true, + passes: 2, + } + input: { + L1: for (var x = 0; x < 3; x++) { + L2: for (var y = 0; y < 2; y++) { + break L2; + } + } + console.log(x, y); + } + expect: { + for (var x = 0; x < 3; x++) { + var y = 0; + y < 2; + } + console.log(x, y); + } + expect_stdout: "3 0" +} + +issue_2740_5: { + options = { + dead_code: true, + loops: true, + passes: 2, + } + input: { + L1: for (var x = 0; x < 3; x++) { + break L1; + L2: for (var y = 0; y < 2; y++) { + break L2; + } + } + console.log(x, y); + } + expect: { + var x = 0; + x < 3; + var y; + console.log(x,y); + } + expect_stdout: "0 undefined" +} -- 2.34.1