EXPERIMENT: invocation control resolves at runtime

ISHIKAWA: why did wraps_body need compile-time knowledge? Because the wrapper
called the target directly. If the wrapper calls through the seam instead, the
seam can call the body itself, and a construct bound after the build decides
how and whether to invoke it.

PREDICTIONS AND RESULTS
  P1 wrap becomes runtime-bindable                  TRUE   body x3 -> 21,
                                                           never invoked -> 111
  P2 codegen shrinks                                TRUE   5042 -> 4977
  P3 cost 5-10% from an indirect call on every fn   TRUE   0.36s -> 0.39s, ~8%
  P4 zero-param fns break on the empty struct       TRUE   empty struct is a GNU
                                                           extension, empty init
                                                           is C23. Fixed with a
                                                           char field.
  P5 fixpoint holds                                 TRUE

PROCESS FAILURE worth recording: my first patch silently did not apply because
I dropped the assert on the string replacement. The build then failed with
"undeclared identifier __thunk_noargs", which I nearly attributed to the
empty-struct prediction. The guard that would have caught it existed and I
removed it -- the same shape as every other defect found tonight.

Removed: declare_wrap, decorator_wrap, cg_wrap_target, cg_wrap_construct,
params_to_call_args, and the wraps_body scanner branch.

prohibits_outside is now the ONLY construct kind left at compile time, and it
cannot move: a #error has no runtime.
This commit is contained in:
bigmerge
2026-08-17 09:06:05 -05:00
parent b40754f07b
commit bc2f26ddfc
5 changed files with 70 additions and 89 deletions
+26 -1
View File
@@ -17116,7 +17116,8 @@ static void el_seam_load(void) {
if (fn[0] == '#') continue;
_el_seam[_el_seam_n].fn = el_strdup(fn);
_el_seam[_el_seam_n].construct = el_strdup(con);
_el_seam[_el_seam_n].phase = (strcmp(ph, "exit") == 0) ? EL_PHASE_EXIT : EL_PHASE_ENTRY;
_el_seam[_el_seam_n].phase = (strcmp(ph, "exit") == 0) ? EL_PHASE_EXIT :
(strcmp(ph, "wrap") == 0) ? 2 : EL_PHASE_ENTRY;
_el_seam[_el_seam_n].target = el_strdup(tgt);
_el_seam_n++;
}
@@ -17124,6 +17125,30 @@ static void el_seam_load(void) {
fclose(f);
}
/* el_seam_wrap — the seam calls the body itself, so a bound construct can
* control invocation: run it zero times, N times, or around a transaction.
* With no binding it is a direct call through the thunk, which is what the
* unwrapped code did anyway. */
el_val_t el_seam_wrap(el_val_t fn_v, el_val_t (*body)(void*), void* env) {
if (!_el_seam_loaded) el_seam_load();
if (_el_seam_n == 0) return body(env);
const char* fn = EL_CSTR(fn_v);
if (!fn) return body(env);
for (int i = 0; i < _el_seam_n; i++) {
if (_el_seam[i].phase != 2) continue; /* 2 = wrap */
if (strcmp(_el_seam[i].fn, fn) != 0) continue;
if (!_el_seam[i].resolve_tried) {
_el_seam[i].resolved = dlsym(RTLD_DEFAULT, _el_seam[i].target);
_el_seam[i].resolve_tried = 1;
}
if (!_el_seam[i].resolved) continue;
el_val_t (*fp)(el_val_t, el_val_t, el_val_t (*)(void*), void*) =
(el_val_t (*)(el_val_t, el_val_t, el_val_t (*)(void*), void*))_el_seam[i].resolved;
return fp(fn_v, el_wrap_str(el_strdup(_el_seam[i].construct)), body, env);
}
return body(env);
}
el_val_t el_seam_run(el_val_t fn_v, el_val_t phase_v, el_val_t result) {
if (!_el_seam_loaded) el_seam_load();
if (_el_seam_n == 0) return result; /* the common path: no bindings */
+2 -1
View File
@@ -888,7 +888,8 @@ el_val_t engram_age_field_catchup(void);
el_val_t engram_chrono_persist_tick(void);
el_val_t engram_chrono_tick(void);
el_val_t engram_boundary_beat(el_val_t op_name, el_val_t construct);
el_val_t el_seam_run(el_val_t fn_name, el_val_t phase, el_val_t result); /* runtime construct seam */ /* API-reshape decorator-seam auto-emit; construct = the decorator that caused the beat */
el_val_t el_seam_run(el_val_t fn_name, el_val_t phase, el_val_t result); /* runtime construct seam */
el_val_t el_seam_wrap(el_val_t fn_name, el_val_t (*body)(void*), void* env); /* runtime invocation control */ /* API-reshape decorator-seam auto-emit; construct = the decorator that caused the beat */
el_val_t engram_self_anchor_capture(void);
el_val_t engram_self_drift_json(void);
el_val_t engram_neighbors_json(el_val_t node_id, el_val_t max_depth, el_val_t direction);