From 59ed23a9e9dee42d884e35ebf9e9862ea3724c4b Mon Sep 17 00:00:00 2001 From: Boopathi Rajaa Date: Wed, 25 Jan 2017 15:29:48 +0100 Subject: [PATCH] Moar optimizations for side-effecty if statements --- .../__tests__/dead-code-elimination-test.js | 34 ++++++++++++++- .../src/index.js | 42 ++++++++++++++----- 2 files changed, 64 insertions(+), 12 deletions(-) diff --git a/packages/babel-plugin-minify-dead-code-elimination/__tests__/dead-code-elimination-test.js b/packages/babel-plugin-minify-dead-code-elimination/__tests__/dead-code-elimination-test.js index 34952c60f..be4f9265c 100644 --- a/packages/babel-plugin-minify-dead-code-elimination/__tests__/dead-code-elimination-test.js +++ b/packages/babel-plugin-minify-dead-code-elimination/__tests__/dead-code-elimination-test.js @@ -2422,12 +2422,42 @@ describe("dce-plugin", () => { expect(transform(source)).toBe(expected); }); - it("should deopt impure expressions in if statements", () => { + it("should impure expressions in confidently evaluated if statements", () => { const source = unpad(` if (a.b(), true) { foo(); } `); - expect(transform(source)).toBe(source); + const expected = unpad(` + a.b(); + + foo(); + `); + expect(transform(source)).toBe(expected); + }); + + it("should extract all necessary things from if statements", () => { + const source = unpad(` + if (a.b(), false) { + var foo = foo1; + foo(); + } else if (b.c(), true) { + var bar = bar1; + bar(); + } else { + var baz = baz1; + baz(); + } + `); + const expected = unpad(` + a.b(); + b.c(); + + var bar = bar1; + bar(); + var baz; + var foo; + `); + expect(transform(source)).toBe(expected); }); }); diff --git a/packages/babel-plugin-minify-dead-code-elimination/src/index.js b/packages/babel-plugin-minify-dead-code-elimination/src/index.js index 7c4583314..d795912cd 100644 --- a/packages/babel-plugin-minify-dead-code-elimination/src/index.js +++ b/packages/babel-plugin-minify-dead-code-elimination/src/index.js @@ -640,9 +640,16 @@ module.exports = ({ types: t, traverse }) => { const alternate = path.get("alternate"); const test = path.get("test"); + const evalResult = test.evaluate(); const isPure = test.isPure(); - const evaluateTest = test.evaluateTruthy(); + const replacements = []; + + if (evalResult.confident && !isPure && test.isSequenceExpression()) { + replacements.push( + t.expressionStatement(extractSequenceImpure(test)) + ); + } // we can check if a test will be truthy 100% and if so then we can inline // the consequent and completely ignore the alternate @@ -650,10 +657,10 @@ module.exports = ({ types: t, traverse }) => { // if (true) { foo; } -> { foo; } // if ("foo") { foo; } -> { foo; } // - if (isPure && evaluateTest === true) { - path.replaceWithMultiple( - [...toStatements(consequent), ...extractVars(alternate)] - ); + if (evalResult.confident && evalResult.value) { + path.replaceWithMultiple([ + ...replacements, ...toStatements(consequent), ...extractVars(alternate) + ]); return; } @@ -663,14 +670,16 @@ module.exports = ({ types: t, traverse }) => { // if ("") { bar; } else { foo; } -> { foo; } // if ("") { bar; } -> // - if (isPure && evaluateTest === false) { + if (evalResult.confident && !evalResult.value) { if (alternate.node) { - path.replaceWithMultiple( - [...toStatements(alternate), ...extractVars(consequent)] - ); + path.replaceWithMultiple([ + ...replacements, ...toStatements(alternate), ...extractVars(consequent) + ]); return; } else { - path.replaceWithMultiple(extractVars(consequent)); + path.replaceWithMultiple([ + ...replacements, ...extractVars(consequent) + ]); } } @@ -700,11 +709,13 @@ module.exports = ({ types: t, traverse }) => { } }, }, + EmptyStatement(path) { if (path.parentPath.isBlockStatement() || path.parentPath.isProgram()) { path.remove(); } }, + Program: { exit(path, { opts: { @@ -1026,4 +1037,15 @@ module.exports = ({ types: t, traverse }) => { } while (parent = parent.parentPath); return false; } + + function extractSequenceImpure(seq) { + const expressions = seq.get("expressions"); + const result = []; + for (let i = 0; i < expressions.length; i++) { + if (!expressions[i].isPure()) { + result.push(expressions[i].node); + } + } + return t.sequenceExpression(result); + } };