Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf(semantic): simplify logic in enter_scope + leave_scope #4383

Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 35 additions & 29 deletions crates/oxc_semantic/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ impl<'a> SemanticBuilder<'a> {
current_symbol_flags: SymbolFlags::empty(),
current_reference_flag: ReferenceFlag::empty(),
current_scope_id,
current_scope_depth: 0,
current_scope_depth: 1, // Start with depth for `Program`
function_stack: vec![],
namespace_stack: vec![],
nodes: AstNodes::default(),
Expand Down Expand Up @@ -200,7 +200,7 @@ impl<'a> SemanticBuilder<'a> {
}
}

debug_assert_eq!(self.current_scope_depth, 0);
debug_assert_eq!(self.current_scope_depth, 1);
self.scope.root_unresolved_references =
self.unresolved_references.into_iter().next().unwrap();

Expand Down Expand Up @@ -460,31 +460,26 @@ impl<'a> SemanticBuilder<'a> {
}

impl<'a> Visit<'a> for SemanticBuilder<'a> {
// NB: Not called for `Program`
fn enter_scope(&mut self, flags: ScopeFlags, scope_id: &Cell<Option<ScopeId>>) {
let parent_scope_id =
if flags.contains(ScopeFlags::Top) { None } else { Some(self.current_scope_id) };
let parent_scope_id = self.current_scope_id;

let mut flags = flags;

if !flags.is_strict_mode() && self.current_node_flags.has_class() {
// NOTE A class definition is always strict mode code.
flags |= ScopeFlags::StrictMode;
};
flags = self.scope.get_new_scope_flags(flags, parent_scope_id);

if let Some(parent_scope_id) = parent_scope_id {
flags = self.scope.get_new_scope_flags(flags, parent_scope_id);
}

self.current_scope_id = self.scope.add_scope(parent_scope_id, self.current_node_id, flags);
self.current_scope_id =
self.scope.add_scope(Some(parent_scope_id), self.current_node_id, flags);
scope_id.set(Some(self.current_scope_id));

if let Some(parent_scope_id) = parent_scope_id {
if self.scope.get_flags(parent_scope_id).is_catch_clause() {
// Clone the `CatchClause` bindings and add them to the current scope.
// to make it easier to check redeclare errors.
let bindings = self.scope.get_bindings(parent_scope_id).clone();
self.scope.get_bindings_mut(self.current_scope_id).extend(bindings);
}
if self.scope.get_flags(parent_scope_id).is_catch_clause() {
// Clone the `CatchClause` bindings and add them to the current scope.
// to make it easier to check redeclare errors.
let bindings = self.scope.get_bindings(parent_scope_id).clone();
self.scope.get_bindings_mut(self.current_scope_id).extend(bindings);
overlookmotel marked this conversation as resolved.
Show resolved Hide resolved
}

// Increment scope depth, and ensure stack is large enough that
Expand All @@ -495,16 +490,25 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
}
}

// NB: Not called for `Program`
fn leave_scope(&mut self) {
self.resolve_references_for_current_scope();
if let Some(parent_id) = self.scope.get_parent_id(self.current_scope_id) {

// `get_parent_id` always returns `Some` because this method is not called for `Program`.
// So we could `.unwrap()` here. But that seems to produce a small perf impact, probably because
// `leave_scope` then doesn't get inlined because of its larger size due to the panic code.
let parent_id = self.scope.get_parent_id(self.current_scope_id);
debug_assert!(parent_id.is_some());
if let Some(parent_id) = parent_id {
self.current_scope_id = parent_id;
}

self.current_scope_depth -= 1;
}

// Setup all the context for the binder.
// The order is important here.
// NB: Not called for `Program`.
fn enter_node(&mut self, kind: AstKind<'a>) {
self.create_ast_node(kind);
self.enter_kind(kind);
Expand Down Expand Up @@ -542,16 +546,15 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
);
self.record_ast_node();

self.enter_scope(
{
let mut flags = ScopeFlags::Top;
if program.is_strict() {
flags |= ScopeFlags::StrictMode;
}
flags
},
&program.scope_id,
);
// Don't call `enter_scope` here as `Program` is a special case - scope has no `parent_id`.
// Inline the specific logic for `Program` here instead.
// This simplifies logic in `enter_scope`, as it doesn't have to handle the special case.
let mut flags = ScopeFlags::Top;
if program.is_strict() {
flags |= ScopeFlags::StrictMode;
}
self.current_scope_id = self.scope.add_scope(None, self.current_node_id, flags);
program.scope_id.set(Some(self.current_scope_id));

if let Some(hashbang) = &program.hashbang {
self.visit_hashbang(hashbang);
Expand All @@ -567,7 +570,10 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
control_flow!(self, |cfg| cfg.release_error_harness(error_harness));
/* cfg */

self.leave_scope();
// Don't call `leave_scope` here as `Program` is a special case - scope has no `parent_id`.
// This simplifies `leave_scope`.
self.resolve_references_for_current_scope();

self.leave_node(kind);
}

Expand Down
Loading