Ensures listeners only bound to compile time objects (#870)

Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
This commit is contained in:
Takeshi Yoneda
2022-11-29 17:25:59 +09:00
committed by GitHub
parent 84d733eb0a
commit 8339045657
16 changed files with 124 additions and 106 deletions

View File

@@ -309,11 +309,12 @@ func (b *hostModuleBuilder) Compile(ctx context.Context) (CompiledModule, error)
}
c := &compiledModule{module: module, compiledEngine: b.r.store.Engine}
if c.listeners, err = buildListeners(ctx, module); err != nil {
listeners, err := buildListeners(ctx, module)
if err != nil {
return nil, err
}
if err = b.r.store.Engine.CompileModule(ctx, module, c.listeners); err != nil {
if err = b.r.store.Engine.CompileModule(ctx, module, listeners); err != nil {
return nil, err
}

View File

@@ -10,7 +10,6 @@ import (
"time"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/experimental"
"github.com/tetratelabs/wazero/internal/engine/compiler"
"github.com/tetratelabs/wazero/internal/engine/interpreter"
"github.com/tetratelabs/wazero/internal/platform"
@@ -201,8 +200,6 @@ type compiledModule struct {
module *wasm.Module
// compiledEngine holds an engine on which `module` is compiled.
compiledEngine wasm.Engine
// listeners are present if the code was compiled with a listener
listeners []experimental.FunctionListener
// closeWithModule prevents leaking compiled code when a module is compiled implicitly.
closeWithModule bool
}

View File

@@ -261,6 +261,8 @@ type (
indexInModule wasm.Index
// sourceModule is the module from which this function is compiled. For logging purpose.
sourceModule *wasm.Module
// listener holds a listener to notify when this function is called.
listener experimental.FunctionListener
}
)
@@ -472,16 +474,19 @@ func (e *engine) CompileModule(ctx context.Context, module *wasm.Module, listene
funcs := make([]*code, len(module.FunctionSection))
ln := len(listeners)
for i, ir := range irs {
withListener := i < ln && listeners[i] != nil
var lsn experimental.FunctionListener
if i < ln {
lsn = listeners[i]
}
funcIndex := wasm.Index(i)
var compiled *code
if ir.GoFunc != nil {
if compiled, err = compileGoDefinedHostFunction(ir, withListener); err != nil {
if compiled, err = compileGoDefinedHostFunction(ir, lsn != nil); err != nil {
def := module.FunctionDefinitionSection[funcIndex+importedFuncs]
return fmt.Errorf("error compiling host go func[%s]: %w", def.DebugName(), err)
}
} else if compiled, err = compileWasmFunction(e.enabledFeatures, ir, withListener); err != nil {
} else if compiled, err = compileWasmFunction(e.enabledFeatures, ir, lsn != nil); err != nil {
def := module.FunctionDefinitionSection[funcIndex+importedFuncs]
return fmt.Errorf("error compiling wasm func[%s]: %w", def.DebugName(), err)
}
@@ -489,6 +494,7 @@ func (e *engine) CompileModule(ctx context.Context, module *wasm.Module, listene
// As this uses mmap, we need to munmap on the compiled machine code when it's GCed.
e.setFinalizer(compiled, releaseCode)
compiled.listener = lsn
compiled.indexInModule = funcIndex
compiled.sourceModule = module
funcs[funcIndex] = compiled
@@ -875,9 +881,9 @@ entry:
case builtinFunctionIndexTableGrow:
ce.builtinFunctionTableGrow(ce.ctx, caller.source.Module.Tables)
case builtinFunctionIndexFunctionListenerBefore:
ce.builtinFunctionFunctionListenerBefore(ce.ctx, caller.source)
ce.builtinFunctionFunctionListenerBefore(ce.ctx, caller)
case builtinFunctionIndexFunctionListenerAfter:
ce.builtinFunctionFunctionListenerAfter(ce.ctx, caller.source)
ce.builtinFunctionFunctionListenerAfter(ce.ctx, caller)
}
if false {
if ce.exitContext.builtinFunctionCallIndex == builtinFunctionIndexBreakPoint {
@@ -942,17 +948,17 @@ func (ce *callEngine) builtinFunctionTableGrow(ctx context.Context, tables []*wa
ce.pushValue(uint64(res))
}
func (ce *callEngine) builtinFunctionFunctionListenerBefore(ctx context.Context, fn *wasm.FunctionInstance) {
func (ce *callEngine) builtinFunctionFunctionListenerBefore(ctx context.Context, fn *function) {
base := int(ce.stackBasePointerInBytes >> 3)
listerCtx := fn.Listener.Before(ctx, fn.Definition, ce.stack[base:base+fn.Type.ParamNumInUint64])
listerCtx := fn.parent.listener.Before(ctx, fn.source.Definition, ce.stack[base:base+fn.source.Type.ParamNumInUint64])
prevStackTop := ce.contextStack
ce.contextStack = &contextStack{self: ctx, prev: prevStackTop}
ce.ctx = listerCtx
}
func (ce *callEngine) builtinFunctionFunctionListenerAfter(ctx context.Context, fn *wasm.FunctionInstance) {
func (ce *callEngine) builtinFunctionFunctionListenerAfter(ctx context.Context, fn *function) {
base := int(ce.stackBasePointerInBytes >> 3)
fn.Listener.After(ctx, fn.Definition, nil, ce.stack[base:base+fn.Type.ResultNumInUint64])
fn.parent.listener.After(ctx, fn.source.Definition, nil, ce.stack[base:base+fn.source.Type.ResultNumInUint64])
ce.ctx = ce.contextStack.self
ce.contextStack = ce.contextStack.prev
}

View File

@@ -282,7 +282,7 @@ func TestCompiler_SliceAllocatedOnHeap(t *testing.T) {
err = s.Engine.CompileModule(testCtx, hm, nil)
require.NoError(t, err)
_, err = s.Instantiate(testCtx, ns, hm, hostModuleName, nil, nil)
_, err = s.Instantiate(testCtx, ns, hm, hostModuleName, nil)
require.NoError(t, err)
const stackCorruption = "value_stack_corruption"
@@ -338,7 +338,7 @@ func TestCompiler_SliceAllocatedOnHeap(t *testing.T) {
err = s.Engine.CompileModule(testCtx, m, nil)
require.NoError(t, err)
mi, err := s.Instantiate(testCtx, ns, m, t.Name(), nil, nil)
mi, err := s.Instantiate(testCtx, ns, m, t.Name(), nil)
require.NoError(t, err)
for _, fnName := range []string{stackCorruption, callStackCorruption} {
@@ -583,14 +583,19 @@ func Test_callFrameOffset(t *testing.T) {
func TestCallEngine_builtinFunctionFunctionListenerBefore(t *testing.T) {
nextContext, currentContext, prevContext := context.Background(), context.Background(), context.Background()
f := &wasm.FunctionInstance{
Definition: newMockFunctionDefinition("1"),
Type: &wasm.FunctionType{ParamNumInUint64: 3},
Listener: mockListener{
before: func(ctx context.Context, def api.FunctionDefinition, paramValues []uint64) context.Context {
require.Equal(t, currentContext, ctx)
require.Equal(t, []uint64{2, 3, 4}, paramValues)
return nextContext
f := &function{
source: &wasm.FunctionInstance{
Definition: newMockFunctionDefinition("1"),
Type: &wasm.FunctionType{ParamNumInUint64: 3},
},
parent: &code{
listener: mockListener{
before: func(ctx context.Context, def api.FunctionDefinition, paramValues []uint64) context.Context {
require.Equal(t, currentContext, ctx)
require.Equal(t, []uint64{2, 3, 4}, paramValues)
return nextContext
},
},
},
}
@@ -608,16 +613,21 @@ func TestCallEngine_builtinFunctionFunctionListenerBefore(t *testing.T) {
func TestCallEngine_builtinFunctionFunctionListenerAfter(t *testing.T) {
currentContext, prevContext := context.Background(), context.Background()
f := &wasm.FunctionInstance{
Definition: newMockFunctionDefinition("1"),
Type: &wasm.FunctionType{ResultNumInUint64: 1},
Listener: mockListener{
after: func(ctx context.Context, def api.FunctionDefinition, err error, resultValues []uint64) {
require.Equal(t, currentContext, ctx)
require.Equal(t, []uint64{5}, resultValues)
f := &function{
source: &wasm.FunctionInstance{
Definition: newMockFunctionDefinition("1"),
Type: &wasm.FunctionType{ResultNumInUint64: 1},
},
parent: &code{
listener: mockListener{
after: func(ctx context.Context, def api.FunctionDefinition, err error, resultValues []uint64) {
require.Equal(t, currentContext, ctx)
require.Equal(t, []uint64{5}, resultValues)
},
},
},
}
ce := &callEngine{
ctx: currentContext, stack: []uint64{0, 1, 2, 3, 4, 5},
stackContext: stackContext{stackBasePointerInBytes: 40},

View File

@@ -170,14 +170,16 @@ type callFrame struct {
}
type code struct {
body []*interpreterOp
hostFn interface{}
body []*interpreterOp
listener experimental.FunctionListener
hostFn interface{}
}
type function struct {
source *wasm.FunctionInstance
body []*interpreterOp
hostFn interface{}
parent *code
}
// functionFromUintptr resurrects the original *function from the given uintptr
@@ -197,6 +199,7 @@ func (c *code) instantiate(f *wasm.FunctionInstance) *function {
source: f,
body: c.body,
hostFn: c.hostFn,
parent: c,
}
}
@@ -220,29 +223,38 @@ type interpreterOp struct {
const callFrameStackSize = 0
// CompileModule implements the same method as documented on wasm.Engine.
func (e *engine) CompileModule(ctx context.Context, module *wasm.Module, _ []experimental.FunctionListener) error {
func (e *engine) CompileModule(ctx context.Context, module *wasm.Module, listeners []experimental.FunctionListener) error {
if _, ok := e.getCodes(module); ok { // cache hit!
return nil
}
funcs := make([]*code, 0, len(module.FunctionSection))
funcs := make([]*code, len(module.FunctionSection))
irs, err := wazeroir.CompileFunctions(ctx, e.enabledFeatures, callFrameStackSize, module)
if err != nil {
return err
}
for i, ir := range irs {
var lsn experimental.FunctionListener
if i < len(listeners) {
lsn = listeners[i]
}
// If this is the host function, there's nothing to do as the runtime representation of
// host function in interpreter is its Go function itself as opposed to Wasm functions,
// which need to be compiled down to wazeroir.
if ir.GoFunc != nil {
funcs = append(funcs, &code{hostFn: ir.GoFunc})
funcs[i] = &code{hostFn: ir.GoFunc, listener: lsn}
continue
} else if compiled, err := e.lowerIR(ir); err != nil {
def := module.FunctionDefinitionSection[uint32(i)+module.ImportFuncCount()]
return fmt.Errorf("failed to lower func[%s] to wazeroir: %w", def.DebugName(), err)
} else {
funcs = append(funcs, compiled)
compiled, err := e.lowerIR(ir)
if err != nil {
def := module.FunctionDefinitionSection[uint32(i)+module.ImportFuncCount()]
return fmt.Errorf("failed to lower func[%s] to wazeroir: %w", def.DebugName(), err)
}
compiled.listener = lsn
funcs[i] = compiled
}
}
e.addCodes(module, funcs)
return nil
@@ -855,7 +867,7 @@ func (ce *callEngine) recoverOnCall(v interface{}) (err error) {
func (ce *callEngine) callFunction(ctx context.Context, callCtx *wasm.CallContext, f *function) {
if f.hostFn != nil {
ce.callGoFuncWithStack(ctx, callCtx, f)
} else if lsn := f.source.Listener; lsn != nil {
} else if lsn := f.parent.listener; lsn != nil {
ce.callNativeFuncWithListener(ctx, callCtx, f, lsn)
} else {
ce.callNativeFunc(ctx, callCtx, f)
@@ -863,9 +875,10 @@ func (ce *callEngine) callFunction(ctx context.Context, callCtx *wasm.CallContex
}
func (ce *callEngine) callGoFunc(ctx context.Context, callCtx *wasm.CallContext, f *function, stack []uint64) {
if f.source.Listener != nil {
lsn := f.parent.listener
if lsn != nil {
params := stack[:f.source.Type.ParamNumInUint64]
ctx = f.source.Listener.Before(ctx, f.source.Definition, params)
ctx = lsn.Before(ctx, f.source.Definition, params)
}
frame := &callFrame{f: f}
ce.pushFrame(frame)
@@ -879,10 +892,10 @@ func (ce *callEngine) callGoFunc(ctx context.Context, callCtx *wasm.CallContext,
}
ce.popFrame()
if f.source.Listener != nil {
if lsn != nil {
// TODO: This doesn't get the error due to use of panic to propagate them.
results := stack[:f.source.Type.ResultNumInUint64]
f.source.Listener.After(ctx, f.source.Definition, nil, results)
lsn.After(ctx, f.source.Definition, nil, results)
}
}

View File

@@ -185,7 +185,7 @@ func setupHostCallBench(requireNoError func(error)) *wasm.ModuleInstance {
hostModule.BuildFunctionDefinitions()
host := &wasm.ModuleInstance{Name: "host", TypeIDs: []wasm.FunctionTypeID{0}}
host.Functions = host.BuildFunctions(hostModule, nil)
host.Functions = host.BuildFunctions(hostModule)
host.BuildExports(hostModule.ExportSection)
goFn := host.Exports["go"].Function
goReflectFn := host.Exports["go-reflect"].Function
@@ -228,7 +228,7 @@ func setupHostCallBench(requireNoError func(error)) *wasm.ModuleInstance {
requireNoError(err)
importing := &wasm.ModuleInstance{TypeIDs: []wasm.FunctionTypeID{0}}
importingFunctions := importing.BuildFunctions(importingModule, nil)
importingFunctions := importing.BuildFunctions(importingModule)
importing.Functions = append([]*wasm.FunctionInstance{goFn, wasnFn}, importingFunctions...)
importing.BuildExports(importingModule.ExportSection)

View File

@@ -370,7 +370,7 @@ func addSpectestModule(t *testing.T, ctx context.Context, s *wasm.Store, ns *was
err = s.Engine.CompileModule(ctx, mod, nil)
require.NoError(t, err)
_, err = s.Instantiate(ctx, ns, mod, mod.NameSection.ModuleName, sys.DefaultContext(nil), nil)
_, err = s.Instantiate(ctx, ns, mod, mod.NameSection.ModuleName, sys.DefaultContext(nil))
require.NoError(t, err)
}
@@ -436,7 +436,7 @@ func Run(t *testing.T, testDataFS embed.FS, ctx context.Context, newEngine func(
err = s.Engine.CompileModule(ctx, mod, nil)
require.NoError(t, err, msg)
_, err = s.Instantiate(ctx, ns, mod, moduleName, nil, nil)
_, err = s.Instantiate(ctx, ns, mod, moduleName, nil)
lastInstantiatedModuleName = moduleName
require.NoError(t, err)
case "register":
@@ -574,7 +574,7 @@ func Run(t *testing.T, testDataFS embed.FS, ctx context.Context, newEngine func(
err = s.Engine.CompileModule(ctx, mod, nil)
require.NoError(t, err, msg)
_, err = s.Instantiate(ctx, ns, mod, t.Name(), nil, nil)
_, err = s.Instantiate(ctx, ns, mod, t.Name(), nil)
require.NoError(t, err, msg)
} else {
requireInstantiationError(t, ctx, s, ns, buf, msg)
@@ -609,7 +609,7 @@ func requireInstantiationError(t *testing.T, ctx context.Context, s *wasm.Store,
return
}
_, err = s.Instantiate(ctx, ns, mod, t.Name(), nil, nil)
_, err = s.Instantiate(ctx, ns, mod, t.Name(), nil)
require.Error(t, err, msg)
}

View File

@@ -97,7 +97,7 @@ func RunTestEngine_InitializeFuncrefGlobals(t *testing.T, et EngineTester) {
// To use the function, we first need to add it to a module.
instance := &wasm.ModuleInstance{Name: t.Name(), TypeIDs: []wasm.FunctionTypeID{0}}
fns := instance.BuildFunctions(m, buildListeners(et.ListenerFactory(), m))
fns := instance.BuildFunctions(m)
me, err := e.NewModuleEngine(t.Name(), m, nil, fns, nil, nil)
require.NoError(t, err)
@@ -148,7 +148,7 @@ func RunTestModuleEngine_Call(t *testing.T, et EngineTester) {
// To use the function, we first need to add it to a module.
module := &wasm.ModuleInstance{Name: t.Name(), TypeIDs: []wasm.FunctionTypeID{0}}
module.Functions = module.BuildFunctions(m, listeners)
module.Functions = module.BuildFunctions(m)
// Compile the module
me, err := e.NewModuleEngine(module.Name, m, nil, module.Functions, nil, nil)
@@ -216,7 +216,7 @@ func requireNewModuleEngine_emptyTable(t *testing.T, e wasm.Engine, et EngineTes
require.NoError(t, err)
module = &wasm.ModuleInstance{Name: t.Name(), Tables: tables, TypeIDs: []wasm.FunctionTypeID{0}}
fns := module.BuildFunctions(m, buildListeners(et.ListenerFactory(), m))
fns := module.BuildFunctions(m)
// Instantiate the module, which has nothing but an empty table.
me, err = e.NewModuleEngine(t.Name(), m, nil, fns, tables, nil)
@@ -251,7 +251,7 @@ func requireNewModuleEngine_multiTable(t *testing.T, e wasm.Engine, et EngineTes
require.NoError(t, err)
module = &wasm.ModuleInstance{Name: t.Name(), Tables: tables, TypeIDs: []wasm.FunctionTypeID{0}}
fns := module.BuildFunctions(m, buildListeners(et.ListenerFactory(), m))
fns := module.BuildFunctions(m)
tableInits := []wasm.TableInitEntry{
{TableIndex: 0, Offset: 0, FunctionIndexes: []*wasm.Index{&func1}},
@@ -290,7 +290,7 @@ func requireNewModuleEngine_tableWithImportedFunction(t *testing.T, e wasm.Engin
require.NoError(t, err)
imported := &wasm.ModuleInstance{Name: t.Name(), Tables: tables, TypeIDs: []wasm.FunctionTypeID{0}}
importedFunctions := imported.BuildFunctions(importedModule, buildListeners(et.ListenerFactory(), importedModule))
importedFunctions := imported.BuildFunctions(importedModule)
// Imported functions are compiled before the importing module is instantiated.
importedMe, err := e.NewModuleEngine(t.Name(), importedModule, nil, importedFunctions, nil, nil)
@@ -313,7 +313,7 @@ func requireNewModuleEngine_tableWithImportedFunction(t *testing.T, e wasm.Engin
}
importing = &wasm.ModuleInstance{Name: t.Name(), Tables: tables, TypeIDs: []wasm.FunctionTypeID{0}}
fns := importing.BuildFunctions(importingModule, buildListeners(et.ListenerFactory(), importingModule))
fns := importing.BuildFunctions(importingModule)
importingMe, err = e.NewModuleEngine(t.Name(), importingModule, importedFunctions, fns, tables, tableInits)
require.NoError(t, err)
@@ -341,7 +341,7 @@ func requireNewModuleEngine_tableWithMixedFunctions(t *testing.T, e wasm.Engine,
err := e.CompileModule(testCtx, importedModule, nil)
require.NoError(t, err)
imported := &wasm.ModuleInstance{Name: t.Name(), TypeIDs: []wasm.FunctionTypeID{0}}
importedFunctions := imported.BuildFunctions(importedModule, buildListeners(et.ListenerFactory(), importedModule))
importedFunctions := imported.BuildFunctions(importedModule)
// Imported functions are compiled before the importing module is instantiated.
importedMe, err := e.NewModuleEngine(t.Name(), importedModule, nil, importedFunctions, nil, nil)
@@ -364,7 +364,7 @@ func requireNewModuleEngine_tableWithMixedFunctions(t *testing.T, e wasm.Engine,
require.NoError(t, err)
importing = &wasm.ModuleInstance{Name: t.Name(), Tables: tables, TypeIDs: []wasm.FunctionTypeID{0}}
fns := importing.BuildFunctions(importingModule, buildListeners(et.ListenerFactory(), importingModule))
fns := importing.BuildFunctions(importingModule)
tableInits := []wasm.TableInitEntry{
{TableIndex: 0, Offset: 0, FunctionIndexes: []*wasm.Index{&func1, &func2}},
@@ -695,7 +695,7 @@ func RunTestModuleEngine_Memory(t *testing.T, et EngineTester) {
var memory api.Memory = module.Memory
// To use functions, we need to instantiate them (associate them with a ModuleInstance).
module.Functions = module.BuildFunctions(m, listeners)
module.Functions = module.BuildFunctions(m)
module.BuildExports(m.ExportSection)
grow, init := module.Functions[0], module.Functions[1]
@@ -827,7 +827,7 @@ func setupCallTests(t *testing.T, e wasm.Engine, divBy *wasm.Code, fnlf experime
err := e.CompileModule(testCtx, hostModule, lns)
require.NoError(t, err)
host := &wasm.ModuleInstance{Name: hostModule.NameSection.ModuleName, TypeIDs: []wasm.FunctionTypeID{0}}
host.Functions = host.BuildFunctions(hostModule, lns)
host.Functions = host.BuildFunctions(hostModule)
host.BuildExports(hostModule.ExportSection)
hostFn := host.Exports[divByGoName].Function
@@ -863,7 +863,7 @@ func setupCallTests(t *testing.T, e wasm.Engine, divBy *wasm.Code, fnlf experime
require.NoError(t, err)
imported := &wasm.ModuleInstance{Name: importedModule.NameSection.ModuleName, TypeIDs: []wasm.FunctionTypeID{0}}
importedFunctions := imported.BuildFunctions(importedModule, lns)
importedFunctions := imported.BuildFunctions(importedModule)
imported.Functions = append([]*wasm.FunctionInstance{hostFn}, importedFunctions...)
imported.BuildExports(importedModule.ExportSection)
callHostFn := imported.Exports[callDivByGoName].Function
@@ -897,7 +897,7 @@ func setupCallTests(t *testing.T, e wasm.Engine, divBy *wasm.Code, fnlf experime
// Add the exported function.
importing := &wasm.ModuleInstance{Name: importingModule.NameSection.ModuleName, TypeIDs: []wasm.FunctionTypeID{0}}
importingFunctions := importing.BuildFunctions(importingModule, lns)
importingFunctions := importing.BuildFunctions(importingModule)
importing.Functions = append([]*wasm.FunctionInstance{callHostFn}, importingFunctions...)
importing.BuildExports(importingModule.ExportSection)
@@ -945,7 +945,7 @@ func setupCallMemTests(t *testing.T, e wasm.Engine, readMem *wasm.Code, fnlf exp
err := e.CompileModule(testCtx, hostModule, nil)
require.NoError(t, err)
host := &wasm.ModuleInstance{Name: hostModule.NameSection.ModuleName, TypeIDs: []wasm.FunctionTypeID{0}}
host.Functions = host.BuildFunctions(hostModule, buildListeners(fnlf, hostModule))
host.Functions = host.BuildFunctions(hostModule)
host.BuildExports(hostModule.ExportSection)
readMemFn := host.Exports[readMemName].Function
callReadMemFn := host.Exports[callReadMemName].Function
@@ -987,7 +987,7 @@ func setupCallMemTests(t *testing.T, e wasm.Engine, readMem *wasm.Code, fnlf exp
// Add the exported function.
importing := &wasm.ModuleInstance{Name: importingModule.NameSection.ModuleName, TypeIDs: []wasm.FunctionTypeID{0}}
importingFunctions := importing.BuildFunctions(importingModule, buildListeners(fnlf, importingModule))
importingFunctions := importing.BuildFunctions(importingModule)
// Note: adds imported functions readMemFn and callReadMemFn at index 0 and 1.
importing.Functions = append([]*wasm.FunctionInstance{callReadMemFn, readMemFn}, importingFunctions...)
importing.BuildExports(importingModule.ExportSection)

View File

@@ -82,7 +82,7 @@ func TestCallContext_String(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
// Ensure paths that can create the host module can see the name.
m, err := s.Instantiate(context.Background(), ns, &Module{}, tc.moduleName, nil, nil)
m, err := s.Instantiate(context.Background(), ns, &Module{}, tc.moduleName, nil)
defer m.Close(testCtx) //nolint
require.NoError(t, err)
@@ -121,7 +121,7 @@ func TestCallContext_Close(t *testing.T) {
t.Run(fmt.Sprintf("%s calls ns.CloseWithExitCode(module.name))", tc.name), func(t *testing.T) {
for _, ctx := range []context.Context{nil, testCtx} { // Ensure it doesn't crash on nil!
moduleName := t.Name()
m, err := s.Instantiate(ctx, ns, &Module{}, moduleName, nil, nil)
m, err := s.Instantiate(ctx, ns, &Module{}, moduleName, nil)
require.NoError(t, err)
// We use side effects to see if Close called ns.CloseWithExitCode (without repeating store_test.go).
@@ -149,7 +149,7 @@ func TestCallContext_Close(t *testing.T) {
_, err := fsCtx.OpenFile(testCtx, "/foo")
require.NoError(t, err)
m, err := s.Instantiate(context.Background(), ns, &Module{}, t.Name(), sysCtx, nil)
m, err := s.Instantiate(context.Background(), ns, &Module{}, t.Name(), sysCtx)
require.NoError(t, err)
// We use side effects to determine if Close in fact called Context.Close (without repeating sys_test.go).
@@ -177,7 +177,7 @@ func TestCallContext_Close(t *testing.T) {
_, err := fsCtx.OpenFile(testCtx, "/foo")
require.NoError(t, err)
m, err := s.Instantiate(context.Background(), ns, &Module{}, t.Name(), sysCtx, nil)
m, err := s.Instantiate(context.Background(), ns, &Module{}, t.Name(), sysCtx)
require.NoError(t, err)
require.EqualError(t, m.Close(testCtx), "error closing")
@@ -217,7 +217,7 @@ func TestCallContext_CallDynamic(t *testing.T) {
t.Run(fmt.Sprintf("%s calls ns.CloseWithExitCode(module.name))", tc.name), func(t *testing.T) {
for _, ctx := range []context.Context{nil, testCtx} { // Ensure it doesn't crash on nil!
moduleName := t.Name()
m, err := s.Instantiate(ctx, ns, &Module{}, moduleName, nil, nil)
m, err := s.Instantiate(ctx, ns, &Module{}, moduleName, nil)
require.NoError(t, err)
// We use side effects to see if Close called ns.CloseWithExitCode (without repeating store_test.go).
@@ -245,7 +245,7 @@ func TestCallContext_CallDynamic(t *testing.T) {
_, err := fsCtx.OpenFile(testCtx, "/foo")
require.NoError(t, err)
m, err := s.Instantiate(context.Background(), ns, &Module{}, t.Name(), sysCtx, nil)
m, err := s.Instantiate(context.Background(), ns, &Module{}, t.Name(), sysCtx)
require.NoError(t, err)
// We use side effects to determine if Close in fact called Context.Close (without repeating sys_test.go).
@@ -273,7 +273,7 @@ func TestCallContext_CallDynamic(t *testing.T) {
_, err := fsCtx.OpenFile(testCtx, "/foo")
require.NoError(t, err)
m, err := s.Instantiate(context.Background(), ns, &Module{}, t.Name(), sysCtx, nil)
m, err := s.Instantiate(context.Background(), ns, &Module{}, t.Name(), sysCtx)
require.NoError(t, err)
require.EqualError(t, m.Close(testCtx), "error closing")

View File

@@ -298,7 +298,7 @@ func TestPublicModule_Global(t *testing.T) {
s, ns := newStore()
t.Run(tc.name, func(t *testing.T) {
// Instantiate the module and get the export of the above global
module, err := s.Instantiate(context.Background(), ns, tc.module, t.Name(), nil, nil)
module, err := s.Instantiate(context.Background(), ns, tc.module, t.Name(), nil)
require.NoError(t, err)
if global := module.ExportedGlobal("global"); tc.expected != nil {

View File

@@ -10,7 +10,6 @@ import (
"strings"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/experimental"
"github.com/tetratelabs/wazero/internal/ieee754"
"github.com/tetratelabs/wazero/internal/leb128"
)
@@ -590,7 +589,7 @@ func (m *Module) buildGlobals(importedGlobals []*GlobalInstance) (globals []*Glo
// - This relies on data generated by Module.BuildFunctionDefinitions.
// - This is exported for tests that don't call Instantiate, notably only
// enginetest.go.
func (m *ModuleInstance) BuildFunctions(mod *Module, listeners []experimental.FunctionListener) (fns []*FunctionInstance) {
func (m *ModuleInstance) BuildFunctions(mod *Module) (fns []*FunctionInstance) {
importCount := mod.ImportFuncCount()
fns = make([]*FunctionInstance, len(mod.FunctionSection))
for i, section := range mod.FunctionSection {
@@ -607,9 +606,6 @@ func (m *ModuleInstance) BuildFunctions(mod *Module, listeners []experimental.Fu
Type: d.funcType,
Definition: d,
}
if listeners != nil {
f.Listener = listeners[i]
}
fns[i] = f
}
return

View File

@@ -792,7 +792,7 @@ func TestModule_buildFunctions(t *testing.T) {
// Note: This only returns module-defined functions, not imported ones. That's why the index starts with 1, not 0.
instance := &ModuleInstance{Name: "counter", TypeIDs: []FunctionTypeID{0}}
instance.BuildFunctions(m, nil)
instance.BuildFunctions(m)
for i, f := range instance.Functions {
require.Equal(t, i, f.Definition.Index())
require.Equal(t, nopCode.Body, f.Body)

View File

@@ -8,7 +8,6 @@ import (
"sync"
"github.com/tetratelabs/wazero/api"
experimentalapi "github.com/tetratelabs/wazero/experimental"
"github.com/tetratelabs/wazero/internal/ieee754"
"github.com/tetratelabs/wazero/internal/leb128"
internalsys "github.com/tetratelabs/wazero/internal/sys"
@@ -140,9 +139,6 @@ type (
// Definition is known at compile time.
Definition api.FunctionDefinition
// Listener holds a listener to notify when this function is called.
Listener experimentalapi.FunctionListener
}
// GlobalInstance represents a global instance in a store.
@@ -299,7 +295,6 @@ func (s *Store) Instantiate(
module *Module,
name string,
sys *internalsys.Context,
listeners []experimentalapi.FunctionListener,
) (*CallContext, error) {
// Collect any imported modules to avoid locking the namespace too long.
importedModuleNames := map[string]struct{}{}
@@ -319,7 +314,7 @@ func (s *Store) Instantiate(
}
// Instantiate the module and add it to the namespace so that other modules can import it.
if callCtx, err := s.instantiate(ctx, ns, module, name, sys, listeners, importedModules); err != nil {
if callCtx, err := s.instantiate(ctx, ns, module, name, sys, importedModules); err != nil {
ns.deleteModule(name)
return nil, err
} else {
@@ -336,7 +331,6 @@ func (s *Store) instantiate(
module *Module,
name string,
sysCtx *internalsys.Context,
listeners []experimentalapi.FunctionListener,
modules map[string]*ModuleInstance,
) (*CallContext, error) {
typeIDs, err := s.getFunctionTypeIDs(module.TypeSection)
@@ -358,7 +352,7 @@ func (s *Store) instantiate(
globals, memory := module.buildGlobals(importedGlobals), module.buildMemory()
m := &ModuleInstance{Name: name, TypeIDs: typeIDs}
functions := m.BuildFunctions(module, listeners)
functions := m.BuildFunctions(module)
// Now we have all instances from imports and local ones, so ready to create a new ModuleInstance.
m.addSections(module, importedFunctions, functions, importedGlobals, globals, tables, importedMemory, memory, module.TypeSection)

View File

@@ -77,7 +77,7 @@ func TestModuleInstance_Memory(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
s, ns := newStore()
instance, err := s.Instantiate(testCtx, ns, tc.input, "test", nil, nil)
instance, err := s.Instantiate(testCtx, ns, tc.input, "test", nil)
require.NoError(t, err)
mem := instance.ExportedMemory("memory")
@@ -96,7 +96,7 @@ func TestStore_Instantiate(t *testing.T) {
require.NoError(t, err)
sysCtx := sys.DefaultContext(nil)
mod, err := s.Instantiate(testCtx, ns, m, "", sysCtx, nil)
mod, err := s.Instantiate(testCtx, ns, m, "", sysCtx)
require.NoError(t, err)
defer mod.Close(testCtx)
@@ -137,7 +137,7 @@ func TestStore_CloseWithExitCode(t *testing.T) {
CodeSection: []*Code{{Body: []byte{OpcodeEnd}}},
ExportSection: []*Export{{Type: ExternTypeFunc, Index: 0, Name: "fn"}},
FunctionDefinitionSection: []*FunctionDefinition{{funcType: v_v}},
}, importedModuleName, nil, nil)
}, importedModuleName, nil)
require.NoError(t, err)
m2, err := s.Instantiate(testCtx, ns, &Module{
@@ -146,7 +146,7 @@ func TestStore_CloseWithExitCode(t *testing.T) {
MemorySection: &Memory{Min: 1, Cap: 1},
GlobalSection: []*Global{{Type: &GlobalType{}, Init: &ConstantExpression{Opcode: OpcodeI32Const, Data: const1}}},
TableSection: []*Table{{Min: 10}},
}, importingModuleName, nil, nil)
}, importingModuleName, nil)
require.NoError(t, err)
if tc.testClosed {
@@ -174,7 +174,7 @@ func TestStore_hammer(t *testing.T) {
require.NoError(t, err)
s, ns := newStore()
imported, err := s.Instantiate(testCtx, ns, m, importedModuleName, nil, nil)
imported, err := s.Instantiate(testCtx, ns, m, importedModuleName, nil)
require.NoError(t, err)
_, ok := ns.modules[imported.Name()]
@@ -205,7 +205,7 @@ func TestStore_hammer(t *testing.T) {
N = 100
}
hammer.NewHammer(t, P, N).Run(func(name string) {
mod, instantiateErr := s.Instantiate(testCtx, ns, importingModule, name, sys.DefaultContext(nil), nil)
mod, instantiateErr := s.Instantiate(testCtx, ns, importingModule, name, sys.DefaultContext(nil))
require.NoError(t, instantiateErr)
require.NoError(t, mod.Close(testCtx))
}, nil)
@@ -229,17 +229,17 @@ func TestStore_Instantiate_Errors(t *testing.T) {
t.Run("Fails if module name already in use", func(t *testing.T) {
s, ns := newStore()
_, err = s.Instantiate(testCtx, ns, m, importedModuleName, nil, nil)
_, err = s.Instantiate(testCtx, ns, m, importedModuleName, nil)
require.NoError(t, err)
// Trying to register it again should fail
_, err = s.Instantiate(testCtx, ns, m, importedModuleName, nil, nil)
_, err = s.Instantiate(testCtx, ns, m, importedModuleName, nil)
require.EqualError(t, err, "module[imported] has already been instantiated")
})
t.Run("fail resolve import", func(t *testing.T) {
s, ns := newStore()
_, err = s.Instantiate(testCtx, ns, m, importedModuleName, nil, nil)
_, err = s.Instantiate(testCtx, ns, m, importedModuleName, nil)
require.NoError(t, err)
hm := ns.modules[importedModuleName]
@@ -253,14 +253,14 @@ func TestStore_Instantiate_Errors(t *testing.T) {
// But the second one tries to import uninitialized-module ->
{Type: ExternTypeFunc, Module: "non-exist", Name: "fn", DescFunc: 0},
},
}, importingModuleName, nil, nil)
}, importingModuleName, nil)
require.EqualError(t, err, "module[non-exist] not instantiated")
})
t.Run("compilation failed", func(t *testing.T) {
s, ns := newStore()
_, err = s.Instantiate(testCtx, ns, m, importedModuleName, nil, nil)
_, err = s.Instantiate(testCtx, ns, m, importedModuleName, nil)
require.NoError(t, err)
hm := ns.modules[importedModuleName]
@@ -282,7 +282,7 @@ func TestStore_Instantiate_Errors(t *testing.T) {
}
importingModule.BuildFunctionDefinitions()
_, err = s.Instantiate(testCtx, ns, importingModule, importingModuleName, nil, nil)
_, err = s.Instantiate(testCtx, ns, importingModule, importingModuleName, nil)
require.EqualError(t, err, "compilation failed: some compilation error")
})
@@ -291,7 +291,7 @@ func TestStore_Instantiate_Errors(t *testing.T) {
engine := s.Engine.(*mockEngine)
engine.callFailIndex = 1
_, err = s.Instantiate(testCtx, ns, m, importedModuleName, nil, nil)
_, err = s.Instantiate(testCtx, ns, m, importedModuleName, nil)
require.NoError(t, err)
hm := ns.modules[importedModuleName]
@@ -309,7 +309,7 @@ func TestStore_Instantiate_Errors(t *testing.T) {
}
importingModule.BuildFunctionDefinitions()
_, err = s.Instantiate(testCtx, ns, importingModule, importingModuleName, nil, nil)
_, err = s.Instantiate(testCtx, ns, importingModule, importingModuleName, nil)
require.EqualError(t, err, "start function[1] failed: call failed")
})
}
@@ -321,7 +321,7 @@ func TestCallContext_ExportedFunction(t *testing.T) {
s, ns := newStore()
// Add the host module
imported, err := s.Instantiate(testCtx, ns, host, host.NameSection.ModuleName, nil, nil)
imported, err := s.Instantiate(testCtx, ns, host, host.NameSection.ModuleName, nil)
require.NoError(t, err)
defer imported.Close(testCtx)
@@ -331,7 +331,7 @@ func TestCallContext_ExportedFunction(t *testing.T) {
ImportSection: []*Import{{Type: ExternTypeFunc, Module: "host", Name: "host_fn", DescFunc: 0}},
MemorySection: &Memory{Min: 1, Cap: 1},
ExportSection: []*Export{{Type: ExternTypeFunc, Name: "host.fn", Index: 0}},
}, "test", nil, nil)
}, "test", nil)
require.NoError(t, err)
defer importing.Close(testCtx)

View File

@@ -79,7 +79,7 @@ func (ns *namespace) InstantiateModule(
}
// Instantiate the module in the appropriate namespace.
mod, err = ns.store.Instantiate(ctx, ns.ns, code.module, name, sysCtx, code.listeners)
mod, err = ns.store.Instantiate(ctx, ns.ns, code.module, name, sysCtx)
if err != nil {
// If there was an error, don't leak the compiled module.
if code.closeWithModule {

View File

@@ -189,11 +189,12 @@ func (r *runtime) CompileModule(ctx context.Context, binary []byte) (CompiledMod
c := &compiledModule{module: internal, compiledEngine: r.store.Engine}
if c.listeners, err = buildListeners(ctx, internal); err != nil {
listeners, err := buildListeners(ctx, internal)
if err != nil {
return nil, err
}
if err = r.store.Engine.CompileModule(ctx, internal, c.listeners); err != nil {
if err = r.store.Engine.CompileModule(ctx, internal, listeners); err != nil {
return nil, err
}