Skip to content

dissolve: bind passed-through embedder import cabi-arena-realloc to the native TCB arena allocator #418

Description

@avrabe

Context

Part of the BYO-OS lean-MCU dissolve pipeline (gale#89):

gale app + kernel-primitive components
  → meld fuse --memory shared
  → loom → synth (native ELF, no memory.grow)

Grow-free components are built with the forked wit-bindgen cabi-realloc-extern feature (pulseengine/wit-bindgen#4): cabi_realloc stays exported but its body routes to an embedder-provided env::__cabi_arena_realloc import, so no memory.grow is pulled in on realloc's account.

What wasm-tools now produces (contract)

The pulseengine/wasm-tools fork now supports component new --import-passthrough env::__cabi_arena_realloc (pulseengine/wasm-tools#2). Instead of rejecting the unmapped env import, it produces a valid component that:

  • imports a world-root function whose extern name is the kebab-case of the core symbol field name — __cabi_arena_realloccabi-arena-realloc — typed func(p0: u32, p1: u32, p2: u32, p3: u32) -> u32 (derived from the core signature (i32,i32,i32,i32) -> i32);
  • canon lowers that import and wires it as the core module's env::__cabi_arena_realloc import;
  • keeps cabi_realloc exported and used as the canonical realloc.

Resulting world surface:

world root {
  import cabi-arena-realloc: func(p0: u32, p1: u32, p2: u32, p3: u32) -> u32;
  export greet: func() -> string;
}

The component import is deliberately left unsatisfied — it's an embedder/host symbol to be bound at native link / dissolve, not by the component model.

Ask (synth)

At dissolve / native link, bind the passed-through import (after meld, see the meld companion issue) to the TCB's native arena allocator symbol __cabi_arena_realloc, honoring the full canonical-ABI realloc contract:

  • signature (old_ptr, old_len, align, new_len) -> ptr (i32×4 → i32);
  • old_len == 0 && new_len == 0 → return align;
  • bounded arena, traps on exhaustion rather than calling memory.grow.

The naming rule is kebab_case(core_field_name); synth should map the component import cabi-arena-realloc back to the native symbol __cabi_arena_realloc. If we'd rather preserve the exact symbol verbatim (avoid the kebab transform), let's decide that here and adjust the wasm-tools fork — the transform is only there because component extern names must be kebab-case.

Refs

pulseengine/wasm-tools#2 (the --import-passthrough flag, implemented), pulseengine/wit-bindgen#4 (cabi-realloc-extern), meld companion issue (pass-through during fuse), synth#383, gale#89.

Nothing here goes upstream to bytecodealliance — this is the pulseengine fork pipeline only.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions