blob: 749c3771d5bb3064bef49853e7369322fbbb0bbf [file] [log] [blame]
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// A program for testing wasmexport.
// This is the driver/host program, which provides the imports
// and calls the exports. testprog is the source of the Wasm
// module, which can be compiled to either an executable or a
// library.
//
// To build it as executable:
// GOARCH=wasm GOOS=wasip1 go build -o /tmp/x.wasm ./testprog
//
// To build it as a library:
// GOARCH=wasm GOOS=wasip1 go build -buildmode=c-shared -o /tmp/x.wasm ./testprog
//
// Then run the driver (which works for both modes):
// go run w.go /tmp/x.wasm
package main
import (
"bytes"
"context"
"fmt"
"io"
"os"
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
)
// exported from wasm
var E func(a int64, b int32, c float64, d float32)
var F func() int64
var G func(int32)
func I() int64 {
println("I start")
E(20, 3, 0.4, 0.05)
r := F() * 2
G(4)
println("I end =", r)
return r
}
func J(x int32) {
println("J", x)
if x > 0 {
G(x)
}
println("J", x, "end")
}
var errbuf bytes.Buffer
var stderr = io.MultiWriter(os.Stderr, &errbuf)
func main() {
ctx := context.Background()
r := wazero.NewRuntime(ctx)
defer r.Close(ctx)
// provide import functions from host
_, err := r.NewHostModuleBuilder("test").
NewFunctionBuilder().WithFunc(I).Export("I").
NewFunctionBuilder().WithFunc(J).Export("J").
Instantiate(ctx)
if err != nil {
panic(err)
}
buf, err := os.ReadFile(os.Args[1])
if err != nil {
panic(err)
}
config := wazero.NewModuleConfig().
WithStdout(os.Stdout).WithStderr(stderr).
WithStartFunctions() // don't call _start
wasi_snapshot_preview1.MustInstantiate(ctx, r)
m, err := r.InstantiateWithConfig(ctx, buf, config)
if err != nil {
panic(err)
}
// get export functions from the module
E = func(a int64, b int32, c float64, d float32) {
exp := m.ExportedFunction("E")
_, err := exp.Call(ctx, api.EncodeI64(a), api.EncodeI32(b), api.EncodeF64(c), api.EncodeF32(d))
if err != nil {
panic(err)
}
}
F = func() int64 {
exp := m.ExportedFunction("F")
r, err := exp.Call(ctx)
if err != nil {
panic(err)
}
rr := int64(r[0])
println("host: F =", rr)
return rr
}
G = func(x int32) {
exp := m.ExportedFunction("G")
_, err := exp.Call(ctx, api.EncodeI32(x))
if err != nil {
panic(err)
}
}
entry := m.ExportedFunction("_start")
if entry != nil {
// Executable mode.
fmt.Println("Executable mode: start")
_, err := entry.Call(ctx)
fmt.Println(err)
return
}
// Library mode.
fmt.Println("Libaray mode: call export before initialization")
shouldPanic(func() { I() })
// reset module
m, err = r.InstantiateWithConfig(ctx, buf, config)
if err != nil {
panic(err)
}
fmt.Println("Library mode: initialize")
entry = m.ExportedFunction("_initialize")
_, err = entry.Call(ctx)
if err != nil {
panic(err)
}
fmt.Println("\nLibrary mode: call export functions")
I()
}
func shouldPanic(f func()) {
defer func() {
e := recover()
if e == nil {
panic("did not panic")
}
if !bytes.Contains(errbuf.Bytes(), []byte("runtime: wasmexport function called before runtime initialization")) {
panic("expected error message missing")
}
}()
f()
}