github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/internal/wasm/function_definition_test.go (about) 1 package wasm 2 3 import ( 4 "testing" 5 6 "github.com/wasilibs/wazerox/api" 7 "github.com/wasilibs/wazerox/internal/testing/hammer" 8 "github.com/wasilibs/wazerox/internal/testing/require" 9 ) 10 11 func TestModule_BuildFunctionDefinitions(t *testing.T) { 12 imp := &Import{ 13 Type: ExternTypeFunc, 14 DescFunc: 2, // Index of type. 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 // Execute the same tests with n=`concurrentCount` goroutines invoking `buildFunctionDefinitions()` at once. 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 }