Files
wazero/examples/namespace/counter.go
Crypt Keeper 429334cf98 Renames ModuleBuilder to HostModuleBuilder and drops memory and globals (#812)
We at one point considered making `ModuleBuilder` create complete
WebAssembly binaries. However, we recently spun out
[wabin](https://github.com/tetratelabs/wabin), which allows this.

Meanwhile, the features in `ModuleBuilder` were confusing and misused.
For example, the only two cases memory was exported on GitHub were done
by accident. This is because host functions act on the guest's memory,
not their own.

Hence, this removes memory and globals from host side definitions, and
renames the type to HostModuleBuilder to clarify this is not ever going
to be used to construct normal Wasm binaries.

Most importantly, this simplifies the API and reduces a lot of code. It
is important to make changes like this, particularly deleting any
experimental things that didn't end up useful.

Signed-off-by: Adrian Cole <adrian@tetrate.io>
Co-authored-by: Anuraag Agrawal <anuraaga@gmail.com>
2022-09-28 14:42:14 +08:00

89 lines
2.3 KiB
Go

package main
import (
"context"
_ "embed"
"fmt"
"log"
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/api"
)
// counterWasm was generated by the following:
//
// cd testdata; wat2wasm --debug-names counter.wat
//
//go:embed testdata/counter.wasm
var counterWasm []byte
// main shows how to instantiate the same module name multiple times in the same runtime.
//
// See README.md for a full description.
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.
// Compile WebAssembly that requires its own "env" module.
compiled, err := r.CompileModule(ctx, counterWasm, wazero.NewCompileConfig())
if err != nil {
log.Panicln(err)
}
// Instantiate two modules, with identical configuration, but independent state.
m1 := instantiateWithEnv(ctx, r, compiled)
m2 := instantiateWithEnv(ctx, r, compiled)
for i := 0; i < 2; i++ {
fmt.Printf("m1 counter=%d\n", counterGet(ctx, m1))
fmt.Printf("m2 counter=%d\n", counterGet(ctx, m2))
}
}
// count calls "counter.get" in the given namespace
func counterGet(ctx context.Context, mod api.Module) uint64 {
results, err := mod.ExportedFunction("get").Call(ctx)
if err != nil {
log.Panicln(err)
}
return results[0]
}
// counter is an example showing state that needs to be independent per importing module.
type counter struct {
counter uint32
}
func (e *counter) getAndIncrement() (ret uint32) {
ret = e.counter
e.counter++
return
}
// instantiateWithEnv returns a module instantiated with its own "env" module.
func instantiateWithEnv(ctx context.Context, r wazero.Runtime, module wazero.CompiledModule) api.Module {
// Create a new namespace to instantiate modules into.
ns := r.NewNamespace(ctx) // Note: this is closed when the Runtime is
// Instantiate a new "env" module which exports a stateful function.
c := &counter{}
_, err := r.NewHostModuleBuilder("env").
ExportFunction("next_i32", c.getAndIncrement).
Instantiate(ctx, ns)
if err != nil {
log.Panicln(err)
}
// Instantiate the module that imports "env".
mod, err := ns.InstantiateModule(ctx, module, wazero.NewModuleConfig())
if err != nil {
log.Panicln(err)
}
return mod
}