You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
#59149 removed the package restrictions on the use of go:wasmimport, but established strict constraints on the types that can be used as input and result parameters. The motivation for this was that supporting rich types between the host and the client would require sophisticated and expensive runtime type conversions because of the mismatch between the 64 bit architecture of the client and the 32 bit architecture of the host.
With the upcoming 32 bit wasm port, this problem goes away, as both client and host will use 32 bit pointers. However, we can also support a limited set of types on 64 bit platforms, where no runtime conversion is necessary.
Proposal
Relax the constraints on types that can be used as input and result parameters with the go:wasmimport compiler directive. The exact allowed types would depend on whether wasm or wasm32 is used.
We define the "small integer types" group as the set of types described by [u]int[8|16]. The following types would be allowed as input parameters to any wasmimport/wasmexport function:
bool
int32, uint32, int64, uint64
float32, float64
string
uintptr, unsafe.Pointer, *T where T is an allowed parameter type or one of the small integer types.
*struct. All fields of the *struct must be allowed parameter types, struct, [...]T, or one of the small integer types.
Any struct fields must also embed structs.HostLayout (recursively).
*T, unsafe.Pointer, uintptr, and string types are only allowed in *struct on wasm32.
*[...]T where T is an allowed type or one of the small integer types.
All input parameter types except string are also allowed as result parameter types.
The following types would remain disallowed as input and output parameter types:
chan T
complex64, complex128
func
interface
map[T]U
[]T
struct
[...]T
The conventions established for use of pointers in CGO will be required when using pointers with wasmimport/wasmexport, e.g. the host can read Go memory, can write pointerless data (like the content of a byte buffer) but cannot write Go pointers to Go memory, and cannot hold on to Go pointers unless they are pinned.
Discussion
Compatibility guarantees
The Go spec does not specify the struct layout and leaves it up to implementations to decide. As such, we cannot provide a guaranteed ABI without having to change the spec or force future layout changes to provide runtime conversion of data. This proposal suggests making it clear to users through documentation that there are no guarantees of compatibility across versions of the Go compiler.
Type conversion rules
The following conversion rules would be automatically applied by the compiler for the respective parameter type:
The wasm architecture uses 64 bit pointers and integer sizes. As the host uses 32 bit pointers, this makes it impossible to allow certain types without costly runtime conversions, such as *struct types containing pointer fields. Since string types are also pointer types, *struct types containing string fields are also disallowed.
Supporting [u]int, [u]int8, [u]int16 as concrete parameters
The [u]int types are problematic as the size of them are not precisely defined, and may cause confusion when used with strictly 32 bit or 64 bit integers. The [u]int8 and [u]int16 types are problematic because we would be forced to automatically convert them to/from the i32 wasm representation, with potential loss of precision or overflow. They are still allowed as pointer type, array elements and struct fields.
Supporting slices, maps
Both slices and maps are disallowed because of the uncertainty around the memory underlying these types and interactions with struct and array rules. Users who wish to use slices can manually use (&slice, len(slice)) or unsafe.Pointer. There is no clear way to support passing or returning map data from the host other than by using unsafe.Pointer and making assumptions about the underlying data.
Related proposals
struct.Hostlayout
#66408 proposes a way for users to request that struct layout is host compatible. Our proposal depends on the definitions put forward in this proposal for struct parameters.
Future work
WASI Preview 2 (AKA WASI 0.2)
WASI Preview 2 defines its API in terms of the Component Model, with a rich type system and an IDL language, WIT. The Component Model also defines a Canonical ABI with a specification for lifting and lowering Component Model types into and out of linear memory. This proposal does not attempt to define the ABI for any hypothetical wasip2 target, and would leave such decisions for any future wasip2 proposal.
Supporting struct and [...]T by value
A previous version of this proposal included support for passing struct and [...]T types by value by expanding each field recursively into call parameters. This was removed in favor of a simpler initial implementation but could be re-added if users require it.
Background
#59149 removed the package restrictions on the use of
go:wasmimport, but established strict constraints on the types that can be used as input and result parameters. The motivation for this was that supporting rich types between the host and the client would require sophisticated and expensive runtime type conversions because of the mismatch between the 64 bit architecture of the client and the 32 bit architecture of the host.With the upcoming 32 bit wasm port, this problem goes away, as both client and host will use 32 bit pointers. However, we can also support a limited set of types on 64 bit platforms, where no runtime conversion is necessary.
Proposal
Relax the constraints on types that can be used as input and result parameters with the
go:wasmimportcompiler directive. The exact allowed types would depend on whetherwasmorwasm32is used.We define the "small integer types" group as the set of types described by
[u]int[8|16]. The following types would be allowed as input parameters to anywasmimport/wasmexportfunction:boolint32,uint32,int64,uint64float32,float64stringuintptr,unsafe.Pointer,*TwhereTis an allowed parameter type or one of the small integer types.*struct. All fields of the*structmust be allowed parameter types,struct,[...]T, or one of the small integer types.structs.HostLayout(see structs: add HostLayout "directive" type #66408).structfields must also embedstructs.HostLayout(recursively).*T,unsafe.Pointer,uintptr, andstringtypes are only allowed in*structonwasm32.*[...]TwhereTis an allowed type or one of the small integer types.All input parameter types except
stringare also allowed as result parameter types.The following types would remain disallowed as input and output parameter types:
chan Tcomplex64,complex128funcinterfacemap[T]U[]Tstruct[...]TThe conventions established for use of pointers in CGO will be required when using pointers with
wasmimport/wasmexport, e.g. the host can read Go memory, can write pointerless data (like the content of a byte buffer) but cannot write Go pointers to Go memory, and cannot hold on to Go pointers unless they are pinned.Discussion
Compatibility guarantees
The Go spec does not specify the struct layout and leaves it up to implementations to decide. As such, we cannot provide a guaranteed ABI without having to change the spec or force future layout changes to provide runtime conversion of data. This proposal suggests making it clear to users through documentation that there are no guarantees of compatibility across versions of the Go compiler.
Type conversion rules
The following conversion rules would be automatically applied by the compiler for the respective parameter type:
booli32int32, uint32int64, uint64i32, i32i64, i64float32, float64f32, f64string(i32, i32)tuple of (pointer, len). Only allowed for input parameters.uintptr,unsafe.Pointer,*T,*struct,*[...]Ti32, i32, i32, i32, i32Strings
Strings are not allowed as result parameters as Wasm practically does not allow more than 1 result parameter.
Supporting
GOARCH=wasmThe
wasmarchitecture uses 64 bit pointers and integer sizes. As the host uses 32 bit pointers, this makes it impossible to allow certain types without costly runtime conversions, such as*structtypes containing pointer fields. Sincestringtypes are also pointer types,*structtypes containingstringfields are also disallowed.Supporting
[u]int,[u]int8,[u]int16as concrete parametersThe
[u]inttypes are problematic as the size of them are not precisely defined, and may cause confusion when used with strictly 32 bit or 64 bit integers. The[u]int8and[u]int16types are problematic because we would be forced to automatically convert them to/from thei32wasm representation, with potential loss of precision or overflow. They are still allowed as pointer type, array elements and struct fields.Supporting slices, maps
Both slices and maps are disallowed because of the uncertainty around the memory underlying these types and interactions with struct and array rules. Users who wish to use slices can manually use
(&slice, len(slice))orunsafe.Pointer. There is no clear way to support passing or returning map data from the host other than by usingunsafe.Pointerand making assumptions about the underlying data.Related proposals
struct.Hostlayout
#66408 proposes a way for users to request that struct layout is host compatible. Our proposal depends on the definitions put forward in this proposal for
structparameters.Future work
WASI Preview 2 (AKA WASI 0.2)
WASI Preview 2 defines its API in terms of the Component Model, with a rich type system and an IDL language, WIT. The Component Model also defines a Canonical ABI with a specification for lifting and lowering Component Model types into and out of linear memory. This proposal does not attempt to define the ABI for any hypothetical wasip2 target, and would leave such decisions for any future wasip2 proposal.
Supporting
structand[...]Tby valueA previous version of this proposal included support for passing
structand[...]Ttypes by value by expanding each field recursively into call parameters. This was removed in favor of a simpler initial implementation but could be re-added if users require it.Contributors
@johanbrandhorst, @evanphx, @achille-roussel, @dgryski, @ydnar
CC @cherrymui @golang/wasm
@gabyhelp's overview of this issue: #66984 (comment)