Makes all examples and docs use Runtime.Close (#537)
This removes tedium in our examples and docs by using `Runtime.Close` instead of tracking everything. Internal tests still track too much, but anyway at least this stops suggesting others should do it. This also changes our examples to use log.PanicXX so that the line number goes into the console output. Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
27
README.md
27
README.md
@@ -24,11 +24,20 @@ func main() {
|
||||
|
||||
// Read a WebAssembly binary containing an exported "fac" function.
|
||||
// * Ex. (func (export "fac") (param i64) (result i64) ...
|
||||
source, _ := os.ReadFile("./path/to/fac.wasm")
|
||||
source, err := os.ReadFile("./path/to/fac.wasm")
|
||||
if err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
// Create a new WebAssembly Runtime.
|
||||
r := wazero.NewRuntime()
|
||||
defer r.Close(ctx) // This closes everything this Runtime created.
|
||||
|
||||
// Instantiate the module and return its exported functions
|
||||
module, _ := wazero.NewRuntime().InstantiateModuleFromCode(ctx, source)
|
||||
defer module.Close(ctx)
|
||||
module, err := r.InstantiateModuleFromCode(ctx, source)
|
||||
if err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
// Discover 7! is 5040
|
||||
fmt.Println(module.ExportedFunction("fac").Call(ctx, 7))
|
||||
@@ -57,15 +66,14 @@ For example, you can grant WebAssembly code access to your console by exporting
|
||||
a function written in Go. The below function can be imported into standard
|
||||
WebAssembly as the module "env" and the function name "log_i32".
|
||||
```go
|
||||
env, err := r.NewModuleBuilder("env").
|
||||
_, err := r.NewModuleBuilder("env").
|
||||
ExportFunction("log_i32", func(v uint32) {
|
||||
fmt.Println("log_i32 >>", v)
|
||||
}).
|
||||
Instantiate(ctx)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer env.Close(ctx)
|
||||
```
|
||||
|
||||
The WebAssembly community has [subgroups][4] which maintain work that may not
|
||||
@@ -78,12 +86,13 @@ bundles an implementation. That way, you don't have to write these functions.
|
||||
For example, here's how you can allow WebAssembly modules to read
|
||||
"/work/home/a.txt" as "/a.txt" or "./a.txt":
|
||||
```go
|
||||
wm, err := wasi.InstantiateSnapshotPreview1(ctx, r)
|
||||
defer wm.Close(ctx)
|
||||
_, err := wasi.InstantiateSnapshotPreview1(ctx, r)
|
||||
if err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
config := wazero.NewModuleConfig().WithFS(os.DirFS("/work/home"))
|
||||
module, err := r.InstantiateModule(ctx, compiled, config)
|
||||
defer module.Close(ctx)
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
@@ -105,6 +105,7 @@ func ValueTypeName(t ValueType) string {
|
||||
|
||||
// Module return functions exported in a module, post-instantiation.
|
||||
//
|
||||
// Note: Closing the wazero.Runtime closes any Module it instantiated.
|
||||
// Note: This is an interface for decoupling, not third-party implementations. All implementations are in wazero.
|
||||
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#external-types%E2%91%A0
|
||||
type Module interface {
|
||||
|
||||
@@ -15,6 +15,9 @@ import (
|
||||
// Ex. Below defines and instantiates a module named "env" with one function:
|
||||
//
|
||||
// ctx := context.Background()
|
||||
// r := wazero.NewRuntime()
|
||||
// defer r.Close(ctx) // This closes everything this Runtime created.
|
||||
//
|
||||
// hello := func() {
|
||||
// fmt.Fprintln(stdout, "hello!")
|
||||
// }
|
||||
@@ -29,10 +32,8 @@ import (
|
||||
// Compile(ctx, wazero.NewCompileConfig())
|
||||
//
|
||||
// env1, _ := r.InstantiateModule(ctx, compiled, wazero.NewModuleConfig().WithName("env.1"))
|
||||
// defer env1.Close(ctx)
|
||||
//
|
||||
// env2, _ := r.InstantiateModule(ctx, compiled, wazero.NewModuleConfig().WithName("env.2"))
|
||||
// defer env2.Close(ctx)
|
||||
//
|
||||
// Notes:
|
||||
// * ModuleBuilder is mutable. WithXXX functions return the same instance for chaining.
|
||||
@@ -157,10 +158,13 @@ type ModuleBuilder interface {
|
||||
ExportGlobalF64(name string, v float64) ModuleBuilder
|
||||
|
||||
// Compile returns a module to instantiate, or an error if any of the configuration is invalid.
|
||||
//
|
||||
// Note: Closing the wazero.Runtime closes any CompiledModule it compiled.
|
||||
Compile(context.Context, CompileConfig) (CompiledModule, error)
|
||||
|
||||
// Instantiate is a convenience that calls Build, then Runtime.InstantiateModule, using default configuration.
|
||||
//
|
||||
// Note: Closing the wazero.Runtime closes any api.Module it instantiated.
|
||||
// Note: Fields in the builder are copied during instantiation: Later changes do not affect the instantiated result.
|
||||
// Note: To avoid using configuration defaults, use Compile instead.
|
||||
Instantiate(context.Context) (api.Module, error)
|
||||
|
||||
@@ -218,6 +218,7 @@ func (c *runtimeConfig) WithWasmCore2() RuntimeConfig {
|
||||
|
||||
// CompiledModule is a WebAssembly 1.0 module ready to be instantiated (Runtime.InstantiateModule) as an api.Module.
|
||||
//
|
||||
// Note: Closing the wazero.Runtime closes any CompiledModule it compiled.
|
||||
// Note: In WebAssembly language, this is a decoded, validated, and possibly also compiled module. wazero avoids using
|
||||
// the name "Module" for both before and after instantiation as the name conflation has caused confusion.
|
||||
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#semantic-phases%E2%91%A0
|
||||
|
||||
@@ -27,7 +27,7 @@ func Example() {
|
||||
(export "add" (func $add))
|
||||
)`))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer mod.Close(ctx)
|
||||
|
||||
@@ -37,7 +37,7 @@ func Example() {
|
||||
x, y := uint64(1), uint64(2)
|
||||
results, err := add.Call(ctx, x, y)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
fmt.Printf("%s: %d + %d = %d\n", mod.Name(), x, y, results[0])
|
||||
|
||||
@@ -25,24 +25,23 @@ func main() {
|
||||
|
||||
// Create a new WebAssembly Runtime.
|
||||
r := wazero.NewRuntime()
|
||||
defer r.Close(ctx) // This closes everything this Runtime created.
|
||||
|
||||
// Instantiate a Go-defined module named "env" that exports a function to
|
||||
// log to the console.
|
||||
env, err := r.NewModuleBuilder("env").
|
||||
_, err := r.NewModuleBuilder("env").
|
||||
ExportFunction("log", logString).
|
||||
Instantiate(ctx)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer env.Close(ctx)
|
||||
|
||||
// Instantiate a WebAssembly module that imports the "log" function defined
|
||||
// in "env" and exports "memory" and functions we'll use in this example.
|
||||
mod, err := r.InstantiateModuleFromCode(ctx, greetWasm)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer mod.Close(ctx)
|
||||
|
||||
// Get references to WebAssembly functions we'll use in this example.
|
||||
greet := mod.ExportedFunction("greet")
|
||||
@@ -59,7 +58,7 @@ func main() {
|
||||
// function could be used to pass binary serialized data to Wasm.
|
||||
results, err := allocate.Call(ctx, nameSize)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
namePtr := results[0]
|
||||
// This pointer was allocated by Rust, but owned by Go, So, we have to
|
||||
@@ -68,21 +67,21 @@ func main() {
|
||||
|
||||
// The pointer is a linear memory offset, which is where we write the name.
|
||||
if !mod.Memory().Write(ctx, uint32(namePtr), []byte(name)) {
|
||||
log.Fatalf("Memory.Write(%d, %d) out of range of memory size %d",
|
||||
log.Panicf("Memory.Write(%d, %d) out of range of memory size %d",
|
||||
namePtr, nameSize, mod.Memory().Size(ctx))
|
||||
}
|
||||
|
||||
// Now, we can call "greet", which reads the string we wrote to memory!
|
||||
_, err = greet.Call(ctx, namePtr, nameSize)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
// Finally, we get the greeting message "greet" printed. This shows how to
|
||||
// read-back something allocated by Rust.
|
||||
ptrSize, err := greeting.Call(ctx, namePtr, nameSize)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
greetingPtr := uint32(ptrSize[0] >> 32)
|
||||
greetingSize := uint32(ptrSize[0])
|
||||
@@ -92,7 +91,7 @@ func main() {
|
||||
|
||||
// The pointer is a linear memory offset, which is where we write the name.
|
||||
if bytes, ok := mod.Memory().Read(ctx, greetingPtr, greetingSize); !ok {
|
||||
log.Fatalf("Memory.Read(%d, %d) out of range of memory size %d",
|
||||
log.Panicf("Memory.Read(%d, %d) out of range of memory size %d",
|
||||
greetingPtr, greetingSize, mod.Memory().Size(ctx))
|
||||
} else {
|
||||
fmt.Println("go >>", string(bytes))
|
||||
@@ -102,7 +101,7 @@ func main() {
|
||||
func logString(ctx context.Context, m api.Module, offset, byteCount uint32) {
|
||||
buf, ok := m.Memory().Read(ctx, offset, byteCount)
|
||||
if !ok {
|
||||
log.Fatalf("Memory.Read(%d, %d) out of range", offset, byteCount)
|
||||
log.Panicf("Memory.Read(%d, %d) out of range", offset, byteCount)
|
||||
}
|
||||
fmt.Println(string(buf))
|
||||
}
|
||||
|
||||
@@ -26,32 +26,29 @@ func main() {
|
||||
|
||||
// Create a new WebAssembly Runtime.
|
||||
r := wazero.NewRuntime()
|
||||
defer r.Close(ctx) // This closes everything this Runtime created.
|
||||
|
||||
// Instantiate a Go-defined module named "env" that exports a function to
|
||||
// log to the console.
|
||||
env, err := r.NewModuleBuilder("env").
|
||||
_, err := r.NewModuleBuilder("env").
|
||||
ExportFunction("log", logString).
|
||||
Instantiate(ctx)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer env.Close(ctx)
|
||||
|
||||
// Note: testdata/greet.go doesn't use WASI, but TinyGo needs it to
|
||||
// implement functions such as panic.
|
||||
wm, err := wasi.InstantiateSnapshotPreview1(ctx, r)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
if _, err = wasi.InstantiateSnapshotPreview1(ctx, r); err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer wm.Close(ctx)
|
||||
|
||||
// Instantiate a WebAssembly module that imports the "log" function defined
|
||||
// in "env" and exports "memory" and functions we'll use in this example.
|
||||
mod, err := r.InstantiateModuleFromCode(ctx, greetWasm)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer mod.Close(ctx)
|
||||
|
||||
// Get references to WebAssembly functions we'll use in this example.
|
||||
greet := mod.ExportedFunction("greet")
|
||||
@@ -69,7 +66,7 @@ func main() {
|
||||
// function could be used to pass binary serialized data to Wasm.
|
||||
results, err := malloc.Call(ctx, nameSize)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
namePtr := results[0]
|
||||
// This pointer is managed by TinyGo, but TinyGo is unaware of external usage.
|
||||
@@ -78,28 +75,28 @@ func main() {
|
||||
|
||||
// The pointer is a linear memory offset, which is where we write the name.
|
||||
if !mod.Memory().Write(ctx, uint32(namePtr), []byte(name)) {
|
||||
log.Fatalf("Memory.Write(%d, %d) out of range of memory size %d",
|
||||
log.Panicf("Memory.Write(%d, %d) out of range of memory size %d",
|
||||
namePtr, nameSize, mod.Memory().Size(ctx))
|
||||
}
|
||||
|
||||
// Now, we can call "greet", which reads the string we wrote to memory!
|
||||
_, err = greet.Call(ctx, namePtr, nameSize)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
// Finally, we get the greeting message "greet" printed. This shows how to
|
||||
// read-back something allocated by TinyGo.
|
||||
ptrSize, err := greeting.Call(ctx, namePtr, nameSize)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
// Note: This pointer is still owned by TinyGo, so don't try to free it!
|
||||
greetingPtr := uint32(ptrSize[0] >> 32)
|
||||
greetingSize := uint32(ptrSize[0])
|
||||
// The pointer is a linear memory offset, which is where we write the name.
|
||||
if bytes, ok := mod.Memory().Read(ctx, greetingPtr, greetingSize); !ok {
|
||||
log.Fatalf("Memory.Read(%d, %d) out of range of memory size %d",
|
||||
log.Panicf("Memory.Read(%d, %d) out of range of memory size %d",
|
||||
greetingPtr, greetingSize, mod.Memory().Size(ctx))
|
||||
} else {
|
||||
fmt.Println("go >>", string(bytes))
|
||||
@@ -109,7 +106,7 @@ func main() {
|
||||
func logString(ctx context.Context, m api.Module, offset, byteCount uint32) {
|
||||
buf, ok := m.Memory().Read(ctx, offset, byteCount)
|
||||
if !ok {
|
||||
log.Fatalf("Memory.Read(%d, %d) out of range", offset, byteCount)
|
||||
log.Panicf("Memory.Read(%d, %d) out of range", offset, byteCount)
|
||||
}
|
||||
fmt.Println(string(buf))
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ func main() {
|
||||
|
||||
// Create a new WebAssembly Runtime.
|
||||
r := wazero.NewRuntime()
|
||||
defer r.Close(ctx) // This closes everything this Runtime created.
|
||||
|
||||
// Add a module to the runtime named "wasm/math" which exports one function "add", implemented in WebAssembly.
|
||||
wasm, err := r.InstantiateModuleFromCode(ctx, []byte(`(module $wasm/math
|
||||
@@ -30,9 +31,8 @@ func main() {
|
||||
(export "add" (func $add))
|
||||
)`))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer wasm.Close(ctx)
|
||||
|
||||
// Add a module to the runtime named "host/math" which exports one function "add", implemented in Go.
|
||||
host, err := r.NewModuleBuilder("host/math").
|
||||
@@ -40,9 +40,8 @@ func main() {
|
||||
return v1 + v2
|
||||
}).Instantiate(ctx)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer host.Close(ctx)
|
||||
|
||||
// Read two args to add.
|
||||
x, y := readTwoArgs()
|
||||
@@ -52,7 +51,7 @@ func main() {
|
||||
add := mod.ExportedFunction("add")
|
||||
results, err := add.Call(ctx, x, y)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
fmt.Printf("%s: %d + %d = %d\n", mod.Name(), x, y, results[0])
|
||||
@@ -62,12 +61,12 @@ func main() {
|
||||
func readTwoArgs() (uint64, uint64) {
|
||||
x, err := strconv.ParseUint(os.Args[1], 10, 64)
|
||||
if err != nil {
|
||||
log.Fatalf("invalid arg %v: %v", os.Args[1], err)
|
||||
log.Panicf("invalid arg %v: %v", os.Args[1], err)
|
||||
}
|
||||
|
||||
y, err := strconv.ParseUint(os.Args[2], 10, 64)
|
||||
if err != nil {
|
||||
log.Fatalf("invalid arg %v: %v", os.Args[2], err)
|
||||
log.Panicf("invalid arg %v: %v", os.Args[2], err)
|
||||
}
|
||||
return x, y
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ func main() {
|
||||
|
||||
// Create a new WebAssembly Runtime.
|
||||
r := wazero.NewRuntime()
|
||||
defer r.Close(ctx) // This closes everything this Runtime created.
|
||||
|
||||
// Instantiate a Go-defined module named "env" that exports functions to
|
||||
// get the current year and log to the console.
|
||||
@@ -30,7 +31,7 @@ func main() {
|
||||
// constrained to a subset of numeric types.
|
||||
// Note: "env" is a module name conventionally used for arbitrary
|
||||
// host-defined functions, but any name would do.
|
||||
env, err := r.NewModuleBuilder("env").
|
||||
_, err := r.NewModuleBuilder("env").
|
||||
ExportFunction("log_i32", func(v uint32) {
|
||||
fmt.Println("log_i32 >>", v)
|
||||
}).
|
||||
@@ -42,9 +43,8 @@ func main() {
|
||||
}).
|
||||
Instantiate(ctx)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer env.Close(ctx)
|
||||
|
||||
// Instantiate a WebAssembly module named "age-calculator" that imports
|
||||
// functions defined in "env".
|
||||
@@ -85,26 +85,25 @@ func main() {
|
||||
)`))
|
||||
// ^^ Note: wazero's text compiler is incomplete #59. We are using it anyway to keep this example dependency free.
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer ageCalculator.Close(ctx)
|
||||
|
||||
// Read the birthYear from the arguments to main
|
||||
birthYear, err := strconv.ParseUint(os.Args[1], 10, 64)
|
||||
if err != nil {
|
||||
log.Fatalf("invalid arg %v: %v", os.Args[1], err)
|
||||
log.Panicf("invalid arg %v: %v", os.Args[1], err)
|
||||
}
|
||||
|
||||
// First, try calling the "get_age" function and printing to the console externally.
|
||||
results, err := ageCalculator.ExportedFunction("get_age").Call(ctx, birthYear)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
fmt.Println("println >>", results[0])
|
||||
|
||||
// First, try calling the "log_age" function and printing to the console externally.
|
||||
_, err = ageCalculator.ExportedFunction("log_age").Call(ctx, birthYear)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,21 +29,20 @@ func main() {
|
||||
ctx := context.Background()
|
||||
|
||||
// Create a new WebAssembly Runtime.
|
||||
runtime := wazero.NewRuntime()
|
||||
r := wazero.NewRuntime()
|
||||
defer r.Close(ctx) // This closes everything this Runtime created.
|
||||
|
||||
// Add a module that uses offset parameters for multiple results, with functions defined in WebAssembly.
|
||||
wasm, err := resultOffsetWasmFunctions(ctx, runtime)
|
||||
wasm, err := resultOffsetWasmFunctions(ctx, r)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer wasm.Close(ctx)
|
||||
|
||||
// Add a module that uses offset parameters for multiple results, with functions defined in Go.
|
||||
host, err := resultOffsetHostFunctions(ctx, runtime)
|
||||
host, err := resultOffsetHostFunctions(ctx, r)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer host.Close(ctx)
|
||||
|
||||
// wazero enables only W3C recommended features by default. Opt-in to other features like so:
|
||||
runtimeWithMultiValue := wazero.NewRuntimeWithConfig(
|
||||
@@ -54,23 +53,21 @@ func main() {
|
||||
// Add a module that uses multiple results values, with functions defined in WebAssembly.
|
||||
wasmWithMultiValue, err := multiValueWasmFunctions(ctx, runtimeWithMultiValue)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer wasmWithMultiValue.Close(ctx)
|
||||
|
||||
// Add a module that uses multiple results values, with functions defined in Go.
|
||||
hostWithMultiValue, err := multiValueHostFunctions(ctx, runtimeWithMultiValue)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer hostWithMultiValue.Close(ctx)
|
||||
|
||||
// Call the same function in all modules and print the results to the console.
|
||||
for _, mod := range []api.Module{wasm, host, wasmWithMultiValue, hostWithMultiValue} {
|
||||
getAge := mod.ExportedFunction("call_get_age")
|
||||
results, err := getAge.Call(ctx)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
fmt.Printf("%s: age=%d\n", mod.Name(), results[0])
|
||||
|
||||
@@ -18,6 +18,7 @@ func main() {
|
||||
|
||||
// Create a new WebAssembly Runtime.
|
||||
r := wazero.NewRuntime()
|
||||
defer r.Close(ctx) // This closes everything this Runtime created.
|
||||
|
||||
// Instantiate a Go-defined module named "assemblyscript" that exports a
|
||||
// function to close the module that calls "abort".
|
||||
@@ -26,7 +27,7 @@ func main() {
|
||||
_ = m.CloseWithExitCode(ctx, 255)
|
||||
}).Instantiate(ctx)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer host.Close(ctx)
|
||||
|
||||
@@ -45,14 +46,14 @@ func main() {
|
||||
(export "abort" (func 0)) ;; exports the import for testing
|
||||
)`), compileConfig)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer code.Close(ctx)
|
||||
|
||||
// Instantiate the WebAssembly module.
|
||||
mod, err := r.InstantiateModule(ctx, code, wazero.NewModuleConfig())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer mod.Close(ctx)
|
||||
|
||||
|
||||
@@ -30,36 +30,32 @@ func main() {
|
||||
|
||||
// Create a new WebAssembly Runtime.
|
||||
r := wazero.NewRuntime()
|
||||
defer r.Close(ctx) // This closes everything this Runtime created.
|
||||
|
||||
// Since wazero uses fs.FS, we can use standard libraries to do things like trim the leading path.
|
||||
rooted, err := fs.Sub(catFS, "testdata")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
// Combine the above into our baseline config, overriding defaults (which discard stdout and have no file system).
|
||||
config := wazero.NewModuleConfig().WithStdout(os.Stdout).WithFS(rooted)
|
||||
|
||||
// Instantiate WASI, which implements system I/O such as console output.
|
||||
wm, err := wasi.InstantiateSnapshotPreview1(ctx, r)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
if _, err = wasi.InstantiateSnapshotPreview1(ctx, r); err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer wm.Close(ctx)
|
||||
|
||||
// Compile the WebAssembly module using the default configuration.
|
||||
code, err := r.CompileModule(ctx, catWasm, wazero.NewCompileConfig())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer code.Close(ctx)
|
||||
|
||||
// InstantiateModule runs the "_start" function which is what TinyGo compiles "main" to.
|
||||
// * Set the program name (arg[0]) to "wasi" and add args to write "test.txt" to stdout twice.
|
||||
// * We use "/test.txt" or "./test.txt" because WithFS by default maps the workdir "." to "/".
|
||||
cat, err := r.InstantiateModule(ctx, code, config.WithArgs("wasi", os.Args[1]))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
if _, err = r.InstantiateModule(ctx, code, config.WithArgs("wasi", os.Args[1])); err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer cat.Close(ctx)
|
||||
}
|
||||
|
||||
@@ -60,11 +60,11 @@ func Example_listener() {
|
||||
ctx := context.WithValue(context.Background(), experimental.FunctionListenerFactoryKey{}, &loggerFactory{})
|
||||
|
||||
r := wazero.NewRuntimeWithConfig(wazero.NewRuntimeConfigInterpreter())
|
||||
wm, err := wasi.InstantiateSnapshotPreview1(ctx, r)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
defer r.Close(ctx) // This closes everything this Runtime created.
|
||||
|
||||
if _, err := wasi.InstantiateSnapshotPreview1(ctx, r); err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer wm.Close(ctx)
|
||||
|
||||
// Compile the WebAssembly module using the default configuration.
|
||||
code, err := r.CompileModule(ctx, []byte(`(module $listener
|
||||
@@ -75,15 +75,13 @@ func Example_listener() {
|
||||
(start 1) ;; call the second function
|
||||
)`), wazero.NewCompileConfig())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer code.Close(ctx)
|
||||
|
||||
mod, err := r.InstantiateModule(ctx, code, wazero.NewModuleConfig().WithStdout(os.Stdout))
|
||||
_, err = r.InstantiateModule(ctx, code, wazero.NewModuleConfig().WithStdout(os.Stdout))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer mod.Close(ctx)
|
||||
|
||||
// Output:
|
||||
// >> listener.[1]
|
||||
|
||||
@@ -37,11 +37,11 @@ func Example_sys() {
|
||||
ctx := context.WithValue(context.Background(), experimental.SysKey{}, &fakeSys{})
|
||||
|
||||
r := wazero.NewRuntimeWithConfig(wazero.NewRuntimeConfigInterpreter())
|
||||
wm, err := wasi.InstantiateSnapshotPreview1(ctx, r)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
defer r.Close(ctx) // This closes everything this Runtime created.
|
||||
|
||||
if _, err := wasi.InstantiateSnapshotPreview1(ctx, r); err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer wm.Close(ctx)
|
||||
|
||||
code, err := r.CompileModule(ctx, []byte(`(module
|
||||
(import "wasi_snapshot_preview1" "random_get"
|
||||
@@ -51,19 +51,17 @@ func Example_sys() {
|
||||
(start 1) ;; call the second function
|
||||
)`), wazero.NewCompileConfig())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer code.Close(ctx)
|
||||
|
||||
mod, err := r.InstantiateModule(ctx, code, wazero.NewModuleConfig().WithStdout(os.Stdout))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer mod.Close(ctx)
|
||||
|
||||
// Try to read 4 bytes of random data.
|
||||
if bytes, ok := mod.Memory().Read(ctx, 0, 4); !ok {
|
||||
log.Fatalf("Memory.Read(0, 4) out of range of memory size %d", mod.Memory().Size(ctx))
|
||||
log.Panicf("Memory.Read(0, 4) out of range of memory size %d", mod.Memory().Size(ctx))
|
||||
} else {
|
||||
fmt.Println(hex.EncodeToString(bytes))
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ func Example() {
|
||||
// Instantiate WASI, which implements system I/O such as console output.
|
||||
wm, err := InstantiateSnapshotPreview1(ctx, r)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer wm.Close(testCtx)
|
||||
|
||||
@@ -40,7 +40,7 @@ func Example() {
|
||||
)
|
||||
`), wazero.NewCompileConfig())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer code.Close(ctx)
|
||||
|
||||
|
||||
10
wasi/wasi.go
10
wasi/wasi.go
@@ -26,7 +26,17 @@ const ModuleSnapshotPreview1 = "wasi_snapshot_preview1"
|
||||
|
||||
// InstantiateSnapshotPreview1 instantiates ModuleSnapshotPreview1, so that other modules can import them.
|
||||
//
|
||||
// Ex. If your source (%.wasm binary) includes an import "wasi_snapshot_preview1", call InstantiateSnapshotPreview1
|
||||
// prior to instantiating it. Otherwise, it will error due to missing imports.
|
||||
// ctx := context.Background()
|
||||
// r := wazero.NewRuntime()
|
||||
// defer r.Close(ctx) // This closes everything this Runtime created.
|
||||
//
|
||||
// _, _ = wasi.InstantiateSnapshotPreview1(ctx, r)
|
||||
// mod, _ := r.InstantiateModuleFromCode(ctx, source)
|
||||
//
|
||||
// Note: All WASI functions return a single Errno result, ErrnoSuccess on success.
|
||||
// Note: Closing the wazero.Runtime closes any api.Module it instantiated.
|
||||
func InstantiateSnapshotPreview1(ctx context.Context, r wazero.Runtime) (api.Module, error) {
|
||||
_, fns := snapshotPreview1Functions(ctx)
|
||||
return r.NewModuleBuilder(ModuleSnapshotPreview1).ExportFunctions(fns).Instantiate(ctx)
|
||||
|
||||
27
wasm.go
27
wasm.go
@@ -16,11 +16,12 @@ import (
|
||||
|
||||
// Runtime allows embedding of WebAssembly modules.
|
||||
//
|
||||
// Ex.
|
||||
// Ex. The below is the basic initialization of wazero's WebAssembly Runtime.
|
||||
// ctx := context.Background()
|
||||
// r := wazero.NewRuntime()
|
||||
// defer r.Close(ctx) // This closes everything this Runtime created.
|
||||
//
|
||||
// module, _ := r.InstantiateModuleFromCode(ctx, source)
|
||||
// defer module.Close()
|
||||
type Runtime interface {
|
||||
// NewModuleBuilder lets you create modules out of functions defined in Go.
|
||||
//
|
||||
@@ -52,8 +53,10 @@ type Runtime interface {
|
||||
//
|
||||
// Ex.
|
||||
// ctx := context.Background()
|
||||
// module, _ := wazero.NewRuntime().InstantiateModuleFromCode(ctx, source)
|
||||
// defer module.Close()
|
||||
// r := wazero.NewRuntime()
|
||||
// defer r.Close(ctx) // This closes everything this Runtime created.
|
||||
//
|
||||
// module, _ := r.InstantiateModuleFromCode(ctx, source)
|
||||
//
|
||||
// Note: When the context is nil, it defaults to context.Background.
|
||||
// Note: This is a convenience utility that chains CompileModule with InstantiateModule. To instantiate the same
|
||||
@@ -66,10 +69,10 @@ type Runtime interface {
|
||||
// Ex.
|
||||
// ctx := context.Background()
|
||||
// r := wazero.NewRuntime()
|
||||
// defer r.Close(ctx) // This closes everything this Runtime created.
|
||||
//
|
||||
// compiled, _ := r.CompileModule(ctx, source, wazero.NewCompileConfig())
|
||||
// defer compiled.Close()
|
||||
// module, _ := r.InstantiateModule(ctx, compiled, wazero.NewModuleConfig().WithName("prod"))
|
||||
// defer module.Close()
|
||||
//
|
||||
// While CompiledModule is pre-validated, there are a few situations which can cause an error:
|
||||
// * The module name is already in use.
|
||||
@@ -80,7 +83,9 @@ type Runtime interface {
|
||||
//
|
||||
// ctx := context.Background()
|
||||
// r := wazero.NewRuntime()
|
||||
// wasi, _ := wasi.InstantiateSnapshotPreview1(r)
|
||||
// defer r.Close(ctx) // This closes everything this Runtime created.
|
||||
//
|
||||
// _, _ := wasi.InstantiateSnapshotPreview1(r)
|
||||
// compiled, _ := r.CompileModule(ctx, source, wazero.NewCompileConfig())
|
||||
//
|
||||
// // Initialize base configuration:
|
||||
@@ -99,7 +104,9 @@ type Runtime interface {
|
||||
// Ex.
|
||||
// ctx := context.Background()
|
||||
// r := wazero.NewRuntime()
|
||||
// defer r.Close(ctx)
|
||||
// defer r.Close(ctx) // This closes everything this Runtime created.
|
||||
//
|
||||
// // Everything below here can be closed, but will anyway due to above.
|
||||
// _, _ = wasi.InstantiateSnapshotPreview1(ctx, r)
|
||||
// mod, _ := r.InstantiateModuleFromCode(ctx, source)
|
||||
Close(context.Context) error
|
||||
@@ -110,7 +117,9 @@ type Runtime interface {
|
||||
// Ex.
|
||||
// ctx := context.Background()
|
||||
// r := wazero.NewRuntime()
|
||||
// defer r.CloseWithExitCode(ctx, 2)
|
||||
// defer r.CloseWithExitCode(ctx, 2) // This closes everything this Runtime created.
|
||||
//
|
||||
// // Everything below here can be closed, but will anyway due to above.
|
||||
// _, _ = wasi.InstantiateSnapshotPreview1(ctx, r)
|
||||
// mod, _ := r.InstantiateModuleFromCode(ctx, source)
|
||||
CloseWithExitCode(ctx context.Context, exitCode uint32) error
|
||||
|
||||
Reference in New Issue
Block a user