mirror of
https://github.com/hanzoai/wasm2go.git
synced 2026-10-30 15:06:48 +00:00
Adds the wasm threads proposal to the codegen and, on top of it, a
copy-on-write memory-sharing facility for embedders that stand up many
instances of the same module.
Threads
- Lower the 0xFE atomic family (load/store/rmw/cmpxchg across widths and
sub-word lanes, plus wait/notify) to sync/atomic-based module helpers.
- wasi_thread_spawn runs each guest thread on a goroutine. A shared memory
is allocated at its declared ceiling once and never relocates, so every
agent's cached base pointer stays valid; growth is a lone atomic store.
- Passive data segments, per-agent globals, coherent plain access for
shared memories, and multi-package output for threaded modules.
- A shared memory's ceiling is a runtime value the embedder chooses, not
the binary's declared maximum.
Copy-on-write shared memory
- NewWithMemory lets the caller supply the linear memory, and memory.init
compares before it writes — so a copy-on-write map of a pre-initialized
image survives the start section instead of being faulted private.
- NewSharedImage builds an initialized image once per process and maps it
copy-on-write into every instance: the data segments (identical in every
instance, read-mostly) then cost almost nothing per instance.
- NewSharedSnapshot / NewFromSnapshot share a WHOLE initialized instance —
memory and wasm globals both — so instances re-run nothing at all.
SaveGlobals/RestoreGlobals carry the initialized state that lives outside
linear memory (the stack pointer and other mutable globals).
Also: coverage for the threads/atomics helpers, a WASM2GO_SSA_PASSES_OFF
diagnostic knob, an AtomicWait timeout margin, and thread-trap visibility.
Co-authored-by: Claude Opus 4.8 <[email protected]>
21 lines
907 B
WebAssembly Text Format
21 lines
907 B
WebAssembly Text Format
;; Passive data segments + memory.init/data.drop — the shape LLVM emits for
|
|
;; shared-memory builds (all data passive, initialized once from a start
|
|
;; function). exports check both the init'd bytes and post-drop trapping.
|
|
(module
|
|
(memory 1 4 shared)
|
|
(data $hello "Hello")
|
|
(data $world ", world")
|
|
(func $init
|
|
(memory.init $hello (i32.const 16) (i32.const 0) (i32.const 5))
|
|
(memory.init $world (i32.const 21) (i32.const 0) (i32.const 7))
|
|
(data.drop $hello))
|
|
(start $init)
|
|
(func (export "read_at") (param i32) (result i32)
|
|
(i32.load8_u (local.get 0)))
|
|
(func (export "reinit_dropped")
|
|
;; memory.init on a dropped segment with n > 0 must trap
|
|
(memory.init $hello (i32.const 64) (i32.const 0) (i32.const 1)))
|
|
(func (export "reinit_zero_len")
|
|
;; n == 0 on a dropped segment is allowed by the spec
|
|
(memory.init $hello (i32.const 64) (i32.const 0) (i32.const 0))))
|