Skip to content

runtime/wasm: stop all workers for garbage collection (based on #119) - #123

Draft
cpunion wants to merge 3 commits into
codex/fork-wasm-bounded-workers-20260801from
codex/fork-wasm-multi-worker-gc-20260801
Draft

runtime/wasm: stop all workers for garbage collection (based on #119)#123
cpunion wants to merge 3 commits into
codex/fork-wasm-bounded-workers-20260801from
codex/fork-wasm-multi-worker-gc-20260801

Conversation

@cpunion

@cpunion cpunion commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Depends on #119.

Problem

The bounded Web worker scheduler can execute Go code on several native wasm threads, but the non-moving wasm collector was still single-threaded:

  • compiler-maintained root chains used one process-global slot;
  • suspended and active contexts could be enumerated concurrently;
  • another worker could mutate the heap during mark or sweep;
  • workers blocked on runtime or allocator locks could not acknowledge a collection request.

Enabling the collector in that state can miss roots or race heap metadata updates.

Changes

  • Give compiler-maintained root chains a native TLS slot when wasm GC and workers are both enabled.
  • Keep the runtime context registry process-wide and synchronized, while active context/root-chain ownership remains per native worker.
  • Register a system-stack root for every worker and publish each worker's active root chain before its stop acknowledgement.
  • Add an odd/even epoch stop-the-world handshake with a single collector owner and ready/stopped worker accounting.
  • Keep both mark and sweep inside the stopped-world interval.
  • Replace worker-shared blocking locks with a small cooperative wasm mutex so a contended worker can reach the GC handshake.
  • Add a multi-worker GC fixture that checks roots on the collector worker, a remote worker, and concurrent allocators.

The compiler only enables TLS roots for wasm GC + workers. Runtime implementations are selected by wasm build tags; native, embedded, single-worker wasm, and wasm without GC retain their existing paths.

Validation

  • Go 1.26.5 macOS: full ssa, cl, and internal/build suites pass; full runtime/... passes.
  • Go 1.24.11 macOS: focused compiler, root, and build-configuration tests pass.
  • Ubuntu amd64 container, limited to 2 CPUs and 6 GiB: focused compiler/build tests and full runtime/... pass.
  • Node: J32/J64 with 2 workers; J32/J64 with 4 workers; scheduler and dedicated GC fixtures pass.
  • Chrome: J32/J64 scheduler and dedicated GC fixtures pass.
  • Optimization coverage: J32 -O0; J64 -O3 -lto=thin; J64 -O3 -lto=full pass.
  • Existing single-worker GC remains valid on J32, J64, and P1.
  • Native runtime demo has unchanged file and section sizes versus runtime/wasm: add bounded Web worker scheduling (based on #116) #119.
  • Cortex-M4 empty output is byte-identical versus runtime/wasm: add bounded Web worker scheduling (based on #116) #119: 1,804 B, text/data/bss 140/0/10.
  • git diff --check passes.
  • Fork CI finishes with 39 successful checks, one expected release-publication skip, and zero failures.
  • Ubuntu and macOS coverage jobs pass. The external Codecov upload cannot publish a patch status from this protected fork branch because no token is available; local profiles cover the new compiler and configuration paths.

Independent diff from #119: 34 files, +687/-120.

@gemini-code-assist

Copy link
Copy Markdown

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown

LLGo baseline benchmarks

3c184b629556 | workflow run | long-term charts

Program measurements

Platform Workload File size vs main Build vs main Run vs main
Linux cprintf 18816 B +1.5% (worse) 309.287 ms -25.0% (better) 1.001 ms -35.5% (better)
Linux fmtprintf 2219448 B +0.3% (worse) 3.118 s -19.1% (better) 2.119 ms -35.5% (better)
Linux println 71776 B -1.2% (better) 308.720 ms -22.8% (better) 1.319 ms -21.2% (better)
macOS cprintf 84672 B +0.0% 431.986 ms +4.3% (worse) 3.510 ms -2.2% (better)
macOS fmtprintf 2361968 B +0.7% (worse) 3.525 s -10.5% (better) 18.457 ms -21.0% (better)
macOS println 125712 B -1.0% (better) 416.606 ms +0.5% (worse) 4.025 ms -44.6% (better)
Core language and compiler benchmarks
Platform Benchmark ns/op vs main
Linux BenchmarkLookupPCRandom 11.300 ns/op -16.2% (better)
Linux BenchmarkMergeCompilerFlags 141.200 ns/op -8.6% (better)
Linux BenchmarkMergeLinkerFlags 95.100 ns/op -6.1% (better)
Linux BenchmarkChannelBuffered 58.210 ns/op +67.5% (worse)
Linux BenchmarkChannelHandoff 26667 ns/op -16.8% (better)
Linux BenchmarkDefer 39.400 ns/op -30.0% (better)
Linux BenchmarkDirectCall 1.057 ns/op -32.4% (better)
Linux BenchmarkGlobalRead 1.417 ns/op -9.2% (better)
Linux BenchmarkGlobalWrite 8.621 ns/op +245.7% (worse)
Linux BenchmarkGoroutine 45229 ns/op -40.2% (better)
Linux BenchmarkInterfaceCall 6.598 ns/op -15.3% (better)
Linux BenchmarkRuntimeGetG 1.421 ns/op -73.2% (better)
macOS BenchmarkLookupPCRandom 13.680 ns/op +10.0% (worse)
macOS BenchmarkMergeCompilerFlags 126.300 ns/op +1.4% (worse)
macOS BenchmarkMergeLinkerFlags 77.730 ns/op +12.1% (worse)
macOS BenchmarkChannelBuffered 22.600 ns/op -18.5% (better)
macOS BenchmarkChannelHandoff 6926 ns/op -1.2% (better)
macOS BenchmarkDefer 29.220 ns/op -21.9% (better)
macOS BenchmarkDirectCall 1.176 ns/op -19.1% (better)
macOS BenchmarkGlobalRead 1.166 ns/op -3.7% (better)
macOS BenchmarkGlobalWrite 1.218 ns/op -18.1% (better)
macOS BenchmarkGoroutine 32921 ns/op +4.0% (worse)
macOS BenchmarkInterfaceCall 4.547 ns/op -15.8% (better)
macOS BenchmarkRuntimeGetG 2.062 ns/op -20.0% (better)

Compared only with the latest matching platform in the main series.

Warning

  • Persistent publishing is unavailable because no data token is configured.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant