aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/link/internal
diff options
context:
space:
mode:
authorCherry Mui <cherryyz@google.com>2024-08-03 14:20:58 -0400
committerCherry Mui <cherryyz@google.com>2024-08-09 20:07:54 +0000
commit1cf6e31f0d03bb3571cfe034f2d909591a0ae453 (patch)
treec89cb9d652377eb4517c497f6c4d4ea4ccf29b70 /src/cmd/link/internal
parentff2a57ba92b9ecc9315c992b332279d0428c36d7 (diff)
downloadgo-1cf6e31f0d03bb3571cfe034f2d909591a0ae453.tar.xz
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 <thanm@golang.org> Reviewed-by: Randy Reddig <randy.reddig@fastly.com> Reviewed-by: David Chase <drchase@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Diffstat (limited to 'src/cmd/link/internal')
-rw-r--r--src/cmd/link/internal/ld/deadcode.go7
-rw-r--r--src/cmd/link/internal/loader/loader.go9
-rw-r--r--src/cmd/link/internal/wasm/asm.go23
3 files changed, 35 insertions, 4 deletions
diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go
index 3d547259a1..a1378fc02c 100644
--- a/src/cmd/link/internal/ld/deadcode.go
+++ b/src/cmd/link/internal/ld/deadcode.go
@@ -116,6 +116,13 @@ func (d *deadcodePass) init() {
}
d.mark(s, 0)
}
+ // So are wasmexports.
+ for _, s := range d.ldr.WasmExports {
+ if d.ctxt.Debugvlog > 1 {
+ d.ctxt.Logf("deadcode start wasmexport: %s<%d>\n", d.ldr.SymName(s), d.ldr.SymVersion(s))
+ }
+ d.mark(s, 0)
+ }
d.mapinitnoop = d.ldr.Lookup("runtime.mapinitnoop", abiInternalVer)
if d.mapinitnoop == 0 {
diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go
index 98bff775fb..a391c8ced9 100644
--- a/src/cmd/link/internal/loader/loader.go
+++ b/src/cmd/link/internal/loader/loader.go
@@ -251,6 +251,8 @@ type Loader struct {
// CgoExports records cgo-exported symbols by SymName.
CgoExports map[string]Sym
+ WasmExports []Sym
+
flags uint32
strictDupMsgs int // number of strict-dup warning/errors, when FlagStrictDups is enabled
@@ -1627,6 +1629,10 @@ func (l *Loader) WasmImportSym(fnSymIdx Sym) Sym {
return l.aux1(fnSymIdx, goobj.AuxWasmImport)
}
+func (l *Loader) WasmTypeSym(s Sym) Sym {
+ return l.aux1(s, goobj.AuxWasmType)
+}
+
// SEHUnwindSym returns the auxiliary SEH unwind symbol associated with
// a given function symbol.
func (l *Loader) SEHUnwindSym(fnSymIdx Sym) Sym {
@@ -2213,6 +2219,9 @@ func (st *loadState) preloadSyms(r *oReader, kind int) {
if a := int32(osym.Align()); a != 0 && a > l.SymAlign(gi) {
l.SetSymAlign(gi, a)
}
+ if osym.WasmExport() {
+ l.WasmExports = append(l.WasmExports, gi)
+ }
}
}
diff --git a/src/cmd/link/internal/wasm/asm.go b/src/cmd/link/internal/wasm/asm.go
index 09c54c1392..cdd8de467d 100644
--- a/src/cmd/link/internal/wasm/asm.go
+++ b/src/cmd/link/internal/wasm/asm.go
@@ -219,6 +219,15 @@ func asmb2(ctxt *ld.Link, ldr *loader.Loader) {
if sig, ok := wasmFuncTypes[ldr.SymName(fn)]; ok {
typ = lookupType(sig, &types)
}
+ if s := ldr.WasmTypeSym(fn); s != 0 {
+ var o obj.WasmFuncType
+ o.Read(ldr.Data(s))
+ t := &wasmFuncType{
+ Params: fieldsToTypes(o.Params),
+ Results: fieldsToTypes(o.Results),
+ }
+ typ = lookupType(t, &types)
+ }
name := nameRegexp.ReplaceAllString(ldr.SymName(fn), "_")
fns[i] = &wasmFunc{Name: name, Type: typ, Code: wfn.Bytes()}
@@ -407,15 +416,21 @@ func writeExportSec(ctxt *ld.Link, ldr *loader.Loader, lenHostImports int) {
switch buildcfg.GOOS {
case "wasip1":
- writeUleb128(ctxt.Out, 2) // number of exports
+ writeUleb128(ctxt.Out, uint64(2+len(ldr.WasmExports))) // number of exports
s := ldr.Lookup("_rt0_wasm_wasip1", 0)
idx := uint32(lenHostImports) + uint32(ldr.SymValue(s)>>16) - funcValueOffset
writeName(ctxt.Out, "_start") // the wasi entrypoint
ctxt.Out.WriteByte(0x00) // func export
writeUleb128(ctxt.Out, uint64(idx)) // funcidx
- writeName(ctxt.Out, "memory") // memory in wasi
- ctxt.Out.WriteByte(0x02) // mem export
- writeUleb128(ctxt.Out, 0) // memidx
+ for _, s := range ldr.WasmExports {
+ idx := uint32(lenHostImports) + uint32(ldr.SymValue(s)>>16) - funcValueOffset
+ writeName(ctxt.Out, ldr.SymName(s))
+ ctxt.Out.WriteByte(0x00) // func export
+ writeUleb128(ctxt.Out, uint64(idx)) // funcidx
+ }
+ writeName(ctxt.Out, "memory") // memory in wasi
+ ctxt.Out.WriteByte(0x02) // mem export
+ writeUleb128(ctxt.Out, 0) // memidx
case "js":
writeUleb128(ctxt.Out, 4) // number of exports
for _, name := range []string{"run", "resume", "getsp"} {