mirror of
https://github.com/hanzoai/wasm2go.git
synced 2026-10-30 15:06:48 +00:00
The threads support and the memory64 support each worked alone but were kept apart by two gates: shared memory64 modules were rejected at translation, and every 0xFE atomic was rejected on a memory64 memory. A wasm64-wasip1-threads toolchain now exists, so compose them. - atomicEA64 mirrors simdEA64's overflow-guarded address math; every atomic op body moves into an ea-keyed core, the wasm32 helpers become one-line wrappers through atomicEA, and each gets an _m64 twin through atomicEA64 (loads/stores/RMW families, wait/notify). Contended fast paths and memory orders are moved, not rewritten. - The 0xFE lowering decodes the memarg offset as u64 under memory64 (the one place still reading u32), passes it as Const64, and selects the _m64 helper names; the inline atomic fast path becomes width-correct instead of truncating. - wasi_thread_spawn under memory64 passes the start_arg as i64 (it is a linear-memory pointer): threadSpawn splits into a shared launch core with per-width entries, and the module wires a threadStart64 field for the widened wasi_thread_start export. - memoryGrow64 gains the no-relocation branch for shared memories a grow must never move the backing array out from under peer agents. A shared memory64 requires a declared maximum: the reservation is the mapping ceiling, and the memory64 hard cap is not a ceiling. - WasiStubs gains the trivial Sched_yield64 LP64 twin (musl's spin paths import sched_yield; single-threaded modules never did). - New shared+i64 fixtures mirror the wasm32 threads fixtures and run under the race detector; an atomicEA64 unit test covers beyond-4GiB addresses, overflow and misalignment; a regression test pins that unshared memory64 modules may use atomics. Generated output for wasm32 modules is byte-identical. Verified end to end: a wasm64-wasip1-threads C program (pthread_create x4 over a shared counter) transpiles and runs correctly on goroutines, including under -race; llama.cpp built for wasm64-wasip1-threads decodes correctly with ggml n_threads parallelism. Co-authored-by: Claude Fable 5 <[email protected]>
29 lines
1.3 KiB
WebAssembly Text Format
29 lines
1.3 KiB
WebAssembly Text Format
;; Cross-thread visibility of PLAIN stores published via atomics — the
|
|
;; cg_threads_visibility.wat scenario on a shared memory64: the main thread
|
|
;; writes a value with a normal (i64-addressed) store, then publishes with an
|
|
;; atomic store (release); the spawned thread spins on an atomic load
|
|
;; (acquire) and must then observe the plain store.
|
|
(module
|
|
(import "wasi" "thread-spawn" (func $spawn (param i64) (result i32)))
|
|
(memory i64 1 4 shared)
|
|
;; addr 16: plain payload / addr 20: atomic flag / addr 24: agent's answer flag
|
|
(func (export "wasi_thread_start") (param $tid i32) (param $arg i64)
|
|
;; spin until the flag publishes
|
|
(block $done
|
|
(loop $spin
|
|
(br_if $done (i32.eq (i32.atomic.load (i64.const 20)) (i32.const 1)))
|
|
(br $spin)))
|
|
;; read the PLAIN store and publish the answer atomically
|
|
(i32.atomic.store (i64.const 24) (i32.load (i64.const 16))))
|
|
(func (export "run") (result i32)
|
|
(drop (call $spawn (i64.const 0)))
|
|
;; plain store, then release-publish
|
|
(i32.store (i64.const 16) (i32.const 4242))
|
|
(i32.atomic.store (i64.const 20) (i32.const 1))
|
|
;; wait for the agent's answer
|
|
(block $got
|
|
(loop $wait
|
|
(br_if $got (i32.ne (i32.atomic.load (i64.const 24)) (i32.const 0)))
|
|
(br $wait)))
|
|
(i32.atomic.load (i64.const 24))))
|