From 1cf6e31f0d03bb3571cfe034f2d909591a0ae453 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Sat, 3 Aug 2024 14:20:58 -0400 Subject: cmd/compile: add basic wasmexport support This CL adds a compiler directive go:wasmexport, which applies to a Go function and makes it an exported function of the Wasm module being built, so it can be called directly from the host. As proposed in #65199, parameter and result types are limited to 32-bit and 64-bit integers and floats, and there can be at most one result. As the Go and Wasm calling conventions are different, for a wasmexport function we generate a wrapper function does the ABI conversion at compile time. Currently this CL only adds basic support. In particular, - it only supports executable mode, i.e. the Go wasm module calls into the host via wasmimport, which then calls back to Go via wasmexport. Library (c-shared) mode is not implemented yet. - only supports wasip1, not js. - if the exported function unwinds stacks (goroutine switch, stack growth, etc.), it probably doesn't work. TODO: support stack unwinding, c-shared mode, js. For #65199. Change-Id: Id1777c2d44f7d51942c1caed3173c0a82f120cc4 Reviewed-on: https://go-review.googlesource.com/c/go/+/603055 Reviewed-by: Than McIntosh Reviewed-by: Randy Reddig Reviewed-by: David Chase LUCI-TryBot-Result: Go LUCI --- src/cmd/compile/internal/noder/noder.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'src/cmd/compile/internal/noder/noder.go') diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go index 1652dc6618..7905c374c5 100644 --- a/src/cmd/compile/internal/noder/noder.go +++ b/src/cmd/compile/internal/noder/noder.go @@ -171,6 +171,7 @@ type pragmas struct { Pos []pragmaPos // position of each individual flag Embeds []pragmaEmbed WasmImport *WasmImport + WasmExport *WasmExport } // WasmImport stores metadata associated with the //go:wasmimport pragma @@ -180,6 +181,12 @@ type WasmImport struct { Name string } +// WasmExport stores metadata associated with the //go:wasmexport pragma +type WasmExport struct { + Pos syntax.Pos + Name string +} + type pragmaPos struct { Flag ir.PragmaFlag Pos syntax.Pos @@ -204,6 +211,9 @@ func (p *noder) checkUnusedDuringParse(pragma *pragmas) { if pragma.WasmImport != nil { p.error(syntax.Error{Pos: pragma.WasmImport.Pos, Msg: "misplaced go:wasmimport directive"}) } + if pragma.WasmExport != nil { + p.error(syntax.Error{Pos: pragma.WasmExport.Pos, Msg: "misplaced go:wasmexport directive"}) + } } // pragma is called concurrently if files are parsed concurrently. @@ -246,6 +256,23 @@ func (p *noder) pragma(pos syntax.Pos, blankLine bool, text string, old syntax.P Name: f[2], } } + + case strings.HasPrefix(text, "go:wasmexport "): + f := strings.Fields(text) + if len(f) != 2 { + // TODO: maybe make the name optional? It was once mentioned on proposal 65199. + p.error(syntax.Error{Pos: pos, Msg: "usage: //go:wasmexport exportname"}) + break + } + + if buildcfg.GOARCH == "wasm" { + // Only actually use them if we're compiling to WASM though. + pragma.WasmExport = &WasmExport{ + Pos: pos, + Name: f[1], + } + } + case strings.HasPrefix(text, "go:linkname "): f := strings.Fields(text) if !(2 <= len(f) && len(f) <= 3) { -- cgit v1.3