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 returns a function exported from this module or nil if it wasn't.
|
||||||
ExportedFunction(name string) Function
|
ExportedFunction(name string) Function
|
||||||
|
|
||||||
|
// ExportedFunctionDefinitions returns all the exported function
|
||||||
|
// definitions in this module, keyed on export name.
|
||||||
|
ExportedFunctionDefinitions() map[string]FunctionDefinition
|
||||||
|
|
||||||
// TODO: Table
|
// TODO: Table
|
||||||
|
|
||||||
// ExportedMemory returns a memory exported from this module or nil if it wasn't.
|
// 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
|
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/design/application-abi.md#current-unstable-abi
|
||||||
ExportedMemory(name string) Memory
|
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 a global exported from this module or nil if it wasn't.
|
||||||
ExportedGlobal(name string) Global
|
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})
|
mod.ExportSection = append(mod.ExportSection, &wasm.Export{Name: "table", Index: 0, Type: wasm.ExternTypeTable})
|
||||||
|
|
||||||
maybeSetMemoryCap(mod)
|
maybeSetMemoryCap(mod)
|
||||||
|
mod.BuildMemoryDefinitions()
|
||||||
mod.BuildFunctionDefinitions()
|
mod.BuildFunctionDefinitions()
|
||||||
|
|
||||||
err = mod.Validate(enabledFeatures)
|
err = mod.Validate(enabledFeatures)
|
||||||
@@ -432,6 +433,7 @@ func Run(t *testing.T, testDataFS embed.FS, ctx context.Context, newEngine func(
|
|||||||
}
|
}
|
||||||
|
|
||||||
maybeSetMemoryCap(mod)
|
maybeSetMemoryCap(mod)
|
||||||
|
mod.BuildMemoryDefinitions()
|
||||||
mod.BuildFunctionDefinitions()
|
mod.BuildFunctionDefinitions()
|
||||||
err = s.Engine.CompileModule(ctx, mod, nil)
|
err = s.Engine.CompileModule(ctx, mod, nil)
|
||||||
require.NoError(t, err, msg)
|
require.NoError(t, err, msg)
|
||||||
@@ -603,6 +605,7 @@ func requireInstantiationError(t *testing.T, ctx context.Context, s *wasm.Store,
|
|||||||
mod.AssignModuleID(buf)
|
mod.AssignModuleID(buf)
|
||||||
|
|
||||||
maybeSetMemoryCap(mod)
|
maybeSetMemoryCap(mod)
|
||||||
|
mod.BuildMemoryDefinitions()
|
||||||
mod.BuildFunctionDefinitions()
|
mod.BuildFunctionDefinitions()
|
||||||
err = s.Engine.CompileModule(ctx, mod, nil)
|
err = s.Engine.CompileModule(ctx, mod, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -135,6 +135,21 @@ func (m *CallContext) ExportedMemory(name string) api.Memory {
|
|||||||
return m.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.
|
// ExportedFunction implements the same method as documented on api.Module.
|
||||||
func (m *CallContext) ExportedFunction(name string) api.Function {
|
func (m *CallContext) ExportedFunction(name string) api.Function {
|
||||||
exp, err := m.module.getExport(name, ExternTypeFunc)
|
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])
|
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.
|
// Module is exposed for emscripten.
|
||||||
func (m *CallContext) Module() *ModuleInstance {
|
func (m *CallContext) Module() *ModuleInstance {
|
||||||
return m.module
|
return m.module
|
||||||
|
|||||||
@@ -657,6 +657,7 @@ func (m *Module) buildMemory() (mem *MemoryInstance) {
|
|||||||
memSec := m.MemorySection
|
memSec := m.MemorySection
|
||||||
if memSec != nil {
|
if memSec != nil {
|
||||||
mem = NewMemoryInstance(memSec)
|
mem = NewMemoryInstance(memSec)
|
||||||
|
mem.definition = m.MemoryDefinitionSection[0]
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -842,10 +842,15 @@ func TestModule_buildMemoryInstance(t *testing.T) {
|
|||||||
t.Run("non-nil", func(t *testing.T) {
|
t.Run("non-nil", func(t *testing.T) {
|
||||||
min := uint32(1)
|
min := uint32(1)
|
||||||
max := uint32(10)
|
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()
|
mem := m.buildMemory()
|
||||||
require.Equal(t, min, mem.Min)
|
require.Equal(t, min, mem.Min)
|
||||||
require.Equal(t, max, mem.Max)
|
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",
|
name: "no memory",
|
||||||
input: &Module{},
|
input: &Module{},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "memory not exported",
|
|
||||||
input: &Module{MemorySection: &Memory{Min: 1, Cap: 1}},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "memory not exported, one page",
|
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",
|
name: "memory exported, different name",
|
||||||
input: &Module{
|
input: &Module{
|
||||||
MemorySection: &Memory{Min: 1, Cap: 1},
|
MemorySection: &Memory{Min: 1, Cap: 1},
|
||||||
|
MemoryDefinitionSection: []*MemoryDefinition{{}},
|
||||||
ExportSection: []*Export{{Type: ExternTypeMemory, Name: "momory", Index: 0}},
|
ExportSection: []*Export{{Type: ExternTypeMemory, Name: "momory", Index: 0}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -47,6 +47,7 @@ func TestModuleInstance_Memory(t *testing.T) {
|
|||||||
name: "memory exported, but zero length",
|
name: "memory exported, but zero length",
|
||||||
input: &Module{
|
input: &Module{
|
||||||
MemorySection: &Memory{},
|
MemorySection: &Memory{},
|
||||||
|
MemoryDefinitionSection: []*MemoryDefinition{{}},
|
||||||
ExportSection: []*Export{{Type: ExternTypeMemory, Name: "memory", Index: 0}},
|
ExportSection: []*Export{{Type: ExternTypeMemory, Name: "memory", Index: 0}},
|
||||||
},
|
},
|
||||||
expected: true,
|
expected: true,
|
||||||
@@ -55,6 +56,7 @@ func TestModuleInstance_Memory(t *testing.T) {
|
|||||||
name: "memory exported, one page",
|
name: "memory exported, one page",
|
||||||
input: &Module{
|
input: &Module{
|
||||||
MemorySection: &Memory{Min: 1, Cap: 1},
|
MemorySection: &Memory{Min: 1, Cap: 1},
|
||||||
|
MemoryDefinitionSection: []*MemoryDefinition{{}},
|
||||||
ExportSection: []*Export{{Type: ExternTypeMemory, Name: "memory", Index: 0}},
|
ExportSection: []*Export{{Type: ExternTypeMemory, Name: "memory", Index: 0}},
|
||||||
},
|
},
|
||||||
expected: true,
|
expected: true,
|
||||||
@@ -64,6 +66,7 @@ func TestModuleInstance_Memory(t *testing.T) {
|
|||||||
name: "memory exported, two pages",
|
name: "memory exported, two pages",
|
||||||
input: &Module{
|
input: &Module{
|
||||||
MemorySection: &Memory{Min: 2, Cap: 2},
|
MemorySection: &Memory{Min: 2, Cap: 2},
|
||||||
|
MemoryDefinitionSection: []*MemoryDefinition{{}},
|
||||||
ExportSection: []*Export{{Type: ExternTypeMemory, Name: "memory", Index: 0}},
|
ExportSection: []*Export{{Type: ExternTypeMemory, Name: "memory", Index: 0}},
|
||||||
},
|
},
|
||||||
expected: true,
|
expected: true,
|
||||||
@@ -154,6 +157,7 @@ func TestStore_CloseWithExitCode(t *testing.T) {
|
|||||||
TypeSection: []*FunctionType{v_v},
|
TypeSection: []*FunctionType{v_v},
|
||||||
ImportSection: []*Import{{Type: ExternTypeFunc, Module: importedModuleName, Name: "fn", DescFunc: 0}},
|
ImportSection: []*Import{{Type: ExternTypeFunc, Module: importedModuleName, Name: "fn", DescFunc: 0}},
|
||||||
MemorySection: &Memory{Min: 1, Cap: 1},
|
MemorySection: &Memory{Min: 1, Cap: 1},
|
||||||
|
MemoryDefinitionSection: []*MemoryDefinition{{}},
|
||||||
GlobalSection: []*Global{{Type: &GlobalType{}, Init: &ConstantExpression{Opcode: OpcodeI32Const, Data: const1}}},
|
GlobalSection: []*Global{{Type: &GlobalType{}, Init: &ConstantExpression{Opcode: OpcodeI32Const, Data: const1}}},
|
||||||
TableSection: []*Table{{Min: 10}},
|
TableSection: []*Table{{Min: 10}},
|
||||||
}, importingModuleName, nil)
|
}, importingModuleName, nil)
|
||||||
@@ -195,6 +199,7 @@ func TestStore_hammer(t *testing.T) {
|
|||||||
FunctionSection: []uint32{0},
|
FunctionSection: []uint32{0},
|
||||||
CodeSection: []*Code{{Body: []byte{OpcodeEnd}}},
|
CodeSection: []*Code{{Body: []byte{OpcodeEnd}}},
|
||||||
MemorySection: &Memory{Min: 1, Cap: 1},
|
MemorySection: &Memory{Min: 1, Cap: 1},
|
||||||
|
MemoryDefinitionSection: []*MemoryDefinition{{}},
|
||||||
GlobalSection: []*Global{{
|
GlobalSection: []*Global{{
|
||||||
Type: &GlobalType{ValType: ValueTypeI32},
|
Type: &GlobalType{ValType: ValueTypeI32},
|
||||||
Init: &ConstantExpression{Opcode: OpcodeI32Const, Data: leb128.EncodeInt32(1)},
|
Init: &ConstantExpression{Opcode: OpcodeI32Const, Data: leb128.EncodeInt32(1)},
|
||||||
|
|||||||
@@ -225,8 +225,13 @@ func TestModule_Memory(t *testing.T) {
|
|||||||
mem := module.ExportedMemory("memory")
|
mem := module.ExportedMemory("memory")
|
||||||
if tc.expected {
|
if tc.expected {
|
||||||
require.Equal(t, tc.expectedLen, mem.Size())
|
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 {
|
} else {
|
||||||
require.Nil(t, mem)
|
require.Nil(t, mem)
|
||||||
|
require.Zero(t, len(module.ExportedMemoryDefinitions()))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -525,7 +530,11 @@ func TestRuntime_CloseWithExitCode(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
func1 := m1.ExportedFunction("func")
|
func1 := m1.ExportedFunction("func")
|
||||||
|
require.Equal(t, map[string]api.FunctionDefinition{"func": func1.Definition()},
|
||||||
|
m1.ExportedFunctionDefinitions())
|
||||||
func2 := m2.ExportedFunction("func")
|
func2 := m2.ExportedFunction("func")
|
||||||
|
require.Equal(t, map[string]api.FunctionDefinition{"func": func2.Definition()},
|
||||||
|
m2.ExportedFunctionDefinitions())
|
||||||
|
|
||||||
// Modules not closed so calls succeed
|
// Modules not closed so calls succeed
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user