From c9019e6406307d41ca0fdfb9fcb23bd0740e790c Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Wed, 13 Sep 2023 12:36:56 +0900 Subject: [PATCH] wazevo: supports for LookupFunction API (#1704) Signed-off-by: Takeshi Yoneda --- internal/engine/compiler/engine_test.go | 5 - .../engine/interpreter/interpreter_test.go | 4 - internal/engine/wazevo/call_engine.go | 6 +- internal/engine/wazevo/e2e_test.go | 3 +- internal/engine/wazevo/engine.go | 3 +- internal/engine/wazevo/module_engine.go | 39 +++++- .../integration_test/engine/adhoc_test.go | 129 ++++++++++++++---- .../integration_test/engine/hammer_test.go | 21 ++- internal/testing/enginetest/enginetest.go | 98 ++----------- 9 files changed, 177 insertions(+), 131 deletions(-) diff --git a/internal/engine/compiler/engine_test.go b/internal/engine/compiler/engine_test.go index e18ace62..d415e9ce 100644 --- a/internal/engine/compiler/engine_test.go +++ b/internal/engine/compiler/engine_test.go @@ -53,11 +53,6 @@ func TestCompiler_MemoryGrowInRecursiveCall(t *testing.T) { enginetest.RunTestEngineMemoryGrowInRecursiveCall(t, et) } -func TestCompiler_ModuleEngine_LookupFunction(t *testing.T) { - defer functionLog.Reset() - enginetest.RunTestModuleEngineLookupFunction(t, et) -} - func TestCompiler_ModuleEngine_Call(t *testing.T) { defer functionLog.Reset() requireSupportedOSArch(t) diff --git a/internal/engine/interpreter/interpreter_test.go b/internal/engine/interpreter/interpreter_test.go index 26efed33..2a598005 100644 --- a/internal/engine/interpreter/interpreter_test.go +++ b/internal/engine/interpreter/interpreter_test.go @@ -92,10 +92,6 @@ func TestInterpreter_Engine_NewModuleEngine(t *testing.T) { enginetest.RunTestEngineNewModuleEngine(t, et) } -func TestInterpreter_ModuleEngine_LookupFunction(t *testing.T) { - enginetest.RunTestModuleEngineLookupFunction(t, et) -} - func TestInterpreter_ModuleEngine_Call(t *testing.T) { defer functionLog.Reset() enginetest.RunTestModuleEngineCall(t, et) diff --git a/internal/engine/wazevo/call_engine.go b/internal/engine/wazevo/call_engine.go index 1683b109..06f2e6f0 100644 --- a/internal/engine/wazevo/call_engine.go +++ b/internal/engine/wazevo/call_engine.go @@ -141,6 +141,10 @@ func (c *callEngine) CallWithStack(ctx context.Context, paramResultStack []uint6 err = builder.FromRecovered(r) // TODO: Abort listener. + } else { + if err != wasmruntime.ErrRuntimeStackOverflow { // Stackoverflow case shouldn't be panic (to avoid extreme stack unwinding). + err = c.parent.module.FailIfClosed() + } } }() @@ -212,7 +216,7 @@ func (c *callEngine) CallWithStack(ctx context.Context, paramResultStack []uint6 } func (c *callEngine) callerModuleInstance() *wasm.ModuleInstance { - return *(**wasm.ModuleInstance)(unsafe.Pointer(c.execCtx.callerModuleContextPtr)) + return moduleInstanceFromOpaquePtr(c.execCtx.callerModuleContextPtr) } func opaqueViewFromPtr(ptr uintptr) []byte { diff --git a/internal/engine/wazevo/e2e_test.go b/internal/engine/wazevo/e2e_test.go index b5b334ad..3a52c30a 100644 --- a/internal/engine/wazevo/e2e_test.go +++ b/internal/engine/wazevo/e2e_test.go @@ -27,12 +27,12 @@ const ( f64 = wasm.ValueTypeF64 ) +// TODO: migrate to integration_test/spectest/v1/spec_test.go by the time when closing https://github.com/tetratelabs/wazero/issues/1496 func TestSpectestV1(t *testing.T) { config := wazero.NewRuntimeConfigCompiler().WithCoreFeatures(api.CoreFeaturesV1) // Configure the new optimizing backend! wazevo.ConfigureWazevo(config) - // TODO: migrate to integration_test/spectest/v1/spec_test.go by the time when closing https://github.com/tetratelabs/wazero/issues/1496 for _, tc := range []struct { name string }{ @@ -120,6 +120,7 @@ func TestSpectestV1(t *testing.T) { } } +// TODO: migrate to integration_test/spectest/v2/spec_test.go by the time when closing https://github.com/tetratelabs/wazero/issues/1496 func TestSpectestV2(t *testing.T) { config := wazero.NewRuntimeConfigCompiler().WithCoreFeatures(api.CoreFeaturesV2) // Configure the new optimizing backend! diff --git a/internal/engine/wazevo/engine.go b/internal/engine/wazevo/engine.go index 880b26e2..d0847c00 100644 --- a/internal/engine/wazevo/engine.go +++ b/internal/engine/wazevo/engine.go @@ -3,6 +3,7 @@ package wazevo import ( "context" "encoding/hex" + "errors" "fmt" "runtime" "sort" @@ -464,7 +465,7 @@ func (e *engine) NewModuleEngine(m *wasm.Module, mi *wasm.ModuleInstance) (wasm. compiled, ok := e.compiledModules[m.ID] if !ok { - return nil, fmt.Errorf("binary of module %q is not compiled", mi.ModuleName) + return nil, errors.New("source module must be compiled before instantiation") } me.parent = compiled me.module = mi diff --git a/internal/engine/wazevo/module_engine.go b/internal/engine/wazevo/module_engine.go index c3d57f11..a0eff8b6 100644 --- a/internal/engine/wazevo/module_engine.go +++ b/internal/engine/wazevo/module_engine.go @@ -7,6 +7,7 @@ import ( "github.com/tetratelabs/wazero/api" "github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi" "github.com/tetratelabs/wazero/internal/wasm" + "github.com/tetratelabs/wazero/internal/wasmruntime" ) type ( @@ -25,6 +26,7 @@ type ( executable *byte moduleContextOpaquePtr *byte typeID wasm.FunctionTypeID + indexInModule wasm.Index } importedFunction struct { @@ -217,15 +219,16 @@ func (m *moduleEngine) FunctionInstanceReference(funcIndex wasm.Index) wasm.Refe begin, _, _ := m.parent.offsets.ImportedFunctionOffset(funcIndex) return uintptr(unsafe.Pointer(&m.opaque[begin])) } - funcIndex -= m.module.Source.ImportFunctionCount + localIndex := funcIndex - m.module.Source.ImportFunctionCount p := m.parent - executable := &p.executable[p.functionOffsets[funcIndex].nativeBegin()] - typeID := m.module.TypeIDs[m.module.Source.FunctionSection[funcIndex]] + executable := &p.executable[p.functionOffsets[localIndex].nativeBegin()] + typeID := m.module.TypeIDs[m.module.Source.FunctionSection[localIndex]] lf := &functionInstance{ executable: executable, moduleContextOpaquePtr: m.opaquePtr, typeID: typeID, + indexInModule: funcIndex, } m.localFunctionInstances = append(m.localFunctionInstances, lf) return uintptr(unsafe.Pointer(lf)) @@ -233,5 +236,33 @@ func (m *moduleEngine) FunctionInstanceReference(funcIndex wasm.Index) wasm.Refe // LookupFunction implements wasm.ModuleEngine. func (m *moduleEngine) LookupFunction(t *wasm.TableInstance, typeId wasm.FunctionTypeID, tableOffset wasm.Index) (*wasm.ModuleInstance, wasm.Index) { - panic("TODO") + if tableOffset >= uint32(len(t.References)) || t.Type != wasm.RefTypeFuncref { + panic(wasmruntime.ErrRuntimeInvalidTableAccess) + } + rawPtr := t.References[tableOffset] + if rawPtr == 0 { + panic(wasmruntime.ErrRuntimeInvalidTableAccess) + } + + tf := functionFromUintptr(rawPtr) + if tf.typeID != typeId { + panic(wasmruntime.ErrRuntimeIndirectCallTypeMismatch) + } + return moduleInstanceFromOpaquePtr(tf.moduleContextOpaquePtr), tf.indexInModule +} + +// functionFromUintptr resurrects the original *function from the given uintptr +// which comes from either funcref table or OpcodeRefFunc instruction. +func functionFromUintptr(ptr uintptr) *functionInstance { + // Wraps ptrs as the double pointer in order to avoid the unsafe access as detected by race detector. + // + // For example, if we have (*function)(unsafe.Pointer(ptr)) instead, then the race detector's "checkptr" + // subroutine wanrs as "checkptr: pointer arithmetic result points to invalid allocation" + // https://github.com/golang/go/blob/1ce7fcf139417d618c2730010ede2afb41664211/src/runtime/checkptr.go#L69 + var wrapped *uintptr = &ptr + return *(**functionInstance)(unsafe.Pointer(wrapped)) +} + +func moduleInstanceFromOpaquePtr(ptr *byte) *wasm.ModuleInstance { + return *(**wasm.ModuleInstance)(unsafe.Pointer(ptr)) } diff --git a/internal/integration_test/engine/adhoc_test.go b/internal/integration_test/engine/adhoc_test.go index ab3c19a6..b6271055 100644 --- a/internal/integration_test/engine/adhoc_test.go +++ b/internal/integration_test/engine/adhoc_test.go @@ -4,6 +4,7 @@ import ( "context" _ "embed" "math" + "runtime" "strconv" "testing" "time" @@ -11,11 +12,14 @@ import ( "github.com/tetratelabs/wazero" "github.com/tetratelabs/wazero/api" + "github.com/tetratelabs/wazero/experimental/table" + "github.com/tetratelabs/wazero/internal/engine/wazevo" "github.com/tetratelabs/wazero/internal/platform" "github.com/tetratelabs/wazero/internal/testing/binaryencoding" "github.com/tetratelabs/wazero/internal/testing/proxy" "github.com/tetratelabs/wazero/internal/testing/require" "github.com/tetratelabs/wazero/internal/wasm" + "github.com/tetratelabs/wazero/internal/wasmruntime" "github.com/tetratelabs/wazero/sys" ) @@ -30,43 +34,62 @@ var memoryCapacityPages = uint32(2) var moduleConfig = wazero.NewModuleConfig() -var tests = map[string]func(t *testing.T, r wazero.Runtime){ - "huge stack": testHugeStack, - "unreachable": testUnreachable, - "recursive entry": testRecursiveEntry, - "host func memory": testHostFuncMemory, - "host function with context parameter": testHostFunctionContextParameter, - "host function with nested context": testNestedGoContext, - "host function with numeric parameter": testHostFunctionNumericParameter, - "close module with in-flight calls": testCloseInFlight, - "multiple instantiation from same source": testMultipleInstantiation, - "exported function that grows memory": testMemOps, - "import functions with reference type in signature": testReftypeImports, - "overflow integer addition": testOverflow, - "un-signed extend global": testGlobalExtend, - "user-defined primitive in host func": testUserDefinedPrimitiveHostFunc, - "ensures invocations terminate on module close": testEnsureTerminationOnClose, - "call host function indirectly": callHostFunctionIndirect, +type testCase struct { + f func(t *testing.T, r wazero.Runtime) + wazevoSkip bool +} + +var tests = map[string]testCase{ + "huge stack": {f: testHugeStack, wazevoSkip: true}, + "unreachable": {f: testUnreachable}, + "recursive entry": {f: testRecursiveEntry}, + "host func memory": {f: testHostFuncMemory}, + "host function with context parameter": {f: testHostFunctionContextParameter}, + "host function with nested context": {f: testNestedGoContext}, + "host function with numeric parameter": {f: testHostFunctionNumericParameter}, + "close module with in-flight calls": {f: testCloseInFlight}, + "multiple instantiation from same source": {f: testMultipleInstantiation}, + "exported function that grows memory": {f: testMemOps, wazevoSkip: true}, + "import functions with reference type in signature": {f: testReftypeImports, wazevoSkip: true}, + "overflow integer addition": {f: testOverflow}, + "un-signed extend global": {f: testGlobalExtend}, + "user-defined primitive in host func": {f: testUserDefinedPrimitiveHostFunc}, + "ensures invocations terminate on module close": {f: testEnsureTerminationOnClose, wazevoSkip: true}, + "call host function indirectly": {f: callHostFunctionIndirect, wazevoSkip: true}, + "lookup function": {f: testLookupFunction}, } func TestEngineCompiler(t *testing.T) { if !platform.CompilerSupported() { t.Skip() } - runAllTests(t, tests, wazero.NewRuntimeConfigCompiler().WithCloseOnContextDone(true)) + runAllTests(t, tests, wazero.NewRuntimeConfigCompiler().WithCloseOnContextDone(true), false) } func TestEngineInterpreter(t *testing.T) { - runAllTests(t, tests, wazero.NewRuntimeConfigInterpreter().WithCloseOnContextDone(true)) + runAllTests(t, tests, wazero.NewRuntimeConfigInterpreter().WithCloseOnContextDone(true), false) } -func runAllTests(t *testing.T, tests map[string]func(t *testing.T, r wazero.Runtime), config wazero.RuntimeConfig) { - for name, testf := range tests { - name := name // pin - testf := testf // pin +func TestEngineWazevo(t *testing.T) { + if runtime.GOARCH != "arm64" { + t.Skip() + } + config := wazero.NewRuntimeConfigInterpreter() + wazevo.ConfigureWazevo(config) + runAllTests(t, tests, config.WithCloseOnContextDone(true), true) +} + +func runAllTests(t *testing.T, tests map[string]testCase, config wazero.RuntimeConfig, isWazevo bool) { + for name, tc := range tests { + name := name + tc := tc + if isWazevo && tc.wazevoSkip { + t.Logf("skipping %s because it is not supported by wazevo", name) + continue + } t.Run(name, func(t *testing.T) { t.Parallel() - testf(t, wazero.NewRuntimeWithConfig(testCtx, config)) + tc.f(t, wazero.NewRuntimeWithConfig(testCtx, config)) }) } } @@ -798,3 +821,61 @@ func testMultipleInstantiation(t *testing.T, r wazero.Runtime) { require.Equal(t, uint64(1000), after) } } + +func testLookupFunction(t *testing.T, r wazero.Runtime) { + bin := binaryencoding.EncodeModule(&wasm.Module{ + TypeSection: []wasm.FunctionType{{Results: []wasm.ValueType{i32}}}, + FunctionSection: []wasm.Index{0, 0, 0}, + CodeSection: []wasm.Code{ + {Body: []byte{wasm.OpcodeI32Const, 1, wasm.OpcodeEnd}}, + {Body: []byte{wasm.OpcodeI32Const, 2, wasm.OpcodeEnd}}, + {Body: []byte{wasm.OpcodeI32Const, 3, wasm.OpcodeEnd}}, + }, + TableSection: []wasm.Table{{Min: 10, Type: wasm.RefTypeFuncref}}, + ElementSection: []wasm.ElementSegment{ + { + OffsetExpr: wasm.ConstantExpression{ + Opcode: wasm.OpcodeI32Const, + Data: []byte{0}, + }, + TableIndex: 0, + Init: []wasm.Index{2, 0}, + }, + }, + }) + + inst, err := r.Instantiate(testCtx, bin) + require.NoError(t, err) + + t.Run("null reference", func(t *testing.T) { + err = require.CapturePanic(func() { + table.LookupFunction(inst, 0, 3, nil, []wasm.ValueType{i32}) + }) + require.Equal(t, wasmruntime.ErrRuntimeInvalidTableAccess, err) + }) + + t.Run("out of range", func(t *testing.T) { + err = require.CapturePanic(func() { + table.LookupFunction(inst, 0, 1000, nil, []wasm.ValueType{i32}) + }) + require.Equal(t, wasmruntime.ErrRuntimeInvalidTableAccess, err) + }) + + t.Run("type mismatch", func(t *testing.T) { + err = require.CapturePanic(func() { + table.LookupFunction(inst, 0, 0, []wasm.ValueType{i32}, nil) + }) + require.Equal(t, wasmruntime.ErrRuntimeIndirectCallTypeMismatch, err) + }) + t.Run("ok", func(t *testing.T) { + f2 := table.LookupFunction(inst, 0, 0, nil, []wasm.ValueType{i32}) + res, err := f2.Call(testCtx) + require.NoError(t, err) + require.Equal(t, uint64(3), res[0]) + + f0 := table.LookupFunction(inst, 0, 1, nil, []wasm.ValueType{i32}) + res, err = f0.Call(testCtx) + require.NoError(t, err) + require.Equal(t, uint64(1), res[0]) + }) +} diff --git a/internal/integration_test/engine/hammer_test.go b/internal/integration_test/engine/hammer_test.go index a6b2deba..dc5f1e02 100644 --- a/internal/integration_test/engine/hammer_test.go +++ b/internal/integration_test/engine/hammer_test.go @@ -2,32 +2,43 @@ package adhoc import ( "context" + "runtime" "sync" "testing" "github.com/tetratelabs/wazero" "github.com/tetratelabs/wazero/api" + "github.com/tetratelabs/wazero/internal/engine/wazevo" "github.com/tetratelabs/wazero/internal/platform" "github.com/tetratelabs/wazero/internal/testing/hammer" "github.com/tetratelabs/wazero/internal/testing/require" "github.com/tetratelabs/wazero/sys" ) -var hammers = map[string]func(t *testing.T, r wazero.Runtime){ +var hammers = map[string]testCase{ // Tests here are similar to what's described in /RATIONALE.md, but deviate as they involve blocking functions. - "close importing module while in use": closeImportingModuleWhileInUse, - "close imported module while in use": closeImportedModuleWhileInUse, + "close importing module while in use": {f: closeImportingModuleWhileInUse, wazevoSkip: true}, + "close imported module while in use": {f: closeImportedModuleWhileInUse, wazevoSkip: true}, } func TestEngineCompiler_hammer(t *testing.T) { if !platform.CompilerSupported() { t.Skip() } - runAllTests(t, hammers, wazero.NewRuntimeConfigCompiler()) + runAllTests(t, hammers, wazero.NewRuntimeConfigCompiler(), false) } func TestEngineInterpreter_hammer(t *testing.T) { - runAllTests(t, hammers, wazero.NewRuntimeConfigInterpreter()) + runAllTests(t, hammers, wazero.NewRuntimeConfigInterpreter(), false) +} + +func TestEngineWazevo_hammer(t *testing.T) { + if runtime.GOARCH != "arm64" { + t.Skip() + } + c := wazero.NewRuntimeConfigInterpreter() + wazevo.ConfigureWazevo(c) + runAllTests(t, hammers, c, true) } func closeImportingModuleWhileInUse(t *testing.T, r wazero.Runtime) { diff --git a/internal/testing/enginetest/enginetest.go b/internal/testing/enginetest/enginetest.go index edd80527..b1287562 100644 --- a/internal/testing/enginetest/enginetest.go +++ b/internal/testing/enginetest/enginetest.go @@ -16,6 +16,9 @@ // // Note: These tests intentionally avoid using wasm.Store as it is important to know both the dependencies and // the capabilities at the wasm.Engine abstraction. +// +// TODO: the purpose of enginetest overlaps with the purpose of internal/integration_test/engine. We should +// migrate there since the tests here are costly maintenance-wise. package enginetest import ( @@ -33,7 +36,6 @@ import ( "github.com/tetratelabs/wazero/internal/u64" "github.com/tetratelabs/wazero/internal/wasm" "github.com/tetratelabs/wazero/internal/wasmdebug" - "github.com/tetratelabs/wazero/internal/wasmruntime" ) const ( @@ -235,89 +237,6 @@ func RunTestModuleEngineCallWithStack(t *testing.T, et EngineTester) { }) } -func RunTestModuleEngineLookupFunction(t *testing.T, et EngineTester) { - e := et.NewEngine(api.CoreFeaturesV1) - - mod := &wasm.Module{ - TypeSection: []wasm.FunctionType{{}, {Params: []wasm.ValueType{wasm.ValueTypeV128}}}, - FunctionSection: []wasm.Index{0, 0, 0}, - CodeSection: []wasm.Code{ - { - Body: []byte{wasm.OpcodeEnd}, - }, {Body: []byte{wasm.OpcodeEnd}}, {Body: []byte{wasm.OpcodeEnd}}, - }, - } - - err := e.CompileModule(testCtx, mod, nil, false) - require.NoError(t, err) - m := &wasm.ModuleInstance{ - TypeIDs: []wasm.FunctionTypeID{0, 1}, - Source: mod, - } - m.Tables = []*wasm.TableInstance{ - {Min: 2, References: make([]wasm.Reference, 2), Type: wasm.RefTypeFuncref}, - {Min: 2, References: make([]wasm.Reference, 2), Type: wasm.RefTypeExternref}, - {Min: 10, References: make([]wasm.Reference, 10), Type: wasm.RefTypeFuncref}, - } - - me, err := e.NewModuleEngine(mod, m) - require.NoError(t, err) - linkModuleToEngine(m, me) - - t.Run("null reference", func(t *testing.T) { - err = require.CapturePanic(func() { - m.LookupFunction(m.Tables[0], m.TypeIDs[0], 0) // offset 0 is not initialized yet. - }) - require.Equal(t, wasmruntime.ErrRuntimeInvalidTableAccess, err) - err = require.CapturePanic(func() { - m.LookupFunction(m.Tables[0], m.TypeIDs[0], 1) // offset 1 is not initialized yet. - }) - require.Equal(t, wasmruntime.ErrRuntimeInvalidTableAccess, err) - }) - - m.Tables[0].References[0] = me.FunctionInstanceReference(2) - m.Tables[0].References[1] = me.FunctionInstanceReference(0) - - t.Run("initialized", func(t *testing.T) { - f1 := m.LookupFunction(m.Tables[0], m.TypeIDs[0], 0) // offset 0 is now initialized. - require.Equal(t, wasm.Index(2), f1.Definition().Index()) - f2 := m.LookupFunction(m.Tables[0], m.TypeIDs[0], 1) // offset 1 is now initialized. - require.Equal(t, wasm.Index(0), f2.Definition().Index()) - }) - - t.Run("out of range", func(t *testing.T) { - err = require.CapturePanic(func() { - me.LookupFunction(m.Tables[0], m.TypeIDs[0], 100 /* out of range */) - }) - require.Equal(t, wasmruntime.ErrRuntimeInvalidTableAccess, err) - }) - - t.Run("access to externref table", func(t *testing.T) { - err := require.CapturePanic(func() { - m.LookupFunction(m.Tables[1], /* table[1] has externref type. */ - m.TypeIDs[0], 0) - }) - require.Equal(t, wasmruntime.ErrRuntimeInvalidTableAccess, err) - }) - - t.Run("access to externref table", func(t *testing.T) { - err = require.CapturePanic(func() { - me.LookupFunction(m.Tables[0], /* type mismatch */ - m.TypeIDs[1], 0) - }) - require.Equal(t, wasmruntime.ErrRuntimeIndirectCallTypeMismatch, err) - }) - - m.Tables[2].References[0] = me.FunctionInstanceReference(1) - m.Tables[2].References[5] = me.FunctionInstanceReference(2) - t.Run("initialized - tables[2]", func(t *testing.T) { - f1 := m.LookupFunction(m.Tables[2], m.TypeIDs[0], 0) - require.Equal(t, wasm.Index(1), f1.Definition().Index()) - f2 := m.LookupFunction(m.Tables[2], m.TypeIDs[0], 5) - require.Equal(t, wasm.Index(2), f2.Definition().Index()) - }) -} - func runTestModuleEngineCallHostFnMem(t *testing.T, et EngineTester, readMem *wasm.Code) { e := et.NewEngine(api.CoreFeaturesV1) defer e.Close() @@ -1188,7 +1107,10 @@ func setupCallTests(t *testing.T, e wasm.Engine, divBy *wasm.Code, fnlf experime lns := buildFunctionListeners(fnlf, hostModule) err := e.CompileModule(testCtx, hostModule, lns, false) require.NoError(t, err) - host := &wasm.ModuleInstance{ModuleName: hostModule.NameSection.ModuleName, TypeIDs: []wasm.FunctionTypeID{0}} + host := &wasm.ModuleInstance{ + ModuleName: hostModule.NameSection.ModuleName, TypeIDs: []wasm.FunctionTypeID{0}, + Source: hostModule, + } host.Exports = exportMap(hostModule) hostME, err := e.NewModuleEngine(hostModule, host) @@ -1223,6 +1145,7 @@ func setupCallTests(t *testing.T, e wasm.Engine, divBy *wasm.Code, fnlf experime require.NoError(t, err) imported := &wasm.ModuleInstance{ + Source: importedModule, ModuleName: importedModule.NameSection.ModuleName, TypeIDs: []wasm.FunctionTypeID{0}, } imported.Exports = exportMap(importedModule) @@ -1256,7 +1179,10 @@ func setupCallTests(t *testing.T, e wasm.Engine, divBy *wasm.Code, fnlf experime require.NoError(t, err) // Add the exported function. - importing := &wasm.ModuleInstance{ModuleName: importingModule.NameSection.ModuleName, TypeIDs: []wasm.FunctionTypeID{0}} + importing := &wasm.ModuleInstance{ + ModuleName: importingModule.NameSection.ModuleName, TypeIDs: []wasm.FunctionTypeID{0}, + Source: importingModule, + } importing.Exports = exportMap(importingModule) // Compile the importing module