Ensures listeners only bound to compile time objects (#870)
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user