Skip to content

Commit

Permalink
feat(minifier): merge similar if stmts
Browse files Browse the repository at this point in the history
  • Loading branch information
camc314 committed Jan 15, 2025
1 parent aa9d7e4 commit 72fa9df
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 23 deletions.
61 changes: 51 additions & 10 deletions crates/oxc_minifier/src/ast_passes/peephole_minimize_conditions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,19 +215,53 @@ impl<'a> PeepholeMinimizeConditions {

fn try_replace_if(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) {
for i in 0..stmts.len() {
let Statement::IfStatement(if_stmt) = &stmts[i] else {
let (current_node, next_node) = {
if i == stmts.len() - 1 {
(stmts.get_mut(i).unwrap(), None)
} else {
let (left, right) = stmts.split_at_mut(i + 1);
(left.last_mut().unwrap(), right.first_mut())
}
};

let Statement::IfStatement(if_stmt) = &current_node else {
continue;
};

let then_branch = &if_stmt.consequent;
let else_branch = &if_stmt.alternate;
let next_node = stmts.get(i + 1);

if next_node.is_some_and(|s| matches!(s, Statement::IfStatement(_)))
if next_node.as_ref().is_some_and(|s| matches!(s, Statement::IfStatement(_)))
&& else_branch.is_none()
&& Self::is_return_block(then_branch)
&& Self::statement_must_exit_parent(then_branch)
{
/* TODO */
} else if next_node.is_some_and(Self::is_return_expression)
// let next_node = next_node.unwrap();
// // `if (x) return; if (y) return;` -> `if (x || y) return;`
// let Statement::IfStatement(next_if) = next_node else { unreachable!() };

// if next_if.alternate.is_none() && next_if.consequent.content_eq(&if_stmt.consequent)
// {
// let Statement::IfStatement(mut if_stmt) = ctx.ast.move_statement(current_node)
// else {
// unreachable!()
// };

// let Statement::IfStatement(mut next) = ctx.ast.move_statement(next_node) else {
// unreachable!()
// };
// let test = ctx.ast.expression_logical(
// next.test.span(),
// ctx.ast.move_expression(&mut if_stmt.test),
// LogicalOperator::Or,
// ctx.ast.move_expression(&mut next.test),
// );
// if_stmt.test = test;
// stmts[i] = Statement::IfStatement(if_stmt);
// self.changed = true;
// }

// TODO: `if (x) return 1; if (y) foo() else return 1;` -> `if (!x&&y) foo() else return 1;`
} else if next_node.as_deref().is_some_and(Self::is_return_expression)
&& else_branch.is_none()
&& Self::is_return_block(then_branch)
{
Expand All @@ -248,6 +282,7 @@ impl<'a> PeepholeMinimizeConditions {
self.changed = true;
break;
} else if else_branch.is_some() && Self::statement_must_exit_parent(then_branch) {
// `if (x) return; else return 1` -> `return x ? void 0 : 1`
let Statement::IfStatement(if_stmt) = &mut stmts[i] else {
unreachable!();
};
Expand Down Expand Up @@ -951,12 +986,16 @@ mod test {
}

#[test]
#[ignore]
fn test_combine_ifs1() {
fn test_combine_ifs() {
fold(
"function f() {if (x) return 1; if (y) return 1}",
"function f() {if (x||y) return 1;}",
);
}

#[test]
#[ignore]
fn test_combine_ifs1() {
fold(
"function f() {if (x) return 1; if (y) foo(); else return 1}",
"function f() {if ((!x)&&y) foo(); else return 1;}",
Expand All @@ -966,8 +1005,10 @@ mod test {
#[test]
#[ignore]
fn test_combine_ifs2() {
// combinable but not yet done
fold_same("function f() {if (x) throw 1; if (y) throw 1}");
fold(
"function f() {if (x) throw 1; if (y) throw 1}",
"function f() {if (x || y) throw 1;}",
);
// Can't combine, side-effect
fold("function f(){ if (x) g(); if (y) g() }", "function f(){ x&&g(); y&&g() }");
fold("function f(){ if (x) g?.(); if (y) g?.() }", "function f(){ x&&g?.(); y&&g?.() }");
Expand Down
4 changes: 1 addition & 3 deletions crates/oxc_minifier/tests/ast_passes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,7 @@ fn cjs() {
});"#,
"
Object.keys(_index6).forEach(function(key) {
if (key === 'default' || key === '__esModule') return;
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
if (key in exports && exports[key] === _index6[key]) return;
if (key === 'default' || key === '__esModule' || Object.prototype.hasOwnProperty.call(_exportNames, key) || key in exports && exports[key] === _index6[key]) return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function() {
Expand Down
20 changes: 10 additions & 10 deletions tasks/minsize/minsize.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,25 @@ Original | minified | minified | gzip | gzip | Fixture
-------------------------------------------------------------------------------------
72.14 kB | 23.70 kB | 23.70 kB | 8.60 kB | 8.54 kB | react.development.js

173.90 kB | 59.79 kB | 59.82 kB | 19.41 kB | 19.33 kB | moment.js
173.90 kB | 59.68 kB | 59.82 kB | 19.40 kB | 19.33 kB | moment.js

287.63 kB | 90.08 kB | 90.07 kB | 32.03 kB | 31.95 kB | jquery.js
287.63 kB | 90.06 kB | 90.07 kB | 32.03 kB | 31.95 kB | jquery.js

342.15 kB | 118.11 kB | 118.14 kB | 44.44 kB | 44.37 kB | vue.js
342.15 kB | 118.07 kB | 118.14 kB | 44.44 kB | 44.37 kB | vue.js

544.10 kB | 71.76 kB | 72.48 kB | 26.15 kB | 26.20 kB | lodash.js

555.77 kB | 273.15 kB | 270.13 kB | 90.92 kB | 90.80 kB | d3.js
555.77 kB | 273.14 kB | 270.13 kB | 90.91 kB | 90.80 kB | d3.js

1.01 MB | 460.17 kB | 458.89 kB | 126.76 kB | 126.71 kB | bundle.min.js
1.01 MB | 459.65 kB | 458.89 kB | 126.75 kB | 126.71 kB | bundle.min.js

1.25 MB | 652.84 kB | 646.76 kB | 163.54 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 | 725.68 kB | 724.14 kB | 180.07 kB | 181.07 kB | victory.js
2.14 MB | 725.66 kB | 724.14 kB | 180.08 kB | 181.07 kB | victory.js

3.20 MB | 1.01 MB | 1.01 MB | 331.79 kB | 331.56 kB | echarts.js
3.20 MB | 1.01 MB | 1.01 MB | 331.78 kB | 331.56 kB | echarts.js

6.69 MB | 2.32 MB | 2.31 MB | 492.64 kB | 488.28 kB | antd.js
6.69 MB | 2.32 MB | 2.31 MB | 492.61 kB | 488.28 kB | antd.js

10.95 MB | 3.49 MB | 3.49 MB | 907.42 kB | 915.50 kB | typescript.js
10.95 MB | 3.49 MB | 3.49 MB | 907.29 kB | 915.50 kB | typescript.js

0 comments on commit 72fa9df

Please sign in to comment.