1 package wasm
2
3 import (
4 "testing"
5
6 "github.com/tetratelabs/wazero/api"
7 "github.com/tetratelabs/wazero/internal/testing/hammer"
8 "github.com/tetratelabs/wazero/internal/testing/require"
9 )
10
11 func TestModule_BuildFunctionDefinitions(t *testing.T) {
12 imp := &Import{
13 Type: ExternTypeFunc,
14 DescFunc: 2,
15 }
16
17 nopCode := Code{Body: []byte{OpcodeEnd}}
18 fn := func(uint32) uint32 { return 1 }
19 tests := []struct {
20 name string
21 m *Module
22 expected []FunctionDefinition
23 expectedImports []api.FunctionDefinition
24 expectedExports map[string]api.FunctionDefinition
25 }{
26 {
27 name: "no exports",
28 m: &Module{},
29 expected: []FunctionDefinition{},
30 expectedExports: map[string]api.FunctionDefinition{},
31 },
32 {
33 name: "no functions",
34 expected: []FunctionDefinition{},
35 m: &Module{
36 ExportSection: []Export{{Type: ExternTypeGlobal, Index: 0}},
37 GlobalSection: []Global{{}},
38 },
39 expectedExports: map[string]api.FunctionDefinition{},
40 },
41 {
42 name: "only imported functions",
43 expected: []FunctionDefinition{
44 {name: "fn", Debugname: ".fn", importDesc: &Import{Module: "foo", Name: "bar", Type: ExternTypeFunc}, Functype: &FunctionType{}},
45 },
46 m: &Module{
47 ExportSection: []Export{{Type: ExternTypeGlobal, Index: 0}},
48 GlobalSection: []Global{{}},
49 TypeSection: []FunctionType{{}},
50 ImportFunctionCount: 1,
51 ImportSection: []Import{{Type: ExternTypeFunc, Name: "bar", Module: "foo"}},
52 NameSection: &NameSection{FunctionNames: NameMap{{Index: Index(0), Name: "fn"}}},
53 },
54 expectedImports: []api.FunctionDefinition{
55 &FunctionDefinition{
56 name: "fn", Debugname: ".fn", importDesc: &Import{Module: "foo", Name: "bar", Type: ExternTypeFunc},
57 Functype: &FunctionType{},
58 },
59 },
60 expectedExports: map[string]api.FunctionDefinition{},
61 },
62 {
63 name: "host func go",
64 m: &Module{
65 TypeSection: []FunctionType{i32_i32},
66 FunctionSection: []Index{0},
67 CodeSection: []Code{MustParseGoReflectFuncCode(fn)},
68 NameSection: &NameSection{
69 ModuleName: "m",
70 FunctionNames: NameMap{{Index: Index(0), Name: "fn"}},
71 LocalNames: IndirectNameMap{{Index: Index(0), NameMap: NameMap{{Index: Index(0), Name: "x"}}}},
72 ResultNames: IndirectNameMap{{Index: Index(0), NameMap: NameMap{{Index: Index(0), Name: "y"}}}},
73 },
74 },
75 expected: []FunctionDefinition{
76 {
77 index: 0,
78 name: "fn",
79 moduleName: "m",
80 Debugname: "m.fn",
81 goFunc: MustParseGoReflectFuncCode(fn).GoFunc,
82 Functype: &i32_i32,
83 paramNames: []string{"x"},
84 resultNames: []string{"y"},
85 },
86 },
87 expectedExports: map[string]api.FunctionDefinition{},
88 },
89 {
90 name: "without imports",
91 m: &Module{
92 ExportSection: []Export{
93 {Name: "function_index=0", Type: ExternTypeFunc, Index: 0},
94 {Name: "function_index=2", Type: ExternTypeFunc, Index: 2},
95 {Name: "", Type: ExternTypeGlobal, Index: 0},
96 {Name: "function_index=1", Type: ExternTypeFunc, Index: 1},
97 },
98 GlobalSection: []Global{{}},
99 FunctionSection: []Index{1, 2, 0},
100 CodeSection: []Code{
101 {Body: []byte{OpcodeEnd}},
102 {Body: []byte{OpcodeEnd}},
103 {Body: []byte{OpcodeEnd}},
104 },
105 TypeSection: []FunctionType{
106 v_v,
107 f64i32_v128i64,
108 f64f32_i64,
109 },
110 },
111 expected: []FunctionDefinition{
112 {
113 index: 0,
114 Debugname: ".$0",
115 exportNames: []string{"function_index=0"},
116 Functype: &f64i32_v128i64,
117 },
118 {
119 index: 1,
120 Debugname: ".$1",
121 exportNames: []string{"function_index=1"},
122 Functype: &f64f32_i64,
123 },
124 {
125 index: 2,
126 Debugname: ".$2",
127 exportNames: []string{"function_index=2"},
128 Functype: &v_v,
129 },
130 },
131 expectedExports: map[string]api.FunctionDefinition{
132 "function_index=0": &FunctionDefinition{
133 index: 0,
134 Debugname: ".$0",
135 exportNames: []string{"function_index=0"},
136 Functype: &f64i32_v128i64,
137 },
138 "function_index=1": &FunctionDefinition{
139 index: 1,
140 exportNames: []string{"function_index=1"},
141 Debugname: ".$1",
142 Functype: &f64f32_i64,
143 },
144 "function_index=2": &FunctionDefinition{
145 index: 2,
146 Debugname: ".$2",
147 exportNames: []string{"function_index=2"},
148 Functype: &v_v,
149 },
150 },
151 },
152 {
153 name: "with imports",
154 m: &Module{
155 ImportFunctionCount: 1,
156 ImportSection: []Import{*imp},
157 ExportSection: []Export{
158 {Name: "imported_function", Type: ExternTypeFunc, Index: 0},
159 {Name: "function_index=1", Type: ExternTypeFunc, Index: 1},
160 {Name: "function_index=2", Type: ExternTypeFunc, Index: 2},
161 },
162 FunctionSection: []Index{1, 0},
163 CodeSection: []Code{{Body: []byte{OpcodeEnd}}, {Body: []byte{OpcodeEnd}}},
164 TypeSection: []FunctionType{
165 v_v,
166 f64i32_v128i64,
167 f64f32_i64,
168 },
169 },
170 expected: []FunctionDefinition{
171 {
172 index: 0,
173 Debugname: ".$0",
174 importDesc: imp,
175 exportNames: []string{"imported_function"},
176 Functype: &f64f32_i64,
177 },
178 {
179 index: 1,
180 Debugname: ".$1",
181 exportNames: []string{"function_index=1"},
182 Functype: &f64i32_v128i64,
183 },
184 {
185 index: 2,
186 Debugname: ".$2",
187 exportNames: []string{"function_index=2"},
188 Functype: &v_v,
189 },
190 },
191 expectedImports: []api.FunctionDefinition{
192 &FunctionDefinition{
193 index: 0,
194 Debugname: ".$0",
195 importDesc: imp,
196 exportNames: []string{"imported_function"},
197 Functype: &f64f32_i64,
198 },
199 },
200 expectedExports: map[string]api.FunctionDefinition{
201 "imported_function": &FunctionDefinition{
202 index: 0,
203 Debugname: ".$0",
204 importDesc: imp,
205 exportNames: []string{"imported_function"},
206 Functype: &f64f32_i64,
207 },
208 "function_index=1": &FunctionDefinition{
209 index: 1,
210 Debugname: ".$1",
211 exportNames: []string{"function_index=1"},
212 Functype: &f64i32_v128i64,
213 },
214 "function_index=2": &FunctionDefinition{
215 index: 2,
216 Debugname: ".$2",
217 exportNames: []string{"function_index=2"},
218 Functype: &v_v,
219 },
220 },
221 },
222 {
223 name: "with names",
224 m: &Module{
225 ImportFunctionCount: 1,
226 TypeSection: []FunctionType{v_v},
227 ImportSection: []Import{{Module: "i", Name: "f", Type: ExternTypeFunc}},
228 NameSection: &NameSection{
229 ModuleName: "module",
230 FunctionNames: NameMap{
231 {Index: Index(2), Name: "two"},
232 {Index: Index(4), Name: "four"},
233 {Index: Index(5), Name: "five"},
234 },
235 },
236 FunctionSection: []Index{0, 0, 0, 0, 0},
237 CodeSection: []Code{nopCode, nopCode, nopCode, nopCode, nopCode},
238 },
239 expected: []FunctionDefinition{
240 {moduleName: "module", index: 0, Debugname: "module.$0", importDesc: &Import{Module: "i", Name: "f"}, Functype: &v_v},
241 {moduleName: "module", index: 1, Debugname: "module.$1", Functype: &v_v},
242 {moduleName: "module", index: 2, Debugname: "module.two", Functype: &v_v, name: "two"},
243 {moduleName: "module", index: 3, Debugname: "module.$3", Functype: &v_v},
244 {moduleName: "module", index: 4, Debugname: "module.four", Functype: &v_v, name: "four"},
245 {moduleName: "module", index: 5, Debugname: "module.five", Functype: &v_v, name: "five"},
246 },
247 expectedImports: []api.FunctionDefinition{
248 &FunctionDefinition{moduleName: "module", index: 0, Debugname: "module.$0", importDesc: &Import{Module: "i", Name: "f"}, Functype: &v_v},
249 },
250 expectedExports: map[string]api.FunctionDefinition{},
251 },
252 }
253
254 for _, tc := range tests {
255 tc := tc
256 t.Run(tc.name, func(t *testing.T) {
257 tc.m.buildFunctionDefinitions()
258 require.Equal(t, tc.expected, tc.m.FunctionDefinitionSection)
259 require.Equal(t, tc.expectedImports, tc.m.ImportedFunctions())
260 require.Equal(t, tc.expectedExports, tc.m.ExportedFunctions())
261 })
262 }
263
264
265 const nGoroutines = 100
266 const nIterations = 10
267 for _, tc := range tests {
268 tc := tc
269 testName := tc.name + " (concurrent)"
270 t.Run(testName, func(t *testing.T) {
271 hammer.NewHammer(t, nGoroutines, nIterations).
272 Run(func(name string) {
273 tc.m.buildFunctionDefinitions()
274 }, nil)
275
276 require.Equal(t, tc.expected, tc.m.FunctionDefinitionSection)
277 require.Equal(t, tc.expectedImports, tc.m.ImportedFunctions())
278 require.Equal(t, tc.expectedExports, tc.m.ExportedFunctions())
279 })
280 }
281 }
282
View as plain text