WebAssembly GC

26.1 Why WasmGC?

Before GC, managed languages had to compile their own garbage collector into linear memory: big binaries, no cycle collection with JS objects, and slower startup.

WasmGC adds host-managed structs and arrays: the engine's GC collects them, and they can reference JS objects and vice versa.

26.2 GC Types and Instructions

any ⊃ eq ⊃ (i31, struct, array), func, extern, plus bottom types (none, nofunc, noextern)

struct.new, struct.new_default, struct.get(_s/_u), struct.set

array.new, array.new_fixed, array.new_data, array.get/set, array.len, array.fill, array.copy

Unboxed 31-bit integers (ref.i31, i31.get_s) ref.test, ref.cast, br_on_cast, br_on_cast_fail

(type $B (sub $A (struct ...))), final types, recursive type groups (rec ...)

any.convert_extern, extern.convert_any

(module
  (type $Point (struct (field $x (mut f64)) (field $y (mut f64))))
  (type $Points (array (mut (ref null $Point))))
  (type $Bytes (array (mut i8)))

  (func $make (export "makePoint") (param $x f64) (param $y f64) (result (ref $Point))
    (struct.new $Point (local.get $x) (local.get $y)))

  (func (export "length") (param $p (ref $Point)) (result f64)
    (f64.sqrt
      (f64.add
        (f64.mul (struct.get $Point $x (local.get $p)) (struct.get $Point $x (local.get $p)))
        (f64.mul (struct.get $Point $y (local.get $p)) (struct.get $Point $y (local.get $p))))))

  (func (export "makeArray") (param $n i32) (result (ref $Points))
    (array.new_default $Points (local.get $n)))

  (func (export "castTest") (param $r anyref) (result i32)
    (ref.test (ref $Point) (local.get $r))))

26.3 Who Uses WasmGC

Kotlin/Wasm, Dart/Flutter web, Java (J2Wasm: Google Sheets), Scala.js, OCaml (wasm_of_ocaml), Scheme (Hoot), and more. It typically gives smaller downloads and faster startup than shipping a GC.

Supported in Chrome/Edge (119+), Firefox (120+), and Safari (18.2+), plus Wasmtime (newer versions) and Node.js.