Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 109 additions & 17 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ anyhow = "1.0"
# Static composition - parse and emit WASM modules
wasmparser = "0.219"
wasm-encoder = "0.219"
walrus = "0.23" # pack compose: internalize memory/globals into one self-contained module
toml = "0.8" # pack compose: manifest parsing

# Hashing for interface compatibility
sha2 = "0.10"
Expand Down
Binary file added assets/adder_fixedbase.wasm
Binary file not shown.
Binary file added assets/doubler_fixedbase.wasm
Binary file not shown.
47 changes: 38 additions & 9 deletions docs/pic-composition.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,18 +190,47 @@ substrate, and the smallest useful validation of §3.

---

## 6. Level 3 (future): static merge → one `.wasm`
## 6. Level 3 (shipped): static merge → one `.wasm` — `pack compose`

Implemented as the **`pack compose`** command. It merges the packages (allocator
+ A + B + …) into a **single self-contained `.wasm` with zero imports** —
the original "package it up and pass it around" goal — that runs on any stock
runtime with no harness (`wasm-tools validate` clean).

**Pipeline** (`src/compose/static_compose.rs`):
1. **`wasm-merge`** (binaryen) fuses the modules and internalizes the
cross-package imports: `(import "math" "double")` → a direct call to the
provider's `double`; `(import "pack:alloc" …)` → a call to the merged-in
allocator. Each package is named by the import-module-name its consumers use.
2. A **`walrus`** pass does what `wasm-merge` can't: unify the several
`env.memory` imports into one internal memory, bake the allocator's
`__memory_base` / `__heap_base` / `__heap_end` imports into constants, and
export the memory.

**Build recipe** — packages are compiled at disjoint **fixed bases** (non-PIC, so
data lands at absolute addresses needing no relocation):

The PIC side modules (allocator + A + B) are relocatable objects. A wasm linker
step (`wasm-ld -r`, or a purpose-built merge) can combine them into a single
relocatable module with one fixed memory layout, finalized into **one passable
`.wasm`** — the original "package it up and pass it around" goal. This is a
larger, separate effort; §3 (runtime PIC composition) is its prerequisite and its
input.
```
RUSTFLAGS="-Clink-arg=--import-memory -Clink-arg=--initial-memory=8388608 \
-Clink-arg=--stack-first -Clink-arg=-zstack-size=262144 \
-Clink-arg=--global-base=<BASE> -Clink-arg=--no-entry"
```

**CLI** — `packr compose <manifest.toml> [-o out.wasm]`, where the manifest lists
`[[package]]` entries (providers before consumers) with `name` = the consumer's
import module-name, plus an optional `[layout]`. Requires `wasm-merge` (binaryen)
on `PATH`.

> **Packaging, not performance.** The merge internalizes the *call*, but the packr
> ABI marshalling (encode/decode/alloc per cross-call) is fossilized into the
> compiled packages, so it remains. `pack compose` gives one portable artifact; it
> does not make the boundary cheaper. A by-reference shared-memory ABI would be the
> separate perf lever.

Keep **both**: runtime PIC composition (level 2) stays valuable for loading /
swapping packages at runtime; the static merge (level 3) is for shipping a frozen
bundle. They share the same PIC side-module format.
swapping packages at runtime; the static merge (`pack compose`) is for shipping a
frozen, self-contained bundle. They share the same PIC/fixed-base side-module
substrate.

---

Expand Down
1 change: 1 addition & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
cargo-expand
wasm-pack
wasmtime
binaryen # wasm-merge, used by `pack compose`
gh
];

Expand Down
Loading
Loading