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>
This commit is contained in:
Crypt Keeper
2022-09-28 14:42:14 +08:00
committed by GitHub
parent 06e2cd3757
commit 429334cf98
38 changed files with 196 additions and 703 deletions

View File

@@ -411,7 +411,7 @@ ways acts similar to a process with a `main` function.
To capture "hello world" written to the console (stdout a.k.a. file descriptor 1) in `exec.Cmd`, you would set the
`Stdout` field accordingly, perhaps to a buffer. In WebAssembly 1.0 (20191205), the only way to perform something like
this is via a host function (ex `ModuleBuilder.ExportFunction`) and internally copy memory corresponding to that string
this is via a host function (ex `HostModuleBuilder.ExportFunction`) and internally copy memory corresponding to that string
to a buffer.
WASI implements system interfaces with host functions. Concretely, to write to console, a WASI command `Module` imports

View File

@@ -38,7 +38,7 @@ 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
_, err := r.NewModuleBuilder("env").
_, err := r.NewHostModuleBuilder("env").
ExportFunction("log_i32", func(v uint32) {
fmt.Println("log_i32 >>", v)
}).

View File

@@ -95,7 +95,7 @@ const (
// (func (import "env" "f") (param externref) (result externref))
//
// This can be defined in Go as:
// r.NewModuleBuilder("env").ExportFunctions(map[string]interface{}{
// r.NewHostModuleBuilder("env").ExportFunctions(map[string]interface{}{
// "f": func(externref uintptr) (resultExternRef uintptr) { return },
// })
//
@@ -229,7 +229,7 @@ type FunctionDefinition interface {
ExportNames() []string
// GoFunc is present when the function was implemented by the embedder
// (ex via wazero.ModuleBuilder) instead of a wasm binary.
// (ex via wazero.HostModuleBuilder) instead of a wasm binary.
//
// This function can be non-deterministic or cause side effects. It also
// has special properties not defined in the WebAssembly Core

View File

@@ -2,15 +2,16 @@ package wazero
import (
"context"
"fmt"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/internal/leb128"
"github.com/tetratelabs/wazero/internal/u64"
"github.com/tetratelabs/wazero/internal/wasm"
)
// ModuleBuilder is a way to define a WebAssembly Module in Go.
// HostModuleBuilder is a way to define host functions (in Go), so that a
// WebAssembly binary (ex. %.wasm file) can import and use them.
//
// Specifically, this implements the host side of an Application Binary
// Interface (ABI) like WASI or AssemblyScript.
//
// Ex. Below defines and instantiates a module named "env" with one function:
//
@@ -21,30 +22,47 @@ import (
// hello := func() {
// fmt.Fprintln(stdout, "hello!")
// }
// env, _ := r.NewModuleBuilder("env").
// env, _ := r.NewHostModuleBuilder("env").
// ExportFunction("hello", hello).
// Instantiate(ctx, r)
//
// If the same module may be instantiated multiple times, it is more efficient
// to separate steps. Ex.
//
// compiled, _ := r.NewModuleBuilder("env").
// compiled, _ := r.NewHostModuleBuilder("env").
// ExportFunction("get_random_string", getRandomString).
// Compile(ctx, wazero.NewCompileConfig())
// Compile(ctx)
//
// env1, _ := r.InstantiateModule(ctx, compiled, wazero.NewModuleConfig().WithName("env.1"))
//
// env2, _ := r.InstantiateModule(ctx, compiled, wazero.NewModuleConfig().WithName("env.2"))
//
// # Memory
//
// All host functions act on the importing api.Module, including any memory
// exported in its binary (%.wasm file). If you are reading or writing memory,
// it is sand-boxed Wasm memory defined by the guest.
//
// Below, `m` is the importing module, defined in Wasm. `fn` is a host function
// added via ExportFunction. This means that `x` was read from memory defined
// in Wasm, not arbitrary memory in the process.
//
// fn := func(ctx context.Context, m api.Module, offset uint32) uint32 {
// x, _ := m.Memory().ReadUint32Le(ctx, offset)
// return x
// }
//
// See ExportFunction for valid host function signatures and other details.
//
// # Notes
//
// - ModuleBuilder is mutable: each method returns the same instance for
// - HostModuleBuilder is mutable: each method returns the same instance for
// chaining.
// - methods do not return errors, to allow chaining. Any validation errors
// are deferred until Compile.
// - Insertion order is not retained. Anything defined by this builder is
// sorted lexicographically on Compile.
type ModuleBuilder interface {
type HostModuleBuilder interface {
// Note: until golang/go#5860, we can't use example tests to embed code in interface godocs.
// ExportFunction adds a function written in Go, which a WebAssembly module can import.
@@ -66,7 +84,7 @@ type ModuleBuilder interface {
// builder.ExportFunction("abort", env.abort, "~lib/builtins/abort",
// "message", "fileName", "lineNumber", "columnNumber")
//
// Valid Signature
// # Valid Signature
//
// Noting a context exception described later, all parameters or result
// types must match WebAssembly 1.0 (20191205) value types. This means
@@ -108,90 +126,15 @@ type ModuleBuilder interface {
// --snip--
//
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#host-functions%E2%91%A2
ExportFunction(exportName string, goFunc interface{}, names ...string) ModuleBuilder
ExportFunction(exportName string, goFunc interface{}, names ...string) HostModuleBuilder
// ExportFunctions is a convenience that calls ExportFunction for each key/value in the provided map.
ExportFunctions(nameToGoFunc map[string]interface{}) ModuleBuilder
// ExportMemory adds linear memory, which a WebAssembly module can import and become available via api.Memory.
// If a memory is already exported with the same name, this overwrites it.
//
// # Parameters
//
// - name - the name to export. Ex "memory" for wasi_snapshot_preview1.ModuleSnapshotPreview1
// - minPages - the possibly zero initial size in pages (65536 bytes per page).
//
// For example, the WebAssembly 1.0 Text Format below is the equivalent of this builder method:
// // (memory (export "memory") 1)
// builder.ExportMemory(1)
//
// # Notes
//
// - This is allowed to grow to (4GiB) limited by api.MemorySizer. To bound it, use ExportMemoryWithMax.
// - Version 1.0 (20191205) of the WebAssembly spec allows at most one memory per module.
//
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#memory-section%E2%91%A0
ExportMemory(name string, minPages uint32) ModuleBuilder
// ExportMemoryWithMax is like ExportMemory, but can prevent overuse of memory.
//
// For example, the WebAssembly 1.0 Text Format below is the equivalent of this builder method:
// // (memory (export "memory") 1 1)
// builder.ExportMemoryWithMax(1, 1)
//
// Note: api.MemorySizer determines the capacity.
ExportMemoryWithMax(name string, minPages, maxPages uint32) ModuleBuilder
// ExportGlobalI32 exports a global constant of type api.ValueTypeI32.
// If a global is already exported with the same name, this overwrites it.
//
// For example, the WebAssembly 1.0 Text Format below is the equivalent of this builder method:
// // (global (export "canvas_width") i32 (i32.const 1024))
// builder.ExportGlobalI32("canvas_width", 1024)
//
// Note: The maximum value of v is math.MaxInt32 to match constraints of initialization in binary format.
//
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#value-types%E2%91%A0 and
// https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#syntax-globaltype
ExportGlobalI32(name string, v int32) ModuleBuilder
// ExportGlobalI64 exports a global constant of type api.ValueTypeI64.
// If a global is already exported with the same name, this overwrites it.
//
// For example, the WebAssembly 1.0 Text Format below is the equivalent of this builder method:
// // (global (export "start_epoch") i64 (i64.const 1620216263544))
// builder.ExportGlobalI64("start_epoch", 1620216263544)
//
// Note: The maximum value of v is math.MaxInt64 to match constraints of initialization in binary format.
//
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#value-types%E2%91%A0 and
// https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#syntax-globaltype
ExportGlobalI64(name string, v int64) ModuleBuilder
// ExportGlobalF32 exports a global constant of type api.ValueTypeF32.
// If a global is already exported with the same name, this overwrites it.
//
// For example, the WebAssembly 1.0 Text Format below is the equivalent of this builder method:
// // (global (export "math/pi") f32 (f32.const 3.1415926536))
// builder.ExportGlobalF32("math/pi", 3.1415926536)
//
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#syntax-globaltype
ExportGlobalF32(name string, v float32) ModuleBuilder
// ExportGlobalF64 exports a global constant of type api.ValueTypeF64.
// If a global is already exported with the same name, this overwrites it.
//
// For example, the WebAssembly 1.0 Text Format below is the equivalent of this builder method:
// // (global (export "math/pi") f64 (f64.const 3.14159265358979323846264338327950288419716939937510582097494459))
// builder.ExportGlobalF64("math/pi", 3.14159265358979323846264338327950288419716939937510582097494459)
//
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#syntax-globaltype
ExportGlobalF64(name string, v float64) ModuleBuilder
ExportFunctions(nameToGoFunc map[string]interface{}) HostModuleBuilder
// Compile returns a CompiledModule that can instantiated in any namespace (Namespace).
//
// Note: Closing the Namespace has the same effect as closing the result.
Compile(context.Context, CompileConfig) (CompiledModule, error)
Compile(context.Context) (CompiledModule, error)
// Instantiate is a convenience that calls Compile, then Namespace.InstantiateModule.
//
@@ -204,7 +147,7 @@ type ModuleBuilder interface {
// hello := func() {
// fmt.Fprintln(stdout, "hello!")
// }
// env, _ := r.NewModuleBuilder("env").
// env, _ := r.NewHostModuleBuilder("env").
// ExportFunction("hello", hello).
// Instantiate(ctx, r)
//
@@ -216,30 +159,26 @@ type ModuleBuilder interface {
Instantiate(context.Context, Namespace) (api.Module, error)
}
// moduleBuilder implements ModuleBuilder
type moduleBuilder struct {
// hostModuleBuilder implements HostModuleBuilder
type hostModuleBuilder struct {
r *runtime
moduleName string
nameToGoFunc map[string]interface{}
funcToNames map[string][]string
nameToMemory map[string]*wasm.Memory
nameToGlobal map[string]*wasm.Global
}
// NewModuleBuilder implements Runtime.NewModuleBuilder
func (r *runtime) NewModuleBuilder(moduleName string) ModuleBuilder {
return &moduleBuilder{
// NewHostModuleBuilder implements Runtime.NewHostModuleBuilder
func (r *runtime) NewHostModuleBuilder(moduleName string) HostModuleBuilder {
return &hostModuleBuilder{
r: r,
moduleName: moduleName,
nameToGoFunc: map[string]interface{}{},
funcToNames: map[string][]string{},
nameToMemory: map[string]*wasm.Memory{},
nameToGlobal: map[string]*wasm.Global{},
}
}
// ExportFunction implements ModuleBuilder.ExportFunction
func (b *moduleBuilder) ExportFunction(exportName string, goFunc interface{}, names ...string) ModuleBuilder {
// ExportFunction implements HostModuleBuilder.ExportFunction
func (b *hostModuleBuilder) ExportFunction(exportName string, goFunc interface{}, names ...string) HostModuleBuilder {
b.nameToGoFunc[exportName] = goFunc
if len(names) > 0 {
b.funcToNames[exportName] = names
@@ -247,81 +186,17 @@ func (b *moduleBuilder) ExportFunction(exportName string, goFunc interface{}, na
return b
}
// ExportFunctions implements ModuleBuilder.ExportFunctions
func (b *moduleBuilder) ExportFunctions(nameToGoFunc map[string]interface{}) ModuleBuilder {
// ExportFunctions implements HostModuleBuilder.ExportFunctions
func (b *hostModuleBuilder) ExportFunctions(nameToGoFunc map[string]interface{}) HostModuleBuilder {
for k, v := range nameToGoFunc {
b.ExportFunction(k, v)
}
return b
}
// ExportMemory implements ModuleBuilder.ExportMemory
func (b *moduleBuilder) ExportMemory(name string, minPages uint32) ModuleBuilder {
b.nameToMemory[name] = &wasm.Memory{Min: minPages}
return b
}
// ExportMemoryWithMax implements ModuleBuilder.ExportMemoryWithMax
func (b *moduleBuilder) ExportMemoryWithMax(name string, minPages, maxPages uint32) ModuleBuilder {
b.nameToMemory[name] = &wasm.Memory{Min: minPages, Max: maxPages, IsMaxEncoded: true}
return b
}
// ExportGlobalI32 implements ModuleBuilder.ExportGlobalI32
func (b *moduleBuilder) ExportGlobalI32(name string, v int32) ModuleBuilder {
b.nameToGlobal[name] = &wasm.Global{
Type: &wasm.GlobalType{ValType: wasm.ValueTypeI32},
// Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeI32Const, Data: leb128.EncodeInt32(v)},
}
return b
}
// ExportGlobalI64 implements ModuleBuilder.ExportGlobalI64
func (b *moduleBuilder) ExportGlobalI64(name string, v int64) ModuleBuilder {
b.nameToGlobal[name] = &wasm.Global{
Type: &wasm.GlobalType{ValType: wasm.ValueTypeI64},
// Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeI64Const, Data: leb128.EncodeInt64(v)},
}
return b
}
// ExportGlobalF32 implements ModuleBuilder.ExportGlobalF32
func (b *moduleBuilder) ExportGlobalF32(name string, v float32) ModuleBuilder {
b.nameToGlobal[name] = &wasm.Global{
Type: &wasm.GlobalType{ValType: wasm.ValueTypeF32},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF32Const, Data: u64.LeBytes(api.EncodeF32(v))},
}
return b
}
// ExportGlobalF64 implements ModuleBuilder.ExportGlobalF64
func (b *moduleBuilder) ExportGlobalF64(name string, v float64) ModuleBuilder {
b.nameToGlobal[name] = &wasm.Global{
Type: &wasm.GlobalType{ValType: wasm.ValueTypeF64},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF64Const, Data: u64.LeBytes(api.EncodeF64(v))},
}
return b
}
// Compile implements ModuleBuilder.Compile
func (b *moduleBuilder) Compile(ctx context.Context, cConfig CompileConfig) (CompiledModule, error) {
config := cConfig.(*compileConfig)
// Verify the maximum limit here, so we don't have to pass it to wasm.NewHostModule
for name, mem := range b.nameToMemory {
var maxP *uint32
if mem.IsMaxEncoded {
maxP = &mem.Max
}
mem.Min, mem.Cap, mem.Max = config.memorySizer(mem.Min, maxP)
if err := mem.Validate(); err != nil {
return nil, fmt.Errorf("memory[%s] %v", name, err)
}
}
module, err := wasm.NewHostModule(b.moduleName, b.nameToGoFunc, b.funcToNames, b.nameToMemory, b.nameToGlobal, b.r.enabledFeatures)
// Compile implements HostModuleBuilder.Compile
func (b *hostModuleBuilder) Compile(ctx context.Context) (CompiledModule, error) {
module, err := wasm.NewHostModule(b.moduleName, b.nameToGoFunc, b.funcToNames, b.r.enabledFeatures)
if err != nil {
return nil, err
} else if err = module.Validate(b.r.enabledFeatures); err != nil {
@@ -340,9 +215,9 @@ func (b *moduleBuilder) Compile(ctx context.Context, cConfig CompileConfig) (Com
return c, nil
}
// Instantiate implements ModuleBuilder.Instantiate
func (b *moduleBuilder) Instantiate(ctx context.Context, ns Namespace) (api.Module, error) {
if compiled, err := b.Compile(ctx, NewCompileConfig()); err != nil {
// Instantiate implements HostModuleBuilder.Instantiate
func (b *hostModuleBuilder) Instantiate(ctx context.Context, ns Namespace) (api.Module, error) {
if compiled, err := b.Compile(ctx); err != nil {
return nil, err
} else {
compiled.(*compiledModule).closeWithModule = true

View File

@@ -1,18 +1,15 @@
package wazero
import (
"math"
"testing"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/internal/leb128"
"github.com/tetratelabs/wazero/internal/testing/require"
"github.com/tetratelabs/wazero/internal/u64"
"github.com/tetratelabs/wazero/internal/wasm"
)
// TestNewModuleBuilder_Compile only covers a few scenarios to avoid duplicating tests in internal/wasm/host_test.go
func TestNewModuleBuilder_Compile(t *testing.T) {
// TestNewHostModuleBuilder_Compile only covers a few scenarios to avoid duplicating tests in internal/wasm/host_test.go
func TestNewHostModuleBuilder_Compile(t *testing.T) {
i32, i64 := api.ValueTypeI32, api.ValueTypeI64
uint32_uint32 := func(uint32) uint32 {
@@ -24,27 +21,27 @@ func TestNewModuleBuilder_Compile(t *testing.T) {
tests := []struct {
name string
input func(Runtime) ModuleBuilder
input func(Runtime) HostModuleBuilder
expected *wasm.Module
}{
{
name: "empty",
input: func(r Runtime) ModuleBuilder {
return r.NewModuleBuilder("")
input: func(r Runtime) HostModuleBuilder {
return r.NewHostModuleBuilder("")
},
expected: &wasm.Module{},
},
{
name: "only name",
input: func(r Runtime) ModuleBuilder {
return r.NewModuleBuilder("env")
input: func(r Runtime) HostModuleBuilder {
return r.NewHostModuleBuilder("env")
},
expected: &wasm.Module{NameSection: &wasm.NameSection{ModuleName: "env"}},
},
{
name: "ExportFunction",
input: func(r Runtime) ModuleBuilder {
return r.NewModuleBuilder("").ExportFunction("1", uint32_uint32)
input: func(r Runtime) HostModuleBuilder {
return r.NewHostModuleBuilder("").ExportFunction("1", uint32_uint32)
},
expected: &wasm.Module{
TypeSection: []*wasm.FunctionType{
@@ -62,8 +59,8 @@ func TestNewModuleBuilder_Compile(t *testing.T) {
},
{
name: "ExportFunction with names",
input: func(r Runtime) ModuleBuilder {
return r.NewModuleBuilder("").ExportFunction("1", uint32_uint32, "get", "x")
input: func(r Runtime) HostModuleBuilder {
return r.NewHostModuleBuilder("").ExportFunction("1", uint32_uint32, "get", "x")
},
expected: &wasm.Module{
TypeSection: []*wasm.FunctionType{
@@ -82,8 +79,8 @@ func TestNewModuleBuilder_Compile(t *testing.T) {
},
{
name: "ExportFunction overwrites existing",
input: func(r Runtime) ModuleBuilder {
return r.NewModuleBuilder("").ExportFunction("1", uint32_uint32).ExportFunction("1", uint64_uint32)
input: func(r Runtime) HostModuleBuilder {
return r.NewHostModuleBuilder("").ExportFunction("1", uint32_uint32).ExportFunction("1", uint64_uint32)
},
expected: &wasm.Module{
TypeSection: []*wasm.FunctionType{
@@ -101,9 +98,9 @@ func TestNewModuleBuilder_Compile(t *testing.T) {
},
{
name: "ExportFunction twice",
input: func(r Runtime) ModuleBuilder {
input: func(r Runtime) HostModuleBuilder {
// Intentionally out of order
return r.NewModuleBuilder("").ExportFunction("2", uint64_uint32).ExportFunction("1", uint32_uint32)
return r.NewHostModuleBuilder("").ExportFunction("2", uint64_uint32).ExportFunction("1", uint32_uint32)
},
expected: &wasm.Module{
TypeSection: []*wasm.FunctionType{
@@ -123,8 +120,8 @@ func TestNewModuleBuilder_Compile(t *testing.T) {
},
{
name: "ExportFunctions",
input: func(r Runtime) ModuleBuilder {
return r.NewModuleBuilder("").ExportFunctions(map[string]interface{}{
input: func(r Runtime) HostModuleBuilder {
return r.NewHostModuleBuilder("").ExportFunctions(map[string]interface{}{
"1": uint32_uint32,
"2": uint64_uint32,
})
@@ -147,8 +144,8 @@ func TestNewModuleBuilder_Compile(t *testing.T) {
},
{
name: "ExportFunctions overwrites",
input: func(r Runtime) ModuleBuilder {
b := r.NewModuleBuilder("").ExportFunction("1", uint64_uint32)
input: func(r Runtime) HostModuleBuilder {
b := r.NewHostModuleBuilder("").ExportFunction("1", uint64_uint32)
return b.ExportFunctions(map[string]interface{}{
"1": uint32_uint32,
"2": uint64_uint32,
@@ -170,198 +167,14 @@ func TestNewModuleBuilder_Compile(t *testing.T) {
},
},
},
{
name: "ExportMemory",
input: func(r Runtime) ModuleBuilder {
return r.NewModuleBuilder("").ExportMemory("memory", 1)
},
expected: &wasm.Module{
MemorySection: &wasm.Memory{Min: 1, Cap: 1, Max: wasm.MemoryLimitPages},
ExportSection: []*wasm.Export{
{Name: "memory", Type: wasm.ExternTypeMemory, Index: 0},
},
},
},
{
name: "ExportMemory overwrites",
input: func(r Runtime) ModuleBuilder {
return r.NewModuleBuilder("").ExportMemory("memory", 1).ExportMemory("memory", 2)
},
expected: &wasm.Module{
MemorySection: &wasm.Memory{Min: 2, Cap: 2, Max: wasm.MemoryLimitPages},
ExportSection: []*wasm.Export{
{Name: "memory", Type: wasm.ExternTypeMemory, Index: 0},
},
},
},
{
name: "ExportMemoryWithMax",
input: func(r Runtime) ModuleBuilder {
return r.NewModuleBuilder("").ExportMemoryWithMax("memory", 1, 1)
},
expected: &wasm.Module{
MemorySection: &wasm.Memory{Min: 1, Cap: 1, Max: 1, IsMaxEncoded: true},
ExportSection: []*wasm.Export{
{Name: "memory", Type: wasm.ExternTypeMemory, Index: 0},
},
},
},
{
name: "ExportMemoryWithMax overwrites",
input: func(r Runtime) ModuleBuilder {
return r.NewModuleBuilder("").ExportMemoryWithMax("memory", 1, 1).ExportMemoryWithMax("memory", 1, 2)
},
expected: &wasm.Module{
MemorySection: &wasm.Memory{Min: 1, Cap: 1, Max: 2, IsMaxEncoded: true},
ExportSection: []*wasm.Export{
{Name: "memory", Type: wasm.ExternTypeMemory, Index: 0},
},
},
},
{
name: "ExportGlobalI32",
input: func(r Runtime) ModuleBuilder {
return r.NewModuleBuilder("").ExportGlobalI32("canvas_width", 1024)
},
expected: &wasm.Module{
GlobalSection: []*wasm.Global{
{
Type: &wasm.GlobalType{ValType: wasm.ValueTypeI32},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeI32Const, Data: leb128.EncodeInt32(1024)},
},
},
ExportSection: []*wasm.Export{
{Name: "canvas_width", Type: wasm.ExternTypeGlobal, Index: 0},
},
},
},
{
name: "ExportGlobalI32 overwrites",
input: func(r Runtime) ModuleBuilder {
return r.NewModuleBuilder("").ExportGlobalI32("canvas_width", 1024).ExportGlobalI32("canvas_width", math.MaxInt32)
},
expected: &wasm.Module{
GlobalSection: []*wasm.Global{
{
Type: &wasm.GlobalType{ValType: wasm.ValueTypeI32},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeI32Const, Data: leb128.EncodeUint32(math.MaxInt32)},
},
},
ExportSection: []*wasm.Export{
{Name: "canvas_width", Type: wasm.ExternTypeGlobal, Index: 0},
},
},
},
{
name: "ExportGlobalI64",
input: func(r Runtime) ModuleBuilder {
return r.NewModuleBuilder("").ExportGlobalI64("start_epoch", 1620216263544)
},
expected: &wasm.Module{
GlobalSection: []*wasm.Global{
{
Type: &wasm.GlobalType{ValType: wasm.ValueTypeI64},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeI64Const, Data: leb128.EncodeUint64(1620216263544)},
},
},
ExportSection: []*wasm.Export{
{Name: "start_epoch", Type: wasm.ExternTypeGlobal, Index: 0},
},
},
},
{
name: "ExportGlobalI64 overwrites",
input: func(r Runtime) ModuleBuilder {
return r.NewModuleBuilder("").ExportGlobalI64("start_epoch", 1620216263544).ExportGlobalI64("start_epoch", math.MaxInt64)
},
expected: &wasm.Module{
GlobalSection: []*wasm.Global{
{
Type: &wasm.GlobalType{ValType: wasm.ValueTypeI64},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeI64Const, Data: leb128.EncodeInt64(math.MaxInt64)},
},
},
ExportSection: []*wasm.Export{
{Name: "start_epoch", Type: wasm.ExternTypeGlobal, Index: 0},
},
},
},
{
name: "ExportGlobalF32",
input: func(r Runtime) ModuleBuilder {
return r.NewModuleBuilder("").ExportGlobalF32("math/pi", 3.1415926536)
},
expected: &wasm.Module{
GlobalSection: []*wasm.Global{
{
Type: &wasm.GlobalType{ValType: wasm.ValueTypeF32},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF32Const, Data: u64.LeBytes(api.EncodeF32(3.1415926536))},
},
},
ExportSection: []*wasm.Export{
{Name: "math/pi", Type: wasm.ExternTypeGlobal, Index: 0},
},
},
},
{
name: "ExportGlobalF32 overwrites",
input: func(r Runtime) ModuleBuilder {
return r.NewModuleBuilder("").ExportGlobalF32("math/pi", 3.1415926536).ExportGlobalF32("math/pi", math.MaxFloat32)
},
expected: &wasm.Module{
GlobalSection: []*wasm.Global{
{
Type: &wasm.GlobalType{ValType: wasm.ValueTypeF32},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF32Const, Data: u64.LeBytes(api.EncodeF32(math.MaxFloat32))},
},
},
ExportSection: []*wasm.Export{
{Name: "math/pi", Type: wasm.ExternTypeGlobal, Index: 0},
},
},
},
{
name: "ExportGlobalF64",
input: func(r Runtime) ModuleBuilder {
return r.NewModuleBuilder("").ExportGlobalF64("math/pi", math.Pi)
},
expected: &wasm.Module{
GlobalSection: []*wasm.Global{
{
Type: &wasm.GlobalType{ValType: wasm.ValueTypeF64},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF64Const, Data: u64.LeBytes(api.EncodeF64(math.Pi))},
},
},
ExportSection: []*wasm.Export{
{Name: "math/pi", Type: wasm.ExternTypeGlobal, Index: 0},
},
},
},
{
name: "ExportGlobalF64 overwrites",
input: func(r Runtime) ModuleBuilder {
return r.NewModuleBuilder("").ExportGlobalF64("math/pi", math.Pi).ExportGlobalF64("math/pi", math.MaxFloat64)
},
expected: &wasm.Module{
GlobalSection: []*wasm.Global{
{
Type: &wasm.GlobalType{ValType: wasm.ValueTypeF64},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF64Const, Data: u64.LeBytes(api.EncodeF64(math.MaxFloat64))},
},
},
ExportSection: []*wasm.Export{
{Name: "math/pi", Type: wasm.ExternTypeGlobal, Index: 0},
},
},
},
}
for _, tt := range tests {
tc := tt
t.Run(tc.name, func(t *testing.T) {
b := tc.input(NewRuntime(testCtx)).(*moduleBuilder)
compiled, err := b.Compile(testCtx, NewCompileConfig())
b := tc.input(NewRuntime(testCtx)).(*hostModuleBuilder)
compiled, err := b.Compile(testCtx)
require.NoError(t, err)
m := compiled.(*compiledModule)
@@ -380,31 +193,27 @@ func TestNewModuleBuilder_Compile(t *testing.T) {
}
}
// TestNewModuleBuilder_Compile_Errors only covers a few scenarios to avoid duplicating tests in internal/wasm/host_test.go
func TestNewModuleBuilder_Compile_Errors(t *testing.T) {
// TestNewHostModuleBuilder_Compile_Errors only covers a few scenarios to avoid
// duplicating tests in internal/wasm/host_test.go
func TestNewHostModuleBuilder_Compile_Errors(t *testing.T) {
tests := []struct {
name string
input func(Runtime) ModuleBuilder
config CompileConfig
input func(Runtime) HostModuleBuilder
expectedErr string
}{
{
name: "memory min > limit", // only one test to avoid duplicating tests in module_test.go
input: func(rt Runtime) ModuleBuilder {
return rt.NewModuleBuilder("").ExportMemory("memory", math.MaxUint32)
name: "error compiling", // should fail due to missing result.
input: func(rt Runtime) HostModuleBuilder {
return rt.NewHostModuleBuilder("").
ExportFunction("fn", &wasm.HostFunc{
ExportNames: []string{"fn"},
ResultTypes: []wasm.ValueType{wasm.ValueTypeI32},
Code: &wasm.Code{IsHostFunction: true, Body: []byte{wasm.OpcodeEnd}},
})
},
config: NewCompileConfig(),
expectedErr: "memory[memory] min 4294967295 pages (3 Ti) over limit of 65536 pages (4 Gi)",
},
{
name: "memory cap < min", // only one test to avoid duplicating tests in module_test.go
input: func(rt Runtime) ModuleBuilder {
return rt.NewModuleBuilder("").ExportMemory("memory", 2)
},
config: NewCompileConfig().WithMemorySizer(func(minPages uint32, maxPages *uint32) (min, capacity, max uint32) {
return 2, 1, 2
}),
expectedErr: "memory[memory] capacity 1 pages (64 Ki) less than minimum 2 pages (128 Ki)",
expectedErr: `invalid function[0] export["fn"]: not enough results
have ()
want (i32)`,
},
}
@@ -412,16 +221,16 @@ func TestNewModuleBuilder_Compile_Errors(t *testing.T) {
tc := tt
t.Run(tc.name, func(t *testing.T) {
_, e := tc.input(NewRuntime(testCtx)).Compile(testCtx, tc.config)
_, e := tc.input(NewRuntime(testCtx)).Compile(testCtx)
require.EqualError(t, e, tc.expectedErr)
})
}
}
// TestNewModuleBuilder_Instantiate ensures Runtime.InstantiateModule is called on success.
func TestNewModuleBuilder_Instantiate(t *testing.T) {
// TestNewHostModuleBuilder_Instantiate ensures Runtime.InstantiateModule is called on success.
func TestNewHostModuleBuilder_Instantiate(t *testing.T) {
r := NewRuntime(testCtx)
m, err := r.NewModuleBuilder("env").Instantiate(testCtx, r)
m, err := r.NewHostModuleBuilder("env").Instantiate(testCtx, r)
require.NoError(t, err)
// If this was instantiated, it would be added to the store under the same name
@@ -432,13 +241,13 @@ func TestNewModuleBuilder_Instantiate(t *testing.T) {
require.Zero(t, r.(*runtime).store.Engine.CompiledModuleCount())
}
// TestNewModuleBuilder_Instantiate_Errors ensures errors propagate from Runtime.InstantiateModule
func TestNewModuleBuilder_Instantiate_Errors(t *testing.T) {
// TestNewHostModuleBuilder_Instantiate_Errors ensures errors propagate from Runtime.InstantiateModule
func TestNewHostModuleBuilder_Instantiate_Errors(t *testing.T) {
r := NewRuntime(testCtx)
_, err := r.NewModuleBuilder("env").Instantiate(testCtx, r)
_, err := r.NewHostModuleBuilder("env").Instantiate(testCtx, r)
require.NoError(t, err)
_, err = r.NewModuleBuilder("env").Instantiate(testCtx, r)
_, err = r.NewHostModuleBuilder("env").Instantiate(testCtx, r)
require.EqualError(t, err, "module[env] has already been instantiated")
}

View File

@@ -165,7 +165,7 @@ func (c *compiledModule) ExportedFunctions() map[string]api.FunctionDefinition {
return c.module.ExportedFunctions()
}
// CompileConfig allows you to override what was decoded from wasm, prior to compilation (ModuleBuilder.Compile or
// CompileConfig allows you to override what was decoded from wasm, prior to compilation (HostModuleBuilder.Compile or
// Runtime.CompileModule).
//
// For example, WithMemorySizer allows you to override memory size that doesn't match your requirements.

View File

@@ -30,7 +30,7 @@ func main() {
// Instantiate a Go-defined module named "env" that exports a function to
// log to the console.
_, err := r.NewModuleBuilder("env").
_, err := r.NewHostModuleBuilder("env").
ExportFunction("log", logString).
Instantiate(ctx, r)
if err != nil {

View File

@@ -31,7 +31,7 @@ func main() {
// Instantiate a Go-defined module named "env" that exports a function to
// log to the console.
_, err := r.NewModuleBuilder("env").
_, err := r.NewHostModuleBuilder("env").
ExportFunction("log", logString).
Instantiate(ctx, r)
if err != nil {

View File

@@ -36,7 +36,7 @@ func run() error {
// Instantiate a Go-defined module named "env" that exports a function to
// log to the console.
_, err := r.NewModuleBuilder("env").
_, err := r.NewHostModuleBuilder("env").
ExportFunction("log", logString).
Instantiate(ctx, r)
if err != nil {

View File

@@ -14,7 +14,7 @@ log_i32 >> 21
WebAssembly has neither a mechanism to get the current year, nor one to print to the console, so we define these in Go.
Similar to Go, WebAssembly functions are namespaced, into modules instead of packages. Just like Go, only exported
functions can be imported into another module. What you'll learn in [age-calculator.go](age-calculator.go), is how to
export functions using [ModuleBuilder](https://pkg.go.dev/github.com/tetratelabs/wazero#ModuleBuilder) and how a
export functions using [HostModuleBuilder](https://pkg.go.dev/github.com/tetratelabs/wazero#HostModuleBuilder) and how a
WebAssembly module defined in its [text format](https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#text-format%E2%91%A0)
imports it. This only uses the text format for demonstration purposes, to show you what's going on. It is likely, you
will use another language to compile a Wasm (WebAssembly Module) binary, such as TinyGo. Regardless of how wasm is

View File

@@ -38,7 +38,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.
_, err := r.NewModuleBuilder("env").
_, err := r.NewHostModuleBuilder("env").
ExportFunction("log_i32", func(v uint32) {
fmt.Println("log_i32 >>", v)
}).

View File

@@ -109,7 +109,7 @@ var multiValueFromImportedHostWasm []byte
// 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").
if _, err := r.NewHostModuleBuilder("multi-value/host").
// Define a function that returns two results
ExportFunction("get_age", func() (age uint64, errno uint32) {
age = 37

View File

@@ -71,7 +71,7 @@ func instantiateWithEnv(ctx context.Context, r wazero.Runtime, module wazero.Com
// Instantiate a new "env" module which exports a stateful function.
c := &counter{}
_, err := r.NewModuleBuilder("env").
_, err := r.NewHostModuleBuilder("env").
ExportFunction("next_i32", c.getAndIncrement).
Instantiate(ctx, ns)
if err != nil {

View File

@@ -54,7 +54,7 @@ const (
// - To add more functions to the "env" module, use FunctionExporter.
// - To instantiate into another wazero.Namespace, use FunctionExporter.
func Instantiate(ctx context.Context, r wazero.Runtime) (api.Closer, error) {
builder := r.NewModuleBuilder("env")
builder := r.NewHostModuleBuilder("env")
NewFunctionExporter().ExportFunctions(builder)
return builder.Instantiate(ctx, r)
}
@@ -77,9 +77,9 @@ type FunctionExporter interface {
// appropriate to use WithTraceToStdout instead.
WithTraceToStderr() FunctionExporter
// ExportFunctions builds functions to export with a wazero.ModuleBuilder
// ExportFunctions builds functions to export with a wazero.HostModuleBuilder
// named "env".
ExportFunctions(builder wazero.ModuleBuilder)
ExportFunctions(builder wazero.HostModuleBuilder)
}
// NewFunctionExporter returns a FunctionExporter object with trace disabled.
@@ -107,7 +107,7 @@ func (e *functionExporter) WithTraceToStderr() FunctionExporter {
}
// ExportFunctions implements FunctionExporter.ExportFunctions
func (e *functionExporter) ExportFunctions(builder wazero.ModuleBuilder) {
func (e *functionExporter) ExportFunctions(builder wazero.HostModuleBuilder) {
builder.ExportFunction(functionAbort, e.abortFn)
builder.ExportFunction(functionTrace, e.traceFn)
builder.ExportFunction(functionSeed, seed)

View File

@@ -34,7 +34,7 @@ func Example_functionExporter() {
defer r.Close(ctx) // This closes everything this Runtime created.
// First construct your own module builder for "env"
envBuilder := r.NewModuleBuilder("env").
envBuilder := r.NewHostModuleBuilder("env").
ExportFunction("get_int", func() uint32 { return 1 })
// Now, add AssemblyScript special function imports into it.

View File

@@ -424,10 +424,10 @@ func requireProxyModule(t *testing.T, fns FunctionExporter, config wazero.Module
r := wazero.NewRuntimeWithConfig(ctx, wazero.NewRuntimeConfigInterpreter())
builder := r.NewModuleBuilder("env")
builder := r.NewHostModuleBuilder("env")
fns.ExportFunctions(builder)
envCompiled, err := builder.Compile(ctx, wazero.NewCompileConfig())
envCompiled, err := builder.Compile(ctx)
require.NoError(t, err)
_, err = r.InstantiateModule(ctx, envCompiled, config)

View File

@@ -29,7 +29,7 @@ import (
// - To add more functions to the "env" module, use FunctionExporter.
// - To instantiate into another wazero.Namespace, use FunctionExporter.
func Instantiate(ctx context.Context, r wazero.Runtime) (api.Closer, error) {
builder := r.NewModuleBuilder("env")
builder := r.NewHostModuleBuilder("env")
NewFunctionExporter().ExportFunctions(builder)
return builder.Instantiate(ctx, r)
}
@@ -37,9 +37,9 @@ func Instantiate(ctx context.Context, r wazero.Runtime) (api.Closer, error) {
// FunctionExporter configures the functions in the "env" module used by
// Emscripten.
type FunctionExporter interface {
// ExportFunctions builds functions to export with a wazero.ModuleBuilder
// ExportFunctions builds functions to export with a wazero.HostModuleBuilder
// named "env".
ExportFunctions(builder wazero.ModuleBuilder)
ExportFunctions(builder wazero.HostModuleBuilder)
}
// NewFunctionExporter returns a FunctionExporter object with trace disabled.
@@ -50,7 +50,7 @@ func NewFunctionExporter() FunctionExporter {
type functionExporter struct{}
// ExportFunctions implements FunctionExporter.ExportFunctions
func (e *functionExporter) ExportFunctions(builder wazero.ModuleBuilder) {
func (e *functionExporter) ExportFunctions(builder wazero.HostModuleBuilder) {
builder.ExportFunction(notifyMemoryGrowth.Name, notifyMemoryGrowth)
}

View File

@@ -45,7 +45,7 @@ func Example_functionExporter() {
// Next, construct your own module builder for "env" with any functions
// you need.
envBuilder := r.NewModuleBuilder("env").
envBuilder := r.NewHostModuleBuilder("env").
ExportFunction("get_int", func() uint32 { return 1 })
// Now, add Emscripten special function imports into it.

View File

@@ -62,7 +62,7 @@ func WithRoundTripper(ctx context.Context, rt http.RoundTripper) context.Context
// - Both the host and guest module are closed after being run.
func Run(ctx context.Context, r wazero.Runtime, compiled wazero.CompiledModule, config wazero.ModuleConfig) error {
// Instantiate the imports needed by go-compiled wasm.
js, err := moduleBuilder(r).Instantiate(ctx, r)
js, err := hostModuleBuilder(r).Instantiate(ctx, r)
if err != nil {
return err
}
@@ -86,9 +86,9 @@ func Run(ctx context.Context, r wazero.Runtime, compiled wazero.CompiledModule,
return err
}
// moduleBuilder returns a new wazero.ModuleBuilder
func moduleBuilder(r wazero.Runtime) wazero.ModuleBuilder {
return r.NewModuleBuilder("go").
// hostModuleBuilder returns a new wazero.HostModuleBuilder
func hostModuleBuilder(r wazero.Runtime) wazero.HostModuleBuilder {
return r.NewHostModuleBuilder("go").
ExportFunction(GetRandomData.Name(), GetRandomData).
ExportFunction(Nanotime1.Name(), Nanotime1).
ExportFunction(WasmExit.Name(), WasmExit).

View File

@@ -47,12 +47,12 @@ type Builder interface {
// Compile compiles the ModuleName module that can instantiated in any
// namespace (wazero.Namespace).
//
// Note: This has the same effect as the same function on wazero.ModuleBuilder.
Compile(context.Context, wazero.CompileConfig) (wazero.CompiledModule, error)
// Note: This has the same effect as the same function on wazero.HostModuleBuilder.
Compile(context.Context) (wazero.CompiledModule, error)
// Instantiate instantiates the ModuleName module into the given namespace.
//
// Note: This has the same effect as the same function on wazero.ModuleBuilder.
// Note: This has the same effect as the same function on wazero.HostModuleBuilder.
Instantiate(context.Context, wazero.Namespace) (api.Closer, error)
}
@@ -63,21 +63,21 @@ func NewBuilder(r wazero.Runtime) Builder {
type builder struct{ r wazero.Runtime }
// moduleBuilder returns a new wazero.ModuleBuilder for ModuleName
func (b *builder) moduleBuilder() wazero.ModuleBuilder {
ret := b.r.NewModuleBuilder(ModuleName)
// hostModuleBuilder returns a new wazero.HostModuleBuilder for ModuleName
func (b *builder) hostModuleBuilder() wazero.HostModuleBuilder {
ret := b.r.NewHostModuleBuilder(ModuleName)
exportFunctions(ret)
return ret
}
// Compile implements Builder.Compile
func (b *builder) Compile(ctx context.Context, config wazero.CompileConfig) (wazero.CompiledModule, error) {
return b.moduleBuilder().Compile(ctx, config)
func (b *builder) Compile(ctx context.Context) (wazero.CompiledModule, error) {
return b.hostModuleBuilder().Compile(ctx)
}
// Instantiate implements Builder.Instantiate
func (b *builder) Instantiate(ctx context.Context, ns wazero.Namespace) (api.Closer, error) {
return b.moduleBuilder().Instantiate(ctx, ns)
return b.hostModuleBuilder().Instantiate(ctx, ns)
}
// ## Translation notes
@@ -109,7 +109,7 @@ func (b *builder) Instantiate(ctx context.Context, ns wazero.Namespace) (api.Clo
// exportFunctions adds all go functions that implement wasi.
// These should be exported in the module named ModuleName.
func exportFunctions(builder wazero.ModuleBuilder) {
func exportFunctions(builder wazero.HostModuleBuilder) {
// Note: these are ordered per spec for consistency even if the resulting
// map can't guarantee that.
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#functions

View File

@@ -4,7 +4,10 @@ import (
"testing"
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/internal/testing/require"
"github.com/tetratelabs/wazero/internal/wasm"
binaryformat "github.com/tetratelabs/wazero/internal/wasm/binary"
)
var testMem = []byte{
@@ -37,11 +40,13 @@ func Test_Benchmark_EnvironGet(t *testing.T) {
}
func Benchmark_EnvironGet(b *testing.B) {
r := wazero.NewRuntimeWithConfig(testCtx, wazero.NewRuntimeConfigInterpreter())
r := wazero.NewRuntime(testCtx)
defer r.Close(testCtx)
compiled, err := r.NewModuleBuilder(b.Name()).
ExportMemoryWithMax("memory", 1, 1).
Compile(testCtx, wazero.NewCompileConfig())
compiled, err := r.CompileModule(testCtx, binaryformat.EncodeModule(&wasm.Module{
MemorySection: &wasm.Memory{Min: 1, Max: 1},
ExportSection: []*wasm.Export{{Name: "memory", Type: api.ExternTypeMemory}},
}), wazero.NewCompileConfig())
if err != nil {
b.Fatal(err)
}

View File

@@ -34,8 +34,7 @@ func requireProxyModule(t *testing.T, config wazero.ModuleConfig) (api.Module, a
r := wazero.NewRuntimeWithConfig(ctx, wazero.NewRuntimeConfigInterpreter())
wasiModuleCompiled, err := (&builder{r}).moduleBuilder().
Compile(ctx, wazero.NewCompileConfig())
wasiModuleCompiled, err := (&builder{r}).hostModuleBuilder().Compile(ctx)
require.NoError(t, err)
_, err = r.InstantiateModule(ctx, wasiModuleCompiled, config)
@@ -65,8 +64,7 @@ func requireErrnoNosys(t *testing.T, funcName string, params ...uint64) string {
defer r.Close(ctx)
// Instantiate the wasi module.
wasiModuleCompiled, err := (&builder{r}).moduleBuilder().
Compile(ctx, wazero.NewCompileConfig())
wasiModuleCompiled, err := (&builder{r}).hostModuleBuilder().Compile(ctx)
require.NoError(t, err)
_, err = r.InstantiateModule(ctx, wasiModuleCompiled, wazero.NewModuleConfig())

View File

@@ -210,7 +210,7 @@ func TestCompiler_SliceAllocatedOnHeap(t *testing.T) {
// Trigger relocation of goroutine stack because at this point we have the majority of
// goroutine stack unused after recursive call.
runtime.GC()
}}, nil, map[string]*wasm.Memory{}, map[string]*wasm.Global{}, enabledFeatures)
}}, nil, enabledFeatures)
require.NoError(t, err)
err = s.Engine.CompileModule(testCtx, hm)

View File

@@ -197,7 +197,7 @@ func TestMustCallFromSP(t *testing.T) {
defer r.Close(testCtx)
funcName := "i64i32i32i32i32_i64i32_withSP"
im, err := r.NewModuleBuilder("go").
im, err := r.NewHostModuleBuilder("go").
ExportFunction(funcName, MustCallFromSP(true, wasm.NewGoFunc(
funcName, funcName,
[]string{"v", "mAddr", "mLen", "argsArray", "argsLen"},

View File

@@ -215,7 +215,7 @@ func createRuntime(b *testing.B, config wazero.RuntimeConfig) wazero.Runtime {
r := wazero.NewRuntimeWithConfig(testCtx, config)
_, err := r.NewModuleBuilder("env").
_, err := r.NewHostModuleBuilder("env").
ExportFunction("get_random_string", getRandomString).
Instantiate(testCtx, r)
if err != nil {

View File

@@ -99,7 +99,7 @@ func testReftypeImports(t *testing.T, r wazero.Runtime) {
}
hostObj := &dog{name: "hello"}
host, err := r.NewModuleBuilder("host").
host, err := r.NewHostModuleBuilder("host").
ExportFunctions(map[string]interface{}{
"externref": func(externrefFromRefNull uintptr) uintptr {
require.Zero(t, externrefFromRefNull)
@@ -176,7 +176,7 @@ func testUnreachable(t *testing.T, r wazero.Runtime) {
panic("panic in host function")
}
_, err := r.NewModuleBuilder("host").ExportFunction("cause_unreachable", callUnreachable).Instantiate(testCtx, r)
_, err := r.NewHostModuleBuilder("host").ExportFunction("cause_unreachable", callUnreachable).Instantiate(testCtx, r)
require.NoError(t, err)
module, err := r.InstantiateModuleFromBinary(testCtx, unreachableWasm)
@@ -199,7 +199,7 @@ func testRecursiveEntry(t *testing.T, r wazero.Runtime) {
require.NoError(t, err)
}
_, err := r.NewModuleBuilder("env").ExportFunction("host_func", hostfunc).Instantiate(testCtx, r)
_, err := r.NewHostModuleBuilder("env").ExportFunction("host_func", hostfunc).Instantiate(testCtx, r)
require.NoError(t, err)
module, err := r.InstantiateModuleFromBinary(testCtx, recursiveWasm)
@@ -222,7 +222,7 @@ func testHostFuncMemory(t *testing.T, r wazero.Runtime) {
return 0
}
host, err := r.NewModuleBuilder("").ExportFunction("store_int", storeInt).Instantiate(testCtx, r)
host, err := r.NewHostModuleBuilder("").ExportFunction("store_int", storeInt).Instantiate(testCtx, r)
require.NoError(t, err)
defer host.Close(testCtx)
@@ -262,7 +262,7 @@ func testNestedGoContext(t *testing.T, r wazero.Runtime) {
},
}
imported, err := r.NewModuleBuilder(importedName).ExportFunctions(fns).Instantiate(testCtx, r)
imported, err := r.NewHostModuleBuilder(importedName).ExportFunctions(fns).Instantiate(testCtx, r)
require.NoError(t, err)
defer imported.Close(testCtx)
@@ -299,7 +299,7 @@ func testHostFunctionContextParameter(t *testing.T, r wazero.Runtime) {
for test := range fns {
t.Run(test, func(t *testing.T) {
imported, err := r.NewModuleBuilder(importedName).
imported, err := r.NewHostModuleBuilder(importedName).
ExportFunction("return_input", fns[test]).
Instantiate(testCtx, r)
require.NoError(t, err)
@@ -369,7 +369,7 @@ func testHostFunctionNumericParameter(t *testing.T, r wazero.Runtime) {
},
} {
t.Run(test.name, func(t *testing.T) {
imported, err := r.NewModuleBuilder(importedName).
imported, err := r.NewHostModuleBuilder(importedName).
ExportFunction("return_input", fns[test.name]).
Instantiate(testCtx, r)
require.NoError(t, err)
@@ -519,8 +519,8 @@ func testCloseInFlight(t *testing.T, r wazero.Runtime) {
}
// Create the host module, which exports the function that closes the importing module.
importedCode, err = r.NewModuleBuilder(t.Name()+"-imported").
ExportFunction("return_input", closeAndReturn).Compile(testCtx, compileConfig)
importedCode, err = r.NewHostModuleBuilder(t.Name()+"-imported").
ExportFunction("return_input", closeAndReturn).Compile(testCtx)
require.NoError(t, err)
imported, err = r.InstantiateModule(testCtx, importedCode, moduleConfig)

View File

@@ -49,7 +49,7 @@ func closeImportedModuleWhileInUse(t *testing.T, r wazero.Runtime) {
require.NoError(t, imported.Close(testCtx))
// Redefine the imported module, with a function that no longer blocks.
imported, err := r.NewModuleBuilder(imported.Name()).ExportFunction("return_input", func(x uint32) uint32 {
imported, err := r.NewHostModuleBuilder(imported.Name()).ExportFunction("return_input", func(x uint32) uint32 {
return x
}).Instantiate(testCtx, r)
require.NoError(t, err)
@@ -78,7 +78,7 @@ func closeModuleWhileInUse(t *testing.T, r wazero.Runtime, closeFn func(imported
}
// Create the host module, which exports the blocking function.
imported, err := r.NewModuleBuilder(t.Name()+"-imported").
imported, err := r.NewHostModuleBuilder(t.Name()+"-imported").
ExportFunction("return_input", blockAndReturn).Instantiate(testCtx, r)
require.NoError(t, err)
defer imported.Close(testCtx)

View File

@@ -93,18 +93,18 @@ func (r *wazeroRuntime) Compile(ctx context.Context, cfg *RuntimeConfig) (err er
r.runtime = wazero.NewRuntimeWithConfig(ctx, r.config)
if cfg.LogFn != nil {
r.logFn = cfg.LogFn
if r.env, err = r.runtime.NewModuleBuilder("env").
ExportFunction("log", r.log).Compile(ctx, wazero.NewCompileConfig()); err != nil {
if r.env, err = r.runtime.NewHostModuleBuilder("env").
ExportFunction("log", r.log).Compile(ctx); err != nil {
return err
}
} else if cfg.EnvFReturnValue != 0 {
if r.env, err = r.runtime.NewModuleBuilder("env").
if r.env, err = r.runtime.NewHostModuleBuilder("env").
ExportFunction("f",
// Note: accepting (context.Context, api.Module) is the slowest type of host function with wazero.
func(context.Context, api.Module, uint64) uint64 {
return cfg.EnvFReturnValue
},
).Compile(ctx, wazero.NewCompileConfig()); err != nil {
).Compile(ctx); err != nil {
return err
}
}

View File

@@ -298,7 +298,7 @@ func fail(t TestingT, m1, m2 string, formatWithArgs ...interface{}) {
}
}
// failStack returns the stack leading to the require fail, without test infrastructure.
// failStack returns the stack leading to the failure, without test infrastructure.
//
// Note: This is similar to assert.CallerInfo in testify
// Note: This is untested because it is a lot of work to do that. The rationale to punt is this is a test-only internal

View File

@@ -114,7 +114,7 @@ func (m *CallContext) close(ctx context.Context, exitCode uint32) (c bool, err e
return false, nil
}
c = true
if sysCtx := m.Sys; sysCtx != nil { // nil if from ModuleBuilder
if sysCtx := m.Sys; sysCtx != nil { // nil if from HostModuleBuilder
err = sysCtx.FS(ctx).Close(ctx)
}
return

View File

@@ -4,7 +4,6 @@ import (
"errors"
"fmt"
"sort"
"strings"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/internal/wasmdebug"
@@ -91,8 +90,6 @@ func NewHostModule(
moduleName string,
nameToGoFunc map[string]interface{},
funcToNames map[string][]string,
nameToMemory map[string]*Memory,
nameToGlobal map[string]*Global,
enabledFeatures api.CoreFeatures,
) (m *Module, err error) {
if moduleName != "" {
@@ -101,52 +98,15 @@ func NewHostModule(
m = &Module{}
}
funcCount := uint32(len(nameToGoFunc))
memoryCount := uint32(len(nameToMemory))
globalCount := uint32(len(nameToGlobal))
exportCount := funcCount + memoryCount + globalCount
if exportCount > 0 {
if exportCount := uint32(len(nameToGoFunc)); exportCount > 0 {
m.ExportSection = make([]*Export, 0, exportCount)
}
// Check name collision as exports cannot collide on names, regardless of type.
for name := range nameToGoFunc {
// manually generate the error message as we don't have debug names yet.
if _, ok := nameToMemory[name]; ok {
return nil, fmt.Errorf("func[%s.%s] exports the same name as a memory", moduleName, name)
}
if _, ok := nameToGlobal[name]; ok {
return nil, fmt.Errorf("func[%s.%s] exports the same name as a global", moduleName, name)
}
}
for name := range nameToMemory {
if _, ok := nameToGlobal[name]; ok {
return nil, fmt.Errorf("memory[%s] exports the same name as a global", name)
}
}
if funcCount > 0 {
if err = addFuncs(m, nameToGoFunc, funcToNames, enabledFeatures); err != nil {
return
}
}
if memoryCount > 0 {
if err = addMemory(m, nameToMemory); err != nil {
return
}
}
// TODO: we can use enabledFeatures to fail early on things like mutable globals (once supported)
if globalCount > 0 {
if err = addGlobals(m, nameToGlobal); err != nil {
return
}
}
// Assigns the ModuleID by calculating sha256 on inputs as host modules do not have `wasm` to hash.
m.AssignModuleID([]byte(fmt.Sprintf("%s:%v:%v:%v:%v",
moduleName, nameToGoFunc, nameToMemory, nameToGlobal, enabledFeatures)))
m.AssignModuleID([]byte(fmt.Sprintf("%s:%v:%v", moduleName, nameToGoFunc, enabledFeatures)))
m.BuildFunctionDefinitions()
return
}
@@ -264,50 +224,6 @@ func addFuncs(
return nil
}
func addMemory(m *Module, nameToMemory map[string]*Memory) error {
memoryCount := uint32(len(nameToMemory))
// Only one memory can be defined or imported
if memoryCount > 1 {
memoryNames := make([]string, 0, memoryCount)
for k := range nameToMemory {
memoryNames = append(memoryNames, k)
}
sort.Strings(memoryNames) // For consistent error messages
return fmt.Errorf("only one memory is allowed, but configured: %s", strings.Join(memoryNames, ", "))
}
// Find the memory name to export.
var name string
for k, v := range nameToMemory {
name = k
if v.Min > v.Max {
return fmt.Errorf("memory[%s] min %d pages (%s) > max %d pages (%s)", name, v.Min, PagesToUnitOfBytes(v.Min), v.Max, PagesToUnitOfBytes(v.Max))
}
m.MemorySection = v
}
m.ExportSection = append(m.ExportSection, &Export{Type: ExternTypeMemory, Name: name, Index: 0})
return nil
}
func addGlobals(m *Module, globals map[string]*Global) error {
globalCount := len(globals)
m.GlobalSection = make([]*Global, 0, globalCount)
globalNames := make([]string, 0, globalCount)
for name := range globals {
globalNames = append(globalNames, name)
}
sort.Strings(globalNames) // For consistent iteration order
for i, name := range globalNames {
m.GlobalSection = append(m.GlobalSection, globals[name])
m.ExportSection = append(m.ExportSection, &Export{Type: ExternTypeGlobal, Name: name, Index: Index(i)})
}
return nil
}
func (m *Module) maybeAddType(params, results []ValueType, enabledFeatures api.CoreFeatures) (Index, error) {
if len(results) > 1 {
// Guard >1.0 feature multi-value

View File

@@ -4,7 +4,6 @@ import (
"testing"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/internal/leb128"
"github.com/tetratelabs/wazero/internal/testing/require"
)
@@ -12,10 +11,6 @@ import (
type wasiAPI struct {
}
func ArgsSizesGet(ctx api.Module, resultArgc, resultArgvBufSize uint32) uint32 {
return 0
}
func (a *wasiAPI) ArgsSizesGet(ctx api.Module, resultArgc, resultArgvBufSize uint32) uint32 {
return 0
}
@@ -37,8 +32,6 @@ func TestNewHostModule(t *testing.T) {
tests := []struct {
name, moduleName string
nameToGoFunc map[string]interface{}
nameToMemory map[string]*Memory
nameToGlobal map[string]*Global
expected *Module
}{
{
@@ -91,91 +84,13 @@ func TestNewHostModule(t *testing.T) {
NameSection: &NameSection{ModuleName: "swapper", FunctionNames: NameMap{{Index: 0, Name: "swap"}}},
},
},
{
name: "memory",
nameToMemory: map[string]*Memory{"memory": {Min: 1, Max: 2}},
expected: &Module{
MemorySection: &Memory{Min: 1, Max: 2},
ExportSection: []*Export{{Name: "memory", Type: ExternTypeMemory, Index: 0}},
},
},
{
name: "globals",
nameToGlobal: map[string]*Global{
"g2": {
Type: &GlobalType{ValType: i32},
Init: &ConstantExpression{Opcode: OpcodeI32Const, Data: leb128.EncodeInt32(2)},
},
"g1": {
Type: &GlobalType{ValType: i32},
Init: &ConstantExpression{Opcode: OpcodeI32Const, Data: const1},
},
},
expected: &Module{
GlobalSection: []*Global{
{
Type: &GlobalType{ValType: i32},
Init: &ConstantExpression{Opcode: OpcodeI32Const, Data: const1},
},
{
Type: &GlobalType{ValType: i32},
Init: &ConstantExpression{Opcode: OpcodeI32Const, Data: leb128.EncodeInt32(2)},
},
},
ExportSection: []*Export{
{Name: "g1", Type: ExternTypeGlobal, Index: 0},
{Name: "g2", Type: ExternTypeGlobal, Index: 1},
},
},
},
{
name: "one of each",
moduleName: "env",
nameToGoFunc: map[string]interface{}{
functionArgsSizesGet: a.ArgsSizesGet,
},
nameToMemory: map[string]*Memory{
"memory": {Min: 1, Max: 1},
},
nameToGlobal: map[string]*Global{
"g": {
Type: &GlobalType{ValType: i32},
Init: &ConstantExpression{Opcode: OpcodeI32Const, Data: const1},
},
},
expected: &Module{
TypeSection: []*FunctionType{
{Params: []ValueType{i32, i32}, Results: []ValueType{i32}},
},
FunctionSection: []Index{0},
CodeSection: []*Code{MustParseGoFuncCode(a.ArgsSizesGet)},
GlobalSection: []*Global{
{
Type: &GlobalType{ValType: i32},
Init: &ConstantExpression{Opcode: OpcodeI32Const, Data: const1},
},
},
MemorySection: &Memory{Min: 1, Max: 1},
ExportSection: []*Export{
{Name: "args_sizes_get", Type: ExternTypeFunc, Index: 0},
{Name: "memory", Type: ExternTypeMemory, Index: 0},
{Name: "g", Type: ExternTypeGlobal, Index: 0},
},
NameSection: &NameSection{
ModuleName: "env",
FunctionNames: NameMap{
{Index: 0, Name: "args_sizes_get"},
},
},
},
},
}
for _, tt := range tests {
tc := tt
t.Run(tc.name, func(t *testing.T) {
m, e := NewHostModule(tc.moduleName, tc.nameToGoFunc, nil, tc.nameToMemory, tc.nameToGlobal,
m, e := NewHostModule(tc.moduleName, tc.nameToGoFunc, nil,
api.CoreFeaturesV1|api.CoreFeatureMultiValue)
require.NoError(t, e)
requireHostModuleEquals(t, tc.expected, m)
@@ -216,8 +131,6 @@ func TestNewHostModule_Errors(t *testing.T) {
tests := []struct {
name, moduleName string
nameToGoFunc map[string]interface{}
nameToMemory map[string]*Memory
nameToGlobal map[string]*Global
expectedErr string
}{
{
@@ -228,38 +141,15 @@ func TestNewHostModule_Errors(t *testing.T) {
{
name: "function has multiple results",
nameToGoFunc: map[string]interface{}{"fn": func() (uint32, uint32) { return 0, 0 }},
nameToMemory: map[string]*Memory{"mem": {Min: 1, Max: 1}},
expectedErr: "func[.fn] multiple result types invalid as feature \"multi-value\" is disabled",
},
{
name: "func collides on memory name",
nameToGoFunc: map[string]interface{}{"fn": ArgsSizesGet},
nameToMemory: map[string]*Memory{"fn": {Min: 1, Max: 1}},
expectedErr: "func[.fn] exports the same name as a memory",
},
{
name: "multiple memories",
nameToMemory: map[string]*Memory{"memory": {Min: 1, Max: 1}, "mem": {Min: 2, Max: 2}},
expectedErr: "only one memory is allowed, but configured: mem, memory",
},
{
name: "memory max < min",
nameToMemory: map[string]*Memory{"memory": {Min: 1, Max: 0}},
expectedErr: "memory[memory] min 1 pages (64 Ki) > max 0 pages (0 Ki)",
},
{
name: "func collides on global name",
nameToGoFunc: map[string]interface{}{"fn": ArgsSizesGet},
nameToGlobal: map[string]*Global{"fn": {}},
expectedErr: "func[.fn] exports the same name as a global",
},
}
for _, tt := range tests {
tc := tt
t.Run(tc.name, func(t *testing.T) {
_, e := NewHostModule(tc.moduleName, tc.nameToGoFunc, nil, tc.nameToMemory, tc.nameToGlobal, api.CoreFeaturesV1)
_, e := NewHostModule(tc.moduleName, tc.nameToGoFunc, nil, api.CoreFeaturesV1)
require.EqualError(t, e, tc.expectedErr)
})
}

View File

@@ -805,7 +805,7 @@ type Export struct {
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-code
type Code struct {
// IsHostFunction returns true if the function was implemented by the
// embedder (ex via wazero.ModuleBuilder) instead of a wasm binary.
// embedder (ex via wazero.HostModuleBuilder) instead of a wasm binary.
//
// Notably, host functions can use the caller's memory, which might be
// different from its defining module.

View File

@@ -91,7 +91,7 @@ func TestModuleInstance_Memory(t *testing.T) {
func TestStore_Instantiate(t *testing.T) {
s, ns := newStore()
m, err := NewHostModule("", map[string]interface{}{"fn": func(api.Module) {}}, nil, map[string]*Memory{}, map[string]*Global{}, api.CoreFeaturesV1)
m, err := NewHostModule("", map[string]interface{}{"fn": func(api.Module) {}}, nil, api.CoreFeaturesV1)
require.NoError(t, err)
sysCtx := sys.DefaultContext(nil)
@@ -169,7 +169,7 @@ func TestStore_CloseWithExitCode(t *testing.T) {
func TestStore_hammer(t *testing.T) {
const importedModuleName = "imported"
m, err := NewHostModule(importedModuleName, map[string]interface{}{"fn": func(api.Module) {}}, nil, map[string]*Memory{}, map[string]*Global{}, api.CoreFeaturesV1)
m, err := NewHostModule(importedModuleName, map[string]interface{}{"fn": func(api.Module) {}}, nil, api.CoreFeaturesV1)
require.NoError(t, err)
s, ns := newStore()
@@ -223,7 +223,7 @@ func TestStore_Instantiate_Errors(t *testing.T) {
const importedModuleName = "imported"
const importingModuleName = "test"
m, err := NewHostModule(importedModuleName, map[string]interface{}{"fn": func(api.Module) {}}, nil, map[string]*Memory{}, map[string]*Global{}, api.CoreFeaturesV1)
m, err := NewHostModule(importedModuleName, map[string]interface{}{"fn": func(api.Module) {}}, nil, api.CoreFeaturesV1)
require.NoError(t, err)
t.Run("Fails if module name already in use", func(t *testing.T) {
@@ -314,7 +314,7 @@ func TestStore_Instantiate_Errors(t *testing.T) {
}
func TestCallContext_ExportedFunction(t *testing.T) {
host, err := NewHostModule("host", map[string]interface{}{"host_fn": func(api.Module) {}}, nil, map[string]*Memory{}, map[string]*Global{}, api.CoreFeaturesV1)
host, err := NewHostModule("host", map[string]interface{}{"host_fn": func(api.Module) {}}, nil, api.CoreFeaturesV1)
require.NoError(t, err)
s, ns := newStore()

View File

@@ -128,13 +128,13 @@ func (s *stackTrace) FromRecovered(recovered interface{}) error {
}
// If we have a runtime.Error, something severe happened which should include the stack trace. This could be
// a nil pointer from wazero or a user-defined function from ModuleBuilder.
// a nil pointer from wazero or a user-defined function from HostModuleBuilder.
if runtimeErr, ok := recovered.(runtime.Error); ok {
// TODO: consider adding debug.Stack(), but last time we attempted, some tests became unstable.
return fmt.Errorf("%w (recovered by wazero)\nwasm stack trace:\n\t%s", runtimeErr, stack)
}
// At this point we expect the error was from a function defined by ModuleBuilder that intentionally called panic.
// At this point we expect the error was from a function defined by HostModuleBuilder that intentionally called panic.
if runtimeErr, ok := recovered.(error); ok { // Ex. panic(errors.New("whoops"))
return fmt.Errorf("%w (recovered by wazero)\nwasm stack trace:\n\t%s", runtimeErr, stack)
} else { // Ex. panic("whoops")

View File

@@ -13,7 +13,7 @@ func TestRuntime_Namespace(t *testing.T) {
defer r.Close(testCtx)
// Compile a module to add to the runtime
compiled, err := r.NewModuleBuilder("env").Compile(testCtx, NewCompileConfig())
compiled, err := r.NewHostModuleBuilder("env").Compile(testCtx)
require.NoError(t, err)
// Instantiate "env" into the runtime default namespace (base case)

View File

@@ -22,7 +22,7 @@ import (
//
// module, _ := r.InstantiateModuleFromBinary(ctx, wasm)
type Runtime interface {
// NewModuleBuilder lets you create modules out of functions defined in Go.
// NewHostModuleBuilder lets you create modules out of functions defined in Go.
//
// Ex. Below defines and instantiates a module named "env" with one function:
//
@@ -30,8 +30,8 @@ type Runtime interface {
// hello := func() {
// fmt.Fprintln(stdout, "hello!")
// }
// _, err := r.NewModuleBuilder("env").ExportFunction("hello", hello).Instantiate(ctx, r)
NewModuleBuilder(moduleName string) ModuleBuilder
// _, err := r.NewHostModuleBuilder("env").ExportFunction("hello", hello).Instantiate(ctx, r)
NewHostModuleBuilder(moduleName string) HostModuleBuilder
// CompileModule decodes the WebAssembly binary (%.wasm) or errs if invalid.
// Any pre-compilation done after decoding wasm is dependent on RuntimeConfig or CompileConfig.

View File

@@ -158,21 +158,20 @@ func TestRuntime_CompileModule_Errors(t *testing.T) {
func TestModule_Memory(t *testing.T) {
tests := []struct {
name string
builder func(Runtime) ModuleBuilder
wasm []byte
expected bool
expectedLen uint32
}{
{
name: "no memory",
builder: func(r Runtime) ModuleBuilder {
return r.NewModuleBuilder(t.Name())
},
wasm: binaryformat.EncodeModule(&wasm.Module{}),
},
{
name: "memory exported, one page",
builder: func(r Runtime) ModuleBuilder {
return r.NewModuleBuilder(t.Name()).ExportMemory("memory", 1)
},
wasm: binaryformat.EncodeModule(&wasm.Module{
MemorySection: &wasm.Memory{Min: 1},
ExportSection: []*wasm.Export{{Name: "memory", Type: api.ExternTypeMemory}},
}),
expected: true,
expectedLen: 65536,
},
@@ -186,7 +185,7 @@ func TestModule_Memory(t *testing.T) {
defer r.Close(testCtx)
// Instantiate the module and get the export of the above memory
module, err := tc.builder(r).Instantiate(testCtx, r)
module, err := r.InstantiateModuleFromBinary(testCtx, tc.wasm)
require.NoError(t, err)
mem := module.ExportedMemory("memory")
@@ -206,7 +205,6 @@ func TestModule_Global(t *testing.T) {
tests := []struct {
name string
module *wasm.Module // module as wat doesn't yet support globals
builder func(Runtime) ModuleBuilder
expected, expectedMutable bool
}{
{
@@ -226,8 +224,16 @@ func TestModule_Global(t *testing.T) {
},
{
name: "global exported",
builder: func(r Runtime) ModuleBuilder {
return r.NewModuleBuilder(t.Name()).ExportGlobalI64("global", globalVal)
module: &wasm.Module{
GlobalSection: []*wasm.Global{
{
Type: &wasm.GlobalType{ValType: wasm.ValueTypeI64},
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeI64Const, Data: leb128.EncodeInt64(globalVal)},
},
},
ExportSection: []*wasm.Export{
{Type: wasm.ExternTypeGlobal, Name: "global"},
},
},
expected: true,
},
@@ -256,13 +262,7 @@ func TestModule_Global(t *testing.T) {
r := NewRuntime(testCtx).(*runtime)
defer r.Close(testCtx)
var m CompiledModule
if tc.module != nil {
m = &compiledModule{module: tc.module}
} else {
m, _ = tc.builder(r).Compile(testCtx, NewCompileConfig())
}
code := m.(*compiledModule)
code := &compiledModule{module: tc.module}
err := r.store.Engine.CompileModule(testCtx, code.module)
require.NoError(t, err)
@@ -299,7 +299,7 @@ func TestRuntime_InstantiateModule_UsesContext(t *testing.T) {
require.Equal(t, testCtx, ctx)
}
_, err := r.NewModuleBuilder("env").
_, err := r.NewHostModuleBuilder("env").
ExportFunction("start", start).
Instantiate(testCtx, r)
require.NoError(t, err)
@@ -376,7 +376,7 @@ func TestRuntime_InstantiateModuleFromBinary_ErrorOnStart(t *testing.T) {
panic(errors.New("ice cream"))
}
host, err := r.NewModuleBuilder("").
host, err := r.NewHostModuleBuilder("").
ExportFunction("start", start).
Instantiate(testCtx, r)
require.NoError(t, err)
@@ -428,7 +428,7 @@ func TestRuntime_InstantiateModule_ExitError(t *testing.T) {
require.NoError(t, m.CloseWithExitCode(ctx, 2))
}
_, err := r.NewModuleBuilder("env").ExportFunction("exit", start).Instantiate(testCtx, r)
_, err := r.NewHostModuleBuilder("env").ExportFunction("exit", start).Instantiate(testCtx, r)
require.NoError(t, err)
one := uint32(1)