Makes it possible to implement FunctionListener and Factory (#716)

This simplifies FunctionListener definition by making it possible to
implement both interfaces without intermediate state. Passing the
function definition to the before/after callbacks is the key.

This also continues efforts towards Go 1.19 doc formatting.

Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
Crypt Keeper
2022-07-25 12:53:41 +08:00
committed by GitHub
parent 8d75403c49
commit 939403c10b
31 changed files with 253 additions and 146 deletions

View File

@@ -125,7 +125,7 @@ func ValueTypeName(t ValueType) string {
// Module return functions exported in a module, post-instantiation.
//
// Notes
// # Notes
//
// - Closing the wazero.Runtime closes any Module it instantiated.
// - This is an interface for decoupling, not third-party implementations. All implementations are in wazero.
@@ -316,7 +316,7 @@ type MutableGlobal interface {
// Memory allows restricted access to a module's memory. Notably, this does not allow growing.
//
// Notes
// # Notes
//
// - All functions accept a context.Context, which when nil, default to context.Background.
// - This is an interface for decoupling, not third-party implementations. All implementations are in wazero.
@@ -334,11 +334,11 @@ type Memory interface {
// The return val is the previous memory size in pages, or false if the
// delta was ignored as it exceeds max memory.
//
// Notes
// # Notes
//
// * This is the same as the "memory.grow" instruction defined in the
// - This is the same as the "memory.grow" instruction defined in the
// WebAssembly Core Specification, except returns false instead of -1.
// * When this returns true, any shared views via Read must be refreshed.
// - When this returns true, any shared views via Read must be refreshed.
//
// See MemorySizer Read and https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#grow-mem
Grow(ctx context.Context, deltaPages uint32) (previousPages uint32, ok bool)

View File

@@ -47,7 +47,7 @@ const (
// Instantiate instantiates the "env" module used by AssemblyScript into the
// runtime default namespace.
//
// Notes
// # Notes
//
// - Closing the wazero.Runtime has the same effect as closing the result.
// - To add more functions to the "env" module, use FunctionExporter.

View File

@@ -14,6 +14,7 @@ import (
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/api"
. "github.com/tetratelabs/wazero/experimental"
"github.com/tetratelabs/wazero/experimental/logging"
"github.com/tetratelabs/wazero/internal/testing/require"
"github.com/tetratelabs/wazero/internal/u64"
"github.com/tetratelabs/wazero/internal/wasm"
@@ -398,7 +399,7 @@ func requireModule(t *testing.T, fns FunctionExporter, config wazero.ModuleConfi
var log bytes.Buffer
// Set context to one that has an experimental listener
ctx := context.WithValue(testCtx, FunctionListenerFactoryKey{}, NewLoggingListenerFactory(&log))
ctx := context.WithValue(testCtx, FunctionListenerFactoryKey{}, logging.NewLoggingListenerFactory(&log))
r := wazero.NewRuntimeWithConfig(wazero.NewRuntimeConfigInterpreter())

View File

@@ -36,7 +36,7 @@ import (
//
// env2, _ := r.InstantiateModule(ctx, compiled, wazero.NewModuleConfig().WithName("env.2"))
//
// Notes
// # Notes
//
// - ModuleBuilder is mutable: each method returns the same instance for
// chaining.
@@ -50,11 +50,11 @@ 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
// # Parameters
//
// * exportName - The name to export. Ex "random_get"
// * goFunc - The `func` to export.
// * names - If present, the first is the api.FunctionDefinition name.
// - 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.
@@ -116,19 +116,19 @@ type ModuleBuilder interface {
// 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
// # 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).
// - 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
// # 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.
// - 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
@@ -208,11 +208,11 @@ type ModuleBuilder interface {
// ExportFunction("hello", hello).
// Instantiate(ctx, r)
//
// Notes
// # 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.
// - 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)
}

View File

@@ -31,10 +31,10 @@ type RuntimeConfig interface {
// ("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.
// - 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".
@@ -49,8 +49,8 @@ type RuntimeConfig interface {
// 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
// - 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/main/proposals/multi-value/Overview.md
WithFeatureMultiValue(bool) RuntimeConfig
@@ -66,22 +66,22 @@ type RuntimeConfig interface {
// ("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`
// - `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/main/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:
// - Introduction of new value types: `funcref` and `externref`.
// - Support for the following new instructions:
// * `ref.null`
// * `ref.func`
// * `ref.is_null`
@@ -90,7 +90,7 @@ type RuntimeConfig interface {
// * `table.grow`
// * `table.set`
// * `table.size`
// * Support for multiple tables per module:
// - 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.
//
@@ -107,7 +107,7 @@ type RuntimeConfig interface {
// 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`
// - 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/main/proposals/sign-extension-ops/Overview.md
WithFeatureSignExtensionOps(bool) RuntimeConfig
@@ -451,11 +451,11 @@ type ModuleConfig interface {
// WithStartFunctions configures the functions to call after the module is
// instantiated. Defaults to "_start".
//
// Notes
// # Notes
//
// * If any function doesn't exist, it is skipped. However, all functions
// - 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
// - Some start functions may exit the module during instantiate with a
// sys.ExitError (ex. emscripten), preventing use of exported functions.
WithStartFunctions(...string) ModuleConfig
@@ -464,10 +464,10 @@ type ModuleConfig interface {
// 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
// # 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.
// - 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
@@ -477,10 +477,10 @@ type ModuleConfig interface {
// 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
// # 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.
// - 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
@@ -490,10 +490,10 @@ type ModuleConfig interface {
// 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
// # 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.
// - 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
@@ -528,11 +528,11 @@ type ModuleConfig interface {
// 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.
// # 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.
@@ -552,12 +552,12 @@ type ModuleConfig interface {
// 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.
// # 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.

View File

@@ -23,7 +23,7 @@ import (
// Instantiate instantiates the "env" module used by Emscripten into the
// runtime default namespace.
//
// Notes
// # Notes
//
// - Closing the wazero.Runtime has the same effect as closing the result.
// - To add more functions to the "env" module, use FunctionExporter.

View File

@@ -8,6 +8,7 @@ import (
"github.com/tetratelabs/wazero"
. "github.com/tetratelabs/wazero/experimental"
"github.com/tetratelabs/wazero/experimental/logging"
"github.com/tetratelabs/wazero/internal/testing/require"
"github.com/tetratelabs/wazero/sys"
"github.com/tetratelabs/wazero/wasi_snapshot_preview1"
@@ -26,7 +27,7 @@ func TestGrow(t *testing.T) {
var log bytes.Buffer
// Set context to one that has an experimental listener
ctx := context.WithValue(testCtx, FunctionListenerFactoryKey{}, NewLoggingListenerFactory(&log))
ctx := context.WithValue(testCtx, FunctionListenerFactoryKey{}, logging.NewLoggingListenerFactory(&log))
r := wazero.NewRuntimeWithConfig(wazero.NewRuntimeConfigInterpreter())
defer r.Close(ctx)

View File

@@ -27,21 +27,23 @@ 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
// # Params
//
// * ctx - the context of the caller function which must be the same
// instance or parent of the result.
// * paramValues - api.ValueType encoded parameters.
Before(ctx context.Context, paramValues []uint64) context.Context
// - 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
// # Params
//
// * ctx - the context returned by Before.
// * err - nil if the function didn't err
// * resultValues - api.ValueType encoded results.
After(ctx context.Context, err error, resultValues []uint64)
// - 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)
}
// TODO: We need to add tests to enginetest to ensure contexts nest. A good test can use a combination of call and call

View File

@@ -0,0 +1,92 @@
package experimental_test
import (
"context"
_ "embed"
"fmt"
"log"
"sort"
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/api"
. "github.com/tetratelabs/wazero/experimental"
"github.com/tetratelabs/wazero/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.GoFunc() == 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 Example_customListenerFactory() {
u := uniqGoFuncs{}
// Set context to one that has an experimental listener
ctx := context.WithValue(context.Background(), FunctionListenerFactoryKey{}, u)
r := wazero.NewRuntimeWithConfig(wazero.NewRuntimeConfigInterpreter())
defer r.Close(ctx) // This closes everything this Runtime created.
if _, err := wasi_snapshot_preview1.Instantiate(ctx, r); err != nil {
log.Panicln(err)
}
// Compile the WebAssembly module using the default configuration.
code, err := r.CompileModule(ctx, listenerWasm, wazero.NewCompileConfig())
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
}

View File

@@ -1,4 +1,4 @@
package experimental
package logging
import (
"context"
@@ -8,12 +8,13 @@ import (
"strings"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/experimental"
"github.com/tetratelabs/wazero/internal/wasi_snapshot_preview1"
)
// NewLoggingListenerFactory implements FunctionListenerFactory to log all
// functions that have a name to the writer.
func NewLoggingListenerFactory(writer io.Writer) FunctionListenerFactory {
func NewLoggingListenerFactory(writer io.Writer) experimental.FunctionListenerFactory {
return &loggingListenerFactory{writer}
}
@@ -21,7 +22,7 @@ type loggingListenerFactory struct{ writer io.Writer }
// NewListener implements the same method as documented on
// experimental.FunctionListener.
func (f *loggingListenerFactory) NewListener(fnd api.FunctionDefinition) FunctionListener {
func (f *loggingListenerFactory) NewListener(fnd api.FunctionDefinition) experimental.FunctionListener {
return &loggingListener{writer: f.writer, fnd: fnd, isWasi: fnd.ModuleName() == "wasi_snapshot_preview1"}
}
@@ -39,7 +40,7 @@ type loggingListener struct {
// Before logs to stdout the module and function name, prefixed with '-->' and
// indented based on the call nesting level.
func (l *loggingListener) Before(ctx context.Context, vals []uint64) context.Context {
func (l *loggingListener) Before(ctx context.Context, _ api.FunctionDefinition, vals []uint64) context.Context {
nestLevel, _ := ctx.Value(nestLevelKey{}).(int)
l.writeIndented(true, nil, vals, nestLevel+1)
@@ -50,7 +51,7 @@ func (l *loggingListener) Before(ctx context.Context, vals []uint64) context.Con
// After logs to stdout the module and function name, prefixed with '<--' and
// indented based on the call nesting level.
func (l *loggingListener) After(ctx context.Context, err error, vals []uint64) {
func (l *loggingListener) After(ctx context.Context, _ api.FunctionDefinition, err error, vals []uint64) {
// Note: We use the nest level directly even though it is the "next" nesting level.
// This works because our indent of zero nesting is one tab.
l.writeIndented(false, err, vals, ctx.Value(nestLevelKey{}).(int))

View File

@@ -1,4 +1,4 @@
package experimental_test
package logging_test
import (
"context"
@@ -7,7 +7,8 @@ import (
"os"
"github.com/tetratelabs/wazero"
. "github.com/tetratelabs/wazero/experimental"
"github.com/tetratelabs/wazero/experimental"
"github.com/tetratelabs/wazero/experimental/logging"
"github.com/tetratelabs/wazero/wasi_snapshot_preview1"
)
@@ -21,7 +22,7 @@ var listenerWasm []byte
// This is a very basic integration of listener. The main goal is to show how it is configured.
func Example_newLoggingListenerFactory() {
// Set context to one that has an experimental listener
ctx := context.WithValue(context.Background(), FunctionListenerFactoryKey{}, NewLoggingListenerFactory(os.Stdout))
ctx := context.WithValue(context.Background(), experimental.FunctionListenerFactoryKey{}, logging.NewLoggingListenerFactory(os.Stdout))
r := wazero.NewRuntimeWithConfig(wazero.NewRuntimeConfigInterpreter())
defer r.Close(ctx) // This closes everything this Runtime created.

View File

@@ -1,18 +1,22 @@
package experimental_test
package logging_test
import (
"bytes"
"context"
"io"
"math"
"testing"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/experimental"
"github.com/tetratelabs/wazero/experimental/logging"
"github.com/tetratelabs/wazero/internal/testing/require"
"github.com/tetratelabs/wazero/internal/wasm"
"github.com/tetratelabs/wazero/wasi_snapshot_preview1"
)
// testCtx is an arbitrary, non-default context. Non-nil also prevents linter errors.
var testCtx = context.WithValue(context.Background(), struct{}{}, "arbitrary")
func Test_loggingListener(t *testing.T) {
wasiFuncName := "random_get"
wasiFuncType := &wasm.FunctionType{
@@ -261,7 +265,7 @@ func Test_loggingListener(t *testing.T) {
}
var out bytes.Buffer
lf := experimental.NewLoggingListenerFactory(&out)
lf := logging.NewLoggingListenerFactory(&out)
fn := func() {}
for _, tt := range tests {
tc := tt
@@ -288,11 +292,12 @@ func Test_loggingListener(t *testing.T) {
m.CodeSection = []*wasm.Code{{Body: []byte{wasm.OpcodeEnd}}}
}
m.BuildFunctionDefinitions()
def := m.FunctionDefinitionSection[0]
l := lf.NewListener(m.FunctionDefinitionSection[0])
out.Reset()
ctx := l.Before(testCtx, tc.params)
l.After(ctx, tc.err, tc.results)
ctx := l.Before(testCtx, def, tc.params)
l.After(ctx, def, tc.err, tc.results)
require.Equal(t, tc.expected, out.String())
})
}
@@ -311,7 +316,7 @@ func toNameMap(names []string) wasm.NameMap {
func Test_loggingListener_indentation(t *testing.T) {
out := bytes.NewBuffer(nil)
lf := experimental.NewLoggingListenerFactory(out)
lf := logging.NewLoggingListenerFactory(out)
m := &wasm.Module{
TypeSection: []*wasm.FunctionType{{}},
FunctionSection: []wasm.Index{0, 0},
@@ -322,13 +327,15 @@ func Test_loggingListener_indentation(t *testing.T) {
},
}
m.BuildFunctionDefinitions()
l1 := lf.NewListener(m.FunctionDefinitionSection[0])
l2 := lf.NewListener(m.FunctionDefinitionSection[1])
def1 := m.FunctionDefinitionSection[0]
l1 := lf.NewListener(def1)
def2 := m.FunctionDefinitionSection[1]
l2 := lf.NewListener(def2)
ctx := l1.Before(testCtx, []uint64{})
ctx1 := l2.Before(ctx, []uint64{})
l2.After(ctx1, nil, []uint64{})
l1.After(ctx, nil, []uint64{})
ctx := l1.Before(testCtx, def1, []uint64{})
ctx1 := l2.Before(ctx, def2, []uint64{})
l2.After(ctx1, def2, nil, []uint64{})
l1.After(ctx, def1, nil, []uint64{})
require.Equal(t, `--> test.fn1()
--> test.fn2()
<-- ()

View File

@@ -692,9 +692,9 @@ const (
// VCNT is the CNT instruction. https://developer.arm.com/documentation/dui0802/a/A64-Advanced-SIMD-Vector-Instructions/CNT--vector-
VCNT
// VMOV has different semantics depending on the types of operands:
// * LDR(SIMD&FP) if the src is memory and dst is a vector: https://developer.arm.com/documentation/ddi0596/2020-12/SIMD-FP-Instructions/LDR--immediate--SIMD-FP---Load-SIMD-FP-Register--immediate-offset--
// * LDR(literal, SIMD&FP) if the src is static const and dst is a vector: https://developer.arm.com/documentation/dui0801/h/A64-Floating-point-Instructions/LDR--literal--SIMD-and-FP-
// * STR(SIMD&FP) if the dst is memory and src is a vector: https://developer.arm.com/documentation/ddi0596/2020-12/SIMD-FP-Instructions/STR--immediate--SIMD-FP---Store-SIMD-FP-register--immediate-offset--
// - LDR(SIMD&FP) if the src is memory and dst is a vector: https://developer.arm.com/documentation/ddi0596/2020-12/SIMD-FP-Instructions/LDR--immediate--SIMD-FP---Load-SIMD-FP-Register--immediate-offset--
// - LDR(literal, SIMD&FP) if the src is static const and dst is a vector: https://developer.arm.com/documentation/dui0801/h/A64-Floating-point-Instructions/LDR--literal--SIMD-and-FP-
// - STR(SIMD&FP) if the dst is memory and src is a vector: https://developer.arm.com/documentation/ddi0596/2020-12/SIMD-FP-Instructions/STR--immediate--SIMD-FP---Store-SIMD-FP-register--immediate-offset--
VMOV
// UMOV is the UMOV instruction https://developer.arm.com/documentation/ddi0596/2021-12/SIMD-FP-Instructions/UMOV--Unsigned-Move-vector-element-to-general-purpose-register-?lang=en
UMOV

View File

@@ -811,7 +811,7 @@ func (ce *callEngine) callFunction(ctx context.Context, callCtx *wasm.CallContex
func (ce *callEngine) callGoFunc(ctx context.Context, callCtx *wasm.CallContext, f *function, params []uint64) (results []uint64) {
callCtx = callCtx.WithMemory(ce.callerMemory())
if f.source.FunctionListener != nil {
ctx = f.source.FunctionListener.Before(ctx, params)
ctx = f.source.FunctionListener.Before(ctx, f.source.Definition(), params)
}
frame := &callFrame{f: f}
ce.pushFrame(frame)
@@ -819,7 +819,7 @@ func (ce *callEngine) callGoFunc(ctx context.Context, callCtx *wasm.CallContext,
ce.popFrame()
if f.source.FunctionListener != nil {
// TODO: This doesn't get the error due to use of panic to propagate them.
f.source.FunctionListener.After(ctx, nil, results)
f.source.FunctionListener.After(ctx, f.source.Definition(), nil, results)
}
return
}
@@ -4299,10 +4299,10 @@ func i32Abs(v uint32) uint32 {
}
func (ce *callEngine) callNativeFuncWithListener(ctx context.Context, callCtx *wasm.CallContext, f *function, fnl experimental.FunctionListener) context.Context {
ctx = fnl.Before(ctx, ce.peekValues(len(f.source.Type.Params)))
ctx = fnl.Before(ctx, f.source.Definition(), ce.peekValues(len(f.source.Type.Params)))
ce.callNativeFunc(ctx, callCtx, f)
// TODO: This doesn't get the error due to use of panic to propagate them.
fnl.After(ctx, nil, ce.peekValues(len(f.source.Type.Results)))
fnl.After(ctx, f.source.Definition(), nil, ce.peekValues(len(f.source.Type.Results)))
return ctx
}

View File

@@ -10,6 +10,7 @@ import (
"unsafe"
"github.com/tetratelabs/wazero/experimental"
"github.com/tetratelabs/wazero/experimental/logging"
"github.com/tetratelabs/wazero/internal/buildoptions"
"github.com/tetratelabs/wazero/internal/testing/enginetest"
"github.com/tetratelabs/wazero/internal/testing/require"
@@ -65,7 +66,7 @@ func TestInterpreter_CallEngine_PushFrame_StackOverflow(t *testing.T) {
// et is used for tests defined in the enginetest package.
var et = &engineTester{}
var functionLog bytes.Buffer
var listenerFactory = experimental.NewLoggingListenerFactory(&functionLog)
var listenerFactory = logging.NewLoggingListenerFactory(&functionLog)
// engineTester implements enginetest.EngineTester.
type engineTester struct{}

View File

@@ -38,10 +38,10 @@ type CallContext struct {
// Sys is exposed for use in special imports such as WASI, assemblyscript
// and wasm_exec.
//
// Notes
// # Notes
//
// * This is a part of CallContext so that scope and Close is coherent.
// * This is not exposed outside this repository (as a host function
// - This is a part of CallContext so that scope and Close is coherent.
// - This is not exposed outside this repository (as a host function
// parameter) because we haven't thought through capabilities based
// security implications.
Sys *internalsys.Context

View File

@@ -579,7 +579,7 @@ func (m *Module) buildGlobals(importedGlobals []*GlobalInstance) (globals []*Glo
// BuildFunctions generates function instances for all host or wasm-defined
// functions in this module.
//
// Notes
// # Notes
// - This relies on data generated by Module.BuildFunctionDefinitions.
// - This is exported for tests that don't call Instantiate, notably only
// enginetest.go.

View File

@@ -22,9 +22,9 @@ type Namespace interface {
// 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.
// - 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.

View File

@@ -36,13 +36,13 @@ type Runtime interface {
// 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.
// - Improve performance when the same module is instantiated multiple times under different names
// - Reduce the amount of errors that can occur during InstantiateModule.
//
// Notes
// # 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.
// - 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)
@@ -57,11 +57,11 @@ type Runtime interface {
//
// module, _ := r.InstantiateModuleFromBinary(ctx, wasm)
//
// Notes
// # Notes
//
// * This is a convenience utility that chains CompileModule with InstantiateModule. To instantiate the same
// - 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.
// - 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
@@ -94,11 +94,11 @@ type Runtime interface {
// _ = b.WithTraceToStdout().InstantiateModule(ctx, ns2)
// m2, _ := ns2.InstantiateModule(ctx, compiled, config)
//
// Notes
// # 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.
// - 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.

View File

@@ -15,7 +15,7 @@ const (
// argsGet is the WASI function named functionArgsGet that reads command-line
// argument data.
//
// Parameters
// # Parameters
//
// - argv: offset to begin writing argument offsets in uint32 little-endian
// encoding to api.Memory
@@ -58,7 +58,7 @@ var argsGet = wasm.NewGoFunc(
// argsSizesGet is the WASI function named functionArgsSizesGet that reads
// command-line argument sizes.
//
// Parameters
// # Parameters
//
// - resultArgc: offset to write the argument count to api.Memory
// - resultArgvBufSize: offset to write the null-terminated argument length to

View File

@@ -28,7 +28,7 @@ const (
// clockResGet is the WASI function named functionClockResGet that returns the
// resolution of time values returned by clockTimeGet.
//
// Parameters
// # Parameters
//
// - id: clock ID to use
// - resultResolution: offset to write the resolution to api.Memory
@@ -83,7 +83,7 @@ var clockResGet = wasm.NewGoFunc(
// clockTimeGet is the WASI function named functionClockTimeGet that returns
// the time value of a name (time.Now).
//
// Parameters
// # Parameters
//
// - id: clock ID to use
// - precision: maximum lag (exclusive) that the returned time value may have,

View File

@@ -15,7 +15,7 @@ const (
// environGet is the WASI function named functionEnvironGet that reads
// environment variables.
//
// Parameters
// # Parameters
//
// - environ: offset to begin writing environment offsets in uint32
// little-endian encoding to api.Memory
@@ -58,7 +58,7 @@ var environGet = wasm.NewGoFunc(
// environSizesGet is the WASI function named functionEnvironSizesGet that
// reads environment variable sizes.
//
// Parameters
// # Parameters
//
// - resultEnvironc: offset to write the count of environment variables to
// api.Memory

View File

@@ -6,7 +6,7 @@ import (
// Errno are the error codes returned by WASI functions.
//
// Notes
// # Notes
//
// - This is not always an error, as ErrnoSuccess is a valid code.
// - Codes are defined even when not relevant to WASI for use in higher-level libraries or alignment with POSIX.

View File

@@ -69,7 +69,7 @@ var fdAllocate = stubFunction(
// fdClose is the WASI function named functionFdClose which closes a file
// descriptor.
//
// Parameters
// # Parameters
//
// - fd: file descriptor to close
//
@@ -107,7 +107,7 @@ var fdDatasync = stubFunction(
// fdFdstatGet is the WASI function named functionFdFdstatGet which returns the
// attributes of a file descriptor.
//
// Parameters
// # Parameters
//
// - fd: file descriptor to get the fdstat attributes data
// - resultFdstat: offset to write the result fdstat data
@@ -219,7 +219,7 @@ var fdPread = stubFunction(
// fdPrestatGet is the WASI function named functionFdPrestatGet which returns
// the prestat data of a file descriptor.
//
// Parameters
// # Parameters
//
// - fd: file descriptor to get the prestat
// - resultPrestat: offset to write the result prestat data
@@ -273,7 +273,7 @@ var fdPrestatGet = wasm.NewGoFunc(
// fdPrestatDirName is the WASI function named functionFdPrestatDirName which
// returns the path of the pre-opened directory of a file descriptor.
//
// Parameters
// # Parameters
//
// - fd: file descriptor to get the path of the pre-opened directory
// - path: offset in api.Memory to write the result path
@@ -289,7 +289,7 @@ var fdPrestatGet = wasm.NewGoFunc(
// - ErrnoNametoolong: `pathLen` is longer than the actual length of the result
//
// For example, the directory name corresponding with `fd` was "/tmp" and
// parameters path=1 pathLen=4 (correct), this function will write the below to
// # Parameters path=1 pathLen=4 (correct), this function will write the below to
// api.Memory:
//
// pathLen
@@ -335,7 +335,7 @@ var fdPwrite = stubFunction(functionFdPwrite,
// fdRead is the WASI function named functionFdRead which reads from a file
// descriptor.
//
// Parameters
// # Parameters
//
// - fd: an opened file descriptor to read data from
// - iovs: offset in api.Memory to read offset, size pairs representing where
@@ -444,7 +444,7 @@ var fdRenumber = stubFunction(
// fdSeek is the WASI function named functionFdSeek which moves the offset of a
// file descriptor.
//
// Parameters
// # Parameters
//
// - fd: file descriptor to move the offset of
// - offset: signed int64, which is encoded as uint64, input argument to
@@ -531,7 +531,7 @@ var fdTell = stubFunction(
// fdWrite is the WASI function named functionFdWrite which writes to a file
// descriptor.
//
// Parameters
// # Parameters
//
// - fd: an opened file descriptor to write data to
// - iovs: offset in api.Memory to read offset, size pairs representing the
@@ -668,7 +668,7 @@ var pathLink = stubFunction(
// pathOpen is the WASI function named functionPathOpen which opens a file or
// directory. This returns ErrnoBadf if the fd is invalid.
//
// Parameters
// # Parameters
//
// - fd: file descriptor of a directory that `path` is relative to
// - dirflags: flags to indicate how to resolve `path`
@@ -713,7 +713,7 @@ var pathLink = stubFunction(
// []byte{ 0..6, ?, 5, 0, 0, 0, ?}
// resultOpenedFd --^
//
// Notes
// # Notes
// - This is similar to `openat` in POSIX. https://linux.die.net/man/3/openat
// - The returned file descriptor is not guaranteed to be the lowest-number
// - Rights will never be implemented per https://github.com/WebAssembly/WASI/issues/469#issuecomment-1045251844

View File

@@ -24,7 +24,7 @@ const (
// pollOneoff is the WASI function named functionPollOneoff that concurrently
// polls for the occurrence of a set of events.
//
// Parameters
// # Parameters
//
// - in: pointer to the subscriptions (48 bytes each)
// - out: pointer to the resulting events (32 bytes each)
@@ -39,7 +39,7 @@ const (
// - ErrnoFault: there is not enough memory to read the subscriptions or
// write results.
//
// Notes
// # Notes
//
// - Since the `out` pointer nests Errno, the result is always ErrnoSuccess.
// - importPollOneoff shows this signature in the WebAssembly 1.0 Text Format.

View File

@@ -17,7 +17,7 @@ const (
// execution of the module with an exit code. The only successful exit code is
// zero.
//
// Parameters
// # Parameters
//
// - exitCode: exit code.
//

View File

@@ -13,7 +13,7 @@ const functionRandomGet = "random_get"
// randomGet is the WASI function named functionRandomGet which writes random
// data to a buffer.
//
// Parameters
// # Parameters
//
// - buf: api.Memory offset to write random values
// - bufLen: size of random data in bytes

View File

@@ -33,7 +33,7 @@ const i32, i64 = wasm.ValueTypeI32, wasm.ValueTypeI64
// Instantiate instantiates the ModuleName module into the runtime default
// namespace.
//
// Notes
// # Notes
//
// - Closing the wazero.Runtime has the same effect as closing the result.
// - To instantiate into another wazero.Namespace, use NewBuilder instead.

View File

@@ -11,6 +11,7 @@ import (
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/api"
. "github.com/tetratelabs/wazero/experimental"
"github.com/tetratelabs/wazero/experimental/logging"
"github.com/tetratelabs/wazero/internal/testing/require"
)
@@ -36,7 +37,7 @@ func requireModule(t *testing.T, config wazero.ModuleConfig) (api.Module, api.Cl
var log bytes.Buffer
// Set context to one that has an experimental listener
ctx := context.WithValue(testCtx, FunctionListenerFactoryKey{}, NewLoggingListenerFactory(&log))
ctx := context.WithValue(testCtx, FunctionListenerFactoryKey{}, logging.NewLoggingListenerFactory(&log))
r := wazero.NewRuntimeWithConfig(wazero.NewRuntimeConfigInterpreter())
@@ -57,7 +58,7 @@ func requireErrnoNosys(t *testing.T, funcName string, params ...uint64) string {
var log bytes.Buffer
// Set context to one that has an experimental listener
ctx := context.WithValue(testCtx, FunctionListenerFactoryKey{}, NewLoggingListenerFactory(&log))
ctx := context.WithValue(testCtx, FunctionListenerFactoryKey{}, logging.NewLoggingListenerFactory(&log))
r := wazero.NewRuntimeWithConfig(wazero.NewRuntimeConfigInterpreter())
defer r.Close(ctx)