From 6e2ec17d51e709b856210ca8412e09f560eb71f0 Mon Sep 17 00:00:00 2001 From: Boshen <1430279+Boshen@users.noreply.github.com> Date: Fri, 3 Jan 2025 10:07:04 +0000 Subject: [PATCH] feat(minifier): statement fusion switch cases; improved minimize exit poitns (#8228) --- .../src/ast_passes/minimize_exit_points.rs | 17 +++++++++++++--- crates/oxc_minifier/src/ast_passes/mod.rs | 10 +--------- .../src/ast_passes/statement_fusion.rs | 17 +++++++--------- tasks/minsize/minsize.snap | 20 +++++++++---------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/crates/oxc_minifier/src/ast_passes/minimize_exit_points.rs b/crates/oxc_minifier/src/ast_passes/minimize_exit_points.rs index 38d70ede7..3792787f5 100644 --- a/crates/oxc_minifier/src/ast_passes/minimize_exit_points.rs +++ b/crates/oxc_minifier/src/ast_passes/minimize_exit_points.rs @@ -56,9 +56,12 @@ impl<'a> MinimizeExitPoints { let body = ctx.ast.vec_from_iter(stmts_rest.iter_mut().map(|s| ctx.ast.move_statement(s))); let Statement::IfStatement(if_stmt) = &mut stmts[index] else { unreachable!() }; let scope_id = ctx.create_child_scope_of_current(ScopeFlags::empty()); - let argument = ctx.ast.move_expression(&mut if_stmt.test); - if_stmt.test = - ctx.ast.expression_unary(argument.span(), UnaryOperator::LogicalNot, argument); + if_stmt.test = match ctx.ast.move_expression(&mut if_stmt.test) { + Expression::UnaryExpression(unary_expr) if unary_expr.operator.is_not() => { + unary_expr.unbox().argument + } + e => ctx.ast.expression_unary(e.span(), UnaryOperator::LogicalNot, e), + }; if_stmt.alternate = None; if_stmt.consequent = Statement::BlockStatement( ctx.ast.alloc_block_statement_with_scope_id(SPAN, body, scope_id), @@ -90,10 +93,18 @@ mod test { "function foo() { if (foo) return; bar; quaz; }", "function foo() { if (!foo) { bar; quaz; } }", ); + fold( + "function foo() { if (!foo) return; bar; quaz; }", + "function foo() { if (foo) { bar; quaz; } }", + ); fold( "function foo() { x; if (foo) return; bar; quaz; }", "function foo() { x; if (!foo) { bar; quaz; } }", ); + fold( + "function foo() { x; if (!foo) return; bar; quaz; }", + "function foo() { x; if (foo) { bar; quaz; } }", + ); fold_same("function foo() { if (foo) return }"); fold_same("function foo() { if (foo) return bar; baz }"); } diff --git a/crates/oxc_minifier/src/ast_passes/mod.rs b/crates/oxc_minifier/src/ast_passes/mod.rs index 460c808a1..fae87b843 100644 --- a/crates/oxc_minifier/src/ast_passes/mod.rs +++ b/crates/oxc_minifier/src/ast_passes/mod.rs @@ -120,15 +120,11 @@ impl<'a> CompressorPass<'a> for PeepholeOptimizations { impl<'a> Traverse<'a> for PeepholeOptimizations { fn exit_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) { - self.x0_statement_fusion.exit_program(program, ctx); self.x4_peephole_remove_dead_code.exit_program(program, ctx); } - fn exit_function_body(&mut self, body: &mut FunctionBody<'a>, ctx: &mut TraverseCtx<'a>) { - self.x0_statement_fusion.exit_function_body(body, ctx); - } - fn exit_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) { + self.x0_statement_fusion.exit_statements(stmts, ctx); self.x1_minimize_exit_points.exit_statements(stmts, ctx); self.x2_exploit_assigns.exit_statements(stmts, ctx); self.x3_collapse_variable_declarations.exit_statements(stmts, ctx); @@ -141,10 +137,6 @@ impl<'a> Traverse<'a> for PeepholeOptimizations { self.x5_peephole_minimize_conditions.exit_statement(stmt, ctx); } - fn exit_block_statement(&mut self, block: &mut BlockStatement<'a>, ctx: &mut TraverseCtx<'a>) { - self.x0_statement_fusion.exit_block_statement(block, ctx); - } - fn exit_return_statement(&mut self, stmt: &mut ReturnStatement<'a>, ctx: &mut TraverseCtx<'a>) { self.x6_peephole_substitute_alternate_syntax.exit_return_statement(stmt, ctx); } diff --git a/crates/oxc_minifier/src/ast_passes/statement_fusion.rs b/crates/oxc_minifier/src/ast_passes/statement_fusion.rs index 4d16abd89..32b6eec51 100644 --- a/crates/oxc_minifier/src/ast_passes/statement_fusion.rs +++ b/crates/oxc_minifier/src/ast_passes/statement_fusion.rs @@ -23,16 +23,8 @@ impl<'a> CompressorPass<'a> for StatementFusion { } impl<'a> Traverse<'a> for StatementFusion { - fn exit_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) { - self.fuse_statements(&mut program.body, ctx); - } - - fn exit_function_body(&mut self, body: &mut FunctionBody<'a>, ctx: &mut TraverseCtx<'a>) { - self.fuse_statements(&mut body.statements, ctx); - } - - fn exit_block_statement(&mut self, block: &mut BlockStatement<'a>, ctx: &mut TraverseCtx<'a>) { - self.fuse_statements(&mut block.body, ctx); + fn exit_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) { + self.fuse_statements(stmts, ctx); } } @@ -308,6 +300,11 @@ mod test { fuse("a;b;c;label:{break label;d;e;}", "a,b,c;label:{break label;d,e;}"); } + #[test] + fn fuse_into_switch_cases() { + fuse("switch (_) { case _: a; return b }", "switch (_) { case _: return a, b }"); + } + #[test] fn no_fuse_into_while() { fuse("a;b;c;while(x){}", "for(a,b,c;x;){}"); diff --git a/tasks/minsize/minsize.snap b/tasks/minsize/minsize.snap index 053e59e67..b37893489 100644 --- a/tasks/minsize/minsize.snap +++ b/tasks/minsize/minsize.snap @@ -5,23 +5,23 @@ Original | minified | minified | gzip | gzip | Fixture 173.90 kB | 59.86 kB | 59.82 kB | 19.43 kB | 19.33 kB | moment.js -287.63 kB | 90.17 kB | 90.07 kB | 32.08 kB | 31.95 kB | jquery.js +287.63 kB | 90.16 kB | 90.07 kB | 32.08 kB | 31.95 kB | jquery.js -342.15 kB | 118.25 kB | 118.14 kB | 44.54 kB | 44.37 kB | vue.js +342.15 kB | 118.23 kB | 118.14 kB | 44.53 kB | 44.37 kB | vue.js -544.10 kB | 71.81 kB | 72.48 kB | 26.18 kB | 26.20 kB | lodash.js +544.10 kB | 71.81 kB | 72.48 kB | 26.19 kB | 26.20 kB | lodash.js -555.77 kB | 273.25 kB | 270.13 kB | 90.99 kB | 90.80 kB | d3.js +555.77 kB | 273.19 kB | 270.13 kB | 90.99 kB | 90.80 kB | d3.js -1.01 MB | 460.39 kB | 458.89 kB | 126.86 kB | 126.71 kB | bundle.min.js +1.01 MB | 460.32 kB | 458.89 kB | 126.85 kB | 126.71 kB | bundle.min.js -1.25 MB | 652.71 kB | 646.76 kB | 163.55 kB | 163.73 kB | three.js +1.25 MB | 652.73 kB | 646.76 kB | 163.55 kB | 163.73 kB | three.js -2.14 MB | 726.38 kB | 724.14 kB | 180.22 kB | 181.07 kB | victory.js +2.14 MB | 726.33 kB | 724.14 kB | 180.21 kB | 181.07 kB | victory.js -3.20 MB | 1.01 MB | 1.01 MB | 332.14 kB | 331.56 kB | echarts.js +3.20 MB | 1.01 MB | 1.01 MB | 331.91 kB | 331.56 kB | echarts.js -6.69 MB | 2.32 MB | 2.31 MB | 492.86 kB | 488.28 kB | antd.js +6.69 MB | 2.32 MB | 2.31 MB | 492.81 kB | 488.28 kB | antd.js -10.95 MB | 3.50 MB | 3.49 MB | 910.01 kB | 915.50 kB | typescript.js +10.95 MB | 3.50 MB | 3.49 MB | 909.54 kB | 915.50 kB | typescript.js