An allocation registry answers what is at an address, without tagging a struct

This commit is contained in:
Joseph Ferano 2026-09-13 08:57:13 +07:00
parent 324d1c6c60
commit fc6b0f5aba

36
NEXT.md
View File

@ -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 `<ptr>` 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.