Files
wazero/examples/multiple-results/multiple-results.go
Crypt Keeper 8abe345249 Elaborates impact of GOWASM variable when compiling Go (#785)
Thanks to @inkeliz for the pointer!

Signed-off-by: Adrian Cole <adrian@tetrate.io>
2022-08-31 12:21:34 +08:00

127 lines
4.4 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 1.0 by default. Opt-in to other features:
runtimeWithMultiValue := wazero.NewRuntimeWithConfig(
ctx, wazero.NewRuntimeConfig().WithFeatureMultiValue(true),
// ^^ Note: WebAssembly 2.0 (WithWasmCore2) includes "multi-value".
)
// 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.InstantiateModuleFromBinary(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.InstantiateModuleFromBinary(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.NewModuleBuilder("multi-value/host").
// Define a function that returns two results
ExportFunction("get_age", func() (age uint64, errno uint32) {
age = 37
errno = 0
return
}).Instantiate(ctx, r); err != nil {
return nil, err
}
// Then, creates the module which imports the `get_age` function from the `multi-value/host` module above.
return r.InstantiateModuleFromBinary(ctx, multiValueFromImportedHostWasm)
}