The program linker merges the allocator module and a set of per-unit modules into the single WebAssembly module loaded by a runtime link group.
This is binary composition, not language name resolution. Source calls have already resolved to symbols, and each unit module already validates independently.
Inputs and output
atoll-flat-wasm allocator
+
ordered per-unit wasm modules
+
unit methods and placement metadata
↓
validated linked program.wasmInput unit order is canonical. Program-stable unit index i corresponds to
input unit i, independent of how units are partitioned into link groups.
Merge order
The allocator module is merged first. Its memory becomes memory zero, its table becomes table zero, and its internal index space forms the base of the linked module.
Units are appended in canonical order. For each unit the linker:
- parses module sections into a summary;
- deduplicates compatible function types;
- resolves allocator imports to definitions already merged from
atoll-flat-wasm; - deduplicates host imports that remain external;
- allocates new function and global indices;
- rewrites every supported index-bearing instruction and section payload;
- renames or preserves exports according to the linked namespace;
- carries supported custom-section data forward.
The result is emitted section by section and validated.
Import treatment
Imports have different destinations:
| Namespace | Link behavior |
|---|---|
atoll_flat_wasm |
Resolve against allocator exports and replace the import with direct linked indices |
atoll_scheduler |
Remain host imports, deduplicated across units |
atoll_libm_wasm |
Remain imports fulfilled through the runtime’s math instance path |
| Other supported host namespaces | Remain imports according to their ABI contract |
The math module is not merged in the current linker. Merging it would require additional memory, table, and element remapping work; documentation must not describe it as embedded merely because unit imports use a compiler-owned namespace.
Index remapping
WebAssembly indices are local to a module. Once modules are combined, the linker builds remap tables for types, functions, globals, memories, tables, elements, and data.
Any payload containing one of those indices must be rewritten through the correct input remap. Atoll unit code currently uses a deliberately constrained module shape, which keeps the supported rewrite surface auditable.
An unsupported unit section is a link error. Passing it through unchanged would be unsafe because its local indices could refer to the wrong linked objects.
Input invariants
Current unit modules:
- import allocator memory rather than declaring their own;
- import allocator, scheduler, and optional math functions;
- define and export per-unit globals and functions;
- do not define their own memory, table, data, or element sections;
- avoid table-indexed indirect calls in user unit code;
- may carry known Atoll custom sections.
The allocator module is different: it declares memory, table, globals, data, and elements and is self-contained. Its placement first is what makes its internal indices the linked base.
These are versioned implementation invariants. If unit emission starts using a new index-bearing instruction or section, linker support and tests must land in the same change.
Unit metadata
The linker adds an atoll.units custom section. Version 1 records, in input
order:
- unit name;
- placement policy;
- optional replication limit and eviction hint;
- exposed method names;
- method signature tags.
The payload is explicitly versioned and length-framed by the Wasm custom section. Readers reject unknown versions, invalid enum tags, truncated fields, invalid UTF-8, and trailing data.
This section is how compiler unit identity reaches the runtime. Export-name scanning alone is not the metadata contract.
Link groups
A program can be partitioned three ways:
| Grouping | Result |
|---|---|
| All in one | One linked module containing every unit; current default |
| One per unit | One allocator-bearing linked module per unit for maximal isolation |
| Custom | An exact partition supplied as unit-index groups |
Custom groups must cover every unit exactly once. Out-of-range indices, duplicates, and gaps are hard errors. Groups and their member indices are normalized into deterministic order.
All-in-one grouping is required to produce bytes identical to a direct link of the same complete unit list. Other groupings trade allocator/module footprint for isolation and redeployment granularity.
Consistency checks
Linking rejects:
- malformed input modules;
- unresolved allocator imports;
- unsupported sections;
- incompatible yield-check modes across units;
- invalid custom grouping;
- malformed metadata construction;
- output that fails WebAssembly validation.
Errors identify whether the allocator or a named unit produced the invalid input whenever possible.
Testing changes
A linker change should include:
- a minimal module fixture exercising the new section or instruction;
- validation of the linked bytes;
- execution when the change affects runtime behavior;
- multi-unit coverage to expose dedup and index-offset errors;
- deterministic output across repeated input;
- all-in-one byte-parity coverage;
- malformed-input rejection.
The runtime interpretation of the result is documented in Deployment and Units.