diff options
-rw-r--r-- | lib/compress.js | 76 | ||||
-rw-r--r-- | test/compress/reduce_vars.js | 68 | ||||
-rw-r--r-- | test/compress/switches.js (renamed from test/compress/switch.js) | 266 |
3 files changed, 321 insertions, 89 deletions
diff --git a/lib/compress.js b/lib/compress.js index c4aee690..3653a5fa 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -8424,7 +8424,6 @@ merge(Compressor.prototype, { OPT(AST_Switch, function(self, compressor) { if (!compressor.option("switches")) return self; - var branch; var value = self.expression.evaluate(compressor); if (!(value instanceof AST_Node)) { var orig = self.expression; @@ -8435,10 +8434,12 @@ merge(Compressor.prototype, { if (value instanceof AST_Node) { value = self.expression.evaluate(compressor, true); } - var decl = []; var body = []; + var branch; + var decl = []; var default_branch; var exact_match; + var side_effects = []; for (var i = 0, len = self.body.length; i < len && !exact_match; i++) { branch = self.body[i]; if (branch instanceof AST_Default) { @@ -8450,13 +8451,9 @@ merge(Compressor.prototype, { default_branch = branch; } } else if (!(value instanceof AST_Node)) { - var exp = branch.expression.evaluate(compressor); - if (!(exp instanceof AST_Node) && exp !== value) { - eliminate_branch(branch, body[body.length - 1]); - continue; - } - if (exp instanceof AST_Node) exp = branch.expression.evaluate(compressor, true); - if (exp === value) { + var exp = branch.expression; + var val = exp.evaluate(compressor, true); + if (val === value) { exact_match = branch; if (default_branch) { var default_index = body.indexOf(default_branch); @@ -8464,18 +8461,41 @@ merge(Compressor.prototype, { eliminate_branch(default_branch, body[default_index - 1]); default_branch = null; } + } else if (!(val instanceof AST_Node)) { + if (exp.has_side_effects(compressor)) side_effects.push(exp); + eliminate_branch(branch, body[body.length - 1]); + continue; } } - if (aborts(branch)) { + if (exact_match || i == len - 1 || aborts(branch)) { var prev = body[body.length - 1]; - if (aborts(prev) && prev.body.length == branch.body.length - && make_node(AST_BlockStatement, prev, prev).equivalent_to(make_node(AST_BlockStatement, branch, branch))) { - prev.body = []; + var statements = branch.body; + if (aborts(prev)) switch (prev.body.length - statements.length) { + case 1: + var stat = prev.body[prev.body.length - 1]; + if (!is_break(stat, compressor)) break; + statements = statements.concat(stat); + case 0: + var prev_block = make_node(AST_BlockStatement, prev, prev); + var next_block = make_node(AST_BlockStatement, branch, { body: statements }); + if (prev_block.equivalent_to(next_block)) prev.body = []; + } + } + if (side_effects.length) { + if (branch instanceof AST_Default) { + body.push(make_node(AST_Case, self, { expression: make_sequence(self, side_effects), body: [] })); + } else { + side_effects.push(branch.expression); + branch.expression = make_sequence(self, side_effects); } + side_effects = []; } body.push(branch); } while (i < len) eliminate_branch(self.body[i++], body[body.length - 1]); + if (side_effects.length && !exact_match) { + body.push(make_node(AST_Case, self, { expression: make_sequence(self, side_effects), body: [] })); + } while (branch = body[body.length - 1]) { var stat = branch.body[branch.body.length - 1]; if (is_break(stat, compressor)) branch.body.pop(); @@ -8492,12 +8512,30 @@ merge(Compressor.prototype, { eliminate_branch(branch); if (body.pop() === default_branch) default_branch = null; } - if (body.length == 0) { - return make_node(AST_BlockStatement, self, { - body: decl.concat(make_node(AST_SimpleStatement, self.expression, { - body: self.expression - })) - }).optimize(compressor); + if (!branch) { + decl.push(make_node(AST_SimpleStatement, self.expression, { body: self.expression })); + if (side_effects.length) decl.push(make_node(AST_SimpleStatement, self, { + body: make_sequence(self, side_effects), + })); + return make_node(AST_BlockStatement, self, { body: decl }).optimize(compressor); + } + if (exact_match ? !branch.expression.has_side_effects(compressor) : branch === default_branch) { + while (branch = body[body.length - 2]) { + if (branch instanceof AST_Default) break; + if (!has_declarations_only(branch)) break; + var exp = branch.expression; + if (exp.has_side_effects(compressor)) { + var prev = body[body.length - 3]; + if (prev && !aborts(prev)) break; + if (exact_match) { + exact_match.expression = make_sequence(self, [ exp, exact_match.expression ]); + } else { + default_branch.body.unshift(make_node(AST_SimpleStatement, self, { body: exp })); + } + } + eliminate_branch(branch); + body.splice(-2, 1); + } } body[0].body = decl.concat(body[0].body); self.body = body; diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js index 33d59982..69f86523 100644 --- a/test/compress/reduce_vars.js +++ b/test/compress/reduce_vars.js @@ -2072,72 +2072,6 @@ issue_1670_2: { issue_1670_3: { options = { - comparisons: true, - conditionals: true, - dead_code: true, - evaluate: true, - reduce_funcs: true, - reduce_vars: true, - side_effects: true, - switches: true, - typeofs: true, - unused: true, - } - input: { - (function f() { - switch (1) { - case 0: - var a = true; - break; - case 1: - if (typeof a === "undefined") console.log("PASS"); - else console.log("FAIL"); - } - })(); - } - expect: { - (function() { - var a; - void 0 === a ? console.log("PASS") : console.log("FAIL"); - })(); - } - expect_stdout: "PASS" -} - -issue_1670_4: { - options = { - conditionals: true, - dead_code: true, - evaluate: true, - passes: 2, - reduce_funcs: true, - reduce_vars: true, - side_effects: true, - switches: true, - unused: true, - } - input: { - (function f() { - switch (1) { - case 0: - var a = true; - break; - case 1: - if (typeof a === "undefined") console.log("PASS"); - else console.log("FAIL"); - } - })(); - } - expect: { - (function() { - console.log("PASS"); - })(); - } - expect_stdout: "PASS" -} - -issue_1670_5: { - options = { conditionals: true, dead_code: true, evaluate: true, @@ -2168,7 +2102,7 @@ issue_1670_5: { expect_stdout: "1" } -issue_1670_6: { +issue_1670_4: { options = { conditionals: true, dead_code: true, diff --git a/test/compress/switch.js b/test/compress/switches.js index e3f6859d..955fd68a 100644 --- a/test/compress/switch.js +++ b/test/compress/switches.js @@ -300,6 +300,37 @@ drop_default_2: { } } +drop_default_3: { + options = { + dead_code: true, + evaluate: true, + switches: true, + } + input: { + function f() { + console.log("PASS"); + return 42; + } + switch (42) { + case f(): + break; + case void console.log("FAIL"): + default: + } + } + expect: { + function f() { + console.log("PASS"); + return 42; + } + switch (42) { + case f(): + case void console.log("FAIL"): + } + } + expect_stdout: "PASS" +} + keep_default: { options = { dead_code: true, @@ -423,7 +454,6 @@ drop_case_3: { switch ({}.p) { default: case void 0: - break; case c = "FAIL": } console.log(c); @@ -454,7 +484,166 @@ drop_case_4: { expect_stdout: "PASS" } -keep_case: { +drop_case_5: { + options = { + dead_code: true, + evaluate: true, + switches: true, + } + input: { + switch (42) { + case void console.log("PASS 1"): + console.log("FAIL 1"); + case 42: + case console.log("FAIL 2"): + console.log("PASS 2"); + } + } + expect: { + switch (42) { + case (void console.log("PASS 1"), 42): + console.log("PASS 2"); + } + } + expect_stdout: [ + "PASS 1", + "PASS 2", + ] +} + +drop_case_6: { + options = { + dead_code: true, + evaluate: true, + switches: true, + } + input: { + switch (console.log("PASS 1"), 2) { + case 0: + console.log("FAIL 1"); + case (console.log("PASS 2"), 1): + console.log("FAIL 2"); + } + } + expect: { + switch (console.log("PASS 1"), 2) { + case (console.log("PASS 2"), 1): + } + } + expect_stdout: [ + "PASS 1", + "PASS 2", + ] +} + +drop_case_7: { + options = { + dead_code: true, + evaluate: true, + switches: true, + } + input: { + switch (2) { + case 0: + console.log("FAIL 1"); + case (console.log("PASS 1"), 1): + console.log("FAIL 2"); + case 2: + console.log("PASS 2"); + } + } + expect: { + switch (2) { + case (console.log("PASS 1"), 1, 2): + console.log("PASS 2"); + } + } + expect_stdout: [ + "PASS 1", + "PASS 2", + ] +} + +drop_case_8: { + options = { + dead_code: true, + switches: true, + } + input: { + function log(msg) { + console.log(msg); + return msg; + } + switch (log("foo")) { + case "bar": + log("moo"); + break; + case log("baz"): + log("moo"); + break; + default: + log("moo"); + } + } + expect: { + function log(msg) { + console.log(msg); + return msg; + } + switch (log("foo")) { + case "bar": + case log("baz"): + default: + log("moo"); + } + } + expect_stdout: [ + "foo", + "baz", + "moo", + ] +} + +drop_case_9: { + options = { + dead_code: true, + switches: true, + } + input: { + function log(msg) { + console.log(msg); + return msg; + } + switch (log("foo")) { + case log("bar"): + log("moo"); + break; + case "baz": + log("moo"); + break; + default: + log("moo"); + } + } + expect: { + function log(msg) { + console.log(msg); + return msg; + } + switch (log("foo")) { + default: + log("bar"); + log("moo"); + } + } + expect_stdout: [ + "foo", + "bar", + "moo", + ] +} + +keep_case_1: { options = { dead_code: true, switches: true, @@ -474,6 +663,76 @@ keep_case: { } } +keep_case_2: { + options = { + dead_code: true, + evaluate: true, + switches: true, + } + input: { + switch ("foo") { + case console.log("bar"): + case console.log("baz"), "moo": + } + } + expect: { + switch ("foo") { + case console.log("bar"): + case console.log("baz"), "moo": + } + } + expect_stdout: [ + "bar", + "baz", + ] +} + +keep_case_3: { + options = { + dead_code: true, + evaluate: true, + switches: true, + } + input: { + var a; + switch (void console.log("PASS")) { + case a: + case console.log("FAIL"), 42: + } + } + expect: { + var a; + switch (void console.log("PASS")) { + case a: + case console.log("FAIL"), 42: + } + } + expect_stdout: "PASS" +} + +keep_case_4: { + options = { + dead_code: true, + evaluate: true, + switches: true, + } + input: { + var a; + switch (void console.log("PASS")) { + case a: + case void console.log("FAIL"): + } + } + expect: { + var a; + switch (void console.log("PASS")) { + case a: + case void console.log("FAIL"): + } + } + expect_stdout: "PASS" +} + issue_376: { options = { dead_code: true, @@ -1088,7 +1347,8 @@ drop_switch_6: { } } expect: { - A === B; + A; + B; x(); C !== D; y(); |