wazero

package module
v0.0.0-...-29e2939 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 13, 2022 License: Apache-2.0 Imports: 16 Imported by: 0

README

wazero

WebAssembly is a way to safely run code compiled in other languages. Runtimes execute WebAssembly Modules (Wasm), which are most often binaries with a .wasm extension.

wazero is a WebAssembly 1.0 (20191205) spec compliant runtime written in Go. It has zero platform dependencies, and doesn't rely on CGO. This means you can run applications in other languages and still keep cross compilation.

Import wazero and extend your Go application with code written in any language!

Example

Here's an example of using wazero to invoke a factorial function:

func main() {
	// Read a WebAssembly binary containing an exported "fac" function.
	// * Ex. (func (export "fac") (param i64) (result i64) ...
	source, _ := os.ReadFile("./tests/bench/testdata/fac.wasm")

	// Instantiate the module and return its exported functions
	module, _ := wazero.NewRuntime().InstantiateModuleFromCode(source)
	defer module.Close()

	// Discover 7! is 5040
	fmt.Println(module.ExportedFunction("fac").Call(nil, 7))
}

Note: While the source for this is in the WebAssembly 1.0 (20191205) Text Format, it could have been written in another language that compiles to (targets) WebAssembly, such as AssemblyScript, C, C++, Rust, TinyGo or Zig.

Deeper dive

The former example is a pure function. While a good start, you probably are wondering how to do something more realistic, like read a file. WebAssembly Modules (Wasm) are sandboxed similar to containers. They can't read anything on your machine unless you explicitly allow it.

System access is defined by an emerging specification called WebAssembly System Interface (WASI). WASI defines how WebAssembly programs interact with the host embedding them.

For example, here's how you can allow WebAssembly modules to read "/work/home/a.txt" as "/a.txt" or "./a.txt":

wm, err := wasi.InstantiateSnapshotPreview1(r)
defer wm.Close()

config := wazero.ModuleConfig().WithFS(os.DirFS("/work/home"))
module, err := r.InstantiateModule(binary, config)
defer module.Close()
...

The best way to learn this and other features you get with wazero is by trying examples.

Runtime

There are two runtime configurations supported in wazero, where JIT is default:

  1. Interpreter: a naive interpreter-based implementation of Wasm virtual machine. Its implementation doesn't have any platform (GOARCH, GOOS) specific code, therefore interpreter can be used for any compilation target available for Go (such as riscv64).
  2. JIT: compiles WebAssembly modules, generates the machine code, and executing it all at runtime. Currently wazero implements the JIT compiler for amd64 and arm64 target. Generally speaking, JIT is faster than Interpreter by order of magnitude. However, the implementation is immature and has a bunch of aspects that could be improved (for example, it just does a singlepass compilation and doesn't do any optimizations, etc.). Please refer to internal/wasm/jit/RATIONALE.md for the design choices and considerations in our JIT compiler.

Both configurations pass 100% of WebAssembly spec test suites (on supported platforms).

Runtime Usage amd64 arm64 others
Interpreter wazero.NewRuntimeConfigInterpreter()
JIT wazero.NewRuntimeConfigJIT()

If you don't choose, ex wazero.NewRuntime(), JIT is used if supported. You can also force the interpreter like so:

r := wazero.NewRuntimeWithConfig(wazero.NewRuntimeConfigInterpreter())

Support Policy

The below support policy focuses on compatability concerns of those embedding wazero into their Go applications.

wazero

wazero is an early project, so APIs are subject to change until version 1.0.

We expect 1.0 to be at or before Q3 2022, so please practice the current APIs to ensure they work for you!

Go

wazero has no dependencies except Go, so the only source of conflict in your project's use of Wazero is the Go version.

To simplify our support policy, we adopt Go's Release Policy (two versions).

This means wazero will remain compilable and tested on the the version prior to the latest release of Go.

For example, once Go 1.29 is released, wazero may choose to use a Go 1.28 feature.

Platform

wazero has two runtime modes: Interpreter and JIT. The only supported operating systems are ones we test, but that doesn't necessarily mean other operating system versions won't work.

We currently test Linux (Ubuntu and scratch), MacOS and Windows as packaged by GitHub Actions.

  • Interpreter
    • Linux is tested on amd64 (native) as well arm64 and riscv64 via emulation.
    • MacOS and Windows are only tested on amd64.
  • JIT
    • Linux is tested on amd64 (native) as well arm64 via emulation.
    • MacOS and Windows are only tested on amd64.

wazero has no dependencies and doesn't require CGO. This means it can also be embedded in an application that doesn't use an operating system. This is a main differentiator between wazero and alternatives.

We verify wazero's independence by running tests in Docker's scratch image. This approach ensures compatibility with any parent image.

Standards Compliance

The WebAssembly Core Specification 1.0 (20191205) is the only part of the WebAssembly ecosystem that is a W3C recommendation.

In practice, this specification is not enough. Most compilers that target Wasm rely both on features that are not yet W3C recommendations, such as bulk-memory-operations and the WebAssembly System Interface (WASI), whose stable point was a snapshot released at the end of 2020. The aim of this section is to familiarize you with what wazero complies with, and through that understand the current state of interop that considers both standards (W3C recommendations) and non-standard features your tooling may use.

WebAssembly Core

wazero supports the only WebAssembly specification which has reached W3C Recommendation (REC) phase: WebAssembly Core Specification 1.0 (20191205).

Independent verification is possible via the WebAssembly spec test suite, which we run on every change and against all supported platforms.

One current limitation of wazero is that it doesn't fully implement the Text Format, yet, e.g. compiling .wat files. The intent is to finish this, and meanwhile users can work around this using tools such as wat2wasm to compile the text format into the binary format.

Post 1.0 Features

The last W3C REC was at the end of 2019. There were other features that didn't make the cut or were developed in the years since. The community unofficially refers to these as Finished Proposals.

To ensure compatability, wazero does not opt-in to any non-standard feature by default. However, the following status covers what's currently possible with wazero.RuntimeConfig.

Feature Status
mutable-global
nontrapping-float-to-int-conversions
sign-extension-ops
multi-value
JS-BigInt-integration N/A
reference-types
bulk-memory-operations
simd

Note: While the above are specified in a WebAssembly GitHub repository, they are not W3C recommendations (standards). This means they can change further between now and any future update to the W3C WebAssembly core specification. Due to this, we cannot guarantee future compatability. Please encourage the WebAssembly community to formalize features you rely on, specifically to reach the W3C recommendation (REC) phase.

WebAssembly System Interface (WASI)

As of early 2022, the WebAssembly System Interface (WASI) has never reached the recommendation phase of the W3C. The closest to stability is a draft (snapshot-01) released in late 2020. Some functions of this draft are used in practice while some features are not known to be used at all. Further confusion exists because some compilers (ex GrainLang) import functions not used. Finally, snapshot-01 includes features such as "rights" that will be removed.

For all of these reasons, wazero will not implement all WASI features, just to complete the below chart. If you desire something not yet implemented, please raise an issue and include your use case (ex which language you are using to compile, a.k.a. target Wasm).

Click to see the full list of supported WASI systemcalls

Function Status Known Usage
args_get TinyGo
args_sizes_get TinyGo
environ_get TinyGo
environ_sizes_get TinyGo
clock_res_get
clock_time_get TinyGo
fd_advise
fd_allocate
fd_close TinyGo
fd_datasync
fd_fdstat_get TinyGo
fd_fdstat_set_flags
fd_fdstat_set_rights
fd_filestat_get
fd_filestat_set_size
fd_filestat_set_times
fd_pread
fd_prestat_get TinyGo,fs.FS
fd_prestat_dir_name TinyGo
fd_pwrite
fd_read TinyGo,fs.FS
fd_readdir
fd_renumber
fd_seek TinyGo
fd_sync
fd_tell
fd_write fs.FS
path_create_directory
path_filestat_get
path_filestat_set_times
path_link
path_open TinyGo,fs.FS
path_readlink
path_remove_directory
path_rename
path_symlink
path_unlink_file
poll_oneoff TinyGo
proc_exit AssemblyScript
proc_raise
sched_yield
random_get
sock_recv
sock_send
sock_shutdown

History of wazero

wazero was originally developed by Takeshi Yoneda as a hobby project in mid 2020. In late 2021, it was sponsored by Tetrate as a top-level project. That said, Takeshi's original motivation is as relevant today as when he started the project, and worthwhile reading:

If you want to provide Wasm host environments in your Go programs, currently there's no other choice than using CGO andleveraging the state-of-the-art runtimes written in C++/Rust (e.g. V8, Wasmtime, Wasmer, WAVM, etc.), and there's no pure Go Wasm runtime out there. (There's only one exception named wagon, but it was archived with the mention to this project.)

First, why do you want to write host environments in Go? You might want to have plugin systems in your Go project and want these plugin systems to be safe/fast/flexible, and enable users to write plugins in their favorite languages. That's where Wasm comes into play. You write your own Wasm host environments and embed Wasm runtime in your projects, and now users are able to write plugins in their own favorite lanugages (AssembyScript, C, C++, Rust, Zig, etc.). As a specific example, you maybe write proxy severs in Go and want to allow users to extend the proxy via Proxy-Wasm ABI. Maybe you are writing server-side rendering applications via Wasm, or OpenPolicyAgent is using Wasm for plugin system.

However, experienced Golang developers often avoid using CGO because it introduces complexity. For example, CGO projects are larger and complicated to consume due to their libc + shared library dependency. Debugging is more difficult for Go developers when most of a library is written in Rustlang. CGO is not Go -- Rob Pike dives in deeper. In short, the primary motivation to start wazero was to avoid CGO.

wazero compiles WebAssembly modules into native assembly (JIT) by default. You may be surprised to find equal or better performance vs mature JIT-style runtimes because CGO is slow. More specifically, if you make large amount of CGO calls which cross the boundary between Go and C (stack) space, then the usage of CGO could be a bottleneck.

Documentation

Index

Constants

View Source
const JITSupported = true

Variables

This section is empty.

Functions

This section is empty.

Types

type CompiledCode

type CompiledCode struct {
	// contains filtered or unexported fields
}

CompiledCode is a WebAssembly 1.0 (20191205) module ready to be instantiated (Runtime.InstantiateModule) as an\ api.Module.

Note: In WebAssembly language, this is a decoded, validated, and possibly also compiled module. wazero avoids using the name "Module" for both before and after instantiation as the name conflation has caused confusion. See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#semantic-phases%E2%91%A0

type ModuleBuilder

type ModuleBuilder interface {

	// ExportFunction adds a function written in Go, which a WebAssembly module can import.
	//
	// * name - the name to export. Ex "random_get"
	// * goFunc - the `func` to export.
	//
	// Noting a context exception described later, all parameters or result types must match WebAssembly 1.0 (20191205) value
	// types. This means uint32, uint64, float32 or float64. Up to one result can be returned.
	//
	// Ex. This is a valid host function:
	//
	//	addInts := func(x uint32, uint32) uint32 {
	//		return x + y
	//	}
	//
	// Host functions may also have an initial parameter (param[0]) of type context.Context or api.Module.
	//
	// Ex. This uses a Go Context:
	//
	//	addInts := func(m context.Context, x uint32, uint32) uint32 {
	//		// add a little extra if we put some in the context!
	//		return x + y + m.Value(extraKey).(uint32)
	//	}
	//
	// The most sophisticated context is api.Module, which allows access to the Go context, but also
	// allows writing to memory. This is important because there are only numeric types in Wasm. The only way to share other
	// data is via writing memory and sharing offsets.
	//
	// Ex. This reads the parameters from!
	//
	//	addInts := func(m api.Module, offset uint32) uint32 {
	//		x, _ := m.Memory().ReadUint32Le(offset)
	//		y, _ := m.Memory().ReadUint32Le(offset + 4) // 32 bits == 4 bytes!
	//		return x + y
	//	}
	//
	// Note: If a function is already exported with the same name, this overwrites it.
	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#host-functions%E2%91%A2
	ExportFunction(name string, goFunc interface{}) ModuleBuilder

	// ExportFunctions is a convenience that calls ExportFunction for each key/value in the provided map.
	ExportFunctions(nameToGoFunc map[string]interface{}) ModuleBuilder

	// ExportMemory adds linear memory, which a WebAssembly module can import and become available via api.Memory.
	//
	// * name - the name to export. Ex "memory" for wasi.ModuleSnapshotPreview1
	// * minPages - the possibly zero initial size in pages (65536 bytes per page).
	//
	// For example, the WebAssembly 1.0 Text Format below is the equivalent of this builder method:
	//	// (memory (export "memory") 1)
	//	builder.ExportMemory(1)
	//
	// Note: This is allowed to grow to RuntimeConfig.WithMemoryMaxPages (4GiB). To bound it, use ExportMemoryWithMax.
	// Note: If a memory is already exported with the same name, this overwrites it.
	// Note: Version 1.0 (20191205) of the WebAssembly spec allows at most one memory per module.
	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#memory-section%E2%91%A0
	ExportMemory(name string, minPages uint32) ModuleBuilder

	// ExportMemoryWithMax is like ExportMemory, but can prevent overuse of memory.
	//
	// For example, the WebAssembly 1.0 Text Format below is the equivalent of this builder method:
	//	// (memory (export "memory") 1 1)
	//	builder.ExportMemoryWithMax(1, 1)
	//
	// Note: maxPages must be at least minPages and no larger than RuntimeConfig.WithMemoryMaxPages
	ExportMemoryWithMax(name string, minPages, maxPages uint32) ModuleBuilder

	// ExportGlobalI32 exports a global constant of type api.ValueTypeI32.
	//
	// For example, the WebAssembly 1.0 Text Format below is the equivalent of this builder method:
	//	// (global (export "canvas_width") i32 (i32.const 1024))
	//	builder.ExportGlobalI32("canvas_width", 1024)
	//
	// Note: If a global is already exported with the same name, this overwrites it.
	// Note: The maximum value of v is math.MaxInt32 to match constraints of initialization in binary format.
	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#value-types%E2%91%A0
	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#syntax-globaltype
	ExportGlobalI32(name string, v int32) ModuleBuilder

	// ExportGlobalI64 exports a global constant of type api.ValueTypeI64.
	//
	// For example, the WebAssembly 1.0 Text Format below is the equivalent of this builder method:
	//	// (global (export "start_epoch") i64 (i64.const 1620216263544))
	//	builder.ExportGlobalI64("start_epoch", 1620216263544)
	//
	// Note: If a global is already exported with the same name, this overwrites it.
	// Note: The maximum value of v is math.MaxInt64 to match constraints of initialization in binary format.
	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#value-types%E2%91%A0
	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#syntax-globaltype
	ExportGlobalI64(name string, v int64) ModuleBuilder

	// ExportGlobalF32 exports a global constant of type api.ValueTypeF32.
	//
	// For example, the WebAssembly 1.0 Text Format below is the equivalent of this builder method:
	//	// (global (export "math/pi") f32 (f32.const 3.1415926536))
	//	builder.ExportGlobalF32("math/pi", 3.1415926536)
	//
	// Note: If a global is already exported with the same name, this overwrites it.
	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#syntax-globaltype
	ExportGlobalF32(name string, v float32) ModuleBuilder

	// ExportGlobalF64 exports a global constant of type api.ValueTypeF64.
	//
	// For example, the WebAssembly 1.0 Text Format below is the equivalent of this builder method:
	//	// (global (export "math/pi") f64 (f64.const 3.14159265358979323846264338327950288419716939937510582097494459))
	//	builder.ExportGlobalF64("math/pi", 3.14159265358979323846264338327950288419716939937510582097494459)
	//
	// Note: If a global is already exported with the same name, this overwrites it.
	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#syntax-globaltype
	ExportGlobalF64(name string, v float64) ModuleBuilder

	// Build returns a module to instantiate, or returns an error if any of the configuration is invalid.
	Build() (*CompiledCode, error)

	// Instantiate is a convenience that calls Build, then Runtime.InstantiateModule
	//
	// Note: Fields in the builder are copied during instantiation: Later changes do not affect the instantiated result.
	Instantiate() (api.Module, error)
}

ModuleBuilder is a way to define a WebAssembly 1.0 (20191205) in Go.

Ex. Below defines and instantiates a module named "env" with one function:

hello := func() {
	fmt.Fprintln(stdout, "hello!")
}
env, _ := r.NewModuleBuilder("env").ExportFunction("hello", hello).Instantiate()

If the same module may be instantiated multiple times, it is more efficient to separate steps. Ex.

env, _ := r.NewModuleBuilder("env").ExportFunction("get_random_string", getRandomString).Build()

env1, _ := r.InstantiateModuleWithConfig(env, NewModuleConfig().WithName("env.1"))
defer env1.Close()

env2, _ := r.InstantiateModuleWithConfig(env, NewModuleConfig().WithName("env.2"))
defer env2.Close()

Note: Builder methods do not return errors, to allow chaining. Any validation errors are deferred until Build. Note: Insertion order is not retained. Anything defined by this builder is sorted lexicographically on Build.

type ModuleConfig

type ModuleConfig struct {
	// contains filtered or unexported fields
}

ModuleConfig configures resources needed by functions that have low-level interactions with the host operating system. Using this, resources such as STDIN can be isolated (ex via StartWASICommandWithConfig), so that the same module can be safely instantiated multiple times.

Note: While wazero supports Windows as a platform, host functions using ModuleConfig follow a UNIX dialect. See RATIONALE.md for design background and relationship to WebAssembly System Interfaces (WASI).

func NewModuleConfig

func NewModuleConfig() *ModuleConfig

func (*ModuleConfig) WithArgs

func (c *ModuleConfig) WithArgs(args ...string) *ModuleConfig

WithArgs assigns command-line arguments visible to an imported function that reads an arg vector (argv). Defaults to none.

These values are commonly read by the functions like "args_get" in "wasi_snapshot_preview1" although they could be read by functions imported from other modules.

Similar to os.Args and exec.Cmd Env, many implementations would expect a program name to be argv[0]. However, neither WebAssembly nor WebAssembly System Interfaces (WASI) define this. Regardless, you may choose to set the first argument to the same value set via WithName.

Note: This does not default to os.Args as that violates sandboxing. Note: Runtime.InstantiateModule errs if any value is empty. See https://linux.die.net/man/3/argv See https://en.wikipedia.org/wiki/Null-terminated_string

func (*ModuleConfig) WithEnv

func (c *ModuleConfig) WithEnv(key, value string) *ModuleConfig

WithEnv sets an environment variable visible to a Module that imports functions. Defaults to none.

Validation is the same as os.Setenv on Linux and replaces any existing value. Unlike exec.Cmd Env, this does not default to the current process environment as that would violate sandboxing. This also does not preserve order.

Environment variables are commonly read by the functions like "environ_get" in "wasi_snapshot_preview1" although they could be read by functions imported from other modules.

While similar to process configuration, there are no assumptions that can be made about anything OS-specific. For example, neither WebAssembly nor WebAssembly System Interfaces (WASI) define concerns processes have, such as case-sensitivity on environment keys. For portability, define entries with case-insensitively unique keys.

Note: Runtime.InstantiateModule errs if the key is empty or contains a NULL(0) or equals("") character. See https://linux.die.net/man/3/environ See https://en.wikipedia.org/wiki/Null-terminated_string

func (*ModuleConfig) WithFS

func (c *ModuleConfig) WithFS(fs fs.FS) *ModuleConfig

WithFS assigns the file system to use for any paths beginning at "/". Defaults to not found.

Ex. This sets a read-only, embedded file-system to serve files under the root ("/") and working (".") directories:

//go:embed testdata/index.html
var testdataIndex embed.FS

rooted, err := fs.Sub(testdataIndex, "testdata")
require.NoError(t, err)

// "index.html" is accessible as both "/index.html" and "./index.html" because we didn't use WithWorkDirFS.
config := wazero.NewModuleConfig().WithFS(rooted)

Note: This sets WithWorkDirFS to the same file-system unless already set.

func (*ModuleConfig) WithImport

func (c *ModuleConfig) WithImport(oldModule, oldName, newModule, newName string) *ModuleConfig

WithImport replaces a specific import module and name with a new one. This allows you to break up a monolithic module imports, such as "env". This can also help reduce cyclic dependencies.

For example, if a module was compiled with one module owning all imports:

(import "js" "tbl" (table $tbl 4 funcref))
(import "js" "increment" (func $increment (result i32)))
(import "js" "decrement" (func $decrement (result i32)))
(import "js" "wasm_increment" (func $wasm_increment (result i32)))
(import "js" "wasm_decrement" (func $wasm_decrement (result i32)))

Use this function to import "increment" and "decrement" from the module "go" and other imports from "wasm":

config.WithImportModule("js", "wasm")
config.WithImport("wasm", "increment", "go", "increment")
config.WithImport("wasm", "decrement", "go", "decrement")

Upon instantiation, imports resolve as if they were compiled like so:

(import "wasm" "tbl" (table $tbl 4 funcref))
(import "go" "increment" (func $increment (result i32)))
(import "go" "decrement" (func $decrement (result i32)))
(import "wasm" "wasm_increment" (func $wasm_increment (result i32)))
(import "wasm" "wasm_decrement" (func $wasm_decrement (result i32)))

Note: Any WithImport instructions happen in order, after any WithImportModule instructions.

func (*ModuleConfig) WithImportModule

func (c *ModuleConfig) WithImportModule(oldModule, newModule string) *ModuleConfig

WithImportModule replaces every import with oldModule with newModule. This is helpful for modules who have transitioned to a stable status since the underlying wasm was compiled.

For example, if a module was compiled like below, with an old module for WASI:

(import "wasi_unstable" "args_get" (func (param i32, i32) (result i32)))

Use this function to update it to the current version:

config.WithImportModule("wasi_unstable", wasi.ModuleSnapshotPreview1)

See WithImport for a comprehensive example. Note: Any WithImportModule instructions happen in order, before any WithImport instructions.

func (*ModuleConfig) WithName

func (c *ModuleConfig) WithName(name string) *ModuleConfig

WithName configures the module name. Defaults to what was decoded from the module source.

If the source was in WebAssembly 1.0 (20191205) Binary Format, this defaults to what was decoded from the custom name section. Otherwise, if it was decoded from Text Format, this defaults to the module ID stripped of leading '$'.

For example, if the Module was decoded from the text format `(module $math)`, the default name is "math".

See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#name-section%E2%91%A0 See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#custom-section%E2%91%A0 See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#modules%E2%91%A0%E2%91%A2

func (*ModuleConfig) WithStartFunctions

func (c *ModuleConfig) WithStartFunctions(startFunctions ...string) *ModuleConfig

WithStartFunctions configures the functions to call after the module is instantiated. Defaults to "_start".

Note: If any function doesn't exist, it is skipped. However, all functions that do exist are called in order.

func (*ModuleConfig) WithStderr

func (c *ModuleConfig) WithStderr(stderr io.Writer) *ModuleConfig

WithStderr configures where standard error (file descriptor 2) is written. Defaults to io.Discard.

This writer is most commonly used by the functions like "fd_write" in "wasi_snapshot_preview1" although it could be used by functions imported from other modules.

Note: The caller is responsible to close any io.Writer they supply: It is not closed on api.Module Close. Note: This does not default to os.Stderr as that both violates sandboxing and prevents concurrent modules. See https://linux.die.net/man/3/stderr

func (*ModuleConfig) WithStdin

func (c *ModuleConfig) WithStdin(stdin io.Reader) *ModuleConfig

WithStdin configures where standard input (file descriptor 0) is read. Defaults to return io.EOF.

This reader is most commonly used by the functions like "fd_read" in "wasi_snapshot_preview1" although it could be used by functions imported from other modules.

Note: The caller is responsible to close any io.Reader they supply: It is not closed on api.Module Close. Note: This does not default to os.Stdin as that both violates sandboxing and prevents concurrent modules. See https://linux.die.net/man/3/stdin

func (*ModuleConfig) WithStdout

func (c *ModuleConfig) WithStdout(stdout io.Writer) *ModuleConfig

WithStdout configures where standard output (file descriptor 1) is written. Defaults to io.Discard.

This writer is most commonly used by the functions like "fd_write" in "wasi_snapshot_preview1" although it could be used by functions imported from other modules.

Note: The caller is responsible to close any io.Writer they supply: It is not closed on api.Module Close. Note: This does not default to os.Stdout as that both violates sandboxing and prevents concurrent modules. See https://linux.die.net/man/3/stdout

func (*ModuleConfig) WithWorkDirFS

func (c *ModuleConfig) WithWorkDirFS(fs fs.FS) *ModuleConfig

WithWorkDirFS indicates the file system to use for any paths beginning at "./". Defaults to the same as WithFS.

Ex. This sets a read-only, embedded file-system as the root ("/"), and a mutable one as the working directory ("."):

//go:embed appA
var rootFS embed.FS

// Files relative to this source under appA are available under "/" and files relative to "/work/appA" under ".".
config := wazero.NewModuleConfig().WithFS(rootFS).WithWorkDirFS(os.DirFS("/work/appA"))

Note: os.DirFS documentation includes important notes about isolation, which also applies to fs.Sub. As of Go 1.18, the built-in file-systems are not jailed (chroot). See https://github.com/golang/go/issues/42322

type Runtime

type Runtime interface {
	// NewModuleBuilder lets you create modules out of functions defined in Go.
	//
	// Ex. Below defines and instantiates a module named "env" with one function:
	//
	//	hello := func() {
	//		fmt.Fprintln(stdout, "hello!")
	//	}
	//	_, err := r.NewModuleBuilder("env").ExportFunction("hello", hello).Instantiate()
	NewModuleBuilder(moduleName string) ModuleBuilder

	// Module returns exports from an instantiated module or nil if there aren't any.
	Module(moduleName string) api.Module

	// CompileModule decodes the WebAssembly 1.0 (20191205) text or binary source or errs if invalid.
	// Any pre-compilation done after decoding the source is dependent on the RuntimeConfig.
	//
	// There are two main reasons to use CompileModule instead of InstantiateModuleFromCode:
	//  * Improve performance when the same module is instantiated multiple times under different names
	//  * Reduce the amount of errors that can occur during InstantiateModule.
	//
	// Note: The resulting module name defaults to what was binary from the custom name section.
	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#name-section%E2%91%A0
	CompileModule(source []byte) (*CompiledCode, error)

	// InstantiateModuleFromCode instantiates a module from the WebAssembly 1.0 (20191205) text or binary source or
	// errs if invalid.
	//
	// Ex.
	//	module, _ := wazero.NewRuntime().InstantiateModuleFromCode(source)
	//	defer module.Close()
	//
	// Note: This is a convenience utility that chains CompileModule with InstantiateModule. To instantiate the same
	// source multiple times, use CompileModule as InstantiateModule avoids redundant decoding and/or compilation.
	InstantiateModuleFromCode(source []byte) (api.Module, error)

	// InstantiateModuleFromCodeWithConfig is a convenience function that chains CompileModule to
	// InstantiateModuleWithConfig.
	//
	// Ex. To only change the module name:
	//	wasm, _ := wazero.NewRuntime().InstantiateModuleFromCodeWithConfig(source, wazero.NewModuleConfig().
	//		WithName("wasm")
	//	)
	//	defer wasm.Close()
	InstantiateModuleFromCodeWithConfig(source []byte, config *ModuleConfig) (api.Module, error)

	// InstantiateModule instantiates the module namespace or errs if the configuration was invalid.
	//
	// Ex.
	//	r := wazero.NewRuntime()
	//	code, _ := r.CompileModule(source)
	//	module, _ := r.InstantiateModule(code)
	//	defer module.Close()
	//
	// While CompiledCode is pre-validated, there are a few situations which can cause an error:
	//  * The module name is already in use.
	//  * The module has a table element initializer that resolves to an index outside the Table minimum size.
	//  * The module has a start function, and it failed to execute.
	//
	// Note: The last value of RuntimeConfig.WithContext is used for any start function.
	InstantiateModule(code *CompiledCode) (api.Module, error)

	// InstantiateModuleWithConfig is like InstantiateModule, except you can override configuration such as the module
	// name or ENV variables.
	//
	// For example, you can use this to define different args depending on the importing module.
	//
	//	r := wazero.NewRuntime()
	//	wasi, _ := r.InstantiateModule(wazero.WASISnapshotPreview1())
	//	code, _ := r.CompileModule(source)
	//
	//	// Initialize base configuration:
	//	config := wazero.NewModuleConfig().WithStdout(buf)
	//
	//	// Assign different configuration on each instantiation
	//	module, _ := r.InstantiateModuleWithConfig(code, config.WithName("rotate").WithArgs("rotate", "angle=90", "dir=cw"))
	//
	// Note: Config is copied during instantiation: Later changes to config do not affect the instantiated result.
	InstantiateModuleWithConfig(code *CompiledCode, config *ModuleConfig) (mod api.Module, err error)
}

Runtime allows embedding of WebAssembly 1.0 (20191205) modules.

Ex.

r := wazero.NewRuntime()
code, _ := r.CompileModule(source)
module, _ := r.InstantiateModule(code)
defer module.Close()

See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/

func NewRuntime

func NewRuntime() Runtime

func NewRuntimeWithConfig

func NewRuntimeWithConfig(config *RuntimeConfig) Runtime

NewRuntimeWithConfig returns a runtime with the given configuration.

type RuntimeConfig

type RuntimeConfig struct {
	// contains filtered or unexported fields
}

RuntimeConfig controls runtime behavior, with the default implementation as NewRuntimeConfig

func NewRuntimeConfig

func NewRuntimeConfig() *RuntimeConfig

NewRuntimeConfig returns NewRuntimeConfigJIT

func NewRuntimeConfigInterpreter

func NewRuntimeConfigInterpreter() *RuntimeConfig

NewRuntimeConfigInterpreter interprets WebAssembly modules instead of compiling them into assembly.

func NewRuntimeConfigJIT

func NewRuntimeConfigJIT() *RuntimeConfig

NewRuntimeConfigJIT compiles WebAssembly modules into runtime.GOARCH-specific assembly for optimal performance.

Note: This panics at runtime the runtime.GOOS or runtime.GOARCH does not support JIT. Use NewRuntimeConfig to safely detect and fallback to NewRuntimeConfigInterpreter if needed.

func (*RuntimeConfig) WithContext

func (c *RuntimeConfig) WithContext(ctx context.Context) *RuntimeConfig

WithContext sets the default context used to initialize the module. Defaults to context.Background if nil.

Notes: * If the Module defines a start function, this is used to invoke it. * This is the outer-most ancestor of api.Module Context() during api.Function invocations. * This is the default context of api.Function when callers pass nil.

See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#start-function%E2%91%A0

func (*RuntimeConfig) WithFeatureMutableGlobal

func (c *RuntimeConfig) WithFeatureMutableGlobal(enabled bool) *RuntimeConfig

WithFeatureMutableGlobal allows globals to be mutable. This defaults to true as the feature was finished in WebAssembly 1.0 (20191205).

When false, a api.Global can never be cast to a api.MutableGlobal, and any source that includes global vars will fail to parse.

func (*RuntimeConfig) WithFeatureSignExtensionOps

func (c *RuntimeConfig) WithFeatureSignExtensionOps(enabled bool) *RuntimeConfig

WithFeatureSignExtensionOps enables sign-extend operations. This defaults to false as the feature was not finished in WebAssembly 1.0 (20191205).

See https://github.com/WebAssembly/spec/blob/main/proposals/sign-extension-ops/Overview.md

func (*RuntimeConfig) WithMemoryMaxPages

func (c *RuntimeConfig) WithMemoryMaxPages(memoryMaxPages uint32) *RuntimeConfig

WithMemoryMaxPages reduces the maximum number of pages a module can define from 65536 pages (4GiB) to a lower value.

Notes: * If a module defines no memory max limit, Runtime.CompileModule sets max to this value. * If a module defines a memory max larger than this amount, it will fail to compile (Runtime.CompileModule). * Any "memory.grow" instruction that results in a larger value than this results in an error at runtime. * Zero is a valid value and results in a crash if any module uses memory.

See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#grow-mem See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#memory-types%E2%91%A0

Directories

Path Synopsis
Package api includes constants and interfaces used by both end-users and internal implementations.
Package api includes constants and interfaces used by both end-users and internal implementations.
internal
asm
testing/enginetest
Package enginetest contains tests common to any wasm.Engine implementation.
Package enginetest contains tests common to any wasm.Engine implementation.
u64
wasmdebug
Package wasmdebug contains utilities used to give consistent search keys between stack traces and error messages.
Package wasmdebug contains utilities used to give consistent search keys between stack traces and error messages.
wasmruntime
Package wasmruntime contains internal symbols shared between modules for error handling.
Package wasmruntime contains internal symbols shared between modules for error handling.
wazeroir
Package wazeroir is a pkg to compile down the standard Wasm binary to wazero's specific IR (wazeroir).
Package wazeroir is a pkg to compile down the standard Wasm binary to wazero's specific IR (wazeroir).
Package sys includes constants and types used by both public and internal APIs.
Package sys includes constants and types used by both public and internal APIs.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL