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}