Skip to content

Commit b2ae42f

Browse files
committed
all: wasip2 support
1 parent 331cfb6 commit b2ae42f

File tree

108 files changed

+6695
-122
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

108 files changed

+6695
-122
lines changed

.gitignore

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
go.work
2+
go.work.sum
3+
14
docs/_build
25
src/device/avr/*.go
36
src/device/avr/*.ld
@@ -17,7 +20,7 @@ src/device/kendryte/*.go
1720
src/device/kendryte/*.s
1821
src/device/rp/*.go
1922
src/device/rp/*.s
20-
vendor
23+
./vendor
2124
llvm-build
2225
llvm-project
2326
build/*

.gitmodules

+6
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,9 @@
3939
path = src/net
4040
url = https://github.com/tinygo-org/net.git
4141
branch = dev
42+
[submodule "lib/wasi-cli"]
43+
path = lib/wasi-cli
44+
url = https://github.com/WebAssembly/wasi-cli
45+
[submodule "src/vendor/github.com/ydnar/wasm-tools-go"]
46+
path = src/vendor/github.com/ydnar/wasm-tools-go
47+
url = https://github.com/ydnar/wasm-tools-go.git

GNUmakefile

+34-2
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,11 @@ lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a:
268268
@if [ ! -e lib/wasi-libc/Makefile ]; then echo "Submodules have not been downloaded. Please download them using:\n git submodule update --init"; exit 1; fi
269269
cd lib/wasi-libc && $(MAKE) -j4 EXTRA_CFLAGS="-O2 -g -DNDEBUG -mnontrapping-fptoint -msign-ext" MALLOC_IMPL=none CC="$(CLANG)" AR=$(LLVM_AR) NM=$(LLVM_NM)
270270

271+
# Generate WASI syscall bindings
272+
.PHONY: wasi-syscall
273+
wasi-syscall:
274+
wit-bindgen-go generate -o ./src/syscall -p syscall --versioned ./lib/wasi-cli/wit
275+
271276
# Check for Node.js used during WASM tests.
272277
NODEJS_VERSION := $(word 1,$(subst ., ,$(shell node -v | cut -c 2-)))
273278
MIN_NODEJS_VERSION=18
@@ -434,11 +439,38 @@ tinygo-test-wasi-fast:
434439
$(TINYGO) test -target wasip1 $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
435440
tinygo-test-wasip1-fast:
436441
GOOS=wasip1 GOARCH=wasm $(TINYGO) test $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
437-
tinygo-bench-wasi:
442+
443+
tinygo-test-wasip2-slow:
444+
$(TINYGO) test -target=wasip2 $(TEST_PACKAGES_SLOW)
445+
tinygo-test-wasip2-fast:
446+
$(TINYGO) test -target=wasip2 $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
447+
448+
tinygo-test-wasip2-wip:
449+
$(TINYGO) test -target wasip2 -x -v $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
450+
tinygo-test-wasip2-dev:
451+
$(TINYGO) test -target wasip2 -wit-package $$(tinygo env TINYGOROOT)/lib/wasi-cli/wit/ -wit-world wasi:cli/command -x -work encoding/csv
452+
tinygo-test-wasip2-sum-slow:
453+
TINYGO=$(TINYGO) \
454+
TARGET=wasip2 \
455+
TESTOPTS="-x -work" \
456+
PACKAGES="$(TEST_PACKAGES_SLOW)" \
457+
gotestsum --raw-command -- ./tools/tgtestjson.sh
458+
tinygo-test-wasip2-sum-fast:
459+
TINYGO=$(TINYGO) \
460+
TARGET=wasip2 \
461+
TESTOPTS="-x -work" \
462+
PACKAGES="$(TEST_PACKAGES_FAST)" \
463+
gotestsum --raw-command -- ./tools/tgtestjson.sh
464+
tinygo-bench-wasip1:
438465
$(TINYGO) test -target wasip1 -bench . $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW)
439-
tinygo-bench-wasi-fast:
466+
tinygo-bench-wasip1-fast:
440467
$(TINYGO) test -target wasip1 -bench . $(TEST_PACKAGES_FAST)
441468

469+
tinygo-bench-wasip2:
470+
$(TINYGO) test -target wasip2 -bench . $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW)
471+
tinygo-bench-wasip2-fast:
472+
$(TINYGO) test -target wasip2 -bench . $(TEST_PACKAGES_FAST)
473+
442474
# Test external packages in a large corpus.
443475
test-corpus:
444476
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=1h -buildmode exe -tags byollvm -run TestCorpus . -corpus=testdata/corpus.yaml

builder/build.go

+79-1
Original file line numberDiff line numberDiff line change
@@ -832,7 +832,11 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
832832
"--output", result.Executable,
833833
)
834834

835-
cmd := exec.Command(goenv.Get("WASMOPT"), args...)
835+
wasmopt := goenv.Get("WASMOPT")
836+
if config.Options.PrintCommands != nil {
837+
config.Options.PrintCommands(wasmopt, args...)
838+
}
839+
cmd := exec.Command(wasmopt, args...)
836840
cmd.Stdout = os.Stdout
837841
cmd.Stderr = os.Stderr
838842

@@ -842,6 +846,80 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
842846
}
843847
}
844848

849+
// Run wasm-tools for component-model binaries
850+
witPackage := strings.ReplaceAll(config.Target.WitPackage, "{root}", goenv.Get("TINYGOROOT"))
851+
if config.Options.WitPackage != "" {
852+
witPackage = config.Options.WitPackage
853+
}
854+
witWorld := config.Target.WitWorld
855+
if config.Options.WitWorld != "" {
856+
witWorld = config.Options.WitWorld
857+
}
858+
if witPackage != "" && witWorld != "" {
859+
860+
// wasm-tools component embed -w wasi:cli/command
861+
// $$(tinygo env TINYGOROOT)/lib/wasi-cli/wit/ main.wasm -o embedded.wasm
862+
args := []string{
863+
"component",
864+
"embed",
865+
"-w", witWorld,
866+
witPackage,
867+
result.Executable,
868+
"-o", result.Executable,
869+
}
870+
871+
wasmtools := goenv.Get("WASMTOOLS")
872+
if config.Options.PrintCommands != nil {
873+
config.Options.PrintCommands(wasmtools, args...)
874+
}
875+
cmd := exec.Command(wasmtools, args...)
876+
cmd.Stdout = os.Stdout
877+
cmd.Stderr = os.Stderr
878+
879+
err := cmd.Run()
880+
if err != nil {
881+
// Preserve a copy of the failure if -work option is used
882+
if config.Options.Work {
883+
dest := filepath.Join(
884+
filepath.Dir(result.Executable),
885+
fmt.Sprintf("%s.embed-fail.wasm", strings.Replace(pkgName, "/", "_", -1)),
886+
)
887+
copyCmd := exec.Command("cp", "-f", result.Executable, dest)
888+
copyCmd.Run()
889+
}
890+
return fmt.Errorf("wasm-tools failed: %w", err)
891+
}
892+
893+
// wasm-tools component new embedded.wasm -o component.wasm
894+
args = []string{
895+
"component",
896+
"new",
897+
result.Executable,
898+
"-o", result.Executable,
899+
}
900+
901+
if config.Options.PrintCommands != nil {
902+
config.Options.PrintCommands(wasmtools, args...)
903+
}
904+
cmd = exec.Command(wasmtools, args...)
905+
cmd.Stdout = os.Stdout
906+
cmd.Stderr = os.Stderr
907+
908+
err = cmd.Run()
909+
if err != nil {
910+
// Preserve a copy of the failure if -work option is used
911+
if config.Options.Work {
912+
dest := filepath.Join(
913+
filepath.Dir(result.Executable),
914+
fmt.Sprintf("%s.comp-fail.wasm", strings.Replace(pkgName, "/", "_", -1)),
915+
)
916+
copyCmd := exec.Command("cp", "-f", result.Executable, dest)
917+
copyCmd.Run()
918+
}
919+
return fmt.Errorf("wasm-tools failed: %w", err)
920+
}
921+
}
922+
845923
// Print code size if requested.
846924
if config.Options.PrintSizes == "short" || config.Options.PrintSizes == "full" {
847925
packagePathMap := make(map[string]string, len(lprogram.Packages))

compileopts/options.go

+2
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ type Options struct {
5353
Monitor bool
5454
BaudRate int
5555
Timeout time.Duration
56+
WitPackage string // pass through to wasm-tools component embed invocation
57+
WitWorld string // pass through to wasm-tools component embed -w option
5658
}
5759

5860
// Verify performs a validation on the given options, raising an error if options are not valid.

compileopts/target.go

+2
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ type TargetSpec struct {
6262
JLinkDevice string `json:"jlink-device,omitempty"`
6363
CodeModel string `json:"code-model,omitempty"`
6464
RelocationModel string `json:"relocation-model,omitempty"`
65+
WitPackage string `json:"wit-package,omitempty"`
66+
WitWorld string `json:"wit-world,omitempty"`
6567
}
6668

6769
// overrideProperties overrides all properties that are set in child into itself using reflection.

compiler/symbol.go

+13-6
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
346346
// The list of allowed types is based on this proposal:
347347
// https://github.com/golang/go/issues/59149
348348
func (c *compilerContext) checkWasmImport(f *ssa.Function, pragma string) {
349-
if c.pkg.Path() == "runtime" || c.pkg.Path() == "syscall/js" {
349+
if c.pkg.Path() == "runtime" || c.pkg.Path() == "syscall/js" || c.pkg.Path() == "syscall" {
350350
// The runtime is a special case. Allow all kinds of parameters
351351
// (importantly, including pointers).
352352
return
@@ -375,19 +375,26 @@ func (c *compilerContext) checkWasmImport(f *ssa.Function, pragma string) {
375375

376376
// Check whether the type maps directly to a WebAssembly type, according to:
377377
// https://github.com/golang/go/issues/59149
378+
// TODO(ydnar): document why we relaxed this for WASI Preview 2.
378379
func isValidWasmType(typ types.Type, isReturn bool) bool {
379380
switch typ := typ.Underlying().(type) {
380381
case *types.Basic:
381382
switch typ.Kind() {
382-
case types.Int32, types.Uint32, types.Int64, types.Uint64:
383+
case types.Bool:
384+
return true
385+
case types.Int8, types.Uint8, types.Int16, types.Uint16, types.Int32, types.Uint32, types.Int64, types.Uint64:
383386
return true
384387
case types.Float32, types.Float64:
385388
return true
386-
case types.UnsafePointer:
387-
if !isReturn {
388-
return true
389-
}
389+
case types.Uintptr, types.UnsafePointer:
390+
return true
391+
case types.String:
392+
return true
390393
}
394+
case *types.Struct:
395+
return true
396+
case *types.Pointer:
397+
return isValidWasmType(typ.Elem(), isReturn)
391398
}
392399
return false
393400
}

compiler/testdata/errors.go

-13
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,6 @@ type Uint uint32
1616
//go:wasmimport modulename validparam
1717
func validparam(a int32, b uint64, c float64, d unsafe.Pointer, e Uint)
1818

19-
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type int
20-
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type string
21-
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type []byte
22-
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type *int32
23-
//
24-
//go:wasmimport modulename invalidparam
25-
func invalidparam(a int, b string, c []byte, d *int32)
26-
2719
//go:wasmimport modulename validreturn
2820
func validreturn() int32
2921

@@ -36,8 +28,3 @@ func manyreturns() (int32, int32)
3628
//
3729
//go:wasmimport modulename invalidreturn
3830
func invalidreturn() int
39-
40-
// ERROR: //go:wasmimport modulename invalidUnsafePointerReturn: unsupported result type unsafe.Pointer
41-
//
42-
//go:wasmimport modulename invalidUnsafePointerReturn
43-
func invalidUnsafePointerReturn() unsafe.Pointer

goenv/goenv.go

+5
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,11 @@ func Get(name string) string {
159159
}
160160

161161
return findWasmOpt()
162+
case "WASMTOOLS":
163+
if path := os.Getenv("WASMTOOLS"); path != "" {
164+
return path
165+
}
166+
return "wasm-tools"
162167
default:
163168
return ""
164169
}

lib/wasi-cli

Submodule wasi-cli added at 6ae8261

loader/goroot.go

+4
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool {
240240
"internal/fuzz/": false,
241241
"internal/reflectlite/": false,
242242
"internal/task/": false,
243+
"internal/wasm/": false,
243244
"machine/": false,
244245
"net/": true,
245246
"net/http/": false,
@@ -249,6 +250,8 @@ func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool {
249250
"runtime/": false,
250251
"sync/": true,
251252
"testing/": true,
253+
"vendor/": true,
254+
"vendor/github.com/": false,
252255
}
253256

254257
if goMinor >= 19 {
@@ -259,6 +262,7 @@ func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool {
259262

260263
if needsSyscallPackage {
261264
paths["syscall/"] = true // include syscall/js
265+
paths["syscall/wasi/"] = false
262266
}
263267
return paths
264268
}

main.go

+36-7
Original file line numberDiff line numberDiff line change
@@ -306,16 +306,25 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
306306
// reads any files.
307307
//
308308
// Ex. run --dir=.. --dir=../.. --dir=../../..
309-
dirs := dirsToModuleRoot(result.MainDir, result.ModuleRoot)
309+
var dirs []string
310+
switch config.GOOS() {
311+
case "wasip1":
312+
dirs = dirsToModuleRootRel(result.MainDir, result.ModuleRoot)
313+
case "wasip2", "linux":
314+
dirs = dirsToModuleRootAbs(result.MainDir, result.ModuleRoot)
315+
default:
316+
return fmt.Errorf("unknown GOOS target: %v", config.GOOS())
317+
}
318+
310319
args := []string{"run"}
311-
for _, d := range dirs[1:] {
320+
for _, d := range dirs {
312321
args = append(args, "--dir="+d)
313322
}
314323

315-
// The below re-organizes the arguments so that the current
316-
// directory is added last.
324+
args = append(args, "--env=PWD="+cmd.Dir)
325+
317326
args = append(args, cmd.Args[1:]...)
318-
cmd.Args = append(cmd.Args[:1:1], args...)
327+
cmd.Args = args
319328
}
320329

321330
// Run the test.
@@ -356,7 +365,7 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
356365
return passed, err
357366
}
358367

359-
func dirsToModuleRoot(maindir, modroot string) []string {
368+
func dirsToModuleRootRel(maindir, modroot string) []string {
360369
var dirs = []string{"."}
361370
last := ".."
362371
// strip off path elements until we hit the module root
@@ -369,6 +378,19 @@ func dirsToModuleRoot(maindir, modroot string) []string {
369378
return dirs
370379
}
371380

381+
func dirsToModuleRootAbs(maindir, modroot string) []string {
382+
var dirs = []string{maindir}
383+
last := filepath.Join(maindir, "..")
384+
// strip off path elements until we hit the module root
385+
// adding `..`, `../..`, `../../..` until we're done
386+
for maindir != modroot {
387+
dirs = append(dirs, last)
388+
last = filepath.Join(last, "..")
389+
maindir = filepath.Dir(maindir)
390+
}
391+
return dirs
392+
}
393+
372394
// Flash builds and flashes the built binary to the given serial port.
373395
func Flash(pkgName, port string, options *compileopts.Options) error {
374396
config, err := builder.NewConfig(options)
@@ -820,7 +842,6 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
820842
} else if config.EmulatorName() == "wasmtime" {
821843
// Wasmtime needs some special flags to pass environment variables
822844
// and allow reading from the current directory.
823-
emuArgs = append(emuArgs, "--dir=.")
824845
for _, v := range environmentVars {
825846
emuArgs = append(emuArgs, "--env", v)
826847
}
@@ -1464,6 +1485,12 @@ func main() {
14641485
flag.StringVar(&outpath, "o", "", "output filename")
14651486
}
14661487

1488+
var witPackage, witWorld string
1489+
if command == "help" || command == "build" || command == "test" {
1490+
flag.StringVar(&witPackage, "wit-package", "", "wit package for wasm component embedding")
1491+
flag.StringVar(&witWorld, "wit-world", "", "wit world for wasm component embedding")
1492+
}
1493+
14671494
var testConfig compileopts.TestConfig
14681495
if command == "help" || command == "test" {
14691496
flag.BoolVar(&testConfig.CompileOnly, "c", false, "compile the test binary but do not run it")
@@ -1543,6 +1570,8 @@ func main() {
15431570
Monitor: *monitor,
15441571
BaudRate: *baudrate,
15451572
Timeout: *timeout,
1573+
WitPackage: witPackage,
1574+
WitWorld: witWorld,
15461575
}
15471576
if *printCommands {
15481577
options.PrintCommands = printCommand

src/crypto/rand/rand_arc4random.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//go:build darwin || tinygo.wasm
1+
//go:build darwin || wasip1 || wasip2
22

33
// This implementation of crypto/rand uses the arc4random_buf function
44
// (available on both MacOS and WASI) to generate random numbers.

src/crypto/rand/rand_urandom.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//go:build linux && !baremetal && !wasip1
1+
//go:build linux && !baremetal && !wasip1 && !wasip2
22

33
// This implementation of crypto/rand uses the /dev/urandom pseudo-file to
44
// generate random numbers.

0 commit comments

Comments
 (0)