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]>
67 lines
2.1 KiB
Go
67 lines
2.1 KiB
Go
// Package sharedimage carries the copy-on-write shared-memory-image runtime
|
|
// that wasm2go emits alongside a translated module.
|
|
//
|
|
// It lives here as source text rather than as a string literal in the
|
|
// generator because it is ordinary Go that happens to be output: keeping it in
|
|
// .go.txt files means it stays readable, reviewable, and greppable. The only
|
|
// generated parts are the identifiers the surrounding package decides — the
|
|
// package name and the Module field names, which single-package output keeps
|
|
// unexported and multi-package output must export.
|
|
package sharedimage
|
|
|
|
import (
|
|
"bytes"
|
|
_ "embed"
|
|
"fmt"
|
|
"go/format"
|
|
"text/template"
|
|
)
|
|
|
|
//go:embed sharedimage.go.txt
|
|
var coreTmpl string
|
|
|
|
//go:embed sharedimage_mmap.go.txt
|
|
var mmapTmpl string
|
|
|
|
//go:embed sharedimage_nommap.go.txt
|
|
var nommapTmpl string
|
|
|
|
// Names are the identifiers the emitting package supplies.
|
|
type Names struct {
|
|
Pkg string // package clause of the generated files
|
|
Module string // the Module type's name (always "Module" today)
|
|
Memory string // Module's linear-memory field
|
|
MemSize string // Module's *atomic.Uint64 current-size field
|
|
DataEnd string // Module's data-segment-extent field
|
|
|
|
// SaveGlobals is the generated globals-snapshot function (see
|
|
// emitGlobalsSnapshot); multi-package output exports it.
|
|
SaveGlobals string
|
|
}
|
|
|
|
// Files renders the runtime: output filename → formatted Go source. The three
|
|
// files split by platform (mmap / no mmap) and must be emitted together.
|
|
func Files(n Names) (map[string][]byte, error) {
|
|
out := map[string][]byte{}
|
|
for name, src := range map[string]string{
|
|
"sharedimage.go": coreTmpl,
|
|
"sharedimage_mmap.go": mmapTmpl,
|
|
"sharedimage_nommap.go": nommapTmpl,
|
|
} {
|
|
t, err := template.New(name).Parse(src)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("sharedimage: parsing %s: %w", name, err)
|
|
}
|
|
var buf bytes.Buffer
|
|
if err := t.Execute(&buf, n); err != nil {
|
|
return nil, fmt.Errorf("sharedimage: rendering %s: %w", name, err)
|
|
}
|
|
formatted, err := format.Source(buf.Bytes())
|
|
if err != nil {
|
|
return nil, fmt.Errorf("sharedimage: formatting %s: %w", name, err)
|
|
}
|
|
out[name] = formatted
|
|
}
|
|
return out, nil
|
|
}
|