Skip to content

Commit

Permalink
refactor(minifier): move optional catch param to peephole_substitute_…
Browse files Browse the repository at this point in the history
…alternate_syntax (#8282)
  • Loading branch information
Boshen committed Jan 6, 2025
1 parent 2e7207f commit b8d26ea
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 57 deletions.
7 changes: 6 additions & 1 deletion crates/oxc_minifier/src/ast_passes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ pub struct PeepholeOptimizations {
}

impl PeepholeOptimizations {
pub fn new(in_fixed_loop: bool, _options: CompressOptions) -> Self {
pub fn new(in_fixed_loop: bool, options: CompressOptions) -> Self {
Self {
x0_statement_fusion: StatementFusion::new(),
x1_minimize_exit_points: MinimizeExitPoints::new(),
Expand All @@ -60,6 +60,7 @@ impl PeepholeOptimizations {
x4_peephole_remove_dead_code: PeepholeRemoveDeadCode::new(),
x5_peephole_minimize_conditions: PeepholeMinimizeConditions::new(in_fixed_loop),
x6_peephole_substitute_alternate_syntax: PeepholeSubstituteAlternateSyntax::new(
options.target,
in_fixed_loop,
),
x7_peephole_replace_known_methods: PeepholeReplaceKnownMethods::new(),
Expand Down Expand Up @@ -218,6 +219,10 @@ impl<'a> Traverse<'a> for PeepholeOptimizations {
) {
self.x6_peephole_substitute_alternate_syntax.exit_accessor_property(prop, ctx);
}

fn exit_catch_clause(&mut self, catch: &mut CatchClause<'a>, ctx: &mut TraverseCtx<'a>) {
self.x6_peephole_substitute_alternate_syntax.exit_catch_clause(catch, ctx);
}
}

pub struct DeadCodeElimination {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use oxc_ecmascript::{constant_evaluation::ConstantEvaluation, ToInt32, ToJsStrin
use oxc_semantic::IsGlobalReference;
use oxc_span::{GetSpan, SPAN};
use oxc_syntax::{
es_target::ESTarget,
identifier::is_identifier_name,
number::NumberBase,
operator::{BinaryOperator, UnaryOperator},
Expand All @@ -17,6 +18,7 @@ use crate::{node_util::Ctx, CompressorPass};
/// with literals, and simplifying returns.
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/PeepholeSubstituteAlternateSyntax.java>
pub struct PeepholeSubstituteAlternateSyntax {
target: ESTarget,
/// Do not compress syntaxes that are hard to analyze inside the fixed loop.
/// e.g. Do not compress `undefined -> void 0`, `true` -> `!0`.
/// Opposite of `late` in Closure Compiler.
Expand All @@ -36,6 +38,10 @@ impl<'a> CompressorPass<'a> for PeepholeSubstituteAlternateSyntax {
}

impl<'a> Traverse<'a> for PeepholeSubstituteAlternateSyntax {
fn exit_catch_clause(&mut self, catch: &mut CatchClause<'a>, ctx: &mut TraverseCtx<'a>) {
self.compress_catch_clause(catch, ctx);
}

fn exit_object_property(&mut self, prop: &mut ObjectProperty<'a>, ctx: &mut TraverseCtx<'a>) {
self.try_compress_property_key(&mut prop.key, &mut prop.computed, ctx);
}
Expand Down Expand Up @@ -157,8 +163,22 @@ impl<'a> Traverse<'a> for PeepholeSubstituteAlternateSyntax {
}

impl<'a, 'b> PeepholeSubstituteAlternateSyntax {
pub fn new(in_fixed_loop: bool) -> Self {
Self { in_fixed_loop, in_define_export: false, changed: false }
pub fn new(target: ESTarget, in_fixed_loop: bool) -> Self {
Self { target, in_fixed_loop, in_define_export: false, changed: false }
}

fn compress_catch_clause(&mut self, catch: &mut CatchClause<'_>, ctx: &mut TraverseCtx<'a>) {
if !self.in_fixed_loop && self.target >= ESTarget::ES2019 {
if let Some(param) = &catch.param {
if let BindingPatternKind::BindingIdentifier(ident) = &param.pattern.kind {
if catch.body.body.is_empty()
|| ctx.symbols().get_resolved_references(ident.symbol_id()).count() == 0
{
catch.param = None;
}
};
}
}
}

fn swap_binary_expressions(e: &mut BinaryExpression<'a>) {
Expand Down Expand Up @@ -903,12 +923,14 @@ impl<'a, 'b> PeepholeSubstituteAlternateSyntax {
#[cfg(test)]
mod test {
use oxc_allocator::Allocator;
use oxc_syntax::es_target::ESTarget;

use crate::tester;

fn test(source_text: &str, expected: &str) {
let allocator = Allocator::default();
let mut pass = super::PeepholeSubstituteAlternateSyntax::new(false);
let target = ESTarget::ESNext;
let mut pass = super::PeepholeSubstituteAlternateSyntax::new(target, false);
tester::test(&allocator, source_text, expected, &mut pass);
}

Expand All @@ -931,8 +953,8 @@ mod test {
fn test_undefined() {
test("var x = undefined", "var x");
test_same("var undefined = 1;function f() {var undefined=2;var x;}");
test("function f(undefined) {}", "function f(undefined){}");
test("try {} catch(undefined) {foo}", "try{}catch(undefined){foo}");
test_same("function f(undefined) {}");
test_same("try {} catch(undefined) {foo(undefined)}");
test("for (undefined in {}) {}", "for(undefined in {}){}");
test("undefined++;", "undefined++");
test("undefined += undefined;", "undefined+=void 0");
Expand Down Expand Up @@ -1463,4 +1485,19 @@ mod test {
test_same("BigInt()");
test_same("BigInt(1)");
}

#[test]
fn optional_catch_binding() {
test("try {} catch(e) {}", "try {} catch {}");
test("try {} catch(e) {foo}", "try {} catch {foo}");
test_same("try {} catch(e) {e}");
test_same("try {} catch([e]) {}");
test_same("try {} catch({e}) {}");

let allocator = Allocator::default();
let target = ESTarget::ES2018;
let mut pass = super::PeepholeSubstituteAlternateSyntax::new(target, false);
let code = "try {} catch(e) {}";
tester::test(&allocator, code, code, &mut pass);
}
}
48 changes: 6 additions & 42 deletions crates/oxc_minifier/src/ast_passes/remove_unused_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,15 @@ use rustc_hash::FxHashSet;

use oxc_allocator::Vec as ArenaVec;
use oxc_ast::ast::*;
use oxc_syntax::{es_target::ESTarget, symbol::SymbolId};
use oxc_syntax::symbol::SymbolId;
use oxc_traverse::{traverse_mut_with_ctx, ReusableTraverseCtx, Traverse, TraverseCtx};

use crate::{CompressOptions, CompressorPass};
use crate::CompressorPass;

/// Remove Unused Code
///
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/RemoveUnusedCode.java>
pub struct RemoveUnusedCode {
options: CompressOptions,

pub(crate) changed: bool,

symbol_ids_to_remove: FxHashSet<SymbolId>,
Expand Down Expand Up @@ -61,65 +59,31 @@ impl<'a> Traverse<'a> for RemoveUnusedCode {
}
}
}

fn exit_catch_clause(&mut self, catch: &mut CatchClause<'a>, _ctx: &mut TraverseCtx<'a>) {
self.compress_catch_clause(catch);
}
}

impl RemoveUnusedCode {
#[allow(dead_code)]
pub fn new(options: CompressOptions) -> Self {
Self { options, changed: false, symbol_ids_to_remove: FxHashSet::default() }
}

fn compress_catch_clause(&mut self, catch: &mut CatchClause<'_>) {
if self.options.target >= ESTarget::ES2019 {
if let Some(param) = &catch.param {
if let BindingPatternKind::BindingIdentifier(ident) = &param.pattern.kind {
if self.symbol_ids_to_remove.contains(&ident.symbol_id()) {
catch.param = None;
self.changed = true;
}
}
};
}
pub fn new() -> Self {
Self { changed: false, symbol_ids_to_remove: FxHashSet::default() }
}
}

#[cfg(test)]
mod test {
use oxc_allocator::Allocator;

use crate::{tester, CompressOptions};
use crate::tester;

fn test(source_text: &str, expected: &str) {
let allocator = Allocator::default();
let options = CompressOptions::default();
let mut pass = super::RemoveUnusedCode::new(options);
let mut pass = super::RemoveUnusedCode::new();
tester::test(&allocator, source_text, expected, &mut pass);
}

fn test_same(source_text: &str) {
test(source_text, source_text);
}

#[test]
fn optional_catch_binding() {
test("try {} catch(e) {}", "try {} catch {}");
test_same("try {} catch([e]) {}");
test_same("try {} catch({e}) {}");

let allocator = Allocator::default();
let options = CompressOptions {
target: oxc_syntax::es_target::ESTarget::ES2018,
..CompressOptions::default()
};
let mut pass = super::RemoveUnusedCode::new(options);
let code = "try {} catch(e) {}";
tester::test(&allocator, code, code, &mut pass);
}

#[test]
fn simple() {
test("var x", "");
Expand Down
18 changes: 9 additions & 9 deletions tasks/minsize/minsize.snap
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
| Oxc | ESBuild | Oxc | ESBuild |
Original | minified | minified | gzip | gzip | Fixture
-------------------------------------------------------------------------------------
72.14 kB | 23.69 kB | 23.70 kB | 8.62 kB | 8.54 kB | react.development.js
72.14 kB | 23.68 kB | 23.70 kB | 8.61 kB | 8.54 kB | react.development.js

173.90 kB | 59.87 kB | 59.82 kB | 19.43 kB | 19.33 kB | moment.js

287.63 kB | 90.18 kB | 90.07 kB | 32.10 kB | 31.95 kB | jquery.js
287.63 kB | 90.15 kB | 90.07 kB | 32.07 kB | 31.95 kB | jquery.js

342.15 kB | 118.23 kB | 118.14 kB | 44.52 kB | 44.37 kB | vue.js
342.15 kB | 118.22 kB | 118.14 kB | 44.52 kB | 44.37 kB | vue.js

544.10 kB | 71.80 kB | 72.48 kB | 26.18 kB | 26.20 kB | lodash.js
544.10 kB | 71.79 kB | 72.48 kB | 26.18 kB | 26.20 kB | lodash.js

555.77 kB | 273.15 kB | 270.13 kB | 90.95 kB | 90.80 kB | d3.js

1.01 MB | 460.33 kB | 458.89 kB | 126.85 kB | 126.71 kB | bundle.min.js
1.01 MB | 460.32 kB | 458.89 kB | 126.84 kB | 126.71 kB | bundle.min.js

1.25 MB | 652.69 kB | 646.76 kB | 163.54 kB | 163.73 kB | three.js
1.25 MB | 652.68 kB | 646.76 kB | 163.53 kB | 163.73 kB | three.js

2.14 MB | 726.17 kB | 724.14 kB | 180.17 kB | 181.07 kB | victory.js
2.14 MB | 726.15 kB | 724.14 kB | 180.16 kB | 181.07 kB | victory.js

3.20 MB | 1.01 MB | 1.01 MB | 331.88 kB | 331.56 kB | echarts.js

6.69 MB | 2.32 MB | 2.31 MB | 492.84 kB | 488.28 kB | antd.js
6.69 MB | 2.32 MB | 2.31 MB | 492.77 kB | 488.28 kB | antd.js

10.95 MB | 3.50 MB | 3.49 MB | 909.14 kB | 915.50 kB | typescript.js
10.95 MB | 3.50 MB | 3.49 MB | 909.11 kB | 915.50 kB | typescript.js

0 comments on commit b8d26ea

Please sign in to comment.