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.
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()
}

View File

@@ -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{}{}}

View File

@@ -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}
}

View File

@@ -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

View File

@@ -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{},
},
}