From f339aa625ffd71b936fe386250858e281e5b87ff Mon Sep 17 00:00:00 2001 From: Andrew Hundt Date: Thu, 13 Aug 2026 01:44:44 -0400 Subject: [PATCH 1/2] perf(lsp): collapse repeated Python scope-chain lookups Add cbm_scope_lookup_binding so callers can read lexical presence, type, and callable identity in one traversal. Route Python expression, call, and callable-reference resolution through that complete binding and use the existing checked bind APIs for allocation-failure detection. The neutral 11-pair production matrix kept exact output parity. Python scale latency was 4.33% below merge parent 07255cfe and 61.01% below upstream parent 0c64de93; incremental instructions were 3.09% and 54.07% lower. Focused ASan/UBSan scope and Python suites passed 33 and 125 tests. Signed-off-by: Andrew Hundt (cherry picked from commit 4d3a10304737b3a70c543ff19563be2dff214fdf) Signed-off-by: Martin Vogel --- internal/cbm/lsp/py_lsp.c | 52 +++++++++++++++++---------------------- internal/cbm/lsp/scope.c | 50 ++++++++++++------------------------- internal/cbm/lsp/scope.h | 4 +++ tests/test_scope.c | 20 +++++++++++++++ 4 files changed, 62 insertions(+), 64 deletions(-) diff --git a/internal/cbm/lsp/py_lsp.c b/internal/cbm/lsp/py_lsp.c index 8a03961152..2cf66ad012 100644 --- a/internal/cbm/lsp/py_lsp.c +++ b/internal/cbm/lsp/py_lsp.c @@ -191,20 +191,15 @@ static void py_disable_callable_value_proof(PyLSPContext *ctx) { static void py_scope_bind(PyLSPContext *ctx, const char *name, const CBMType *type) { ctx->type_cache_gen++; - cbm_scope_bind(ctx->current_scope, name, type); - if (name && !cbm_scope_contains(ctx->current_scope, name)) + if (!cbm_scope_bind_checked(ctx->current_scope, name, type)) py_disable_callable_value_proof(ctx); } static void py_scope_bind_callable(PyLSPContext *ctx, const char *name, const CBMType *type, const char *callable_qn) { ctx->type_cache_gen++; - cbm_scope_bind_callable(ctx->current_scope, name, type, callable_qn); - const char *bound = name ? cbm_scope_lookup_callable(ctx->current_scope, name) : NULL; - if (name && (!cbm_scope_contains(ctx->current_scope, name) || - (callable_qn && (!bound || strcmp(bound, callable_qn) != 0)))) { + if (!cbm_scope_bind_callable_checked(ctx->current_scope, name, type, callable_qn)) py_disable_callable_value_proof(ctx); - } } static CBMScope *py_scope_push_checked(PyLSPContext *ctx) { @@ -938,8 +933,9 @@ static const char *py_exact_callable_target_ex(PyLSPContext *ctx, TSNode node, char *name = py_node_text(ctx, node); if (!name) return NULL; - if (cbm_scope_contains(ctx->current_scope, name)) { - const char *bound = cbm_scope_lookup_callable(ctx->current_scope, name); + const CBMVarBinding *binding = cbm_scope_lookup_binding(ctx->current_scope, name); + if (binding) { + const char *bound = binding->callable_qn; if (bound && lexical_alias_out) { /* A lexical binding that does NOT simply name the module symbol * of the same spelling is an alias introduced in this body. Only @@ -1018,11 +1014,12 @@ static void py_resolve_value_references_at(PyLSPContext *ctx, TSNode call) { const char *candidate = strcmp(kind, "identifier") == 0 ? py_exact_imported_reference_candidate(ctx, source_name) : NULL; - if (candidate && cbm_scope_contains(ctx->current_scope, source_name)) { - const CBMType *binding = - cbm_type_resolve_alias(cbm_scope_lookup(ctx->current_scope, source_name)); - if (binding && binding->kind == CBM_TYPE_NAMED && binding->data.named.qualified_name && - strcmp(binding->data.named.qualified_name, candidate) == 0) { + const CBMVarBinding *scope_binding = + candidate ? cbm_scope_lookup_binding(ctx->current_scope, source_name) : NULL; + if (scope_binding) { + const CBMType *type = cbm_type_resolve_alias(scope_binding->type); + if (type && type->kind == CBM_TYPE_NAMED && type->data.named.qualified_name && + strcmp(type->data.named.qualified_name, candidate) == 0) { py_emit_unresolved_reference(ctx, candidate, arg); } } @@ -1498,9 +1495,9 @@ static const CBMType *py_eval_expr_type_uncached(PyLSPContext *ctx, TSNode node) char *name = py_node_text(ctx, node); if (!name) return cbm_type_unknown(); - const CBMType *t = cbm_scope_lookup(ctx->current_scope, name); - if (cbm_scope_contains(ctx->current_scope, name)) - return t ? t : cbm_type_unknown(); + const CBMVarBinding *binding = cbm_scope_lookup_binding(ctx->current_scope, name); + if (binding) + return binding->type ? binding->type : cbm_type_unknown(); // Builtin globals: True / False / None at top level. if (strcmp(name, "True") == 0 || strcmp(name, "False") == 0) return cbm_type_builtin(ctx->arena, "bool"); @@ -1767,8 +1764,9 @@ static const CBMType *py_eval_expr_type_uncached(PyLSPContext *ctx, TSNode node) } } // Constructor call: ClassName() returns NAMED(ClassName). - const CBMType *in_scope = cbm_scope_lookup(ctx->current_scope, fname); - const char *callable_qn = cbm_scope_lookup_callable(ctx->current_scope, fname); + const CBMVarBinding *binding = cbm_scope_lookup_binding(ctx->current_scope, fname); + const CBMType *in_scope = binding && binding->type ? binding->type : cbm_type_unknown(); + const char *callable_qn = binding ? binding->callable_qn : NULL; if (callable_qn) { return py_func_return_type(ctx, callable_qn); } @@ -1796,7 +1794,7 @@ static const CBMType *py_eval_expr_type_uncached(PyLSPContext *ctx, TSNode node) } /* Even an UNKNOWN local/parameter is a real lexical shadow. Do * not borrow the return type of a same-named module function. */ - if (cbm_scope_contains(ctx->current_scope, fname)) + if (binding) return cbm_type_unknown(); // Module-local function call. const CBMRegisteredFunc *f = @@ -2566,14 +2564,15 @@ static void py_emit_call_for(PyLSPContext *ctx, TSNode call_node) { * An ordinary local binding is also a hard shadow: if it is not a * proven callable alias, do not fall through and fabricate a direct * call to a module-level function with the same spelling. */ - if (cbm_scope_contains(ctx->current_scope, fname)) { - const char *alias_target = cbm_scope_lookup_callable(ctx->current_scope, fname); + const CBMVarBinding *binding = cbm_scope_lookup_binding(ctx->current_scope, fname); + if (binding) { + const char *alias_target = binding->callable_qn; if (alias_target) { py_emit_resolved_call_reason(ctx, alias_target, "lsp_callable_alias", 0.97f, fname, call_node); return; } - const CBMType *in_scope = cbm_scope_lookup(ctx->current_scope, fname); + const CBMType *in_scope = binding->type ? binding->type : cbm_type_unknown(); if (!cbm_type_is_unknown(in_scope) && in_scope->kind == CBM_TYPE_NAMED) { const char *qn = in_scope->data.named.qualified_name; const char *tail = qn ? strrchr(qn, '.') : NULL; @@ -2604,13 +2603,6 @@ static void py_emit_call_for(PyLSPContext *ctx, TSNode call_node) { } return; } - // Constructor call (ClassName()) - const CBMType *in_scope = cbm_scope_lookup(ctx->current_scope, fname); - if (!cbm_type_is_unknown(in_scope) && in_scope->kind == CBM_TYPE_NAMED) { - const char *qn = in_scope->data.named.qualified_name; - py_emit_resolved_call(ctx, qn, "lsp_constructor", 0.85f, call_node); - return; - } // Module-local function const CBMRegisteredFunc *f = cbm_registry_lookup_symbol(ctx->registry, ctx->module_qn, fname); diff --git a/internal/cbm/lsp/scope.c b/internal/cbm/lsp/scope.c index 5b842cc1ba..c44a0b544a 100644 --- a/internal/cbm/lsp/scope.c +++ b/internal/cbm/lsp/scope.c @@ -88,52 +88,34 @@ bool cbm_scope_bind_callable_checked(CBMScope *scope, const char *name, const CB return cbm_scope_bind_value(scope, name, type, callable_qn); } -const CBMType* cbm_scope_lookup(const CBMScope* scope, const char* name) { - if (!name) { - return cbm_type_unknown(); - } +const CBMVarBinding *cbm_scope_lookup_binding(const CBMScope *scope, const char *name) { + if (!name) + return NULL; for (const CBMScope* s = scope; s != NULL; s = s->parent) { - for (CBMScopeChunk* c = s->chunks; c != NULL; c = c->next) { + for (const CBMScopeChunk* c = s->chunks; c != NULL; c = c->next) { for (int i = 0; i < c->used; i++) { - if (c->bindings[i].name && strcmp(c->bindings[i].name, name) == 0) { - return c->bindings[i].type; - } + if (c->bindings[i].name && strcmp(c->bindings[i].name, name) == 0) + return &c->bindings[i]; } } } + return NULL; +} + +const CBMType* cbm_scope_lookup(const CBMScope* scope, const char* name) { + const CBMVarBinding *binding = cbm_scope_lookup_binding(scope, name); + if (binding) + return binding->type; return cbm_type_unknown(); } bool cbm_scope_contains(const CBMScope *scope, const char *name) { - if (!name) { - return false; - } - for (const CBMScope *s = scope; s != NULL; s = s->parent) { - for (const CBMScopeChunk *c = s->chunks; c != NULL; c = c->next) { - for (int i = 0; i < c->used; i++) { - if (c->bindings[i].name && strcmp(c->bindings[i].name, name) == 0) { - return true; - } - } - } - } - return false; + return cbm_scope_lookup_binding(scope, name) != NULL; } const char *cbm_scope_lookup_callable(const CBMScope *scope, const char *name) { - if (!name) { - return NULL; - } - for (const CBMScope *s = scope; s != NULL; s = s->parent) { - for (const CBMScopeChunk *c = s->chunks; c != NULL; c = c->next) { - for (int i = 0; i < c->used; i++) { - if (c->bindings[i].name && strcmp(c->bindings[i].name, name) == 0) { - return c->bindings[i].callable_qn; - } - } - } - } - return NULL; + const CBMVarBinding *binding = cbm_scope_lookup_binding(scope, name); + return binding ? binding->callable_qn : NULL; } bool cbm_scope_update_callable(CBMScope *scope, const char *name, const char *callable_qn) { diff --git a/internal/cbm/lsp/scope.h b/internal/cbm/lsp/scope.h index f4ec782a7e..3ec438fe9a 100644 --- a/internal/cbm/lsp/scope.h +++ b/internal/cbm/lsp/scope.h @@ -82,6 +82,10 @@ bool cbm_scope_bind_callable_checked(CBMScope *scope, const char *name, const CB void cbm_scope_bind_callable(CBMScope *scope, const char *name, const CBMType *type, const char *callable_qn); const CBMType* cbm_scope_lookup(const CBMScope* scope, const char* name); +/* Return the complete nearest binding in one scope-chain walk, or NULL when + * unbound. Callers that need presence, type, and callable identity together + * should use this instead of repeating three linear scans. */ +const CBMVarBinding *cbm_scope_lookup_binding(const CBMScope *scope, const char *name); /* True when any lexical frame contains name, even when its type is UNKNOWN. */ bool cbm_scope_contains(const CBMScope *scope, const char *name); /* Return the exact callable QN from the nearest binding. A nearer ordinary diff --git a/tests/test_scope.c b/tests/test_scope.c index 9effb7ca9b..9ecd497bc2 100644 --- a/tests/test_scope.c +++ b/tests/test_scope.c @@ -125,6 +125,25 @@ TEST(scope_callable_identity_follows_nearest_binding) { PASS(); } +TEST(scope_lookup_binding_returns_nearest_complete_record) { + CBMArena a; + cbm_arena_init(&a); + CBMScope *root = cbm_scope_push(&a, NULL); + CBMScope *child = cbm_scope_push(&a, root); + cbm_scope_bind_callable(root, "callback", named_t(&a, "Callback"), "pkg.actual"); + cbm_scope_bind(child, "callback", named_t(&a, "Shadow")); + + const CBMVarBinding *binding = cbm_scope_lookup_binding(child, "callback"); + ASSERT_NOT_NULL(binding); + ASSERT_STR_EQ(binding->name, "callback"); + ASSERT_STR_EQ(binding->type->data.named.qualified_name, "Shadow"); + ASSERT_NULL(binding->callable_qn); + ASSERT_NULL(cbm_scope_lookup_binding(child, "missing")); + + cbm_arena_destroy(&a); + PASS(); +} + TEST(scope_assignment_updates_or_clears_nearest_callable_only) { CBMArena a; cbm_arena_init(&a); @@ -260,6 +279,7 @@ SUITE(scope) { RUN_TEST(scope_lookup_walks_parent_chain); RUN_TEST(scope_child_shadows_parent); RUN_TEST(scope_callable_identity_follows_nearest_binding); + RUN_TEST(scope_lookup_binding_returns_nearest_complete_record); RUN_TEST(scope_assignment_updates_or_clears_nearest_callable_only); RUN_TEST(scope_checked_bind_reports_child_oom_despite_parent_name); RUN_TEST(scope_dynamic_growth_300_bindings); From df8dd1011bd1987d0ca5a45f324775aad2411f54 Mon Sep 17 00:00:00 2001 From: Andrew Hundt Date: Thu, 13 Aug 2026 02:58:52 -0400 Subject: [PATCH 2/2] internal/cbm/lsp/scope.*: inline complete binding lookup Previous behavior: cbm_scope_lookup(), cbm_scope_contains(), and cbm_scope_lookup_callable() called an out-of-line complete-binding scan after the Python lookup consolidation. What changed: - internal/cbm/lsp/scope.h defines cbm_scope_lookup_binding() as the one static-inline scope-chain scan. - internal/cbm/lsp/scope.c keeps the type, presence, and callable wrappers on that shared implementation without another function boundary. Why: Python still reads type and callable identity in one traversal, while existing language resolvers retain the direct hot path used before the consolidation. Verification: - CBM_ONLY_SUITE=scope build/c/test-runner: 33 passed - CBM_ONLY_SUITE=cs_lsp build/c/test-runner: 62 passed - CBM_ONLY_SUITE=py_lsp build/c/test-runner: 125 passed - neutral 11-pair extraction matrix: output parity; C# latency -2.97% vs first parent and -1.64% vs upstream; retired instructions +0.29% vs first parent and -1.01% vs upstream; Python scale latency -4.25% and instructions -2.81% vs first parent Signed-off-by: Andrew Hundt (cherry picked from commit 150c88e1c85a3f0a5ee4f97cde02729d896d7fc5) Signed-off-by: Martin Vogel --- internal/cbm/lsp/scope.c | 14 -------------- internal/cbm/lsp/scope.h | 24 ++++++++++++++++++++---- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/internal/cbm/lsp/scope.c b/internal/cbm/lsp/scope.c index c44a0b544a..2d9740db0c 100644 --- a/internal/cbm/lsp/scope.c +++ b/internal/cbm/lsp/scope.c @@ -88,20 +88,6 @@ bool cbm_scope_bind_callable_checked(CBMScope *scope, const char *name, const CB return cbm_scope_bind_value(scope, name, type, callable_qn); } -const CBMVarBinding *cbm_scope_lookup_binding(const CBMScope *scope, const char *name) { - if (!name) - return NULL; - for (const CBMScope* s = scope; s != NULL; s = s->parent) { - for (const CBMScopeChunk* c = s->chunks; c != NULL; c = c->next) { - for (int i = 0; i < c->used; i++) { - if (c->bindings[i].name && strcmp(c->bindings[i].name, name) == 0) - return &c->bindings[i]; - } - } - } - return NULL; -} - const CBMType* cbm_scope_lookup(const CBMScope* scope, const char* name) { const CBMVarBinding *binding = cbm_scope_lookup_binding(scope, name); if (binding) diff --git a/internal/cbm/lsp/scope.h b/internal/cbm/lsp/scope.h index 3ec438fe9a..5ba7265a36 100644 --- a/internal/cbm/lsp/scope.h +++ b/internal/cbm/lsp/scope.h @@ -5,6 +5,7 @@ #include "../arena.h" #include /* relaxed cache for cbm_lsp_max_walk_depth */ #include /* getenv, atoi (cbm_lsp_max_walk_depth) */ +#include /* strcmp (cbm_scope_lookup_binding) */ typedef struct { const char* name; @@ -30,6 +31,25 @@ typedef struct CBMScope { CBMArena* arena; // owning arena, propagated to children at push time } CBMScope; +/* Return the complete nearest binding in one scope-chain walk, or NULL when + * unbound. Keep this internal hot-path primitive inline: all language + * resolvers use cbm_scope_lookup(), while Python also consumes the complete + * record to avoid repeating the same linear scan. */ +static inline const CBMVarBinding *cbm_scope_lookup_binding(const CBMScope *scope, + const char *name) { + if (!name) + return NULL; + for (const CBMScope *s = scope; s != NULL; s = s->parent) { + for (const CBMScopeChunk *c = s->chunks; c != NULL; c = c->next) { + for (int i = 0; i < c->used; i++) { + if (c->bindings[i].name && strcmp(c->bindings[i].name, name) == 0) + return &c->bindings[i]; + } + } + } + return NULL; +} + // Bail-to-UNKNOWN depth for type-lookup chains: alias resolution, MRO walks, // embedded-field/struct-traversal. Exceeding this collapses to cbm_type_unknown // rather than recursing — guards against pathological hierarchies. @@ -82,10 +102,6 @@ bool cbm_scope_bind_callable_checked(CBMScope *scope, const char *name, const CB void cbm_scope_bind_callable(CBMScope *scope, const char *name, const CBMType *type, const char *callable_qn); const CBMType* cbm_scope_lookup(const CBMScope* scope, const char* name); -/* Return the complete nearest binding in one scope-chain walk, or NULL when - * unbound. Callers that need presence, type, and callable identity together - * should use this instead of repeating three linear scans. */ -const CBMVarBinding *cbm_scope_lookup_binding(const CBMScope *scope, const char *name); /* True when any lexical frame contains name, even when its type is UNKNOWN. */ bool cbm_scope_contains(const CBMScope *scope, const char *name); /* Return the exact callable QN from the nearest binding. A nearer ordinary