mirror of
https://github.com/morluto/rea
synced 2026-10-26 14:25:49 -04:00
perf(javascript): reduce retained semantic analysis allocations (#1601)
Reduce retained semantic allocations and memoize lexical scope ancestry while preserving semantic identities. Refs #1065 and #1563; the complete-directory memory failure remains open.
This commit is contained in:
@@ -60,6 +60,7 @@ export interface JavaScriptSemanticAnalysisState {
|
||||
readonly parentsByNode: WeakMap<t.Node, t.Node>;
|
||||
readonly scopes: JavaScriptSemanticScopeState[];
|
||||
readonly scopesById: Map<string, JavaScriptSemanticScopeState>;
|
||||
/** Scope boundaries and descendant scopes resolved on demand. */
|
||||
readonly scopeByNode: WeakMap<t.Node, JavaScriptSemanticScopeState>;
|
||||
readonly bindingsById: Map<string, JavaScriptSemanticBindingState>;
|
||||
readonly callables: JavaScriptSemanticCallable[];
|
||||
@@ -94,7 +95,7 @@ export const resolveSemanticBindingState = (
|
||||
node: t.Node,
|
||||
name: string,
|
||||
): JavaScriptSemanticBindingState | undefined => {
|
||||
let scope = state.scopeByNode.get(node);
|
||||
let scope = semanticScopeForNode(state, node);
|
||||
while (scope !== undefined) {
|
||||
const binding = scope.bindings.get(name);
|
||||
if (binding !== undefined) return binding;
|
||||
@@ -113,7 +114,7 @@ export const semanticResolutionBlocked = (
|
||||
node: t.Node,
|
||||
name: string,
|
||||
): boolean => {
|
||||
let scope = state.scopeByNode.get(node);
|
||||
let scope = semanticScopeForNode(state, node);
|
||||
while (scope !== undefined) {
|
||||
if (scope.bindings.has(name)) return false;
|
||||
if (!scope.bindingsComplete) return true;
|
||||
@@ -125,6 +126,28 @@ export const semanticResolutionBlocked = (
|
||||
return false;
|
||||
};
|
||||
|
||||
const semanticScopeForNode = (
|
||||
state: JavaScriptSemanticAnalysisState,
|
||||
node: t.Node,
|
||||
): JavaScriptSemanticScopeState | undefined => {
|
||||
let candidate: t.Node | undefined = node;
|
||||
while (candidate !== undefined) {
|
||||
const scope = state.scopeByNode.get(candidate);
|
||||
if (scope !== undefined) {
|
||||
// Repeated references in a deep expression share this ancestry. Cache
|
||||
// the traversed path without eagerly indexing nodes never resolved.
|
||||
let descendant: t.Node | undefined = node;
|
||||
while (descendant !== undefined && descendant !== candidate) {
|
||||
state.scopeByNode.set(descendant, scope);
|
||||
descendant = state.parentsByNode.get(descendant);
|
||||
}
|
||||
return scope;
|
||||
}
|
||||
candidate = state.parentsByNode.get(candidate);
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
/** Resolve one name starting from an explicitly selected lexical scope. */
|
||||
export const resolveSemanticBindingFromScope = (
|
||||
scope: JavaScriptSemanticScopeState,
|
||||
|
||||
Reference in New Issue
Block a user