Adds ExportedFunctionDefinitions and ExportedMemoryDefinitions (#986)
This adds ExportedFunctionDefinitions and ExportedMemoryDefinitions to api.Module so that those who can't access CompileModule can see them. Fixes #839 Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
11
api/wasm.go
11
api/wasm.go
@@ -147,6 +147,10 @@ type Module interface {
|
||||
// ExportedFunction returns a function exported from this module or nil if it wasn't.
|
||||
ExportedFunction(name string) Function
|
||||
|
||||
// ExportedFunctionDefinitions returns all the exported function
|
||||
// definitions in this module, keyed on export name.
|
||||
ExportedFunctionDefinitions() map[string]FunctionDefinition
|
||||
|
||||
// TODO: Table
|
||||
|
||||
// ExportedMemory returns a memory exported from this module or nil if it wasn't.
|
||||
@@ -157,6 +161,13 @@ type Module interface {
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/design/application-abi.md#current-unstable-abi
|
||||
ExportedMemory(name string) Memory
|
||||
|
||||
// ExportedMemoryDefinitions returns all the exported memory definitions
|
||||
// in this module, keyed on export name.
|
||||
//
|
||||
// Note: As of WebAssembly Core Specification 2.0, there can be at most one
|
||||
// memory.
|
||||
ExportedMemoryDefinitions() map[string]MemoryDefinition
|
||||
|
||||
// ExportedGlobal a global exported from this module or nil if it wasn't.
|
||||
ExportedGlobal(name string) Global
|
||||
|
||||
|
||||
@@ -362,6 +362,7 @@ func addSpectestModule(t *testing.T, ctx context.Context, s *wasm.Store, ns *was
|
||||
mod.ExportSection = append(mod.ExportSection, &wasm.Export{Name: "table", Index: 0, Type: wasm.ExternTypeTable})
|
||||
|
||||
maybeSetMemoryCap(mod)
|
||||
mod.BuildMemoryDefinitions()
|
||||
mod.BuildFunctionDefinitions()
|
||||
|
||||
err = mod.Validate(enabledFeatures)
|
||||
@@ -432,6 +433,7 @@ func Run(t *testing.T, testDataFS embed.FS, ctx context.Context, newEngine func(
|
||||
}
|
||||
|
||||
maybeSetMemoryCap(mod)
|
||||
mod.BuildMemoryDefinitions()
|
||||
mod.BuildFunctionDefinitions()
|
||||
err = s.Engine.CompileModule(ctx, mod, nil)
|
||||
require.NoError(t, err, msg)
|
||||
@@ -603,6 +605,7 @@ func requireInstantiationError(t *testing.T, ctx context.Context, s *wasm.Store,
|
||||
mod.AssignModuleID(buf)
|
||||
|
||||
maybeSetMemoryCap(mod)
|
||||
mod.BuildMemoryDefinitions()
|
||||
mod.BuildFunctionDefinitions()
|
||||
err = s.Engine.CompileModule(ctx, mod, nil)
|
||||
if err != nil {
|
||||
|
||||
@@ -135,6 +135,21 @@ func (m *CallContext) ExportedMemory(name string) api.Memory {
|
||||
return m.memory
|
||||
}
|
||||
|
||||
// ExportedMemoryDefinitions implements the same method as documented on
|
||||
// api.Module.
|
||||
func (m *CallContext) ExportedMemoryDefinitions() map[string]api.MemoryDefinition {
|
||||
// Special case as we currently only support one memory.
|
||||
if mem := m.module.Memory; mem != nil {
|
||||
// Now, find out if it is exported
|
||||
for name, exp := range m.module.Exports {
|
||||
if exp.Type == ExternTypeMemory {
|
||||
return map[string]api.MemoryDefinition{name: mem.definition}
|
||||
}
|
||||
}
|
||||
}
|
||||
return map[string]api.MemoryDefinition{}
|
||||
}
|
||||
|
||||
// ExportedFunction implements the same method as documented on api.Module.
|
||||
func (m *CallContext) ExportedFunction(name string) api.Function {
|
||||
exp, err := m.module.getExport(name, ExternTypeFunc)
|
||||
@@ -145,6 +160,18 @@ func (m *CallContext) ExportedFunction(name string) api.Function {
|
||||
return m.function(&m.module.Functions[exp.Index])
|
||||
}
|
||||
|
||||
// ExportedFunctionDefinitions implements the same method as documented on
|
||||
// api.Module.
|
||||
func (m *CallContext) ExportedFunctionDefinitions() map[string]api.FunctionDefinition {
|
||||
result := map[string]api.FunctionDefinition{}
|
||||
for name, exp := range m.module.Exports {
|
||||
if exp.Type == ExternTypeFunc {
|
||||
result[name] = m.module.Functions[exp.Index].Definition
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Module is exposed for emscripten.
|
||||
func (m *CallContext) Module() *ModuleInstance {
|
||||
return m.module
|
||||
|
||||
@@ -657,6 +657,7 @@ func (m *Module) buildMemory() (mem *MemoryInstance) {
|
||||
memSec := m.MemorySection
|
||||
if memSec != nil {
|
||||
mem = NewMemoryInstance(memSec)
|
||||
mem.definition = m.MemoryDefinitionSection[0]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -842,10 +842,15 @@ func TestModule_buildMemoryInstance(t *testing.T) {
|
||||
t.Run("non-nil", func(t *testing.T) {
|
||||
min := uint32(1)
|
||||
max := uint32(10)
|
||||
m := Module{MemorySection: &Memory{Min: min, Cap: min, Max: max}}
|
||||
mDef := &MemoryDefinition{moduleName: "foo"}
|
||||
m := Module{
|
||||
MemorySection: &Memory{Min: min, Cap: min, Max: max},
|
||||
MemoryDefinitionSection: []*MemoryDefinition{mDef},
|
||||
}
|
||||
mem := m.buildMemory()
|
||||
require.Equal(t, min, mem.Min)
|
||||
require.Equal(t, max, mem.Max)
|
||||
require.Equal(t, mDef, mem.definition)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -28,18 +28,18 @@ func TestModuleInstance_Memory(t *testing.T) {
|
||||
name: "no memory",
|
||||
input: &Module{},
|
||||
},
|
||||
{
|
||||
name: "memory not exported",
|
||||
input: &Module{MemorySection: &Memory{Min: 1, Cap: 1}},
|
||||
},
|
||||
{
|
||||
name: "memory not exported, one page",
|
||||
input: &Module{MemorySection: &Memory{Min: 1, Cap: 1}},
|
||||
input: &Module{
|
||||
MemorySection: &Memory{Min: 1, Cap: 1},
|
||||
MemoryDefinitionSection: []*MemoryDefinition{{}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "memory exported, different name",
|
||||
input: &Module{
|
||||
MemorySection: &Memory{Min: 1, Cap: 1},
|
||||
MemoryDefinitionSection: []*MemoryDefinition{{}},
|
||||
ExportSection: []*Export{{Type: ExternTypeMemory, Name: "momory", Index: 0}},
|
||||
},
|
||||
},
|
||||
@@ -47,6 +47,7 @@ func TestModuleInstance_Memory(t *testing.T) {
|
||||
name: "memory exported, but zero length",
|
||||
input: &Module{
|
||||
MemorySection: &Memory{},
|
||||
MemoryDefinitionSection: []*MemoryDefinition{{}},
|
||||
ExportSection: []*Export{{Type: ExternTypeMemory, Name: "memory", Index: 0}},
|
||||
},
|
||||
expected: true,
|
||||
@@ -55,6 +56,7 @@ func TestModuleInstance_Memory(t *testing.T) {
|
||||
name: "memory exported, one page",
|
||||
input: &Module{
|
||||
MemorySection: &Memory{Min: 1, Cap: 1},
|
||||
MemoryDefinitionSection: []*MemoryDefinition{{}},
|
||||
ExportSection: []*Export{{Type: ExternTypeMemory, Name: "memory", Index: 0}},
|
||||
},
|
||||
expected: true,
|
||||
@@ -64,6 +66,7 @@ func TestModuleInstance_Memory(t *testing.T) {
|
||||
name: "memory exported, two pages",
|
||||
input: &Module{
|
||||
MemorySection: &Memory{Min: 2, Cap: 2},
|
||||
MemoryDefinitionSection: []*MemoryDefinition{{}},
|
||||
ExportSection: []*Export{{Type: ExternTypeMemory, Name: "memory", Index: 0}},
|
||||
},
|
||||
expected: true,
|
||||
@@ -154,6 +157,7 @@ func TestStore_CloseWithExitCode(t *testing.T) {
|
||||
TypeSection: []*FunctionType{v_v},
|
||||
ImportSection: []*Import{{Type: ExternTypeFunc, Module: importedModuleName, Name: "fn", DescFunc: 0}},
|
||||
MemorySection: &Memory{Min: 1, Cap: 1},
|
||||
MemoryDefinitionSection: []*MemoryDefinition{{}},
|
||||
GlobalSection: []*Global{{Type: &GlobalType{}, Init: &ConstantExpression{Opcode: OpcodeI32Const, Data: const1}}},
|
||||
TableSection: []*Table{{Min: 10}},
|
||||
}, importingModuleName, nil)
|
||||
@@ -195,6 +199,7 @@ func TestStore_hammer(t *testing.T) {
|
||||
FunctionSection: []uint32{0},
|
||||
CodeSection: []*Code{{Body: []byte{OpcodeEnd}}},
|
||||
MemorySection: &Memory{Min: 1, Cap: 1},
|
||||
MemoryDefinitionSection: []*MemoryDefinition{{}},
|
||||
GlobalSection: []*Global{{
|
||||
Type: &GlobalType{ValType: ValueTypeI32},
|
||||
Init: &ConstantExpression{Opcode: OpcodeI32Const, Data: leb128.EncodeInt32(1)},
|
||||
|
||||
@@ -225,8 +225,13 @@ func TestModule_Memory(t *testing.T) {
|
||||
mem := module.ExportedMemory("memory")
|
||||
if tc.expected {
|
||||
require.Equal(t, tc.expectedLen, mem.Size())
|
||||
defs := module.ExportedMemoryDefinitions()
|
||||
require.Equal(t, 1, len(defs))
|
||||
def := defs["memory"]
|
||||
require.Equal(t, tc.expectedLen>>16, def.Min())
|
||||
} else {
|
||||
require.Nil(t, mem)
|
||||
require.Zero(t, len(module.ExportedMemoryDefinitions()))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -525,7 +530,11 @@ func TestRuntime_CloseWithExitCode(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
func1 := m1.ExportedFunction("func")
|
||||
require.Equal(t, map[string]api.FunctionDefinition{"func": func1.Definition()},
|
||||
m1.ExportedFunctionDefinitions())
|
||||
func2 := m2.ExportedFunction("func")
|
||||
require.Equal(t, map[string]api.FunctionDefinition{"func": func2.Definition()},
|
||||
m2.ExportedFunctionDefinitions())
|
||||
|
||||
// Modules not closed so calls succeed
|
||||
|
||||
|
||||
Reference in New Issue
Block a user