experimental

package
v1.0.2 Latest Latest
Warning

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

Go to latest
Published: Nov 11, 2023 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Overview

Package experimental includes features we aren't yet sure about. These are enabled with context.Context keys.

Note: All features here may be changed or deleted at any time, so use with caution!

Example (CustomListenerFactory)

This shows how to make a listener that counts go function calls.

package main

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

	"wa-lang.org/wazero"
	"wa-lang.org/wazero/api"
	. "wa-lang.org/wazero/experimental"
	"wa-lang.org/wazero/imports/wasi_snapshot_preview1"
)

// listenerWasm was generated by the following:
//
//	cd testdata; wat2wasm --debug-names listener.wat
//
//go:embed logging/testdata/listener.wasm
var listenerWasm []byte

// uniqGoFuncs implements both FunctionListenerFactory and FunctionListener
type uniqGoFuncs map[string]struct{}

// callees returns the go functions called.
func (u uniqGoFuncs) callees() []string {
	ret := make([]string, 0, len(u))
	for k := range u {
		ret = append(ret, k)
	}
	// Sort names for consistent iteration
	sort.Strings(ret)
	return ret
}

// NewListener implements FunctionListenerFactory.NewListener
func (u uniqGoFuncs) NewListener(def api.FunctionDefinition) FunctionListener {
	if def.GoFunction() == nil {
		return nil // only track go funcs
	}
	return u
}

// Before implements FunctionListener.Before
func (u uniqGoFuncs) Before(ctx context.Context, def api.FunctionDefinition, _ []uint64) context.Context {
	u[def.DebugName()] = struct{}{}
	return ctx
}

// After implements FunctionListener.After
func (u uniqGoFuncs) After(context.Context, api.FunctionDefinition, error, []uint64) {}

// This shows how to make a listener that counts go function calls.
func main() {
	u := uniqGoFuncs{}

	// Set context to one that has an experimental listener
	ctx := context.WithValue(context.Background(), FunctionListenerFactoryKey{}, u)

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

	wasi_snapshot_preview1.MustInstantiate(ctx, r)

	// Compile the WebAssembly module using the default configuration.
	code, err := r.CompileModule(ctx, listenerWasm)
	if err != nil {
		log.Panicln(err)
	}

	mod, err := r.InstantiateModule(ctx, code, wazero.NewModuleConfig())
	if err != nil {
		log.Panicln(err)
	}

	for i := 0; i < 5; i++ {
		if _, err = mod.ExportedFunction("rand").Call(ctx, 4); err != nil {
			log.Panicln(err)
		}
	}

	// A Go function was called multiple times, but we should only see it once.
	for _, f := range u.callees() {
		fmt.Println(f)
	}

}
Output:

wasi_snapshot_preview1.random_get
Example (WithCompilationCacheDirName)

This is a basic example of using the file system compilation cache via WithCompilationCacheDirName. The main goal is to show how it is configured.

package main

import (
	"context"
	"log"
	"os"

	"wa-lang.org/wazero"
	"wa-lang.org/wazero/experimental"
)

// This is a basic example of using the file system compilation cache via WithCompilationCacheDirName.
// The main goal is to show how it is configured.
func main() {
	// Prepare a cache directory.
	cacheDir, err := os.MkdirTemp("", "example")
	if err != nil {
		log.Panicln(err)
	}
	defer os.RemoveAll(cacheDir)

	// Append the directory into the context for configuration.
	ctx, err := experimental.WithCompilationCacheDirName(context.Background(), cacheDir)
	if err != nil {
		log.Panicln(err)
	}

	// Repeat newRuntimeCompileClose with the same cache directory.
	newRuntimeCompileClose(ctx)
	// Since the above stored compiled functions to dist, below won't compile.
	// Instead, code stored in the file cache is re-used.
	newRuntimeCompileClose(ctx)
	newRuntimeCompileClose(ctx)

}

// newRuntimeCompileDestroy creates a new wazero.Runtime, compile a binary, and then delete the runtime.
func newRuntimeCompileClose(ctx context.Context) {
	r := wazero.NewRuntime(ctx)
	defer r.Close(ctx) // This closes everything this Runtime created except the file system cache.

	_, err := r.CompileModule(ctx, fsWasm)
	if err != nil {
		log.Panicln(err)
	}
}
Output:

Example (WithFS)

This is a basic example of overriding the file system via WithFS. The main goal is to show how it is configured.

package main

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

	"wa-lang.org/wazero"
	"wa-lang.org/wazero/experimental"
	"wa-lang.org/wazero/imports/wasi_snapshot_preview1"
)

// fsWasm was generated by the following:
//
//	cd testdata; wat2wasm --debug-names fs.wat
//
//go:embed testdata/fs.wasm
var fsWasm []byte

// This is a basic example of overriding the file system via WithFS. The main
// goal is to show how it is configured.
func main() {
	ctx := context.Background()

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

	wasi_snapshot_preview1.MustInstantiate(ctx, r)

	// Instantiate a module exporting a WASI function that uses the filesystem.
	mod, err := r.InstantiateModuleFromBinary(ctx, fsWasm)
	if err != nil {
		log.Panicln(err)
	}

	// Setup the filesystem overlay, noting that it can fail if the directory is
	// invalid and must be closed.
	ctx, closer := experimental.WithFS(ctx, os.DirFS("."))
	defer closer.Close(ctx)

	fdPrestatDirName := mod.ExportedFunction("fd_prestat_dir_name")
	fd := 3         // after stderr
	pathLen := 1    // length we expect the path to be.
	pathOffset := 0 // where to write pathLen bytes.

	// By default, there are no pre-opened directories. If the configuration
	// was wrong, this call would fail.
	results, err := fdPrestatDirName.Call(ctx, uint64(fd), uint64(pathOffset), uint64(pathLen))
	if err != nil {
		log.Panicln(err)
	}
	if results[0] != 0 {
		log.Panicf("received errno %d\n", results[0])
	}

	// Try to read the path!
	if path, ok := mod.Memory().Read(ctx, uint32(pathOffset), uint32(pathLen)); !ok {
		log.Panicln("out of memory reading path")
	} else {
		fmt.Println(string(path))
	}

}
Output:

/

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func WithCompilationCacheDirName

func WithCompilationCacheDirName(ctx context.Context, dirname string) (context.Context, error)

WithCompilationCacheDirName configures the destination directory of the compilation cache. Regardless of the usage of this, the compiled functions are cached in memory, but its lifetime is bound to the lifetime of wazero.Runtime or wazero.CompiledModule.

If the dirname doesn't exist, this creates the directory.

With the given non-empty directory, wazero persists the cache into the directory and that cache will be used as long as the running wazero version match the version of compilation wazero.

A cache is only valid for use in one wazero.Runtime at a time. Concurrent use of a wazero.Runtime is supported, but multiple runtimes must not share the same directory.

Note: The embedder must safeguard this directory from external changes.

Usage:

ctx, _ := experimental.WithCompilationCacheDirName(context.Background(), "/home/me/.cache/wazero")
r := wazero.NewRuntimeWithConfig(ctx, wazero.NewRuntimeConfigCompiler())

func WithFS

func WithFS(ctx context.Context, fs fs.FS) (context.Context, api.Closer)

WithFS overrides fs.FS in the context-based manner. Caller needs to take responsibility for closing the filesystem.

Note: This has the same effect as the same function on wazero.ModuleConfig.

Types

type FunctionListener

type FunctionListener interface {
	// Before is invoked before a function is called. The returned context will
	// be used as the context of this function call.
	//
	// # Params
	//
	//   - ctx: the context of the caller function which must be the same
	//	   instance or parent of the result.
	//   - def: the function definition.
	//   - paramValues:  api.ValueType encoded parameters.
	Before(ctx context.Context, def api.FunctionDefinition, paramValues []uint64) context.Context

	// After is invoked after a function is called.
	//
	// # Params
	//
	//   - ctx: the context returned by Before.
	//   - def: the function definition.
	//   - err: nil if the function didn't err
	//   - resultValues: api.ValueType encoded results.
	After(ctx context.Context, def api.FunctionDefinition, err error, resultValues []uint64)
}

FunctionListener can be registered for any function via FunctionListenerFactory to be notified when the function is called.

type FunctionListenerFactory

type FunctionListenerFactory interface {
	// NewListener returns a FunctionListener for a defined function. If nil is
	// returned, no listener will be notified.
	NewListener(api.FunctionDefinition) FunctionListener
}

FunctionListenerFactory returns FunctionListeners to be notified when a function is called.

type FunctionListenerFactoryKey

type FunctionListenerFactoryKey struct{}

FunctionListenerFactoryKey is a context.Context Value key. Its associated value should be a FunctionListenerFactory.

See https://github.com/tetratelabs/wazero/issues/451

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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