This renames `InstantiateModuleFromBinary` to `Instantiate` to both make first time use simpler to write and also de-complicate adding a `WithConfig` variant as requested in #1105 End users in simple case need to change their signature like so. ```diff - mod, err := r.InstantiateModuleFromBinary(ctx, addWasm) + mod, err := r.Instantiate(ctx, addWasm) ``` In practice, many will not need to change their signature because they had to use the `InstantiateModule` function in order to assign configuration such as the module name, filesystem or use a real clock. Instead, they had to use the more complicated chain of `CompileModule` and `InstantiateModule` even when only assigning config. Users in this situation can opt into the more simplified syntax below: ```go mod, err := r.InstantiateWithConfig(ctx, addWasm, wazero.NewModuleConfig().WithName("adder")) ``` ```diff - mod, err := r.InstantiateModuleFromBinary(ctx, addWasm) + mod, err := r.Instantiate(ctx, addWasm) ``` Signed-off-by: Adrian Cole <adrian@tetrate.io>
127 lines
4.2 KiB
Go
127 lines
4.2 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
_ "embed"
|
|
"fmt"
|
|
"log"
|
|
|
|
"github.com/tetratelabs/wazero"
|
|
"github.com/tetratelabs/wazero/api"
|
|
)
|
|
|
|
// main implements functions with multiple returns values, using both an
|
|
// approach portable with any WebAssembly 1.0 runtime, as well one dependent
|
|
// on the "multiple-results" feature.
|
|
//
|
|
// The portable approach uses parameters to return additional results. The
|
|
// parameter value is a memory offset to write the next value. This is the same
|
|
// approach used by WASI.
|
|
// - resultOffsetWasmFunctions
|
|
// - resultOffsetHostFunctions
|
|
//
|
|
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md
|
|
//
|
|
// Another approach is to enable the "multiple-results" feature. While
|
|
// "multiple-results" is not yet a W3C recommendation, most WebAssembly
|
|
// runtimes support it by default, and it is include in the draft of 2.0.
|
|
// - multiValueWasmFunctions
|
|
// - multiValueHostFunctions
|
|
//
|
|
// See https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/multi-value/Overview.md
|
|
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.
|
|
|
|
// Add a module that uses offset parameters for multiple results defined in WebAssembly.
|
|
wasm, err := resultOffsetWasmFunctions(ctx, r)
|
|
if err != nil {
|
|
log.Panicln(err)
|
|
}
|
|
|
|
// wazero enables WebAssembly Core Specification 2.0 features by default.
|
|
runtimeWithMultiValue := wazero.NewRuntime(ctx)
|
|
|
|
// Add a module that uses multiple results values
|
|
|
|
// ... defined in WebAssembly.
|
|
wasmWithMultiValue, err := multiValueWasmFunctions(ctx, runtimeWithMultiValue)
|
|
if err != nil {
|
|
log.Panicln(err)
|
|
}
|
|
|
|
// ... defined in Go.
|
|
multiValueFromImportedHost, err := multiValueFromImportedHostWasmFunctions(ctx, runtimeWithMultiValue)
|
|
if err != nil {
|
|
log.Panicln(err)
|
|
}
|
|
|
|
// Call the function from each module and print the results to the console.
|
|
for _, mod := range []api.Module{wasm, wasmWithMultiValue, multiValueFromImportedHost} {
|
|
getAge := mod.ExportedFunction("call_get_age")
|
|
results, err := getAge.Call(ctx)
|
|
if err != nil {
|
|
log.Panicln(err)
|
|
}
|
|
|
|
fmt.Printf("%s: age=%d\n", mod.Name(), results[0])
|
|
}
|
|
}
|
|
|
|
// resultOffsetWasm was generated by the following:
|
|
//
|
|
// cd testdata; wat2wasm --debug-names result_offset.wat
|
|
//
|
|
//go:embed testdata/result_offset.wasm
|
|
var resultOffsetWasm []byte
|
|
|
|
// resultOffsetWasmFunctions are the WebAssembly equivalent of the Go-defined
|
|
// resultOffsetHostFunctions. The source is in testdata/result_offset.wat
|
|
func resultOffsetWasmFunctions(ctx context.Context, r wazero.Runtime) (api.Module, error) {
|
|
return r.Instantiate(ctx, resultOffsetWasm)
|
|
}
|
|
|
|
// multiValueWasm was generated by the following:
|
|
//
|
|
// cd testdata; wat2wasm --debug-names multi_value.wat
|
|
//
|
|
//go:embed testdata/multi_value.wasm
|
|
var multiValueWasm []byte
|
|
|
|
// multiValueWasmFunctions are the WebAssembly equivalent of the Go-defined
|
|
// multiValueHostFunctions. The source is in testdata/multi_value.wat
|
|
func multiValueWasmFunctions(ctx context.Context, r wazero.Runtime) (api.Module, error) {
|
|
return r.Instantiate(ctx, multiValueWasm)
|
|
}
|
|
|
|
// multiValueWasm was generated by the following:
|
|
//
|
|
// cd testdata; wat2wasm --debug-names multi_value_imported.wat
|
|
//
|
|
//go:embed testdata/multi_value_imported.wasm
|
|
var multiValueFromImportedHostWasm []byte
|
|
|
|
// multiValueFromImportedHostWasmFunctions return the WebAssembly which imports the Go-defined "get_age" function.
|
|
// The imported "get_age" function returns multiple results. The source is in testdata/multi_value_imported.wat
|
|
func multiValueFromImportedHostWasmFunctions(ctx context.Context, r wazero.Runtime) (api.Module, error) {
|
|
// Instantiate the host module with the exported `get_age` function which returns multiple results.
|
|
if _, err := r.NewHostModuleBuilder("multi-value/host").
|
|
// Define a function that returns two results
|
|
NewFunctionBuilder().
|
|
WithFunc(func(context.Context) (age uint64, errno uint32) {
|
|
age = 37
|
|
errno = 0
|
|
return
|
|
}).
|
|
Export("get_age").
|
|
Instantiate(ctx); err != nil {
|
|
return nil, err
|
|
}
|
|
// Then, creates the module which imports the `get_age` function from the `multi-value/host` module above.
|
|
return r.Instantiate(ctx, multiValueFromImportedHostWasm)
|
|
}
|