Skip to content

aowlabi — the shared value-representation / ABI truth

The single canonical answer to "how is each type laid out, per target." Before aowlabi, three places each kept their own copy of that answer — the aowli interpreter, the aowlc C backend, and the aowljs JavaScript backend — and the three copies drifted. aowlabi is the one spec they all read, so they agree by construction.

Status: landed · private repo. Consumed by aowlc, aowljs, and aowli today. Access via Discord timbuktu_guy.

Why this repo exists

Layout is a fact about a program, not about a backend — the size of a seq, the offset of a variant's discriminator, the shape of a string header. When each backend re-derives that fact independently, they slip out of sync, and the moment one boundary uses a layout another disagrees with, data corrupts silently. aowlabi moves the fact to one place. The interpreter's marshaler and the C backend's codegen read the same offsets, so a value written by one and read by the other is byte-for-byte compatible — no coordination, no drift.

Three parts

1 · Size / alignment / field-offset engine

One implementation of the C-struct layout rules — align, pad, finish; the object base-size prefix; array stride; the recursive walk over tuple and variant members. It's parameterized by pointer size, so the same rules give you the 32-bit and 64-bit answers from one source. A caller works against an abstract type descriptor and maps its own type representation onto it, so nothing about a particular backend's IR leaks in.

2 · Canonical heap-block spec

Named offset constants for the compound heap types, so nobody hardcodes a magic number:

BlockLayout
string (SSO)16-byte small-string-optimized cell, 4 modes; spills to LongString{fullLen, rc, cap, data}
seq{len, data}
ARC ref box{rc @ 0, data @ ptrSize}

One truth for these offsets means the interpreter allocating a string and the C backend indexing into one are reading the identical map.

3 · Marshal matrix

Classifies each type by how it crosses a native boundary — by value, by buffer, or by fallback — across the categories that matter:

CategoryCrosses as
scalarby value
POD object / tupleby value (flat) or by buffer
stringby buffer
seqby buffer
ref / closurefallback

Plus the JS representation mapping the JavaScript backend reads:

nimonyJS
intnumber
faithful 64-bitbigint
char1-char string
tuplepositional array
objectobject literal
refobject ref

Why it matters

This is what makes aowli's hybrid mode sound. In hybrid mode the interpreter marshals values across a live boundary into natively-compiled code — and the interpreter's marshaler and the C backend's codegen must agree on layout byte-for-byte, or a single hybrid native call corrupts memory. Because both sides read aowlabi instead of their own copy, they agree by construction rather than by luck.

Consumed by

aowlc, aowljs, and aowli all build against it:

-p:.../aowlabi/src
import aowlabi

Repo: github.com/aoughwl/aowlabi.

aoughwl — self-hosted platform for things n stuff. Contact / Support on Discord for access to the private backends.