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" "fmt" "log" "sort" _ "embed" "github.com/tetratelabs/wazero" "github.com/tetratelabs/wazero/api" "github.com/tetratelabs/wazero/experimental" "github.com/tetratelabs/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.Strings(ret) return ret } // NewFunctionListener implements FunctionListenerFactory.NewFunctionListener func (u uniqGoFuncs) NewFunctionListener(def api.FunctionDefinition) experimental.FunctionListener { if def.GoFunction() == nil { return nil } return u } // Before implements FunctionListener.Before func (u uniqGoFuncs) Before(ctx context.Context, _ api.Module, def api.FunctionDefinition, _ []uint64, _ experimental.StackIterator) { u[def.DebugName()] = struct{}{} } // After implements FunctionListener.After func (u uniqGoFuncs) After(context.Context, api.Module, api.FunctionDefinition, []uint64) {} // Abort implements FunctionListener.Abort func (u uniqGoFuncs) Abort(context.Context, api.Module, api.FunctionDefinition, error) {} func main() { u := uniqGoFuncs{} // Set context to one that has an experimental listener ctx := context.WithValue(context.Background(), experimental.FunctionListenerFactoryKey{}, u) r := wazero.NewRuntime(ctx) defer r.Close(ctx) // This closes everything this Runtime created. wasi_snapshot_preview1.MustInstantiate(ctx, r) mod, err := r.Instantiate(ctx, listenerWasm) 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.fd_write wasi_snapshot_preview1.random_get
Example (StackIterator) ¶
package main import ( "fmt" _ "embed" "github.com/tetratelabs/wazero/api" "github.com/tetratelabs/wazero/experimental" "github.com/tetratelabs/wazero/internal/wasm" ) func main() { it := &fakeStackIterator{} for it.Next() { fn := it.Function() pc := it.ProgramCounter() fmt.Println("function:", fn.Definition().DebugName()) fmt.Println("\tparameters:", it.Parameters()) fmt.Println("\tprogram counter:", pc) fmt.Println("\tsource offset:", fn.SourceOffsetForPC(pc)) } } type fakeStackIterator struct { iteration int def api.FunctionDefinition args []uint64 pc uint64 sourceOffset uint64 } func (s *fakeStackIterator) Next() bool { switch s.iteration { case 0: s.def = &mockFunctionDefinition{debugName: "fn0"} s.args = []uint64{1, 2, 3} s.pc = 5890831 s.sourceOffset = 1234 case 1: s.def = &mockFunctionDefinition{debugName: "fn1"} s.args = []uint64{} s.pc = 5899822 s.sourceOffset = 7286 case 2: s.def = &mockFunctionDefinition{debugName: "fn2"} s.args = []uint64{4} s.pc = 6820312 s.sourceOffset = 935891 case 3: return false } s.iteration++ return true } func (s *fakeStackIterator) Function() experimental.InternalFunction { return internalFunction{ definition: s.def, sourceOffset: s.sourceOffset, } } func (s *fakeStackIterator) Parameters() []uint64 { return s.args } func (s *fakeStackIterator) ProgramCounter() experimental.ProgramCounter { return experimental.ProgramCounter(s.pc) } type internalFunction struct { definition api.FunctionDefinition sourceOffset uint64 } func (f internalFunction) Definition() api.FunctionDefinition { return f.definition } func (f internalFunction) SourceOffsetForPC(pc experimental.ProgramCounter) uint64 { return f.sourceOffset } type mockFunctionDefinition struct { debugName string *wasm.FunctionDefinition } func (f *mockFunctionDefinition) DebugName() string { return f.debugName } func (f *mockFunctionDefinition) ParamTypes() []wasm.ValueType { return []wasm.ValueType{} } func (f *mockFunctionDefinition) ResultTypes() []wasm.ValueType { return []wasm.ValueType{} }
Output: function: fn0 parameters: [1 2 3] program counter: 5890831 source offset: 1234 function: fn1 parameters: [] program counter: 5899822 source offset: 7286 function: fn2 parameters: [4] program counter: 6820312 source offset: 935891
Index ¶
- func BenchmarkFunctionListener(n int, module api.Module, stack []StackFrame, listener FunctionListener)
- type FunctionListener
- type FunctionListenerFactory
- type FunctionListenerFactoryFunc
- type FunctionListenerFactoryKey
- type FunctionListenerFunc
- func (f FunctionListenerFunc) Abort(context.Context, api.Module, api.FunctionDefinition, error)
- func (f FunctionListenerFunc) After(context.Context, api.Module, api.FunctionDefinition, []uint64)
- func (f FunctionListenerFunc) Before(ctx context.Context, mod api.Module, def api.FunctionDefinition, ...)
- type InternalFunction
- type InternalModule
- type ProgramCounter
- type StackFrame
- type StackIterator
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func BenchmarkFunctionListener ¶ added in v1.2.0
func BenchmarkFunctionListener(n int, module api.Module, stack []StackFrame, listener FunctionListener)
BenchmarkFunctionListener implements a benchmark for function listeners.
The benchmark calls Before and After methods repeatedly using the provided module an stack frames to invoke the methods.
The stack frame is a representation of the call stack that the Before method will be invoked with. The top of the stack is stored at index zero. The stack must contain at least one frame or the benchmark will fail.
Types ¶
type FunctionListener ¶
type FunctionListener interface { // Before is invoked before a function is called. // // There is always one corresponding call to After or Abort for each call to // Before. This guarantee allows the listener to maintain an internal stack // to perform correlations between the entry and exit of functions. // // # Params // // - ctx: the context of the caller function which must be the same // instance or parent of the result. // - mod: the calling module. // - def: the function definition. // - params: api.ValueType encoded parameters. // - stackIterator: iterator on the call stack. At least one entry is // guaranteed (the called function), whose Args() will be equal to // params. The iterator will be reused between calls to Before. // // Note: api.Memory is meant for inspection, not modification. // mod can be cast to InternalModule to read non-exported globals. Before(ctx context.Context, mod api.Module, def api.FunctionDefinition, params []uint64, stackIterator StackIterator) // After is invoked after a function is called. // // # Params // // - ctx: the context of the caller function. // - mod: the calling module. // - def: the function definition. // - results: api.ValueType encoded results. // // # Notes // // - api.Memory is meant for inspection, not modification. // - This is not called when a host function panics, or a guest function traps. // See Abort for more details. After(ctx context.Context, mod api.Module, def api.FunctionDefinition, results []uint64) // Abort is invoked when a function does not return due to a trap or panic. // // # Params // // - ctx: the context of the caller function. // - mod: the calling module. // - def: the function definition. // - err: the error value representing the reason why the function aborted. // // # Notes // // - api.Memory is meant for inspection, not modification. Abort(ctx context.Context, mod api.Module, def api.FunctionDefinition, err error) }
FunctionListener can be registered for any function via FunctionListenerFactory to be notified when the function is called.
type FunctionListenerFactory ¶
type FunctionListenerFactory interface { // NewFunctionListener returns a FunctionListener for a defined function. // If nil is returned, no listener will be notified. NewFunctionListener(api.FunctionDefinition) FunctionListener }
FunctionListenerFactory returns FunctionListeners to be notified when a function is called.
func MultiFunctionListenerFactory ¶ added in v1.2.0
func MultiFunctionListenerFactory(factories ...FunctionListenerFactory) FunctionListenerFactory
MultiFunctionListenerFactory constructs a FunctionListenerFactory which combines the listeners created by each of the factories passed as arguments.
This function is useful when multiple listeners need to be hooked to a module because the propagation mechanism based on installing a listener factory in the context.Context used when instantiating modules allows for a single listener to be installed.
The stack iterator passed to the Before method is reset so that each listener can iterate the call stack independently without impacting the ability of other listeners to do so.
type FunctionListenerFactoryFunc ¶ added in v1.2.0
type FunctionListenerFactoryFunc func(api.FunctionDefinition) FunctionListener
FunctionListenerFactoryFunc is a function type implementing the FunctionListenerFactory interface, making it possible to use regular functions and methods as factory of function listeners.
func (FunctionListenerFactoryFunc) NewFunctionListener ¶ added in v1.2.0
func (f FunctionListenerFactoryFunc) NewFunctionListener(def api.FunctionDefinition) FunctionListener
NewFunctionListener satisfies the FunctionListenerFactory interface, calls f.
type FunctionListenerFactoryKey ¶
type FunctionListenerFactoryKey struct{}
FunctionListenerFactoryKey is a context.Context Value key. Its associated value should be a FunctionListenerFactory.
type FunctionListenerFunc ¶ added in v1.2.0
type FunctionListenerFunc func(context.Context, api.Module, api.FunctionDefinition, []uint64, StackIterator)
FunctionListenerFunc is a function type implementing the FunctionListener interface, making it possible to use regular functions and methods as listeners of function invocation.
The FunctionListener interface declares two methods (Before and After), but this type invokes its value only when Before is called. It is best suites for cases where the host does not need to perform correlation between the start and end of the function call.
func (FunctionListenerFunc) Abort ¶ added in v1.2.0
func (f FunctionListenerFunc) Abort(context.Context, api.Module, api.FunctionDefinition, error)
Abort is declared to satisfy the FunctionListener interface, but it does nothing.
func (FunctionListenerFunc) After ¶ added in v1.2.0
func (f FunctionListenerFunc) After(context.Context, api.Module, api.FunctionDefinition, []uint64)
After is declared to satisfy the FunctionListener interface, but it does nothing.
func (FunctionListenerFunc) Before ¶ added in v1.2.0
func (f FunctionListenerFunc) Before(ctx context.Context, mod api.Module, def api.FunctionDefinition, params []uint64, stackIterator StackIterator)
Before satisfies the FunctionListener interface, calls f.
type InternalFunction ¶ added in v1.2.0
type InternalFunction interface { // Definition provides introspection into the function's names and // signature. Definition() api.FunctionDefinition // SourceOffsetForPC resolves a program counter into its corresponding // offset in the Code section of the module this function belongs to. // The source offset is meant to help map the function calls to their // location in the original source files. Returns 0 if the offset cannot // be calculated. SourceOffsetForPC(pc ProgramCounter) uint64 }
InternalFunction exposes some information about a function instance.
type InternalModule ¶ added in v1.1.0
type InternalModule interface { api.Module // NumGlobal returns the count of all globals in the module. NumGlobal() int // Global provides a read-only view for a given global index. // // The methods panics if i is out of bounds. Global(i int) api.Global }
InternalModule is an api.Module that exposes additional information.
type ProgramCounter ¶ added in v1.2.0
type ProgramCounter uint64
ProgramCounter is an opaque value representing a specific execution point in a module. It is meant to be used with Function.SourceOffsetForPC and StackIterator.
type StackFrame ¶ added in v1.2.0
type StackFrame struct { Function api.Function Params []uint64 Results []uint64 PC uint64 SourceOffset uint64 }
StackFrame represents a frame on the call stack.
type StackIterator ¶ added in v1.0.2
type StackIterator interface { // Next moves the iterator to the next function in the stack. Returns // false if it reached the bottom of the stack. Next() bool // Function describes the function called by the current frame. Function() InternalFunction // ProgramCounter returns the program counter associated with the // function call. ProgramCounter() ProgramCounter // Parameters returns api.ValueType-encoded parameters of the current // function. Do not modify the content of the slice, and copy out any // value you need. Parameters() []uint64 }
StackIterator allows iterating on each function of the call stack, starting from the top. At least one call to Next() is required to start the iteration.
Note: The iterator provides a view of the call stack at the time of iteration. As a result, parameter values may be different than the ones their function was called with.
func NewStackIterator ¶ added in v1.2.0
func NewStackIterator(stack ...StackFrame) StackIterator
NewStackIterator constructs a stack iterator from a list of stack frames. The top most frame is the last one.