Makes ExportedFunctions unique (#698)

Exported functions are easier to use as a map vs making the callers do
it.

Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
Crypt Keeper
2022-07-14 18:05:12 +08:00
committed by GitHub
parent 040736caac
commit 5f92e37d19
5 changed files with 81 additions and 25 deletions

View File

@@ -267,15 +267,24 @@ func (c *runtimeConfig) WithWasmCore2() RuntimeConfig {
// //
// Note: Closing the wazero.Runtime closes any CompiledModule it compiled. // Note: Closing the wazero.Runtime closes any CompiledModule it compiled.
type CompiledModule interface { 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 ImportedFunctions() []api.FunctionDefinition
// ExportedFunctions returns all the exported functions (api.FunctionDefinition) in this module. // ExportedFunctions returns all the exported functions
ExportedFunctions() []api.FunctionDefinition // (api.FunctionDefinition) in this module keyed on export name.
ExportedFunctions() map[string]api.FunctionDefinition
// Close releases all the allocated resources for this CompiledModule. // 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 Close(context.Context) error
} }
@@ -289,6 +298,14 @@ type compiledModule struct {
closeWithModule bool 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 // Close implements CompiledModule.Close
func (c *compiledModule) Close(_ context.Context) error { func (c *compiledModule) Close(_ context.Context) error {
// Note: If you use the context.Context param, don't forget to coerce nil to context.Background()! // 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 // ExportedFunctions implements CompiledModule.ExportedFunctions
func (c *compiledModule) ExportedFunctions() []api.FunctionDefinition { func (c *compiledModule) ExportedFunctions() map[string]api.FunctionDefinition {
return c.module.ExportedFunctions() return c.module.ExportedFunctions()
} }

View File

@@ -689,6 +689,7 @@ func TestModuleConfig_toSysContext_Errors(t *testing.T) {
}) })
} }
} }
func TestModuleConfig_clone(t *testing.T) { func TestModuleConfig_clone(t *testing.T) {
mc := NewModuleConfig().(*moduleConfig) mc := NewModuleConfig().(*moduleConfig)
cloned := mc.clone() cloned := mc.clone()
@@ -707,7 +708,37 @@ func TestModuleConfig_clone(t *testing.T) {
require.Nil(t, cloned.fs) 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! for _, ctx := range []context.Context{nil, testCtx} { // Ensure it doesn't crash on nil!
e := &mockEngine{name: "1", cachedModules: map[*wasm.Module]struct{}{}} e := &mockEngine{name: "1", cachedModules: map[*wasm.Module]struct{}{}}

View File

@@ -12,7 +12,7 @@ import (
) )
// NewLoggingListenerFactory implements FunctionListenerFactory to log all // 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 { func NewLoggingListenerFactory(writer io.Writer) FunctionListenerFactory {
return &loggingListenerFactory{writer} return &loggingListenerFactory{writer}
} }

View File

@@ -6,6 +6,8 @@ import (
) )
// ImportedFunctions returns the definitions of each imported function. // 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) { func (m *Module) ImportedFunctions() (ret []api.FunctionDefinition) {
for _, d := range m.FunctionDefinitionSection { for _, d := range m.FunctionDefinitionSection {
if d.importDesc != nil { if d.importDesc != nil {
@@ -16,13 +18,14 @@ func (m *Module) ImportedFunctions() (ret []api.FunctionDefinition) {
} }
// ExportedFunctions returns the definitions of each exported function. // 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 { for _, d := range m.FunctionDefinitionSection {
if d.exportNames != nil { for _, e := range d.exportNames {
ret = append(ret, d) ret[e] = d
} }
} }
return return ret
} }
// BuildFunctionDefinitions generates function metadata that can be parsed from // BuildFunctionDefinitions generates function metadata that can be parsed from

View File

@@ -12,14 +12,16 @@ func TestModule_BuildFunctionDefinitions(t *testing.T) {
nopCode := &Code{nil, []byte{OpcodeEnd}} nopCode := &Code{nil, []byte{OpcodeEnd}}
fnV := reflect.ValueOf(func() {}) fnV := reflect.ValueOf(func() {})
tests := []struct { tests := []struct {
name string name string
m *Module m *Module
expected []*FunctionDefinition expected []*FunctionDefinition
expectedImports, expectedExports []api.FunctionDefinition expectedImports []api.FunctionDefinition
expectedExports map[string]api.FunctionDefinition
}{ }{
{ {
name: "no exports", name: "no exports",
m: &Module{}, m: &Module{},
expectedExports: map[string]api.FunctionDefinition{},
}, },
{ {
name: "no functions", name: "no functions",
@@ -27,6 +29,7 @@ func TestModule_BuildFunctionDefinitions(t *testing.T) {
ExportSection: []*Export{{Type: ExternTypeGlobal, Index: 0}}, ExportSection: []*Export{{Type: ExternTypeGlobal, Index: 0}},
GlobalSection: []*Global{{}}, GlobalSection: []*Global{{}},
}, },
expectedExports: map[string]api.FunctionDefinition{},
}, },
{ {
name: "host func", name: "host func",
@@ -43,6 +46,7 @@ func TestModule_BuildFunctionDefinitions(t *testing.T) {
funcType: v_v, funcType: v_v,
}, },
}, },
expectedExports: map[string]api.FunctionDefinition{},
}, },
{ {
name: "without imports", name: "without imports",
@@ -81,20 +85,20 @@ func TestModule_BuildFunctionDefinitions(t *testing.T) {
funcType: v_v, funcType: v_v,
}, },
}, },
expectedExports: []api.FunctionDefinition{ expectedExports: map[string]api.FunctionDefinition{
&FunctionDefinition{ "function_index=0": &FunctionDefinition{
index: 0, index: 0,
debugName: ".$0", debugName: ".$0",
exportNames: []string{"function_index=0"}, exportNames: []string{"function_index=0"},
funcType: &FunctionType{Params: []ValueType{ValueTypeF64, ValueTypeI32}, Results: []ValueType{ValueTypeV128, ValueTypeI64}}, funcType: &FunctionType{Params: []ValueType{ValueTypeF64, ValueTypeI32}, Results: []ValueType{ValueTypeV128, ValueTypeI64}},
}, },
&FunctionDefinition{ "function_index=1": &FunctionDefinition{
index: 1, index: 1,
exportNames: []string{"function_index=1"}, exportNames: []string{"function_index=1"},
debugName: ".$1", debugName: ".$1",
funcType: &FunctionType{Params: []ValueType{ValueTypeF64, ValueTypeF32}, Results: []ValueType{ValueTypeI64}}, funcType: &FunctionType{Params: []ValueType{ValueTypeF64, ValueTypeF32}, Results: []ValueType{ValueTypeI64}},
}, },
&FunctionDefinition{ "function_index=2": &FunctionDefinition{
index: 2, index: 2,
debugName: ".$2", debugName: ".$2",
exportNames: []string{"function_index=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}}, funcType: &FunctionType{Params: []ValueType{ValueTypeF64, ValueTypeF32}, Results: []ValueType{ValueTypeI64}},
}, },
}, },
expectedExports: []api.FunctionDefinition{ expectedExports: map[string]api.FunctionDefinition{
&FunctionDefinition{ "imported_function": &FunctionDefinition{
index: 0, index: 0,
debugName: ".$0", debugName: ".$0",
importDesc: &[2]string{"", ""}, importDesc: &[2]string{"", ""},
exportNames: []string{"imported_function"}, exportNames: []string{"imported_function"},
funcType: &FunctionType{Params: []ValueType{ValueTypeF64, ValueTypeF32}, Results: []ValueType{ValueTypeI64}}, funcType: &FunctionType{Params: []ValueType{ValueTypeF64, ValueTypeF32}, Results: []ValueType{ValueTypeI64}},
}, },
&FunctionDefinition{ "function_index=1": &FunctionDefinition{
index: 1, index: 1,
debugName: ".$1", debugName: ".$1",
exportNames: []string{"function_index=1"}, exportNames: []string{"function_index=1"},
funcType: &FunctionType{Params: []ValueType{ValueTypeF64, ValueTypeI32}, Results: []ValueType{ValueTypeV128, ValueTypeI64}}, funcType: &FunctionType{Params: []ValueType{ValueTypeF64, ValueTypeI32}, Results: []ValueType{ValueTypeV128, ValueTypeI64}},
}, },
&FunctionDefinition{ "function_index=2": &FunctionDefinition{
index: 2, index: 2,
debugName: ".$2", debugName: ".$2",
exportNames: []string{"function_index=2"}, exportNames: []string{"function_index=2"},
@@ -200,6 +204,7 @@ func TestModule_BuildFunctionDefinitions(t *testing.T) {
expectedImports: []api.FunctionDefinition{ expectedImports: []api.FunctionDefinition{
&FunctionDefinition{moduleName: "module", index: 0, debugName: "module.$0", importDesc: &[2]string{"i", "f"}, funcType: v_v}, &FunctionDefinition{moduleName: "module", index: 0, debugName: "module.$0", importDesc: &[2]string{"i", "f"}, funcType: v_v},
}, },
expectedExports: map[string]api.FunctionDefinition{},
}, },
} }