From fcb7cc90228b480e522fea12e4830cb0cc89dc63 Mon Sep 17 00:00:00 2001 From: Matthew Stanley <1379tech@gmail.com> Date: Mon, 15 Jun 2026 17:12:16 -0700 Subject: [PATCH] =?UTF-8?q?sljit:=20enforce=20gcc>sljit=20load=20priority?= =?UTF-8?q?=20=E2=80=94=20obsolete=20superseded=20shards?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root-cause class: load priority is static > gcc shard > sljit shard > interp, but it was only emergent from chain registration order (LIFO prepend), not enforced, and a superseded sljit shard was never retired. A shipped/optimized gcc DLL must outrank — and obsolete — a user machine's locally-JIT'd sljit shard for the same content. Fix (overlay_loader.c): when a gcc/DLL candidate registers (cand_register), retire any same-PC sljit shard JIT'd from IDENTICAL bytes (same crc_code) — blacklist it so it can never run even if the gcc candidate is later self-mod blacklisted. Precise by content: a sljit shard for a DIFFERENT overlay variant at the same address is distinct coverage and is kept. New counter s_sljit_obsoleted, surfaced via overlay_loader_sljit_obsoleted(). debug_server.c: sljit_status now reports live + obsoleted (observability for the validation playtest — measure, don't eyeball). Runtime-only (no regen). Refs SLJIT.md §11 Phase B. Co-Authored-By: Claude Opus 4.8 (1M context) --- runtime/src/debug_server.c | 11 +++++++---- runtime/src/overlay_loader.c | 29 ++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/runtime/src/debug_server.c b/runtime/src/debug_server.c index 4b021864..2e5fd8b9 100644 --- a/runtime/src/debug_server.c +++ b/runtime/src/debug_server.c @@ -7767,17 +7767,20 @@ static void handle_sljit_status(int id, const char *json) { /* Declarations come from overlay_sljit.h (included above). */ extern unsigned int overlay_loader_sljit_registered(void); + extern unsigned int overlay_loader_sljit_obsoleted(void); + extern int overlay_loader_get_sljit_live(void); (void)json; int selftest = overlay_sljit_selftest(); int available = 0, st_ok = 0; unsigned long long compiles = 0, declines = 0, bytes = 0; overlay_sljit_get_status(&available, &st_ok, &compiles, &declines, &bytes); send_fmt("{\"id\":%d,\"ok\":true,\"backend\":\"%s\",\"available\":%d," - "\"selftest_ok\":%d,\"compiles\":%llu,\"declines\":%llu," - "\"bytes_emitted\":%llu,\"shards_registered\":%u}\n", + "\"selftest_ok\":%d,\"live\":%d,\"compiles\":%llu,\"declines\":%llu," + "\"bytes_emitted\":%llu,\"shards_registered\":%u,\"obsoleted\":%u}\n", id, overlay_backend_name(overlay_backend_active()), available, - selftest, compiles, declines, bytes, - overlay_loader_sljit_registered()); + selftest, overlay_loader_get_sljit_live(), compiles, declines, bytes, + overlay_loader_sljit_registered(), + overlay_loader_sljit_obsoleted()); } /* sljit_try : force a one-shot JIT of the leaf function at a phys diff --git a/runtime/src/overlay_loader.c b/runtime/src/overlay_loader.c index 3f06d24d..0298b1c6 100644 --- a/runtime/src/overlay_loader.c +++ b/runtime/src/overlay_loader.c @@ -167,6 +167,7 @@ static uint32_t s_last_crc = 0; static uint32_t s_no_manifest = 0; /* exports skipped (no manifest range)*/ static uint32_t s_selfmod = 0; /* entries blacklisted (self-mod) */ static uint32_t s_sljit_registered = 0; /* sljit Tier-2 shards registered */ +static uint32_t s_sljit_obsoleted = 0; /* sljit shards superseded by a gcc DLL*/ static uint32_t s_last_write_pc = 0; static uint32_t s_last_write_addr = 0; static uint32_t s_last_write_size = 0; @@ -256,6 +257,8 @@ static ManFn *man_find(ManFn *arr, int n, uint32_t entry) { /* ---- Candidate registration -------------------------------------------- */ +static void loader_log(const char *fmt, ...); /* defined below */ + static void cand_register(uint32_t phys, OverlayFn fn, const ManFn *m, int dll) { if (s_cand_n >= CAND_CAP) return; int idx = s_cand_n++; @@ -291,10 +294,31 @@ static void cand_register(uint32_t phys, OverlayFn fn, const ManFn *m, int dll) c->next = idx_head(phys); idx_set_head(phys, idx); if (c->state == ENTRY_VALID) s_valid_count++; + + /* Obsolescence (load priority: static > gcc shard > sljit shard > interp). A + * gcc DLL is the optimized, dev-validated artifact and OUTRANKS an sljit shard + * a user machine JIT'd for the SAME content. Once this gcc candidate is in the + * chain it already wins dispatch (it's at the head, ahead of the older sljit + * shard, and content-keyed dispatch picks the first match), but we also + * explicitly retire the superseded sljit shard so it can never run — even if + * this gcc candidate is later self-mod-blacklisted. Precise by content: only a + * shard JIT'd from the IDENTICAL bytes (same crc_code) is superseded; an sljit + * shard for a DIFFERENT overlay variant at this address is distinct coverage + * and is kept. */ + for (int j = c->next; j >= 0; j = s_cand[j].next) { + Candidate *o = &s_cand[j]; + if (o->dll == -1 && o->state != ENTRY_BLACKLIST && + o->crc_code == c->crc_code) { + if (o->state == ENTRY_VALID && s_valid_count > 0) s_valid_count--; + o->state = ENTRY_BLACKLIST; + s_sljit_obsoleted++; + loader_log("sljit shard 0x%08X obsoleted by gcc DLL (crc 0x%08X)", + o->addr, o->crc_code); + } + } } /* ---- sljit Tier-2 shard registration (SLJIT.md §7 step 5) -------------- */ -static void loader_log(const char *fmt, ...); /* defined below */ /* Register an in-process JIT shard as a native candidate, parallel to * cand_register but without a .ranges manifest: the shard was JIT'd from the * live RAM bytes over [lo, lo+len), so crc_code is hashed from those same bytes @@ -974,6 +998,9 @@ int overlay_loader_registered_count(void) { return s_valid_count; } /* sljit Tier-2 shards registered as candidates this session (diagnostics). */ uint32_t overlay_loader_sljit_registered(void) { return s_sljit_registered; } +/* sljit shards superseded by a higher-priority gcc DLL (same content). */ +uint32_t overlay_loader_sljit_obsoleted(void) { return s_sljit_obsoleted; } + /* Force a one-shot sljit JIT attempt of the leaf function at `addr` from live * RAM and register it on success (bypasses the diff-mode gate — a probe). For * the sljit_try debug command. Returns via the result struct. */