mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
perf(semantics): avoid hashing when resolving references (#248)
This commit is contained in:
parent
b17335d724
commit
222dcb3bf1
6 changed files with 87 additions and 22 deletions
|
|
@ -93,7 +93,7 @@ impl Rule for ValidTypeof {
|
|||
}
|
||||
|
||||
if sibling.is_undefined()
|
||||
&& ctx.symbols().get_resolved_reference(sibling_id.into()).is_none()
|
||||
&& ctx.semantic().is_unresolved_reference(sibling_id.into())
|
||||
{
|
||||
ctx.diagnostic_with_fix(
|
||||
if self.require_string_literals {
|
||||
|
|
|
|||
|
|
@ -11,8 +11,9 @@ mod symbol;
|
|||
use std::rc::Rc;
|
||||
|
||||
pub use builder::SemanticBuilder;
|
||||
use node::AstNodeId;
|
||||
pub use node::{AstNode, AstNodes, SemanticNode};
|
||||
use oxc_ast::{module_record::ModuleRecord, SourceType, Trivias};
|
||||
use oxc_ast::{module_record::ModuleRecord, AstKind, SourceType, Trivias};
|
||||
pub use scope::{Scope, ScopeFlags, ScopeTree};
|
||||
pub use symbol::{Reference, ResolvedReference, Symbol, SymbolFlags, SymbolTable};
|
||||
|
||||
|
|
@ -67,4 +68,12 @@ impl<'a> Semantic<'a> {
|
|||
pub fn symbols(&self) -> &SymbolTable {
|
||||
&self.symbols
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_unresolved_reference(&self, node_id: AstNodeId) -> bool {
|
||||
let reference_node = &self.nodes()[node_id];
|
||||
let AstKind::IdentifierReference(id) = reference_node.kind() else { return false; };
|
||||
let scope = &self.scopes()[reference_node.scope_id()];
|
||||
scope.unresolved_references.contains_key(&id.name)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,11 +73,7 @@ impl ScopeBuilder {
|
|||
let scope = &self.scopes[scope];
|
||||
if let Some(symbol_id) = scope.get().get_variable_symbol_id(&variable) {
|
||||
// We have resolved this reference.
|
||||
let symbol = &mut symbol_table[symbol_id];
|
||||
symbol.add_references(&reference);
|
||||
for r in reference {
|
||||
symbol_table.resolve_reference(r.ast_node_id, r.resolve_to(symbol_id));
|
||||
}
|
||||
symbol_table.resolve_reference(reference, symbol_id);
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ mod table;
|
|||
use bitflags::bitflags;
|
||||
use oxc_ast::{Atom, Span};
|
||||
|
||||
use self::reference::ResolvedReferenceId;
|
||||
pub use self::{
|
||||
id::SymbolId,
|
||||
reference::{Reference, ReferenceFlag, ResolvedReference},
|
||||
|
|
@ -24,7 +25,7 @@ pub struct Symbol {
|
|||
span: Span,
|
||||
flags: SymbolFlags,
|
||||
/// Pointers to the AST Nodes that reference this symbol
|
||||
references: Vec<AstNodeId>,
|
||||
references: Vec<ResolvedReferenceId>,
|
||||
}
|
||||
|
||||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
||||
|
|
@ -119,12 +120,8 @@ impl Symbol {
|
|||
self.flags.contains(SymbolFlags::Export)
|
||||
}
|
||||
|
||||
pub fn add_references(&mut self, new_references: &[Reference]) {
|
||||
self.references.extend(new_references.iter().map(|r| r.ast_node_id));
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn references(&self) -> &[AstNodeId] {
|
||||
pub fn references(&self) -> &[ResolvedReferenceId] {
|
||||
&self.references
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#![allow(non_upper_case_globals)]
|
||||
|
||||
use std::num::NonZeroUsize;
|
||||
|
||||
use bitflags::bitflags;
|
||||
use oxc_ast::Span;
|
||||
|
||||
|
|
@ -83,3 +85,24 @@ impl ResolvedReference {
|
|||
self.reference.span
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct ResolvedReferenceId(NonZeroUsize);
|
||||
|
||||
impl Default for ResolvedReferenceId {
|
||||
fn default() -> Self {
|
||||
Self::new(1)
|
||||
}
|
||||
}
|
||||
|
||||
impl ResolvedReferenceId {
|
||||
#[must_use]
|
||||
pub fn new(n: usize) -> Self {
|
||||
unsafe { Self(NonZeroUsize::new_unchecked(n)) }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub(crate) fn index0(self) -> usize {
|
||||
self.0.get() - 1
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,23 @@
|
|||
use std::ops::{Deref, Index, IndexMut};
|
||||
|
||||
use oxc_ast::{Atom, Span};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use super::reference::ResolvedReferenceId;
|
||||
use super::{Symbol, SymbolFlags, SymbolId};
|
||||
use crate::node::AstNodeId;
|
||||
use crate::ResolvedReference;
|
||||
use crate::{Reference, ResolvedReference};
|
||||
|
||||
/// `SymbolTable` is a storage of all the symbols (related to `BindingIdentifiers`)
|
||||
/// and references (related to `IdentifierReferences`) of the program. It supports two
|
||||
/// kinds of queries: indexing by `SymbolId` retrieves the corresponding `Symbol` and
|
||||
/// indexing by `ResolvedReferenceId` retrieves the correspodning `ResolvedReference`
|
||||
///
|
||||
#[derive(Debug, Default)]
|
||||
pub struct SymbolTable {
|
||||
/// Stores all the `Symbols` indexed by `SymbolId`
|
||||
symbols: Vec<Symbol>,
|
||||
resolved_references: FxHashMap<AstNodeId, ResolvedReference>,
|
||||
/// Stores all the resolved references indexed by `ResolvedReferenceId`
|
||||
resolved_references: Vec<ResolvedReference>,
|
||||
}
|
||||
|
||||
impl Index<SymbolId> for SymbolTable {
|
||||
|
|
@ -27,6 +34,20 @@ impl IndexMut<SymbolId> for SymbolTable {
|
|||
}
|
||||
}
|
||||
|
||||
impl Index<ResolvedReferenceId> for SymbolTable {
|
||||
type Output = ResolvedReference;
|
||||
|
||||
fn index(&self, index: ResolvedReferenceId) -> &Self::Output {
|
||||
&self.resolved_references[index.index0()]
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<ResolvedReferenceId> for SymbolTable {
|
||||
fn index_mut(&mut self, index: ResolvedReferenceId) -> &mut Self::Output {
|
||||
&mut self.resolved_references[index.index0()]
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for SymbolTable {
|
||||
type Target = Vec<Symbol>;
|
||||
|
||||
|
|
@ -42,12 +63,12 @@ impl SymbolTable {
|
|||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get(&self, id: SymbolId) -> Option<&Symbol> {
|
||||
pub fn get_symbol(&self, id: SymbolId) -> Option<&Symbol> {
|
||||
self.symbols.get(id.index0())
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn create(
|
||||
pub(crate) fn create(
|
||||
&mut self,
|
||||
declaration: AstNodeId,
|
||||
name: Atom,
|
||||
|
|
@ -61,11 +82,30 @@ impl SymbolTable {
|
|||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get_resolved_reference(&self, id: AstNodeId) -> Option<&ResolvedReference> {
|
||||
self.resolved_references.get(&id)
|
||||
pub fn resolved_references(&self) -> &Vec<ResolvedReference> {
|
||||
&self.resolved_references
|
||||
}
|
||||
|
||||
pub fn resolve_reference(&mut self, id: AstNodeId, reference: ResolvedReference) {
|
||||
self.resolved_references.insert(id, reference);
|
||||
#[must_use]
|
||||
pub fn get_resolved_reference(&self, id: ResolvedReferenceId) -> Option<&ResolvedReference> {
|
||||
self.resolved_references.get(id.index0())
|
||||
}
|
||||
|
||||
/// Resolve all `references` to `symbol_id`
|
||||
pub(crate) fn resolve_reference(&mut self, references: Vec<Reference>, symbol_id: SymbolId) {
|
||||
let additional_len = references.len();
|
||||
let symbol = &mut self.symbols[symbol_id];
|
||||
|
||||
self.resolved_references.reserve(additional_len);
|
||||
symbol.references.reserve(additional_len);
|
||||
|
||||
for reference in references {
|
||||
let resolved_reference_id =
|
||||
ResolvedReferenceId::new(self.resolved_references.len() + 1);
|
||||
let resolved_reference = reference.resolve_to(symbol_id);
|
||||
self.resolved_references.push(resolved_reference);
|
||||
// explicitly push to vector here in correspondence to the previous reserve call
|
||||
symbol.references.push(resolved_reference_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue