Files
wazero/internal/wasm/memory_definition.go
Crypt Keeper 9a623c4f88 Adds MemoryDefinition to CompiledModule and Memory (#817)
It is more often the case that projects are enabling a freestanding
target, and that may or may not have an exporting memory depending on
how that's interpreted. This adds the ability to inspect memories
similar to how you can already inspect compiled code prior to
instantiation. For example, you can enforce an ABI constraint that
"memory" must be exported even if WASI is not in use.

Signed-off-by: Adrian Cole <adrian@tetrate.io>
2022-09-29 13:37:52 +08:00

120 lines
3.1 KiB
Go

package wasm
import "github.com/tetratelabs/wazero/api"
// ImportedMemories implements the same method as documented on wazero.CompiledModule.
func (m *Module) ImportedMemories() (ret []api.MemoryDefinition) {
for _, d := range m.MemoryDefinitionSection {
if d.importDesc != nil {
ret = append(ret, d)
}
}
return
}
// ExportedMemories implements the same method as documented on wazero.CompiledModule.
func (m *Module) ExportedMemories() map[string]api.MemoryDefinition {
ret := map[string]api.MemoryDefinition{}
for _, d := range m.MemoryDefinitionSection {
for _, e := range d.exportNames {
ret[e] = d
}
}
return ret
}
// BuildMemoryDefinitions generates memory metadata that can be parsed from
// the module. This must be called after all validation.
//
// Note: This is exported for wazero.Runtime `CompileModule`.
func (m *Module) BuildMemoryDefinitions() {
var moduleName string
if m.NameSection != nil {
moduleName = m.NameSection.ModuleName
}
memoryCount := m.ImportMemoryCount()
if m.MemorySection != nil {
memoryCount++
}
if memoryCount == 0 {
return
}
m.MemoryDefinitionSection = make([]*MemoryDefinition, 0, memoryCount)
importMemIdx := Index(0)
for _, i := range m.ImportSection {
if i.Type != ExternTypeMemory {
continue
}
m.MemoryDefinitionSection = append(m.MemoryDefinitionSection, &MemoryDefinition{
importDesc: &[2]string{i.Module, i.Name},
index: importMemIdx,
memory: i.DescMem,
})
importMemIdx++
}
if m.MemorySection != nil {
m.MemoryDefinitionSection = append(m.MemoryDefinitionSection, &MemoryDefinition{
index: importMemIdx,
memory: m.MemorySection,
})
}
for _, d := range m.MemoryDefinitionSection {
d.moduleName = moduleName
for _, e := range m.ExportSection {
if e.Type == ExternTypeMemory && e.Index == d.index {
d.exportNames = append(d.exportNames, e.Name)
}
}
}
}
// MemoryDefinition implements api.MemoryDefinition
type MemoryDefinition struct {
moduleName string
index Index
importDesc *[2]string
exportNames []string
memory *Memory
}
// ModuleName implements the same method as documented on api.MemoryDefinition.
func (f *MemoryDefinition) ModuleName() string {
return f.moduleName
}
// Index implements the same method as documented on api.MemoryDefinition.
func (f *MemoryDefinition) Index() uint32 {
return f.index
}
// Import implements the same method as documented on api.MemoryDefinition.
func (f *MemoryDefinition) Import() (moduleName, name string, isImport bool) {
if importDesc := f.importDesc; importDesc != nil {
moduleName, name, isImport = importDesc[0], importDesc[1], true
}
return
}
// ExportNames implements the same method as documented on api.MemoryDefinition.
func (f *MemoryDefinition) ExportNames() []string {
return f.exportNames
}
// Min implements the same method as documented on api.MemoryDefinition.
func (f *MemoryDefinition) Min() uint32 {
return f.memory.Min
}
// Max implements the same method as documented on api.MemoryDefinition.
func (f *MemoryDefinition) Max() (max uint32, encoded bool) {
max = f.memory.Max
encoded = f.memory.IsMaxEncoded
return
}