[WASM R0] build: define ecosystem ABI profiles - #2471
Conversation
There was a problem hiding this comment.
Review: WASM target profiles (memory64 / emscripten)
Solid, well-tested change. The new WasmABI type gives WebAssembly ecosystem ABIs a first-class, cache-participating identity instead of overloading GOOS/GOARCH, validation is layered defensively across the direct/named/generic entry points, and the model_32.go / model_memory64.go fixture pair genuinely verifies 64-bit pointer semantics at runtime rather than just checking WASM magic bytes. No correctness-blocking defects found. Security review found nothing exploitable (the emulator template is executed via shellparse + exec.Command, not a shell; scripts quote inputs and operate on trusted build-time data). Performance is unaffected — all changed Go paths run once per build.
Findings below are minor / worth-acknowledging, not blocking.
Additional (no reliable inline location):
dev/test_wasm_target_profiles.sh— Theemscripten-memory64-runner.mjsprobe/retry logic is never exercised by CI.run_nodealways invokestargets/emscripten-runner.mjsand the memory64 case manually retries with--experimental-wasm-memory64, whilellgo runuses the newemscripten-memory64-runner.mjs(with itsWebAssembly.validateprobe +spawnSyncre-exec). The shipped runner's non-trivial branching therefore has no automated coverage, and the script's manual--experimental-wasm-memory64retry contradicts that runner's own comment about newer Node rejecting the flag. Consider running the actual memory64 runner, or aligning/clarifying the divergence.THIRD_PARTY_NOTICES.md:33— Stale reference totargets/wasm_exec.js. This PR removes the last functional use of that file (the oldwasm.jsonemulator line) and the file is not present in the tree, so the notice entry should be removed or corrected.- User-facing docs —
-target wasmmaterially changes: it now inherits fromemscriptenand emits an ES-module (.mjs) + sibling.wasmviaemcc/Node instead of a WASI.wasmviawasm-ld. Neither the newemscripten/emscripten-memory64profiles nor the output-extension change are reflected in the README target table (line ~57). Worth documenting so operators aren't surprised by the.mjsoutput. targets/wasip2.json/targets/wasm-unknown.json— Both drop"libc": "wasmbuiltins". SincegetLibcCompileConfigByNameonly supportspicolibc/newlib-esp32, awasmbuiltinsvalue would have errored if these targets reachedUseTargetwith libc set — so this is effectively a cleanup/fix rather than a regression, worth calling out explicitly given the PR is otherwise framed as additive.
|
Addressed the non-inline review notes in b837f77:
I kept the |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
LLGo baseline benchmarks
Program measurements
Core language and compiler benchmarks
Timer runtime benchmarks
Compared with |
Part of #2152.
This replaces the earlier draft #2469 after the target contract was clarified and the implementation was rebuilt on current main. Full CI validation was completed in cpunion#218.
Summary
emscripten,emscripten-memory64, andwasi;wasmas the Emscripten wasm32 compatibility name andwasip1as the WASI Preview 1 compatibility name;.wasmsuffix;wasm-unknownandwasip2as distinct freestanding/component profiles without treating their borrowed source-selection GOOS/GOARCH as the physical backend.The public target contract is:
llgo build -target emscriptenllgo build -target emscripten-memory64llgo build -target wasmemscriptenllgo build -target wasillgo build -target wasip1wasiCompatibility and scope
The standard
wasm,js && wasm, andwasip1 && wasmsource constraints are reserved for official Go semantics. R0 does not introduce anllgo.wasm.gotag and does not add a C-ecosystem tag to rawGOOS/GOARCH:GOOS=js GOARCH=wasmkeeps its current driver behavior but receives nollgo.wasm.emscriptentag or Emscripten cache identity;GOOS=wasip1 GOARCH=wasmkeeps its current driver behavior but receives nollgo.wasm.wasitag or WASI C-profile cache identity;llgo.wasm.emscripten,llgo.wasm.emscripten.memory64, orllgo.wasm.wasi;The current raw 32-bit layout and runtime are implementation gaps to close in G1/G2, not long-term C-profile contracts. G1/G2 make the standard tag combinations Go-compatible without requiring a positive LLGo-specific Go ABI source tag.
The old
targets/wasm.jsonwas an unreachable TinyGo-derived mixture of a JS source context, WASI triple/libc, andwasm_exec.js; it was not the working rawjs/wasmpath. The retainedwasmname now follows that working Emscripten path.This intentionally changes the implicit executable name for
-target wasmfrom
package.wasmto the Emscripten entry modulepackage.mjs(with itspackage.wasmsidecar). Scripts that consume a standalone WASI module shoulduse
-target wasi; scripts using the legacy Emscripten target should launch orpublish the
.mjsentry module.The named Emscripten/WASI JSON files contain only the profile identity, source
tags, LLVM triple, and emulator fields that the named path actually consumes.
Ecosystem driver, compiler, libc, and linker flags remain centralized in the
existing installed-toolchain paths instead of presenting ignored JSON knobs.
The Memory64 emulator probes Node and uses the legacy
--experimental-wasm-memory64flag only on releases that still require it.This is the R0 foundation only. It does not add a scheduler, blocking primitive, timer, or collector. R1 changes WASI process entry, imported-memory ownership, exception/longjmp behavior, and scheduling as one coherent runtime contract before executing the WASI probes under Wasmtime. R3 restores linked freestanding/component acceptance; R0 verifies their resolver, backend, layout, and cache identities without reviving the borrowed
linux/armsource set as an ABI.Validation
go test ./internal/targets ./internal/crosscompile ./ssago test -coverprofile=... ./internal/crosscompile(90.5% package coverage)go test -coverprofile=... ./internal/build(425.975s, 86.4% package coverage)go test ./internal/build -run '^TestPCLNExternalLinkOptionsIntegration$' -count=1 -vdev/test_wasm_target_profiles.shllgo run -target emscripten -emulator ./internal/build/testdata/wasm-profilellgo run -target emscripten-memory64 -emulator ./internal/build/testdata/wasm-profilellgo run -target wasm -emulator ./internal/build/testdata/wasm-profileactionlint .github/workflows/llgo.ymlThe executable probes verify Go
uintptr, Csizeof(void *), and Csizeof(long)together. Emscripten wasm32, Memory64, and the legacy alias all instantiate their generated module and printwasm ABI profile ok; canonical and legacy WASI entries emit modules with the WebAssembly magic rather than host binaries.Native macOS/arm64 size comparison against the direct
mainbase, with identical flags and cache disabled:cprintfprintlnfmtprintfAll three native binaries also produced the same expected output.