# WasmGC

## §1 Provenance

- **WasmGC.** Proposal repo: https://github.com/WebAssembly/gc. Champions: Andreas Rossberg (Mozilla, retd.), Francis McCabe (Google).
- Standardised as part of **WebAssembly 3.0**, W3C Recommendation, September 24, 2025.
- Earlier: Wasm 2.0 (Dec 2024, W3C REC); WasmGC was post-2.0 work that landed in 3.0.
- Browser support:
  - Chrome 119 (Oct 2023)
  - Firefox 120 (Nov 2023)
  - Safari 18.2 (Dec 2024) — last to ship, unblocking GC-language deployment.

## §2 Mechanism

WasmGC adds **typed managed references** to Wasm. Distinct from linear memory; references live in a separate "managed heap" that the host engine garbage-collects.

Core primitives:

1. **Struct types.** `(type $point (struct (field f64) (field f64)))` — fixed-shape product types. Allocated with `struct.new`. Fields accessed by index.
2. **Array types.** `(type $bytes (array i8))` — fixed-element arrays with bound. `array.new`, `array.get`, `array.set`, `array.len`.
3. **Ref types.** `(ref $point)`, `(ref null $point)`, `(ref any)`, `(ref eq)`, `(ref i31)`, etc. — typed references that the host knows are pointers (not integers), so it can trace them.
4. **`i31ref`.** A tagged 31-bit integer that fits in a reference slot — the standard small-int unboxing trick from Smalltalk/V8.
5. **Subtyping.** `(sub final $base $derived)` — single-inheritance type hierarchy with `ref.test`, `ref.cast`, `br_on_cast`. Enables OO-style downcasts.
6. **Function references.** `(ref $functype)` — typed function pointers; enables vtables.

The engine traces references precisely (it knows what's a pointer and what's a scalar from the type system). No conservative scanning, no fat pointers.

Languages compiling to WasmGC give up control of *when* GC runs but gain the engine's industrial-strength collector for free, and don't ship MB of nursery/old-gen plumbing inside their `.wasm` binary.

## §3 Memory-safety property

The engine's GC provides full **temporal safety** on the managed heap: a `ref` is either null or live. The Wasm type system provides **spatial safety** within each struct/array (field/element indices are checked against the declared type). The host engine is responsible for the actual collection algorithm.

This delivers the same memory-safety class as Java or .NET: managed-heap UAF and OOB are structurally impossible.

## §4 Production status (May 2026)

- All major browsers ship WasmGC.
- **Languages compiling to WasmGC in production:**
  - **Kotlin/Wasm** (JetBrains) — using WasmGC since Kotlin 1.9.20. Compose for Web hit Beta Sept 2025. JetBrains' benchmarks show ~3× JS-build perf in UI-heavy workloads.
  - **Dart/Flutter** — `--wasm` flag; falls back to JS if WasmGC not detected. Production-supported by Google.
  - **wasm_of_ocaml** — emits WasmGC since 2024.
  - **J2CL (Google)** — Java to WasmGC, used in Google Sheets and other internal apps.
  - **Scala.js** — adds WasmGC backend (Issue #4928).
  - **Scheme**, several research languages.
- **Languages explicitly *not* using WasmGC**: Rust, C++, Go, anything that wants direct memory control — they continue to use Wasm linear memory + ship their own GC if needed.

## §5 Cost

- **Throughput.** The host's GC is heavily optimised (V8 reuses Oilpan-class infrastructure). On Kotlin/Wasm benchmarks: comparable to JVM, generally faster than Kotlin/JS.
- **Binary size.** Huge win. A Kotlin/Wasm app drops the bundled-GC overhead (typical savings: hundreds of KB to MBs).
- **Startup latency.** Faster startup than JS-compiled equivalents (no need to JIT-warm the embedded GC).
- **Cross-language interop.** A Dart object and a Kotlin object live in the same heap; no copy across linear memories. Cross-language calls are zero-marshalling.
- **Hidden cost.** Languages with very specific GC requirements (low-latency real-time) cannot tune the engine GC; you take what V8/SpiderMonkey/JSC gives you.

## §6 Mochi adaptation note

vm3's handle ABI is *already* a WasmGC-style ref encoding. Compare:

| WasmGC | vm3 |
|---|---|
| `(ref $point)` | `Cell{arena_tag=kArenaStruct, gen, slot} → struct layout` |
| `(ref null $arr)` | `Cell{arena_tag=kArenaList, ...}` plus a null Cell value |
| `i31ref` | We could pack small ints into Cells (currently use typed banks instead) |
| `array.get` / bounds check | `ListGet(h, i)` with explicit bounds check |
| `struct.new` | `AllocStruct(...)` |
| Engine GC | Go GC for backing slices + vm3 free-list/mark-sweep for slot liveness |

So if Mochi ever wanted to compile to WasmGC, the mapping is direct:

- Each typed arena (MEP-40 §6.2) maps to a WasmGC `(array …)` type.
- The Cell handle is a WasmGC `ref`.
- The 12-bit generation field is gone (the engine GC subsumes it; UAF is impossible by construction).
- compiler3 emits `array.get`/`array.set` instead of `ListGet`/`ListSet`.

This is the smallest patch to make Mochi browser-portable in the future. It's a Phase-8-or-later prospect, but the architectural alignment is striking: **MEP-40 chose the same abstractions WasmGC chose, independently**. Worth flagging in MEP-41 as a validation point.

Adaptation note for *now* (Mochi-on-Go):

1. **Mochi.wasm target via WasmGC.** A future MEP-50 could deliver Mochi-on-the-browser by emitting WasmGC instead of Go bytecode. The compiler3 IR is already type-driven (§7.2); the emit pass would target Wasm 3.0 GC instructions.
2. **i31ref-style packing in vm3 today.** If we ever want to elide the typed register banks for small-int-heavy code, packing 31-bit ints into a "fake" Cell with arena_tag = kArenaSmallInt and slot = the int value is the same trick.

No design conflict. WasmGC validates Mochi's typed-handle abstraction; the only divergence is that Mochi's host is Go, not a browser.

## §7 Open questions for MEP-41

- Should the MEP-40 cell layout be revised to make a future WasmGC port one-to-one? Specifically, should we adopt 31-bit unboxed-int representation now, instead of the typed register banks?
- WasmGC's GC algorithm is engine-defined. If Mochi compiles to Wasm, do we lose the ability to tune for our workload? (Yes; the trade-off is portability.)
- The WasmGC type system is single-inheritance + interfaces (`(ref any)`). Mochi has structural typing. How awkward is the mapping?
- Could vm3 share its handle ABI with a WasmGC engine running embedded in the Go process, for FFI? Probably overkill, but worth thinking about for the long term.

## Sources

- [WebAssembly/gc GitHub repo](https://github.com/WebAssembly/gc)
- [Webassembly Feature Status](https://webassembly.org/features/)
- [WebAssembly 3.0 Release (x-cmd blog)](https://www.x-cmd.com/blog/250924/)
- [Kotlin/Wasm — Supported versions and configuration](https://kotlinlang.org/docs/wasm-configuration.html)
- [Flutter — Wasm support](https://docs.flutter.dev/platform-integration/web/wasm)
- [State of WebAssembly 2026 (devnewsletter.com)](https://devnewsletter.com/p/state-of-webassembly-2026/)
- [Scala.js WebAssembly Linker Backend (Issue #4928)](https://github.com/scala-js/scala-js/issues/4928)
- [WebAssembly in 2026 (JavaCodeGeeks)](https://www.javacodegeeks.com/2026/04/webassembly-in-2026-where-it-has-landed-what-wasi-0-2-changes-and-why-java-and-kotlin-developers-should-pay-attention-now.html)
