Appearance
Work with calls and state
Instance.InvokeValues checks typed arguments against the export signature and uses the supplied context for cancellation.
| Wasm type | Go argument | Read a result |
|---|---|---|
i32 | wago.ValueI32(v) | result.I32() |
i64 | wago.ValueI64(v) | result.I64() |
f32 | wago.ValueF32(v) | result.F32() |
f64 | wago.ValueF64(v) | result.F64() |
Use Invoke for raw ABI slots without a caller-supplied context, or InvokeContext when raw-slot execution also needs cancellation. Resolve repeated calls once with WasmFunc; its Invoke method accepts every arity and performs lifecycle admission for each call.
See instance state survive
Create counter.wat:
wat
(module
(global $count (export "count") (mut i32) (i32.const 0))
(func (export "inc") (result i32)
global.get $count
i32.const 1
i32.add
global.set $count
global.get $count))Compile it with WABT:
sh
wat2wasm counter.wat -o counter.wasmReplace main.go with:
go
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/wago-org/wago"
)
func run(ctx context.Context) error {
wasm, err := os.ReadFile("counter.wasm")
if err != nil { return err }
runtime := wago.NewRuntime()
defer runtime.Close()
module, err := runtime.Compile(wasm)
if err != nil { return err }; defer module.Close()
instance, err := runtime.Instantiate(ctx, module)
if err != nil { return err }; defer instance.Close()
for range 3 {
results, err := instance.InvokeValues(ctx, "inc")
if err != nil { return err }; fmt.Println(results[0].I32())
}
count, err := instance.GlobalValue("count")
if err != nil { return err }
fmt.Println("count:", count.I32())
if err := instance.SetGlobalValue("count", wago.ValueI32(40)); err != nil { return err }
results, err := instance.InvokeValues(ctx, "inc")
if err != nil { return err }; fmt.Println("after set:", results[0].I32())
fresh, err := runtime.Instantiate(ctx, module)
if err != nil { return err }; defer fresh.Close()
results, err = fresh.InvokeValues(ctx, "inc")
if err != nil { return err }; fmt.Println("fresh instance:", results[0].I32())
return nil
}
func main() {
if err := run(context.Background()); err != nil {
log.Fatal(err)
}
}sh
go run .text
1
2
3
count: 3
after set: 41
fresh instance: 1One instance preserves state and accepts one call at a time. A fresh instance starts with the module's initial state while reusing the same compiled code.
Read and write memory safely
Use checked copies for ordinary host access:
go
data, ok := instance.Read(offset, length)
if !ok {
return fmt.Errorf("guest memory range is out of bounds")
}
if ok := instance.Write(offset, replacement); !ok {
return fmt.Errorf("guest memory range is out of bounds")
}Read returns a copy. Write either copies the whole slice or changes nothing. Typed little-endian helpers such as ReadUint32Le and WriteUint32Le are available for scalar fields.
instance.Memory().UnsafeBytes() is a zero-copy mutable view. Use it only when you can keep the view inside a tightly controlled operation; never retain it after closing the instance.
