Skip to content

Commit 1eac3d2

Browse files
authored
perf(semantic): use Atom<'a> for References (#3972)
Relates to [this issue](oxc-project/backlog#31) on the backlog.
1 parent 0c81fbe commit 1eac3d2

File tree

12 files changed

+88
-88
lines changed

12 files changed

+88
-88
lines changed

crates/oxc_linter/src/rules/eslint/no_global_assign.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ impl Rule for NoGlobalAssign {
6666
let reference = symbol_table.get_reference(reference_id);
6767
if reference.is_write() {
6868
let name = reference.name();
69-
if !self.excludes.contains(name) && ctx.env_contains_var(name) {
69+
// Vec::contains isn't working here, but this has the same
70+
// effect and time complexity.
71+
if !self.excludes.iter().any(|e| e == name) && ctx.env_contains_var(name) {
7072
ctx.diagnostic(no_global_assign_diagnostic(name, reference.span()));
7173
}
7274
}

crates/oxc_minifier/src/mangler/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ use oxc_span::CompactStr;
77
type Slot = usize;
88

99
#[derive(Debug)]
10-
pub struct Mangler {
11-
symbol_table: SymbolTable,
10+
pub struct Mangler<'a> {
11+
symbol_table: SymbolTable<'a>,
1212
}
1313

14-
impl Mangler {
14+
impl<'a> Mangler<'a> {
1515
pub fn get_symbol_name(&self, symbol_id: SymbolId) -> &str {
1616
self.symbol_table.get_name(symbol_id)
1717
}

crates/oxc_semantic/src/builder.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use oxc_cfg::{
99
IterationInstructionKind, ReturnInstructionKind,
1010
};
1111
use oxc_diagnostics::OxcDiagnostic;
12-
use oxc_span::{CompactStr, SourceType, Span};
12+
use oxc_span::{Atom, CompactStr, SourceType, Span};
1313
use oxc_syntax::{module_record::ModuleRecord, operator::AssignmentOperator};
1414

1515
use crate::{
@@ -63,8 +63,8 @@ pub struct SemanticBuilder<'a> {
6363

6464
// builders
6565
pub nodes: AstNodes<'a>,
66-
pub scope: ScopeTree,
67-
pub symbols: SymbolTable,
66+
pub scope: ScopeTree<'a>,
67+
pub symbols: SymbolTable<'a>,
6868

6969
pub(crate) module_record: Arc<ModuleRecord>,
7070

@@ -315,7 +315,7 @@ impl<'a> SemanticBuilder<'a> {
315315

316316
pub fn declare_reference(
317317
&mut self,
318-
reference: Reference,
318+
reference: Reference<'a>,
319319
add_unresolved_reference: bool,
320320
) -> ReferenceId {
321321
let reference_name = reference.name().clone();
@@ -327,7 +327,7 @@ impl<'a> SemanticBuilder<'a> {
327327
reference_id,
328328
);
329329
} else {
330-
self.resolve_reference_ids(reference_name.clone(), vec![reference_id]);
330+
self.resolve_reference_ids(reference_name, vec![reference_id]);
331331
}
332332
reference_id
333333
}
@@ -361,7 +361,7 @@ impl<'a> SemanticBuilder<'a> {
361361
}
362362
}
363363

364-
fn resolve_reference_ids(&mut self, name: CompactStr, reference_ids: Vec<ReferenceId>) {
364+
fn resolve_reference_ids(&mut self, name: Atom<'a>, reference_ids: Vec<ReferenceId>) {
365365
let parent_scope_id =
366366
self.scope.get_parent_id(self.current_scope_id).unwrap_or(self.current_scope_id);
367367

@@ -1884,9 +1884,9 @@ impl<'a> SemanticBuilder<'a> {
18841884
}
18851885
}
18861886

1887-
fn reference_identifier(&mut self, ident: &IdentifierReference) {
1887+
fn reference_identifier(&mut self, ident: &IdentifierReference<'a>) {
18881888
let flag = self.resolve_reference_usages();
1889-
let name = ident.name.to_compact_str();
1889+
let name = ident.name.clone();
18901890
let reference = Reference::new(ident.span, name, self.current_node_id, flag);
18911891
// `function foo({bar: identifier_reference}) {}`
18921892
// ^^^^^^^^^^^^^^^^^^^^ Parameter initializer must be resolved immediately
@@ -1905,7 +1905,7 @@ impl<'a> SemanticBuilder<'a> {
19051905
}
19061906
}
19071907

1908-
fn reference_jsx_identifier(&mut self, ident: &JSXIdentifier) {
1908+
fn reference_jsx_identifier(&mut self, ident: &JSXIdentifier<'a>) {
19091909
match self.nodes.parent_kind(self.current_node_id) {
19101910
Some(AstKind::JSXElementName(_)) => {
19111911
if !ident.name.chars().next().is_some_and(char::is_uppercase) {
@@ -1917,7 +1917,7 @@ impl<'a> SemanticBuilder<'a> {
19171917
}
19181918
let reference = Reference::new(
19191919
ident.span,
1920-
ident.name.to_compact_str(),
1920+
ident.name.clone(),
19211921
self.current_node_id,
19221922
ReferenceFlag::read(),
19231923
);

crates/oxc_semantic/src/lib.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ pub struct Semantic<'a> {
4242

4343
nodes: AstNodes<'a>,
4444

45-
scopes: ScopeTree,
45+
scopes: ScopeTree<'a>,
4646

47-
symbols: SymbolTable,
47+
symbols: SymbolTable<'a>,
4848

4949
classes: ClassTable,
5050

@@ -60,7 +60,7 @@ pub struct Semantic<'a> {
6060
}
6161

6262
impl<'a> Semantic<'a> {
63-
pub fn into_symbol_table_and_scope_tree(self) -> (SymbolTable, ScopeTree) {
63+
pub fn into_symbol_table_and_scope_tree(self) -> (SymbolTable<'a>, ScopeTree<'a>) {
6464
(self.symbols, self.scopes)
6565
}
6666

@@ -84,7 +84,7 @@ impl<'a> Semantic<'a> {
8484
&self.classes
8585
}
8686

87-
pub fn scopes_mut(&mut self) -> &mut ScopeTree {
87+
pub fn scopes_mut(&mut self) -> &mut ScopeTree<'a> {
8888
&mut self.scopes
8989
}
9090

crates/oxc_semantic/src/reference.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Silence erroneous warnings from Rust Analyser for `#[derive(Tsify)]`
22
#![allow(non_snake_case)]
33

4-
use oxc_span::{CompactStr, Span};
4+
use oxc_span::{Atom, Span};
55
pub use oxc_syntax::reference::{ReferenceFlag, ReferenceId};
66
#[cfg(feature = "serialize")]
77
use serde::Serialize;
@@ -13,25 +13,25 @@ use crate::{symbol::SymbolId, AstNodeId};
1313
#[derive(Debug, Clone)]
1414
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
1515
#[cfg_attr(feature = "serialize", serde(rename_all = "camelCase"))]
16-
pub struct Reference {
16+
pub struct Reference<'a> {
1717
span: Span,
1818
/// The name of the identifier that was referred to
19-
name: CompactStr,
19+
name: Atom<'a>,
2020
node_id: AstNodeId,
2121
symbol_id: Option<SymbolId>,
2222
/// Describes how this referenced is used by other AST nodes. References can
2323
/// be reads, writes, or both.
2424
flag: ReferenceFlag,
2525
}
2626

27-
impl Reference {
28-
pub fn new(span: Span, name: CompactStr, node_id: AstNodeId, flag: ReferenceFlag) -> Self {
27+
impl<'a> Reference<'a> {
28+
pub fn new(span: Span, name: Atom<'a>, node_id: AstNodeId, flag: ReferenceFlag) -> Self {
2929
Self { span, name, node_id, symbol_id: None, flag }
3030
}
3131

3232
pub fn new_with_symbol_id(
3333
span: Span,
34-
name: CompactStr,
34+
name: Atom<'a>,
3535
node_id: AstNodeId,
3636
symbol_id: SymbolId,
3737
flag: ReferenceFlag,
@@ -43,7 +43,7 @@ impl Reference {
4343
self.span
4444
}
4545

46-
pub fn name(&self) -> &CompactStr {
46+
pub fn name(&self) -> &Atom<'a> {
4747
&self.name
4848
}
4949

crates/oxc_semantic/src/scope.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::hash::BuildHasherDefault;
22

33
use indexmap::IndexMap;
44
use oxc_index::IndexVec;
5-
use oxc_span::CompactStr;
5+
use oxc_span::{Atom, CompactStr};
66
pub use oxc_syntax::scope::{ScopeFlags, ScopeId};
77
use rustc_hash::{FxHashMap, FxHasher};
88

@@ -11,13 +11,13 @@ use crate::{reference::ReferenceId, symbol::SymbolId, AstNodeId};
1111
type FxIndexMap<K, V> = IndexMap<K, V, BuildHasherDefault<FxHasher>>;
1212

1313
type Bindings = FxIndexMap<CompactStr, SymbolId>;
14-
type UnresolvedReferences = FxHashMap<CompactStr, Vec<ReferenceId>>;
14+
type UnresolvedReferences<'a> = FxHashMap<Atom<'a>, Vec<ReferenceId>>;
1515

1616
/// Scope Tree
1717
///
1818
/// `SoA` (Struct of Arrays) for memory efficiency.
1919
#[derive(Debug, Default)]
20-
pub struct ScopeTree {
20+
pub struct ScopeTree<'a> {
2121
/// Maps a scope to the parent scope it belongs in
2222
parent_ids: IndexVec<ScopeId, Option<ScopeId>>,
2323

@@ -27,10 +27,10 @@ pub struct ScopeTree {
2727
node_ids: FxHashMap<ScopeId, AstNodeId>,
2828
flags: IndexVec<ScopeId, ScopeFlags>,
2929
bindings: IndexVec<ScopeId, Bindings>,
30-
unresolved_references: IndexVec<ScopeId, UnresolvedReferences>,
30+
unresolved_references: IndexVec<ScopeId, UnresolvedReferences<'a>>,
3131
}
3232

33-
impl ScopeTree {
33+
impl<'a> ScopeTree<'a> {
3434
pub fn len(&self) -> usize {
3535
self.parent_ids.len()
3636
}
@@ -141,7 +141,7 @@ impl ScopeTree {
141141
self.get_binding(self.root_scope_id(), name)
142142
}
143143

144-
pub fn add_root_unresolved_reference(&mut self, name: CompactStr, reference_id: ReferenceId) {
144+
pub fn add_root_unresolved_reference(&mut self, name: Atom<'a>, reference_id: ReferenceId) {
145145
self.add_unresolved_reference(self.root_scope_id(), name, reference_id);
146146
}
147147

@@ -208,7 +208,7 @@ impl ScopeTree {
208208
pub(crate) fn add_unresolved_reference(
209209
&mut self,
210210
scope_id: ScopeId,
211-
name: CompactStr,
211+
name: Atom<'a>,
212212
reference_id: ReferenceId,
213213
) {
214214
self.unresolved_references[scope_id].entry(name).or_default().push(reference_id);
@@ -217,7 +217,7 @@ impl ScopeTree {
217217
pub(crate) fn extend_unresolved_reference(
218218
&mut self,
219219
scope_id: ScopeId,
220-
name: CompactStr,
220+
name: Atom<'a>,
221221
reference_ids: Vec<ReferenceId>,
222222
) {
223223
self.unresolved_references[scope_id].entry(name).or_default().extend(reference_ids);
@@ -226,7 +226,7 @@ impl ScopeTree {
226226
pub(crate) fn unresolved_references_mut(
227227
&mut self,
228228
scope_id: ScopeId,
229-
) -> &mut UnresolvedReferences {
229+
) -> &mut UnresolvedReferences<'a> {
230230
&mut self.unresolved_references[scope_id]
231231
}
232232
}

crates/oxc_semantic/src/symbol.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,19 @@ export type IndexVec<I, T> = Array<T>;
2828
/// `SoA` (Struct of Arrays) for memory efficiency.
2929
#[derive(Debug, Default)]
3030
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify), serde(rename_all = "camelCase"))]
31-
pub struct SymbolTable {
31+
pub struct SymbolTable<'a> {
3232
pub spans: IndexVec<SymbolId, Span>,
3333
pub names: IndexVec<SymbolId, CompactStr>,
3434
pub flags: IndexVec<SymbolId, SymbolFlags>,
3535
pub scope_ids: IndexVec<SymbolId, ScopeId>,
3636
/// Pointer to the AST Node where this symbol is declared
3737
pub declarations: IndexVec<SymbolId, AstNodeId>,
3838
pub resolved_references: IndexVec<SymbolId, Vec<ReferenceId>>,
39-
pub references: IndexVec<ReferenceId, Reference>,
39+
pub references: IndexVec<ReferenceId, Reference<'a>>,
4040
pub redeclare_variables: IndexVec<SymbolId, Vec<Span>>,
4141
}
4242

43-
impl SymbolTable {
43+
impl<'a> SymbolTable<'a> {
4444
pub fn len(&self) -> usize {
4545
self.spans.len()
4646
}
@@ -136,15 +136,15 @@ impl SymbolTable {
136136
self.redeclare_variables[symbol_id].push(span);
137137
}
138138

139-
pub fn create_reference(&mut self, reference: Reference) -> ReferenceId {
139+
pub fn create_reference(&mut self, reference: Reference<'a>) -> ReferenceId {
140140
self.references.push(reference)
141141
}
142142

143-
pub fn get_reference(&self, reference_id: ReferenceId) -> &Reference {
143+
pub fn get_reference(&self, reference_id: ReferenceId) -> &Reference<'a> {
144144
&self.references[reference_id]
145145
}
146146

147-
pub fn get_reference_mut(&mut self, reference_id: ReferenceId) -> &mut Reference {
147+
pub fn get_reference_mut(&mut self, reference_id: ReferenceId) -> &mut Reference<'a> {
148148
&mut self.references[reference_id]
149149
}
150150

crates/oxc_semantic/tests/integration/util/symbol_tester.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -110,18 +110,24 @@ impl<'a> SymbolTester<'a> {
110110
self
111111
}
112112

113+
// Note: can't use `Reference::is_read()` due to error warning about overly
114+
// generic FnMut impl.
115+
113116
#[must_use]
114117
pub fn has_number_of_reads(self, ref_count: usize) -> Self {
115-
self.has_number_of_references_where(ref_count, Reference::is_read)
118+
#[allow(clippy::redundant_closure_for_method_calls)]
119+
self.has_number_of_references_where(ref_count, |r| r.is_read())
116120
}
117121

118122
#[must_use]
119123
pub fn has_number_of_writes(self, ref_count: usize) -> Self {
120-
self.has_number_of_references_where(ref_count, Reference::is_write)
124+
#[allow(clippy::redundant_closure_for_method_calls)]
125+
self.has_number_of_references_where(ref_count, |r| r.is_write())
121126
}
122127

123128
#[must_use]
124129
pub fn has_number_of_references(self, ref_count: usize) -> Self {
130+
#[allow(clippy::redundant_closure_for_method_calls)]
125131
self.has_number_of_references_where(ref_count, |_| true)
126132
}
127133

crates/oxc_transformer/src/react/jsx.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -986,8 +986,7 @@ fn get_read_identifier_reference<'a>(
986986
name: Atom<'a>,
987987
ctx: &mut TraverseCtx<'a>,
988988
) -> IdentifierReference<'a> {
989-
let reference_id =
990-
ctx.create_reference_in_current_scope(name.to_compact_str(), ReferenceFlag::Read);
989+
let reference_id = ctx.create_reference_in_current_scope(name.clone(), ReferenceFlag::Read);
991990
IdentifierReference::new_read(span, name, Some(reference_id))
992991
}
993992

crates/oxc_transformer/src/typescript/annotations.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -540,11 +540,8 @@ struct Assignment<'a> {
540540
impl<'a> Assignment<'a> {
541541
// Creates `this.name = name`
542542
fn create_this_property_assignment(&self, ctx: &mut TraverseCtx<'a>) -> Statement<'a> {
543-
let reference_id = ctx.create_bound_reference(
544-
self.name.to_compact_str(),
545-
self.symbol_id,
546-
ReferenceFlag::Read,
547-
);
543+
let reference_id =
544+
ctx.create_bound_reference(self.name.clone(), self.symbol_id, ReferenceFlag::Read);
548545
let id = IdentifierReference::new_read(self.span, self.name.clone(), Some(reference_id));
549546

550547
ctx.ast.expression_statement(

0 commit comments

Comments
 (0)