wazero

package module
v1.0.0-beta.2 Latest Latest
Warning

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

Go to latest
Published: Aug 31, 2022 License: Apache-2.0 Imports: 20 Imported by: 417

README

wazero: the zero dependency WebAssembly runtime for Go developers

WebAssembly Core Specification Test Go Reference License

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 Core Specification 1.0 and 2.0 compliant runtime written in Go. It has zero 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

The best way to learn wazero is by trying one of our examples.

For the impatient, here's a peek of a general flow with wazero:

First, you need to compile your code into the WebAssembly Binary Format (Wasm).

Here's source in TinyGo, which exports an "add" function:

package main

//export add
func add(x, y uint32) uint32 {
	return x + y
}

Here's the minimal command to build a %.wasm binary.

tinygo build -o add.wasm -target=wasi add.go

Finally, you can run that inside your Go application.

func main() {
	// Choose the context to use for function calls.
	ctx := context.Background()

	// Read a WebAssembly binary containing an exported "add" function.
	wasm, err := os.ReadFile("./path/to/add.wasm")
	if err != nil {
		log.Panicln(err)
	}

	// Create a new WebAssembly Runtime.
	r := wazero.NewRuntime(ctx)
	defer r.Close(ctx) // This closes everything this Runtime created.

	// Instantiate the module and return its exported functions
	module, err := r.InstantiateModuleFromBinary(ctx, wasm)
	if err != nil {
		log.Panicln(err)
	}

	// Discover 1+2=3
	fmt.Println(module.ExportedFunction("add").Call(ctx, 1, 2))
}

Notes:

  • The embedding application is often called the "host" in WebAssembly.
  • The Wasm binary is often called the "guest" in WebAssembly. Sometimes they need [imports][imports] to implement features such as console output.
  • Many languages compile to (target) Wasm including AssemblyScript, C, C++, Rust, TinyGo and 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.

The WebAssembly Core Specification is a standard, governed by W3C process, but it has no scope to specify how system resources like files are accessed. Instead, WebAssembly defines "host functions" and the signatures they can use. In wazero, "host functions" are written in Go, and let you do anything including access files. The main constraint is that WebAssembly only allows numeric types. wazero includes [imports][imports] for common languages and compiler toolchains.

For example, you can grant WebAssembly code access to your console by exporting a function written in Go. The below function can be imported into standard WebAssembly as the module "env" and the function name "log_i32".

_, err := r.NewModuleBuilder("env").
	ExportFunction("log_i32", func(v uint32) {
		fmt.Println("log_i32 >>", v)
	}).
	Instantiate(ctx, r)
if err != nil {
    log.Panicln(err)
}

The WebAssembly community has subgroups which maintain work that may not result in a Web Standard. One such group is the WebAssembly System Interface (WASI), which defines functions similar to Go's x/sys/unix.

The wasi_snapshot_preview1 tag of WASI is widely implemented, so wazero bundles an implementation. That way, you don't have to write these functions.

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

_, err := wasi_snapshot_preview1.Instantiate(ctx, r)
if err != nil {
    log.Panicln(err)
}

config := wazero.NewModuleConfig().
	WithFS(os.DirFS("/work/home")). // instead of no file system
    WithSysWalltime().WithSysNanotime() // instead of fake time

module, err := r.InstantiateModule(ctx, compiled, config)
...

While we hope this deeper dive was useful, we also provide examples to elaborate each point. Please try these before raising usage questions as they may answer them for you!

Runtime

There are two runtime configurations supported in wazero: Compiler is default:

By default, ex wazero.NewRuntime(ctx), the Compiler is used if supported. You can also force the interpreter like so:

r := wazero.NewRuntimeWithConfig(ctx, wazero.NewRuntimeConfigInterpreter())
Interpreter

Interpreter is 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).

Compiler

Compiler compiles WebAssembly modules into machine code ahead of time (AOT), during Runtime.CompileModule. This means your WebAssembly functions execute natively at runtime. Compiler is faster than Interpreter, often by order of magnitude (10x) or more. This is done without host-specific dependencies.

If interested, check out the RATIONALE.md and help us optimize further!

Conformance

Both runtimes pass WebAssembly Core 1.0 and 2.0 specification tests on supported platforms:

Runtime Usage amd64 arm64 others
Interpreter wazero.NewRuntimeConfigInterpreter()
Compiler wazero.NewRuntimeConfigCompiler()

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.

Wazero 1.0 will have a floor Go version of 1.19. The first beta will be the end of August 2022, and the final release will be after Go 1.20 is released, in February 2023.

Meanwhile, 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 version prior to the latest release of Go.

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

Platform

wazero has two runtime modes: Interpreter and Compiler. 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, as well FreeBSD via Vagrant/VirtualBox.

  • Interpreter
    • Linux is tested on amd64 (native) as well arm64 and riscv64 via emulation.
    • FreeBSD, MacOS and Windows are only tested on amd64.
  • Compiler
    • Linux is tested on amd64 (native) as well arm64 via emulation.
    • FreeBSD, 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 zero dependencies by running tests in Docker's scratch image. This approach ensures compatibility with any parent image.


wazero is a registered trademark of Tetrate.io, Inc. in the United States and/or other countries

Documentation

Overview

Example

This is an example of how to use WebAssembly via adding two numbers.

See https://github.com/tetratelabs/wazero/tree/main/examples for more.

package main

import (
	"context"
	_ "embed"
	"fmt"
	"log"
)

// addWasm was generated by the following:
//
//	cd examples/basic/testdata/testdata; wat2wasm --debug-names add.wat
//
//go:embed examples/basic/testdata/add.wasm
var addWasm []byte

// This is an example of how to use WebAssembly via adding two numbers.
//
// See https://github.com/tetratelabs/wazero/tree/main/examples for more.
func main() {
	// Choose the context to use for function calls.
	ctx := context.Background()

	// Create a new WebAssembly Runtime.
	r := NewRuntime(ctx)

	// Add a module to the runtime named "wasm/math" which exports one function
	// "add", implemented in WebAssembly.
	mod, err := r.InstantiateModuleFromBinary(ctx, addWasm)
	if err != nil {
		log.Panicln(err)
	}
	defer mod.Close(ctx)

	// Get a function that can be reused until its module is closed:
	add := mod.ExportedFunction("add")

	x, y := uint64(1), uint64(2)
	results, err := add.Call(ctx, x, y)
	if err != nil {
		log.Panicln(err)
	}

	fmt.Printf("%s: %d + %d = %d\n", mod.Name(), x, y, results[0])

}
Output:

wasm/math: 1 + 2 = 3

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type CompileConfig

type CompileConfig interface {
	// WithMemorySizer are the allocation parameters used for a Wasm memory.
	// The default is to set cap=min and max=65536 if unset. A nil function is invalid and ignored.
	WithMemorySizer(api.MemorySizer) CompileConfig
}

CompileConfig allows you to override what was decoded from wasm, prior to compilation (ModuleBuilder.Compile or Runtime.CompileModule).

For example, WithMemorySizer allows you to override memoryc size that doesn't match your requirements.

Note: CompileConfig is immutable. Each WithXXX function returns a new instance including the corresponding change.

func NewCompileConfig

func NewCompileConfig() CompileConfig

NewCompileConfig returns a CompileConfig that can be used for configuring module compilation.

type CompiledModule

type CompiledModule interface {
	// Name returns the module name encoded into the binary or empty if not.
	Name() string

	// ImportedFunctions returns all the imported functions
	// (api.FunctionDefinition) in this module or nil if there are none.
	//
	// Note: Unlike ExportedFunctions, there is no unique constraint on
	// imports.
	ImportedFunctions() []api.FunctionDefinition

	// ExportedFunctions returns all the exported functions
	// (api.FunctionDefinition) in this module keyed on export name.
	ExportedFunctions() map[string]api.FunctionDefinition

	// Close releases all the allocated resources for this CompiledModule.
	//
	// Note: It is safe to call Close while having outstanding calls from an
	// api.Module instantiated from this.
	Close(context.Context) error
}

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

In WebAssembly terminology, 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

Note: Closing the wazero.Runtime closes any CompiledModule it compiled.

type ModuleBuilder

type ModuleBuilder interface {

	// ExportFunction adds a function written in Go, which a WebAssembly module can import.
	// If a function is already exported with the same name, this overwrites it.
	//
	// # Parameters
	//
	//   - exportName - The name to export. Ex "random_get"
	//   - goFunc - The `func` to export.
	//   - names - If present, the first is the api.FunctionDefinition name.
	//	  If any follow, they must match the count of goFunc's parameters.
	//
	// Ex.
	//	// Just export the function, and use "abort" in stack traces.
	// 	builder.ExportFunction("abort", env.abort)
	//	// Ensure "~lib/builtins/abort" is used in stack traces.
	//	builder.ExportFunction("abort", env.abort, "~lib/builtins/abort")
	//	// Allow function listeners to know the param names for logging, etc.
	//	builder.ExportFunction("abort", env.abort, "~lib/builtins/abort",
	//		"message", "fileName", "lineNumber", "columnNumber")
	//
	// Valid Signature
	//
	// 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, y 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(ctx context.Context, x, y uint32) uint32 {
	//		// add a little extra if we put some in the context!
	//		return x + y + ctx.Value(extraKey).(uint32)
	//	}
	//
	// Ex. This uses an api.Module to reads the parameters from 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.
	//
	//	addInts := func(ctx context.Context, m api.Module, offset uint32) uint32 {
	//		x, _ := m.Memory().ReadUint32Le(ctx, offset)
	//		y, _ := m.Memory().ReadUint32Le(ctx, offset + 4) // 32 bits == 4 bytes!
	//		return x + y
	//	}
	//
	// If both parameters exist, they must be in order at positions 0 and 1.
	//
	// Ex. This uses propagates context properly when calling other functions
	// exported in the api.Module:
	//	callRead := func(ctx context.Context, m api.Module, offset, byteCount uint32) uint32 {
	//		fn = m.ExportedFunction("__read")
	//		results, err := fn(ctx, offset, byteCount)
	//	--snip--
	//
	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#host-functions%E2%91%A2
	ExportFunction(exportName string, goFunc interface{}, names ...string) 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.
	// If a memory is already exported with the same name, this overwrites it.
	//
	// # Parameters
	//
	//   - name - the name to export. Ex "memory" for wasi_snapshot_preview1.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)
	//
	// # Notes
	//
	//   - This is allowed to grow to (4GiB) limited by api.MemorySizer. To bound it, use ExportMemoryWithMax.
	//   - 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: api.MemorySizer determines the capacity.
	ExportMemoryWithMax(name string, minPages, maxPages uint32) ModuleBuilder

	// ExportGlobalI32 exports a global constant of type api.ValueTypeI32.
	// If a global is already exported with the same name, this overwrites it.
	//
	// 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: 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 and
	// 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.
	// If a global is already exported with the same name, this overwrites it.
	//
	// 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: 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 and
	// 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.
	// If a global is already exported with the same name, this overwrites it.
	//
	// 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)
	//
	// 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.
	// If a global is already exported with the same name, this overwrites it.
	//
	// 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)
	//
	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#syntax-globaltype
	ExportGlobalF64(name string, v float64) ModuleBuilder

	// Compile returns a CompiledModule that can instantiated in any namespace (Namespace).
	//
	// Note: Closing the Namespace has the same effect as closing the result.
	Compile(context.Context, CompileConfig) (CompiledModule, error)

	// Instantiate is a convenience that calls Compile, then Namespace.InstantiateModule.
	//
	// Ex.
	//
	//	ctx := context.Background()
	//	r := wazero.NewRuntime(ctx)
	//	defer r.Close(ctx) // This closes everything this Runtime created.
	//
	//	hello := func() {
	//		fmt.Fprintln(stdout, "hello!")
	//	}
	//	env, _ := r.NewModuleBuilder("env").
	//		ExportFunction("hello", hello).
	//		Instantiate(ctx, r)
	//
	// # Notes
	//
	//   - Closing the Namespace has the same effect as closing the result.
	//   - Fields in the builder are copied during instantiation: Later changes do not affect the instantiated result.
	//   - To avoid using configuration defaults, use Compile instead.
	Instantiate(context.Context, Namespace) (api.Module, error)
}

ModuleBuilder is a way to define a WebAssembly Module in Go.

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

ctx := context.Background()
r := wazero.NewRuntime(ctx)
defer r.Close(ctx) // This closes everything this Runtime created.

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

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

compiled, _ := r.NewModuleBuilder("env").
	ExportFunction("get_random_string", getRandomString).
	Compile(ctx, wazero.NewCompileConfig())

env1, _ := r.InstantiateModule(ctx, compiled, wazero.NewModuleConfig().WithName("env.1"))

env2, _ := r.InstantiateModule(ctx, compiled, wazero.NewModuleConfig().WithName("env.2"))

Notes

  • ModuleBuilder is mutable: each method returns the same instance for chaining.
  • methods do not return errors, to allow chaining. Any validation errors are deferred until Compile.
  • Insertion order is not retained. Anything defined by this builder is sorted lexicographically on Compile.

type ModuleConfig

type ModuleConfig interface {

	// WithArgs assigns command-line arguments visible to an imported function that reads an arg vector (argv). Defaults to
	// none. Runtime.InstantiateModule errs if any arg is empty.
	//
	// 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.
	//
	// See https://linux.die.net/man/3/argv and https://en.wikipedia.org/wiki/Null-terminated_string
	WithArgs(...string) ModuleConfig

	// WithEnv sets an environment variable visible to a Module that imports functions. Defaults to none.
	// Runtime.InstantiateModule errs if the key is empty or contains a NULL(0) or equals("") character.
	//
	// 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.
	//
	// See https://linux.die.net/man/3/environ and https://en.wikipedia.org/wiki/Null-terminated_string
	WithEnv(key, value string) ModuleConfig

	// WithFS assigns the file system to use for any paths beginning at "/".
	// Defaults return fs.ErrNotExist.
	//
	// Ex. This sets a read-only, embedded file-system:
	//
	//	//go:embed testdata/index.html
	//	var testdataIndex embed.FS
	//
	//	rooted, err := fs.Sub(testdataIndex, "testdata")
	//	require.NoError(t, err)
	//
	//	// "index.html" is accessible as "/index.html".
	//	config := wazero.NewModuleConfig().WithFS(rooted)
	//
	// Ex. This sets a mutable file-system:
	//
	//	// Files relative to "/work/appA" are accessible as "/".
	//	config := wazero.NewModuleConfig().WithFS(os.DirFS("/work/appA"))
	//
	// Isolation
	//
	// os.DirFS documentation includes important notes about isolation, which
	// also applies to fs.Sub. As of Go 1.19, the built-in file-systems are not
	// jailed (chroot). See https://github.com/golang/go/issues/42322
	//
	// Working Directory "."
	//
	// Relative path resolution, such as "./config.yml" to "/config.yml" or
	// otherwise, is compiler-specific. See /RATIONALE.md for notes.
	WithFS(fs.FS) ModuleConfig

	// WithName configures the module name. Defaults to what was decoded or overridden via CompileConfig.WithModuleName.
	WithName(string) ModuleConfig

	// WithStartFunctions configures the functions to call after the module is
	// instantiated. Defaults to "_start".
	//
	// # Notes
	//
	//   - If any function doesn't exist, it is skipped. However, all functions
	//	  that do exist are called in order.
	//   - Some start functions may exit the module during instantiate with a
	//	  sys.ExitError (ex. emscripten), preventing use of exported functions.
	WithStartFunctions(...string) 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.
	//
	// # Notes
	//
	//   - The caller is responsible to close any io.Writer they supply: It is not closed on api.Module Close.
	//   - This does not default to os.Stderr as that both violates sandboxing and prevents concurrent modules.
	//
	// See https://linux.die.net/man/3/stderr
	WithStderr(io.Writer) 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.
	//
	// # Notes
	//
	//   - The caller is responsible to close any io.Reader they supply: It is not closed on api.Module Close.
	//   - This does not default to os.Stdin as that both violates sandboxing and prevents concurrent modules.
	//
	// See https://linux.die.net/man/3/stdin
	WithStdin(io.Reader) 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.
	//
	// # Notes
	//
	//   - The caller is responsible to close any io.Writer they supply: It is not closed on api.Module Close.
	//   - This does not default to os.Stdout as that both violates sandboxing and prevents concurrent modules.
	//
	// See https://linux.die.net/man/3/stdout
	WithStdout(io.Writer) ModuleConfig

	// WithWalltime configures the wall clock, sometimes referred to as the
	// real time clock. Defaults to a fake result that increases by 1ms on
	// each reading.
	//
	// Ex. To override with your own clock:
	//	moduleConfig = moduleConfig.
	//		WithWalltime(func(context.Context) (sec int64, nsec int32) {
	//			return clock.walltime()
	//		}, sys.ClockResolution(time.Microsecond.Nanoseconds()))
	//
	// Note: This does not default to time.Now as that violates sandboxing. Use
	// WithSysWalltime for a usable implementation.
	WithWalltime(sys.Walltime, sys.ClockResolution) ModuleConfig

	// WithSysWalltime uses time.Now for sys.Walltime with a resolution of 1us
	// (1000ns).
	//
	// See WithWalltime
	WithSysWalltime() ModuleConfig

	// WithNanotime configures the monotonic clock, used to measure elapsed
	// time in nanoseconds. Defaults to a fake result that increases by 1ms
	// on each reading.
	//
	// Ex. To override with your own clock:
	//	moduleConfig = moduleConfig.
	//		WithNanotime(func(context.Context) int64 {
	//			return clock.nanotime()
	//		}, sys.ClockResolution(time.Microsecond.Nanoseconds()))
	//
	// # Notes:
	//   - This does not default to time.Since as that violates sandboxing.
	//   - Some compilers implement sleep by looping on sys.Nanotime (ex. Go).
	//   - If you set this, you should probably set WithNanosleep also.
	//   - Use WithSysNanotime for a usable implementation.
	WithNanotime(sys.Nanotime, sys.ClockResolution) ModuleConfig

	// WithSysNanotime uses time.Now for sys.Nanotime with a resolution of 1us.
	//
	// See WithNanotime
	WithSysNanotime() ModuleConfig

	// WithNanosleep configures the how to pause the current goroutine for at
	// least the configured nanoseconds. Defaults to return immediately.
	//
	// Ex. To override with your own sleep function:
	//	moduleConfig = moduleConfig.
	//		WithNanosleep(func(ctx context.Context, ns int64) {
	//			rel := unix.NsecToTimespec(ns)
	//			remain := unix.Timespec{}
	//			for { // loop until no more time remaining
	//				err := unix.ClockNanosleep(unix.CLOCK_MONOTONIC, 0, &rel, &remain)
	//			--snip--
	//
	// # Notes:
	//   - This primarily supports `poll_oneoff` for relative clock events.
	//   - This does not default to time.Sleep as that violates sandboxing.
	//   - Some compilers implement sleep by looping on sys.Nanotime (ex. Go).
	//   - If you set this, you should probably set WithNanotime also.
	//   - Use WithSysNanosleep for a usable implementation.
	WithNanosleep(sys.Nanosleep) ModuleConfig

	// WithSysNanosleep uses time.Sleep for sys.Nanosleep.
	//
	// See WithNanosleep
	WithSysNanosleep() ModuleConfig

	// WithRandSource configures a source of random bytes. Defaults to return a
	// deterministic source. You might override this with crypto/rand.Reader
	//
	// This reader is most commonly used by the functions like "random_get" in
	// "wasi_snapshot_preview1", "seed" in AssemblyScript standard "env", and
	// "getRandomData" when runtime.GOOS is "js".
	//
	// Note: The caller is responsible to close any io.Reader they supply: It
	// is not closed on api.Module Close.
	WithRandSource(io.Reader) ModuleConfig
}

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, so that the same module can be safely instantiated multiple times.

Ex.

// Initialize base configuration:
config := wazero.NewModuleConfig().WithStdout(buf).WithSysNanotime()

// Assign different configuration on each instantiation
module, _ := r.InstantiateModule(ctx, compiled, config.WithName("rotate").WithArgs("rotate", "angle=90", "dir=cw"))

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).

Note: ModuleConfig is immutable. Each WithXXX function returns a new instance including the corresponding change.

func NewModuleConfig

func NewModuleConfig() ModuleConfig

NewModuleConfig returns a ModuleConfig that can be used for configuring module instantiation.

type Namespace

type Namespace interface {
	// Module returns exports from an instantiated module in this namespace or nil if there aren't any.
	Module(moduleName string) api.Module

	// InstantiateModule instantiates the module namespace or errs if the configuration was invalid.
	//
	// Ex.
	//	module, _ := n.InstantiateModule(ctx, compiled, wazero.NewModuleConfig().WithName("prod"))
	//
	// While CompiledModule 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.
	InstantiateModule(ctx context.Context, compiled CompiledModule, config ModuleConfig) (api.Module, error)

	// CloseWithExitCode closes all modules initialized in this Namespace with the provided exit code.
	// An error is returned if any module returns an error when closed.
	//
	// Ex.
	//	n := r.NewNamespace(ctx)
	//	defer n.CloseWithExitCode(ctx, 2) // This closes all modules in this Namespace.
	//
	//	Everything below here can be closed, but will anyway due to above.
	//	_, _ = wasi_snapshot_preview1.InstantiateSnapshotPreview1(ctx, n)
	//	mod, _ := n.InstantiateModuleFromBinary(ctx, wasm)
	//
	// See Closer
	CloseWithExitCode(ctx context.Context, exitCode uint32) error

	// Closer closes modules initialized in this Namespace by delegating to CloseWithExitCode with an exit code of zero.
	//
	// Ex.
	//	n := r.NewNamespace(ctx)
	//	defer n.Close(ctx) // This closes all modules in this Namespace.
	api.Closer
}

Namespace contains instantiated modules, which cannot conflict until they are closed.

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:
	//
	//	ctx := context.Background()
	//	hello := func() {
	//		fmt.Fprintln(stdout, "hello!")
	//	}
	//	_, err := r.NewModuleBuilder("env").ExportFunction("hello", hello).Instantiate(ctx, r)
	NewModuleBuilder(moduleName string) ModuleBuilder

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

	// InstantiateModuleFromBinary instantiates a module from the WebAssembly binary (%.wasm) or errs if invalid.
	//
	// Ex.
	//	ctx := context.Background()
	//	r := wazero.NewRuntime(ctx)
	//	defer r.Close(ctx) // This closes everything this Runtime created.
	//
	//	module, _ := r.InstantiateModuleFromBinary(ctx, wasm)
	//
	// # Notes
	//
	//   - 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.
	//   - To avoid using configuration defaults, use InstantiateModule instead.
	InstantiateModuleFromBinary(ctx context.Context, source []byte) (api.Module, error)

	// Namespace is the default namespace of this runtime, and is embedded for convenience. Most users will only use the
	// default namespace.
	//
	// Advanced use cases can use NewNamespace to redefine modules of the same name. For example, to allow different
	// modules to define their own stateful "env" module.
	Namespace

	// NewNamespace creates an empty namespace which won't conflict with any other namespace including the default.
	// This is more efficient than multiple runtimes, as namespaces share a compiler cache.
	//
	// In simplest case, a namespace won't conflict if another has a module with the same name:
	//	b := assemblyscript.NewBuilder(r)
	//	m1, _ := b.InstantiateModule(ctx, r.NewNamespace(ctx))
	//	m2, _ := b.InstantiateModule(ctx, r.NewNamespace(ctx))
	//
	// This is also useful for different modules that import the same module name (like "env"), but need different
	// configuration or state. For example, one with trace logging enabled and another disabled:
	//	b := assemblyscript.NewBuilder(r)
	//
	//	// m1 has trace logging disabled
	//	ns1 := r.NewNamespace(ctx)
	//	_ = b.InstantiateModule(ctx, ns1)
	//	m1, _ := ns1.InstantiateModule(ctx, compiled, config)
	//
	//	// m2 has trace logging enabled
	//	ns2 := r.NewNamespace(ctx)
	//	_ = b.WithTraceToStdout().InstantiateModule(ctx, ns2)
	//	m2, _ := ns2.InstantiateModule(ctx, compiled, config)
	//
	// # Notes
	//
	//   - The returned namespace does not inherit any modules from the runtime default namespace.
	//   - Closing the returned namespace closes any modules in it.
	//   - Closing this runtime also closes the namespace returned from this function.
	NewNamespace(context.Context) Namespace

	// CloseWithExitCode closes all the modules that have been initialized in this Runtime with the provided exit code.
	// An error is returned if any module returns an error when closed.
	//
	// Ex.
	//	ctx := context.Background()
	//	r := wazero.NewRuntime(ctx)
	//	defer r.CloseWithExitCode(ctx, 2) // This closes everything this Runtime created.
	//
	//	// Everything below here can be closed, but will anyway due to above.
	//	_, _ = wasi_snapshot_preview1.InstantiateSnapshotPreview1(ctx, r)
	//	mod, _ := r.InstantiateModuleFromBinary(ctx, wasm)
	CloseWithExitCode(ctx context.Context, exitCode uint32) error

	// Closer closes all namespace and compiled code by delegating to CloseWithExitCode with an exit code of zero.
	api.Closer
}

Runtime allows embedding of WebAssembly modules.

Ex. The below is the basic initialization of wazero's WebAssembly Runtime.

ctx := context.Background()
r := wazero.NewRuntime(ctx)
defer r.Close(ctx) // This closes everything this Runtime created.

module, _ := r.InstantiateModuleFromBinary(ctx, wasm)

func NewRuntime

func NewRuntime(ctx context.Context) Runtime

NewRuntime returns a runtime with a configuration assigned by NewRuntimeConfig.

func NewRuntimeWithConfig

func NewRuntimeWithConfig(ctx context.Context, rConfig RuntimeConfig) Runtime

NewRuntimeWithConfig returns a runtime with the given configuration.

type RuntimeConfig

type RuntimeConfig interface {

	// WithFeatureBulkMemoryOperations adds instructions modify ranges of memory or table entries
	// ("bulk-memory-operations"). This defaults to false as the feature was not finished in WebAssembly 1.0.
	//
	// Here are the notable effects:
	//   - Adds `memory.fill`, `memory.init`, `memory.copy` and `data.drop` instructions.
	//   - Adds `table.init`, `table.copy` and `elem.drop` instructions.
	//   - Introduces a "passive" form of element and data segments.
	//   - Stops checking "active" element and data segment boundaries at compile-time, meaning they can error at runtime.
	//
	// Note: "bulk-memory-operations" is mixed with the "reference-types" proposal
	// due to the WebAssembly Working Group merging them "mutually dependent".
	// Therefore, enabling this feature results in enabling WithFeatureReferenceTypes, and vice-versa.
	//
	// See https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/bulk-memory-operations/Overview.md
	// https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/reference-types/Overview.md and
	// https://github.com/WebAssembly/spec/pull/1287
	WithFeatureBulkMemoryOperations(bool) RuntimeConfig

	// WithFeatureMultiValue enables multiple values ("multi-value"). This defaults to false as the feature was not
	// finished in WebAssembly 1.0 (20191205).
	//
	// Here are the notable effects:
	//   - Function (`func`) types allow more than one result
	//   - Block types (`block`, `loop` and `if`) can be arbitrary function types
	//
	// See https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/multi-value/Overview.md
	WithFeatureMultiValue(bool) RuntimeConfig

	// WithFeatureMutableGlobal allows globals to be mutable. This defaults to true as the feature was finished in
	// WebAssembly 1.0 (20191205).
	//
	// When false, an api.Global can never be cast to an api.MutableGlobal, and any wasm that includes global vars
	// will fail to parse.
	WithFeatureMutableGlobal(bool) RuntimeConfig

	// WithFeatureNonTrappingFloatToIntConversion enables non-trapping float-to-int conversions.
	// ("nontrapping-float-to-int-conversion"). This defaults to false as the feature was not in WebAssembly 1.0.
	//
	// The only effect of enabling is allowing the following instructions, which return 0 on NaN instead of panicking.
	//   - `i32.trunc_sat_f32_s`
	//   - `i32.trunc_sat_f32_u`
	//   - `i32.trunc_sat_f64_s`
	//   - `i32.trunc_sat_f64_u`
	//   - `i64.trunc_sat_f32_s`
	//   - `i64.trunc_sat_f32_u`
	//   - `i64.trunc_sat_f64_s`
	//   - `i64.trunc_sat_f64_u`
	//
	// See https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/nontrapping-float-to-int-conversion/Overview.md
	WithFeatureNonTrappingFloatToIntConversion(bool) RuntimeConfig

	// WithFeatureReferenceTypes enables various instructions and features related to table and new reference types.
	//
	//   - Introduction of new value types: `funcref` and `externref`.
	//   - Support for the following new instructions:
	//	 * `ref.null`
	//	 * `ref.func`
	//	 * `ref.is_null`
	//	 * `table.fill`
	//	 * `table.get`
	//	 * `table.grow`
	//	 * `table.set`
	//	 * `table.size`
	//   - Support for multiple tables per module:
	//	 * `call_indirect`, `table.init`, `table.copy` and `elem.drop` instructions can take non-zero table index.
	//	 * Element segments can take non-zero table index.
	//
	// Note: "reference-types" is mixed with the "bulk-memory-operations" proposal
	// due to the WebAssembly Working Group merging them "mutually dependent".
	// Therefore, enabling this feature results in enabling WithFeatureBulkMemoryOperations, and vice-versa.
	//
	// See https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/bulk-memory-operations/Overview.md
	// https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/reference-types/Overview.md and
	// https://github.com/WebAssembly/spec/pull/1287
	WithFeatureReferenceTypes(enabled bool) RuntimeConfig

	// WithFeatureSignExtensionOps enables sign extension instructions ("sign-extension-ops"). This defaults to false
	// as the feature was not in WebAssembly 1.0.
	//
	// Here are the notable effects:
	//   - Adds instructions `i32.extend8_s`, `i32.extend16_s`, `i64.extend8_s`, `i64.extend16_s` and `i64.extend32_s`
	//
	// See https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/sign-extension-ops/Overview.md
	WithFeatureSignExtensionOps(bool) RuntimeConfig

	// WithFeatureSIMD enables the vector value type and vector instructions (aka SIMD). This defaults to false
	// as the feature was not in WebAssembly 1.0.
	//
	// See https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/simd/SIMD.md
	WithFeatureSIMD(bool) RuntimeConfig

	// WithWasmCore1 enables features included in the WebAssembly Core Specification 1.0. Selecting this
	// overwrites any currently accumulated features with only those included in this W3C recommendation.
	//
	// This is default because as of mid 2022, this is the only version that is a Web Standard (W3C Recommendation).
	//
	// You can select the latest draft of the WebAssembly Core Specification 2.0 instead via WithWasmCore2. You can
	// also enable or disable individual features via `WithXXX` methods. Ex.
	//	rConfig = wazero.NewRuntimeConfig().WithWasmCore1().WithFeatureMutableGlobal(false)
	//
	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/
	WithWasmCore1() RuntimeConfig

	// WithWasmCore2 enables features included in the WebAssembly Core Specification 2.0 (20220419). Selecting this
	// overwrites any currently accumulated features with only those included in this W3C working draft.
	//
	// This is not default because it is not yet incomplete and also not yet a Web Standard (W3C Recommendation).
	//
	// Even after selecting this, you can enable or disable individual features via `WithXXX` methods. Ex.
	//	rConfig = wazero.NewRuntimeConfig().WithWasmCore2().WithFeatureMutableGlobal(false)
	//
	// See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/
	WithWasmCore2() RuntimeConfig
}

RuntimeConfig controls runtime behavior, with the default implementation as NewRuntimeConfig

Ex. To explicitly limit to Wasm Core 1.0 features as opposed to relying on defaults:

rConfig = wazero.NewRuntimeConfig().WithWasmCore1()

Note: RuntimeConfig is immutable. Each WithXXX function returns a new instance including the corresponding change.

func NewRuntimeConfig

func NewRuntimeConfig() RuntimeConfig

NewRuntimeConfig returns a RuntimeConfig using the compiler if it is supported in this environment, or the interpreter otherwise.

func NewRuntimeConfigCompiler

func NewRuntimeConfigCompiler() RuntimeConfig

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

The default implementation is AOT (Ahead of Time) compilation, applied at Runtime.CompileModule. This allows consistent runtime performance, as well the ability to reduce any first request penalty.

Note: While this is technically AOT, this does not imply any action on your part. wazero automatically performs ahead-of-time compilation as needed when Runtime.CompileModule is invoked.

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

func NewRuntimeConfigInterpreter

func NewRuntimeConfigInterpreter() RuntimeConfig

NewRuntimeConfigInterpreter interprets WebAssembly modules instead of compiling them into assembly.

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.
cmd
wazero Module
examples
Package experimental includes features we aren't yet sure about.
Package experimental includes features we aren't yet sure about.
imports
assemblyscript
Package assemblyscript contains Go-defined special functions imported by AssemblyScript under the module name "env".
Package assemblyscript contains Go-defined special functions imported by AssemblyScript under the module name "env".
emscripten
Package emscripten contains Go-defined special functions imported by Emscripten under the module name "env".
Package emscripten contains Go-defined special functions imported by Emscripten under the module name "env".
go
Package gojs allows you to run wasm binaries compiled by Go when `GOOS=js` and `GOARCH=wasm`.
Package gojs allows you to run wasm binaries compiled by Go when `GOOS=js` and `GOARCH=wasm`.
wasi_snapshot_preview1
Package wasi_snapshot_preview1 contains Go-defined functions to access system calls, such as opening a file, similar to Go's x/sys package.
Package wasi_snapshot_preview1 contains Go-defined functions to access system calls, such as opening a file, similar to Go's x/sys package.
internal
asm
platform
Package platform includes runtime-specific code needed for the compiler or otherwise.
Package platform includes runtime-specific code needed for the compiler or otherwise.
sys
testing/enginetest
Package enginetest contains tests common to any wasm.Engine implementation.
Package enginetest contains tests common to any wasm.Engine implementation.
testing/require
Package require includes test assertions that fail the test immediately.
Package require includes test assertions that fail the test immediately.
u32
u64
wasi_snapshot_preview1
Package wasi_snapshot_preview1 is an internal helper to remove package cycles re-using errno
Package wasi_snapshot_preview1 is an internal helper to remove package cycles re-using errno
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