Description
Background
The go:wasmimport
directive was added in #38248 and has since been used to implement the prototype implementation of the WASI port. It is currently limited to use in the runtime
, syscall
and syscall/js
standard library packages. With #59149 we want to allow any Go user to write their own go:wasmimport
statements to access functions implemented on the WASI host.
Wasm today uses 32 bit pointers, while internally in the Go Wasm implementation we use 64 bit pointers. When a function is decorated with the go:wasmimport
directive, the compiler translates the arguments (including pointers) to Wasm types. However, pointers to structs containing pointers cannot have their pointer fields converted in the same way since the conversion would require copying the objects to new memory locations, including the conversion of pointer fields to 32 bits, and copying the data back into the objects when the call returns. The mechanism would have to recursively walk the objects, dealing with pointer cycles, and likely introduce a significant overhead when calling go:wasmimport
functions.
What is the behaviour today?
The compiler does not error when compiling functions with arguments that point to pointers. At runtime, there is an ABI mismatch between the Go program and the Wasm host modules, the latter expecting pointers to be 32 bits, causing misalignment of fields in struct types passed by pointer to go:wasmimport
functions.
What did I expect to see?
I expected the compiler to disallow functions using arguments that point to pointers so we prevent users of go:wasmimport
from constructing programs with a memory layout that is incompatible with the Wasm host.
Discussion
The following should be allowed (no internal struct pointers):
//go:wasmimport module F1
func F1(p *byte)
//go:wasmimport module F2
func F2(p unsafe.Pointer)
type buffer struct {
ptr uint32
len uint32
}
//go:wasmimport module F3
func F3(b *buffer)
The following should not be allowed (types contain pointers to pointers):
type buffer struct {
ptr *byte
len uint32
}
//go:wasmimport module F4
func F4(b *buffer)
//go:wasmimport module F5
func F5(p **byte)