Skip to content

Commit

Permalink
all: wasip2 support
Browse files Browse the repository at this point in the history
  • Loading branch information
dgryski committed Apr 24, 2024
1 parent 3d433fe commit 589e1ec
Show file tree
Hide file tree
Showing 114 changed files with 6,767 additions and 129 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
go.work
go.work.sum

docs/_build
src/device/avr/*.go
src/device/avr/*.ld
Expand All @@ -17,7 +20,7 @@ src/device/kendryte/*.go
src/device/kendryte/*.s
src/device/rp/*.go
src/device/rp/*.s
vendor
./vendor
llvm-build
llvm-project
build/*
Expand Down
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,9 @@
path = src/net
url = https://github.com/tinygo-org/net.git
branch = dev
[submodule "lib/wasi-cli"]
path = lib/wasi-cli
url = https://github.com/WebAssembly/wasi-cli
[submodule "src/vendor/github.com/ydnar/wasm-tools-go"]
path = src/vendor/github.com/ydnar/wasm-tools-go
url = https://github.com/ydnar/wasm-tools-go.git
36 changes: 34 additions & 2 deletions GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,11 @@ lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a:
@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
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)

# Generate WASI syscall bindings
.PHONY: wasi-syscall
wasi-syscall:
wit-bindgen-go generate -o ./src/internal -p internal --versioned ./lib/wasi-cli/wit

# Check for Node.js used during WASM tests.
NODEJS_VERSION := $(word 1,$(subst ., ,$(shell node -v | cut -c 2-)))
MIN_NODEJS_VERSION=18
Expand Down Expand Up @@ -434,11 +439,38 @@ tinygo-test-wasi-fast:
$(TINYGO) test -target wasip1 $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
tinygo-test-wasip1-fast:
GOOS=wasip1 GOARCH=wasm $(TINYGO) test $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
tinygo-bench-wasi:

tinygo-test-wasip2-slow:
$(TINYGO) test -target=wasip2 $(TEST_PACKAGES_SLOW)
tinygo-test-wasip2-fast:
$(TINYGO) test -target=wasip2 $(TEST_PACKAGES_FAST) ./tests/runtime_wasi

tinygo-test-wasip2-wip:
$(TINYGO) test -target wasip2 -x -v $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
tinygo-test-wasip2-dev:
$(TINYGO) test -target wasip2 -wit-package $$(tinygo env TINYGOROOT)/lib/wasi-cli/wit/ -wit-world wasi:cli/command -x -work encoding/csv
tinygo-test-wasip2-sum-slow:
TINYGO=$(TINYGO) \
TARGET=wasip2 \
TESTOPTS="-x -work" \
PACKAGES="$(TEST_PACKAGES_SLOW)" \
gotestsum --raw-command -- ./tools/tgtestjson.sh
tinygo-test-wasip2-sum-fast:
TINYGO=$(TINYGO) \
TARGET=wasip2 \
TESTOPTS="-x -work" \
PACKAGES="$(TEST_PACKAGES_FAST)" \
gotestsum --raw-command -- ./tools/tgtestjson.sh
tinygo-bench-wasip1:
$(TINYGO) test -target wasip1 -bench . $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW)
tinygo-bench-wasi-fast:
tinygo-bench-wasip1-fast:
$(TINYGO) test -target wasip1 -bench . $(TEST_PACKAGES_FAST)

tinygo-bench-wasip2:
$(TINYGO) test -target wasip2 -bench . $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW)
tinygo-bench-wasip2-fast:
$(TINYGO) test -target wasip2 -bench . $(TEST_PACKAGES_FAST)

# Test external packages in a large corpus.
test-corpus:
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
Expand Down
80 changes: 79 additions & 1 deletion builder/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -832,7 +832,11 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
"--output", result.Executable,
)

cmd := exec.Command(goenv.Get("WASMOPT"), args...)
wasmopt := goenv.Get("WASMOPT")
if config.Options.PrintCommands != nil {
config.Options.PrintCommands(wasmopt, args...)
}
cmd := exec.Command(wasmopt, args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr

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

// Run wasm-tools for component-model binaries
witPackage := strings.ReplaceAll(config.Target.WITPackage, "{root}", goenv.Get("TINYGOROOT"))
if config.Options.WITPackage != "" {
witPackage = config.Options.WITPackage
}
witWorld := config.Target.WITWorld
if config.Options.WITWorld != "" {
witWorld = config.Options.WITWorld
}
if witPackage != "" && witWorld != "" {

// wasm-tools component embed -w wasi:cli/command
// $$(tinygo env TINYGOROOT)/lib/wasi-cli/wit/ main.wasm -o embedded.wasm
args := []string{
"component",
"embed",
"-w", witWorld,
witPackage,
result.Executable,
"-o", result.Executable,
}

wasmtools := goenv.Get("WASMTOOLS")
if config.Options.PrintCommands != nil {
config.Options.PrintCommands(wasmtools, args...)
}
cmd := exec.Command(wasmtools, args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr

err := cmd.Run()
if err != nil {
// Preserve a copy of the failure if -work option is used
if config.Options.Work {
dest := filepath.Join(
filepath.Dir(result.Executable),
fmt.Sprintf("%s.embed-fail.wasm", strings.Replace(pkgName, "/", "_", -1)),
)
copyCmd := exec.Command("cp", "-f", result.Executable, dest)
copyCmd.Run()
}
return fmt.Errorf("wasm-tools failed: %w", err)
}

// wasm-tools component new embedded.wasm -o component.wasm
args = []string{
"component",
"new",
result.Executable,
"-o", result.Executable,
}

if config.Options.PrintCommands != nil {
config.Options.PrintCommands(wasmtools, args...)
}
cmd = exec.Command(wasmtools, args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr

err = cmd.Run()
if err != nil {
// Preserve a copy of the failure if -work option is used
if config.Options.Work {
dest := filepath.Join(
filepath.Dir(result.Executable),
fmt.Sprintf("%s.comp-fail.wasm", strings.Replace(pkgName, "/", "_", -1)),
)
copyCmd := exec.Command("cp", "-f", result.Executable, dest)
copyCmd.Run()
}
return fmt.Errorf("wasm-tools failed: %w", err)
}
}

// Print code size if requested.
if config.Options.PrintSizes == "short" || config.Options.PrintSizes == "full" {
packagePathMap := make(map[string]string, len(lprogram.Packages))
Expand Down
2 changes: 2 additions & 0 deletions compileopts/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ type Options struct {
Monitor bool
BaudRate int
Timeout time.Duration
WITPackage string // pass through to wasm-tools component embed invocation
WITWorld string // pass through to wasm-tools component embed -w option
}

// Verify performs a validation on the given options, raising an error if options are not valid.
Expand Down
2 changes: 2 additions & 0 deletions compileopts/target.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ type TargetSpec struct {
JLinkDevice string `json:"jlink-device,omitempty"`
CodeModel string `json:"code-model,omitempty"`
RelocationModel string `json:"relocation-model,omitempty"`
WITPackage string `json:"wit-package,omitempty"`
WITWorld string `json:"wit-world,omitempty"`
}

// overrideProperties overrides all properties that are set in child into itself using reflection.
Expand Down
19 changes: 13 additions & 6 deletions compiler/symbol.go
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
// The list of allowed types is based on this proposal:
// https://github.com/golang/go/issues/59149
func (c *compilerContext) checkWasmImport(f *ssa.Function, pragma string) {
if c.pkg.Path() == "runtime" || c.pkg.Path() == "syscall/js" {
if c.pkg.Path() == "runtime" || c.pkg.Path() == "syscall/js" || c.pkg.Path() == "syscall" {
// The runtime is a special case. Allow all kinds of parameters
// (importantly, including pointers).
return
Expand Down Expand Up @@ -375,19 +375,26 @@ func (c *compilerContext) checkWasmImport(f *ssa.Function, pragma string) {

// Check whether the type maps directly to a WebAssembly type, according to:
// https://github.com/golang/go/issues/59149
// TODO(ydnar): document why we relaxed this for WASI Preview 2.
func isValidWasmType(typ types.Type, isReturn bool) bool {
switch typ := typ.Underlying().(type) {
case *types.Basic:
switch typ.Kind() {
case types.Int32, types.Uint32, types.Int64, types.Uint64:
case types.Bool:
return true
case types.Int8, types.Uint8, types.Int16, types.Uint16, types.Int32, types.Uint32, types.Int64, types.Uint64:
return true
case types.Float32, types.Float64:
return true
case types.UnsafePointer:
if !isReturn {
return true
}
case types.Uintptr, types.UnsafePointer:
return true
case types.String:
return true
}
case *types.Struct:
return true
case *types.Pointer:
return isValidWasmType(typ.Elem(), isReturn)
}
return false
}
Expand Down
13 changes: 0 additions & 13 deletions compiler/testdata/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,6 @@ type Uint uint32
//go:wasmimport modulename validparam
func validparam(a int32, b uint64, c float64, d unsafe.Pointer, e Uint)

// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type int
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type string
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type []byte
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type *int32
//
//go:wasmimport modulename invalidparam
func invalidparam(a int, b string, c []byte, d *int32)

//go:wasmimport modulename validreturn
func validreturn() int32

Expand All @@ -36,8 +28,3 @@ func manyreturns() (int32, int32)
//
//go:wasmimport modulename invalidreturn
func invalidreturn() int

// ERROR: //go:wasmimport modulename invalidUnsafePointerReturn: unsupported result type unsafe.Pointer
//
//go:wasmimport modulename invalidUnsafePointerReturn
func invalidUnsafePointerReturn() unsafe.Pointer
5 changes: 5 additions & 0 deletions goenv/goenv.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,11 @@ func Get(name string) string {
}

return findWasmOpt()
case "WASMTOOLS":
if path := os.Getenv("WASMTOOLS"); path != "" {
return path
}
return "wasm-tools"
default:
return ""
}
Expand Down
1 change: 1 addition & 0 deletions lib/wasi-cli
Submodule wasi-cli added at 6ae826
3 changes: 3 additions & 0 deletions loader/goroot.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool {
"internal/fuzz/": false,
"internal/reflectlite/": false,
"internal/task/": false,
"internal/wasi/": false,
"machine/": false,
"net/": true,
"net/http/": false,
Expand All @@ -249,6 +250,8 @@ func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool {
"runtime/": false,
"sync/": true,
"testing/": true,
"vendor/": true,
"vendor/github.com/": false,
}

if goMinor >= 19 {
Expand Down

0 comments on commit 589e1ec

Please sign in to comment.