function_definition.go

  1package wasm
  2
  3import (
  4	"github.com/tetratelabs/wazero/api"
  5	"github.com/tetratelabs/wazero/internal/internalapi"
  6	"github.com/tetratelabs/wazero/internal/wasmdebug"
  7)
  8
  9// ImportedFunctions returns the definitions of each imported function.
 10//
 11// Note: Unlike ExportedFunctions, there is no unique constraint on imports.
 12func (m *Module) ImportedFunctions() (ret []api.FunctionDefinition) {
 13	for i := uint32(0); i < m.ImportFunctionCount; i++ {
 14		ret = append(ret, m.FunctionDefinition(i))
 15	}
 16	return
 17}
 18
 19// ExportedFunctions returns the definitions of each exported function.
 20func (m *Module) ExportedFunctions() map[string]api.FunctionDefinition {
 21	ret := map[string]api.FunctionDefinition{}
 22	for i := range m.ExportSection {
 23		exp := &m.ExportSection[i]
 24		if exp.Type == ExternTypeFunc {
 25			d := m.FunctionDefinition(exp.Index)
 26			ret[exp.Name] = d
 27		}
 28	}
 29	return ret
 30}
 31
 32// FunctionDefinition returns the FunctionDefinition for the given `index`.
 33func (m *Module) FunctionDefinition(index Index) *FunctionDefinition {
 34	// TODO: function initialization is lazy, but bulk. Make it per function.
 35	m.buildFunctionDefinitions()
 36	return &m.FunctionDefinitionSection[index]
 37}
 38
 39// buildFunctionDefinitions generates function metadata that can be parsed from
 40// the module. This must be called after all validation.
 41func (m *Module) buildFunctionDefinitions() {
 42	m.functionDefinitionSectionInitOnce.Do(m.buildFunctionDefinitionsOnce)
 43}
 44
 45func (m *Module) buildFunctionDefinitionsOnce() {
 46	var moduleName string
 47	var functionNames NameMap
 48	var localNames, resultNames IndirectNameMap
 49	if m.NameSection != nil {
 50		moduleName = m.NameSection.ModuleName
 51		functionNames = m.NameSection.FunctionNames
 52		localNames = m.NameSection.LocalNames
 53		resultNames = m.NameSection.ResultNames
 54	}
 55
 56	importCount := m.ImportFunctionCount
 57	m.FunctionDefinitionSection = make([]FunctionDefinition, importCount+uint32(len(m.FunctionSection)))
 58
 59	importFuncIdx := Index(0)
 60	for i := range m.ImportSection {
 61		imp := &m.ImportSection[i]
 62		if imp.Type != ExternTypeFunc {
 63			continue
 64		}
 65
 66		def := &m.FunctionDefinitionSection[importFuncIdx]
 67		def.importDesc = imp
 68		def.index = importFuncIdx
 69		def.Functype = &m.TypeSection[imp.DescFunc]
 70		importFuncIdx++
 71	}
 72
 73	for codeIndex, typeIndex := range m.FunctionSection {
 74		code := &m.CodeSection[codeIndex]
 75		idx := importFuncIdx + Index(codeIndex)
 76		def := &m.FunctionDefinitionSection[idx]
 77		def.index = idx
 78		def.Functype = &m.TypeSection[typeIndex]
 79		def.goFunc = code.GoFunc
 80	}
 81
 82	n, nLen := 0, len(functionNames)
 83	for i := range m.FunctionDefinitionSection {
 84		d := &m.FunctionDefinitionSection[i]
 85		// The function name section begins with imports, but can be sparse.
 86		// This keeps track of how far in the name section we've searched.
 87		funcIdx := d.index
 88		var funcName string
 89		for ; n < nLen; n++ {
 90			next := &functionNames[n]
 91			if next.Index > funcIdx {
 92				break // we have function names, but starting at a later index.
 93			} else if next.Index == funcIdx {
 94				funcName = next.Name
 95				break
 96			}
 97		}
 98
 99		d.moduleName = moduleName
100		d.name = funcName
101		d.Debugname = wasmdebug.FuncName(moduleName, funcName, funcIdx)
102		d.paramNames = paramNames(localNames, funcIdx, len(d.Functype.Params))
103		d.resultNames = paramNames(resultNames, funcIdx, len(d.Functype.Results))
104
105		for i := range m.ExportSection {
106			e := &m.ExportSection[i]
107			if e.Type == ExternTypeFunc && e.Index == funcIdx {
108				d.exportNames = append(d.exportNames, e.Name)
109			}
110		}
111	}
112}
113
114// FunctionDefinition implements api.FunctionDefinition
115type FunctionDefinition struct {
116	internalapi.WazeroOnlyType
117	moduleName string
118	index      Index
119	name       string
120	// Debugname is exported for testing purpose.
121	Debugname string
122	goFunc    interface{}
123	// Functype is exported for testing purpose.
124	Functype    *FunctionType
125	importDesc  *Import
126	exportNames []string
127	paramNames  []string
128	resultNames []string
129}
130
131// ModuleName implements the same method as documented on api.FunctionDefinition.
132func (f *FunctionDefinition) ModuleName() string {
133	return f.moduleName
134}
135
136// Index implements the same method as documented on api.FunctionDefinition.
137func (f *FunctionDefinition) Index() uint32 {
138	return f.index
139}
140
141// Name implements the same method as documented on api.FunctionDefinition.
142func (f *FunctionDefinition) Name() string {
143	return f.name
144}
145
146// DebugName implements the same method as documented on api.FunctionDefinition.
147func (f *FunctionDefinition) DebugName() string {
148	return f.Debugname
149}
150
151// Import implements the same method as documented on api.FunctionDefinition.
152func (f *FunctionDefinition) Import() (moduleName, name string, isImport bool) {
153	if f.importDesc != nil {
154		importDesc := f.importDesc
155		moduleName, name, isImport = importDesc.Module, importDesc.Name, true
156	}
157	return
158}
159
160// ExportNames implements the same method as documented on api.FunctionDefinition.
161func (f *FunctionDefinition) ExportNames() []string {
162	return f.exportNames
163}
164
165// GoFunction implements the same method as documented on api.FunctionDefinition.
166func (f *FunctionDefinition) GoFunction() interface{} {
167	return f.goFunc
168}
169
170// ParamTypes implements api.FunctionDefinition ParamTypes.
171func (f *FunctionDefinition) ParamTypes() []ValueType {
172	return f.Functype.Params
173}
174
175// ParamNames implements the same method as documented on api.FunctionDefinition.
176func (f *FunctionDefinition) ParamNames() []string {
177	return f.paramNames
178}
179
180// ResultTypes implements api.FunctionDefinition ResultTypes.
181func (f *FunctionDefinition) ResultTypes() []ValueType {
182	return f.Functype.Results
183}
184
185// ResultNames implements the same method as documented on api.FunctionDefinition.
186func (f *FunctionDefinition) ResultNames() []string {
187	return f.resultNames
188}