Expand description
#418 — bind the passed-through embedder import env::__cabi_arena_realloc
to a synthesized in-module arena allocator, unlocking the fully
SELF-CONTAINED dissolve.
§The seam this closes
The BYO-OS lean-MCU dissolve (gale#89) builds grow-free components with the
wit-bindgen cabi-realloc-extern feature: cabi_realloc stays exported but
its body routes to an embedder-provided env::__cabi_arena_realloc import.
On the --relocatable host-link path that import is DELIBERATELY left as an
undefined symbol the TCB’s native allocator satisfies at link (#420 locks
that layering — nothing here changes it). But on the default SELF-CONTAINED
path the same import previously degraded the compile to an ET_REL “link me
with the Kiln bridge” object: the one unresolved seam blocking a fully
self-contained image.
§The binding (a wasm→wasm rewrite, not new codegen)
When the arena import is the module’s ONLY import, replace it with a DEFINED WebAssembly function implementing the #418 contract, compiled through synth’s ordinary pipeline like any other module function:
- signature
(old_ptr, old_len, align, new_len) -> ptr(i32×4 → i32); old_len == 0 && new_len == 0→ returnalignverbatim;- bump allocation from a fresh mutable cursor global (appended at the end of the global index space), aligned up per call;
- realloc preserves
min(old_len, new_len)bytes (byte-copy loop); - BOUNDED arena
[arena_base, arena_end)— exhaustion (or a zero / non-power-of-two-shapedalignwrap) executesunreachable, i.e. traps, and NEVER callsmemory.grow.
arena_base mirrors the shipped used-extent rule (main.rs #237/#354):
max(data_end, every i32-const global init ≤ linmem) — the latter covers
both the __stack_pointer class and wasm-ld’s __data_end/__heap_base
layout globals — rounded up to 16 (floor 16 so the allocator never returns
a null-looking pointer). arena_end = the initial linear-memory size
(grow-free modules never extend it).
§Why the rewrite is index-preserving
The wasm function index space is imports-first. Removing the SOLE function
import and prepending the allocator as the FIRST defined function gives it
the import’s old index — every call, ref.func, export, and element
entry keeps its meaning without any remapping. Untouched sections are
copied byte-for-byte; only import (dropped), function/code (one entry
prepended) and global (one entry appended) change.
Structs§
- Bound
Arena - A successful #418 binding.
Enums§
- Arena
Bind - Outcome of
bind_cabi_arena_realloc.
Constants§
- ARENA_
IMPORT_ FIELD - ARENA_
IMPORT_ MODULE - The core-module field name of the embedder arena import (#418). The kebab
cabi-arena-reallocis component-surface only and never reaches synth.
Functions§
- bind_
cabi_ arena_ realloc - Bind a sole
env::__cabi_arena_reallocfunction import to a synthesized in-module arena allocator (#418). See the module docs for the contract.