perf(semantics): avoid hashing when resolving references (#248)

This commit is contained in:
yangchenye 2023-04-03 01:47:59 -05:00 committed by GitHub
parent b17335d724
commit 222dcb3bf1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 87 additions and 22 deletions

View file

@ -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 {

View file

@ -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)
}
}

View file

@ -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;
}
}

View file

@ -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
}

View file

@ -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
}
}

View file

@ -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);
}
}
}