Skip to content

Commit

Permalink
all: wasip2 support
Browse files Browse the repository at this point in the history
  • Loading branch information
dgryski committed May 1, 2024
1 parent 293b620 commit 19780b4
Show file tree
Hide file tree
Showing 117 changed files with 6,829 additions and 147 deletions.
26 changes: 14 additions & 12 deletions .github/workflows/linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -134,17 +134,19 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: true
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: '1.22'
cache: true
- name: Install wasmtime
run: |
mkdir -p $HOME/.wasmtime $HOME/.wasmtime/bin
curl https://github.com/bytecodealliance/wasmtime/releases/download/v14.0.4/wasmtime-v14.0.4-x86_64-linux.tar.xz -o wasmtime-v14.0.4-x86_64-linux.tar.xz -SfL
tar -C $HOME/.wasmtime/bin --wildcards -xf wasmtime-v14.0.4-x86_64-linux.tar.xz --strip-components=1 wasmtime-v14.0.4-x86_64-linux/*
echo "$HOME/.wasmtime/bin" >> $GITHUB_PATH
uses: bytecodealliance/actions/wasmtime/setup@v1
with:
version: "19.0.1"
- name: Install wasm-tools
uses: bytecodealliance/actions/wasm-tools/setup@v1
- name: Download release artifact
uses: actions/download-artifact@v4
with:
Expand All @@ -154,8 +156,8 @@ jobs:
mkdir -p ~/lib
tar -C ~/lib -xf tinygo.linux-amd64.tar.gz
ln -s ~/lib/tinygo/bin/tinygo ~/go/bin/tinygo
- run: make tinygo-test-wasi-fast
- run: make tinygo-test-wasip1-fast
# - run: make tinygo-test-wasip1-fast
- run: make tinygo-test-wasip2-fast
- run: make smoketest
assert-test-linux:
# Run all tests that can run on Linux, with LLVM assertions enabled to catch
Expand Down Expand Up @@ -187,11 +189,11 @@ jobs:
with:
node-version: '18'
- name: Install wasmtime
run: |
mkdir -p $HOME/.wasmtime $HOME/.wasmtime/bin
curl -L https://github.com/bytecodealliance/wasmtime/releases/download/v14.0.4/wasmtime-v14.0.4-x86_64-linux.tar.xz -o wasmtime-v14.0.4-x86_64-linux.tar.xz -SfL
tar -C $HOME/.wasmtime/bin --wildcards -xf wasmtime-v14.0.4-x86_64-linux.tar.xz --strip-components=1 wasmtime-v14.0.4-x86_64-linux/*
echo "$HOME/.wasmtime/bin" >> $GITHUB_PATH
uses: bytecodealliance/actions/wasmtime/setup@v1
with:
version: "19.0.1"
- name: Setup `wasm-tools`
uses: bytecodealliance/actions/wasm-tools/setup@v1
- name: Restore LLVM source cache
uses: actions/cache/restore@v4
id: cache-llvm-source
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -220,5 +220,5 @@ jobs:
shell: bash
working-directory: build
run: 7z x release.zip -r
- name: Test stdlib packages on wasi
run: make tinygo-test-wasi-fast TINYGO=$(PWD)/build/tinygo/bin/tinygo
- name: Test stdlib packages on wasip1
run: make tinygo-test-wasip1-fast TINYGO=$(PWD)/build/tinygo/bin/tinygo
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
42 changes: 37 additions & 5 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 @@ -430,15 +435,40 @@ tinygo-test-wasi:
$(TINYGO) test -target wasip1 $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
tinygo-test-wasip1:
GOOS=wasip1 GOARCH=wasm $(TINYGO) test $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
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 -target=wasip1 $(TEST_PACKAGES_FAST) ./tests/runtime_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 Expand Up @@ -828,6 +858,7 @@ build/release: tinygo gen-device wasi-libc $(if $(filter 1,$(USE_SYSTEM_BINARYEN
@mkdir -p build/release/tinygo/lib/wasi-libc/libc-bottom-half/headers
@mkdir -p build/release/tinygo/lib/wasi-libc/libc-top-half/musl/arch
@mkdir -p build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
@mkdir -p build/release/tinygo/lib/wasi-cli/
@mkdir -p build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0
@mkdir -p build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0plus
@mkdir -p build/release/tinygo/pkg/thumbv7em-unknown-unknown-eabi-cortex-m4
Expand Down Expand Up @@ -887,6 +918,7 @@ endif
@cp -rp lib/wasi-libc/libc-top-half/musl/src/string build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
@cp -rp lib/wasi-libc/libc-top-half/musl/include build/release/tinygo/lib/wasi-libc/libc-top-half/musl
@cp -rp lib/wasi-libc/sysroot build/release/tinygo/lib/wasi-libc/sysroot
@cp -rp lib/wasi-cli/wit build/release/tinygo/lib/wasi-cli/wit
@cp -rp llvm-project/compiler-rt/lib/builtins build/release/tinygo/lib/compiler-rt-builtins
@cp -rp llvm-project/compiler-rt/LICENSE.TXT build/release/tinygo/lib/compiler-rt-builtins
@cp -rp src build/release/tinygo/src
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 19780b4

Please sign in to comment.