Code Examples
package main
import (
"context"
_ "embed"
"fmt"
"log"
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
)
// addWasm was generated by the following:
//
// cd examples/basic/testdata; tinygo build -o add.wasm -target=wasi add.go
//
//go:embed examples/basic/testdata/add.wasm
var addWasm []byte
// This is an example of how to extend a Go application with an addition
// function defined in WebAssembly.
//
// Since addWasm was compiled with TinyGo's `wasi` target, we need to configure
// WASI host imports.
//
// A complete project that does the same as this is available here:
// https://github.com/tetratelabs/wazero/tree/main/examples/basic
func main() {
// Choose the context to use for function calls.
ctx := context.Background()
// Create a new WebAssembly Runtime.
r := wazero.NewRuntime(ctx)
defer r.Close(ctx) // This closes everything this Runtime created.
// Instantiate WASI, which implements host functions needed for TinyGo to
// implement `panic`.
wasi_snapshot_preview1.MustInstantiate(ctx, r)
// Instantiate the guest Wasm into the same runtime. It exports the `add`
// function, implemented in WebAssembly.
mod, err := r.InstantiateWithConfig(ctx, addWasm, wazero.NewModuleConfig().WithStartFunctions("_initialize"))
if err != nil {
log.Panicln(err)
}
// Call the `add` function and print the results to the console.
x, y := uint64(1), uint64(2)
results, err := mod.ExportedFunction("add").Call(ctx, x, y)
if err != nil {
log.Panicln(err)
}
fmt.Printf("%d + %d = %d\n", x, y, results[0])
}
Package-Level Type Names (total 8)
/* sort by: | */
CompilationCache reduces time spent compiling (Runtime.CompileModule) the same wasm module.
# Notes
- This is an interface for decoupling, not third-party implementations.
All implementations are in wazero.
- Instances of this can be reused across multiple runtimes, if configured
via RuntimeConfig.
- The cache check happens before the compilation, so if multiple Goroutines are
trying to compile the same module simultaneously, it is possible that they
all compile the module. The design here is that the lock isn't held for the action "Compile"
but only for checking and saving the compiled result. Therefore, we strongly recommend that the embedder
does the centralized compilation in a single Goroutines (or multiple Goroutines per Wasm binary) to generate cache rather than
trying to Compile in parallel for a single module. In other words, we always recommend to produce CompiledModule
share it across multiple Goroutines to avoid trying to compile the same module simultaneously. Close closes the resource.
Note: The context parameter is used for value lookup, such as for
logging. A canceled or otherwise done context will not prevent Close
from succeeding.CompiledModule(interface)Runtime(interface)
github.com/tetratelabs/wazero/api.Closer(interface)
github.com/tetratelabs/wazero/api.Module(interface)
github.com/tetratelabs/wazero/experimental.InternalModule(interface)
*github.com/tetratelabs/wazero/internal/wasm.ModuleInstance
github.com/polarsignals/iceberg-go/table.SnapshotWriter(interface)
*github.com/redis/go-redis/v9.Tx
CompilationCache : github.com/tetratelabs/wazero/api.Closer
func NewCompilationCache() CompilationCache
func NewCompilationCacheWithDir(dirname string) (CompilationCache, error)
func RuntimeConfig.WithCompilationCache(CompilationCache) RuntimeConfig
CompiledModule is a WebAssembly 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
# Notes
- This is an interface for decoupling, not third-party implementations.
All implementations are in wazero.
- Closing the wazero.Runtime closes any CompiledModule it compiled. 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. CustomSections returns all the custom sections
(api.CustomSection) in this module keyed on the section name. ExportedFunctions returns all the exported functions
(api.FunctionDefinition) in this module keyed on export name. ExportedMemories returns all the exported memories
(api.MemoryDefinition) in this module keyed on export name.
Note: As of WebAssembly Core Specification 2.0, there can be at most one
memory. 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. ImportedMemories returns all the imported memories
(api.MemoryDefinition) in this module or nil if there are none.
## Notes
- As of WebAssembly Core Specification 2.0, there can be at most one
memory.
- Unlike ExportedMemories, there is no unique constraint on imports. Name returns the module name encoded into the binary or empty if not.
CompiledModule : CompilationCache
CompiledModule : github.com/tetratelabs/wazero/api.Closer
CompiledModule : github.com/polarsignals/frostdb/query/logicalplan.Named
func HostModuleBuilder.Compile(context.Context) (CompiledModule, error)
func Runtime.CompileModule(ctx context.Context, binary []byte) (CompiledModule, error)
func Runtime.InstantiateModule(ctx context.Context, compiled CompiledModule, config ModuleConfig) (api.Module, error)
FSConfig configures filesystem paths the embedding host allows the wasm
guest to access. Unconfigured paths are not allowed, so functions like
`path_open` result in unsupported errors (e.g. syscall.ENOSYS).
# Guest Path
`guestPath` is the name of the path the guest should use a filesystem for, or
empty for any files.
All `guestPath` paths are normalized, specifically removing any leading or
trailing slashes. This means "/", "./" or "." all coerce to empty "".
Multiple `guestPath` values can be configured, but the last longest match
wins. For example, if "tmp", then "" were added, a request to open
"tmp/foo.txt" use the filesystem associated with "tmp" even though a wider
path, "" (all files), was added later.
A `guestPath` of "." coerces to the empty string "" because the current
directory is handled by the guest. In other words, the guest resolves ites
current directory prior to requesting files.
More notes on `guestPath`
- Working directories are typically tracked in wasm, though possible some
relative paths are requested. For example, TinyGo may attempt to resolve
a path "../.." in unit tests.
- Zig uses the first path name it sees as the initial working directory of
the process.
# Scope
Configuration here is module instance scoped. This means you can use the
same configuration for multiple calls to Runtime.InstantiateModule. Each
module will have a different file descriptor table. Any errors accessing
resources allowed here are deferred to instantiation time of each module.
Any host resources present at the time of configuration, but deleted before
Runtime.InstantiateModule will trap/panic when the guest wasm initializes or
calls functions like `fd_read`.
# Windows
While wazero supports Windows as a platform, all known compilers use POSIX
conventions at runtime. For example, even when running on Windows, paths
used by wasm are separated by forward slash (/), not backslash (\).
# Notes
- This is an interface for decoupling, not third-party implementations.
All implementations are in wazero.
- FSConfig is immutable. Each WithXXX function returns a new instance
including the corresponding change.
- RATIONALE.md includes design background and relationship to WebAssembly
System Interfaces (WASI). WithDirMount assigns a directory at `dir` to any paths beginning at
`guestPath`.
For example, `dirPath` as / (or c:\ in Windows), makes the entire host
volume writeable to the path on the guest. The `guestPath` is always a
POSIX style path, slash (/) delimited, even if run on Windows.
If the same `guestPath` was assigned before, this overrides its value,
retaining the original precedence. See the documentation of FSConfig for
more details on `guestPath`.
# Isolation
The guest will have full access to this directory including escaping it
via relative path lookups like "../../". Full access includes operations
such as creating or deleting files, limited to any host level access
controls.
# os.DirFS
This configuration optimizes for WASI compatibility which is sometimes
at odds with the behavior of os.DirFS. Hence, this will not behave
exactly the same as os.DirFS. See /RATIONALE.md for more. WithFSMount assigns a fs.FS file system for any paths beginning at
`guestPath`.
If the same `guestPath` was assigned before, this overrides its value,
retaining the original precedence. See the documentation of FSConfig for
more details on `guestPath`.
# Isolation
fs.FS does not restrict the ability to overwrite returned files via
io.Writer. Moreover, 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
# os.DirFS
Due to limited control and functionality available in os.DirFS, we
advise using WithDirMount instead. There will be behavior differences
between os.DirFS and WithDirMount, as the latter biases towards what's
expected from WASI implementations.
# Custom fs.FileInfo
The underlying implementation supports data not usually in fs.FileInfo
when `info.Sys` returns *sys.Stat_t. For example, a custom fs.FS can use
this approach to generate or mask sys.Inode data. Such a filesystem
needs to decorate any functions that can return fs.FileInfo:
- `Stat` as defined on `fs.File` (always)
- `Readdir` as defined on `os.File` (if defined)
See sys.NewStat_t for examples. WithReadOnlyDirMount assigns a directory at `dir` to any paths
beginning at `guestPath`.
This is the same as WithDirMount except only read operations are
permitted. However, escaping the directory via relative path lookups
like "../../" is still allowed.
func NewFSConfig() FSConfig
func FSConfig.WithDirMount(dir, guestPath string) FSConfig
func FSConfig.WithFSMount(fs fs.FS, guestPath string) FSConfig
func FSConfig.WithReadOnlyDirMount(dir, guestPath string) FSConfig
func ModuleConfig.WithFSConfig(FSConfig) ModuleConfig
HostFunctionBuilder defines a host function (in Go), so that a
WebAssembly binary (e.g. %.wasm file) can import and use it.
Here's an example of an addition function:
hostModuleBuilder.NewFunctionBuilder().
WithFunc(func(cxt context.Context, x, y uint32) uint32 {
return x + y
}).
Export("add")
# Memory
All host functions act on the importing api.Module, including any memory
exported in its binary (%.wasm file). If you are reading or writing memory,
it is sand-boxed Wasm memory defined by the guest.
Below, `m` is the importing module, defined in Wasm. `fn` is a host function
added via Export. This means that `x` was read from memory defined in Wasm,
not arbitrary memory in the process.
fn := func(ctx context.Context, m api.Module, offset uint32) uint32 {
x, _ := m.Memory().ReadUint32Le(ctx, offset)
return x
}
# Notes
- This is an interface for decoupling, not third-party implementations.
All implementations are in wazero. Export exports this to the HostModuleBuilder as the given name, e.g.
"random_get" WithFunc uses reflect.Value to map a go `func` to a WebAssembly
compatible Signature. An input that isn't a `func` will fail to
instantiate.
Here's an example of an addition function:
builder.WithFunc(func(cxt context.Context, x, y uint32) uint32 {
return x + y
})
# Defining a function
Except for the context.Context and optional api.Module, all parameters
or result types must map to WebAssembly numeric value types. This means
uint32, int32, uint64, int64, float32 or float64.
api.Module may be specified as the second parameter, usually to access
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.
builder.WithFunc(func(ctx context.Context, m api.Module, offset uint32) uint32 {
mem := m.Memory()
x, _ := mem.ReadUint32Le(ctx, offset)
y, _ := mem.ReadUint32Le(ctx, offset + 4) // 32 bits == 4 bytes!
return x + y
})
This example propagates context properly when calling other functions
exported in the api.Module:
builder.WithFunc(func(ctx context.Context, m api.Module, offset, byteCount uint32) uint32 {
fn = m.ExportedFunction("__read")
results, err := fn(ctx, offset, byteCount)
--snip-- WithGoFunction is an advanced feature for those who need higher
performance than WithFunc at the cost of more complexity.
Here's an example addition function:
builder.WithGoFunction(api.GoFunc(func(ctx context.Context, stack []uint64) {
x, y := api.DecodeI32(stack[0]), api.DecodeI32(stack[1])
sum := x + y
stack[0] = api.EncodeI32(sum)
}), []api.ValueType{api.ValueTypeI32, api.ValueTypeI32}, []api.ValueType{api.ValueTypeI32})
As you can see above, defining in this way implies knowledge of which
WebAssembly api.ValueType is appropriate for each parameter and result.
See WithGoModuleFunction if you also need to access the calling module. WithGoModuleFunction is an advanced feature for those who need higher
performance than WithFunc at the cost of more complexity.
Here's an example addition function that loads operands from memory:
builder.WithGoModuleFunction(api.GoModuleFunc(func(ctx context.Context, m api.Module, stack []uint64) {
mem := m.Memory()
offset := api.DecodeU32(stack[0])
x, _ := mem.ReadUint32Le(ctx, offset)
y, _ := mem.ReadUint32Le(ctx, offset + 4) // 32 bits == 4 bytes!
sum := x + y
stack[0] = api.EncodeU32(sum)
}), []api.ValueType{api.ValueTypeI32}, []api.ValueType{api.ValueTypeI32})
As you can see above, defining in this way implies knowledge of which
WebAssembly api.ValueType is appropriate for each parameter and result.
See WithGoFunction if you don't need access to the calling module. WithName defines the optional module-local name of this function, e.g.
"random_get"
Note: This is not required to match the Export name. WithParameterNames defines optional parameter names of the function
signature, e.x. "buf", "buf_len"
Note: When defined, names must be provided for all parameters. WithResultNames defines optional result names of the function
signature, e.x. "errno"
Note: When defined, names must be provided for all results.
func HostFunctionBuilder.WithFunc(interface{}) HostFunctionBuilder
func HostFunctionBuilder.WithGoFunction(fn api.GoFunction, params, results []api.ValueType) HostFunctionBuilder
func HostFunctionBuilder.WithGoModuleFunction(fn api.GoModuleFunction, params, results []api.ValueType) HostFunctionBuilder
func HostFunctionBuilder.WithName(name string) HostFunctionBuilder
func HostFunctionBuilder.WithParameterNames(names ...string) HostFunctionBuilder
func HostFunctionBuilder.WithResultNames(names ...string) HostFunctionBuilder
func HostModuleBuilder.NewFunctionBuilder() HostFunctionBuilder
HostModuleBuilder is a way to define host functions (in Go), so that a
WebAssembly binary (e.g. %.wasm file) can import and use them.
Specifically, this implements the host side of an Application Binary
Interface (ABI) like WASI or AssemblyScript.
For example, this 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() {
println("hello!")
}
env, _ := r.NewHostModuleBuilder("env").
NewFunctionBuilder().WithFunc(hello).Export("hello").
Instantiate(ctx)
If the same module may be instantiated multiple times, it is more efficient
to separate steps. Here's an example:
compiled, _ := r.NewHostModuleBuilder("env").
NewFunctionBuilder().WithFunc(getRandomString).Export("get_random_string").
Compile(ctx)
env1, _ := r.InstantiateModule(ctx, compiled, wazero.NewModuleConfig().WithName("env.1"))
env2, _ := r.InstantiateModule(ctx, compiled, wazero.NewModuleConfig().WithName("env.2"))
See HostFunctionBuilder for valid host function signatures and other details.
# Notes
- This is an interface for decoupling, not third-party implementations.
All implementations are in wazero.
- HostModuleBuilder 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.
- Functions are indexed in order of calls to NewFunctionBuilder as
insertion ordering is needed by ABI such as Emscripten (invoke_*).
- The semantics of host functions assumes the existence of an "importing module" because, for example, the host function needs access to
the memory of the importing module. Therefore, direct use of ExportedFunction is forbidden for host modules.
Practically speaking, it is usually meaningless to directly call a host function from Go code as it is already somewhere in Go code. Compile returns a CompiledModule that can be instantiated by Runtime. Instantiate is a convenience that calls Compile, then Runtime.InstantiateModule.
This can fail for reasons documented on Runtime.InstantiateModule.
Here's an example:
ctx := context.Background()
r := wazero.NewRuntime(ctx)
defer r.Close(ctx) // This closes everything this Runtime created.
hello := func() {
println("hello!")
}
env, _ := r.NewHostModuleBuilder("env").
NewFunctionBuilder().WithFunc(hello).Export("hello").
Instantiate(ctx)
# Notes
- Closing the Runtime 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. NewFunctionBuilder begins the definition of a host function.
func HostFunctionBuilder.Export(name string) HostModuleBuilder
func Runtime.NewHostModuleBuilder(moduleName string) HostModuleBuilder
func github.com/ncruces/go-sqlite3/vfs.ExportHostFunctions(env HostModuleBuilder) HostModuleBuilder
func github.com/ncruces/go-sqlite3/internal/util.ExportFuncII[TR, T0](mod HostModuleBuilder, name string, fn func(context.Context, api.Module, T0) TR)
func github.com/ncruces/go-sqlite3/internal/util.ExportFuncIII[TR, T0, T1](mod HostModuleBuilder, name string, fn func(context.Context, api.Module, T0, T1) TR)
func github.com/ncruces/go-sqlite3/internal/util.ExportFuncIIII[TR, T0, T1, T2](mod HostModuleBuilder, name string, fn func(context.Context, api.Module, T0, T1, T2) TR)
func github.com/ncruces/go-sqlite3/internal/util.ExportFuncIIIII[TR, T0, T1, T2, T3](mod HostModuleBuilder, name string, fn func(context.Context, api.Module, T0, T1, T2, T3) TR)
func github.com/ncruces/go-sqlite3/internal/util.ExportFuncIIIIII[TR, T0, T1, T2, T3, T4](mod HostModuleBuilder, name string, fn func(context.Context, api.Module, T0, T1, T2, T3, T4) TR)
func github.com/ncruces/go-sqlite3/internal/util.ExportFuncIIIIIII[TR, T0, T1, T2, T3, T4, T5](mod HostModuleBuilder, name string, fn func(context.Context, api.Module, T0, T1, T2, T3, T4, T5) TR)
func github.com/ncruces/go-sqlite3/internal/util.ExportFuncIIIIJ[TR, T0, T1, T2, T3](mod HostModuleBuilder, name string, fn func(context.Context, api.Module, T0, T1, T2, T3) TR)
func github.com/ncruces/go-sqlite3/internal/util.ExportFuncIIJ[TR, T0, T1](mod HostModuleBuilder, name string, fn func(context.Context, api.Module, T0, T1) TR)
func github.com/ncruces/go-sqlite3/internal/util.ExportFuncVI[T0](mod HostModuleBuilder, name string, fn func(context.Context, api.Module, T0))
func github.com/ncruces/go-sqlite3/internal/util.ExportFuncVIII[T0, T1, T2](mod HostModuleBuilder, name string, fn func(context.Context, api.Module, T0, T1, T2))
func github.com/ncruces/go-sqlite3/internal/util.ExportFuncVIIII[T0, T1, T2, T3](mod HostModuleBuilder, name string, fn func(context.Context, api.Module, T0, T1, T2, T3))
func github.com/ncruces/go-sqlite3/internal/util.ExportFuncVIIIII[T0, T1, T2, T3, T4](mod HostModuleBuilder, name string, fn func(context.Context, api.Module, T0, T1, T2, T3, T4))
func github.com/ncruces/go-sqlite3/internal/util.ExportFuncVIIIIJ[T0, T1, T2, T3, T4](mod HostModuleBuilder, name string, fn func(context.Context, api.Module, T0, T1, T2, T3, T4))
func github.com/ncruces/go-sqlite3/vfs.ExportHostFunctions(env HostModuleBuilder) HostModuleBuilder
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.
Here's an example:
// Initialize base configuration:
config := wazero.NewModuleConfig().WithStdout(buf).WithSysNanotime()
// Assign different configuration on each instantiation
mod, _ := 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).
# Notes
- This is an interface for decoupling, not third-party implementations.
All implementations are in wazero.
- ModuleConfig is immutable. Each WithXXX function returns a new instance
including the corresponding change. 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 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 WithFS is a convenience that calls WithFSConfig with an FSConfig of the
input for the root ("/") guest path. WithFSConfig configures the filesystem available to each guest
instantiated with this configuration. By default, no file access is
allowed, so functions like `path_open` result in unsupported errors
(e.g. syscall.ENOSYS). WithName configures the module name. Defaults to what was decoded from
the name section. Duplicate names are not allowed in a single Runtime.
Calling this with the empty string "" makes the module anonymous.
That is useful when you want to instantiate the same CompiledModule multiple times like below:
for i := 0; i < N; i++ {
// Instantiate a new Wasm module from the already compiled `compiledWasm` anonymously without a name.
instance, err := r.InstantiateModule(ctx, compiledWasm, wazero.NewModuleConfig().WithName(""))
// ....
}
See the `concurrent-instantiation` example for a complete usage.
Non-empty named modules are available for other modules to import by name. WithNanosleep configures the how to pause the current goroutine for at
least the configured nanoseconds. Defaults to return immediately.
This example uses a custom sleep function:
moduleConfig = moduleConfig.
WithNanosleep(func(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 does not default to time.Sleep as that violates sandboxing.
- This is used to implement host functions such as WASI `poll_oneoff`.
- Some compilers implement sleep by looping on sys.Nanotime (e.g. Go).
- If you set this, you should probably set WithNanotime also.
- Use WithSysNanosleep for a usable implementation. WithNanotime configures the monotonic clock, used to measure elapsed
time in nanoseconds. Defaults to a fake result that increases by 1ms
on each reading.
Here's an example that uses a custom 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.
- This is used to implement host functions such as WASI
`clock_time_get` with the `monotonic` clock ID.
- Some compilers implement sleep by looping on sys.Nanotime (e.g. Go).
- If you set this, you should probably set WithNanosleep also.
- Use WithSysNanotime for a usable implementation. WithOsyield yields the processor, typically to implement spin-wait
loops. Defaults to return immediately.
# Notes:
- This primarily supports `sched_yield` in WASI
- This does not default to runtime.osyield as that violates sandboxing. 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. WithStartFunctions configures the functions to call after the module is
instantiated. Defaults to "_start".
Clearing the default is supported, via `WithStartFunctions()`.
# Notes
- If a start function doesn't exist, it is skipped. However, any that
do exist are called in order.
- Start functions are not intended to be called multiple times.
Functions that should be called multiple times should be invoked
manually via api.Module's `ExportedFunction` method.
- Start functions commonly exit the module during instantiation,
preventing use of any functions later. This is the case in "wasip1",
which defines the default value "_start".
- See /RATIONALE.md for motivation of this feature. 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 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 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 WithSysNanosleep uses time.Sleep for sys.Nanosleep.
See WithNanosleep WithSysNanotime uses time.Now for sys.Nanotime with a resolution of 1us.
See WithNanotime WithSysWalltime uses time.Now for sys.Walltime with a resolution of 1us
(1000ns).
See WithWalltime WithWalltime configures the wall clock, sometimes referred to as the
real time clock. sys.Walltime returns the current unix/epoch time,
seconds since midnight UTC 1 January 1970, with a nanosecond fraction.
This defaults to a fake result that increases by 1ms on each reading.
Here's an example that uses a custom clock:
moduleConfig = moduleConfig.
WithWalltime(func(context.Context) (sec int64, nsec int32) {
return clock.walltime()
}, sys.ClockResolution(time.Microsecond.Nanoseconds()))
# Notes:
- This does not default to time.Now as that violates sandboxing.
- This is used to implement host functions such as WASI
`clock_time_get` with the `realtime` clock ID.
- Use WithSysWalltime for a usable implementation.
func NewModuleConfig() ModuleConfig
func ModuleConfig.WithArgs(...string) ModuleConfig
func ModuleConfig.WithEnv(key, value string) ModuleConfig
func ModuleConfig.WithFS(fs.FS) ModuleConfig
func ModuleConfig.WithFSConfig(FSConfig) ModuleConfig
func ModuleConfig.WithName(string) ModuleConfig
func ModuleConfig.WithNanosleep(sys.Nanosleep) ModuleConfig
func ModuleConfig.WithNanotime(sys.Nanotime, sys.ClockResolution) ModuleConfig
func ModuleConfig.WithOsyield(sys.Osyield) ModuleConfig
func ModuleConfig.WithRandSource(io.Reader) ModuleConfig
func ModuleConfig.WithStartFunctions(...string) ModuleConfig
func ModuleConfig.WithStderr(io.Writer) ModuleConfig
func ModuleConfig.WithStdin(io.Reader) ModuleConfig
func ModuleConfig.WithStdout(io.Writer) ModuleConfig
func ModuleConfig.WithSysNanosleep() ModuleConfig
func ModuleConfig.WithSysNanotime() ModuleConfig
func ModuleConfig.WithSysWalltime() ModuleConfig
func ModuleConfig.WithWalltime(sys.Walltime, sys.ClockResolution) ModuleConfig
func Runtime.InstantiateModule(ctx context.Context, compiled CompiledModule, config ModuleConfig) (api.Module, error)
func Runtime.InstantiateWithConfig(ctx context.Context, source []byte, config ModuleConfig) (api.Module, error)
Runtime allows embedding of WebAssembly modules.
The below is an example of basic initialization:
ctx := context.Background()
r := wazero.NewRuntime(ctx)
defer r.Close(ctx) // This closes everything this Runtime created.
mod, _ := r.Instantiate(ctx, wasm)
# Notes
- This is an interface for decoupling, not third-party implementations.
All implementations are in wazero.
- Closing this closes any CompiledModule or Module it instantiated. Close closes the resource.
Note: The context parameter is used for value lookup, such as for
logging. A canceled or otherwise done context will not prevent Close
from succeeding. 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.
Here's an example:
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.Instantiate(ctx, wasm) CompileModule decodes the WebAssembly binary (%.wasm) or errs if invalid.
Any pre-compilation done after decoding wasm is dependent on RuntimeConfig.
There are two main reasons to use CompileModule instead of Instantiate:
- 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.
See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#name-section%E2%91%A0 Instantiate instantiates a module from the WebAssembly binary (%.wasm)
with default configuration, which notably calls the "_start" function,
if it exists.
Here's an example:
ctx := context.Background()
r := wazero.NewRuntime(ctx)
defer r.Close(ctx) // This closes everything this Runtime created.
mod, _ := r.Instantiate(ctx, wasm)
# Notes
- See notes on InstantiateModule for error scenarios.
- See InstantiateWithConfig for configuration overrides. InstantiateModule instantiates the module or errs for reasons including
exit or validation.
Here's an example:
mod, _ := n.InstantiateModule(ctx, compiled, wazero.NewModuleConfig().
WithName("prod"))
# Errors
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.
- The module was compiled to WASI and exited with a non-zero exit
code, you'll receive a sys.ExitError.
- RuntimeConfig.WithCloseOnContextDone was enabled and a context
cancellation or deadline triggered before a start function returned. InstantiateWithConfig instantiates a module from the WebAssembly binary
(%.wasm) or errs for reasons including exit or validation.
Here's an example:
ctx := context.Background()
r := wazero.NewRuntime(ctx)
defer r.Close(ctx) // This closes everything this Runtime created.
mod, _ := r.InstantiateWithConfig(ctx, wasm,
wazero.NewModuleConfig().WithName("rotate"))
# Notes
- See notes on InstantiateModule for error scenarios.
- If you aren't overriding defaults, use Instantiate.
- 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. Module returns an instantiated module in this runtime or nil if there aren't any. NewHostModuleBuilder lets you create modules out of functions defined in Go.
Below defines and instantiates a module named "env" with one function:
ctx := context.Background()
hello := func() {
fmt.Fprintln(stdout, "hello!")
}
_, err := r.NewHostModuleBuilder("env").
NewFunctionBuilder().WithFunc(hello).Export("hello").
Instantiate(ctx, r)
Note: empty `moduleName` is not allowed.
Runtime : CompilationCache
Runtime : github.com/tetratelabs/wazero/api.Closer
func NewRuntime(ctx context.Context) Runtime
func NewRuntimeWithConfig(ctx context.Context, rConfig RuntimeConfig) Runtime
RuntimeConfig controls runtime behavior, with the default implementation as
NewRuntimeConfig
The example below explicitly limits to Wasm Core 1.0 features as opposed to
relying on defaults:
rConfig = wazero.NewRuntimeConfig().WithCoreFeatures(api.CoreFeaturesV1)
# Notes
- This is an interface for decoupling, not third-party implementations.
All implementations are in wazero.
- RuntimeConfig is immutable. Each WithXXX function returns a new instance
including the corresponding change. WithCloseOnContextDone ensures the executions of functions to be terminated under one of the following circumstances:
- context.Context passed to the Call method of api.Function is canceled during execution. (i.e. ctx by context.WithCancel)
- context.Context passed to the Call method of api.Function reaches timeout during execution. (i.e. ctx by context.WithTimeout or context.WithDeadline)
- Close or CloseWithExitCode of api.Module is explicitly called during execution.
This is especially useful when one wants to run untrusted Wasm binaries since otherwise, any invocation of
api.Function can potentially block the corresponding Goroutine forever. Moreover, it might block the
entire underlying OS thread which runs the api.Function call. See "Why it's safe to execute runtime-generated
machine codes against async Goroutine preemption" section in RATIONALE.md for detail.
Upon the termination of the function executions, api.Module is closed.
Note that this comes with a bit of extra cost when enabled. The reason is that internally this forces
interpreter and compiler runtimes to insert the periodical checks on the conditions above. For that reason,
this is disabled by default.
See examples in context_done_example_test.go for the end-to-end demonstrations.
When the invocations of api.Function are closed due to this, sys.ExitError is raised to the callers and
the api.Module from which the functions are derived is made closed. WithCompilationCache configures how runtime caches the compiled modules. In the default configuration, compilation results are
only in-memory until Runtime.Close is closed, and not shareable by multiple Runtime.
Below defines the shared cache across multiple instances of Runtime:
// Creates the new Cache and the runtime configuration with it.
cache := wazero.NewCompilationCache()
defer cache.Close()
config := wazero.NewRuntimeConfig().WithCompilationCache(c)
// Creates two runtimes while sharing compilation caches.
foo := wazero.NewRuntimeWithConfig(context.Background(), config)
bar := wazero.NewRuntimeWithConfig(context.Background(), config)
# Cache Key
Cached files are keyed on the version of wazero. This is obtained from go.mod of your application,
and we use it to verify the compatibility of caches against the currently-running wazero.
However, if you use this in tests of a package not named as `main`, then wazero cannot obtain the correct
version of wazero due to the known issue of debug.BuildInfo function: https://github.com/golang/go/issues/33976.
As a consequence, your cache won't contain the correct version information and always be treated as `dev` version.
To avoid this issue, you can pass -ldflags "-X github.com/tetratelabs/wazero/internal/version.version=foo" when running tests. WithCoreFeatures sets the WebAssembly Core specification features this
runtime supports. Defaults to api.CoreFeaturesV2.
Example of disabling a specific feature:
features := api.CoreFeaturesV2.SetEnabled(api.CoreFeatureMutableGlobal, false)
rConfig = wazero.NewRuntimeConfig().WithCoreFeatures(features)
# Why default to version 2.0?
Many compilers that target WebAssembly require features after
api.CoreFeaturesV1 by default. For example, TinyGo v0.24+ requires
api.CoreFeatureBulkMemoryOperations. To avoid runtime errors, wazero
defaults to api.CoreFeaturesV2, even though it is not yet a Web
Standard (REC). WithCustomSections toggles parsing of "custom sections". Defaults to false.
When enabled, it is possible to retrieve custom sections from a CompiledModule:
config := wazero.NewRuntimeConfig().WithCustomSections(true)
r := wazero.NewRuntimeWithConfig(ctx, config)
c, err := r.CompileModule(ctx, wasm)
customSections := c.CustomSections() WithDebugInfoEnabled toggles DWARF based stack traces in the face of
runtime errors. Defaults to true.
Those who wish to disable this, can like so:
r := wazero.NewRuntimeWithConfig(wazero.NewRuntimeConfig().WithDebugInfoEnabled(false)
When disabled, a stack trace message looks like:
wasm stack trace:
.runtime._panic(i32)
.myFunc()
.main.main()
.runtime.run()
._start()
When enabled, the stack trace includes source code information:
wasm stack trace:
.runtime._panic(i32)
0x16e2: /opt/homebrew/Cellar/tinygo/0.26.0/src/runtime/runtime_tinygowasm.go:73:6
.myFunc()
0x190b: /Users/XXXXX/wazero/internal/testing/dwarftestdata/testdata/main.go:19:7
.main.main()
0x18ed: /Users/XXXXX/wazero/internal/testing/dwarftestdata/testdata/main.go:4:3
.runtime.run()
0x18cc: /opt/homebrew/Cellar/tinygo/0.26.0/src/runtime/scheduler_none.go:26:10
._start()
0x18b6: /opt/homebrew/Cellar/tinygo/0.26.0/src/runtime/runtime_wasm_wasi.go:22:5
Note: This only takes into effect when the original Wasm binary has the
DWARF "custom sections" that are often stripped, depending on
optimization flags passed to the compiler. WithMemoryCapacityFromMax eagerly allocates max memory, unless max is
not defined. The default is false, which means minimum memory is
allocated and any call to grow memory results in re-allocations.
This example ensures any memory.grow instruction will never re-allocate:
rConfig = wazero.NewRuntimeConfig().WithMemoryCapacityFromMax(true)
See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#grow-mem
Note: if the memory maximum is not encoded in a Wasm binary, this
results in allocating 4GB. See the doc on WithMemoryLimitPages for detail. WithMemoryLimitPages overrides the maximum pages allowed per memory. The
default is 65536, allowing 4GB total memory per instance if the maximum is
not encoded in a Wasm binary. Setting a value larger than default will panic.
This example reduces the largest possible memory size from 4GB to 128KB:
rConfig = wazero.NewRuntimeConfig().WithMemoryLimitPages(2)
Note: Wasm has 32-bit memory and each page is 65536 (2^16) bytes. This
implies a max of 65536 (2^16) addressable pages.
See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#grow-mem
func NewRuntimeConfig() RuntimeConfig
func NewRuntimeConfigCompiler() RuntimeConfig
func NewRuntimeConfigInterpreter() RuntimeConfig
func RuntimeConfig.WithCloseOnContextDone(bool) RuntimeConfig
func RuntimeConfig.WithCompilationCache(CompilationCache) RuntimeConfig
func RuntimeConfig.WithCoreFeatures(api.CoreFeatures) RuntimeConfig
func RuntimeConfig.WithCustomSections(bool) RuntimeConfig
func RuntimeConfig.WithDebugInfoEnabled(bool) RuntimeConfig
func RuntimeConfig.WithMemoryCapacityFromMax(memoryCapacityFromMax bool) RuntimeConfig
func RuntimeConfig.WithMemoryLimitPages(memoryLimitPages uint32) RuntimeConfig
func NewRuntimeWithConfig(ctx context.Context, rConfig RuntimeConfig) Runtime
var github.com/ncruces/go-sqlite3.RuntimeConfig
Package-Level Functions (total 9)
NewCompilationCache returns a new CompilationCache to be passed to RuntimeConfig.
This configures only in-memory cache, and doesn't persist to the file system. See wazero.NewCompilationCacheWithDir for detail.
The returned CompilationCache can be used to share the in-memory compilation results across multiple instances of wazero.Runtime.
NewCompilationCacheWithDir is like wazero.NewCompilationCache except the result also writes
state into the directory specified by `dirname` parameter.
If the dirname doesn't exist, this creates it or returns an error.
Those running wazero as a CLI or frequently restarting a process using the same wasm should
use this feature to reduce time waiting to compile the same module a second time.
The contents written into dirname are wazero-version specific, meaning different versions of
wazero will duplicate entries for the same input wasm.
Note: The embedder must safeguard this directory from external changes.
NewFSConfig returns a FSConfig that can be used for configuring module instantiation.
NewModuleConfig returns a ModuleConfig that can be used for configuring module instantiation.
NewRuntime returns a runtime with a configuration assigned by NewRuntimeConfig.
NewRuntimeConfig returns a RuntimeConfig using the compiler if it is supported in this environment,
or the interpreter otherwise.
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.
- If you are using wazero in buildmode=c-archive or c-shared, make sure that you set up the alternate signal stack
by using, e.g. `sigaltstack` combined with `SA_ONSTACK` flag on `sigaction` on Linux,
before calling any api.Function. This is because the Go runtime does not set up the alternate signal stack
for c-archive or c-shared modes, and wazero uses the different stack than the calling Goroutine.
Hence, the signal handler might get invoked on the wazero's stack, which may cause a stack overflow.
https://github.com/tetratelabs/wazero/blob/2092c0a879f30d49d7b37f333f4547574b8afe0d/internal/integration_test/fuzz/fuzz/tests/sigstack.rs#L19-L36
NewRuntimeConfigInterpreter interprets WebAssembly modules instead of compiling them into assembly.
NewRuntimeWithConfig returns a runtime with the given configuration.
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.