mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 20:28:58 +00:00
feat(minifier): compress `a != null ? a.b : undefined` to `a?.b` (#8802) refactor(minifier): some clean ups
This commit is contained in:
parent
d8fac6d76b
commit
e525e60e5b
4 changed files with 10 additions and 58 deletions
|
|
@ -1,30 +1,3 @@
|
|||
use oxc_allocator::Vec;
|
||||
use oxc_ast::ast::*;
|
||||
|
||||
use crate::ctx::Ctx;
|
||||
|
||||
use super::PeepholeOptimizations;
|
||||
|
||||
impl<'a> PeepholeOptimizations {
|
||||
/// Transform the structure of the AST so that the number of explicit exits
|
||||
/// are minimized and instead flows to implicit exits conditions.
|
||||
///
|
||||
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/MinimizeExitPoints.java>
|
||||
pub fn minimize_exit_points(&mut self, body: &mut FunctionBody<'_>, _ctx: Ctx<'a, '_>) {
|
||||
self.remove_last_return(&mut body.statements);
|
||||
}
|
||||
|
||||
// `function foo() { return }` -> `function foo() {}`
|
||||
fn remove_last_return(&mut self, stmts: &mut Vec<'a, Statement<'a>>) {
|
||||
if let Some(last) = stmts.last() {
|
||||
if matches!(last, Statement::ReturnStatement(ret) if ret.argument.is_none()) {
|
||||
stmts.pop();
|
||||
self.mark_current_function_as_changed();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::tester::{test, test_same};
|
||||
|
|
|
|||
|
|
@ -16,14 +16,15 @@ impl<'a> PeepholeOptimizations {
|
|||
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/StatementFusion.java>
|
||||
///
|
||||
/// ## Collapse variable declarations
|
||||
///
|
||||
/// ## Join Vars
|
||||
/// `var a; var b = 1; var c = 2` => `var a, b = 1; c = 2`
|
||||
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/CollapseVariableDeclarations.java>
|
||||
///
|
||||
/// ## Collapse into for statements:
|
||||
/// `var a = 0; for(;a<0;a++) {}` => `for(var a = 0;a<0;a++) {}`
|
||||
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/Denormalize.java>
|
||||
///
|
||||
/// ## MinimizeExitPoints:
|
||||
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/MinimizeExitPoints.java>
|
||||
pub fn minimize_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: Ctx<'a, '_>) {
|
||||
let mut result: Vec<'a, Statement<'a>> = ctx.ast.vec_with_capacity(stmts.len());
|
||||
let mut is_control_flow_dead = false;
|
||||
|
|
|
|||
|
|
@ -159,14 +159,6 @@ impl<'a> Traverse<'a> for PeepholeOptimizations {
|
|||
self.substitute_return_statement(stmt, ctx);
|
||||
}
|
||||
|
||||
fn exit_function_body(&mut self, body: &mut FunctionBody<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
if !self.is_prev_function_changed() {
|
||||
return;
|
||||
}
|
||||
let ctx = Ctx(ctx);
|
||||
self.minimize_exit_points(body, ctx);
|
||||
}
|
||||
|
||||
fn exit_variable_declaration(
|
||||
&mut self,
|
||||
decl: &mut VariableDeclaration<'a>,
|
||||
|
|
|
|||
|
|
@ -18,14 +18,6 @@ use super::{LatePeepholeOptimizations, PeepholeOptimizations};
|
|||
/// See `KeepVar` at the end of this file for `var` hoisting logic.
|
||||
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/PeepholeRemoveDeadCode.java>
|
||||
impl<'a, 'b> PeepholeOptimizations {
|
||||
pub fn remove_dead_code_exit_statements(
|
||||
&mut self,
|
||||
stmts: &mut Vec<'a, Statement<'a>>,
|
||||
ctx: Ctx<'a, '_>,
|
||||
) {
|
||||
self.dead_code_elimination(stmts, ctx);
|
||||
}
|
||||
|
||||
pub fn remove_dead_code_exit_statement(&mut self, stmt: &mut Statement<'a>, ctx: Ctx<'a, '_>) {
|
||||
if let Some(new_stmt) = match stmt {
|
||||
Statement::BlockStatement(s) => Self::try_optimize_block(s, ctx),
|
||||
|
|
@ -66,18 +58,22 @@ impl<'a, 'b> PeepholeOptimizations {
|
|||
}
|
||||
|
||||
/// Removes dead code thats comes after `return`, `throw`, `continue` and `break` statements.
|
||||
fn dead_code_elimination(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: Ctx<'a, 'b>) {
|
||||
pub fn remove_dead_code_exit_statements(
|
||||
&mut self,
|
||||
stmts: &mut Vec<'a, Statement<'a>>,
|
||||
ctx: Ctx<'a, '_>,
|
||||
) {
|
||||
// Remove code after `return` and `throw` statements
|
||||
let mut index = None;
|
||||
'outer: for (i, stmt) in stmts.iter().enumerate() {
|
||||
if Self::is_unreachable_statement(stmt) {
|
||||
if stmt.is_jump_statement() {
|
||||
index.replace(i);
|
||||
break;
|
||||
}
|
||||
// Double check block statements folded by if statements above
|
||||
if let Statement::BlockStatement(block_stmt) = stmt {
|
||||
for stmt in &block_stmt.body {
|
||||
if Self::is_unreachable_statement(stmt) {
|
||||
if stmt.is_jump_statement() {
|
||||
index.replace(i);
|
||||
break 'outer;
|
||||
}
|
||||
|
|
@ -125,16 +121,6 @@ impl<'a, 'b> PeepholeOptimizations {
|
|||
}
|
||||
}
|
||||
|
||||
fn is_unreachable_statement(stmt: &Statement<'a>) -> bool {
|
||||
matches!(
|
||||
stmt,
|
||||
Statement::ReturnStatement(_)
|
||||
| Statement::ThrowStatement(_)
|
||||
| Statement::BreakStatement(_)
|
||||
| Statement::ContinueStatement(_)
|
||||
)
|
||||
}
|
||||
|
||||
/// Remove block from single line blocks
|
||||
/// `{ block } -> block`
|
||||
fn try_optimize_block(
|
||||
|
|
|
|||
Loading…
Reference in a new issue