github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/internal/wasm/module_instance_lookup.go (about) 1 package wasm 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/wasilibs/wazerox/api" 8 "github.com/wasilibs/wazerox/internal/internalapi" 9 ) 10 11 // LookupFunction looks up the table by the given index, and returns the api.Function implementation if found, 12 // otherwise this panics according to the same semantics as call_indirect instruction. 13 // Currently, this is only used by emscripten which needs to do call_indirect-like operation in the host function. 14 func (m *ModuleInstance) LookupFunction(t *TableInstance, typeId FunctionTypeID, tableOffset Index) api.Function { 15 fm, index := m.Engine.LookupFunction(t, typeId, tableOffset) 16 if source := fm.Source; source.IsHostModule { 17 // This case, the found function is a host function stored in the table. Generally, Engine.NewFunction are only 18 // responsible for calling Wasm-defined functions (not designed for calling Go functions!). Hence we need to wrap 19 // the host function as a special case. 20 def := &source.FunctionDefinitionSection[index] 21 goF := source.CodeSection[index].GoFunc 22 switch typed := goF.(type) { 23 case api.GoFunction: 24 // GoFunction doesn't need looked up module. 25 return &lookedUpGoFunction{def: def, g: goFunctionAsGoModuleFunction(typed)} 26 case api.GoModuleFunction: 27 return &lookedUpGoFunction{def: def, lookedUpModule: m, g: typed} 28 default: 29 panic(fmt.Sprintf("unexpected GoFunc type: %T", goF)) 30 } 31 } else { 32 return fm.Engine.NewFunction(index) 33 } 34 } 35 36 // lookedUpGoFunction implements lookedUpGoModuleFunction. 37 type lookedUpGoFunction struct { 38 internalapi.WazeroOnly 39 def *FunctionDefinition 40 // lookedUpModule is the *ModuleInstance from which this Go function is looked up, i.e. owner of the table. 41 lookedUpModule *ModuleInstance 42 g api.GoModuleFunction 43 } 44 45 // goFunctionAsGoModuleFunction converts api.GoFunction to api.GoModuleFunction which ignores the api.Module argument. 46 func goFunctionAsGoModuleFunction(g api.GoFunction) api.GoModuleFunction { 47 return api.GoModuleFunc(func(ctx context.Context, _ api.Module, stack []uint64) { 48 g.Call(ctx, stack) 49 }) 50 } 51 52 // Definition implements api.Function. 53 func (l *lookedUpGoFunction) Definition() api.FunctionDefinition { return l.def } 54 55 // Call implements api.Function. 56 func (l *lookedUpGoFunction) Call(ctx context.Context, params ...uint64) ([]uint64, error) { 57 typ := l.def.Functype 58 stackSize := typ.ParamNumInUint64 59 rn := typ.ResultNumInUint64 60 if rn > stackSize { 61 stackSize = rn 62 } 63 stack := make([]uint64, stackSize) 64 copy(stack, params) 65 return stack[:rn], l.CallWithStack(ctx, stack) 66 } 67 68 // CallWithStack implements api.Function. 69 func (l *lookedUpGoFunction) CallWithStack(ctx context.Context, stack []uint64) error { 70 // The Go host function always needs to access caller's module, in this case the one holding the table. 71 l.g.Call(ctx, l.lookedUpModule, stack) 72 return nil 73 }