Skip to content

Commit

Permalink
refactor(minifier): move compress block to dce
Browse files Browse the repository at this point in the history
  • Loading branch information
7086cmd committed Oct 12, 2024
1 parent 7645e5c commit dda0c8d
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 23 deletions.
57 changes: 54 additions & 3 deletions crates/oxc_minifier/src/ast_passes/peephole_remove_dead_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ impl<'a> Traverse<'a> for PeepholeRemoveDeadCode {
}
}

fn exit_statement(&mut self, stmt: &mut Statement<'a>, ctx: &mut TraverseCtx<'a>) {
self.compress_block(stmt, ctx);
}

fn exit_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) {
if stmts.iter().any(|stmt| matches!(stmt, Statement::EmptyStatement(_))) {
stmts.retain(|stmt| !matches!(stmt, Statement::EmptyStatement(_)));
Expand Down Expand Up @@ -128,6 +132,27 @@ impl<'a> PeepholeRemoveDeadCode {
}
}

/// Remove block from single line blocks
/// `{ block } -> block`
fn compress_block(&mut self, stmt: &mut Statement<'a>, ctx: &mut TraverseCtx<'a>) {
if let Statement::BlockStatement(block) = stmt {
// Avoid compressing `if (x) { var x = 1 }` to `if (x) var x = 1` due to different
// semantics according to AnnexB, which lead to different semantics.
if block.body.len() == 1 && !block.body[0].is_declaration() {
*stmt = block.body.remove(0);
self.compress_block(stmt, ctx);
self.changed = true;
return;
}
if block.body.len() == 0
&& (ctx.parent().is_block_statement() || ctx.parent().is_program())
{
// Remove the block if it is empty and the parent is a block statement.
*stmt = ctx.ast.statement_empty(SPAN);
}
}
}

fn try_fold_if(
&mut self,
if_stmt: &mut IfStatement<'a>,
Expand Down Expand Up @@ -264,6 +289,35 @@ mod test {
test(js, expected);
}

#[test]
#[ignore]
fn test_fold_block() {
fold("{{foo()}}", "foo()");
fold("{foo();{}}", "foo()");
fold("{{foo()}{}}", "foo()");
// fold("{{foo()}{bar()}}", "foo();bar()");
fold("{if(false)foo(); {bar()}}", "bar()");
fold("{if(false)if(false)if(false)foo(); {bar()}}", "bar()");

fold("{'hi'}", "");
// fold("{x==3}", "");
// fold("{`hello ${foo}`}", "");
// fold("{ (function(){x++}) }", "");
// fold_same("function f(){return;}");
// fold("function f(){return 3;}", "function f(){return 3}");
// fold_same("function f(){if(x)return; x=3; return; }");
// fold("{x=3;;;y=2;;;}", "x=3;y=2");

// Cases to test for empty block.
// fold("while(x()){x}", "while(x());");
// fold("while(x()){x()}", "while(x())x()");
// fold("for(x=0;x<100;x++){x}", "for(x=0;x<100;x++);");
// fold("for(x in y){x}", "for(x in y);");
// fold("for (x of y) {x}", "for(x of y);");
// fold_same("for (let x = 1; x <10; x++ ) {}");
// fold_same("for (var x = 1; x <10; x++ ) {}");
}

#[test]
#[ignore]
fn test_remove_no_op_labelled_statement() {
Expand Down Expand Up @@ -300,9 +354,6 @@ mod test {
fold("for(;false;) { foo(); continue }", "");

// fold("l1:for(;false;) { }", "");

// TODO handle single block statement
fold_same("for(;a;) { foo(); }");
}

#[test]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,6 @@ impl<'a> CompressorPass<'a> for PeepholeSubstituteAlternateSyntax {
}

impl<'a> Traverse<'a> for PeepholeSubstituteAlternateSyntax {
fn enter_statement(&mut self, stmt: &mut Statement<'a>, _ctx: &mut TraverseCtx<'a>) {
self.compress_block(stmt);
// self.compress_while(stmt);
}

fn exit_return_statement(
&mut self,
stmt: &mut ReturnStatement<'a>,
Expand Down Expand Up @@ -161,20 +156,6 @@ impl<'a> PeepholeSubstituteAlternateSyntax {

/* Statements */

/// Remove block from single line blocks
/// `{ block } -> block`
fn compress_block(&mut self, stmt: &mut Statement<'a>) {
if let Statement::BlockStatement(block) = stmt {
// Avoid compressing `if (x) { var x = 1 }` to `if (x) var x = 1` due to different
// semantics according to AnnexB, which lead to different semantics.
if block.body.len() == 1 && !block.body[0].is_declaration() {
*stmt = block.body.remove(0);
self.compress_block(stmt);
self.changed = true;
}
}
}

// /// Transforms `while(expr)` to `for(;expr;)`
// fn compress_while(&mut self, stmt: &mut Statement<'a>) {
// let Statement::WhileStatement(while_stmt) = stmt else { return };
Expand Down Expand Up @@ -531,7 +512,8 @@ mod test {
test("function f(){return void 0;}", "function f(){return}");
test("function f(){return void foo();}", "function f(){return void foo()}");
test("function f(){return undefined;}", "function f(){return}");
test("function f(){if(a()){return undefined;}}", "function f(){if(a())return}");
// Here we handle the block in dce.
test("function f(){if(a()){return undefined;}}", "function f(){if(a()){return}}");
}

#[test]
Expand Down

0 comments on commit dda0c8d

Please sign in to comment.