1 package wasm
2
3 import (
4 "bytes"
5 "fmt"
6 "testing"
7
8 "github.com/tetratelabs/wazero/api"
9 "github.com/tetratelabs/wazero/internal/leb128"
10 "github.com/tetratelabs/wazero/internal/testing/require"
11 )
12
13 func TestModule_ValidateFunction_validateFunctionWithMaxStackValues(t *testing.T) {
14 const max = 100
15 const valuesNum = max + 1
16
17
18 var body []byte
19 for i := 0; i < valuesNum; i++ {
20 body = append(body, OpcodeI32Const, 1)
21 }
22
23
24 for i := 0; i < valuesNum; i++ {
25 body = append(body, OpcodeDrop)
26 }
27
28
29 body = append(body, OpcodeEnd)
30
31 m := &Module{
32 TypeSection: []FunctionType{v_v},
33 FunctionSection: []Index{0},
34 CodeSection: []Code{{Body: body}},
35 }
36
37 t.Run("not exceed", func(t *testing.T) {
38 err := m.validateFunctionWithMaxStackValues(&stacks{}, api.CoreFeaturesV1,
39 0, []Index{0}, nil, nil, nil, max+1, nil, bytes.NewReader(nil))
40 require.NoError(t, err)
41 })
42 t.Run("exceed", func(t *testing.T) {
43 err := m.validateFunctionWithMaxStackValues(&stacks{}, api.CoreFeaturesV1,
44 0, []Index{0}, nil, nil, nil, max, nil, bytes.NewReader(nil))
45 require.Error(t, err)
46 expMsg := fmt.Sprintf("function may have %d stack values, which exceeds limit %d", valuesNum, max)
47 require.Equal(t, expMsg, err.Error())
48 })
49 }
50
51 func TestModule_ValidateFunction_SignExtensionOps(t *testing.T) {
52 tests := []struct {
53 input Opcode
54 expectedErrOnDisable string
55 }{
56 {
57 input: OpcodeI32Extend8S,
58 expectedErrOnDisable: "i32.extend8_s invalid as feature \"sign-extension-ops\" is disabled",
59 },
60 {
61 input: OpcodeI32Extend16S,
62 expectedErrOnDisable: "i32.extend16_s invalid as feature \"sign-extension-ops\" is disabled",
63 },
64 {
65 input: OpcodeI64Extend8S,
66 expectedErrOnDisable: "i64.extend8_s invalid as feature \"sign-extension-ops\" is disabled",
67 },
68 {
69 input: OpcodeI64Extend16S,
70 expectedErrOnDisable: "i64.extend16_s invalid as feature \"sign-extension-ops\" is disabled",
71 },
72 {
73 input: OpcodeI64Extend32S,
74 expectedErrOnDisable: "i64.extend32_s invalid as feature \"sign-extension-ops\" is disabled",
75 },
76 }
77
78 for _, tt := range tests {
79 tc := tt
80 t.Run(InstructionName(tc.input), func(t *testing.T) {
81 t.Run("disabled", func(t *testing.T) {
82 m := &Module{
83 TypeSection: []FunctionType{v_v},
84 FunctionSection: []Index{0},
85 CodeSection: []Code{{Body: []byte{tc.input}}},
86 }
87 err := m.validateFunction(&stacks{}, api.CoreFeaturesV1,
88 0, []Index{0}, nil, nil, nil, nil,
89 bytes.NewReader(nil))
90 require.EqualError(t, err, tc.expectedErrOnDisable)
91 })
92 t.Run("enabled", func(t *testing.T) {
93 is32bit := tc.input == OpcodeI32Extend8S || tc.input == OpcodeI32Extend16S
94 var body []byte
95 if is32bit {
96 body = append(body, OpcodeI32Const)
97 } else {
98 body = append(body, OpcodeI64Const)
99 }
100 body = append(body, tc.input, 123, OpcodeDrop, OpcodeEnd)
101 m := &Module{
102 TypeSection: []FunctionType{v_v},
103 FunctionSection: []Index{0},
104 CodeSection: []Code{{Body: body}},
105 }
106 err := m.validateFunction(&stacks{}, api.CoreFeatureSignExtensionOps,
107 0, []Index{0}, nil, nil, nil,
108 nil, bytes.NewReader(nil))
109 require.NoError(t, err)
110 })
111 })
112 }
113 }
114
115 func TestModule_ValidateFunction_NonTrappingFloatToIntConversion(t *testing.T) {
116 tests := []struct {
117 input Opcode
118 expectedErrOnDisable string
119 }{
120 {
121 input: OpcodeMiscI32TruncSatF32S,
122 expectedErrOnDisable: "i32.trunc_sat_f32_s invalid as feature \"nontrapping-float-to-int-conversion\" is disabled",
123 },
124 {
125 input: OpcodeMiscI32TruncSatF32U,
126 expectedErrOnDisable: "i32.trunc_sat_f32_u invalid as feature \"nontrapping-float-to-int-conversion\" is disabled",
127 },
128 {
129 input: OpcodeMiscI32TruncSatF64S,
130 expectedErrOnDisable: "i32.trunc_sat_f64_s invalid as feature \"nontrapping-float-to-int-conversion\" is disabled",
131 },
132 {
133 input: OpcodeMiscI32TruncSatF64U,
134 expectedErrOnDisable: "i32.trunc_sat_f64_u invalid as feature \"nontrapping-float-to-int-conversion\" is disabled",
135 },
136 {
137 input: OpcodeMiscI64TruncSatF32S,
138 expectedErrOnDisable: "i64.trunc_sat_f32_s invalid as feature \"nontrapping-float-to-int-conversion\" is disabled",
139 },
140 {
141 input: OpcodeMiscI64TruncSatF32U,
142 expectedErrOnDisable: "i64.trunc_sat_f32_u invalid as feature \"nontrapping-float-to-int-conversion\" is disabled",
143 },
144 {
145 input: OpcodeMiscI64TruncSatF64S,
146 expectedErrOnDisable: "i64.trunc_sat_f64_s invalid as feature \"nontrapping-float-to-int-conversion\" is disabled",
147 },
148 {
149 input: OpcodeMiscI64TruncSatF64U,
150 expectedErrOnDisable: "i64.trunc_sat_f64_u invalid as feature \"nontrapping-float-to-int-conversion\" is disabled",
151 },
152 }
153
154 for _, tt := range tests {
155 tc := tt
156 t.Run(InstructionName(tc.input), func(t *testing.T) {
157 t.Run("disabled", func(t *testing.T) {
158 m := &Module{
159 TypeSection: []FunctionType{v_v},
160 FunctionSection: []Index{0},
161 CodeSection: []Code{{Body: []byte{OpcodeMiscPrefix, tc.input}}},
162 }
163 err := m.validateFunction(&stacks{}, api.CoreFeaturesV1,
164 0, []Index{0}, nil, nil, nil, nil, bytes.NewReader(nil))
165 require.EqualError(t, err, tc.expectedErrOnDisable)
166 })
167 t.Run("enabled", func(t *testing.T) {
168 var body []byte
169 switch tc.input {
170 case OpcodeMiscI32TruncSatF32S, OpcodeMiscI32TruncSatF32U, OpcodeMiscI64TruncSatF32S, OpcodeMiscI64TruncSatF32U:
171 body = []byte{OpcodeF32Const, 1, 2, 3, 4}
172 case OpcodeMiscI32TruncSatF64S, OpcodeMiscI32TruncSatF64U, OpcodeMiscI64TruncSatF64S, OpcodeMiscI64TruncSatF64U:
173 body = []byte{OpcodeF64Const, 1, 2, 3, 4, 5, 6, 7, 8}
174 }
175 body = append(body, OpcodeMiscPrefix, tc.input, OpcodeDrop, OpcodeEnd)
176
177 m := &Module{
178 TypeSection: []FunctionType{v_v},
179 FunctionSection: []Index{0},
180 CodeSection: []Code{{Body: body}},
181 }
182 err := m.validateFunction(&stacks{}, api.CoreFeatureNonTrappingFloatToIntConversion,
183 0, []Index{0}, nil, nil, nil, nil, bytes.NewReader(nil))
184 require.NoError(t, err)
185 })
186 })
187 }
188 }
189
190
191
192
193
194 func TestModule_ValidateFunction_MultiValue(t *testing.T) {
195 tests := []struct {
196 name string
197 module *Module
198 expectedErrOnDisable string
199 }{
200 {
201 name: "block with function type",
202 module: &Module{
203 TypeSection: []FunctionType{v_f64f64},
204 FunctionSection: []Index{0},
205 CodeSection: []Code{{Body: []byte{
206 OpcodeBlock, 0,
207 OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0x10, 0x40,
208 OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0x14, 0x40,
209 OpcodeBr, 0,
210 OpcodeF64Add,
211 OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0x18, 0x40,
212 OpcodeEnd,
213 OpcodeEnd,
214 }}},
215 },
216 expectedErrOnDisable: "read block: block with function type return invalid as feature \"multi-value\" is disabled",
217 },
218 {
219 name: "if with function type",
220 module: &Module{
221 TypeSection: []FunctionType{i32_i32},
222 FunctionSection: []Index{0},
223 CodeSection: []Code{{Body: []byte{
224 OpcodeI32Const, 1,
225 OpcodeLocalGet, 0, OpcodeIf, 0,
226 OpcodeI32Const, 2, OpcodeI32Add,
227 OpcodeElse, OpcodeI32Const, 0x7e, OpcodeI32Add,
228 OpcodeEnd,
229 OpcodeEnd,
230 }}},
231 },
232 expectedErrOnDisable: "read block: block with function type return invalid as feature \"multi-value\" is disabled",
233 },
234 {
235 name: "if with function type - br",
236 module: &Module{
237 TypeSection: []FunctionType{
238 i32_i32,
239 i32i32_i32,
240 },
241 FunctionSection: []Index{0},
242 CodeSection: []Code{{Body: []byte{
243 OpcodeI32Const, 1,
244 OpcodeI32Const, 2,
245 OpcodeLocalGet, 0, OpcodeIf, 1,
246 OpcodeI32Add, OpcodeBr, 0,
247 OpcodeElse, OpcodeI32Sub, OpcodeBr, 0,
248 OpcodeEnd,
249 OpcodeEnd,
250 }}},
251 },
252 expectedErrOnDisable: "read block: block with function type return invalid as feature \"multi-value\" is disabled",
253 },
254 }
255
256 for _, tt := range tests {
257 tc := tt
258 t.Run(tc.name, func(t *testing.T) {
259 t.Run("disabled", func(t *testing.T) {
260 err := tc.module.validateFunction(&stacks{}, api.CoreFeaturesV1,
261 0, []Index{0}, nil, nil, nil, nil, bytes.NewReader(nil))
262 require.EqualError(t, err, tc.expectedErrOnDisable)
263 })
264 t.Run("enabled", func(t *testing.T) {
265 err := tc.module.validateFunction(&stacks{}, api.CoreFeatureMultiValue,
266 0, []Index{0}, nil, nil, nil, nil, bytes.NewReader(nil))
267 require.NoError(t, err)
268 })
269 })
270 }
271 }
272
273 func TestModule_ValidateFunction_BulkMemoryOperations(t *testing.T) {
274 t.Run("ok", func(t *testing.T) {
275 for _, op := range []OpcodeMisc{
276 OpcodeMiscMemoryInit, OpcodeMiscDataDrop, OpcodeMiscMemoryCopy,
277 OpcodeMiscMemoryFill, OpcodeMiscTableInit, OpcodeMiscElemDrop, OpcodeMiscTableCopy,
278 } {
279 t.Run(MiscInstructionName(op), func(t *testing.T) {
280 var body []byte
281 if op != OpcodeMiscDataDrop && op != OpcodeMiscElemDrop {
282 body = append(body, OpcodeI32Const, 1, OpcodeI32Const, 2, OpcodeI32Const, 3)
283 }
284
285 body = append(body, OpcodeMiscPrefix, op)
286 if op != OpcodeMiscDataDrop && op != OpcodeMiscMemoryFill && op != OpcodeMiscElemDrop {
287 body = append(body, 0, 0)
288 } else {
289 body = append(body, 0)
290 }
291
292 body = append(body, OpcodeEnd)
293
294 c := uint32(0)
295 m := &Module{
296 TypeSection: []FunctionType{v_v},
297 FunctionSection: []Index{0},
298 CodeSection: []Code{{Body: body}},
299 DataSection: []DataSegment{{}},
300 ElementSection: []ElementSegment{{}},
301 DataCountSection: &c,
302 }
303 err := m.validateFunction(&stacks{}, api.CoreFeatureBulkMemoryOperations,
304 0, []Index{0}, nil, &Memory{}, []Table{{}, {}}, nil, bytes.NewReader(nil))
305 require.NoError(t, err)
306 })
307 }
308 })
309 t.Run("errors", func(t *testing.T) {
310 tests := []struct {
311 body []byte
312 dataSection []DataSegment
313 elementSection []ElementSegment
314 dataCountSectionNil bool
315 memory *Memory
316 tables []Table
317 flag api.CoreFeatures
318 expectedErr string
319 }{
320
321 {
322 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit},
323 flag: api.CoreFeatureBulkMemoryOperations,
324 memory: nil,
325 expectedErr: "memory must exist for memory.init",
326 },
327 {
328 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit},
329 flag: api.CoreFeaturesV1,
330 expectedErr: `memory.init invalid as feature "bulk-memory-operations" is disabled`,
331 },
332 {
333 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit},
334 flag: api.CoreFeatureBulkMemoryOperations,
335 dataCountSectionNil: true,
336 expectedErr: `memory must exist for memory.init`,
337 },
338 {
339 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit},
340 flag: api.CoreFeatureBulkMemoryOperations,
341 memory: &Memory{},
342 expectedErr: "failed to read data segment index for memory.init: EOF",
343 },
344 {
345 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit, 100 },
346 flag: api.CoreFeatureBulkMemoryOperations,
347 memory: &Memory{},
348 dataSection: []DataSegment{{}},
349 expectedErr: "index 100 out of range of data section(len=1)",
350 },
351 {
352 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit, 0},
353 flag: api.CoreFeatureBulkMemoryOperations,
354 memory: &Memory{},
355 dataSection: []DataSegment{{}},
356 expectedErr: "failed to read memory index for memory.init: EOF",
357 },
358 {
359 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit, 0, 1},
360 flag: api.CoreFeatureBulkMemoryOperations,
361 memory: &Memory{},
362 dataSection: []DataSegment{{}},
363 expectedErr: "memory.init reserved byte must be zero encoded with 1 byte",
364 },
365 {
366 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit, 0, 0},
367 flag: api.CoreFeatureBulkMemoryOperations,
368 memory: &Memory{},
369 dataSection: []DataSegment{{}},
370 expectedErr: "cannot pop the operand for memory.init: i32 missing",
371 },
372 {
373 body: []byte{OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscMemoryInit, 0, 0},
374 flag: api.CoreFeatureBulkMemoryOperations,
375 memory: &Memory{},
376 dataSection: []DataSegment{{}},
377 expectedErr: "cannot pop the operand for memory.init: i32 missing",
378 },
379 {
380 body: []byte{OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscMemoryInit, 0, 0},
381 flag: api.CoreFeatureBulkMemoryOperations,
382 memory: &Memory{},
383 dataSection: []DataSegment{{}},
384 expectedErr: "cannot pop the operand for memory.init: i32 missing",
385 },
386
387 {
388 body: []byte{OpcodeMiscPrefix, OpcodeMiscDataDrop},
389 flag: api.CoreFeaturesV1,
390 expectedErr: `data.drop invalid as feature "bulk-memory-operations" is disabled`,
391 },
392 {
393 body: []byte{OpcodeMiscPrefix, OpcodeMiscDataDrop},
394 dataCountSectionNil: true,
395 memory: &Memory{},
396 flag: api.CoreFeatureBulkMemoryOperations,
397 expectedErr: `data.drop requires data count section`,
398 },
399 {
400 body: []byte{OpcodeMiscPrefix, OpcodeMiscDataDrop},
401 flag: api.CoreFeatureBulkMemoryOperations,
402 memory: &Memory{},
403 expectedErr: "failed to read data segment index for data.drop: EOF",
404 },
405 {
406 body: []byte{OpcodeMiscPrefix, OpcodeMiscDataDrop, 100 },
407 flag: api.CoreFeatureBulkMemoryOperations,
408 memory: &Memory{},
409 dataSection: []DataSegment{{}},
410 expectedErr: "index 100 out of range of data section(len=1)",
411 },
412
413 {
414 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryCopy},
415 flag: api.CoreFeatureBulkMemoryOperations,
416 memory: nil,
417 expectedErr: "memory must exist for memory.copy",
418 },
419 {
420 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryCopy},
421 flag: api.CoreFeaturesV1,
422 expectedErr: `memory.copy invalid as feature "bulk-memory-operations" is disabled`,
423 },
424 {
425 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryCopy},
426 flag: api.CoreFeatureBulkMemoryOperations,
427 memory: &Memory{},
428 expectedErr: `failed to read memory index for memory.copy: EOF`,
429 },
430 {
431 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryCopy, 0},
432 flag: api.CoreFeatureBulkMemoryOperations,
433 memory: &Memory{},
434 expectedErr: "failed to read memory index for memory.copy: EOF",
435 },
436 {
437 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryCopy, 0, 1},
438 flag: api.CoreFeatureBulkMemoryOperations,
439 memory: &Memory{},
440 expectedErr: "memory.copy reserved byte must be zero encoded with 1 byte",
441 },
442 {
443 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryCopy, 0, 0},
444 flag: api.CoreFeatureBulkMemoryOperations,
445 memory: &Memory{},
446 expectedErr: "cannot pop the operand for memory.copy: i32 missing",
447 },
448 {
449 body: []byte{OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscMemoryCopy, 0, 0},
450 flag: api.CoreFeatureBulkMemoryOperations,
451 memory: &Memory{},
452 expectedErr: "cannot pop the operand for memory.copy: i32 missing",
453 },
454 {
455 body: []byte{OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscMemoryCopy, 0, 0},
456 flag: api.CoreFeatureBulkMemoryOperations,
457 memory: &Memory{},
458 expectedErr: "cannot pop the operand for memory.copy: i32 missing",
459 },
460
461 {
462 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryFill},
463 flag: api.CoreFeatureBulkMemoryOperations,
464 memory: nil,
465 expectedErr: "memory must exist for memory.fill",
466 },
467 {
468 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryFill},
469 flag: api.CoreFeaturesV1,
470 expectedErr: `memory.fill invalid as feature "bulk-memory-operations" is disabled`,
471 },
472 {
473 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryFill},
474 flag: api.CoreFeatureBulkMemoryOperations,
475 memory: &Memory{},
476 expectedErr: `failed to read memory index for memory.fill: EOF`,
477 },
478 {
479 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryFill, 1},
480 flag: api.CoreFeatureBulkMemoryOperations,
481 memory: &Memory{},
482 expectedErr: `memory.fill reserved byte must be zero encoded with 1 byte`,
483 },
484 {
485 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryFill, 0},
486 flag: api.CoreFeatureBulkMemoryOperations,
487 memory: &Memory{},
488 expectedErr: "cannot pop the operand for memory.fill: i32 missing",
489 },
490 {
491 body: []byte{OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscMemoryFill, 0},
492 flag: api.CoreFeatureBulkMemoryOperations,
493 memory: &Memory{},
494 expectedErr: "cannot pop the operand for memory.fill: i32 missing",
495 },
496 {
497 body: []byte{OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscMemoryFill, 0},
498 flag: api.CoreFeatureBulkMemoryOperations,
499 memory: &Memory{},
500 expectedErr: "cannot pop the operand for memory.fill: i32 missing",
501 },
502
503 {
504 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableInit},
505 flag: api.CoreFeaturesV1,
506 tables: []Table{{}},
507 expectedErr: `table.init invalid as feature "bulk-memory-operations" is disabled`,
508 },
509 {
510 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableInit},
511 flag: api.CoreFeatureBulkMemoryOperations,
512 tables: []Table{{}},
513 expectedErr: "failed to read element segment index for table.init: EOF",
514 },
515 {
516 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableInit, 100 },
517 flag: api.CoreFeatureBulkMemoryOperations,
518 tables: []Table{{}},
519 elementSection: []ElementSegment{{}},
520 expectedErr: "index 100 out of range of element section(len=1)",
521 },
522 {
523 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableInit, 0},
524 flag: api.CoreFeatureBulkMemoryOperations,
525 tables: []Table{{}},
526 elementSection: []ElementSegment{{}},
527 expectedErr: "failed to read source table index for table.init: EOF",
528 },
529 {
530 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableInit, 0, 10},
531 flag: api.CoreFeatureBulkMemoryOperations,
532 tables: []Table{{}},
533 elementSection: []ElementSegment{{}},
534 expectedErr: "source table index must be zero for table.init as feature \"reference-types\" is disabled",
535 },
536 {
537 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableInit, 0, 10},
538 flag: api.CoreFeatureBulkMemoryOperations | api.CoreFeatureReferenceTypes,
539 tables: []Table{{}},
540 elementSection: []ElementSegment{{}},
541 expectedErr: "table of index 10 not found",
542 },
543 {
544 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableInit, 0, 1},
545 flag: api.CoreFeatureBulkMemoryOperations | api.CoreFeatureReferenceTypes,
546 tables: []Table{{}, {Type: RefTypeExternref}},
547 elementSection: []ElementSegment{{Type: RefTypeFuncref}},
548 expectedErr: "type mismatch for table.init: element type funcref does not match table type externref",
549 },
550 {
551 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableInit, 0, 0},
552 flag: api.CoreFeatureBulkMemoryOperations,
553 tables: []Table{{}},
554 elementSection: []ElementSegment{{}},
555 expectedErr: "cannot pop the operand for table.init: i32 missing",
556 },
557 {
558 body: []byte{OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscTableInit, 0, 0},
559 flag: api.CoreFeatureBulkMemoryOperations,
560 tables: []Table{{}},
561 elementSection: []ElementSegment{{}},
562 expectedErr: "cannot pop the operand for table.init: i32 missing",
563 },
564 {
565 body: []byte{OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscTableInit, 0, 0},
566 flag: api.CoreFeatureBulkMemoryOperations,
567 tables: []Table{{}},
568 elementSection: []ElementSegment{{}},
569 expectedErr: "cannot pop the operand for table.init: i32 missing",
570 },
571
572 {
573 body: []byte{OpcodeMiscPrefix, OpcodeMiscElemDrop},
574 flag: api.CoreFeaturesV1,
575 tables: []Table{{}},
576 expectedErr: `elem.drop invalid as feature "bulk-memory-operations" is disabled`,
577 },
578 {
579 body: []byte{OpcodeMiscPrefix, OpcodeMiscElemDrop},
580 flag: api.CoreFeatureBulkMemoryOperations,
581 tables: []Table{{}},
582 expectedErr: "failed to read element segment index for elem.drop: EOF",
583 },
584 {
585 body: []byte{OpcodeMiscPrefix, OpcodeMiscElemDrop, 100 },
586 flag: api.CoreFeatureBulkMemoryOperations,
587 tables: []Table{{}},
588 elementSection: []ElementSegment{{}},
589 expectedErr: "index 100 out of range of element section(len=1)",
590 },
591
592 {
593 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy},
594 flag: api.CoreFeaturesV1,
595 tables: []Table{{}},
596 expectedErr: `table.copy invalid as feature "bulk-memory-operations" is disabled`,
597 },
598 {
599 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy},
600 flag: api.CoreFeatureBulkMemoryOperations,
601 tables: []Table{{}},
602 expectedErr: `failed to read destination table index for table.copy: EOF`,
603 },
604 {
605 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy, 10},
606 flag: api.CoreFeatureBulkMemoryOperations,
607 tables: []Table{{}},
608 expectedErr: "destination table index must be zero for table.copy as feature \"reference-types\" is disabled",
609 },
610 {
611 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy, 3},
612 flag: api.CoreFeatureBulkMemoryOperations | api.CoreFeatureReferenceTypes,
613 tables: []Table{{}, {}},
614 expectedErr: "table of index 3 not found",
615 },
616 {
617 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy, 3},
618 flag: api.CoreFeatureBulkMemoryOperations | api.CoreFeatureReferenceTypes,
619 tables: []Table{{}, {}, {}, {}},
620 expectedErr: "failed to read source table index for table.copy: EOF",
621 },
622 {
623 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy, 0, 3},
624 flag: api.CoreFeatureBulkMemoryOperations,
625 tables: []Table{{}, {}, {}, {}},
626 expectedErr: "source table index must be zero for table.copy as feature \"reference-types\" is disabled",
627 },
628 {
629 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy, 3, 1},
630 flag: api.CoreFeatureBulkMemoryOperations | api.CoreFeatureReferenceTypes,
631 tables: []Table{{}, {Type: RefTypeFuncref}, {}, {Type: RefTypeExternref}},
632 expectedErr: "table type mismatch for table.copy: funcref (src) != externref (dst)",
633 },
634 {
635 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy, 0, 0},
636 flag: api.CoreFeatureBulkMemoryOperations,
637 tables: []Table{{}},
638 expectedErr: "cannot pop the operand for table.copy: i32 missing",
639 },
640 {
641 body: []byte{OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscTableCopy, 0, 0},
642 flag: api.CoreFeatureBulkMemoryOperations,
643 tables: []Table{{}},
644 expectedErr: "cannot pop the operand for table.copy: i32 missing",
645 },
646 {
647 body: []byte{OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscTableCopy, 0, 0},
648 flag: api.CoreFeatureBulkMemoryOperations,
649 tables: []Table{{}},
650 expectedErr: "cannot pop the operand for table.copy: i32 missing",
651 },
652 }
653
654 for _, tt := range tests {
655 tc := tt
656 t.Run(tc.expectedErr, func(t *testing.T) {
657 m := &Module{
658 TypeSection: []FunctionType{v_v},
659 FunctionSection: []Index{0},
660 CodeSection: []Code{{Body: tc.body}},
661 ElementSection: tc.elementSection,
662 DataSection: tc.dataSection,
663 }
664 if !tc.dataCountSectionNil {
665 c := uint32(0)
666 m.DataCountSection = &c
667 }
668 err := m.validateFunction(&stacks{}, tc.flag, 0, []Index{0}, nil, tc.memory, tc.tables, nil, bytes.NewReader(nil))
669 require.EqualError(t, err, tc.expectedErr)
670 })
671 }
672 })
673 }
674
675 var (
676 f32, f64, i32, i64, v128, externref = ValueTypeF32, ValueTypeF64, ValueTypeI32, ValueTypeI64, ValueTypeV128, ValueTypeExternref
677 f32i32_v = initFt([]ValueType{f32, i32}, nil)
678 f64f32_i64 = initFt([]ValueType{f64, f32}, []ValueType{i64})
679 f64i32_v128i64 = initFt([]ValueType{f64, i32}, []ValueType{v128, i64})
680 i32_i32 = initFt([]ValueType{i32}, []ValueType{i32})
681 i32f64_v = initFt([]ValueType{i32, f64}, nil)
682 i32i32_i32 = initFt([]ValueType{i32, i32}, []ValueType{i32})
683 i32_v = initFt([]ValueType{i32}, nil)
684 v_v = FunctionType{}
685 v_f32 = initFt(nil, []ValueType{f32})
686 v_f32f32 = initFt(nil, []ValueType{f32, f32})
687 v_f64i32 = initFt(nil, []ValueType{f64, i32})
688 v_f64f64 = initFt(nil, []ValueType{f64, f64})
689 v_i32 = initFt(nil, []ValueType{i32})
690 v_i32i32 = initFt(nil, []ValueType{i32, i32})
691 v_i32i64 = initFt(nil, []ValueType{i32, i64})
692 v_i64i64 = initFt(nil, []ValueType{i64, i64})
693 )
694
695 func initFt(params, results []ValueType) FunctionType {
696 ft := FunctionType{Params: params, Results: results}
697 ft.CacheNumInUint64()
698 return ft
699 }
700
701
702
703
704 func TestModule_ValidateFunction_MultiValue_TypeMismatch(t *testing.T) {
705 tests := []struct {
706 name string
707 module *Module
708 expectedErr string
709 enabledFeatures api.CoreFeatures
710 }{
711
712
713 {
714 name: `func.wast - type-empty-f64-i32`,
715 module: &Module{
716 TypeSection: []FunctionType{v_f64i32},
717 FunctionSection: []Index{0},
718 CodeSection: []Code{{Body: []byte{OpcodeEnd}}},
719 },
720 expectedErr: `not enough results
721 have ()
722 want (f64, i32)`,
723 },
724 {
725 name: `func.wast - type-value-void-vs-nums`,
726 module: &Module{
727 TypeSection: []FunctionType{v_i32i32},
728 FunctionSection: []Index{0},
729 CodeSection: []Code{{Body: []byte{OpcodeNop, OpcodeEnd}}},
730 },
731 expectedErr: `not enough results
732 have ()
733 want (i32, i32)`,
734 },
735 {
736 name: `func.wast - type-value-nums-vs-void`,
737 module: &Module{
738 TypeSection: []FunctionType{v_v},
739 FunctionSection: []Index{0},
740 CodeSection: []Code{{Body: []byte{OpcodeI32Const, 0, OpcodeI64Const, 0, OpcodeEnd}}},
741 },
742 expectedErr: `too many results
743 have (i32, i64)
744 want ()`,
745 },
746 {
747 name: `func.wast - type-value-num-vs-nums - v_f32f32 -> f32`,
748 module: &Module{
749 TypeSection: []FunctionType{v_f32f32},
750 FunctionSection: []Index{0},
751 CodeSection: []Code{{Body: []byte{
752 OpcodeF32Const, 0, 0, 0, 0,
753 OpcodeEnd,
754 }}},
755 },
756 expectedErr: `not enough results
757 have (f32)
758 want (f32, f32)`,
759 },
760 {
761 name: `func.wast - type-value-num-vs-nums - v_f32 -> f32f32`,
762 module: &Module{
763 TypeSection: []FunctionType{v_f32},
764 FunctionSection: []Index{0},
765 CodeSection: []Code{{Body: []byte{
766 OpcodeF32Const, 0, 0, 0, 0, OpcodeF32Const, 0, 0, 0, 0,
767 OpcodeEnd,
768 }}},
769 },
770 expectedErr: `too many results
771 have (f32, f32)
772 want (f32)`,
773 },
774 {
775 name: `func.wast - type-return-last-empty-vs-nums`,
776 module: &Module{
777 TypeSection: []FunctionType{v_f32f32},
778 FunctionSection: []Index{0},
779 CodeSection: []Code{{Body: []byte{OpcodeReturn, OpcodeEnd}}},
780 },
781 expectedErr: `not enough results
782 have ()
783 want (f32, f32)`,
784 },
785 {
786 name: `func.wast - type-return-last-void-vs-nums`,
787 module: &Module{
788 TypeSection: []FunctionType{v_i32i64},
789 FunctionSection: []Index{0},
790 CodeSection: []Code{{Body: []byte{OpcodeNop, OpcodeReturn, OpcodeEnd}}},
791 },
792 expectedErr: `not enough results
793 have ()
794 want (i32, i64)`,
795 },
796 {
797 name: `func.wast - type-return-last-num-vs-nums`,
798 module: &Module{
799 TypeSection: []FunctionType{v_i64i64},
800 FunctionSection: []Index{0},
801 CodeSection: []Code{{Body: []byte{
802 OpcodeI64Const, 0, OpcodeReturn,
803 OpcodeEnd,
804 }}},
805 },
806 expectedErr: `not enough results
807 have (i64)
808 want (i64, i64)`,
809 },
810 {
811 name: `func.wast - type-return-empty-vs-nums`,
812
813
814
815
816 module: &Module{
817 TypeSection: []FunctionType{v_i32i32},
818 FunctionSection: []Index{0},
819 CodeSection: []Code{{Body: []byte{
820 OpcodeReturn, OpcodeI32Const, 1, OpcodeI32Const, 2,
821 OpcodeEnd,
822 }}},
823 },
824 expectedErr: `not enough results
825 have ()
826 want (i32, i32)`,
827 },
828 {
829 name: `func.wast - type-return-partial-vs-nums`,
830
831
832
833
834 module: &Module{
835 TypeSection: []FunctionType{v_i32i32},
836 FunctionSection: []Index{0},
837 CodeSection: []Code{{Body: []byte{
838 OpcodeI32Const, 1, OpcodeReturn, OpcodeI32Const, 2,
839 OpcodeEnd,
840 }}},
841 },
842 expectedErr: `not enough results
843 have (i32)
844 want (i32, i32)`,
845 },
846 {
847 name: `func.wast - type-return-void-vs-nums`,
848
849
850
851
852 module: &Module{
853 TypeSection: []FunctionType{v_i32i32},
854 FunctionSection: []Index{0},
855 CodeSection: []Code{{Body: []byte{
856 OpcodeNop, OpcodeReturn,
857 OpcodeI32Const, 1,
858 OpcodeEnd,
859 }}},
860 },
861 expectedErr: `not enough results
862 have ()
863 want (i32, i32)`,
864 },
865
866 {
867 name: `func.wast - type-return-num-vs-nums`,
868 module: &Module{
869 TypeSection: []FunctionType{v_i32i32},
870 FunctionSection: []Index{0},
871 CodeSection: []Code{{Body: []byte{
872 OpcodeI64Const, 1, OpcodeReturn,
873 OpcodeI32Const, 1, OpcodeI32Const, 2,
874 OpcodeEnd,
875 }}},
876 },
877 expectedErr: `not enough results
878 have (i64)
879 want (i32, i32)`,
880 },
881 {
882 name: `func.wast - type-return-first-num-vs-nums`,
883
884
885
886
887 module: &Module{
888 TypeSection: []FunctionType{v_i32i32},
889 FunctionSection: []Index{0},
890 CodeSection: []Code{{Body: []byte{
891 OpcodeI64Const, 1, OpcodeReturn,
892 OpcodeI32Const, 1, OpcodeI32Const, 2, OpcodeReturn,
893 OpcodeEnd,
894 }}},
895 },
896 expectedErr: `not enough results
897 have (i64)
898 want (i32, i32)`,
899 },
900 {
901 name: `func.wast - type-break-last-num-vs-nums`,
902 module: &Module{
903 TypeSection: []FunctionType{v_i32i32},
904 FunctionSection: []Index{0},
905 CodeSection: []Code{{Body: []byte{
906 OpcodeI32Const, 0, OpcodeBr, 0,
907 OpcodeEnd,
908 }}},
909 },
910 expectedErr: `not enough results in br block
911 have (i32)
912 want (i32, i32)`,
913 },
914 {
915 name: `func.wast - type-break-void-vs-nums`,
916
917
918
919
920 module: &Module{
921 TypeSection: []FunctionType{v_i32i32},
922 FunctionSection: []Index{0},
923 CodeSection: []Code{{Body: []byte{
924 OpcodeBr, 0,
925 OpcodeI32Const, 1, OpcodeI32Const, 2,
926 OpcodeEnd,
927 }}},
928 },
929 expectedErr: `not enough results in br block
930 have ()
931 want (i32, i32)`,
932 },
933 {
934 name: `func.wast - type-break-num-vs-nums`,
935
936
937
938
939 module: &Module{
940 TypeSection: []FunctionType{v_i32i32},
941 FunctionSection: []Index{0},
942 CodeSection: []Code{{Body: []byte{
943 OpcodeI32Const, 1, OpcodeBr, 0,
944 OpcodeI32Const, 1, OpcodeI32Const, 2,
945 OpcodeEnd,
946 }}},
947 },
948 expectedErr: `not enough results in br block
949 have (i32)
950 want (i32, i32)`,
951 },
952 {
953 name: `func.wast - type-break-nested-empty-vs-nums`,
954
955
956
957
958 module: &Module{
959 TypeSection: []FunctionType{v_i32i32},
960 FunctionSection: []Index{0},
961 CodeSection: []Code{{Body: []byte{
962 OpcodeBlock, 0x40, OpcodeBr, 0x01, OpcodeEnd,
963 OpcodeI32Const, 1, OpcodeI32Const, 2, OpcodeBr, 0,
964 OpcodeEnd,
965 }}},
966 },
967 expectedErr: `not enough results in br block
968 have ()
969 want (i32, i32)`,
970 },
971 {
972 name: `func.wast - type-break-nested-void-vs-nums`,
973
974
975
976
977 module: &Module{
978 TypeSection: []FunctionType{v_i32i32},
979 FunctionSection: []Index{0},
980 CodeSection: []Code{{Body: []byte{
981 OpcodeBlock, 0x40, OpcodeNop, OpcodeBr, 0x01, OpcodeEnd,
982 OpcodeI32Const, 1, OpcodeI32Const, 2, OpcodeBr, 0,
983 OpcodeEnd,
984 }}},
985 },
986 expectedErr: `not enough results in br block
987 have ()
988 want (i32, i32)`,
989 },
990 {
991 name: `func.wast - type-break-nested-num-vs-nums`,
992
993
994
995
996 module: &Module{
997 TypeSection: []FunctionType{v_i32i32},
998 FunctionSection: []Index{0},
999 CodeSection: []Code{{Body: []byte{
1000 OpcodeBlock, 0x7f, OpcodeI32Const, 1, OpcodeBr, 1, OpcodeEnd,
1001 OpcodeI32Const, 1, OpcodeI32Const, 2, OpcodeBr, 0,
1002 OpcodeEnd,
1003 }}},
1004 },
1005 expectedErr: `not enough results in br block
1006 have (i32)
1007 want (i32, i32)`,
1008 },
1009
1010
1011 {
1012 name: `if.wast - wrong signature for if type use`,
1013
1014
1015
1016
1017
1018 module: &Module{
1019 TypeSection: []FunctionType{v_v},
1020 FunctionSection: []Index{0},
1021 CodeSection: []Code{{Body: []byte{
1022 OpcodeI32Const, 1,
1023 OpcodeI32Const, 0, OpcodeIf, 0,
1024 OpcodeEnd,
1025 OpcodeEnd,
1026 }}},
1027 },
1028 expectedErr: `too many results
1029 have (i32)
1030 want ()`,
1031 },
1032 {
1033 name: `if.wast - type-then-value-nums-vs-void`,
1034
1035
1036
1037
1038 module: &Module{
1039 TypeSection: []FunctionType{v_v},
1040 FunctionSection: []Index{0},
1041 CodeSection: []Code{{Body: []byte{
1042 OpcodeI32Const, 1, OpcodeIf, 0x40,
1043 OpcodeI32Const, 1, OpcodeI32Const, 2,
1044 OpcodeEnd,
1045 OpcodeEnd,
1046 }}},
1047 },
1048 expectedErr: `too many results in if block
1049 have (i32, i32)
1050 want ()`,
1051 },
1052 {
1053 name: `if.wast - type-then-value-nums-vs-void-else`,
1054
1055
1056
1057
1058 module: &Module{
1059 TypeSection: []FunctionType{v_v},
1060 FunctionSection: []Index{0},
1061 CodeSection: []Code{{Body: []byte{
1062 OpcodeI32Const, 1, OpcodeIf, 0x40,
1063 OpcodeI32Const, 1, OpcodeI32Const, 2,
1064 OpcodeElse,
1065 OpcodeEnd,
1066 OpcodeEnd,
1067 }}},
1068 },
1069 expectedErr: `too many results in if block
1070 have (i32, i32)
1071 want ()`,
1072 },
1073 {
1074 name: `if.wast - type-else-value-nums-vs-void`,
1075
1076
1077
1078
1079 module: &Module{
1080 TypeSection: []FunctionType{v_v},
1081 FunctionSection: []Index{0},
1082 CodeSection: []Code{{Body: []byte{
1083 OpcodeI32Const, 1, OpcodeIf, 0x40,
1084 OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 2,
1085 OpcodeEnd,
1086 OpcodeEnd,
1087 }}},
1088 },
1089 expectedErr: `too many results in else block
1090 have (i32, i32)
1091 want ()`,
1092 },
1093 {
1094 name: `if.wast - type-both-value-nums-vs-void`,
1095
1096
1097
1098
1099 module: &Module{
1100 TypeSection: []FunctionType{v_v},
1101 FunctionSection: []Index{0},
1102 CodeSection: []Code{{Body: []byte{
1103 OpcodeI32Const, 1, OpcodeIf, 0x40,
1104 OpcodeI32Const, 1, OpcodeI32Const, 2,
1105 OpcodeElse, OpcodeI32Const, 2, OpcodeI32Const, 1,
1106 OpcodeEnd,
1107 OpcodeEnd,
1108 }}},
1109 },
1110 expectedErr: `too many results in if block
1111 have (i32, i32)
1112 want ()`,
1113 },
1114 {
1115 name: `if.wast - type-then-value-empty-vs-nums`,
1116
1117
1118
1119
1120 module: &Module{
1121 TypeSection: []FunctionType{v_v, v_i32i32},
1122 FunctionSection: []Index{0},
1123 CodeSection: []Code{{Body: []byte{
1124 OpcodeI32Const, 1, OpcodeIf, 0x01,
1125 OpcodeElse, OpcodeI32Const, 0, OpcodeI32Const, 2,
1126 OpcodeEnd,
1127 OpcodeEnd,
1128 }}},
1129 },
1130 expectedErr: `not enough results in if block
1131 have ()
1132 want (i32, i32)`,
1133 },
1134 {
1135 name: `if.wast - type-else-value-empty-vs-nums`,
1136
1137
1138
1139
1140 module: &Module{
1141 TypeSection: []FunctionType{v_v, v_i32i32},
1142 FunctionSection: []Index{0},
1143 CodeSection: []Code{{Body: []byte{
1144 OpcodeI32Const, 1, OpcodeIf, 0x01,
1145 OpcodeI32Const, 0, OpcodeI32Const, 2,
1146 OpcodeElse,
1147 OpcodeEnd,
1148 OpcodeEnd,
1149 }}},
1150 },
1151 expectedErr: `not enough results in else block
1152 have ()
1153 want (i32, i32)`,
1154 },
1155 {
1156 name: `if.wast - type-both-value-empty-vs-nums`,
1157
1158
1159
1160
1161 module: &Module{
1162 TypeSection: []FunctionType{v_v, v_i32i32},
1163 FunctionSection: []Index{0},
1164 CodeSection: []Code{{Body: []byte{
1165 OpcodeI32Const, 1, OpcodeIf, 0x01,
1166 OpcodeElse,
1167 OpcodeEnd,
1168 OpcodeEnd,
1169 }}},
1170 },
1171 expectedErr: `not enough results in if block
1172 have ()
1173 want (i32, i32)`,
1174 },
1175 {
1176 name: `if.wast - type-no-else-vs-nums`,
1177
1178
1179
1180
1181 module: &Module{
1182 TypeSection: []FunctionType{v_v, v_i32i32},
1183 FunctionSection: []Index{0},
1184 CodeSection: []Code{{Body: []byte{
1185 OpcodeI32Const, 1, OpcodeIf, 0x01,
1186 OpcodeI32Const, 1, OpcodeI32Const, 1,
1187 OpcodeEnd,
1188 OpcodeEnd,
1189 }}},
1190 },
1191 expectedErr: `not enough results in else block
1192 have ()
1193 want (i32, i32)`,
1194 },
1195 {
1196 name: `if.wast - type-then-value-void-vs-nums`,
1197
1198
1199
1200
1201 module: &Module{
1202 TypeSection: []FunctionType{v_v, v_i32i32},
1203 FunctionSection: []Index{0},
1204 CodeSection: []Code{{Body: []byte{
1205 OpcodeI32Const, 1, OpcodeIf, 0x01,
1206 OpcodeNop,
1207 OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1,
1208 OpcodeEnd,
1209 OpcodeEnd,
1210 }}},
1211 },
1212 expectedErr: `not enough results in if block
1213 have ()
1214 want (i32, i32)`,
1215 },
1216 {
1217 name: `if.wast - type-then-value-void-vs-nums`,
1218
1219
1220
1221
1222 module: &Module{
1223 TypeSection: []FunctionType{v_i32i32},
1224 FunctionSection: []Index{0},
1225 CodeSection: []Code{{Body: []byte{
1226 OpcodeI32Const, 1, OpcodeIf, 0x00,
1227 OpcodeI32Const, 0, OpcodeI32Const, 0,
1228 OpcodeElse, OpcodeNop,
1229 OpcodeEnd,
1230 OpcodeEnd,
1231 }}},
1232 },
1233 expectedErr: `not enough results in else block
1234 have ()
1235 want (i32, i32)`,
1236 },
1237 {
1238 name: `if.wast - type-both-value-void-vs-nums`,
1239
1240
1241
1242
1243 module: &Module{
1244 TypeSection: []FunctionType{v_i32i32},
1245 FunctionSection: []Index{0},
1246 CodeSection: []Code{{Body: []byte{
1247 OpcodeI32Const, 1, OpcodeIf, 0x00,
1248 OpcodeNop,
1249 OpcodeElse, OpcodeNop,
1250 OpcodeEnd,
1251 OpcodeEnd,
1252 }}},
1253 },
1254 expectedErr: `not enough results in if block
1255 have ()
1256 want (i32, i32)`,
1257 },
1258 {
1259 name: `if.wast - type-then-value-num-vs-nums`,
1260
1261
1262
1263
1264 module: &Module{
1265 TypeSection: []FunctionType{v_i32i32},
1266 FunctionSection: []Index{0},
1267 CodeSection: []Code{{Body: []byte{
1268 OpcodeI32Const, 1, OpcodeIf, 0x00,
1269 OpcodeI32Const, 1,
1270 OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1,
1271 OpcodeEnd,
1272 OpcodeEnd,
1273 }}},
1274 },
1275 expectedErr: `not enough results in if block
1276 have (i32)
1277 want (i32, i32)`,
1278 },
1279 {
1280 name: `if.wast - type-else-value-num-vs-nums`,
1281
1282
1283
1284
1285 module: &Module{
1286 TypeSection: []FunctionType{v_i32i32},
1287 FunctionSection: []Index{0},
1288 CodeSection: []Code{{Body: []byte{
1289 OpcodeI32Const, 1, OpcodeIf, 0x00,
1290 OpcodeI32Const, 1, OpcodeI32Const, 1,
1291 OpcodeElse, OpcodeI32Const, 1,
1292 OpcodeEnd,
1293 OpcodeEnd,
1294 }}},
1295 },
1296 expectedErr: `not enough results in else block
1297 have (i32)
1298 want (i32, i32)`,
1299 },
1300 {
1301 name: `if.wast - type-both-value-num-vs-nums`,
1302
1303
1304
1305
1306 module: &Module{
1307 TypeSection: []FunctionType{v_i32i32},
1308 FunctionSection: []Index{0},
1309 CodeSection: []Code{{Body: []byte{
1310 OpcodeI32Const, 1, OpcodeIf, 0x00,
1311 OpcodeI32Const, 1,
1312 OpcodeElse, OpcodeI32Const, 1,
1313 OpcodeEnd,
1314 OpcodeEnd,
1315 }}},
1316 },
1317 expectedErr: `not enough results in if block
1318 have (i32)
1319 want (i32, i32)`,
1320 },
1321 {
1322 name: `if.wast - type-then-value-partial-vs-nums`,
1323
1324
1325
1326
1327
1328 module: &Module{
1329 TypeSection: []FunctionType{v_i32i32},
1330 FunctionSection: []Index{0},
1331 CodeSection: []Code{{Body: []byte{
1332 OpcodeI32Const, 0,
1333 OpcodeI32Const, 1, OpcodeIf, 0x00,
1334 OpcodeI32Const, 1,
1335 OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1,
1336 OpcodeEnd,
1337 OpcodeEnd,
1338 }}},
1339 },
1340 expectedErr: `not enough results in if block
1341 have (i32)
1342 want (i32, i32)`,
1343 },
1344 {
1345 name: `if.wast - type-else-value-partial-vs-nums`,
1346
1347
1348
1349
1350
1351 module: &Module{
1352 TypeSection: []FunctionType{v_i32i32},
1353 FunctionSection: []Index{0},
1354 CodeSection: []Code{{Body: []byte{
1355 OpcodeI32Const, 0,
1356 OpcodeI32Const, 1, OpcodeIf, 0x00,
1357 OpcodeI32Const, 1, OpcodeI32Const, 1,
1358 OpcodeElse, OpcodeI32Const, 1,
1359 OpcodeEnd,
1360 OpcodeEnd,
1361 }}},
1362 },
1363 expectedErr: `not enough results in else block
1364 have (i32)
1365 want (i32, i32)`,
1366 },
1367 {
1368 name: `if.wast - type-both-value-partial-vs-nums`,
1369
1370
1371
1372
1373
1374 module: &Module{
1375 TypeSection: []FunctionType{v_i32i32},
1376 FunctionSection: []Index{0},
1377 CodeSection: []Code{{Body: []byte{
1378 OpcodeI32Const, 0,
1379 OpcodeI32Const, 1, OpcodeIf, 0x00,
1380 OpcodeI32Const, 1,
1381 OpcodeElse, OpcodeI32Const, 1,
1382 OpcodeEnd,
1383 OpcodeEnd,
1384 }}},
1385 },
1386 expectedErr: `not enough results in if block
1387 have (i32)
1388 want (i32, i32)`,
1389 },
1390 {
1391 name: `if.wast - type-then-value-nums-vs-num`,
1392
1393
1394
1395
1396 module: &Module{
1397 TypeSection: []FunctionType{v_i32},
1398 FunctionSection: []Index{0},
1399 CodeSection: []Code{{Body: []byte{
1400 OpcodeI32Const, 1, OpcodeIf, 0x00,
1401 OpcodeI32Const, 1, OpcodeI32Const, 1,
1402 OpcodeElse, OpcodeI32Const, 1,
1403 OpcodeEnd,
1404 OpcodeEnd,
1405 }}},
1406 },
1407 expectedErr: `too many results in if block
1408 have (i32, i32)
1409 want (i32)`,
1410 },
1411 {
1412 name: `if.wast - type-else-value-nums-vs-num`,
1413
1414
1415
1416
1417 module: &Module{
1418 TypeSection: []FunctionType{v_i32},
1419 FunctionSection: []Index{0},
1420 CodeSection: []Code{{Body: []byte{
1421 OpcodeI32Const, 1, OpcodeIf, 0x00,
1422 OpcodeI32Const, 1,
1423 OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1,
1424 OpcodeEnd,
1425 OpcodeEnd,
1426 }}},
1427 },
1428 expectedErr: `too many results in else block
1429 have (i32, i32)
1430 want (i32)`,
1431 },
1432 {
1433 name: `if.wast - type-both-value-nums-vs-num`,
1434
1435
1436
1437
1438 module: &Module{
1439 TypeSection: []FunctionType{v_i32},
1440 FunctionSection: []Index{0},
1441 CodeSection: []Code{{Body: []byte{
1442 OpcodeI32Const, 1, OpcodeIf, 0x00,
1443 OpcodeI32Const, 1, OpcodeI32Const, 1,
1444 OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1,
1445 OpcodeEnd,
1446 OpcodeEnd,
1447 }}},
1448 },
1449 expectedErr: `too many results in if block
1450 have (i32, i32)
1451 want (i32)`,
1452 },
1453 {
1454 name: `if.wast - type-both-different-value-nums-vs-nums`,
1455
1456
1457
1458
1459 module: &Module{
1460 TypeSection: []FunctionType{v_i32i32},
1461 FunctionSection: []Index{0},
1462 CodeSection: []Code{{Body: []byte{
1463 OpcodeI32Const, 1, OpcodeIf, 0x00,
1464 OpcodeI32Const, 1, OpcodeI32Const, 1, OpcodeI32Const, 1,
1465 OpcodeElse, OpcodeI32Const, 1,
1466 OpcodeEnd,
1467 OpcodeEnd,
1468 }}},
1469 },
1470 expectedErr: `too many results in if block
1471 have (i32, i32, i32)
1472 want (i32, i32)`,
1473 },
1474 {
1475 name: `if.wast - type-then-break-last-void-vs-nums`,
1476
1477
1478
1479
1480 module: &Module{
1481 TypeSection: []FunctionType{v_i32i32},
1482 FunctionSection: []Index{0},
1483 CodeSection: []Code{{Body: []byte{
1484 OpcodeI32Const, 1, OpcodeIf, 0x00,
1485 OpcodeBr, 0,
1486 OpcodeElse, OpcodeI32Const, 1,
1487 OpcodeEnd,
1488 OpcodeEnd,
1489 }}},
1490 },
1491 expectedErr: `not enough results in br block
1492 have ()
1493 want (i32, i32)`,
1494 },
1495 {
1496 name: `if.wast - type-else-break-last-void-vs-nums`,
1497
1498
1499
1500
1501 module: &Module{
1502 TypeSection: []FunctionType{v_i32i32},
1503 FunctionSection: []Index{0},
1504 CodeSection: []Code{{Body: []byte{
1505 OpcodeI32Const, 1, OpcodeIf, 0x00,
1506 OpcodeI32Const, 1, OpcodeI32Const, 1,
1507 OpcodeElse, OpcodeBr, 0,
1508 OpcodeEnd,
1509 OpcodeEnd,
1510 }}},
1511 },
1512 expectedErr: `not enough results in br block
1513 have ()
1514 want (i32, i32)`,
1515 },
1516 {
1517 name: `if.wast - type-then-break-empty-vs-nums`,
1518
1519
1520
1521
1522
1523
1524
1525 module: &Module{
1526 TypeSection: []FunctionType{v_i32i32},
1527 FunctionSection: []Index{0},
1528 CodeSection: []Code{{Body: []byte{
1529 OpcodeI32Const, 1, OpcodeIf, 0x00,
1530 OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1,
1531
1532 OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1,
1533 OpcodeEnd,
1534 OpcodeEnd,
1535 }}},
1536 },
1537 expectedErr: `not enough results in br block
1538 have ()
1539 want (i32, i32)`,
1540 },
1541 {
1542 name: `if.wast - type-else-break-empty-vs-nums`,
1543
1544
1545
1546
1547
1548
1549
1550 module: &Module{
1551 TypeSection: []FunctionType{v_i32i32},
1552 FunctionSection: []Index{0},
1553 CodeSection: []Code{{Body: []byte{
1554 OpcodeI32Const, 1, OpcodeIf, 0x00,
1555 OpcodeI32Const, 1, OpcodeI32Const, 1,
1556 OpcodeElse, OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1,
1557
1558 OpcodeEnd,
1559 OpcodeEnd,
1560 }}},
1561 },
1562 expectedErr: `not enough results in br block
1563 have ()
1564 want (i32, i32)`,
1565 },
1566 {
1567 name: `if.wast - type-then-break-void-vs-nums`,
1568
1569
1570
1571
1572
1573
1574
1575 module: &Module{
1576 TypeSection: []FunctionType{v_i32i32},
1577 FunctionSection: []Index{0},
1578 CodeSection: []Code{{Body: []byte{
1579 OpcodeI32Const, 1, OpcodeIf, 0x00,
1580 OpcodeNop, OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1,
1581
1582 OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1,
1583 OpcodeEnd,
1584 OpcodeEnd,
1585 }}},
1586 },
1587 expectedErr: `not enough results in br block
1588 have ()
1589 want (i32, i32)`,
1590 },
1591 {
1592 name: `if.wast - type-else-break-void-vs-nums`,
1593
1594
1595
1596
1597
1598
1599
1600 module: &Module{
1601 TypeSection: []FunctionType{v_i32i32},
1602 FunctionSection: []Index{0},
1603 CodeSection: []Code{{Body: []byte{
1604 OpcodeI32Const, 1, OpcodeIf, 0x00,
1605 OpcodeI32Const, 1, OpcodeI32Const, 1,
1606 OpcodeElse, OpcodeNop, OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1,
1607
1608 OpcodeEnd,
1609 OpcodeEnd,
1610 }}},
1611 },
1612 expectedErr: `not enough results in br block
1613 have ()
1614 want (i32, i32)`,
1615 },
1616 {
1617 name: `if.wast - type-then-break-num-vs-nums`,
1618
1619
1620
1621
1622
1623
1624
1625 module: &Module{
1626 TypeSection: []FunctionType{v_i32i32},
1627 FunctionSection: []Index{0},
1628 CodeSection: []Code{{Body: []byte{
1629 OpcodeI32Const, 1, OpcodeIf, 0x00,
1630 OpcodeI64Const, 1, OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1,
1631
1632 OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1,
1633 OpcodeEnd,
1634 OpcodeEnd,
1635 }}},
1636 },
1637 expectedErr: `not enough results in br block
1638 have (i64)
1639 want (i32, i32)`,
1640 },
1641 {
1642 name: `if.wast - type-else-break-num-vs-nums`,
1643
1644
1645
1646
1647
1648
1649
1650 module: &Module{
1651 TypeSection: []FunctionType{v_i32i32},
1652 FunctionSection: []Index{0},
1653 CodeSection: []Code{{Body: []byte{
1654 OpcodeI32Const, 1, OpcodeIf, 0x00,
1655 OpcodeI32Const, 1, OpcodeI32Const, 1,
1656 OpcodeElse, OpcodeI64Const, 1, OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1,
1657
1658 OpcodeEnd,
1659 OpcodeEnd,
1660 }}},
1661 },
1662 expectedErr: `not enough results in br block
1663 have (i64)
1664 want (i32, i32)`,
1665 },
1666 {
1667 name: `if.wast - type-then-break-partial-vs-nums`,
1668
1669
1670
1671
1672
1673
1674
1675
1676 module: &Module{
1677 TypeSection: []FunctionType{v_i32i32},
1678 FunctionSection: []Index{0},
1679 CodeSection: []Code{{Body: []byte{
1680 OpcodeI32Const, 1,
1681 OpcodeI32Const, 1, OpcodeIf, 0x00,
1682 OpcodeI64Const, 1, OpcodeBr, 0, OpcodeI32Const, 1,
1683
1684 OpcodeElse, OpcodeI32Const, 1,
1685 OpcodeEnd,
1686 OpcodeEnd,
1687 }}},
1688 },
1689 expectedErr: `not enough results in br block
1690 have (i64)
1691 want (i32, i32)`,
1692 },
1693 {
1694 name: `if.wast - type-else-break-partial-vs-nums`,
1695
1696
1697
1698
1699
1700
1701
1702
1703 module: &Module{
1704 TypeSection: []FunctionType{v_i32i32},
1705 FunctionSection: []Index{0},
1706 CodeSection: []Code{{Body: []byte{
1707 OpcodeI32Const, 1,
1708 OpcodeI32Const, 1, OpcodeIf, 0x00,
1709 OpcodeI32Const, 1,
1710 OpcodeElse, OpcodeI64Const, 1, OpcodeBr, 0, OpcodeI32Const, 1,
1711
1712 OpcodeEnd,
1713 OpcodeEnd,
1714 }}},
1715 },
1716 expectedErr: `not enough results in if block
1717 have (i32)
1718 want (i32, i32)`,
1719 },
1720 {
1721 name: `if.wast - type-param-void-vs-num`,
1722
1723
1724
1725
1726 module: &Module{
1727 TypeSection: []FunctionType{v_v, i32_v},
1728 FunctionSection: []Index{0},
1729 CodeSection: []Code{{Body: []byte{
1730 OpcodeI32Const, 1, OpcodeIf, 0x01,
1731 OpcodeDrop,
1732 OpcodeEnd,
1733 OpcodeEnd,
1734 }}},
1735 },
1736 expectedErr: `not enough params for if block
1737 have ()
1738 want (i32)`,
1739 },
1740 {
1741 name: `if.wast - type-param-void-vs-nums`,
1742
1743
1744
1745
1746 module: &Module{
1747 TypeSection: []FunctionType{v_v, i32f64_v},
1748 FunctionSection: []Index{0},
1749 CodeSection: []Code{{Body: []byte{
1750 OpcodeI32Const, 1, OpcodeIf, 0x01,
1751 OpcodeI32Const, 1, OpcodeDrop,
1752 OpcodeEnd,
1753 OpcodeEnd,
1754 }}},
1755 },
1756 expectedErr: `not enough params for if block
1757 have ()
1758 want (i32, f64)`,
1759 },
1760 {
1761 name: `if.wast - type-param-num-vs-num`,
1762
1763
1764
1765
1766 module: &Module{
1767 TypeSection: []FunctionType{v_v, i32_v},
1768 FunctionSection: []Index{0},
1769 CodeSection: []Code{{Body: []byte{
1770 OpcodeF32Const, 0, 0, 0, 0,
1771 OpcodeI32Const, 1, OpcodeIf, 0x01,
1772 OpcodeDrop,
1773 OpcodeEnd,
1774 OpcodeEnd,
1775 }}},
1776 },
1777 expectedErr: "cannot use f32 in if block as param[0] type i32",
1778 },
1779 {
1780 name: `if.wast - type-param-num-vs-nums`,
1781
1782
1783
1784
1785 module: &Module{
1786 TypeSection: []FunctionType{v_v, f32i32_v},
1787 FunctionSection: []Index{0},
1788 CodeSection: []Code{{Body: []byte{
1789 OpcodeF32Const, 0, 0, 0, 0,
1790 OpcodeI32Const, 1, OpcodeIf, 0x01,
1791 OpcodeDrop, OpcodeDrop,
1792 OpcodeEnd,
1793 OpcodeEnd,
1794 }}},
1795 },
1796 expectedErr: `not enough params for if block
1797 have (f32)
1798 want (f32, i32)`,
1799 },
1800 {
1801 name: `if.wast - type-param-nested-void-vs-num`,
1802
1803
1804
1805
1806 module: &Module{
1807 TypeSection: []FunctionType{v_v, i32_v},
1808 FunctionSection: []Index{0},
1809 CodeSection: []Code{{Body: []byte{
1810 OpcodeBlock, 0x40,
1811 OpcodeI32Const, 1, OpcodeIf, 0x01,
1812 OpcodeDrop,
1813 OpcodeEnd,
1814 OpcodeEnd,
1815 OpcodeEnd,
1816 }}},
1817 },
1818 expectedErr: `not enough params for if block
1819 have ()
1820 want (i32)`,
1821 },
1822 {
1823 name: `if.wast - type-param-void-vs-nums`,
1824
1825
1826
1827
1828 module: &Module{
1829 TypeSection: []FunctionType{v_v, i32f64_v},
1830 FunctionSection: []Index{0},
1831 CodeSection: []Code{{Body: []byte{
1832 OpcodeBlock, 0x40,
1833 OpcodeI32Const, 1, OpcodeIf, 0x01,
1834 OpcodeDrop,
1835 OpcodeEnd,
1836 OpcodeEnd,
1837 OpcodeEnd,
1838 }}},
1839 },
1840 expectedErr: `not enough params for if block
1841 have ()
1842 want (i32, f64)`,
1843 },
1844 {
1845 name: `if.wast - type-param-num-vs-num`,
1846
1847
1848
1849
1850 module: &Module{
1851 TypeSection: []FunctionType{v_v, i32_v},
1852 FunctionSection: []Index{0},
1853 CodeSection: []Code{{Body: []byte{
1854 OpcodeBlock, 0x40,
1855 OpcodeF32Const, 0, 0, 0, 0,
1856 OpcodeI32Const, 1, OpcodeIf, 0x01,
1857 OpcodeDrop,
1858 OpcodeEnd,
1859 OpcodeEnd,
1860 OpcodeEnd,
1861 }}},
1862 },
1863 expectedErr: "cannot use f32 in if block as param[0] type i32",
1864 },
1865 {
1866 name: `if.wast - type-param-num-vs-nums`,
1867
1868
1869
1870
1871 module: &Module{
1872 TypeSection: []FunctionType{v_v, f32i32_v},
1873 FunctionSection: []Index{0},
1874 CodeSection: []Code{{Body: []byte{
1875 OpcodeBlock, 0x40,
1876 OpcodeF32Const, 0, 0, 0, 0,
1877 OpcodeI32Const, 1, OpcodeIf, 0x01,
1878 OpcodeDrop,
1879 OpcodeEnd,
1880 OpcodeEnd,
1881 OpcodeEnd,
1882 }}},
1883 },
1884 expectedErr: `not enough params for if block
1885 have (f32)
1886 want (f32, i32)`,
1887 },
1888
1889
1890 {
1891 name: `loop.wast - wrong signature for loop type use`,
1892
1893
1894
1895
1896
1897 module: &Module{
1898 TypeSection: []FunctionType{v_v},
1899 FunctionSection: []Index{0},
1900 CodeSection: []Code{{Body: []byte{
1901 OpcodeLoop, 0, OpcodeI32Const, 0,
1902 OpcodeEnd,
1903 OpcodeEnd,
1904 }}},
1905 },
1906 expectedErr: `too many results in loop block
1907 have (i32)
1908 want ()`,
1909 },
1910 {
1911 name: `loop.wast - type-value-nums-vs-void`,
1912
1913
1914
1915
1916 module: &Module{
1917 TypeSection: []FunctionType{v_v},
1918 FunctionSection: []Index{0},
1919 CodeSection: []Code{{Body: []byte{
1920 OpcodeLoop, 0x40, OpcodeI32Const, 1, OpcodeI32Const, 2,
1921 OpcodeEnd,
1922 OpcodeEnd,
1923 }}},
1924 },
1925 expectedErr: `too many results in loop block
1926 have (i32, i32)
1927 want ()`,
1928 },
1929 {
1930 name: `loop.wast - type-value-empty-vs-nums`,
1931
1932
1933
1934
1935 module: &Module{
1936 TypeSection: []FunctionType{v_i32i32},
1937 FunctionSection: []Index{0},
1938 CodeSection: []Code{{Body: []byte{
1939 OpcodeLoop, 0x0,
1940 OpcodeEnd,
1941 OpcodeEnd,
1942 }}},
1943 },
1944 expectedErr: `not enough results in loop block
1945 have ()
1946 want (i32, i32)`,
1947 },
1948 {
1949 name: `loop.wast - type-value-void-vs-nums`,
1950
1951
1952
1953
1954 module: &Module{
1955 TypeSection: []FunctionType{v_i32i32},
1956 FunctionSection: []Index{0},
1957 CodeSection: []Code{{Body: []byte{
1958 OpcodeLoop, 0x0,
1959 OpcodeNop,
1960 OpcodeEnd,
1961 OpcodeEnd,
1962 }}},
1963 },
1964 expectedErr: `not enough results in loop block
1965 have ()
1966 want (i32, i32)`,
1967 },
1968 {
1969 name: `loop.wast - type-value-num-vs-nums`,
1970
1971
1972
1973
1974 module: &Module{
1975 TypeSection: []FunctionType{v_i32i32},
1976 FunctionSection: []Index{0},
1977 CodeSection: []Code{{Body: []byte{
1978 OpcodeLoop, 0x0,
1979 OpcodeI32Const, 0,
1980 OpcodeEnd,
1981 OpcodeEnd,
1982 }}},
1983 },
1984 expectedErr: `not enough results in loop block
1985 have (i32)
1986 want (i32, i32)`,
1987 },
1988 {
1989 name: `loop.wast - type-value-partial-vs-nums`,
1990
1991
1992
1993
1994 module: &Module{
1995 TypeSection: []FunctionType{v_i32i32},
1996 FunctionSection: []Index{0},
1997 CodeSection: []Code{{Body: []byte{
1998 OpcodeI32Const, 1,
1999 OpcodeLoop, 0x0,
2000 OpcodeI32Const, 2,
2001 OpcodeEnd,
2002 OpcodeEnd,
2003 }}},
2004 },
2005 expectedErr: `not enough results in loop block
2006 have (i32)
2007 want (i32, i32)`,
2008 },
2009 {
2010 name: `loop.wast - type-value-nums-vs-num`,
2011
2012
2013
2014
2015 module: &Module{
2016 TypeSection: []FunctionType{v_i32},
2017 FunctionSection: []Index{0},
2018 CodeSection: []Code{{Body: []byte{
2019 OpcodeLoop, 0x0,
2020 OpcodeI32Const, 1, OpcodeI32Const, 2,
2021 OpcodeEnd,
2022 OpcodeEnd,
2023 }}},
2024 },
2025 expectedErr: `too many results in loop block
2026 have (i32, i32)
2027 want (i32)`,
2028 },
2029 {
2030 name: `loop.wast - type-param-void-vs-num`,
2031
2032
2033
2034
2035 module: &Module{
2036 TypeSection: []FunctionType{v_v, i32_v},
2037 FunctionSection: []Index{0},
2038 CodeSection: []Code{{Body: []byte{
2039 OpcodeLoop, 0x1,
2040 OpcodeDrop,
2041 OpcodeEnd,
2042 OpcodeEnd,
2043 }}},
2044 },
2045 expectedErr: `not enough params for loop block
2046 have ()
2047 want (i32)`,
2048 },
2049 {
2050 name: `loop.wast - type-param-void-vs-nums`,
2051
2052
2053
2054
2055 module: &Module{
2056 TypeSection: []FunctionType{v_v, i32f64_v},
2057 FunctionSection: []Index{0},
2058 CodeSection: []Code{{Body: []byte{
2059 OpcodeLoop, 0x1,
2060 OpcodeDrop,
2061 OpcodeDrop,
2062 OpcodeEnd,
2063 OpcodeEnd,
2064 }}},
2065 },
2066 expectedErr: `not enough params for loop block
2067 have ()
2068 want (i32, f64)`,
2069 },
2070 {
2071 name: `loop.wast - type-param-num-vs-num`,
2072
2073
2074
2075
2076 module: &Module{
2077 TypeSection: []FunctionType{v_v, i32_v},
2078 FunctionSection: []Index{0},
2079 CodeSection: []Code{{Body: []byte{
2080 OpcodeF32Const, 0, 0, 0, 0,
2081 OpcodeLoop, 0x1,
2082 OpcodeDrop,
2083 OpcodeEnd,
2084 OpcodeEnd,
2085 }}},
2086 },
2087 expectedErr: "cannot use f32 in loop block as param[0] type i32",
2088 },
2089 {
2090 name: `loop.wast - type-param-num-vs-num`,
2091
2092
2093
2094
2095 module: &Module{
2096 TypeSection: []FunctionType{v_v, f32i32_v},
2097 FunctionSection: []Index{0},
2098 CodeSection: []Code{{Body: []byte{
2099 OpcodeF32Const, 0, 0, 0, 0,
2100 OpcodeLoop, 0x1,
2101 OpcodeDrop, OpcodeDrop,
2102 OpcodeEnd,
2103 OpcodeEnd,
2104 }}},
2105 },
2106 expectedErr: `not enough params for loop block
2107 have (f32)
2108 want (f32, i32)`,
2109 },
2110 {
2111 name: `loop.wast - type-param-nested-void-vs-num`,
2112
2113
2114
2115
2116 module: &Module{
2117 TypeSection: []FunctionType{v_v, i32_v},
2118 FunctionSection: []Index{0},
2119 CodeSection: []Code{{Body: []byte{
2120 OpcodeBlock, 0x40,
2121 OpcodeLoop, 0x1,
2122 OpcodeDrop,
2123 OpcodeEnd,
2124 OpcodeEnd,
2125 OpcodeEnd,
2126 }}},
2127 },
2128 expectedErr: `not enough params for loop block
2129 have ()
2130 want (i32)`,
2131 },
2132 {
2133 name: `loop.wast - type-param-void-vs-nums`,
2134
2135
2136
2137
2138 module: &Module{
2139 TypeSection: []FunctionType{v_v, i32f64_v},
2140 FunctionSection: []Index{0},
2141 CodeSection: []Code{{Body: []byte{
2142 OpcodeBlock, 0x40,
2143 OpcodeLoop, 0x1,
2144 OpcodeDrop, OpcodeDrop,
2145 OpcodeEnd,
2146 OpcodeEnd,
2147 OpcodeEnd,
2148 }}},
2149 },
2150 expectedErr: `not enough params for loop block
2151 have ()
2152 want (i32, f64)`,
2153 },
2154 {
2155 name: `loop.wast - type-param-void-vs-nums`,
2156
2157
2158
2159
2160 module: &Module{
2161 TypeSection: []FunctionType{v_v, i32_v},
2162 FunctionSection: []Index{0},
2163 CodeSection: []Code{{Body: []byte{
2164 OpcodeBlock, 0x40,
2165 OpcodeF32Const, 0, 0, 0, 0,
2166 OpcodeLoop, 0x1,
2167 OpcodeDrop,
2168 OpcodeEnd,
2169 OpcodeEnd,
2170 OpcodeEnd,
2171 }}},
2172 },
2173 expectedErr: "cannot use f32 in loop block as param[0] type i32",
2174 },
2175 {
2176 name: `loop.wast - type-param-void-vs-nums`,
2177
2178
2179
2180
2181 module: &Module{
2182 TypeSection: []FunctionType{v_v, f32i32_v},
2183 FunctionSection: []Index{0},
2184 CodeSection: []Code{{Body: []byte{
2185 OpcodeBlock, 0x40,
2186 OpcodeF32Const, 0, 0, 0, 0,
2187 OpcodeLoop, 0x1,
2188 OpcodeDrop, OpcodeDrop,
2189 OpcodeEnd,
2190 OpcodeEnd,
2191 OpcodeEnd,
2192 }}},
2193 },
2194 expectedErr: `not enough params for loop block
2195 have (f32)
2196 want (f32, i32)`,
2197 },
2198 }
2199
2200 for _, tt := range tests {
2201 tc := tt
2202
2203 t.Run(tc.name, func(t *testing.T) {
2204 err := tc.module.validateFunction(&stacks{}, api.CoreFeatureMultiValue,
2205 0, []Index{0}, nil, nil, nil, nil, bytes.NewReader(nil))
2206 require.EqualError(t, err, tc.expectedErr)
2207 })
2208 }
2209 }
2210
2211 func TestModule_funcValidation_CallIndirect(t *testing.T) {
2212 t.Run("ok", func(t *testing.T) {
2213 m := &Module{
2214 TypeSection: []FunctionType{v_v},
2215 FunctionSection: []Index{0},
2216 CodeSection: []Code{{Body: []byte{
2217 OpcodeI32Const, 1,
2218 OpcodeCallIndirect, 0, 0,
2219 OpcodeEnd,
2220 }}},
2221 }
2222 err := m.validateFunction(&stacks{}, api.CoreFeatureReferenceTypes,
2223 0, []Index{0}, nil, &Memory{}, []Table{{Type: RefTypeFuncref}}, nil, bytes.NewReader(nil))
2224 require.NoError(t, err)
2225 })
2226 t.Run("non zero table index", func(t *testing.T) {
2227 m := &Module{
2228 TypeSection: []FunctionType{v_v},
2229 FunctionSection: []Index{0},
2230 CodeSection: []Code{{Body: []byte{
2231 OpcodeI32Const, 1,
2232 OpcodeCallIndirect, 0, 100,
2233 OpcodeEnd,
2234 }}},
2235 }
2236 t.Run("disabled", func(t *testing.T) {
2237 err := m.validateFunction(&stacks{}, api.CoreFeaturesV1,
2238 0, []Index{0}, nil, &Memory{}, []Table{{}, {}}, nil, bytes.NewReader(nil))
2239 require.EqualError(t, err, "table index must be zero but was 100: feature \"reference-types\" is disabled")
2240 })
2241 t.Run("enabled but out of range", func(t *testing.T) {
2242 err := m.validateFunction(&stacks{}, api.CoreFeatureReferenceTypes,
2243 0, []Index{0}, nil, &Memory{}, []Table{{}, {}}, nil, bytes.NewReader(nil))
2244 require.EqualError(t, err, "unknown table index: 100")
2245 })
2246 })
2247 t.Run("non funcref table", func(t *testing.T) {
2248 m := &Module{
2249 TypeSection: []FunctionType{v_v},
2250 FunctionSection: []Index{0},
2251 CodeSection: []Code{{Body: []byte{
2252 OpcodeI32Const, 1,
2253 OpcodeCallIndirect, 0, 0,
2254 OpcodeEnd,
2255 }}},
2256 }
2257 err := m.validateFunction(&stacks{}, api.CoreFeatureReferenceTypes,
2258 0, []Index{0}, nil, &Memory{}, []Table{{Type: RefTypeExternref}}, nil, bytes.NewReader(nil))
2259 require.EqualError(t, err, "table is not funcref type but was externref for call_indirect")
2260 })
2261 }
2262
2263 func TestModule_funcValidation_RefTypes(t *testing.T) {
2264 tests := []struct {
2265 name string
2266 body []byte
2267 flag api.CoreFeatures
2268 declaredFunctionIndexes map[Index]struct{}
2269 expectedErr string
2270 }{
2271 {
2272 name: "ref.null (funcref)",
2273 flag: api.CoreFeatureReferenceTypes,
2274 body: []byte{
2275 OpcodeRefNull, ValueTypeFuncref,
2276 OpcodeDrop, OpcodeEnd,
2277 },
2278 },
2279 {
2280 name: "ref.null (externref)",
2281 flag: api.CoreFeatureReferenceTypes,
2282 body: []byte{
2283 OpcodeRefNull, ValueTypeExternref,
2284 OpcodeDrop, OpcodeEnd,
2285 },
2286 },
2287 {
2288 name: "ref.null - disabled",
2289 flag: api.CoreFeaturesV1,
2290 body: []byte{
2291 OpcodeRefNull, ValueTypeFuncref,
2292 OpcodeDrop, OpcodeEnd,
2293 },
2294 expectedErr: "ref.null invalid as feature \"reference-types\" is disabled",
2295 },
2296 {
2297 name: "ref.is_null",
2298 flag: api.CoreFeatureReferenceTypes,
2299 body: []byte{
2300 OpcodeRefNull, ValueTypeFuncref,
2301 OpcodeRefIsNull,
2302 OpcodeDrop, OpcodeEnd,
2303 },
2304 },
2305 {
2306 name: "ref.is_null - disabled",
2307 flag: api.CoreFeaturesV1,
2308 body: []byte{
2309 OpcodeRefIsNull,
2310 OpcodeDrop, OpcodeEnd,
2311 },
2312 expectedErr: `ref.is_null invalid as feature "reference-types" is disabled`,
2313 },
2314 {
2315 name: "ref.func",
2316 flag: api.CoreFeatureReferenceTypes,
2317 declaredFunctionIndexes: map[uint32]struct{}{0: {}},
2318 body: []byte{
2319 OpcodeRefFunc, 0,
2320 OpcodeDrop, OpcodeEnd,
2321 },
2322 },
2323 {
2324 name: "ref.func - undeclared function index",
2325 flag: api.CoreFeatureReferenceTypes,
2326 declaredFunctionIndexes: map[uint32]struct{}{0: {}},
2327 body: []byte{
2328 OpcodeRefFunc, 100,
2329 OpcodeDrop, OpcodeEnd,
2330 },
2331 expectedErr: `undeclared function index 100 for ref.func`,
2332 },
2333 {
2334 name: "ref.func",
2335 flag: api.CoreFeaturesV1,
2336 declaredFunctionIndexes: map[uint32]struct{}{0: {}},
2337 body: []byte{
2338 OpcodeRefFunc, 0,
2339 OpcodeDrop, OpcodeEnd,
2340 },
2341 expectedErr: "ref.func invalid as feature \"reference-types\" is disabled",
2342 },
2343 }
2344
2345 for _, tt := range tests {
2346 tc := tt
2347 t.Run(tc.name, func(t *testing.T) {
2348 m := &Module{
2349 TypeSection: []FunctionType{v_v},
2350 FunctionSection: []Index{0},
2351 CodeSection: []Code{{Body: tc.body}},
2352 }
2353 err := m.validateFunction(&stacks{}, tc.flag,
2354 0, []Index{0}, nil, nil, nil, tc.declaredFunctionIndexes, bytes.NewReader(nil))
2355 if tc.expectedErr != "" {
2356 require.EqualError(t, err, tc.expectedErr)
2357 } else {
2358 require.NoError(t, err)
2359 }
2360 })
2361 }
2362 }
2363
2364 func TestModule_funcValidation_TableGrowSizeFill(t *testing.T) {
2365 tables := []Table{{Type: RefTypeFuncref}, {Type: RefTypeExternref}}
2366 tests := []struct {
2367 name string
2368 body []byte
2369 flag api.CoreFeatures
2370 expectedErr string
2371 }{
2372 {
2373 name: "table.grow (funcref)",
2374 body: []byte{
2375 OpcodeRefNull, RefTypeFuncref,
2376 OpcodeI32Const, 1,
2377 OpcodeMiscPrefix, OpcodeMiscTableGrow,
2378 0,
2379 OpcodeDrop,
2380 OpcodeEnd,
2381 },
2382 flag: api.CoreFeatureReferenceTypes,
2383 },
2384 {
2385 name: "table.grow (funcref) - type mismatch",
2386 body: []byte{
2387 OpcodeRefNull, RefTypeFuncref,
2388 OpcodeI32Const, 1,
2389 OpcodeMiscPrefix, OpcodeMiscTableGrow,
2390 1,
2391 OpcodeEnd,
2392 },
2393 flag: api.CoreFeatureReferenceTypes,
2394 expectedErr: `cannot pop the operand for table.grow: type mismatch: expected externref, but was funcref`,
2395 },
2396 {
2397 name: "table.grow (externref)",
2398 body: []byte{
2399 OpcodeRefNull, RefTypeExternref,
2400 OpcodeI32Const, 1,
2401 OpcodeMiscPrefix, OpcodeMiscTableGrow,
2402 1,
2403 OpcodeDrop,
2404 OpcodeEnd,
2405 },
2406 flag: api.CoreFeatureReferenceTypes,
2407 },
2408 {
2409 name: "table.grow (externref) type mismatch",
2410 body: []byte{
2411 OpcodeRefNull, RefTypeExternref,
2412 OpcodeI32Const, 1,
2413 OpcodeMiscPrefix, OpcodeMiscTableGrow,
2414 0,
2415 OpcodeEnd,
2416 },
2417 flag: api.CoreFeatureReferenceTypes,
2418 expectedErr: `cannot pop the operand for table.grow: type mismatch: expected funcref, but was externref`,
2419 },
2420 {
2421 name: "table.grow - table not found",
2422 body: []byte{
2423 OpcodeRefNull, RefTypeFuncref,
2424 OpcodeI32Const, 1,
2425 OpcodeMiscPrefix, OpcodeMiscTableGrow,
2426 10,
2427 OpcodeEnd,
2428 },
2429 flag: api.CoreFeatureReferenceTypes,
2430 expectedErr: `table of index 10 not found`,
2431 },
2432 {
2433 name: "table.size - table not found",
2434 body: []byte{
2435 OpcodeMiscPrefix, OpcodeMiscTableSize,
2436 10,
2437 OpcodeEnd,
2438 },
2439 flag: api.CoreFeatureReferenceTypes,
2440 expectedErr: `table of index 10 not found`,
2441 },
2442 {
2443 name: "table.size",
2444 body: []byte{
2445 OpcodeMiscPrefix, OpcodeMiscTableSize,
2446 1,
2447 OpcodeDrop,
2448 OpcodeEnd,
2449 },
2450 flag: api.CoreFeatureReferenceTypes,
2451 },
2452 {
2453 name: "table.fill (funcref)",
2454 body: []byte{
2455 OpcodeI32Const, 1,
2456 OpcodeRefNull, RefTypeFuncref,
2457 OpcodeI32Const, 1,
2458 OpcodeMiscPrefix, OpcodeMiscTableFill,
2459 0,
2460 OpcodeEnd,
2461 },
2462 flag: api.CoreFeatureReferenceTypes,
2463 },
2464 {
2465 name: "table.fill (funcref) - type mismatch",
2466 body: []byte{
2467 OpcodeI32Const, 1,
2468 OpcodeRefNull, RefTypeFuncref,
2469 OpcodeI32Const, 1,
2470 OpcodeMiscPrefix, OpcodeMiscTableFill,
2471 1,
2472 OpcodeEnd,
2473 },
2474 flag: api.CoreFeatureReferenceTypes,
2475 expectedErr: `cannot pop the operand for table.fill: type mismatch: expected externref, but was funcref`,
2476 },
2477 {
2478 name: "table.fill (externref)",
2479 body: []byte{
2480 OpcodeI32Const, 1,
2481 OpcodeRefNull, RefTypeExternref,
2482 OpcodeI32Const, 1,
2483 OpcodeMiscPrefix, OpcodeMiscTableFill,
2484 1,
2485 OpcodeEnd,
2486 },
2487 flag: api.CoreFeatureReferenceTypes,
2488 },
2489 {
2490 name: "table.fill (externref) - type mismatch",
2491 body: []byte{
2492 OpcodeI32Const, 1,
2493 OpcodeRefNull, RefTypeExternref,
2494 OpcodeI32Const, 1,
2495 OpcodeMiscPrefix, OpcodeMiscTableFill,
2496 0,
2497 OpcodeEnd,
2498 },
2499 flag: api.CoreFeatureReferenceTypes,
2500 expectedErr: `cannot pop the operand for table.fill: type mismatch: expected funcref, but was externref`,
2501 },
2502 {
2503 name: "table.fill - table not found",
2504 body: []byte{
2505 OpcodeMiscPrefix, OpcodeMiscTableFill,
2506 10,
2507 OpcodeEnd,
2508 },
2509 flag: api.CoreFeatureReferenceTypes,
2510 expectedErr: `table of index 10 not found`,
2511 },
2512 }
2513
2514 for _, tt := range tests {
2515 tc := tt
2516 t.Run(tc.name, func(t *testing.T) {
2517 m := &Module{
2518 TypeSection: []FunctionType{v_v},
2519 FunctionSection: []Index{0},
2520 CodeSection: []Code{{Body: tc.body}},
2521 }
2522 err := m.validateFunction(&stacks{}, tc.flag,
2523 0, []Index{0}, nil, nil, tables, nil, bytes.NewReader(nil))
2524 if tc.expectedErr != "" {
2525 require.EqualError(t, err, tc.expectedErr)
2526 } else {
2527 require.NoError(t, err)
2528 }
2529 })
2530 }
2531 }
2532
2533 func TestModule_funcValidation_TableGetSet(t *testing.T) {
2534 tables := []Table{{Type: RefTypeFuncref}, {Type: RefTypeExternref}}
2535 tests := []struct {
2536 name string
2537 body []byte
2538 flag api.CoreFeatures
2539 expectedErr string
2540 }{
2541 {
2542 name: "table.get (funcref)",
2543 body: []byte{
2544 OpcodeI32Const, 0,
2545 OpcodeTableGet, 0,
2546 OpcodeRefIsNull,
2547 OpcodeDrop,
2548 OpcodeEnd,
2549 },
2550 flag: api.CoreFeatureReferenceTypes,
2551 },
2552 {
2553 name: "table.get (externref)",
2554 body: []byte{
2555 OpcodeI32Const, 0,
2556 OpcodeTableGet, 1,
2557 OpcodeRefIsNull,
2558 OpcodeDrop,
2559 OpcodeEnd,
2560 },
2561 flag: api.CoreFeatureReferenceTypes,
2562 },
2563 {
2564 name: "table.get (disabled)",
2565 body: []byte{
2566 OpcodeI32Const, 0,
2567 OpcodeTableGet, 0,
2568 OpcodeDrop,
2569 OpcodeEnd,
2570 },
2571 flag: api.CoreFeaturesV1,
2572 expectedErr: `table.get is invalid as feature "reference-types" is disabled`,
2573 },
2574 {
2575 name: "table.set (funcref)",
2576 body: []byte{
2577 OpcodeI32Const, 0,
2578 OpcodeRefNull, ValueTypeFuncref,
2579 OpcodeTableSet, 0,
2580 OpcodeEnd,
2581 },
2582 flag: api.CoreFeatureReferenceTypes,
2583 },
2584 {
2585 name: "table.set type mismatch (src=funcref, dst=externref)",
2586 body: []byte{
2587 OpcodeI32Const, 0,
2588 OpcodeRefNull, ValueTypeFuncref,
2589 OpcodeTableSet, 1,
2590 OpcodeEnd,
2591 },
2592 flag: api.CoreFeatureReferenceTypes,
2593 expectedErr: `cannot pop the operand for table.set: type mismatch: expected externref, but was funcref`,
2594 },
2595 {
2596 name: "table.set (externref)",
2597 body: []byte{
2598 OpcodeI32Const, 0,
2599 OpcodeRefNull, ValueTypeExternref,
2600 OpcodeTableSet, 1,
2601 OpcodeEnd,
2602 },
2603 flag: api.CoreFeatureReferenceTypes,
2604 },
2605 {
2606 name: "table.set type mismatch (src=externref, dst=funcref)",
2607 body: []byte{
2608 OpcodeI32Const, 0,
2609 OpcodeRefNull, ValueTypeExternref,
2610 OpcodeTableSet, 0,
2611 OpcodeEnd,
2612 },
2613 flag: api.CoreFeatureReferenceTypes,
2614 expectedErr: `cannot pop the operand for table.set: type mismatch: expected funcref, but was externref`,
2615 },
2616 {
2617 name: "table.set (disabled)",
2618 body: []byte{
2619 OpcodeTableSet, 1,
2620 OpcodeEnd,
2621 },
2622 flag: api.CoreFeaturesV1,
2623 expectedErr: `table.set is invalid as feature "reference-types" is disabled`,
2624 },
2625 }
2626
2627 for _, tt := range tests {
2628 tc := tt
2629 t.Run(tc.name, func(t *testing.T) {
2630 m := &Module{
2631 TypeSection: []FunctionType{v_v},
2632 FunctionSection: []Index{0},
2633 CodeSection: []Code{{Body: tc.body}},
2634 }
2635 err := m.validateFunction(&stacks{}, tc.flag,
2636 0, []Index{0}, nil, nil, tables, nil, bytes.NewReader(nil))
2637 if tc.expectedErr != "" {
2638 require.EqualError(t, err, tc.expectedErr)
2639 } else {
2640 require.NoError(t, err)
2641 }
2642 })
2643 }
2644 }
2645
2646 func TestModule_funcValidation_Select_error(t *testing.T) {
2647 tests := []struct {
2648 name string
2649 body []byte
2650 flag api.CoreFeatures
2651 expectedErr string
2652 }{
2653 {
2654 name: "typed_select (disabled)",
2655 body: []byte{
2656 OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeI32Const, 0,
2657 OpcodeTypedSelect, 1, ValueTypeI32,
2658 OpcodeDrop,
2659 OpcodeEnd,
2660 },
2661 flag: api.CoreFeaturesV1,
2662 expectedErr: "typed_select is invalid as feature \"reference-types\" is disabled",
2663 },
2664 {
2665 name: "typed_select (too many immediate types)",
2666 body: []byte{
2667 OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeI32Const, 0,
2668 OpcodeTypedSelect, 2,
2669 },
2670 flag: api.CoreFeatureReferenceTypes,
2671 expectedErr: `too many type immediates for typed_select`,
2672 },
2673 {
2674 name: "typed_select (immediate type not found)",
2675 body: []byte{
2676 OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeI32Const, 0,
2677 OpcodeTypedSelect, 1, 0,
2678 OpcodeEnd,
2679 },
2680 flag: api.CoreFeatureReferenceTypes,
2681 expectedErr: `invalid type unknown for typed_select`,
2682 },
2683 }
2684
2685 for _, tt := range tests {
2686 tc := tt
2687 t.Run(tc.name, func(t *testing.T) {
2688 m := &Module{
2689 TypeSection: []FunctionType{v_v},
2690 FunctionSection: []Index{0},
2691 CodeSection: []Code{{Body: tc.body}},
2692 }
2693 err := m.validateFunction(&stacks{}, tc.flag,
2694 0, []Index{0}, nil, nil, nil, nil, bytes.NewReader(nil))
2695 require.EqualError(t, err, tc.expectedErr)
2696 })
2697 }
2698 }
2699
2700 func TestModule_funcValidation_SIMD(t *testing.T) {
2701 addV128Const := func(in []byte) []byte {
2702 return append(in, OpcodeVecPrefix,
2703 OpcodeVecV128Const,
2704 1, 1, 1, 1, 1, 1, 1, 1,
2705 1, 1, 1, 1, 1, 1, 1, 1)
2706 }
2707 vv2v := func(vec OpcodeVec) (ret []byte) {
2708 ret = addV128Const(ret)
2709 ret = addV128Const(ret)
2710 return append(ret,
2711 OpcodeVecPrefix,
2712 vec,
2713 OpcodeDrop,
2714 OpcodeEnd,
2715 )
2716 }
2717 vvv2v := func(vec OpcodeVec) (ret []byte) {
2718 ret = addV128Const(ret)
2719 ret = addV128Const(ret)
2720 ret = addV128Const(ret)
2721 return append(ret,
2722 OpcodeVecPrefix,
2723 vec,
2724 OpcodeDrop,
2725 OpcodeEnd,
2726 )
2727 }
2728
2729 v2v := func(vec OpcodeVec) (ret []byte) {
2730 ret = addV128Const(ret)
2731 return append(ret,
2732 OpcodeVecPrefix,
2733 vec,
2734 OpcodeDrop,
2735 OpcodeEnd,
2736 )
2737 }
2738
2739 vi2v := func(vec OpcodeVec) (ret []byte) {
2740 ret = addV128Const(ret)
2741 return append(ret,
2742 OpcodeI32Const, 1,
2743 OpcodeVecPrefix,
2744 vec,
2745 OpcodeDrop,
2746 OpcodeEnd,
2747 )
2748 }
2749
2750 load := func(vec OpcodeVec, offset, align uint32) (ret []byte) {
2751 ret = []byte{
2752 OpcodeI32Const, 1,
2753 OpcodeVecPrefix,
2754 vec,
2755 }
2756
2757 ret = append(ret, leb128.EncodeUint32(align)...)
2758 ret = append(ret, leb128.EncodeUint32(offset)...)
2759 ret = append(ret,
2760 OpcodeDrop,
2761 OpcodeEnd,
2762 )
2763 return
2764 }
2765
2766 loadLane := func(vec OpcodeVec, offset, align uint32, lane byte) (ret []byte) {
2767 ret = addV128Const([]byte{OpcodeI32Const, 1})
2768 ret = append(ret,
2769 OpcodeVecPrefix,
2770 vec,
2771 )
2772
2773 ret = append(ret, leb128.EncodeUint32(align)...)
2774 ret = append(ret, leb128.EncodeUint32(offset)...)
2775 ret = append(ret,
2776 lane,
2777 OpcodeDrop,
2778 OpcodeEnd,
2779 )
2780 return
2781 }
2782
2783 storeLane := func(vec OpcodeVec, offset, align uint32, lane byte) (ret []byte) {
2784 ret = addV128Const([]byte{OpcodeI32Const, 1})
2785 ret = append(ret,
2786 OpcodeVecPrefix,
2787 vec,
2788 )
2789 ret = append(ret, leb128.EncodeUint32(align)...)
2790 ret = append(ret, leb128.EncodeUint32(offset)...)
2791 ret = append(ret,
2792 lane,
2793 OpcodeEnd,
2794 )
2795 return
2796 }
2797
2798 extractLane := func(vec OpcodeVec, lane byte) (ret []byte) {
2799 ret = addV128Const(ret)
2800 ret = append(ret,
2801 OpcodeVecPrefix,
2802 vec,
2803 lane,
2804 OpcodeDrop,
2805 OpcodeEnd,
2806 )
2807 return
2808 }
2809
2810 replaceLane := func(vec OpcodeVec, lane byte) (ret []byte) {
2811 ret = addV128Const(ret)
2812
2813 switch vec {
2814 case OpcodeVecI8x16ReplaceLane, OpcodeVecI16x8ReplaceLane, OpcodeVecI32x4ReplaceLane:
2815 ret = append(ret, OpcodeI32Const, 0)
2816 case OpcodeVecI64x2ReplaceLane:
2817 ret = append(ret, OpcodeI64Const, 0)
2818 case OpcodeVecF32x4ReplaceLane:
2819 ret = append(ret, OpcodeF32Const, 0, 0, 0, 0)
2820 case OpcodeVecF64x2ReplaceLane:
2821 ret = append(ret, OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0, 0)
2822 }
2823
2824 ret = append(ret,
2825 OpcodeVecPrefix,
2826 vec,
2827 lane,
2828 OpcodeDrop,
2829 OpcodeEnd,
2830 )
2831 return
2832 }
2833
2834 splat := func(vec OpcodeVec) (ret []byte) {
2835 switch vec {
2836 case OpcodeVecI8x16Splat, OpcodeVecI16x8Splat, OpcodeVecI32x4Splat:
2837 ret = append(ret, OpcodeI32Const, 0, 0, 0, 0)
2838 case OpcodeVecI64x2Splat:
2839 ret = append(ret, OpcodeI64Const, 0, 0, 0, 0, 0, 0, 0, 0)
2840 case OpcodeVecF32x4Splat:
2841 ret = append(ret, OpcodeF32Const, 0, 0, 0, 0)
2842 case OpcodeVecF64x2Splat:
2843 ret = append(ret, OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0, 0)
2844 }
2845
2846 ret = append(ret,
2847 OpcodeVecPrefix,
2848 vec,
2849 OpcodeDrop,
2850 OpcodeEnd,
2851 )
2852 return
2853 }
2854
2855 tests := []struct {
2856 name string
2857 body []byte
2858 expectedErr string
2859 }{
2860 {
2861 name: "v128.const",
2862 body: []byte{
2863 OpcodeVecPrefix,
2864 OpcodeVecV128Const,
2865 1, 1, 1, 1, 1, 1, 1, 1,
2866 1, 1, 1, 1, 1, 1, 1, 1,
2867 OpcodeDrop,
2868 OpcodeEnd,
2869 },
2870 },
2871 {name: OpcodeVecI8x16AddName, body: vv2v(OpcodeVecI8x16Add)},
2872 {name: OpcodeVecI16x8AddName, body: vv2v(OpcodeVecI16x8Add)},
2873 {name: OpcodeVecI32x4AddName, body: vv2v(OpcodeVecI32x4Add)},
2874 {name: OpcodeVecI64x2AddName, body: vv2v(OpcodeVecI64x2Add)},
2875 {name: OpcodeVecI8x16SubName, body: vv2v(OpcodeVecI8x16Sub)},
2876 {name: OpcodeVecI16x8SubName, body: vv2v(OpcodeVecI16x8Sub)},
2877 {name: OpcodeVecI32x4SubName, body: vv2v(OpcodeVecI32x4Sub)},
2878 {name: OpcodeVecI64x2SubName, body: vv2v(OpcodeVecI64x2Sub)},
2879 {name: OpcodeVecV128AnyTrueName, body: v2v(OpcodeVecV128AnyTrue)},
2880 {name: OpcodeVecI8x16AllTrueName, body: v2v(OpcodeVecI8x16AllTrue)},
2881 {name: OpcodeVecI16x8AllTrueName, body: v2v(OpcodeVecI16x8AllTrue)},
2882 {name: OpcodeVecI32x4AllTrueName, body: v2v(OpcodeVecI32x4AllTrue)},
2883 {name: OpcodeVecI64x2AllTrueName, body: v2v(OpcodeVecI64x2AllTrue)},
2884 {name: OpcodeVecI8x16BitMaskName, body: v2v(OpcodeVecI8x16BitMask)},
2885 {name: OpcodeVecI16x8BitMaskName, body: v2v(OpcodeVecI16x8BitMask)},
2886 {name: OpcodeVecI32x4BitMaskName, body: v2v(OpcodeVecI32x4BitMask)},
2887 {name: OpcodeVecI64x2BitMaskName, body: v2v(OpcodeVecI64x2BitMask)},
2888 {name: OpcodeVecV128LoadName, body: load(OpcodeVecV128Load, 0, 0)},
2889 {name: OpcodeVecV128LoadName + "/align=4", body: load(OpcodeVecV128Load, 0, 4)},
2890 {name: OpcodeVecV128Load8x8SName, body: load(OpcodeVecV128Load8x8s, 1, 0)},
2891 {name: OpcodeVecV128Load8x8SName + "/align=1", body: load(OpcodeVecV128Load8x8s, 0, 1)},
2892 {name: OpcodeVecV128Load8x8UName, body: load(OpcodeVecV128Load8x8u, 0, 0)},
2893 {name: OpcodeVecV128Load8x8UName + "/align=1", body: load(OpcodeVecV128Load8x8u, 0, 1)},
2894 {name: OpcodeVecV128Load16x4SName, body: load(OpcodeVecV128Load16x4s, 1, 0)},
2895 {name: OpcodeVecV128Load16x4SName + "/align=2", body: load(OpcodeVecV128Load16x4s, 0, 2)},
2896 {name: OpcodeVecV128Load16x4UName, body: load(OpcodeVecV128Load16x4u, 0, 0)},
2897 {name: OpcodeVecV128Load16x4UName + "/align=2", body: load(OpcodeVecV128Load16x4u, 0, 2)},
2898 {name: OpcodeVecV128Load32x2SName, body: load(OpcodeVecV128Load32x2s, 1, 0)},
2899 {name: OpcodeVecV128Load32x2SName + "/align=3", body: load(OpcodeVecV128Load32x2s, 0, 3)},
2900 {name: OpcodeVecV128Load32x2UName, body: load(OpcodeVecV128Load32x2u, 0, 0)},
2901 {name: OpcodeVecV128Load32x2UName + "/align=3", body: load(OpcodeVecV128Load32x2u, 0, 3)},
2902 {name: OpcodeVecV128Load8SplatName, body: load(OpcodeVecV128Load8Splat, 2, 0)},
2903 {name: OpcodeVecV128Load16SplatName, body: load(OpcodeVecV128Load16Splat, 0, 1)},
2904 {name: OpcodeVecV128Load32SplatName, body: load(OpcodeVecV128Load32Splat, 3, 2)},
2905 {name: OpcodeVecV128Load64SplatName, body: load(OpcodeVecV128Load64Splat, 0, 3)},
2906 {name: OpcodeVecV128Load32zeroName, body: load(OpcodeVecV128Load32zero, 0, 2)},
2907 {name: OpcodeVecV128Load64zeroName, body: load(OpcodeVecV128Load64zero, 5, 3)},
2908 {name: OpcodeVecV128Load8LaneName, body: loadLane(OpcodeVecV128Load8Lane, 5, 0, 10)},
2909 {name: OpcodeVecV128Load16LaneName, body: loadLane(OpcodeVecV128Load16Lane, 100, 1, 7)},
2910 {name: OpcodeVecV128Load32LaneName, body: loadLane(OpcodeVecV128Load32Lane, 0, 2, 3)},
2911 {name: OpcodeVecV128Load64LaneName, body: loadLane(OpcodeVecV128Load64Lane, 0, 3, 1)},
2912 {
2913 name: OpcodeVecV128StoreName, body: []byte{
2914 OpcodeI32Const,
2915 1, 1, 1, 1,
2916 OpcodeVecPrefix,
2917 OpcodeVecV128Const,
2918 1, 1, 1, 1, 1, 1, 1, 1,
2919 1, 1, 1, 1, 1, 1, 1, 1,
2920 OpcodeVecPrefix,
2921 OpcodeVecV128Store,
2922 4,
2923 10,
2924 OpcodeEnd,
2925 },
2926 },
2927 {name: OpcodeVecV128Store8LaneName, body: storeLane(OpcodeVecV128Store8Lane, 0, 0, 0)},
2928 {name: OpcodeVecV128Store8LaneName + "/lane=15", body: storeLane(OpcodeVecV128Store8Lane, 100, 0, 15)},
2929 {name: OpcodeVecV128Store16LaneName, body: storeLane(OpcodeVecV128Store16Lane, 0, 0, 0)},
2930 {name: OpcodeVecV128Store16LaneName + "/lane=7/align=1", body: storeLane(OpcodeVecV128Store16Lane, 100, 1, 7)},
2931 {name: OpcodeVecV128Store32LaneName, body: storeLane(OpcodeVecV128Store32Lane, 0, 0, 0)},
2932 {name: OpcodeVecV128Store32LaneName + "/lane=3/align=2", body: storeLane(OpcodeVecV128Store32Lane, 100, 2, 3)},
2933 {name: OpcodeVecV128Store64LaneName, body: storeLane(OpcodeVecV128Store64Lane, 0, 0, 0)},
2934 {name: OpcodeVecV128Store64LaneName + "/lane=1/align=3", body: storeLane(OpcodeVecV128Store64Lane, 50, 3, 1)},
2935 {name: OpcodeVecI8x16ExtractLaneSName, body: extractLane(OpcodeVecI8x16ExtractLaneS, 0)},
2936 {name: OpcodeVecI8x16ExtractLaneSName + "/lane=15", body: extractLane(OpcodeVecI8x16ExtractLaneS, 15)},
2937 {name: OpcodeVecI8x16ExtractLaneUName, body: extractLane(OpcodeVecI8x16ExtractLaneU, 0)},
2938 {name: OpcodeVecI8x16ExtractLaneUName + "/lane=15", body: extractLane(OpcodeVecI8x16ExtractLaneU, 15)},
2939 {name: OpcodeVecI16x8ExtractLaneSName, body: extractLane(OpcodeVecI16x8ExtractLaneS, 0)},
2940 {name: OpcodeVecI16x8ExtractLaneSName + "/lane=7", body: extractLane(OpcodeVecI16x8ExtractLaneS, 7)},
2941 {name: OpcodeVecI16x8ExtractLaneUName, body: extractLane(OpcodeVecI16x8ExtractLaneU, 0)},
2942 {name: OpcodeVecI16x8ExtractLaneUName + "/lane=8", body: extractLane(OpcodeVecI16x8ExtractLaneU, 7)},
2943 {name: OpcodeVecI32x4ExtractLaneName, body: extractLane(OpcodeVecI32x4ExtractLane, 0)},
2944 {name: OpcodeVecI32x4ExtractLaneName + "/lane=3", body: extractLane(OpcodeVecI32x4ExtractLane, 3)},
2945 {name: OpcodeVecI64x2ExtractLaneName, body: extractLane(OpcodeVecI64x2ExtractLane, 0)},
2946 {name: OpcodeVecI64x2ExtractLaneName + "/lane=1", body: extractLane(OpcodeVecI64x2ExtractLane, 1)},
2947 {name: OpcodeVecF32x4ExtractLaneName, body: extractLane(OpcodeVecF32x4ExtractLane, 0)},
2948 {name: OpcodeVecF32x4ExtractLaneName + "/lane=3", body: extractLane(OpcodeVecF32x4ExtractLane, 3)},
2949 {name: OpcodeVecF64x2ExtractLaneName, body: extractLane(OpcodeVecF64x2ExtractLane, 0)},
2950 {name: OpcodeVecF64x2ExtractLaneName + "/lane=1", body: extractLane(OpcodeVecF64x2ExtractLane, 1)},
2951 {name: OpcodeVecI8x16ReplaceLaneName, body: replaceLane(OpcodeVecI8x16ReplaceLane, 0)},
2952 {name: OpcodeVecI8x16ReplaceLaneName + "/lane=15", body: replaceLane(OpcodeVecI8x16ReplaceLane, 15)},
2953 {name: OpcodeVecI16x8ReplaceLaneName, body: replaceLane(OpcodeVecI16x8ReplaceLane, 0)},
2954 {name: OpcodeVecI16x8ReplaceLaneName + "/lane=7", body: replaceLane(OpcodeVecI16x8ReplaceLane, 7)},
2955 {name: OpcodeVecI32x4ReplaceLaneName, body: replaceLane(OpcodeVecI32x4ReplaceLane, 0)},
2956 {name: OpcodeVecI32x4ReplaceLaneName + "/lane=3", body: replaceLane(OpcodeVecI32x4ReplaceLane, 3)},
2957 {name: OpcodeVecI64x2ReplaceLaneName, body: replaceLane(OpcodeVecI64x2ReplaceLane, 0)},
2958 {name: OpcodeVecI64x2ReplaceLaneName + "/lane=1", body: replaceLane(OpcodeVecI64x2ReplaceLane, 1)},
2959 {name: OpcodeVecF32x4ReplaceLaneName, body: replaceLane(OpcodeVecF32x4ReplaceLane, 0)},
2960 {name: OpcodeVecF32x4ReplaceLaneName + "/lane=3", body: replaceLane(OpcodeVecF32x4ReplaceLane, 3)},
2961 {name: OpcodeVecF64x2ReplaceLaneName, body: replaceLane(OpcodeVecF64x2ReplaceLane, 0)},
2962 {name: OpcodeVecF64x2ReplaceLaneName + "/lane=1", body: replaceLane(OpcodeVecF64x2ReplaceLane, 1)},
2963 {name: OpcodeVecI8x16SplatName, body: splat(OpcodeVecI8x16Splat)},
2964 {name: OpcodeVecI16x8SplatName, body: splat(OpcodeVecI16x8Splat)},
2965 {name: OpcodeVecI32x4SplatName, body: splat(OpcodeVecI32x4Splat)},
2966 {name: OpcodeVecI64x2SplatName, body: splat(OpcodeVecI64x2Splat)},
2967 {name: OpcodeVecF32x4SplatName, body: splat(OpcodeVecF32x4Splat)},
2968 {name: OpcodeVecF64x2SplatName, body: splat(OpcodeVecF64x2Splat)},
2969 {name: OpcodeVecI8x16SwizzleName, body: vv2v(OpcodeVecI8x16Swizzle)},
2970 {
2971 name: OpcodeVecV128i8x16ShuffleName, body: []byte{
2972 OpcodeVecPrefix,
2973 OpcodeVecV128Const,
2974 1, 1, 1, 1, 1, 1, 1, 1,
2975 1, 1, 1, 1, 1, 1, 1, 1,
2976 OpcodeVecPrefix,
2977 OpcodeVecV128Const,
2978 1, 1, 1, 1, 1, 1, 1, 1,
2979 1, 1, 1, 1, 1, 1, 1, 1,
2980 OpcodeVecPrefix,
2981 OpcodeVecV128i8x16Shuffle,
2982 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
2983 OpcodeDrop,
2984 OpcodeEnd,
2985 },
2986 },
2987 {name: OpcodeVecV128NotName, body: v2v(OpcodeVecV128Not)},
2988 {name: OpcodeVecV128AndName, body: vv2v(OpcodeVecV128And)},
2989 {name: OpcodeVecV128AndNotName, body: vv2v(OpcodeVecV128AndNot)},
2990 {name: OpcodeVecV128OrName, body: vv2v(OpcodeVecV128Or)},
2991 {name: OpcodeVecV128XorName, body: vv2v(OpcodeVecV128Xor)},
2992 {name: OpcodeVecV128BitselectName, body: vvv2v(OpcodeVecV128Bitselect)},
2993 {name: OpcodeVecI8x16ShlName, body: vi2v(OpcodeVecI8x16Shl)},
2994 {name: OpcodeVecI8x16ShrSName, body: vi2v(OpcodeVecI8x16ShrS)},
2995 {name: OpcodeVecI8x16ShrUName, body: vi2v(OpcodeVecI8x16ShrU)},
2996 {name: OpcodeVecI16x8ShlName, body: vi2v(OpcodeVecI16x8Shl)},
2997 {name: OpcodeVecI16x8ShrSName, body: vi2v(OpcodeVecI16x8ShrS)},
2998 {name: OpcodeVecI16x8ShrUName, body: vi2v(OpcodeVecI16x8ShrU)},
2999 {name: OpcodeVecI32x4ShlName, body: vi2v(OpcodeVecI32x4Shl)},
3000 {name: OpcodeVecI32x4ShrSName, body: vi2v(OpcodeVecI32x4ShrS)},
3001 {name: OpcodeVecI32x4ShrUName, body: vi2v(OpcodeVecI32x4ShrU)},
3002 {name: OpcodeVecI64x2ShlName, body: vi2v(OpcodeVecI64x2Shl)},
3003 {name: OpcodeVecI64x2ShrSName, body: vi2v(OpcodeVecI64x2ShrS)},
3004 {name: OpcodeVecI64x2ShrUName, body: vi2v(OpcodeVecI64x2ShrU)},
3005 {name: OpcodeVecI8x16EqName, body: vv2v(OpcodeVecI8x16Eq)},
3006 {name: OpcodeVecI8x16NeName, body: vv2v(OpcodeVecI8x16Ne)},
3007 {name: OpcodeVecI8x16LtSName, body: vv2v(OpcodeVecI8x16LtS)},
3008 {name: OpcodeVecI8x16LtUName, body: vv2v(OpcodeVecI8x16LtU)},
3009 {name: OpcodeVecI8x16GtSName, body: vv2v(OpcodeVecI8x16GtS)},
3010 {name: OpcodeVecI8x16GtUName, body: vv2v(OpcodeVecI8x16GtU)},
3011 {name: OpcodeVecI8x16LeSName, body: vv2v(OpcodeVecI8x16LeS)},
3012 {name: OpcodeVecI8x16LeUName, body: vv2v(OpcodeVecI8x16LeU)},
3013 {name: OpcodeVecI8x16GeSName, body: vv2v(OpcodeVecI8x16GeS)},
3014 {name: OpcodeVecI8x16GeUName, body: vv2v(OpcodeVecI8x16GeU)},
3015 {name: OpcodeVecI16x8EqName, body: vv2v(OpcodeVecI16x8Eq)},
3016 {name: OpcodeVecI16x8NeName, body: vv2v(OpcodeVecI16x8Ne)},
3017 {name: OpcodeVecI16x8LtSName, body: vv2v(OpcodeVecI16x8LtS)},
3018 {name: OpcodeVecI16x8LtUName, body: vv2v(OpcodeVecI16x8LtU)},
3019 {name: OpcodeVecI16x8GtSName, body: vv2v(OpcodeVecI16x8GtS)},
3020 {name: OpcodeVecI16x8GtUName, body: vv2v(OpcodeVecI16x8GtU)},
3021 {name: OpcodeVecI16x8LeSName, body: vv2v(OpcodeVecI16x8LeS)},
3022 {name: OpcodeVecI16x8LeUName, body: vv2v(OpcodeVecI16x8LeU)},
3023 {name: OpcodeVecI16x8GeSName, body: vv2v(OpcodeVecI16x8GeS)},
3024 {name: OpcodeVecI16x8GeUName, body: vv2v(OpcodeVecI16x8GeU)},
3025 {name: OpcodeVecI32x4EqName, body: vv2v(OpcodeVecI32x4Eq)},
3026 {name: OpcodeVecI32x4NeName, body: vv2v(OpcodeVecI32x4Ne)},
3027 {name: OpcodeVecI32x4LtSName, body: vv2v(OpcodeVecI32x4LtS)},
3028 {name: OpcodeVecI32x4LtUName, body: vv2v(OpcodeVecI32x4LtU)},
3029 {name: OpcodeVecI32x4GtSName, body: vv2v(OpcodeVecI32x4GtS)},
3030 {name: OpcodeVecI32x4GtUName, body: vv2v(OpcodeVecI32x4GtU)},
3031 {name: OpcodeVecI32x4LeSName, body: vv2v(OpcodeVecI32x4LeS)},
3032 {name: OpcodeVecI32x4LeUName, body: vv2v(OpcodeVecI32x4LeU)},
3033 {name: OpcodeVecI32x4GeSName, body: vv2v(OpcodeVecI32x4GeS)},
3034 {name: OpcodeVecI32x4GeUName, body: vv2v(OpcodeVecI32x4GeU)},
3035 {name: OpcodeVecI64x2EqName, body: vv2v(OpcodeVecI64x2Eq)},
3036 {name: OpcodeVecI64x2NeName, body: vv2v(OpcodeVecI64x2Ne)},
3037 {name: OpcodeVecI64x2LtSName, body: vv2v(OpcodeVecI64x2LtS)},
3038 {name: OpcodeVecI64x2GtSName, body: vv2v(OpcodeVecI64x2GtS)},
3039 {name: OpcodeVecI64x2LeSName, body: vv2v(OpcodeVecI64x2LeS)},
3040 {name: OpcodeVecI64x2GeSName, body: vv2v(OpcodeVecI64x2GeS)},
3041 {name: OpcodeVecF32x4EqName, body: vv2v(OpcodeVecF32x4Eq)},
3042 {name: OpcodeVecF32x4NeName, body: vv2v(OpcodeVecF32x4Ne)},
3043 {name: OpcodeVecF32x4LtName, body: vv2v(OpcodeVecF32x4Lt)},
3044 {name: OpcodeVecF32x4GtName, body: vv2v(OpcodeVecF32x4Gt)},
3045 {name: OpcodeVecF32x4LeName, body: vv2v(OpcodeVecF32x4Le)},
3046 {name: OpcodeVecF32x4GeName, body: vv2v(OpcodeVecF32x4Ge)},
3047 {name: OpcodeVecF64x2EqName, body: vv2v(OpcodeVecF64x2Eq)},
3048 {name: OpcodeVecF64x2NeName, body: vv2v(OpcodeVecF64x2Ne)},
3049 {name: OpcodeVecF64x2LtName, body: vv2v(OpcodeVecF64x2Lt)},
3050 {name: OpcodeVecF64x2GtName, body: vv2v(OpcodeVecF64x2Gt)},
3051 {name: OpcodeVecF64x2LeName, body: vv2v(OpcodeVecF64x2Le)},
3052 {name: OpcodeVecF64x2GeName, body: vv2v(OpcodeVecF64x2Ge)},
3053 {name: OpcodeVecI8x16AddName, body: vv2v(OpcodeVecI8x16Add)},
3054 {name: OpcodeVecI8x16AddSatSName, body: vv2v(OpcodeVecI8x16AddSatS)},
3055 {name: OpcodeVecI8x16AddSatUName, body: vv2v(OpcodeVecI8x16AddSatU)},
3056 {name: OpcodeVecI8x16SubName, body: vv2v(OpcodeVecI8x16Sub)},
3057 {name: OpcodeVecI8x16SubSatSName, body: vv2v(OpcodeVecI8x16SubSatS)},
3058 {name: OpcodeVecI8x16SubSatUName, body: vv2v(OpcodeVecI8x16SubSatU)},
3059 {name: OpcodeVecI16x8AddName, body: vv2v(OpcodeVecI16x8Add)},
3060 {name: OpcodeVecI16x8AddSatSName, body: vv2v(OpcodeVecI16x8AddSatS)},
3061 {name: OpcodeVecI16x8AddSatUName, body: vv2v(OpcodeVecI16x8AddSatU)},
3062 {name: OpcodeVecI16x8SubName, body: vv2v(OpcodeVecI16x8Sub)},
3063 {name: OpcodeVecI16x8SubSatSName, body: vv2v(OpcodeVecI16x8SubSatS)},
3064 {name: OpcodeVecI16x8SubSatUName, body: vv2v(OpcodeVecI16x8SubSatU)},
3065 {name: OpcodeVecI16x8MulName, body: vv2v(OpcodeVecI16x8Mul)},
3066 {name: OpcodeVecI32x4AddName, body: vv2v(OpcodeVecI32x4Add)},
3067 {name: OpcodeVecI32x4SubName, body: vv2v(OpcodeVecI32x4Sub)},
3068 {name: OpcodeVecI32x4MulName, body: vv2v(OpcodeVecI32x4Mul)},
3069 {name: OpcodeVecI64x2AddName, body: vv2v(OpcodeVecI64x2Add)},
3070 {name: OpcodeVecI64x2SubName, body: vv2v(OpcodeVecI64x2Sub)},
3071 {name: OpcodeVecI64x2MulName, body: vv2v(OpcodeVecI64x2Mul)},
3072 {name: OpcodeVecF32x4AddName, body: vv2v(OpcodeVecF32x4Add)},
3073 {name: OpcodeVecF32x4SubName, body: vv2v(OpcodeVecF32x4Sub)},
3074 {name: OpcodeVecF32x4MulName, body: vv2v(OpcodeVecF32x4Mul)},
3075 {name: OpcodeVecF32x4DivName, body: vv2v(OpcodeVecF32x4Div)},
3076 {name: OpcodeVecF64x2AddName, body: vv2v(OpcodeVecF64x2Add)},
3077 {name: OpcodeVecF64x2SubName, body: vv2v(OpcodeVecF64x2Sub)},
3078 {name: OpcodeVecF64x2MulName, body: vv2v(OpcodeVecF64x2Mul)},
3079 {name: OpcodeVecF64x2DivName, body: vv2v(OpcodeVecF64x2Div)},
3080 {name: OpcodeVecI8x16NegName, body: v2v(OpcodeVecI8x16Neg)},
3081 {name: OpcodeVecI16x8NegName, body: v2v(OpcodeVecI16x8Neg)},
3082 {name: OpcodeVecI32x4NegName, body: v2v(OpcodeVecI32x4Neg)},
3083 {name: OpcodeVecI64x2NegName, body: v2v(OpcodeVecI64x2Neg)},
3084 {name: OpcodeVecF32x4NegName, body: v2v(OpcodeVecF32x4Neg)},
3085 {name: OpcodeVecF64x2NegName, body: v2v(OpcodeVecF64x2Neg)},
3086 {name: OpcodeVecF32x4SqrtName, body: v2v(OpcodeVecF32x4Sqrt)},
3087 {name: OpcodeVecF64x2SqrtName, body: v2v(OpcodeVecF64x2Sqrt)},
3088 {name: OpcodeVecI8x16MinSName, body: vv2v(OpcodeVecI8x16MinS)},
3089 {name: OpcodeVecI8x16MinUName, body: vv2v(OpcodeVecI8x16MinU)},
3090 {name: OpcodeVecI8x16MaxSName, body: vv2v(OpcodeVecI8x16MaxS)},
3091 {name: OpcodeVecI8x16MaxUName, body: vv2v(OpcodeVecI8x16MaxU)},
3092 {name: OpcodeVecI8x16AvgrUName, body: vv2v(OpcodeVecI8x16AvgrU)},
3093 {name: OpcodeVecI8x16AbsName, body: v2v(OpcodeVecI8x16Abs)},
3094 {name: OpcodeVecI8x16PopcntName, body: v2v(OpcodeVecI8x16Popcnt)},
3095 {name: OpcodeVecI16x8MinSName, body: vv2v(OpcodeVecI16x8MinS)},
3096 {name: OpcodeVecI16x8MinUName, body: vv2v(OpcodeVecI16x8MinU)},
3097 {name: OpcodeVecI16x8MaxSName, body: vv2v(OpcodeVecI16x8MaxS)},
3098 {name: OpcodeVecI16x8MaxUName, body: vv2v(OpcodeVecI16x8MaxU)},
3099 {name: OpcodeVecI16x8AvgrUName, body: vv2v(OpcodeVecI16x8AvgrU)},
3100 {name: OpcodeVecI16x8AbsName, body: v2v(OpcodeVecI16x8Abs)},
3101 {name: OpcodeVecI32x4MinSName, body: vv2v(OpcodeVecI32x4MinS)},
3102 {name: OpcodeVecI32x4MinUName, body: vv2v(OpcodeVecI32x4MinU)},
3103 {name: OpcodeVecI32x4MaxSName, body: vv2v(OpcodeVecI32x4MaxS)},
3104 {name: OpcodeVecI32x4MaxUName, body: vv2v(OpcodeVecI32x4MaxU)},
3105 {name: OpcodeVecI32x4AbsName, body: v2v(OpcodeVecI32x4Abs)},
3106 {name: OpcodeVecI64x2AbsName, body: v2v(OpcodeVecI64x2Abs)},
3107 {name: OpcodeVecF32x4AbsName, body: v2v(OpcodeVecF32x4Abs)},
3108 {name: OpcodeVecF64x2AbsName, body: v2v(OpcodeVecF64x2Abs)},
3109 {name: OpcodeVecF32x4MinName, body: vv2v(OpcodeVecF32x4Min)},
3110 {name: OpcodeVecF32x4MaxName, body: vv2v(OpcodeVecF32x4Max)},
3111 {name: OpcodeVecF64x2MinName, body: vv2v(OpcodeVecF64x2Min)},
3112 {name: OpcodeVecF64x2MaxName, body: vv2v(OpcodeVecF64x2Max)},
3113 {name: OpcodeVecF32x4CeilName, body: v2v(OpcodeVecF32x4Ceil)},
3114 {name: OpcodeVecF32x4FloorName, body: v2v(OpcodeVecF32x4Floor)},
3115 {name: OpcodeVecF32x4TruncName, body: v2v(OpcodeVecF32x4Trunc)},
3116 {name: OpcodeVecF32x4NearestName, body: v2v(OpcodeVecF32x4Nearest)},
3117 {name: OpcodeVecF64x2CeilName, body: v2v(OpcodeVecF64x2Ceil)},
3118 {name: OpcodeVecF64x2FloorName, body: v2v(OpcodeVecF64x2Floor)},
3119 {name: OpcodeVecF64x2TruncName, body: v2v(OpcodeVecF64x2Trunc)},
3120 {name: OpcodeVecF64x2NearestName, body: v2v(OpcodeVecF64x2Nearest)},
3121 {name: OpcodeVecF32x4MinName, body: vv2v(OpcodeVecF32x4Pmin)},
3122 {name: OpcodeVecF32x4MaxName, body: vv2v(OpcodeVecF32x4Pmax)},
3123 {name: OpcodeVecF64x2MinName, body: vv2v(OpcodeVecF64x2Pmin)},
3124 {name: OpcodeVecF64x2MaxName, body: vv2v(OpcodeVecF64x2Pmax)},
3125 {name: OpcodeVecI16x8ExtendLowI8x16SName, body: v2v(OpcodeVecI16x8ExtendLowI8x16S)},
3126 {name: OpcodeVecI16x8ExtendHighI8x16SName, body: v2v(OpcodeVecI16x8ExtendHighI8x16S)},
3127 {name: OpcodeVecI16x8ExtendLowI8x16UName, body: v2v(OpcodeVecI16x8ExtendLowI8x16U)},
3128 {name: OpcodeVecI16x8ExtendHighI8x16UName, body: v2v(OpcodeVecI16x8ExtendHighI8x16U)},
3129 {name: OpcodeVecI32x4ExtendLowI16x8SName, body: v2v(OpcodeVecI32x4ExtendLowI16x8S)},
3130 {name: OpcodeVecI32x4ExtendHighI16x8SName, body: v2v(OpcodeVecI32x4ExtendHighI16x8S)},
3131 {name: OpcodeVecI32x4ExtendLowI16x8UName, body: v2v(OpcodeVecI32x4ExtendLowI16x8U)},
3132 {name: OpcodeVecI32x4ExtendHighI16x8UName, body: v2v(OpcodeVecI32x4ExtendHighI16x8U)},
3133 {name: OpcodeVecI64x2ExtendLowI32x4SName, body: v2v(OpcodeVecI64x2ExtendLowI32x4S)},
3134 {name: OpcodeVecI64x2ExtendHighI32x4SName, body: v2v(OpcodeVecI64x2ExtendHighI32x4S)},
3135 {name: OpcodeVecI64x2ExtendLowI32x4UName, body: v2v(OpcodeVecI64x2ExtendLowI32x4U)},
3136 {name: OpcodeVecI64x2ExtendHighI32x4UName, body: v2v(OpcodeVecI64x2ExtendHighI32x4U)},
3137 {name: OpcodeVecI16x8Q15mulrSatSName, body: vv2v(OpcodeVecI16x8Q15mulrSatS)},
3138 {name: OpcodeVecI16x8ExtMulLowI8x16SName, body: vv2v(OpcodeVecI16x8ExtMulLowI8x16S)},
3139 {name: OpcodeVecI16x8ExtMulHighI8x16SName, body: vv2v(OpcodeVecI16x8ExtMulHighI8x16S)},
3140 {name: OpcodeVecI16x8ExtMulLowI8x16UName, body: vv2v(OpcodeVecI16x8ExtMulLowI8x16U)},
3141 {name: OpcodeVecI16x8ExtMulHighI8x16UName, body: vv2v(OpcodeVecI16x8ExtMulHighI8x16U)},
3142 {name: OpcodeVecI32x4ExtMulLowI16x8SName, body: vv2v(OpcodeVecI32x4ExtMulLowI16x8S)},
3143 {name: OpcodeVecI32x4ExtMulHighI16x8SName, body: vv2v(OpcodeVecI32x4ExtMulHighI16x8S)},
3144 {name: OpcodeVecI32x4ExtMulLowI16x8UName, body: vv2v(OpcodeVecI32x4ExtMulLowI16x8U)},
3145 {name: OpcodeVecI32x4ExtMulHighI16x8UName, body: vv2v(OpcodeVecI32x4ExtMulHighI16x8U)},
3146 {name: OpcodeVecI64x2ExtMulLowI32x4SName, body: vv2v(OpcodeVecI64x2ExtMulLowI32x4S)},
3147 {name: OpcodeVecI64x2ExtMulHighI32x4SName, body: vv2v(OpcodeVecI64x2ExtMulHighI32x4S)},
3148 {name: OpcodeVecI64x2ExtMulLowI32x4UName, body: vv2v(OpcodeVecI64x2ExtMulLowI32x4U)},
3149 {name: OpcodeVecI64x2ExtMulHighI32x4UName, body: vv2v(OpcodeVecI64x2ExtMulHighI32x4U)},
3150 {name: OpcodeVecI16x8ExtaddPairwiseI8x16SName, body: v2v(OpcodeVecI16x8ExtaddPairwiseI8x16S)},
3151 {name: OpcodeVecI16x8ExtaddPairwiseI8x16UName, body: v2v(OpcodeVecI16x8ExtaddPairwiseI8x16U)},
3152 {name: OpcodeVecI32x4ExtaddPairwiseI16x8SName, body: v2v(OpcodeVecI32x4ExtaddPairwiseI16x8S)},
3153 {name: OpcodeVecI32x4ExtaddPairwiseI16x8UName, body: v2v(OpcodeVecI32x4ExtaddPairwiseI16x8U)},
3154 {name: OpcodeVecF64x2PromoteLowF32x4ZeroName, body: v2v(OpcodeVecF64x2PromoteLowF32x4Zero)},
3155 {name: OpcodeVecF32x4DemoteF64x2ZeroName, body: v2v(OpcodeVecF32x4DemoteF64x2Zero)},
3156 {name: OpcodeVecF32x4ConvertI32x4SName, body: v2v(OpcodeVecF32x4ConvertI32x4S)},
3157 {name: OpcodeVecF32x4ConvertI32x4UName, body: v2v(OpcodeVecF32x4ConvertI32x4U)},
3158 {name: OpcodeVecF64x2ConvertLowI32x4SName, body: v2v(OpcodeVecF64x2ConvertLowI32x4S)},
3159 {name: OpcodeVecF64x2ConvertLowI32x4UName, body: v2v(OpcodeVecF64x2ConvertLowI32x4U)},
3160 {name: OpcodeVecI32x4DotI16x8SName, body: vv2v(OpcodeVecI32x4DotI16x8S)},
3161 {name: OpcodeVecI8x16NarrowI16x8SName, body: vv2v(OpcodeVecI8x16NarrowI16x8S)},
3162 {name: OpcodeVecI8x16NarrowI16x8UName, body: vv2v(OpcodeVecI8x16NarrowI16x8U)},
3163 {name: OpcodeVecI16x8NarrowI32x4SName, body: vv2v(OpcodeVecI16x8NarrowI32x4S)},
3164 {name: OpcodeVecI16x8NarrowI32x4UName, body: vv2v(OpcodeVecI16x8NarrowI32x4U)},
3165 {name: OpcodeVecI32x4TruncSatF32x4SName, body: v2v(OpcodeVecI32x4TruncSatF32x4S)},
3166 {name: OpcodeVecI32x4TruncSatF32x4UName, body: v2v(OpcodeVecI32x4TruncSatF32x4U)},
3167 {name: OpcodeVecI32x4TruncSatF64x2SZeroName, body: v2v(OpcodeVecI32x4TruncSatF64x2SZero)},
3168 {name: OpcodeVecI32x4TruncSatF64x2UZeroName, body: v2v(OpcodeVecI32x4TruncSatF64x2UZero)},
3169 }
3170
3171 for _, tt := range tests {
3172 tc := tt
3173 t.Run(tc.name, func(t *testing.T) {
3174 m := &Module{
3175 TypeSection: []FunctionType{v_v},
3176 FunctionSection: []Index{0},
3177 CodeSection: []Code{{Body: tc.body}},
3178 }
3179 err := m.validateFunction(&stacks{}, api.CoreFeatureSIMD,
3180 0, []Index{0}, nil, &Memory{}, nil, nil, bytes.NewReader(nil))
3181 require.NoError(t, err)
3182 })
3183 }
3184 }
3185
3186 func TestModule_funcValidation_SIMD_error(t *testing.T) {
3187 type testCase struct {
3188 name string
3189 body []byte
3190 flag api.CoreFeatures
3191 expectedErr string
3192 }
3193
3194 tests := []testCase{
3195 {
3196 name: "simd disabled",
3197 body: []byte{
3198 OpcodeVecPrefix,
3199 OpcodeVecF32x4Abs,
3200 },
3201 flag: api.CoreFeaturesV1,
3202 expectedErr: "f32x4.abs invalid as feature \"simd\" is disabled",
3203 },
3204 {
3205 name: "v128.const immediate",
3206 body: []byte{
3207 OpcodeVecPrefix,
3208 OpcodeVecV128Const,
3209 1, 1, 1, 1, 1, 1, 1, 1,
3210 1, 1, 1, 1, 1, 1, 1,
3211 },
3212 flag: api.CoreFeatureSIMD,
3213 expectedErr: "cannot read constant vector value for v128.const",
3214 },
3215 {
3216 name: "i32x4.add operand",
3217 body: []byte{
3218 OpcodeVecPrefix,
3219 OpcodeVecV128Const,
3220 1, 1, 1, 1, 1, 1, 1, 1,
3221 1, 1, 1, 1, 1, 1, 1, 1,
3222 OpcodeVecPrefix,
3223 OpcodeVecI32x4Add,
3224 OpcodeDrop,
3225 OpcodeEnd,
3226 },
3227 flag: api.CoreFeatureSIMD,
3228 expectedErr: "cannot pop the operand for i32x4.add: v128 missing",
3229 },
3230 {
3231 name: "i64x2.add operand",
3232 body: []byte{
3233 OpcodeVecPrefix,
3234 OpcodeVecV128Const,
3235 1, 1, 1, 1, 1, 1, 1, 1,
3236 1, 1, 1, 1, 1, 1, 1, 1,
3237 OpcodeVecPrefix,
3238 OpcodeVecI64x2Add,
3239 OpcodeDrop,
3240 OpcodeEnd,
3241 },
3242 flag: api.CoreFeatureSIMD,
3243 expectedErr: "cannot pop the operand for i64x2.add: v128 missing",
3244 },
3245 {
3246 name: "shuffle lane index not found",
3247 flag: api.CoreFeatureSIMD,
3248 body: []byte{
3249 OpcodeVecPrefix,
3250 OpcodeVecV128i8x16Shuffle,
3251 },
3252 expectedErr: "16 lane indexes for v128.shuffle not found",
3253 },
3254 {
3255 name: "shuffle lane index not found",
3256 flag: api.CoreFeatureSIMD,
3257 body: []byte{
3258 OpcodeVecPrefix,
3259 OpcodeVecV128i8x16Shuffle,
3260 0xff, 0, 0, 0, 0, 0, 0, 0,
3261 0, 0, 0, 0, 0, 0, 0, 0,
3262 },
3263 expectedErr: "invalid lane index[0] 255 >= 32 for v128.shuffle",
3264 },
3265 }
3266
3267 addExtractOrReplaceLaneOutOfIndexCase := func(op OpcodeVec, lane, laneCeil byte) {
3268 n := VectorInstructionName(op)
3269 tests = append(tests, testCase{
3270 name: n + "/lane index out of range",
3271 flag: api.CoreFeatureSIMD,
3272 body: []byte{
3273 OpcodeVecPrefix, op, lane,
3274 },
3275 expectedErr: fmt.Sprintf("invalid lane index %d >= %d for %s", lane, laneCeil, n),
3276 })
3277 }
3278
3279 addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI8x16ExtractLaneS, 16, 16)
3280 addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI8x16ExtractLaneU, 20, 16)
3281 addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI16x8ExtractLaneS, 8, 8)
3282 addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI16x8ExtractLaneU, 8, 8)
3283 addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI32x4ExtractLane, 4, 4)
3284 addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecF32x4ExtractLane, 4, 4)
3285 addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI64x2ExtractLane, 2, 2)
3286 addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecF64x2ExtractLane, 2, 2)
3287 addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI8x16ReplaceLane, 16, 16)
3288 addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI16x8ReplaceLane, 8, 8)
3289 addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI32x4ReplaceLane, 4, 4)
3290 addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI64x2ReplaceLane, 2, 2)
3291 addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecF32x4ReplaceLane, 10, 4)
3292 addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecF64x2ReplaceLane, 3, 2)
3293
3294 addStoreOrLoadLaneOutOfIndexCase := func(op OpcodeVec, lane, laneCeil byte) {
3295 n := VectorInstructionName(op)
3296 tests = append(tests, testCase{
3297 name: n + "/lane index out of range",
3298 flag: api.CoreFeatureSIMD,
3299 body: []byte{
3300 OpcodeVecPrefix, op,
3301 0, 0,
3302 lane,
3303 },
3304 expectedErr: fmt.Sprintf("invalid lane index %d >= %d for %s", lane, laneCeil, n),
3305 })
3306 }
3307
3308 addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Load8Lane, 16, 16)
3309 addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Load16Lane, 8, 8)
3310 addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Load32Lane, 4, 4)
3311 addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Load64Lane, 2, 2)
3312 addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Store8Lane, 16, 16)
3313 addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Store16Lane, 8, 8)
3314 addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Store32Lane, 4, 4)
3315 addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Store64Lane, 2, 2)
3316
3317 for _, tt := range tests {
3318 tc := tt
3319 t.Run(tc.name, func(t *testing.T) {
3320 m := &Module{
3321 TypeSection: []FunctionType{v_v},
3322 FunctionSection: []Index{0},
3323 CodeSection: []Code{{Body: tc.body}},
3324 }
3325 err := m.validateFunction(&stacks{}, tc.flag,
3326 0, []Index{0}, nil, &Memory{}, nil, nil, bytes.NewReader(nil))
3327 require.EqualError(t, err, tc.expectedErr)
3328 })
3329 }
3330 }
3331
3332 func TestDecodeBlockType(t *testing.T) {
3333 t.Run("primitive", func(t *testing.T) {
3334 for _, tc := range []struct {
3335 name string
3336 in byte
3337 exp ValueType
3338 expResultNumInUint64 int
3339 }{
3340 {name: "nil", in: 0x40},
3341 {name: "i32", in: 0x7f, exp: ValueTypeI32, expResultNumInUint64: 1},
3342 {name: "i64", in: 0x7e, exp: ValueTypeI64, expResultNumInUint64: 1},
3343 {name: "f32", in: 0x7d, exp: ValueTypeF32, expResultNumInUint64: 1},
3344 {name: "f64", in: 0x7c, exp: ValueTypeF64, expResultNumInUint64: 1},
3345 {name: "v128", in: 0x7b, exp: ValueTypeV128, expResultNumInUint64: 2},
3346 {name: "funcref", in: 0x70, exp: ValueTypeFuncref, expResultNumInUint64: 1},
3347 {name: "externref", in: 0x6f, exp: ValueTypeExternref, expResultNumInUint64: 1},
3348 } {
3349 tc := tc
3350 t.Run(tc.name, func(t *testing.T) {
3351 actual, read, err := DecodeBlockType(nil, bytes.NewReader([]byte{tc.in}), api.CoreFeaturesV2)
3352 require.NoError(t, err)
3353 require.Equal(t, uint64(1), read)
3354 require.Equal(t, 0, len(actual.Params))
3355 require.Equal(t, tc.expResultNumInUint64, actual.ResultNumInUint64)
3356 require.Equal(t, 0, actual.ParamNumInUint64)
3357 if tc.exp == 0 {
3358 require.Equal(t, 0, len(actual.Results))
3359 } else {
3360 require.Equal(t, 1, len(actual.Results))
3361 require.Equal(t, tc.exp, actual.Results[0])
3362 }
3363 })
3364 }
3365 })
3366 t.Run("function type", func(t *testing.T) {
3367 types := []FunctionType{
3368 {},
3369 {Params: []ValueType{ValueTypeI32}},
3370 {Results: []ValueType{ValueTypeI32}},
3371 {Params: []ValueType{ValueTypeF32, ValueTypeV128}, Results: []ValueType{ValueTypeI32}},
3372 {Params: []ValueType{ValueTypeF32, ValueTypeV128}, Results: []ValueType{ValueTypeI32, ValueTypeF32, ValueTypeV128}},
3373 }
3374 for index := range types {
3375 expected := &types[index]
3376 actual, read, err := DecodeBlockType(types, bytes.NewReader([]byte{byte(index)}), api.CoreFeatureMultiValue)
3377 require.NoError(t, err)
3378 require.Equal(t, uint64(1), read)
3379 require.Equal(t, expected, actual)
3380 }
3381 })
3382 }
3383
3384
3385
3386
3387 func TestFuncValidation_UnreachableBrTable_NotModifyTypes(t *testing.T) {
3388 funcType := FunctionType{Results: []ValueType{i32, i64}, Params: []ValueType{i32}}
3389 copiedFuncType := FunctionType{
3390 Params: make([]ValueType, len(funcType.Params)),
3391 Results: make([]ValueType, len(funcType.Results)),
3392 }
3393
3394 copy(copiedFuncType.Results, funcType.Results)
3395 copy(copiedFuncType.Params, funcType.Params)
3396
3397 for _, tc := range []struct {
3398 name string
3399 m *Module
3400 }{
3401 {
3402 name: "on function return",
3403 m: &Module{
3404 TypeSection: []FunctionType{funcType},
3405 FunctionSection: []Index{0},
3406 CodeSection: []Code{
3407 {Body: []byte{
3408 OpcodeUnreachable,
3409
3410 OpcodeI32Const, 1,
3411
3412
3413 OpcodeBrTable, 2, 0, 0, 0,
3414 OpcodeEnd,
3415 }},
3416 },
3417 },
3418 },
3419 {
3420 name: "on loop return",
3421 m: &Module{
3422 TypeSection: []FunctionType{funcType},
3423 FunctionSection: []Index{0},
3424 CodeSection: []Code{
3425 {Body: []byte{
3426 OpcodeUnreachable,
3427 OpcodeLoop, 0,
3428 OpcodeUnreachable,
3429
3430 OpcodeI32Const, 1,
3431
3432
3433 OpcodeBrTable, 2, 0, 0, 0,
3434 OpcodeEnd,
3435 OpcodeEnd,
3436 }},
3437 },
3438 },
3439 },
3440 } {
3441 tc := tc
3442 t.Run(tc.name, func(t *testing.T) {
3443 err := tc.m.validateFunction(&stacks{}, api.CoreFeaturesV2,
3444 0, nil, nil, nil, nil, nil, bytes.NewReader(nil))
3445 require.NoError(t, err)
3446
3447
3448 require.Equal(t, copiedFuncType, funcType)
3449 })
3450 }
3451 }
3452
3453 func TestModule_funcValidation_loopWithParams(t *testing.T) {
3454 tests := []struct {
3455 name string
3456 body []byte
3457 expErr string
3458 }{
3459 {
3460 name: "br",
3461 body: []byte{
3462 OpcodeI32Const, 1,
3463 OpcodeLoop, 1,
3464 OpcodeBr, 0,
3465 OpcodeEnd,
3466 OpcodeUnreachable,
3467 OpcodeEnd,
3468 },
3469 },
3470 {
3471 name: "br_if",
3472 body: []byte{
3473 OpcodeI32Const, 1,
3474 OpcodeLoop, 1,
3475 OpcodeI32Const, 1,
3476 OpcodeBrIf, 0,
3477 OpcodeUnreachable,
3478 OpcodeEnd,
3479 OpcodeUnreachable,
3480 OpcodeEnd,
3481 },
3482 },
3483 {
3484 name: "br_table",
3485 body: []byte{
3486 OpcodeI32Const, 1,
3487 OpcodeLoop, 1,
3488 OpcodeI32Const, 4,
3489 OpcodeBrTable, 2, 0, 0, 0, 0,
3490 OpcodeEnd,
3491 OpcodeUnreachable,
3492 OpcodeEnd,
3493 },
3494 },
3495 {
3496 name: "br_table - nested",
3497 body: []byte{
3498 OpcodeI32Const, 1,
3499 OpcodeLoop, 1,
3500 OpcodeLoop, 1,
3501 OpcodeI32Const, 4,
3502 OpcodeBrTable, 2, 0, 1, 0,
3503 OpcodeEnd,
3504 OpcodeEnd,
3505 OpcodeUnreachable,
3506 OpcodeEnd,
3507 },
3508 },
3509 {
3510 name: "br / mismatch",
3511 body: []byte{
3512 OpcodeI32Const, 1,
3513 OpcodeLoop, 1,
3514 OpcodeDrop,
3515 OpcodeBr, 0,
3516 OpcodeEnd,
3517 OpcodeUnreachable,
3518 OpcodeEnd,
3519 },
3520 expErr: `not enough results in br block
3521 have ()
3522 want (i32)`,
3523 },
3524 {
3525 name: "br_if / mismatch",
3526 body: []byte{
3527 OpcodeI32Const, 1,
3528 OpcodeLoop, 1,
3529
3530 OpcodeBrIf, 0,
3531 OpcodeUnreachable,
3532 OpcodeEnd,
3533 OpcodeUnreachable,
3534 OpcodeEnd,
3535 },
3536 expErr: `not enough results in br_if block
3537 have ()
3538 want (i32)`,
3539 },
3540 {
3541 name: "br_table",
3542 body: []byte{
3543 OpcodeI32Const, 1,
3544 OpcodeLoop, 1,
3545
3546 OpcodeBrTable, 2, 0, 0, 0,
3547 OpcodeEnd,
3548 OpcodeUnreachable,
3549 OpcodeEnd,
3550 },
3551 expErr: `not enough results in br_table block
3552 have ()
3553 want (i32)`,
3554 },
3555 }
3556
3557 for _, tt := range tests {
3558 tc := tt
3559 t.Run(tc.name, func(t *testing.T) {
3560 m := &Module{
3561 TypeSection: []FunctionType{
3562 v_i32,
3563 i32_v,
3564 },
3565 FunctionSection: []Index{0},
3566 CodeSection: []Code{{Body: tc.body}},
3567 }
3568 err := m.validateFunction(&stacks{}, api.CoreFeatureMultiValue,
3569 0, []Index{0}, nil, nil, nil, nil, bytes.NewReader(nil))
3570 if tc.expErr != "" {
3571 require.EqualError(t, err, tc.expErr)
3572 } else {
3573 require.NoError(t, err)
3574 }
3575 })
3576 }
3577 }
3578
3579
3580 func TestFunctionValidation_redundantEnd(t *testing.T) {
3581 m := &Module{
3582 TypeSection: []FunctionType{{}},
3583 FunctionSection: []Index{0},
3584 CodeSection: []Code{{Body: []byte{OpcodeEnd, OpcodeEnd}}},
3585 }
3586 err := m.validateFunction(&stacks{}, api.CoreFeaturesV2,
3587 0, nil, nil, nil, nil, nil, bytes.NewReader(nil))
3588 require.EqualError(t, err, "redundant End instruction at 0x1")
3589 }
3590
3591
3592 func TestFunctionValidation_redundantElse(t *testing.T) {
3593 m := &Module{
3594 TypeSection: []FunctionType{{}},
3595 FunctionSection: []Index{0},
3596 CodeSection: []Code{{Body: []byte{OpcodeEnd, OpcodeElse}}},
3597 }
3598 err := m.validateFunction(&stacks{}, api.CoreFeaturesV2,
3599 0, nil, nil, nil, nil, nil, bytes.NewReader(nil))
3600 require.EqualError(t, err, "redundant Else instruction at 0x1")
3601 }
3602
3603 func Test_SplitCallStack(t *testing.T) {
3604 oneToEight := []uint64{1, 2, 3, 4, 5, 6, 7, 8}
3605
3606 tests := []struct {
3607 name string
3608 ft *FunctionType
3609 stack, expectedParams, expectedResults []uint64
3610 expectedErr string
3611 }{
3612 {
3613 name: "v_v",
3614 ft: &v_v,
3615 stack: oneToEight,
3616 expectedParams: nil,
3617 expectedResults: nil,
3618 },
3619 {
3620 name: "v_v - stack nil",
3621 ft: &v_v,
3622 expectedParams: nil,
3623 expectedResults: nil,
3624 },
3625 {
3626 name: "v_i32",
3627 ft: &v_i32,
3628 stack: oneToEight,
3629 expectedParams: nil,
3630 expectedResults: []uint64{1},
3631 },
3632 {
3633 name: "f32i32_v",
3634 ft: &f32i32_v,
3635 stack: oneToEight,
3636 expectedParams: []uint64{1, 2},
3637 expectedResults: nil,
3638 },
3639 {
3640 name: "f64f32_i64",
3641 ft: &f64f32_i64,
3642 stack: oneToEight,
3643 expectedParams: []uint64{1, 2},
3644 expectedResults: []uint64{1},
3645 },
3646 {
3647 name: "f64i32_v128i64",
3648 ft: &f64i32_v128i64,
3649 stack: oneToEight,
3650 expectedParams: []uint64{1, 2},
3651 expectedResults: []uint64{1, 2, 3},
3652 },
3653 {
3654 name: "not enough room for params",
3655 ft: &f64i32_v128i64,
3656 stack: oneToEight[0:1],
3657 expectedErr: "need 2 params, but stack size is 1",
3658 },
3659 {
3660 name: "not enough room for results",
3661 ft: &f64i32_v128i64,
3662 stack: oneToEight[0:2],
3663 expectedErr: "need 3 results, but stack size is 2",
3664 },
3665 }
3666
3667 for _, tt := range tests {
3668 tc := tt
3669
3670 t.Run(tc.name, func(t *testing.T) {
3671 params, results, err := SplitCallStack(tc.ft, tc.stack)
3672 if tc.expectedErr != "" {
3673 require.EqualError(t, err, tc.expectedErr)
3674 } else {
3675 require.Equal(t, tc.expectedParams, params)
3676 require.Equal(t, tc.expectedResults, results)
3677 }
3678 })
3679 }
3680 }
3681
View as plain text