forked from tetratelabs/wazero
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
If set in context, the ImportResolver will be used as the first step in resolving imports. Closes tetratelabs#2294
- Loading branch information
Showing
11 changed files
with
259 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package experimental | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/tetratelabs/wazero/api" | ||
"github.com/tetratelabs/wazero/internal/expctxkeys" | ||
) | ||
|
||
// ImportResolver is an experimental func type that, if set, | ||
// will be used as the first step in resolving imports. | ||
// See https://github.com/tetratelabs/wazero/issues/2294 | ||
// If the import name is not found, it should return nil. | ||
type ImportResolver func(name string) api.Module | ||
|
||
// WithImportResolver returns a new context with the given ImportResolver. | ||
func WithImportResolver(ctx context.Context, resolver ImportResolver) context.Context { | ||
return context.WithValue(ctx, expctxkeys.ImportResolverKey{}, resolver) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
package experimental_test | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
_ "embed" | ||
"fmt" | ||
"log" | ||
|
||
"github.com/tetratelabs/wazero" | ||
"github.com/tetratelabs/wazero/api" | ||
"github.com/tetratelabs/wazero/experimental" | ||
"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1" | ||
) | ||
|
||
var ( | ||
// These wasm files were generated by the following: | ||
// cd testdata | ||
// wat2wasm --debug-names inoutdispatcher.wat | ||
// wat2wasm --debug-names inoutdispatcherclient.wat | ||
|
||
//go:embed testdata/inoutdispatcher.wasm | ||
inoutdispatcherWasm []byte | ||
//go:embed testdata/inoutdispatcherclient.wasm | ||
inoutdispatcherclientWasm []byte | ||
) | ||
|
||
func Example_importResolver() { | ||
ctx := context.Background() | ||
|
||
r := wazero.NewRuntime(ctx) | ||
defer r.Close(ctx) | ||
|
||
// The client imports the inoutdispatcher module that reads from stdin and writes to stdout. | ||
// This means that we need multiple instances of the inoutdispatcher module to have different stdin/stdout. | ||
// This example demonstrates a way to do that. | ||
type mod struct { | ||
in bytes.Buffer | ||
out bytes.Buffer | ||
|
||
client api.Module | ||
} | ||
|
||
wasi_snapshot_preview1.MustInstantiate(ctx, r) | ||
|
||
const numInstances = 3 | ||
mods := make([]*mod, numInstances) | ||
for i := range mods { | ||
mods[i] = &mod{} | ||
m := mods[i] | ||
idm, err := r.CompileModule(ctx, inoutdispatcherWasm) | ||
if err != nil { | ||
log.Panicln(err) | ||
} | ||
idcm, err := r.CompileModule(ctx, inoutdispatcherclientWasm) | ||
if err != nil { | ||
log.Panicln(err) | ||
} | ||
|
||
const inoutDispatcherModuleName = "inoutdispatcher" | ||
|
||
// Name is set to "" to make it an anonymous module. | ||
dispatcherInstance, err := r.InstantiateModule(ctx, idm, wazero.NewModuleConfig().WithStdin(&m.in).WithStdout(&m.out).WithName("")) | ||
if err != nil { | ||
log.Panicln(err) | ||
} | ||
ctx = experimental.WithImportResolver(ctx, func(name string) api.Module { | ||
if name == inoutDispatcherModuleName { | ||
return dispatcherInstance | ||
} | ||
return nil | ||
}) | ||
|
||
m.client, err = r.InstantiateModule(ctx, idcm, wazero.NewModuleConfig().WithName(fmt.Sprintf("m%d", i))) | ||
if err != nil { | ||
log.Panicln(err) | ||
} | ||
|
||
} | ||
|
||
for i, m := range mods { | ||
m.in.WriteString(fmt.Sprintf("M%d", i)) | ||
m.client.ExportedFunction("dispatch").Call(ctx) | ||
} | ||
|
||
for i, m := range mods { | ||
fmt.Printf("out%d: %s\n", i, m.out.String()) | ||
} | ||
|
||
// Output: | ||
// out0: M0 | ||
// out1: M1 | ||
// out2: M2 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package experimental_test | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/tetratelabs/wazero" | ||
"github.com/tetratelabs/wazero/api" | ||
"github.com/tetratelabs/wazero/experimental" | ||
"github.com/tetratelabs/wazero/internal/testing/binaryencoding" | ||
"github.com/tetratelabs/wazero/internal/testing/require" | ||
"github.com/tetratelabs/wazero/internal/wasm" | ||
) | ||
|
||
func TestImportResolver(t *testing.T) { | ||
ctx := context.Background() | ||
|
||
r := wazero.NewRuntime(ctx) | ||
defer r.Close(ctx) | ||
|
||
for i := 0; i < 5; i++ { | ||
var callCount int | ||
start := func(ctx context.Context) { | ||
callCount++ | ||
} | ||
modImport, err := r.NewHostModuleBuilder(fmt.Sprintf("env%d", i)). | ||
NewFunctionBuilder().WithFunc(start).Export("start"). | ||
Compile(ctx) | ||
require.NoError(t, err) | ||
// Anonymous module, it will be resolved by the import resolver. | ||
instanceImport, err := r.InstantiateModule(ctx, modImport, wazero.NewModuleConfig().WithName("")) | ||
require.NoError(t, err) | ||
|
||
resolveImport := func(name string) api.Module { | ||
if name == "env" { | ||
return instanceImport | ||
} | ||
return nil | ||
} | ||
|
||
// Set the import resolver in the context. | ||
ctx = experimental.WithImportResolver(context.Background(), resolveImport) | ||
|
||
one := uint32(1) | ||
binary := binaryencoding.EncodeModule(&wasm.Module{ | ||
TypeSection: []wasm.FunctionType{{}}, | ||
ImportSection: []wasm.Import{{Module: "env", Name: "start", Type: wasm.ExternTypeFunc, DescFunc: 0}}, | ||
FunctionSection: []wasm.Index{0}, | ||
CodeSection: []wasm.Code{ | ||
{Body: []byte{wasm.OpcodeCall, 0, wasm.OpcodeEnd}}, // Call the imported env.start. | ||
}, | ||
StartSection: &one, | ||
}) | ||
|
||
modMain, err := r.CompileModule(ctx, binary) | ||
require.NoError(t, err) | ||
|
||
_, err = r.InstantiateModule(ctx, modMain, wazero.NewModuleConfig()) | ||
|
||
require.Equal(t, 1, callCount) | ||
} | ||
} |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
(module | ||
(import "wasi_snapshot_preview1" "fd_read" (func $fd_read (param i32 i32 i32 i32) (result i32))) | ||
(import "wasi_snapshot_preview1" "fd_write" (func $fd_write (param i32 i32 i32 i32) (result i32))) | ||
(memory 1 1 ) | ||
(func (export "dispatch") | ||
;; Buffer of 100 chars to read into. | ||
(i32.store (i32.const 4) (i32.const 12)) | ||
(i32.store (i32.const 8) (i32.const 100)) | ||
|
||
;; Read from stdin. | ||
(call $fd_read | ||
(i32.const 0) ;; fd; 0 is stdin. | ||
(i32.const 4) ;; iovs | ||
(i32.const 1) ;; iovs_len | ||
(i32.const 8) ;; nread | ||
) | ||
drop | ||
|
||
;; Write to stdout. | ||
(call $fd_write | ||
(i32.const 1) ;; fd; 1 is stdout. | ||
(i32.const 4) ;; iovs | ||
(i32.const 1) ;; iovs_len | ||
(i32.const 0) ;; nwritten | ||
) | ||
drop | ||
) | ||
) |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
|
||
(module | ||
(import "inoutdispatcher" "dispatch" (func $dispatch)) | ||
(func (export "dispatch") | ||
(call $dispatch) | ||
) | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package expctxkeys | ||
|
||
// ImportResolverKey is a context.Context Value key. | ||
// Its associated value should be an ImportResolver. | ||
// See https://github.com/tetratelabs/wazero/issues/2294 | ||
type ImportResolverKey struct{} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.