diff --git a/config.go b/config.go index 51b5b6ab..dd90a444 100644 --- a/config.go +++ b/config.go @@ -267,15 +267,24 @@ func (c *runtimeConfig) WithWasmCore2() RuntimeConfig { // // Note: Closing the wazero.Runtime closes any CompiledModule it compiled. type CompiledModule interface { - // ImportedFunctions returns all the imported functions (api.FunctionDefinition) in this module. + // Name returns the module name encoded into the binary or empty if not. + Name() string + + // ImportedFunctions returns all the imported functions + // (api.FunctionDefinition) in this module or nil if there are none. + // + // Note: Unlike ExportedFunctions, there is no unique constraint on + // imports. ImportedFunctions() []api.FunctionDefinition - // ExportedFunctions returns all the exported functions (api.FunctionDefinition) in this module. - ExportedFunctions() []api.FunctionDefinition + // ExportedFunctions returns all the exported functions + // (api.FunctionDefinition) in this module keyed on export name. + ExportedFunctions() map[string]api.FunctionDefinition // Close releases all the allocated resources for this CompiledModule. // - // Note: It is safe to call Close while having outstanding calls from an api.Module instantiated from this. + // Note: It is safe to call Close while having outstanding calls from an + // api.Module instantiated from this. Close(context.Context) error } @@ -289,6 +298,14 @@ type compiledModule struct { closeWithModule bool } +// Name implements CompiledModule.Name +func (c *compiledModule) Name() (moduleName string) { + if ns := c.module.NameSection; ns != nil { + moduleName = ns.ModuleName + } + return +} + // Close implements CompiledModule.Close func (c *compiledModule) Close(_ context.Context) error { // Note: If you use the context.Context param, don't forget to coerce nil to context.Background()! @@ -304,7 +321,7 @@ func (c *compiledModule) ImportedFunctions() []api.FunctionDefinition { } // ExportedFunctions implements CompiledModule.ExportedFunctions -func (c *compiledModule) ExportedFunctions() []api.FunctionDefinition { +func (c *compiledModule) ExportedFunctions() map[string]api.FunctionDefinition { return c.module.ExportedFunctions() } diff --git a/config_test.go b/config_test.go index c1188c46..a17b2711 100644 --- a/config_test.go +++ b/config_test.go @@ -689,6 +689,7 @@ func TestModuleConfig_toSysContext_Errors(t *testing.T) { }) } } + func TestModuleConfig_clone(t *testing.T) { mc := NewModuleConfig().(*moduleConfig) cloned := mc.clone() @@ -707,7 +708,37 @@ func TestModuleConfig_clone(t *testing.T) { require.Nil(t, cloned.fs) } -func TestCompiledCode_Close(t *testing.T) { +func Test_compiledModule_Name(t *testing.T) { + tests := []struct { + name string + input *compiledModule + expected string + }{ + { + name: "no name section", + input: &compiledModule{module: &wasm.Module{}}, + }, + { + name: "empty name", + input: &compiledModule{module: &wasm.Module{NameSection: &wasm.NameSection{}}}, + }, + { + name: "name", + input: &compiledModule{module: &wasm.Module{NameSection: &wasm.NameSection{ModuleName: "foo"}}}, + expected: "foo", + }, + } + + for _, tt := range tests { + tc := tt + + t.Run(tc.name, func(t *testing.T) { + require.Equal(t, tc.expected, tc.input.Name()) + }) + } +} + +func Test_compiledModule_Close(t *testing.T) { for _, ctx := range []context.Context{nil, testCtx} { // Ensure it doesn't crash on nil! e := &mockEngine{name: "1", cachedModules: map[*wasm.Module]struct{}{}} diff --git a/experimental/log_listener.go b/experimental/log_listener.go index 202a6260..94c1d43d 100644 --- a/experimental/log_listener.go +++ b/experimental/log_listener.go @@ -12,7 +12,7 @@ import ( ) // NewLoggingListenerFactory implements FunctionListenerFactory to log all -// function calls to the writer. +// functions that have a name to the writer. func NewLoggingListenerFactory(writer io.Writer) FunctionListenerFactory { return &loggingListenerFactory{writer} } diff --git a/internal/wasm/function_definition.go b/internal/wasm/function_definition.go index 281fe790..45d6c6dc 100644 --- a/internal/wasm/function_definition.go +++ b/internal/wasm/function_definition.go @@ -6,6 +6,8 @@ import ( ) // ImportedFunctions returns the definitions of each imported function. +// +// Note: Unlike ExportedFunctions, there is no unique constraint on imports. func (m *Module) ImportedFunctions() (ret []api.FunctionDefinition) { for _, d := range m.FunctionDefinitionSection { if d.importDesc != nil { @@ -16,13 +18,14 @@ func (m *Module) ImportedFunctions() (ret []api.FunctionDefinition) { } // ExportedFunctions returns the definitions of each exported function. -func (m *Module) ExportedFunctions() (ret []api.FunctionDefinition) { +func (m *Module) ExportedFunctions() map[string]api.FunctionDefinition { + ret := map[string]api.FunctionDefinition{} for _, d := range m.FunctionDefinitionSection { - if d.exportNames != nil { - ret = append(ret, d) + for _, e := range d.exportNames { + ret[e] = d } } - return + return ret } // BuildFunctionDefinitions generates function metadata that can be parsed from diff --git a/internal/wasm/function_definition_test.go b/internal/wasm/function_definition_test.go index 408893ff..9400b043 100644 --- a/internal/wasm/function_definition_test.go +++ b/internal/wasm/function_definition_test.go @@ -12,14 +12,16 @@ func TestModule_BuildFunctionDefinitions(t *testing.T) { nopCode := &Code{nil, []byte{OpcodeEnd}} fnV := reflect.ValueOf(func() {}) tests := []struct { - name string - m *Module - expected []*FunctionDefinition - expectedImports, expectedExports []api.FunctionDefinition + name string + m *Module + expected []*FunctionDefinition + expectedImports []api.FunctionDefinition + expectedExports map[string]api.FunctionDefinition }{ { - name: "no exports", - m: &Module{}, + name: "no exports", + m: &Module{}, + expectedExports: map[string]api.FunctionDefinition{}, }, { name: "no functions", @@ -27,6 +29,7 @@ func TestModule_BuildFunctionDefinitions(t *testing.T) { ExportSection: []*Export{{Type: ExternTypeGlobal, Index: 0}}, GlobalSection: []*Global{{}}, }, + expectedExports: map[string]api.FunctionDefinition{}, }, { name: "host func", @@ -43,6 +46,7 @@ func TestModule_BuildFunctionDefinitions(t *testing.T) { funcType: v_v, }, }, + expectedExports: map[string]api.FunctionDefinition{}, }, { name: "without imports", @@ -81,20 +85,20 @@ func TestModule_BuildFunctionDefinitions(t *testing.T) { funcType: v_v, }, }, - expectedExports: []api.FunctionDefinition{ - &FunctionDefinition{ + expectedExports: map[string]api.FunctionDefinition{ + "function_index=0": &FunctionDefinition{ index: 0, debugName: ".$0", exportNames: []string{"function_index=0"}, funcType: &FunctionType{Params: []ValueType{ValueTypeF64, ValueTypeI32}, Results: []ValueType{ValueTypeV128, ValueTypeI64}}, }, - &FunctionDefinition{ + "function_index=1": &FunctionDefinition{ index: 1, exportNames: []string{"function_index=1"}, debugName: ".$1", funcType: &FunctionType{Params: []ValueType{ValueTypeF64, ValueTypeF32}, Results: []ValueType{ValueTypeI64}}, }, - &FunctionDefinition{ + "function_index=2": &FunctionDefinition{ index: 2, debugName: ".$2", exportNames: []string{"function_index=2"}, @@ -151,21 +155,21 @@ func TestModule_BuildFunctionDefinitions(t *testing.T) { funcType: &FunctionType{Params: []ValueType{ValueTypeF64, ValueTypeF32}, Results: []ValueType{ValueTypeI64}}, }, }, - expectedExports: []api.FunctionDefinition{ - &FunctionDefinition{ + expectedExports: map[string]api.FunctionDefinition{ + "imported_function": &FunctionDefinition{ index: 0, debugName: ".$0", importDesc: &[2]string{"", ""}, exportNames: []string{"imported_function"}, funcType: &FunctionType{Params: []ValueType{ValueTypeF64, ValueTypeF32}, Results: []ValueType{ValueTypeI64}}, }, - &FunctionDefinition{ + "function_index=1": &FunctionDefinition{ index: 1, debugName: ".$1", exportNames: []string{"function_index=1"}, funcType: &FunctionType{Params: []ValueType{ValueTypeF64, ValueTypeI32}, Results: []ValueType{ValueTypeV128, ValueTypeI64}}, }, - &FunctionDefinition{ + "function_index=2": &FunctionDefinition{ index: 2, debugName: ".$2", exportNames: []string{"function_index=2"}, @@ -200,6 +204,7 @@ func TestModule_BuildFunctionDefinitions(t *testing.T) { expectedImports: []api.FunctionDefinition{ &FunctionDefinition{moduleName: "module", index: 0, debugName: "module.$0", importDesc: &[2]string{"i", "f"}, funcType: v_v}, }, + expectedExports: map[string]api.FunctionDefinition{}, }, }