spec-memory.md defines an allocator as a procedure plus an opaque data pointer, which reads as a function value, which check.ml refuses four ways. None of the four is anywhere near this: `Allocator` is a `Types.t` case with no user-writable constructor, the way `string` is a builtin ptr+len, its procedure is a C symbol the emitter names, and every operation is an ordinary named call that `check_call` already routes through `named_call`. The one thing that really does need milestone 5 is a *user-written* allocator — it wants a defn's name in value position — and that is refused by name with that reason rather than left to come back as an unknown function. An `Allocator` value is a pointer to the runtime's struct and never a copy of one. That is forced, not chosen: the capability set has to be readable from wherever a container landed, and `free-all` bumps an epoch every container made from the allocator has to observe. A copy would give each its own epoch and the dev trap would never fire. Two decisions the spec left to be made here, both announced in BUILT.md: `free-all` is retain-capacity — offset = 0, the pages stay — and handing the pages back is `arena-destroy`, a separate operation. Zig's reset takes a mode; Odin's arena_free_all is already retain-capacity in effect. Taking the mode would have grown the operation table the spec froze at four. The epoch is bumped either way, because the pages being the same does not make a container made before the reset valid. `context/allocator` and `context/temp` are dynamic variables with save and restore, not extra parameters. The spec calls the allocator part of the calling convention; the literal reading touches every signature, the FFI shim, the dev trampolines and the reload ABI for the same observable behaviour. `with-allocator` is its own IR node rather than a let and two calls, because the restore has to happen on the transfer path too. A body that errors leaves through the landing pad, and a context allocator left pointing into a region nobody outside the body has heard of would be wrong in the break loop, which is exactly where something is about to allocate to render a condition. The acceptance program asserts that path by taking a restart out of a body. The backend grew one prim, `Rt of string`: a call into the runtime's C named by symbol, with argument and result types read off the expression nodes. The container runtime is type-erased and therefore *is* a list of C entry points, so one arm covers all of them rather than one arm each.
Description
Languages
OCaml
67.2%
Emacs Lisp
15.2%
C
10.4%
HTML
2.9%
Standard ML
2.8%
Other
1.5%