Skip to content

Commit

Permalink
perf(semantic): allocate child scope in allocator (#8045)
Browse files Browse the repository at this point in the history
  • Loading branch information
Boshen committed Dec 20, 2024
1 parent 414e828 commit 2e8872c
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 36 deletions.
82 changes: 48 additions & 34 deletions crates/oxc_semantic/src/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use std::{fmt, mem};

use rustc_hash::{FxBuildHasher, FxHashMap};

use oxc_allocator::Allocator;
use oxc_index::IndexVec;
use oxc_allocator::{Allocator, Vec as ArenaVec};
use oxc_index::{Idx, IndexVec};
use oxc_span::CompactStr;
use oxc_syntax::{
node::NodeId,
Expand All @@ -29,9 +29,6 @@ pub struct ScopeTree {
/// Maps a scope to the parent scope it belongs in.
parent_ids: IndexVec<ScopeId, Option<ScopeId>>,

/// Maps a scope to direct children scopes.
child_ids: IndexVec<ScopeId, Vec<ScopeId>>,

/// Runtime flag for constructing child_ids.
pub(crate) build_child_ids: bool,

Expand All @@ -55,13 +52,13 @@ impl Default for ScopeTree {
fn default() -> Self {
Self {
parent_ids: IndexVec::new(),
child_ids: IndexVec::new(),
build_child_ids: false,
node_ids: IndexVec::new(),
flags: IndexVec::new(),
root_unresolved_references: UnresolvedReferences::default(),
cell: ScopeTreeCell::new(Allocator::default(), |_bump| ScopeTreeInner {
cell: ScopeTreeCell::new(Allocator::default(), |allocator| ScopeTreeInner {
bindings: IndexVec::new(),
child_ids: ArenaVec::new_in(allocator),
}),
}
}
Expand All @@ -80,6 +77,9 @@ pub(crate) struct ScopeTreeInner<'cell> {
///
/// A binding is a mapping from an identifier name to its [`SymbolId`]
pub(crate) bindings: IndexVec<ScopeId, Bindings<'cell>>,

/// Maps a scope to direct children scopes.
child_ids: ArenaVec<'cell, ArenaVec<'cell, ScopeId>>,
}

impl ScopeTree {
Expand Down Expand Up @@ -189,7 +189,9 @@ impl ScopeTree {
if self.build_child_ids {
// Set this scope as child of parent scope
if let Some(parent_id) = parent_id {
self.child_ids[parent_id].push(scope_id);
self.cell.with_dependent_mut(|_allocator, inner| {
inner.child_ids[parent_id.index()].push(scope_id);
});
}
}
}
Expand All @@ -200,25 +202,29 @@ impl ScopeTree {
pub fn change_parent_id(&mut self, scope_id: ScopeId, new_parent_id: Option<ScopeId>) {
let old_parent_id = mem::replace(&mut self.parent_ids[scope_id], new_parent_id);
if self.build_child_ids {
// Remove this scope from old parent scope
if let Some(old_parent_id) = old_parent_id {
self.child_ids[old_parent_id].retain(|&child_id| child_id != scope_id);
}
// And add it to new parent scope
if let Some(parent_id) = new_parent_id {
self.child_ids[parent_id].push(scope_id);
}
self.cell.with_dependent_mut(|_allocator, inner| {
// Remove this scope from old parent scope
if let Some(old_parent_id) = old_parent_id {
inner.child_ids[old_parent_id.index()].retain(|&child_id| child_id != scope_id);
}
// And add it to new parent scope
if let Some(parent_id) = new_parent_id {
inner.child_ids[parent_id.index()].push(scope_id);
}
});
}
}

/// Delete a scope.
pub fn delete_scope(&mut self, scope_id: ScopeId) {
if self.build_child_ids {
self.child_ids[scope_id].clear();
let parent_id = self.parent_ids[scope_id];
if let Some(parent_id) = parent_id {
self.child_ids[parent_id].retain(|&child_id| child_id != scope_id);
}
self.cell.with_dependent_mut(|_allocator, inner| {
inner.child_ids[scope_id.index()].clear();
let parent_id = self.parent_ids[scope_id];
if let Some(parent_id) = parent_id {
inner.child_ids[parent_id.index()].retain(|&child_id| child_id != scope_id);
}
});
}
}

Expand Down Expand Up @@ -310,15 +316,18 @@ impl ScopeTree {
/// Get the child scopes of a scope
#[inline]
pub fn get_child_ids(&self, scope_id: ScopeId) -> &[ScopeId] {
&self.child_ids[scope_id]
&self.cell.borrow_dependent().child_ids[scope_id.index()]
}

pub fn iter_all_child_ids(&self, scope_id: ScopeId) -> impl Iterator<Item = ScopeId> + '_ {
let mut stack = self.child_ids[scope_id].clone();
let child_ids: &IndexVec<ScopeId, Vec<ScopeId>> = &self.child_ids;
let mut stack = self.cell.borrow_dependent().child_ids[scope_id.index()]
.iter()
.copied()
.collect::<Vec<_>>();
let child_ids = &self.cell.borrow_dependent().child_ids;
std::iter::from_fn(move || {
if let Some(scope_id) = stack.pop() {
if let Some(children) = child_ids.get(scope_id) {
if let Some(children) = child_ids.get(scope_id.index()) {
stack.extend(children.iter().copied());
}
Some(scope_id)
Expand All @@ -328,10 +337,11 @@ impl ScopeTree {
})
}

/// Get a mutable reference to a scope's children
#[inline]
pub fn get_child_ids_mut(&mut self, scope_id: ScopeId) -> &mut Vec<ScopeId> {
&mut self.child_ids[scope_id]
pub fn remove_child_scopes(&mut self, scope_id: ScopeId, child_scope_ids: &[ScopeId]) {
self.cell.with_dependent_mut(|_allocator, inner| {
inner.child_ids[scope_id.index()]
.retain(|scope_id| !child_scope_ids.contains(scope_id));
});
}

/// Create a scope.
Expand All @@ -349,10 +359,12 @@ impl ScopeTree {
});
self.node_ids.push(node_id);
if self.build_child_ids {
self.child_ids.push(vec![]);
if let Some(parent_id) = parent_id {
self.child_ids[parent_id].push(scope_id);
}
self.cell.with_dependent_mut(|allocator, inner| {
inner.child_ids.push(ArenaVec::new_in(allocator));
if let Some(parent_id) = parent_id {
inner.child_ids[parent_id.index()].push(scope_id);
}
});
}
scope_id
}
Expand Down Expand Up @@ -418,7 +430,9 @@ impl ScopeTree {
});
self.node_ids.reserve(additional);
if self.build_child_ids {
self.child_ids.reserve(additional);
self.cell.with_dependent_mut(|_allocator, inner| {
inner.child_ids.reserve(additional);
});
}
}
}
3 changes: 1 addition & 2 deletions crates/oxc_traverse/src/context/scoping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,7 @@ impl TraverseScoping {
fn insert_scope_below(&mut self, child_scope_ids: &[ScopeId], flags: ScopeFlags) -> ScopeId {
// Remove these scopes from parent's children
if self.scopes.has_child_ids() {
let current_child_scope_ids = self.scopes.get_child_ids_mut(self.current_scope_id);
current_child_scope_ids.retain(|scope_id| !child_scope_ids.contains(scope_id));
self.scopes.remove_child_scopes(self.current_scope_id, child_scope_ids);
}

// Create new scope as child of parent
Expand Down

0 comments on commit 2e8872c

Please sign in to comment.