Runtime value representation #
WebAssembly gives a compiler numeric values, functions, tables, and linear memory. A source language such as Gleam has richer values: strings, lists, tuples, records, custom types, and closures. Runtime representation is the set of choices that explain how those values live in WebAssembly memory and how code passes them around.
Scalar values can often map directly to WebAssembly value types. Managed values need layout rules, allocation, and an ABI between generated WebAssembly and the host runtime.
Runtime ABI #
An ABI, or application binary interface, is the rulebook for how values cross a compiled-code boundary. For this compiler, the boundary is usually between a Gleam function compiled to WebAssembly and host code such as a Wasmtime test or a browser JavaScript caller.
Scalar values cross that boundary as ordinary WebAssembly values:
| Gleam type | ABI value |
|---|---|
Int |
i64 |
Float |
f64 |
Bool |
i32 |
Nil |
no value |
Managed values cross as i32 pointers into WebAssembly linear memory. A pointer
is a byte offset where the runtime object starts. The object begins with an
8-byte header:
0..4 tag: object kind
4..8 size: length, arity, or field count
8.. payload bytes or fields
For example, a function that returns a tuple gives the host an i32, not the
tuple fields directly. The host reads memory at that pointer, checks the tag to
see that it is a tuple, reads the arity from the second word, and then reads the
payload fields. Strings, bit arrays, lists, records, custom values, and closures
use the same pointer-based idea with different tags and payload layouts.
This convention keeps WebAssembly function signatures small, but it means both sides must agree on layout, ownership, and when a wrapper is needed. A raw pointer is enough for generated WebAssembly to pass managed values around; a human-facing or JavaScript-facing API may still wrap that pointer in a safer shape.