From fc6b0f5aba302952f28b961a211a4db19f0e9308 Mon Sep 17 00:00:00 2001 From: Joseph Ferano Date: Sun, 13 Sep 2026 08:57:13 +0700 Subject: [PATCH] An allocation registry answers what is at an address, without tagging a struct --- NEXT.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/NEXT.md b/NEXT.md index fd0e7d3..49effe8 100644 --- a/NEXT.md +++ b/NEXT.md @@ -20,6 +20,42 @@ This matters more here than in most Lisps because the intended use is a **game l skip a frame and carry on rather than die — exactly the case where a non-idempotent mutation bites. Write it into `conditions.org` and `spec-conditions.md`'s prose, and into `web/index.html` beside the restart documentation. +## Queued: a dev-build allocation registry — address to type + +Raised in conversation and wanted. **What it is:** in a dev build only, every allocation records what type it was +made for. Address → type becomes a lookup. + +**Why it is possible without tagging anything.** A Flan struct is exactly its C layout with no header and no tag word +— deliberately, and it is what makes structs free and the FFI work. So "what is at this address" is normally +unanswerable at run time, and a tag cannot be added without breaking raylib. The registry sidesteps that: the +*allocator* knows the type at the moment it hands out memory, so nothing about the value's layout has to change. +Costs nothing in a release build. + +**What it buys, in rough order of value:** + +- **Following a pointer.** `(Ptr T)` renders as `` today and stops there. With a registry the inspector follows + it and renders what is actually at the other end. +- **Use-after-free that names what died.** The address is in the registry and marked dead: *"this was an Enemy, freed + at frame 412"* instead of garbage, a crash, or silence. +- Point at any heap address and get a typed rendering rather than bytes. +- **A memory breakdown by type** — how many bytes are Enemies, how many are strings. A real profiling tool for a game. +- **Leak attribution at exit**, which generalises the debug tracking allocator already queued for counting forgotten + textures. +- It closes the **arena hole Valgrind found**: releasing a region could mark everything in it dead, where today the + bytes stay quietly readable because `free-all` is retain-capacity and memcheck is never told. + +**What it does not cover, and does not need to:** stack locals and globals, which the shadow stack and the static type +table already answer by name. + +**The cost to watch, and it is the design question.** An arena allocation is a bump pointer — close to free — and a +registry insert per allocation could easily cost more than the allocation itself, in a loop that runs every frame. +Mitigations to weigh: record per *region* rather than per allocation; record ranges rather than addresses; or make the +registry opt-in per allocator so a frame arena can decline it. Decide this before building, because it determines +whether the feature is usable in the loop it is most wanted in. + +**Note on classes:** `defclass` instances will carry shape metadata by design, so they get identification for free and +do not need the registry. This is for plain structs, `Vec`, `Map` and pool storage. + ## Picked up first, 2026-09-13 Three things, in order. The first two are one line each and unblock a real game.