summaryrefslogtreecommitdiff
path: root/vendor/github.com/tetratelabs/wazero/internal/wasm/module_instance_lookup.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/tetratelabs/wazero/internal/wasm/module_instance_lookup.go')
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/module_instance_lookup.go73
1 files changed, 73 insertions, 0 deletions
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/module_instance_lookup.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/module_instance_lookup.go
new file mode 100644
index 000000000..442d26a22
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/module_instance_lookup.go
@@ -0,0 +1,73 @@
+package wasm
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/tetratelabs/wazero/api"
+ "github.com/tetratelabs/wazero/internal/internalapi"
+)
+
+// LookupFunction looks up the table by the given index, and returns the api.Function implementation if found,
+// otherwise this panics according to the same semantics as call_indirect instruction.
+// Currently, this is only used by emscripten which needs to do call_indirect-like operation in the host function.
+func (m *ModuleInstance) LookupFunction(t *TableInstance, typeId FunctionTypeID, tableOffset Index) api.Function {
+ fm, index := m.Engine.LookupFunction(t, typeId, tableOffset)
+ if source := fm.Source; source.IsHostModule {
+ // This case, the found function is a host function stored in the table. Generally, Engine.NewFunction are only
+ // responsible for calling Wasm-defined functions (not designed for calling Go functions!). Hence we need to wrap
+ // the host function as a special case.
+ def := &source.FunctionDefinitionSection[index]
+ goF := source.CodeSection[index].GoFunc
+ switch typed := goF.(type) {
+ case api.GoFunction:
+ // GoFunction doesn't need looked up module.
+ return &lookedUpGoFunction{def: def, g: goFunctionAsGoModuleFunction(typed)}
+ case api.GoModuleFunction:
+ return &lookedUpGoFunction{def: def, lookedUpModule: m, g: typed}
+ default:
+ panic(fmt.Sprintf("unexpected GoFunc type: %T", goF))
+ }
+ } else {
+ return fm.Engine.NewFunction(index)
+ }
+}
+
+// lookedUpGoFunction implements lookedUpGoModuleFunction.
+type lookedUpGoFunction struct {
+ internalapi.WazeroOnly
+ def *FunctionDefinition
+ // lookedUpModule is the *ModuleInstance from which this Go function is looked up, i.e. owner of the table.
+ lookedUpModule *ModuleInstance
+ g api.GoModuleFunction
+}
+
+// goFunctionAsGoModuleFunction converts api.GoFunction to api.GoModuleFunction which ignores the api.Module argument.
+func goFunctionAsGoModuleFunction(g api.GoFunction) api.GoModuleFunction {
+ return api.GoModuleFunc(func(ctx context.Context, _ api.Module, stack []uint64) {
+ g.Call(ctx, stack)
+ })
+}
+
+// Definition implements api.Function.
+func (l *lookedUpGoFunction) Definition() api.FunctionDefinition { return l.def }
+
+// Call implements api.Function.
+func (l *lookedUpGoFunction) Call(ctx context.Context, params ...uint64) ([]uint64, error) {
+ typ := l.def.Functype
+ stackSize := typ.ParamNumInUint64
+ rn := typ.ResultNumInUint64
+ if rn > stackSize {
+ stackSize = rn
+ }
+ stack := make([]uint64, stackSize)
+ copy(stack, params)
+ return stack[:rn], l.CallWithStack(ctx, stack)
+}
+
+// CallWithStack implements api.Function.
+func (l *lookedUpGoFunction) CallWithStack(ctx context.Context, stack []uint64) error {
+ // The Go host function always needs to access caller's module, in this case the one holding the table.
+ l.g.Call(ctx, l.lookedUpModule, stack)
+ return nil
+}