Skip to content

Commit faaa1ee

Browse files
committed
trick
1 parent bf85bad commit faaa1ee

File tree

7 files changed

+72
-95
lines changed

7 files changed

+72
-95
lines changed

crates/oxc_mangler/src/lib.rs

+54-60
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_hash::FxHashSet;
88
use oxc_allocator::{Allocator, Vec};
99
use oxc_ast::ast::{Declaration, Program, Statement};
1010
use oxc_index::Idx;
11-
use oxc_semantic::{ReferenceId, ScopeTree, SemanticBuilder, SymbolId, SymbolTable};
11+
use oxc_semantic::{ReferenceId, ScopeTree, Semantic, SemanticBuilder, SymbolId, SymbolTable};
1212
use oxc_span::Atom;
1313

1414
#[derive(Default, Debug, Clone, Copy)]
@@ -92,24 +92,18 @@ impl Mangler {
9292
pub fn build(self, program: &Program<'_>) -> Mangler {
9393
let semantic =
9494
SemanticBuilder::new().with_scope_tree_child_ids(true).build(program).semantic;
95-
let (symbol_table, scope_tree) = semantic.into_symbol_table_and_scope_tree();
96-
self.build_with_symbols_and_scopes(symbol_table, &scope_tree, program)
95+
self.build_with_semantic(semantic, program)
9796
}
9897

9998
/// # Panics
10099
///
101100
/// Panics if the child_ids does not exist in scope_tree.
102101
#[must_use]
103-
pub fn build_with_symbols_and_scopes(
104-
self,
105-
symbol_table: SymbolTable,
106-
scope_tree: &ScopeTree,
107-
program: &Program<'_>,
108-
) -> Mangler {
102+
pub fn build_with_semantic(self, semantic: Semantic<'_>, program: &Program<'_>) -> Mangler {
109103
if self.options.debug {
110-
self.build_with_symbols_and_scopes_impl(symbol_table, scope_tree, program, debug_name)
104+
self.build_with_symbols_and_scopes_impl(semantic, program, debug_name)
111105
} else {
112-
self.build_with_symbols_and_scopes_impl(symbol_table, scope_tree, program, base54)
106+
self.build_with_symbols_and_scopes_impl(semantic, program, base54)
113107
}
114108
}
115109

@@ -118,11 +112,12 @@ impl Mangler {
118112
G: Fn(usize) -> InlineString<CAPACITY>,
119113
>(
120114
mut self,
121-
symbol_table: SymbolTable,
122-
scope_tree: &ScopeTree,
115+
semantic: Semantic<'_>,
123116
program: &Program<'_>,
124117
generate_name: G,
125118
) -> Mangler {
119+
let (mut symbol_table, scope_tree, ast_nodes) = semantic.into_symbols_scopes_nodes();
120+
126121
assert!(scope_tree.has_child_ids(), "child_id needs to be generated");
127122

128123
let (exported_names, exported_symbols) = if self.options.top_level {
@@ -133,10 +128,6 @@ impl Mangler {
133128

134129
let allocator = Allocator::default();
135130

136-
// Mangle the symbol table by computing slots from the scope tree.
137-
// A slot is the occurrence index of a binding identifier inside a scope.
138-
let mut symbol_table = symbol_table;
139-
140131
// All symbols with their assigned slots. Keyed by symbol id.
141132
let mut slots: Vec<'_, Slot> = Vec::with_capacity_in(symbol_table.len(), &allocator);
142133
for _ in 0..symbol_table.len() {
@@ -150,54 +141,57 @@ impl Mangler {
150141
for scope_id in iter::once(scope_tree.root_scope_id())
151142
.chain(scope_tree.iter_all_child_ids(scope_tree.root_scope_id()))
152143
{
144+
let bindings = scope_tree.get_bindings(scope_id);
145+
if bindings.is_empty() {
146+
continue;
147+
}
148+
149+
let mut slot = slot_liveness.len();
150+
153151
let nearest_var_scope_id = scope_tree
154152
.ancestors(scope_id)
155153
.find(|s_id| scope_tree.get_flags(*s_id).is_var())
156154
.unwrap_or(scope_tree.root_scope_id());
157-
let bindings = scope_tree.get_bindings(scope_id);
158155

159-
let mut slot = slot_liveness.len();
160-
161-
if !bindings.is_empty() {
162-
let reusable_slots = Vec::from_iter_in(
163-
slot_liveness
164-
.iter()
165-
.enumerate()
166-
.filter(|(_, slot_liveness)| !slot_liveness.contains(scope_id.index()))
167-
.map(|(slot, _)| slot)
168-
.take(bindings.len()),
169-
&allocator,
170-
);
171-
let remaining_count = bindings.len() - reusable_slots.len();
172-
173-
let assignable_slots =
174-
reusable_slots.into_iter().chain(slot..slot + remaining_count);
175-
slot += remaining_count;
176-
if slot_liveness.len() < slot {
177-
slot_liveness
178-
.resize_with(slot, || FixedBitSet::with_capacity(scope_tree.len()));
179-
}
156+
let reusable_slots = Vec::from_iter_in(
157+
slot_liveness
158+
.iter()
159+
.enumerate()
160+
.filter(|(_, slot_liveness)| !slot_liveness.contains(scope_id.index()))
161+
.map(|(slot, _)| slot)
162+
.take(bindings.len()),
163+
&allocator,
164+
);
165+
166+
let remaining_count = bindings.len() - reusable_slots.len();
167+
168+
let assignable_slots = reusable_slots.into_iter().chain(slot..slot + remaining_count);
169+
slot += remaining_count;
170+
if slot_liveness.len() < slot {
171+
slot_liveness.resize_with(slot, || FixedBitSet::with_capacity(scope_tree.len()));
172+
}
180173

181-
// Sort `bindings` in declaration order.
182-
tmp_bindings.clear();
183-
tmp_bindings.extend(bindings.values().copied());
184-
tmp_bindings.sort_unstable();
185-
for (symbol_id, assigned_slot) in tmp_bindings.iter().zip(assignable_slots) {
186-
slots[symbol_id.index()] = assigned_slot;
187-
188-
let lived_scope_ids = symbol_table
189-
.get_resolved_references(*symbol_id)
190-
.flat_map(|reference| {
191-
// treat all symbols as var for now
192-
// the reusability can be improved by reducing the lived scope ids for const / let / class
193-
scope_tree
194-
.ancestors(reference.scope_id())
195-
.take_while(|s_id| *s_id != nearest_var_scope_id)
196-
})
197-
.chain(iter::once(nearest_var_scope_id));
198-
for scope_id in lived_scope_ids {
199-
slot_liveness[assigned_slot].insert(scope_id.index());
200-
}
174+
// Sort `bindings` in declaration order.
175+
tmp_bindings.clear();
176+
tmp_bindings.extend(bindings.values().copied());
177+
tmp_bindings.sort_unstable();
178+
for (symbol_id, assigned_slot) in tmp_bindings.iter().zip(assignable_slots) {
179+
slots[symbol_id.index()] = assigned_slot;
180+
181+
let lived_scope_ids = symbol_table
182+
.get_resolved_references(*symbol_id)
183+
.flat_map(|reference| {
184+
let scope_id = ast_nodes.get_node(reference.node_id()).scope_id();
185+
// Treat all symbols as var for now.
186+
// Reusability can be improved by reducing the lived scope ids for const / let / class
187+
scope_tree
188+
.ancestors(scope_id)
189+
.take_while(|s_id| *s_id != nearest_var_scope_id)
190+
})
191+
.chain(iter::once(nearest_var_scope_id));
192+
193+
for scope_id in lived_scope_ids {
194+
slot_liveness[assigned_slot].insert(scope_id.index());
201195
}
202196
}
203197
}
@@ -207,7 +201,7 @@ impl Mangler {
207201
let frequencies = self.tally_slot_frequencies(
208202
&symbol_table,
209203
&exported_symbols,
210-
scope_tree,
204+
&scope_tree,
211205
total_number_of_slots,
212206
&slots,
213207
&allocator,

crates/oxc_minifier/src/lib.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,7 @@ impl Minifier {
6060
.with_scope_tree_child_ids(true)
6161
.build(program)
6262
.semantic;
63-
let (symbols, scopes) = semantic.into_symbol_table_and_scope_tree();
64-
Mangler::default()
65-
.with_options(options)
66-
.build_with_symbols_and_scopes(symbols, &scopes, program)
63+
Mangler::default().with_options(options).build_with_semantic(semantic, program)
6764
});
6865
MinifierReturn { mangler }
6966
}

crates/oxc_semantic/src/builder.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2119,7 +2119,7 @@ impl<'a> SemanticBuilder<'a> {
21192119

21202120
fn reference_identifier(&mut self, ident: &IdentifierReference<'a>) {
21212121
let flags = self.resolve_reference_usages();
2122-
let reference = Reference::new(self.current_node_id, self.current_scope_id, flags);
2122+
let reference = Reference::new(self.current_node_id, flags);
21232123
let reference_id = self.declare_reference(ident.name, reference);
21242124
ident.reference_id.set(Some(reference_id));
21252125
}

crates/oxc_semantic/src/lib.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,16 @@ pub struct Semantic<'a> {
9090
}
9191

9292
impl<'a> Semantic<'a> {
93-
/// Extract the [`SymbolTable`] and [`ScopeTree`] from the [`Semantic`]
94-
/// instance, consuming `self`.
93+
/// Extract [`SymbolTable`] and [`ScopeTree`] from [`Semantic`].
9594
pub fn into_symbol_table_and_scope_tree(self) -> (SymbolTable, ScopeTree) {
9695
(self.symbols, self.scopes)
9796
}
9897

98+
/// Extract [`SymbolTable`], [`ScopeTree`] and [`AstNode`] from the [`Semantic`].
99+
pub fn into_symbols_scopes_nodes(self) -> (SymbolTable, ScopeTree, AstNodes<'a>) {
100+
(self.symbols, self.scopes, self.nodes)
101+
}
102+
99103
/// Source code of the JavaScript/TypeScript program being analyzed.
100104
pub fn source_text(&self) -> &'a str {
101105
self.source_text

crates/oxc_syntax/src/reference.rs

+5-18
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use oxc_index::Idx;
66
#[cfg(feature = "serialize")]
77
use serde::{Serialize, Serializer};
88

9-
use crate::{node::NodeId, scope::ScopeId, symbol::SymbolId};
9+
use crate::{node::NodeId, symbol::SymbolId};
1010

1111
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
1212
pub struct ReferenceId(NonMaxU32);
@@ -234,8 +234,6 @@ impl<'alloc> CloneIn<'alloc> for ReferenceFlags {
234234
pub struct Reference {
235235
/// The AST node making the reference.
236236
node_id: NodeId,
237-
/// The scope of the AST node making the reference.
238-
scope_id: ScopeId,
239237
/// The symbol being referenced.
240238
///
241239
/// This will be [`None`] if no symbol could be found within
@@ -250,19 +248,14 @@ pub struct Reference {
250248
impl Reference {
251249
/// Create a new unresolved reference.
252250
#[inline]
253-
pub fn new(node_id: NodeId, scope_id: ScopeId, flags: ReferenceFlags) -> Self {
254-
Self { node_id, scope_id, symbol_id: None, flags }
251+
pub fn new(node_id: NodeId, flags: ReferenceFlags) -> Self {
252+
Self { node_id, symbol_id: None, flags }
255253
}
256254

257255
/// Create a new resolved reference on a symbol.
258256
#[inline]
259-
pub fn new_with_symbol_id(
260-
node_id: NodeId,
261-
scope_id: ScopeId,
262-
symbol_id: SymbolId,
263-
flags: ReferenceFlags,
264-
) -> Self {
265-
Self { node_id, scope_id, symbol_id: Some(symbol_id), flags }
257+
pub fn new_with_symbol_id(node_id: NodeId, symbol_id: SymbolId, flags: ReferenceFlags) -> Self {
258+
Self { node_id, symbol_id: Some(symbol_id), flags }
266259
}
267260

268261
/// Get the id of the node that is referencing the symbol.
@@ -271,12 +264,6 @@ impl Reference {
271264
self.node_id
272265
}
273266

274-
/// Get the id of the scope that is referencing the symbol.
275-
#[inline]
276-
pub fn scope_id(&self) -> ScopeId {
277-
self.scope_id
278-
}
279-
280267
/// Get the id of the symbol being referenced.
281268
///
282269
/// Will return [`None`] if the symbol could not be resolved.

crates/oxc_traverse/src/context/scoping.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -306,16 +306,15 @@ impl TraverseScoping {
306306
symbol_id: SymbolId,
307307
flags: ReferenceFlags,
308308
) -> ReferenceId {
309-
let reference =
310-
Reference::new_with_symbol_id(NodeId::DUMMY, self.current_scope_id, symbol_id, flags);
309+
let reference = Reference::new_with_symbol_id(NodeId::DUMMY, symbol_id, flags);
311310
let reference_id = self.symbols.create_reference(reference);
312311
self.symbols.add_resolved_reference(symbol_id, reference_id);
313312
reference_id
314313
}
315314

316315
/// Create an unbound reference
317316
pub fn create_unbound_reference(&mut self, name: &str, flags: ReferenceFlags) -> ReferenceId {
318-
let reference = Reference::new(NodeId::DUMMY, self.current_scope_id, flags);
317+
let reference = Reference::new(NodeId::DUMMY, flags);
319318
let reference_id = self.symbols.create_reference(reference);
320319
self.scopes.add_root_unresolved_reference(name, reference_id);
321320
reference_id

tasks/benchmark/benches/minifier.rs

+3-7
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,10 @@ fn bench_mangler(criterion: &mut Criterion) {
5858
b.iter_with_setup_wrapper(|runner| {
5959
allocator.reset();
6060
let program = Parser::new(&allocator, source_text, source_type).parse().program;
61-
let (symbols, scopes) = SemanticBuilder::new()
62-
.with_scope_tree_child_ids(true)
63-
.build(&program)
64-
.semantic
65-
.into_symbol_table_and_scope_tree();
61+
let semantic =
62+
SemanticBuilder::new().with_scope_tree_child_ids(true).build(&program).semantic;
6663
runner.run(|| {
67-
let _ =
68-
Mangler::new().build_with_symbols_and_scopes(symbols, &scopes, &program);
64+
let _ = Mangler::new().build_with_semantic(semantic, &program);
6965
});
7066
});
7167
});

0 commit comments

Comments
 (0)