Skip to content

Commit df8dd10

Browse files
ahundtDeusData
authored andcommitted
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 <ATHundt@gmail.com> (cherry picked from commit 150c88e) Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
1 parent f339aa6 commit df8dd10

2 files changed

Lines changed: 20 additions & 18 deletions

File tree

‎internal/cbm/lsp/scope.c‎

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -88,20 +88,6 @@ bool cbm_scope_bind_callable_checked(CBMScope *scope, const char *name, const CB
8888
return cbm_scope_bind_value(scope, name, type, callable_qn);
8989
}
9090

91-
const CBMVarBinding *cbm_scope_lookup_binding(const CBMScope *scope, const char *name) {
92-
if (!name)
93-
return NULL;
94-
for (const CBMScope* s = scope; s != NULL; s = s->parent) {
95-
for (const CBMScopeChunk* c = s->chunks; c != NULL; c = c->next) {
96-
for (int i = 0; i < c->used; i++) {
97-
if (c->bindings[i].name && strcmp(c->bindings[i].name, name) == 0)
98-
return &c->bindings[i];
99-
}
100-
}
101-
}
102-
return NULL;
103-
}
104-
10591
const CBMType* cbm_scope_lookup(const CBMScope* scope, const char* name) {
10692
const CBMVarBinding *binding = cbm_scope_lookup_binding(scope, name);
10793
if (binding)

‎internal/cbm/lsp/scope.h‎

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "../arena.h"
66
#include <stdatomic.h> /* relaxed cache for cbm_lsp_max_walk_depth */
77
#include <stdlib.h> /* getenv, atoi (cbm_lsp_max_walk_depth) */
8+
#include <string.h> /* strcmp (cbm_scope_lookup_binding) */
89

910
typedef struct {
1011
const char* name;
@@ -30,6 +31,25 @@ typedef struct CBMScope {
3031
CBMArena* arena; // owning arena, propagated to children at push time
3132
} CBMScope;
3233

34+
/* Return the complete nearest binding in one scope-chain walk, or NULL when
35+
* unbound. Keep this internal hot-path primitive inline: all language
36+
* resolvers use cbm_scope_lookup(), while Python also consumes the complete
37+
* record to avoid repeating the same linear scan. */
38+
static inline const CBMVarBinding *cbm_scope_lookup_binding(const CBMScope *scope,
39+
const char *name) {
40+
if (!name)
41+
return NULL;
42+
for (const CBMScope *s = scope; s != NULL; s = s->parent) {
43+
for (const CBMScopeChunk *c = s->chunks; c != NULL; c = c->next) {
44+
for (int i = 0; i < c->used; i++) {
45+
if (c->bindings[i].name && strcmp(c->bindings[i].name, name) == 0)
46+
return &c->bindings[i];
47+
}
48+
}
49+
}
50+
return NULL;
51+
}
52+
3353
// Bail-to-UNKNOWN depth for type-lookup chains: alias resolution, MRO walks,
3454
// embedded-field/struct-traversal. Exceeding this collapses to cbm_type_unknown
3555
// rather than recursing — guards against pathological hierarchies.
@@ -82,10 +102,6 @@ bool cbm_scope_bind_callable_checked(CBMScope *scope, const char *name, const CB
82102
void cbm_scope_bind_callable(CBMScope *scope, const char *name, const CBMType *type,
83103
const char *callable_qn);
84104
const CBMType* cbm_scope_lookup(const CBMScope* scope, const char* name);
85-
/* Return the complete nearest binding in one scope-chain walk, or NULL when
86-
* unbound. Callers that need presence, type, and callable identity together
87-
* should use this instead of repeating three linear scans. */
88-
const CBMVarBinding *cbm_scope_lookup_binding(const CBMScope *scope, const char *name);
89105
/* True when any lexical frame contains name, even when its type is UNKNOWN. */
90106
bool cbm_scope_contains(const CBMScope *scope, const char *name);
91107
/* Return the exact callable QN from the nearest binding. A nearer ordinary

0 commit comments

Comments
 (0)