Skip to content

all: add GOOS=wasip1 GOARCH=wasm port #58141

Closed
@johanbrandhorst

Description

@johanbrandhorst

Background

The WebAssembly System Interface (WASI, https://wasi.dev/) is gaining popularity as a compile-once-run-anywhere target for developer and cloud native applications. Many cloud providers are offering services that make it possible to execute WASI directly inside familiar orchestration frameworks like Kubernetes (https://learn.microsoft.com/en-us/azure/aks/use-wasi-node-pools, https://docs.krustlet.dev/howto/), or on edge compute platforms (https://developer.fastly.com/learning/compute/, https://blog.cloudflare.com/announcing-wasi-on-workers/) and the popular developer tool Docker has beta support for executing wasi directly (https://docs.docker.com/desktop/wasm/). For Go to remain relevant in a hypothetical world where this becomes a significant part of software delivery, it must support compiling code to the Wasm binary format and the WASI syscall API.

Proposal

We propose adding a new port, GOOS=wasip1 GOARCH=wasm, that targets the wasi_snapshot_preview1 syscall API. We further propose allowing the use of the go:wasmimport compiler directive in the syscall package, in addition to the currently allowed runtime and syscall/js packages.

Discussion

Go already supports WebAssembly (Wasm) through the existing GOOS=js GOARCH=wasm port, and the implementation of this proposal would reuse the existing Wasm architecture code and change the interface with which the compiled code interacts with the outside world. It builds on the accepted proposal (#38248) for a go:wasmimport compiler directive for defining Wasm host function imports. The compiled code would be a “Command”, executing func main and running until exit, similar to the existing js/wasm port.

Syscall API target

Today, implementing WASI means implementing the wasi_snapshot_preview1 API described in the spec. However, this interface is evolving without the insurance of backward compatibility. A “preview2” version is already being worked on. Should the Go compiler support the old one for now, and switch to the new one in the future, or should we name the new GOOS such that we can add new GOOS’s for new WASI APIs? We propose that we assume the wasi_snapshot_preview1 API for now and that future releases of Go may add support for newer syscall APIs under a different GOOS (e.g. GOOS=wasip2 for wasi_snapshot_preview2).

Maintainers

Since this is a new port and the porting policy requires at least two maintainers, Evan Phoenix (@evanphx), Julien Fabre (@Pryz) and I (@johanbrandhorst) are volunteering to be maintainers of this port.

Testing

The wasi/wasm port will be tested by executing the standard library tests using an established WASI VM, such as Wasmtime. This software has precompiled binaries available for download, which can be used to set up a builder for the trybots, similar to how NodeJS is used for the js/wasm port.

What happens to the js/wasm port?

The existing js/wasm port will remain relevant for the purposes of compiling Go Wasm for running in a JavaScript VM and using the syscall/js interface for interacting with the JS world. Both ports will coexist, and should eventually require minimal differences in compiler and syscall code. See the discussion on rewriting wasm_exec.js for more information.

A note on capabilities

wasi_snapshot_preview1 is limited in ways that may be surprising to users, for example, it is not possible to open a network socket with the APIs defined in the spec. The initial implementation of the wasi target will aim to implement as much of the standard library as possible, but there will be big gaps.

Related issues

This would close #31105, which has mostly been a discussion issue.

Future work

WASI Preview2

As the second snapshot of the WASI standard matures, we will aim to add support for the new standard. This will unlock new functionality such as networking sockets and ensure that Go’s WASI support remains relevant for users. This could be done in any new major release of the Go toolchain, but not in a minor revision.

Considering the upcoming changes in preview 2, it is a legitimate question to ask whether the work to add support for wasi_snapshot_preview1 is worth doing; could we simply wait for the next standard iteration? We believe the work to be useful because at this time, all compilers are targeting preview 1, and preview 2 seems far from being fully completed. We also believe that runtimes will provide polyfills to preview 1 while preview 2 is in the process of being implemented (see this Wasmtime issue). Finally, the next version of the WASI standard is split into multiple components, and it is possible that specifications for each component will be finalized at different times, with preview 1 remaining the de-facto fallback for components that are not yet fully specified or implemented by runtimes yet.

Rewriting wasm_exec.js as WASI and unifying syscall interfaces

The existing js/wasm port has a custom syscall interface implemented by wasm_exec.js and run on any JavaScript VM. Now that a standard is emerging, the js/wasm target should reuse the same syscall interface, allowing parts of the syscall interface between wasi and js to be unified to reduce maintenance burden. This would require implementing a WASI interface shim in wasm_exec.js, which is a significant undertaking, and thus out of scope of this initial WASI work.

WASI Libraries (AKA Reactors)

The WASI concept of libraries allow compiled binaries to expose single functions for consumption from the host. This is not something that will be supported in the initial WASI port, as it requires a concept of marking Go functions as exported (i.e. //go:wasmexport), and somehow facilitating the execution of a single function. For more discussions on why this is complicated, see #42372.

GOOS=none GOARCH=wasm

Binary wasm can run without any particular knowledge of its host, perhaps using something like GOOS=none, similar to Rust’s wasm32-unknown-unknown target. This proposal does not propose any such port be added, but it may be something to consider in the future. The name “none” is, of course, not decided.

Authors

@johanbrandhorst, @Pryz, @evanphx, @achille-roussel

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions