Skip to content

Commit 24c11d4

Browse files
authored
compiler: conform to latest iteration of wasm types proposal (#4501)
compiler: align with current wasm types proposal golang/go#66984 - Remove int and uint as allowed types in params, results, pointers, or struct fields - Only allow small integers in pointers, arrays, or struct fields - enforce structs.HostLayout usage per wasm types proposal golang/go#66984 - require go1.23 for structs.HostLayout - use an interface to check if GoVersion() exists This permits TinyGo to compile with Go 1.21. - use goenv.Compare instead of WantGoVersion - testdata/wasmexport: use int32 instead of int - compiler/testdata: add structs.HostLayout - compiler/testdata: improve tests for structs.HostLayout
1 parent 3dcac3b commit 24c11d4

File tree

4 files changed

+72
-23
lines changed

4 files changed

+72
-23
lines changed

compiler/symbol.go

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"strings"
1313

1414
"github.com/tinygo-org/tinygo/compiler/llvmutil"
15+
"github.com/tinygo-org/tinygo/goenv"
1516
"github.com/tinygo-org/tinygo/loader"
1617
"golang.org/x/tools/go/ssa"
1718
"tinygo.org/x/go-llvm"
@@ -422,14 +423,14 @@ func (c *compilerContext) checkWasmImportExport(f *ssa.Function, pragma string)
422423
c.addError(f.Signature.Results().At(1).Pos(), fmt.Sprintf("%s: too many return values", pragma))
423424
} else if f.Signature.Results().Len() == 1 {
424425
result := f.Signature.Results().At(0)
425-
if !isValidWasmType(result.Type(), siteResult) {
426+
if !c.isValidWasmType(result.Type(), siteResult) {
426427
c.addError(result.Pos(), fmt.Sprintf("%s: unsupported result type %s", pragma, result.Type().String()))
427428
}
428429
}
429430
for _, param := range f.Params {
430431
// Check whether the type is allowed.
431432
// Only a very limited number of types can be mapped to WebAssembly.
432-
if !isValidWasmType(param.Type(), siteParam) {
433+
if !c.isValidWasmType(param.Type(), siteParam) {
433434
c.addError(param.Pos(), fmt.Sprintf("%s: unsupported parameter type %s", pragma, param.Type().String()))
434435
}
435436
}
@@ -442,13 +443,15 @@ func (c *compilerContext) checkWasmImportExport(f *ssa.Function, pragma string)
442443
//
443444
// This previously reflected the additional restrictions documented here:
444445
// https://github.com/golang/go/issues/59149
445-
func isValidWasmType(typ types.Type, site wasmSite) bool {
446+
func (c *compilerContext) isValidWasmType(typ types.Type, site wasmSite) bool {
446447
switch typ := typ.Underlying().(type) {
447448
case *types.Basic:
448449
switch typ.Kind() {
449450
case types.Bool:
450451
return true
451-
case types.Int, types.Uint, types.Int8, types.Uint8, types.Int16, types.Uint16, types.Int32, types.Uint32, types.Int64, types.Uint64:
452+
case types.Int8, types.Uint8, types.Int16, types.Uint16:
453+
return site == siteIndirect
454+
case types.Int32, types.Uint32, types.Int64, types.Uint64:
452455
return true
453456
case types.Float32, types.Float64:
454457
return true
@@ -459,19 +462,35 @@ func isValidWasmType(typ types.Type, site wasmSite) bool {
459462
return site == siteParam || site == siteIndirect
460463
}
461464
case *types.Array:
462-
return site == siteIndirect && isValidWasmType(typ.Elem(), siteIndirect)
465+
return site == siteIndirect && c.isValidWasmType(typ.Elem(), siteIndirect)
463466
case *types.Struct:
464467
if site != siteIndirect {
465468
return false
466469
}
470+
// Structs with no fields do not need structs.HostLayout
471+
if typ.NumFields() == 0 {
472+
return true
473+
}
474+
hasHostLayout := true // default to true before detecting Go version
475+
// (*types.Package).GoVersion added in go1.21
476+
if gv, ok := any(c.pkg).(interface{ GoVersion() string }); ok {
477+
if goenv.Compare(gv.GoVersion(), "go1.23") >= 0 {
478+
hasHostLayout = false // package structs added in go1.23
479+
}
480+
}
467481
for i := 0; i < typ.NumFields(); i++ {
468-
if !isValidWasmType(typ.Field(i).Type(), siteIndirect) {
482+
ftyp := typ.Field(i).Type()
483+
if ftyp.String() == "structs.HostLayout" {
484+
hasHostLayout = true
485+
continue
486+
}
487+
if !c.isValidWasmType(ftyp, siteIndirect) {
469488
return false
470489
}
471490
}
472-
return true
491+
return hasHostLayout
473492
case *types.Pointer:
474-
return isValidWasmType(typ.Elem(), siteIndirect)
493+
return c.isValidWasmType(typ.Elem(), siteIndirect)
475494
}
476495
return false
477496
}

compiler/testdata/errors.go

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package main
22

3-
import "unsafe"
3+
import (
4+
"structs"
5+
"unsafe"
6+
)
47

58
//go:wasmimport modulename empty
69
func empty()
@@ -14,31 +17,37 @@ func implementation() {
1417
type Uint uint32
1518

1619
type S struct {
20+
_ structs.HostLayout
1721
a [4]uint32
1822
b uintptr
19-
c int
2023
d float32
2124
e float64
2225
}
2326

2427
//go:wasmimport modulename validparam
25-
func validparam(a int32, b uint64, c float64, d unsafe.Pointer, e Uint, f uintptr, g string, h *int32, i *S)
28+
func validparam(a int32, b uint64, c float64, d unsafe.Pointer, e Uint, f uintptr, g string, h *int32, i *S, j *struct{}, k *[8]uint8)
2629

2730
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type [4]uint32
2831
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type []byte
2932
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type struct{a int}
3033
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type chan struct{}
3134
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type func()
35+
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type int
36+
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type uint
37+
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type [8]int
3238
//
3339
//go:wasmimport modulename invalidparam
34-
func invalidparam(a [4]uint32, b []byte, c struct{ a int }, d chan struct{}, e func())
40+
func invalidparam(a [4]uint32, b []byte, c struct{ a int }, d chan struct{}, e func(), f int, g uint, h [8]int)
41+
42+
// ERROR: //go:wasmimport modulename invalidparam_no_hostlayout: unsupported parameter type *struct{int}
43+
// ERROR: //go:wasmimport modulename invalidparam_no_hostlayout: unsupported parameter type *struct{string}
44+
//
45+
//go:wasmimport modulename invalidparam_no_hostlayout
46+
func invalidparam_no_hostlayout(a *struct{ int }, b *struct{ string })
3547

3648
//go:wasmimport modulename validreturn_int32
3749
func validreturn_int32() int32
3850

39-
//go:wasmimport modulename validreturn_int
40-
func validreturn_int() int
41-
4251
//go:wasmimport modulename validreturn_ptr_int32
4352
func validreturn_ptr_int32() *int32
4453

@@ -48,6 +57,12 @@ func validreturn_ptr_string() *string
4857
//go:wasmimport modulename validreturn_ptr_struct
4958
func validreturn_ptr_struct() *S
5059

60+
//go:wasmimport modulename validreturn_ptr_struct
61+
func validreturn_ptr_empty_struct() *struct{}
62+
63+
//go:wasmimport modulename validreturn_ptr_array
64+
func validreturn_ptr_array() *[8]uint8
65+
5166
//go:wasmimport modulename validreturn_unsafe_pointer
5267
func validreturn_unsafe_pointer() unsafe.Pointer
5368

@@ -56,11 +71,26 @@ func validreturn_unsafe_pointer() unsafe.Pointer
5671
//go:wasmimport modulename manyreturns
5772
func manyreturns() (int32, int32)
5873

74+
// ERROR: //go:wasmimport modulename invalidreturn_int: unsupported result type int
75+
//
76+
//go:wasmimport modulename invalidreturn_int
77+
func invalidreturn_int() int
78+
79+
// ERROR: //go:wasmimport modulename invalidreturn_int: unsupported result type uint
80+
//
81+
//go:wasmimport modulename invalidreturn_int
82+
func invalidreturn_uint() uint
83+
5984
// ERROR: //go:wasmimport modulename invalidreturn_func: unsupported result type func()
6085
//
6186
//go:wasmimport modulename invalidreturn_func
6287
func invalidreturn_func() func()
6388

89+
// ERROR: //go:wasmimport modulename invalidreturn_pointer_array_int: unsupported result type *[8]int
90+
//
91+
//go:wasmimport modulename invalidreturn_pointer_array_int
92+
func invalidreturn_pointer_array_int() *[8]int
93+
6494
// ERROR: //go:wasmimport modulename invalidreturn_slice_byte: unsupported result type []byte
6595
//
6696
//go:wasmimport modulename invalidreturn_slice_byte

testdata/wasmexport-noscheduler.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,16 @@ func hello() {
1818
}
1919

2020
//go:wasmexport add
21-
func add(a, b int) int {
21+
func add(a, b int32) int32 {
2222
println("called add:", a, b)
2323
return a + b
2424
}
2525

2626
//go:wasmimport tester callOutside
27-
func callOutside(a, b int) int
27+
func callOutside(a, b int32) int32
2828

2929
//go:wasmexport reentrantCall
30-
func reentrantCall(a, b int) int {
30+
func reentrantCall(a, b int32) int32 {
3131
println("reentrantCall:", a, b)
3232
result := callOutside(a, b)
3333
println("reentrantCall result:", result)

testdata/wasmexport.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@ func hello() {
2121
}
2222

2323
//go:wasmexport add
24-
func add(a, b int) int {
24+
func add(a, b int32) int32 {
2525
println("called add:", a, b)
2626
addInputs <- a
2727
addInputs <- b
2828
return <-addOutput
2929
}
3030

31-
var addInputs = make(chan int)
32-
var addOutput = make(chan int)
31+
var addInputs = make(chan int32)
32+
var addOutput = make(chan int32)
3333

3434
func adder() {
3535
for {
@@ -41,10 +41,10 @@ func adder() {
4141
}
4242

4343
//go:wasmimport tester callOutside
44-
func callOutside(a, b int) int
44+
func callOutside(a, b int32) int32
4545

4646
//go:wasmexport reentrantCall
47-
func reentrantCall(a, b int) int {
47+
func reentrantCall(a, b int32) int32 {
4848
println("reentrantCall:", a, b)
4949
result := callOutside(a, b)
5050
println("reentrantCall result:", result)

0 commit comments

Comments
 (0)