Skip to content

Commit 5ec9201

Browse files
committed
perf(minifier): use arena allocated HashMap and HashSet
1 parent d50d949 commit 5ec9201

File tree

4 files changed

+51
-33
lines changed

4 files changed

+51
-33
lines changed

crates/oxc_minifier/src/compressor.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ impl<'a> Compressor<'a> {
3131
options: CompressOptions,
3232
) -> u8 {
3333
let max_iterations = options.max_iterations;
34-
let state = MinifierState::new(program.source_type, options);
34+
let state = MinifierState::new(self.allocator, program.source_type, options);
3535
let mut ctx = ReusableTraverseCtx::new(state, scoping, self.allocator);
3636
let normalize_options =
3737
NormalizeOptions { convert_while_to_fors: true, convert_const_to_let: true };
@@ -52,7 +52,7 @@ impl<'a> Compressor<'a> {
5252
options: CompressOptions,
5353
) -> u8 {
5454
let max_iterations = options.max_iterations;
55-
let state = MinifierState::new(program.source_type, options);
55+
let state = MinifierState::new(self.allocator, program.source_type, options);
5656
let mut ctx = ReusableTraverseCtx::new(state, scoping, self.allocator);
5757
let normalize_options =
5858
NormalizeOptions { convert_while_to_fors: false, convert_const_to_let: false };

crates/oxc_minifier/src/peephole/mod.rs

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ mod remove_unused_private_members;
1717
mod replace_known_methods;
1818
mod substitute_alternate_syntax;
1919

20+
use oxc_allocator::HashSet;
2021
use oxc_ast_visit::Visit;
2122
use oxc_semantic::ReferenceId;
22-
use rustc_hash::FxHashSet;
2323

2424
use oxc_allocator::Vec;
2525
use oxc_ast::ast::*;
@@ -116,12 +116,16 @@ impl<'a> Traverse<'a, MinifierState<'a>> for PeepholeOptimizations {
116116
self.changed = ctx.state.changed;
117117
if self.changed {
118118
// Remove unused references by visiting the AST again and diff the collected references.
119-
let refs_before =
120-
ctx.scoping().resolved_references().flatten().copied().collect::<FxHashSet<_>>();
121-
let mut counter = ReferencesCounter::default();
119+
let refs_before = HashSet::from_iter_in(
120+
ctx.scoping().resolved_references().flatten().copied(),
121+
ctx.ast.allocator,
122+
);
123+
let mut counter = ReferencesCounter::new_in(ctx.ast.allocator);
122124
counter.visit_program(program);
123-
for reference_id_to_remove in refs_before.difference(&counter.refs) {
124-
ctx.scoping_mut().delete_reference(*reference_id_to_remove);
125+
for reference_id in &refs_before {
126+
if !counter.refs.contains(reference_id) {
127+
ctx.scoping_mut().delete_reference(*reference_id);
128+
}
125129
}
126130
}
127131
debug_assert!(ctx.state.class_symbols_stack.is_exhausted());
@@ -365,7 +369,7 @@ impl<'a> Traverse<'a, MinifierState<'a>> for PeepholeOptimizations {
365369
}
366370

367371
fn enter_class_body(&mut self, _body: &mut ClassBody<'a>, ctx: &mut TraverseCtx<'a>) {
368-
ctx.state.class_symbols_stack.push_class_scope();
372+
ctx.state.class_symbols_stack.push_class_scope(ctx.ast.allocator);
369373
}
370374

371375
fn exit_class_body(&mut self, body: &mut ClassBody<'a>, ctx: &mut TraverseCtx<'a>) {
@@ -451,12 +455,16 @@ impl<'a> Traverse<'a, MinifierState<'a>> for DeadCodeElimination {
451455
self.changed = ctx.state.changed;
452456
if self.changed {
453457
// Remove unused references by visiting the AST again and diff the collected references.
454-
let refs_before =
455-
ctx.scoping().resolved_references().flatten().copied().collect::<FxHashSet<_>>();
456-
let mut counter = ReferencesCounter::default();
458+
let refs_before = HashSet::from_iter_in(
459+
ctx.scoping().resolved_references().flatten().copied(),
460+
ctx.ast.allocator,
461+
);
462+
let mut counter = ReferencesCounter::new_in(ctx.ast.allocator);
457463
counter.visit_program(program);
458-
for reference_id_to_remove in refs_before.difference(&counter.refs) {
459-
ctx.scoping_mut().delete_reference(*reference_id_to_remove);
464+
for reference_id in &refs_before {
465+
if !counter.refs.contains(reference_id) {
466+
ctx.scoping_mut().delete_reference(*reference_id);
467+
}
460468
}
461469
}
462470
}
@@ -534,12 +542,17 @@ impl<'a> Traverse<'a, MinifierState<'a>> for DeadCodeElimination {
534542
}
535543
}
536544

537-
#[derive(Default)]
538-
struct ReferencesCounter {
539-
refs: FxHashSet<ReferenceId>,
545+
struct ReferencesCounter<'a> {
546+
refs: HashSet<'a, ReferenceId>,
547+
}
548+
549+
impl<'a> ReferencesCounter<'a> {
550+
fn new_in(allocator: &'a oxc_allocator::Allocator) -> Self {
551+
Self { refs: HashSet::new_in(allocator) }
552+
}
540553
}
541554

542-
impl<'a> Visit<'a> for ReferencesCounter {
555+
impl<'a> Visit<'a> for ReferencesCounter<'a> {
543556
fn visit_identifier_reference(&mut self, it: &IdentifierReference<'a>) {
544557
let reference_id = it.reference_id();
545558
self.refs.insert(reference_id);

crates/oxc_minifier/src/state.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
use oxc_allocator::HashSet;
12
use oxc_ecmascript::constant_evaluation::ConstantValue;
2-
use rustc_hash::{FxHashMap, FxHashSet};
3+
use rustc_hash::FxHashMap;
34

45
use oxc_data_structures::stack::NonEmptyStack;
56
use oxc_span::{Atom, SourceType};
@@ -23,27 +24,31 @@ pub struct MinifierState<'a> {
2324
pub changed: bool,
2425
}
2526

26-
impl MinifierState<'_> {
27-
pub fn new(source_type: SourceType, options: CompressOptions) -> Self {
27+
impl<'a> MinifierState<'a> {
28+
pub fn new(
29+
allocator: &'a oxc_allocator::Allocator,
30+
source_type: SourceType,
31+
options: CompressOptions,
32+
) -> Self {
2833
Self {
2934
source_type,
3035
options,
3136
pure_functions: FxHashMap::default(),
3237
symbol_values: SymbolValues::default(),
33-
class_symbols_stack: ClassSymbolsStack::new(),
38+
class_symbols_stack: ClassSymbolsStack::new_in(allocator),
3439
changed: false,
3540
}
3641
}
3742
}
3843

3944
/// Stack to track class symbol information
4045
pub struct ClassSymbolsStack<'a> {
41-
stack: NonEmptyStack<FxHashSet<Atom<'a>>>,
46+
stack: NonEmptyStack<HashSet<'a, Atom<'a>>>,
4247
}
4348

4449
impl<'a> ClassSymbolsStack<'a> {
45-
pub fn new() -> Self {
46-
Self { stack: NonEmptyStack::new(FxHashSet::default()) }
50+
pub fn new_in(allocator: &'a oxc_allocator::Allocator) -> Self {
51+
Self { stack: NonEmptyStack::new(HashSet::new_in(allocator)) }
4752
}
4853

4954
/// Check if the stack is exhausted
@@ -52,8 +57,8 @@ impl<'a> ClassSymbolsStack<'a> {
5257
}
5358

5459
/// Enter a new class scope
55-
pub fn push_class_scope(&mut self) {
56-
self.stack.push(FxHashSet::default());
60+
pub fn push_class_scope(&mut self, allocator: &'a oxc_allocator::Allocator) {
61+
self.stack.push(HashSet::new_in(allocator));
5762
}
5863

5964
/// Exit the current class scope
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
File | File size || Sys allocs | Sys reallocs || Arena allocs | Arena reallocs | Arena bytes
22
-------------------------------------------------------------------------------------------------------------------------------------------
3-
checker.ts | 2.92 MB || 83500 | 14179 || 152592 | 28237
3+
checker.ts | 2.92 MB || 83404 | 14179 || 152592 | 28237
44

5-
cal.com.tsx | 1.06 MB || 40449 | 3033 || 37146 | 4583
5+
cal.com.tsx | 1.06 MB || 40393 | 3033 || 37146 | 4583
66

7-
RadixUIAdoptionSection.jsx | 2.52 kB || 85 | 9 || 30 | 6
7+
RadixUIAdoptionSection.jsx | 2.52 kB || 75 | 9 || 30 | 6
88

9-
pdf.mjs | 567.30 kB || 19808 | 2899 || 47442 | 7725
9+
pdf.mjs | 567.30 kB || 19510 | 2899 || 47442 | 7725
1010

11-
antd.js | 6.69 MB || 99524 | 13523 || 331573 | 69338
11+
antd.js | 6.69 MB || 99396 | 13523 || 331573 | 69338
1212

13-
binder.ts | 193.08 kB || 4760 | 974 || 7075 | 824
13+
binder.ts | 193.08 kB || 4736 | 974 || 7075 | 824
1414

0 commit comments

Comments
 (0)