github.com/bananabytelabs/wazero@v0.0.0-20240105073314-54b22a776da8/internal/wasm/func_validation_test.go (about) 1 package wasm 2 3 import ( 4 "bytes" 5 "fmt" 6 "testing" 7 8 "github.com/bananabytelabs/wazero/api" 9 "github.com/bananabytelabs/wazero/internal/leb128" 10 "github.com/bananabytelabs/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 // Compile a function which has max+1 const instructions. 18 var body []byte 19 for i := 0; i < valuesNum; i++ { 20 body = append(body, OpcodeI32Const, 1) 21 } 22 23 // Drop all the consts so that if the max is higher, this function body would be sound. 24 for i := 0; i < valuesNum; i++ { 25 body = append(body, OpcodeDrop) 26 } 27 28 // Plus all functions must end with End opcode. 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 // TestModule_ValidateFunction_MultiValue only tests what can't yet be detected during compilation. These examples are 191 // from test/core/if.wast from the commit that added "multi-value" support. 192 // 193 // See https://github.com/WebAssembly/spec/commit/484180ba3d9d7638ba1cb400b699ffede796927c 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, // (block (result f64 f64) 207 OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0x10, 0x40, // (f64.const 4) 208 OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0x14, 0x40, // (f64.const 5) 209 OpcodeBr, 0, 210 OpcodeF64Add, 211 OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0x18, 0x40, // (f64.const 6) 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", // a.k.a. "param" 220 module: &Module{ 221 TypeSection: []FunctionType{i32_i32}, // (func (param i32) (result i32) 222 FunctionSection: []Index{0}, 223 CodeSection: []Code{{Body: []byte{ 224 OpcodeI32Const, 1, // (i32.const 1) 225 OpcodeLocalGet, 0, OpcodeIf, 0, // (if (param i32) (result i32) (local.get 0) 226 OpcodeI32Const, 2, OpcodeI32Add, // (then (i32.const 2) (i32.add)) 227 OpcodeElse, OpcodeI32Const, 0x7e, OpcodeI32Add, // (else (i32.const -2) (i32.add)) 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", // a.k.a. "params-break" 236 module: &Module{ 237 TypeSection: []FunctionType{ 238 i32_i32, // (func (param i32) (result i32) 239 i32i32_i32, // (if (param i32 i32) (result i32) 240 }, 241 FunctionSection: []Index{0}, 242 CodeSection: []Code{{Body: []byte{ 243 OpcodeI32Const, 1, // (i32.const 1) 244 OpcodeI32Const, 2, // (i32.const 2) 245 OpcodeLocalGet, 0, OpcodeIf, 1, // (if (param i32) (result i32) (local.get 0) 246 OpcodeI32Add, OpcodeBr, 0, // (then (i32.add) (br 0)) 247 OpcodeElse, OpcodeI32Sub, OpcodeBr, 0, // (else (i32.sub) (br 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 // memory.init 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 /* data section out of range */}, 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 // data.drop 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 /* data section out of range */}, 407 flag: api.CoreFeatureBulkMemoryOperations, 408 memory: &Memory{}, 409 dataSection: []DataSegment{{}}, 410 expectedErr: "index 100 out of range of data section(len=1)", 411 }, 412 // memory.copy 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 // memory.fill 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 // table.init 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 /* data section out of range */}, 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 // elem.drop 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 /* element section out of range */}, 586 flag: api.CoreFeatureBulkMemoryOperations, 587 tables: []Table{{}}, 588 elementSection: []ElementSegment{{}}, 589 expectedErr: "index 100 out of range of element section(len=1)", 590 }, 591 // table.copy 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, // Multiple tables require api.CoreFeatureReferenceTypes. 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 // TestModule_ValidateFunction_MultiValue_TypeMismatch are "type mismatch" tests when "multi-value" was merged. 702 // 703 // See https://github.com/WebAssembly/spec/commit/484180ba3d9d7638ba1cb400b699ffede796927c 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 // test/core/func.wast 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, // (f32.const 0) 753 OpcodeEnd, // func 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, // (f32.const 0) (f32.const 0) 767 OpcodeEnd, // func 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}}}, // (return (nop)) 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, // (return (i64.const 0)) 803 OpcodeEnd, // func 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 // This should err because (return) precedes the values expected in the signature (i32i32): 813 // (module (func $type-return-empty-vs-nums (result i32 i32) 814 // (return) (i32.const 1) (i32.const 2) 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, // func 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 // This should err because (return) precedes one of the values expected in the signature (i32i32): 831 // (module (func $type-return-partial-vs-nums (result i32 i32) 832 // (i32.const 1) (return) (i32.const 2) 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, // func 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 // This should err because (return) is empty due to nop, but the signature requires i32i32: 849 // (module (func $type-return-void-vs-nums (result i32 i32) 850 // (return (nop)) (i32.const 1) 851 // )) 852 module: &Module{ 853 TypeSection: []FunctionType{v_i32i32}, 854 FunctionSection: []Index{0}, 855 CodeSection: []Code{{Body: []byte{ 856 OpcodeNop, OpcodeReturn, // (return (nop)) 857 OpcodeI32Const, 1, // (i32.const 1) 858 OpcodeEnd, // func 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, // (return (i64.const 1)) 873 OpcodeI32Const, 1, OpcodeI32Const, 2, // (i32.const 1) (i32.const 2) 874 OpcodeEnd, // func 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 // This should err because the return block doesn't return enough values. 884 // (module (func $type-return-first-num-vs-nums (result i32 i32) 885 // (return (i32.const 1)) (return (i32.const 1) (i32.const 2)) 886 // )) 887 module: &Module{ 888 TypeSection: []FunctionType{v_i32i32}, 889 FunctionSection: []Index{0}, 890 CodeSection: []Code{{Body: []byte{ 891 OpcodeI64Const, 1, OpcodeReturn, // (return (i64.const 1)) 892 OpcodeI32Const, 1, OpcodeI32Const, 2, OpcodeReturn, // (return (i32.const 1) (i32.const 2)) 893 OpcodeEnd, // func 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, // (br 0 (i32.const 0)) 907 OpcodeEnd, // func 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 // This should err because (br 0) returns no values, but its enclosing function requires two: 917 // (module (func $type-break-void-vs-nums (result i32 i32) 918 // (br 0) (i32.const 1) (i32.const 2) 919 // )) 920 module: &Module{ 921 TypeSection: []FunctionType{v_i32i32}, 922 FunctionSection: []Index{0}, 923 CodeSection: []Code{{Body: []byte{ 924 OpcodeBr, 0, // (br 0) 925 OpcodeI32Const, 1, OpcodeI32Const, 2, // (i32.const 1) (i32.const 2) 926 OpcodeEnd, // func 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 // This should err because (br 0) returns one value, but its enclosing function requires two: 936 // (module (func $type-break-num-vs-nums (result i32 i32) 937 // (br 0 (i32.const 1)) (i32.const 1) (i32.const 2) 938 // )) 939 module: &Module{ 940 TypeSection: []FunctionType{v_i32i32}, 941 FunctionSection: []Index{0}, 942 CodeSection: []Code{{Body: []byte{ 943 OpcodeI32Const, 1, OpcodeBr, 0, // (br 0 (i32.const 1)) 944 OpcodeI32Const, 1, OpcodeI32Const, 2, // (i32.const 1) (i32.const 2) 945 OpcodeEnd, // func 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 // This should err because (br 1) doesn't return values, but its enclosing function does: 955 // (module (func $type-break-nested-empty-vs-nums (result i32 i32) 956 // (block (br 1)) (br 0 (i32.const 1) (i32.const 2)) 957 // )) 958 module: &Module{ 959 TypeSection: []FunctionType{v_i32i32}, 960 FunctionSection: []Index{0}, 961 CodeSection: []Code{{Body: []byte{ 962 OpcodeBlock, 0x40, OpcodeBr, 0x01, OpcodeEnd, // (block (br 1)) 963 OpcodeI32Const, 1, OpcodeI32Const, 2, OpcodeBr, 0, // (br 0 (i32.const 1) (i32.const 2)) 964 OpcodeEnd, // func 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 // This should err because nop returns the empty type, but the enclosing function returns i32i32: 974 // (module (func $type-break-nested-void-vs-nums (result i32 i32) 975 // (block (br 1 (nop))) (br 0 (i32.const 1) (i32.const 2)) 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, // (block (br 1 (nop))) 982 OpcodeI32Const, 1, OpcodeI32Const, 2, OpcodeBr, 0, // (br 0 (i32.const 1) (i32.const 2)) 983 OpcodeEnd, // func 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 // This should err because the block signature is v_i32, but the enclosing function is v_i32i32: 993 // (module (func $type-break-nested-num-vs-nums (result i32 i32) 994 // (block (result i32) (br 1 (i32.const 1))) (br 0 (i32.const 1) (i32.const 2)) 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, // (block (result i32) (br 1 (i32.const 1))) 1001 OpcodeI32Const, 1, OpcodeI32Const, 2, OpcodeBr, 0, // (br 0 (i32.const 1) (i32.const 2)) 1002 OpcodeEnd, // func 1003 }}}, 1004 }, 1005 expectedErr: `not enough results in br block 1006 have (i32) 1007 want (i32, i32)`, 1008 }, 1009 1010 // test/core/if.wast 1011 { 1012 name: `if.wast - wrong signature for if type use`, 1013 // This should err because (br 0) returns no values, but its enclosing function requires two: 1014 // (module 1015 // (type $sig (func)) 1016 // (func (i32.const 1) (if (type $sig) (i32.const 0) (then))) 1017 // ) 1018 module: &Module{ 1019 TypeSection: []FunctionType{v_v}, 1020 FunctionSection: []Index{0}, 1021 CodeSection: []Code{{Body: []byte{ 1022 OpcodeI32Const, 1, // (i32.const 1) 1023 OpcodeI32Const, 0, OpcodeIf, 0, // (if (type $sig) (i32.const 0) 1024 OpcodeEnd, // if 1025 OpcodeEnd, // func 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 // This should err because (if) without a type use returns no values, but its (then) returns two: 1035 // (module (func $type-then-value-nums-vs-void 1036 // (if (i32.const 1) (then (i32.const 1) (i32.const 2))) 1037 // )) 1038 module: &Module{ 1039 TypeSection: []FunctionType{v_v}, 1040 FunctionSection: []Index{0}, 1041 CodeSection: []Code{{Body: []byte{ 1042 OpcodeI32Const, 1, OpcodeIf, 0x40, // (if (i32.const 1) 1043 OpcodeI32Const, 1, OpcodeI32Const, 2, // (then (i32.const 1) (i32.const 2)) 1044 OpcodeEnd, // if 1045 OpcodeEnd, // func 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 // This should err because (if) without a type use returns no values, but its (then) returns two: 1055 // (module (func $type-then-value-nums-vs-void-else 1056 // (if (i32.const 1) (then (i32.const 1) (i32.const 2)) (else)) 1057 // )) 1058 module: &Module{ 1059 TypeSection: []FunctionType{v_v}, 1060 FunctionSection: []Index{0}, 1061 CodeSection: []Code{{Body: []byte{ 1062 OpcodeI32Const, 1, OpcodeIf, 0x40, // (if (i32.const 1) 1063 OpcodeI32Const, 1, OpcodeI32Const, 2, // (then (i32.const 1) (i32.const 2)) 1064 OpcodeElse, // (else) 1065 OpcodeEnd, // if 1066 OpcodeEnd, // func 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 // This should err because (if) without a type use returns no values, but its (else) returns two: 1076 // (module (func $type-else-value-nums-vs-void 1077 // (if (i32.const 1) (then) (else (i32.const 1) (i32.const 2))) 1078 // )) 1079 module: &Module{ 1080 TypeSection: []FunctionType{v_v}, 1081 FunctionSection: []Index{0}, 1082 CodeSection: []Code{{Body: []byte{ 1083 OpcodeI32Const, 1, OpcodeIf, 0x40, // (if (i32.const 1) (then) 1084 OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 2, // (else (i32.const 1) (i32.const 2)) 1085 OpcodeEnd, // if 1086 OpcodeEnd, // func 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 // This should err because (if) without a type use returns no values, each branch returns two: 1096 // (module (func $type-both-value-nums-vs-void 1097 // (if (i32.const 1) (then (i32.const 1) (i32.const 2)) (else (i32.const 2) (i32.const 1))) 1098 // )) 1099 module: &Module{ 1100 TypeSection: []FunctionType{v_v}, 1101 FunctionSection: []Index{0}, 1102 CodeSection: []Code{{Body: []byte{ 1103 OpcodeI32Const, 1, OpcodeIf, 0x40, // (if (i32.const 1) 1104 OpcodeI32Const, 1, OpcodeI32Const, 2, // (then (i32.const 1) (i32.const 2)) 1105 OpcodeElse, OpcodeI32Const, 2, OpcodeI32Const, 1, // (else (i32.const 2) (i32.const 1)) 1106 OpcodeEnd, // if 1107 OpcodeEnd, // func 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 // This should err because the if branch is empty, but its type use requires two i32s: 1117 // (module (func $type-then-value-empty-vs-nums (result i32 i32) 1118 // (if (result i32 i32) (i32.const 1) (then) (else (i32.const 0) (i32.const 2))) 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, // (if (result i32 i32) (i32.const 1) (then) 1125 OpcodeElse, OpcodeI32Const, 0, OpcodeI32Const, 2, // (else (i32.const 0) (i32.const 2))) 1126 OpcodeEnd, // if 1127 OpcodeEnd, // func 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 // This should err because the else branch is empty, but its type use requires two i32s: 1137 // (module (func $type-else-value-empty-vs-nums (result i32 i32) 1138 // (if (result i32 i32) (i32.const 1) (then (i32.const 0) (i32.const 1)) (else)) 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, // (if (result i32 i32) (i32.const 1) 1145 OpcodeI32Const, 0, OpcodeI32Const, 2, // (then (i32.const 0) (i32.const 1)) 1146 OpcodeElse, // (else) 1147 OpcodeEnd, // if 1148 OpcodeEnd, // func 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 // This should err because the both branches are empty, but the if type use requires two i32s: 1158 // (module (func $type-both-value-empty-vs-nums (result i32 i32) 1159 // (if (result i32 i32) (i32.const 1) (then) (else)) 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, // (if (result i32 i32) (i32.const 1) (then) 1166 OpcodeElse, // (else) 1167 OpcodeEnd, // if 1168 OpcodeEnd, // func 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 // This should err because the else branch is missing, but its type use requires two i32s: 1178 // (module (func $type-no-else-vs-nums (result i32 i32) 1179 // (if (result i32 i32) (i32.const 1) (then (i32.const 1) (i32.const 1))) 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, // (if (result i32 i32) (i32.const 1) 1186 OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1)) 1187 OpcodeEnd, // if 1188 OpcodeEnd, // func 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 // This should err because the then branch evaluates to empty, but its type use requires two i32s: 1198 // (module (func $type-then-value-void-vs-nums (result i32 i32) 1199 // (if (result i32 i32) (i32.const 1) (then (nop)) (else (i32.const 0) (i32.const 0))) 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, // (if (result i32 i32) (i32.const 1) 1206 OpcodeNop, // (then (nop)) 1207 OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1)) 1208 OpcodeEnd, // if 1209 OpcodeEnd, // func 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 // This should err because the else branch evaluates to empty, but its type use requires two i32s: 1219 // (module (func $type-else-value-void-vs-nums (result i32 i32) 1220 // (if (result i32 i32) (i32.const 1) (then (i32.const 0) (i32.const 0)) (else (nop))) 1221 // )) 1222 module: &Module{ 1223 TypeSection: []FunctionType{v_i32i32}, 1224 FunctionSection: []Index{0}, 1225 CodeSection: []Code{{Body: []byte{ 1226 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1227 OpcodeI32Const, 0, OpcodeI32Const, 0, // (then (i32.const 0) (i32.const 0)) 1228 OpcodeElse, OpcodeNop, // (else (nop)) 1229 OpcodeEnd, // if 1230 OpcodeEnd, // func 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 // This should err because the if branch evaluates to empty, but its type use requires two i32s: 1240 // (module (func $type-both-value-void-vs-nums (result i32 i32) 1241 // (if (result i32 i32) (i32.const 1) (then (nop)) (else (nop))) 1242 // )) 1243 module: &Module{ 1244 TypeSection: []FunctionType{v_i32i32}, 1245 FunctionSection: []Index{0}, 1246 CodeSection: []Code{{Body: []byte{ 1247 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1248 OpcodeNop, // (then (nop)) 1249 OpcodeElse, OpcodeNop, // (else (nop)) 1250 OpcodeEnd, // if 1251 OpcodeEnd, // func 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 // This should err because the if branch returns one value, but its type use requires two: 1261 // (module (func $type-then-value-num-vs-nums (result i32 i32) 1262 // (if (result i32 i32) (i32.const 1) (then (i32.const 1)) (else (i32.const 1) (i32.const 1))) 1263 // )) 1264 module: &Module{ 1265 TypeSection: []FunctionType{v_i32i32}, 1266 FunctionSection: []Index{0}, 1267 CodeSection: []Code{{Body: []byte{ 1268 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1269 OpcodeI32Const, 1, // (then (i32.const 1)) 1270 OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1))) 1271 OpcodeEnd, // if 1272 OpcodeEnd, // func 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 // This should err because the else branch returns one value, but its type use requires two: 1282 // (module (func $type-else-value-num-vs-nums (result i32 i32) 1283 // (if (result i32 i32) (i32.const 1) (then (i32.const 1) (i32.const 1)) (else (i32.const 1))) 1284 // )) 1285 module: &Module{ 1286 TypeSection: []FunctionType{v_i32i32}, 1287 FunctionSection: []Index{0}, 1288 CodeSection: []Code{{Body: []byte{ 1289 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1290 OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1)) 1291 OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1))) 1292 OpcodeEnd, // if 1293 OpcodeEnd, // func 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 // This should err because the if branch returns one value, but its type use requires two: 1303 // (module (func $type-both-value-num-vs-nums (result i32 i32) 1304 // (if (result i32 i32) (i32.const 1) (then (i32.const 1)) (else (i32.const 1))) 1305 // )) 1306 module: &Module{ 1307 TypeSection: []FunctionType{v_i32i32}, 1308 FunctionSection: []Index{0}, 1309 CodeSection: []Code{{Body: []byte{ 1310 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1311 OpcodeI32Const, 1, // (then (i32.const 1)) 1312 OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1))) 1313 OpcodeEnd, // if 1314 OpcodeEnd, // func 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 // This should err because the if branch returns one value, but its type use requires two: 1324 // (module (func $type-then-value-partial-vs-nums (result i32 i32) 1325 // (i32.const 0) 1326 // (if (result i32 i32) (i32.const 1) (then (i32.const 1)) (else (i32.const 1) (i32.const 1))) 1327 // )) 1328 module: &Module{ 1329 TypeSection: []FunctionType{v_i32i32}, 1330 FunctionSection: []Index{0}, 1331 CodeSection: []Code{{Body: []byte{ 1332 OpcodeI32Const, 0, // (i32.const 0) - NOTE: this is outside the (if) 1333 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1334 OpcodeI32Const, 1, // (then (i32.const 1)) 1335 OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1)) 1336 OpcodeEnd, // if 1337 OpcodeEnd, // func 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 // This should err because the else branch returns one value, but its type use requires two: 1347 // (module (func $type-else-value-partial-vs-nums (result i32 i32) 1348 // (i32.const 0) 1349 // (if (result i32 i32) (i32.const 1) (then (i32.const 1) (i32.const 1)) (else (i32.const 1))) 1350 // )) 1351 module: &Module{ 1352 TypeSection: []FunctionType{v_i32i32}, 1353 FunctionSection: []Index{0}, 1354 CodeSection: []Code{{Body: []byte{ 1355 OpcodeI32Const, 0, // (i32.const 0) - NOTE: this is outside the (if) 1356 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1357 OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1)) 1358 OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1)) 1359 OpcodeEnd, // if 1360 OpcodeEnd, // func 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 // This should err because the if branch returns one value, but its type use requires two: 1370 // (module (func $type-both-value-partial-vs-nums (result i32 i32) 1371 // (i32.const 0) 1372 // (if (result i32 i32) (i32.const 1) (then (i32.const 1)) (else (i32.const 1))) 1373 // )) 1374 module: &Module{ 1375 TypeSection: []FunctionType{v_i32i32}, 1376 FunctionSection: []Index{0}, 1377 CodeSection: []Code{{Body: []byte{ 1378 OpcodeI32Const, 0, // (i32.const 0) - NOTE: this is outside the (if) 1379 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1380 OpcodeI32Const, 1, // (then (i32.const 1)) 1381 OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1)) 1382 OpcodeEnd, // if 1383 OpcodeEnd, // func 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 // This should err because the if branch returns two values, but its type use requires one: 1393 // (module (func $type-then-value-nums-vs-num (result i32) 1394 // (if (result i32) (i32.const 1) (then (i32.const 1) (i32.const 1)) (else (i32.const 1))) 1395 // )) 1396 module: &Module{ 1397 TypeSection: []FunctionType{v_i32}, 1398 FunctionSection: []Index{0}, 1399 CodeSection: []Code{{Body: []byte{ 1400 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32) (i32.const 1) 1401 OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1)) 1402 OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1)) 1403 OpcodeEnd, // if 1404 OpcodeEnd, // func 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 // This should err because the else branch returns two values, but its type use requires one: 1414 // (module (func $type-else-value-nums-vs-num (result i32) 1415 // (if (result i32) (i32.const 1) (then (i32.const 1)) (else (i32.const 1) (i32.const 1))) 1416 // )) 1417 module: &Module{ 1418 TypeSection: []FunctionType{v_i32}, 1419 FunctionSection: []Index{0}, 1420 CodeSection: []Code{{Body: []byte{ 1421 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32) (i32.const 1) 1422 OpcodeI32Const, 1, // (then (i32.const 1)) 1423 OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1)) 1424 OpcodeEnd, // if 1425 OpcodeEnd, // func 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 // This should err because the if branch returns two values, but its type use requires one: 1435 // (module (func $type-both-value-nums-vs-num (result i32) 1436 // (if (result i32) (i32.const 1) (then (i32.const 1) (i32.const 1)) (else (i32.const 1) (i32.const 1))) 1437 // )) 1438 module: &Module{ 1439 TypeSection: []FunctionType{v_i32}, 1440 FunctionSection: []Index{0}, 1441 CodeSection: []Code{{Body: []byte{ 1442 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32) (i32.const 1) 1443 OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1)) 1444 OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1)) 1445 OpcodeEnd, // if 1446 OpcodeEnd, // func 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 // This should err because the if branch returns three values, but its type use requires two: 1456 // (module (func $type-both-different-value-nums-vs-nums (result i32 i32) 1457 // (if (result i32 i32) (i32.const 1) (then (i32.const 1) (i32.const 1) (i32.const 1)) (else (i32.const 1))) 1458 // )) 1459 module: &Module{ 1460 TypeSection: []FunctionType{v_i32i32}, 1461 FunctionSection: []Index{0}, 1462 CodeSection: []Code{{Body: []byte{ 1463 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1464 OpcodeI32Const, 1, OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1) (i32.const 1)) 1465 OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1)) 1466 OpcodeEnd, // if 1467 OpcodeEnd, // func 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 // This should err because the branch in the if returns no values, but its type use requires two: 1477 // (module (func $type-then-break-last-void-vs-nums (result i32 i32) 1478 // (if (result i32 i32) (i32.const 1) (then (br 0)) (else (i32.const 1) (i32.const 1))) 1479 // )) 1480 module: &Module{ 1481 TypeSection: []FunctionType{v_i32i32}, 1482 FunctionSection: []Index{0}, 1483 CodeSection: []Code{{Body: []byte{ 1484 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1485 OpcodeBr, 0, // (then (br 0)) 1486 OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1))) 1487 OpcodeEnd, // if 1488 OpcodeEnd, // func 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 // This should err because the branch in the else returns no values, but its type use requires two: 1498 // (module (func $type-else-break-last-void-vs-nums (result i32 i32) 1499 // (if (result i32 i32) (i32.const 1) (then (i32.const 1) (i32.const 1)) (else (br 0))) 1500 // )) 1501 module: &Module{ 1502 TypeSection: []FunctionType{v_i32i32}, 1503 FunctionSection: []Index{0}, 1504 CodeSection: []Code{{Body: []byte{ 1505 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1506 OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1)) 1507 OpcodeElse, OpcodeBr, 0, // (else (br 0)) 1508 OpcodeEnd, // if 1509 OpcodeEnd, // func 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 // This should err because the branch in the if returns no values, but its type use requires two: 1519 // (module (func $type-then-break-empty-vs-nums (result i32 i32) 1520 // (if (result i32 i32) (i32.const 1) 1521 // (then (br 0) (i32.const 1) (i32.const 1)) 1522 // (else (i32.const 1) (i32.const 1)) 1523 // ) 1524 // )) 1525 module: &Module{ 1526 TypeSection: []FunctionType{v_i32i32}, 1527 FunctionSection: []Index{0}, 1528 CodeSection: []Code{{Body: []byte{ 1529 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1530 OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (br 0) (i32.const 1) (i32.const 1)) 1531 // ^^ NOTE: consts are outside the br block 1532 OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1)) 1533 OpcodeEnd, // if 1534 OpcodeEnd, // func 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 // This should err because the branch in the else returns no values, but its type use requires two: 1544 // (module (func $type-else-break-empty-vs-nums (result i32 i32) 1545 // (if (result i32 i32) (i32.const 1) 1546 // (then (i32.const 1) (i32.const 1)) 1547 // (else (br 0) (i32.const 1) (i32.const 1)) 1548 // ) 1549 // )) 1550 module: &Module{ 1551 TypeSection: []FunctionType{v_i32i32}, 1552 FunctionSection: []Index{0}, 1553 CodeSection: []Code{{Body: []byte{ 1554 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1555 OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1)) 1556 OpcodeElse, OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (br 0) (i32.const 1) (i32.const 1)) 1557 // ^^ NOTE: consts are outside the br block 1558 OpcodeEnd, // if 1559 OpcodeEnd, // func 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 // This should err because the branch in the if evaluates to no values, but its type use requires two: 1569 // (module (func $type-then-break-void-vs-nums (result i32 i32) 1570 // (if (result i32 i32) (i32.const 1) 1571 // (then (br 0 (nop)) (i32.const 1) (i32.const 1)) 1572 // (else (i32.const 1) (i32.const 1)) 1573 // ) 1574 // )) 1575 module: &Module{ 1576 TypeSection: []FunctionType{v_i32i32}, 1577 FunctionSection: []Index{0}, 1578 CodeSection: []Code{{Body: []byte{ 1579 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1580 OpcodeNop, OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (br 0 (nop)) (i32.const 1) (i32.const 1)) 1581 // ^^ NOTE: consts are outside the br block 1582 OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1)) 1583 OpcodeEnd, // if 1584 OpcodeEnd, // func 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 // This should err because the branch in the else evaluates to no values, but its type use requires two: 1594 // (module (func $type-else-break-void-vs-nums (result i32 i32) 1595 // (if (result i32 i32) (i32.const 1) 1596 // (then (i32.const 1) (i32.const 1)) 1597 // (else (br 0 (nop)) (i32.const 1) (i32.const 1)) 1598 // ) 1599 // )) 1600 module: &Module{ 1601 TypeSection: []FunctionType{v_i32i32}, 1602 FunctionSection: []Index{0}, 1603 CodeSection: []Code{{Body: []byte{ 1604 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1605 OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1)) 1606 OpcodeElse, OpcodeNop, OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (br 0 (nop)) (i32.const 1) (i32.const 1)) 1607 // ^^ NOTE: consts are outside the br block 1608 OpcodeEnd, // if 1609 OpcodeEnd, // func 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 // This should err because the branch in the if evaluates to one value, but its type use requires two: 1619 // (module (func $type-then-break-num-vs-nums (result i32 i32) 1620 // (if (result i32 i32) (i32.const 1) 1621 // (then (br 0 (i64.const 1)) (i32.const 1) (i32.const 1)) 1622 // (else (i32.const 1) (i32.const 1)) 1623 // ) 1624 // )) 1625 module: &Module{ 1626 TypeSection: []FunctionType{v_i32i32}, 1627 FunctionSection: []Index{0}, 1628 CodeSection: []Code{{Body: []byte{ 1629 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1630 OpcodeI64Const, 1, OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (br 0 (i64.const 1)) (i32.const 1) (i32.const 1)) 1631 // ^^ NOTE: only one (incorrect) const is inside the br block 1632 OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1)) 1633 OpcodeEnd, // if 1634 OpcodeEnd, // func 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 // This should err because the branch in the else evaluates to one value, but its type use requires two: 1644 // (module (func $type-else-break-num-vs-nums (result i32 i32) 1645 // (if (result i32 i32) (i32.const 1) 1646 // (then (i32.const 1) (i32.const 1)) 1647 // (else (br 0 (i64.const 1)) (i32.const 1) (i32.const 1)) 1648 // ) 1649 // )) 1650 module: &Module{ 1651 TypeSection: []FunctionType{v_i32i32}, 1652 FunctionSection: []Index{0}, 1653 CodeSection: []Code{{Body: []byte{ 1654 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1655 OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1)) 1656 OpcodeElse, OpcodeI64Const, 1, OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (br 0 (i64.const 1)) (i32.const 1) (i32.const 1)) 1657 // ^^ NOTE: only one (incorrect) const is inside the br block 1658 OpcodeEnd, // if 1659 OpcodeEnd, // func 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 // This should err because the branch in the if evaluates to one value, but its type use requires two: 1669 // (module (func $type-then-break-partial-vs-nums (result i32 i32) 1670 // (i32.const 1) 1671 // (if (result i32 i32) (i32.const 1) 1672 // (then (br 0 (i64.const 1)) (i32.const 1)) 1673 // (else (i32.const 1)) 1674 // ) 1675 // )) 1676 module: &Module{ 1677 TypeSection: []FunctionType{v_i32i32}, 1678 FunctionSection: []Index{0}, 1679 CodeSection: []Code{{Body: []byte{ 1680 OpcodeI32Const, 1, // (i32.const 1) 1681 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1682 OpcodeI64Const, 1, OpcodeBr, 0, OpcodeI32Const, 1, // (then (br 0 (i64.const 1)) (i32.const 1)) 1683 // ^^ NOTE: only one (incorrect) const is inside the br block 1684 OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1)) 1685 OpcodeEnd, // if 1686 OpcodeEnd, // func 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 // This should err because the branch in the if evaluates to one value, but its type use requires two: 1696 // (module (func $type-else-break-partial-vs-nums (result i32 i32) 1697 // (i32.const 1) 1698 // (if (result i32 i32) (i32.const 1) 1699 // (then (i32.const 1)) 1700 // (else (br 0 (i64.const 1)) (i32.const 1)) 1701 // ) 1702 // )) 1703 module: &Module{ 1704 TypeSection: []FunctionType{v_i32i32}, 1705 FunctionSection: []Index{0}, 1706 CodeSection: []Code{{Body: []byte{ 1707 OpcodeI32Const, 1, // (i32.const 1) 1708 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1709 OpcodeI32Const, 1, // (then (i32.const 1)) 1710 OpcodeElse, OpcodeI64Const, 1, OpcodeBr, 0, OpcodeI32Const, 1, // (else (br 0 (i64.const 1)) (i32.const 1)) 1711 // ^^ NOTE: only one (incorrect) const is inside the br block 1712 OpcodeEnd, // if 1713 OpcodeEnd, // func 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 // This should err because the stack has no values, but the if type use requires two: 1723 // (module (func $type-param-void-vs-num 1724 // (if (param i32) (i32.const 1) (then (drop))) 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, // (if (param i32) (i32.const 1) 1731 OpcodeDrop, // (then (drop))) 1732 OpcodeEnd, // if 1733 OpcodeEnd, // func 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 // This should err because the stack has no values, but the if type use requires two: 1743 // (module (func $type-param-void-vs-nums 1744 // (if (param i32 f64) (i32.const 1) (then (drop) (drop))) 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, // (if (param i32 f64) (i32.const 1) 1751 OpcodeI32Const, 1, OpcodeDrop, // (then (drop) (drop)) 1752 OpcodeEnd, // if 1753 OpcodeEnd, // func 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 // This should err because the stack has a different value that what the if type use requires: 1763 // (module (func $type-param-num-vs-num 1764 // (f32.const 0) (if (param i32) (i32.const 1) (then (drop))) 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, // (f32.const 0) 1771 OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param i32) (i32.const 1) 1772 OpcodeDrop, // (then (drop)) 1773 OpcodeEnd, // if 1774 OpcodeEnd, // func 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 // This should err because the stack has one value, but the if type use requires two: 1782 // (module (func $type-param-num-vs-nums 1783 // (f32.const 0) (if (param f32 i32) (i32.const 1) (then (drop) (drop))) 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, // (f32.const 0) 1790 OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param f32 i32) (i32.const 1) 1791 OpcodeDrop, OpcodeDrop, // (then (drop) (drop)) 1792 OpcodeEnd, // if 1793 OpcodeEnd, // func 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 // This should err because the stack has no values, but the if type use requires one: 1803 // (module (func $type-param-nested-void-vs-num 1804 // (block (if (param i32) (i32.const 1) (then (drop)))) 1805 // )) 1806 module: &Module{ 1807 TypeSection: []FunctionType{v_v, i32_v}, 1808 FunctionSection: []Index{0}, 1809 CodeSection: []Code{{Body: []byte{ 1810 OpcodeBlock, 0x40, // (block 1811 OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param i32) (i32.const 1) 1812 OpcodeDrop, // (then (drop)) 1813 OpcodeEnd, // block 1814 OpcodeEnd, // if 1815 OpcodeEnd, // func 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 // This should err because the stack has no values, but the if type use requires two: 1825 // (module (func $type-param-void-vs-nums 1826 // (block (if (param i32 f64) (i32.const 1) (then (drop) (drop)))) 1827 // )) 1828 module: &Module{ 1829 TypeSection: []FunctionType{v_v, i32f64_v}, 1830 FunctionSection: []Index{0}, 1831 CodeSection: []Code{{Body: []byte{ 1832 OpcodeBlock, 0x40, // (block 1833 OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param i32 f64) (i32.const 1) 1834 OpcodeDrop, // (then (drop) (drop)) 1835 OpcodeEnd, // block 1836 OpcodeEnd, // if 1837 OpcodeEnd, // func 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 // This should err because the stack has a different values than required by the if type use: 1847 // (module (func $type-param-num-vs-num 1848 // (block (f32.const 0) (if (param i32) (i32.const 1) (then (drop)))) 1849 // )) 1850 module: &Module{ 1851 TypeSection: []FunctionType{v_v, i32_v}, 1852 FunctionSection: []Index{0}, 1853 CodeSection: []Code{{Body: []byte{ 1854 OpcodeBlock, 0x40, // (block 1855 OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0) 1856 OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param i32) (i32.const 1) 1857 OpcodeDrop, // (then (drop)) 1858 OpcodeEnd, // block 1859 OpcodeEnd, // if 1860 OpcodeEnd, // func 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 // This should err because the stack has one value, but the if type use requires two: 1868 // (module (func $type-param-num-vs-nums 1869 // (block (f32.const 0) (if (param f32 i32) (i32.const 1) (then (drop) (drop)))) 1870 // )) 1871 module: &Module{ 1872 TypeSection: []FunctionType{v_v, f32i32_v}, 1873 FunctionSection: []Index{0}, 1874 CodeSection: []Code{{Body: []byte{ 1875 OpcodeBlock, 0x40, // (block 1876 OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0) 1877 OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param f32 i32) (i32.const 1) 1878 OpcodeDrop, // (then (drop) (drop)) 1879 OpcodeEnd, // block 1880 OpcodeEnd, // if 1881 OpcodeEnd, // func 1882 }}}, 1883 }, 1884 expectedErr: `not enough params for if block 1885 have (f32) 1886 want (f32, i32)`, 1887 }, 1888 1889 // test/core/loop.wast 1890 { 1891 name: `loop.wast - wrong signature for loop type use`, 1892 // This should err because the loop type use returns no values, but its block returns one: 1893 // (module 1894 // (type $sig (func)) 1895 // (func (loop (type $sig) (i32.const 0))) 1896 // ) 1897 module: &Module{ 1898 TypeSection: []FunctionType{v_v}, 1899 FunctionSection: []Index{0}, 1900 CodeSection: []Code{{Body: []byte{ 1901 OpcodeLoop, 0, OpcodeI32Const, 0, // (loop (type $sig) (i32.const 0)) 1902 OpcodeEnd, // loop 1903 OpcodeEnd, // func 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 // This should err because the empty block type requires no values, but the loop returns two: 1913 // (module (func $type-value-nums-vs-void 1914 // (loop (i32.const 1) (i32.const 2)) 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, // (loop (i32.const 1) (i32.const 2)) 1921 OpcodeEnd, // loop 1922 OpcodeEnd, // func 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 // This should err because the loop type use returns two values, but the block returns none: 1932 // (module (func $type-value-empty-vs-nums (result i32 i32) 1933 // (loop (result i32 i32)) 1934 // )) 1935 module: &Module{ 1936 TypeSection: []FunctionType{v_i32i32}, 1937 FunctionSection: []Index{0}, 1938 CodeSection: []Code{{Body: []byte{ 1939 OpcodeLoop, 0x0, // (loop (result i32 i32)) - matches existing func type 1940 OpcodeEnd, // loop 1941 OpcodeEnd, // func 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 // This should err because the loop type use returns two values, but the block returns none: 1951 // (module (func $type-value-void-vs-nums (result i32 i32) 1952 // (loop (result i32 i32) (nop)) 1953 // )) 1954 module: &Module{ 1955 TypeSection: []FunctionType{v_i32i32}, 1956 FunctionSection: []Index{0}, 1957 CodeSection: []Code{{Body: []byte{ 1958 OpcodeLoop, 0x0, // (loop (result i32 i32) - matches existing func type 1959 OpcodeNop, // (nop) 1960 OpcodeEnd, // loop 1961 OpcodeEnd, // func 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 // This should err because the loop type use returns two values, but the block returns one: 1971 // (module (func $type-value-num-vs-nums (result i32 i32) 1972 // (loop (result i32 i32) (i32.const 0)) 1973 // )) 1974 module: &Module{ 1975 TypeSection: []FunctionType{v_i32i32}, 1976 FunctionSection: []Index{0}, 1977 CodeSection: []Code{{Body: []byte{ 1978 OpcodeLoop, 0x0, // (loop (result i32 i32) - matches existing func type 1979 OpcodeI32Const, 0, // (i32.const 0) 1980 OpcodeEnd, // loop 1981 OpcodeEnd, // func 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 // This should err because the loop type use returns two values, but the block returns one: 1991 // (module (func $type-value-partial-vs-nums (result i32 i32) 1992 // (i32.const 1) (loop (result i32 i32) (i32.const 2)) 1993 // )) 1994 module: &Module{ 1995 TypeSection: []FunctionType{v_i32i32}, 1996 FunctionSection: []Index{0}, 1997 CodeSection: []Code{{Body: []byte{ 1998 OpcodeI32Const, 1, // (i32.const 1) - NOTE: outside the loop! 1999 OpcodeLoop, 0x0, // (loop (result i32 i32) - matches existing func type 2000 OpcodeI32Const, 2, // (i32.const 2) 2001 OpcodeEnd, // loop 2002 OpcodeEnd, // func 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 // This should err because the loop type use returns one value, but the block returns two: 2012 // (module (func $type-value-nums-vs-num (result i32) 2013 // (loop (result i32) (i32.const 1) (i32.const 2)) 2014 // )) 2015 module: &Module{ 2016 TypeSection: []FunctionType{v_i32}, 2017 FunctionSection: []Index{0}, 2018 CodeSection: []Code{{Body: []byte{ 2019 OpcodeLoop, 0x0, // (loop (result i32) - matches existing func type 2020 OpcodeI32Const, 1, OpcodeI32Const, 2, // (i32.const 1) (i32.const 2)) 2021 OpcodeEnd, // loop 2022 OpcodeEnd, // func 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 // This should err because the loop type use requires one param, but the stack has none: 2032 // (module (func $type-param-void-vs-num 2033 // (loop (param i32) (drop)) 2034 // )) 2035 module: &Module{ 2036 TypeSection: []FunctionType{v_v, i32_v}, 2037 FunctionSection: []Index{0}, 2038 CodeSection: []Code{{Body: []byte{ 2039 OpcodeLoop, 0x1, // (loop (param i32) 2040 OpcodeDrop, // (drop) 2041 OpcodeEnd, // loop 2042 OpcodeEnd, // func 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 // This should err because the loop type use requires two params, but the stack has none: 2052 // (module (func $type-param-void-vs-nums 2053 // (loop (param i32 f64) (drop) (drop)) 2054 // )) 2055 module: &Module{ 2056 TypeSection: []FunctionType{v_v, i32f64_v}, 2057 FunctionSection: []Index{0}, 2058 CodeSection: []Code{{Body: []byte{ 2059 OpcodeLoop, 0x1, // (loop (param i32 f64) 2060 OpcodeDrop, // (drop) 2061 OpcodeDrop, // (drop) 2062 OpcodeEnd, // loop 2063 OpcodeEnd, // func 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 // This should err because the loop type use requires a different param type than what's on the stack: 2073 // (module (func $type-param-num-vs-num 2074 // (f32.const 0) (loop (param i32) (drop)) 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, // (f32.const 0) 2081 OpcodeLoop, 0x1, // (loop (param i32) 2082 OpcodeDrop, // (drop) 2083 OpcodeEnd, // loop 2084 OpcodeEnd, // func 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 // This should err because the loop type use requires a more parameters than what's on the stack: 2092 // (module (func $type-param-num-vs-nums 2093 // (f32.const 0) (loop (param f32 i32) (drop) (drop)) 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, // (f32.const 0) 2100 OpcodeLoop, 0x1, // (loop (param f32 i32) 2101 OpcodeDrop, OpcodeDrop, // (drop) (drop) 2102 OpcodeEnd, // loop 2103 OpcodeEnd, // func 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 // This should err because the loop type use requires a more parameters than what's on the stack: 2113 // (module (func $type-param-nested-void-vs-num 2114 // (block (loop (param i32) (drop))) 2115 // )) 2116 module: &Module{ 2117 TypeSection: []FunctionType{v_v, i32_v}, 2118 FunctionSection: []Index{0}, 2119 CodeSection: []Code{{Body: []byte{ 2120 OpcodeBlock, 0x40, // (block 2121 OpcodeLoop, 0x1, // (loop (param i32) 2122 OpcodeDrop, // (drop) 2123 OpcodeEnd, // loop 2124 OpcodeEnd, // block 2125 OpcodeEnd, // func 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 // This should err because the loop type use requires a more parameters than what's on the stack: 2135 // (module (func $type-param-void-vs-nums 2136 // (block (loop (param i32 f64) (drop) (drop))) 2137 // )) 2138 module: &Module{ 2139 TypeSection: []FunctionType{v_v, i32f64_v}, 2140 FunctionSection: []Index{0}, 2141 CodeSection: []Code{{Body: []byte{ 2142 OpcodeBlock, 0x40, // (block 2143 OpcodeLoop, 0x1, // (loop (param i32 f64) 2144 OpcodeDrop, OpcodeDrop, // (drop) (drop) 2145 OpcodeEnd, // loop 2146 OpcodeEnd, // block 2147 OpcodeEnd, // func 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 // This should err because the loop type use requires a different param type than what's on the stack: 2157 // (module (func $type-param-num-vs-num 2158 // (block (f32.const 0) (loop (param i32) (drop))) 2159 // )) 2160 module: &Module{ 2161 TypeSection: []FunctionType{v_v, i32_v}, 2162 FunctionSection: []Index{0}, 2163 CodeSection: []Code{{Body: []byte{ 2164 OpcodeBlock, 0x40, // (block 2165 OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0) 2166 OpcodeLoop, 0x1, // (loop (param i32) 2167 OpcodeDrop, // (drop) 2168 OpcodeEnd, // loop 2169 OpcodeEnd, // block 2170 OpcodeEnd, // func 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 // This should err because the loop type use requires a more parameters than what's on the stack: 2178 // (module (func $type-param-num-vs-nums 2179 // (block (f32.const 0) (loop (param f32 i32) (drop) (drop))) 2180 // )) 2181 module: &Module{ 2182 TypeSection: []FunctionType{v_v, f32i32_v}, 2183 FunctionSection: []Index{0}, 2184 CodeSection: []Code{{Body: []byte{ 2185 OpcodeBlock, 0x40, // (block 2186 OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0) 2187 OpcodeLoop, 0x1, // (loop (param f32 i32) 2188 OpcodeDrop, OpcodeDrop, // (drop) (drop) 2189 OpcodeEnd, // loop 2190 OpcodeEnd, // block 2191 OpcodeEnd, // func 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, // number of elements 2377 OpcodeMiscPrefix, OpcodeMiscTableGrow, 2378 0, // Table Index. 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, // number of elements 2389 OpcodeMiscPrefix, OpcodeMiscTableGrow, 2390 1, // Table of externref type -> mismatch. 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, // number of elements 2401 OpcodeMiscPrefix, OpcodeMiscTableGrow, 2402 1, // Table Index. 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, // number of elements 2413 OpcodeMiscPrefix, OpcodeMiscTableGrow, 2414 0, // Table of funcref type -> mismatch. 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, // number of elements 2425 OpcodeMiscPrefix, OpcodeMiscTableGrow, 2426 10, // Table Index. 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, // Table Index. 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, // Table Index. 2447 OpcodeDrop, 2448 OpcodeEnd, 2449 }, 2450 flag: api.CoreFeatureReferenceTypes, 2451 }, 2452 { 2453 name: "table.fill (funcref)", 2454 body: []byte{ 2455 OpcodeI32Const, 1, // offset 2456 OpcodeRefNull, RefTypeFuncref, 2457 OpcodeI32Const, 1, // number of elements 2458 OpcodeMiscPrefix, OpcodeMiscTableFill, 2459 0, // Table Index. 2460 OpcodeEnd, 2461 }, 2462 flag: api.CoreFeatureReferenceTypes, 2463 }, 2464 { 2465 name: "table.fill (funcref) - type mismatch", 2466 body: []byte{ 2467 OpcodeI32Const, 1, // offset 2468 OpcodeRefNull, RefTypeFuncref, 2469 OpcodeI32Const, 1, // number of elements 2470 OpcodeMiscPrefix, OpcodeMiscTableFill, 2471 1, // Table of externref type -> mismatch. 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, // offset 2481 OpcodeRefNull, RefTypeExternref, 2482 OpcodeI32Const, 1, // number of elements 2483 OpcodeMiscPrefix, OpcodeMiscTableFill, 2484 1, // Table Index. 2485 OpcodeEnd, 2486 }, 2487 flag: api.CoreFeatureReferenceTypes, 2488 }, 2489 { 2490 name: "table.fill (externref) - type mismatch", 2491 body: []byte{ 2492 OpcodeI32Const, 1, // offset 2493 OpcodeRefNull, RefTypeExternref, 2494 OpcodeI32Const, 1, // number of elements 2495 OpcodeMiscPrefix, OpcodeMiscTableFill, 2496 0, // Table of funcref type -> mismatch. 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, // Table Index. 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, // immediate vector's size must be one 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, // immediate vector's size must be one 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, // alignment 2923 10, // offset 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, // align and offset. 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 // TestFuncValidation_UnreachableBrTable_NotModifyTypes ensures that we do not modify the 3385 // original function type during the function validation with the presence of unreachable br_table 3386 // targeting the function return label. 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 // Having br_table in unreachable state. 3410 OpcodeI32Const, 1, 3411 // Setting the destination as labels of index 0 which 3412 // is the function return. 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, // indicates that loop has funcType as its block type 3428 OpcodeUnreachable, 3429 // Having br_table in unreachable state. 3430 OpcodeI32Const, 1, 3431 // Setting the destination as labels of index 0 which 3432 // is the loop return. 3433 OpcodeBrTable, 2, 0, 0, 0, 3434 OpcodeEnd, // End of loop 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 // Ensures that funcType has remained intact. 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, // loop (param i32) 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, // loop (param i32) 3475 OpcodeI32Const, 1, // operand for br_if 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, // loop (param i32) 3488 OpcodeI32Const, 4, // Operand for br_table. 3489 OpcodeBrTable, 2, 0, 0, 0, 0, // Jump into the loop header anyway. 3490 OpcodeEnd, 3491 OpcodeUnreachable, 3492 OpcodeEnd, 3493 }, 3494 }, 3495 { 3496 name: "br_table - nested", 3497 body: []byte{ 3498 OpcodeI32Const, 1, 3499 OpcodeLoop, 1, // loop (param i32) 3500 OpcodeLoop, 1, // loop (param i32) 3501 OpcodeI32Const, 4, // Operand for br_table. 3502 OpcodeBrTable, 2, 0, 1, 0, // Jump into the loop header anyway. 3503 OpcodeEnd, 3504 OpcodeEnd, 3505 OpcodeUnreachable, 3506 OpcodeEnd, 3507 }, 3508 }, 3509 { 3510 name: "br / mismatch", 3511 body: []byte{ 3512 OpcodeI32Const, 1, 3513 OpcodeLoop, 1, // loop (param i32) 3514 OpcodeDrop, 3515 OpcodeBr, 0, // trying to jump the loop head after dropping the value which causes the type mismatch. 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, // loop (param i32) 3529 // Use up the param for the br_if, therefore at the time of jumping, we don't have any param to the header. 3530 OpcodeBrIf, 0, // trying to jump the loop head after dropping the value which causes the type mismatch. 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, // loop (param i32) 3545 // Use up the param for the br_table, therefore at the time of jumping, we don't have any param to the header. 3546 OpcodeBrTable, 2, 0, 0, 0, // Jump into the loop header anyway. 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 // TestFunctionValidation_redundantEnd is found in th validation fuzzing #879. 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 // TestFunctionValidation_redundantEnd is found in th validation fuzzing. 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 3682 func TestModule_funcValidation_Atomic(t *testing.T) { 3683 t.Run("valid bytecode", func(t *testing.T) { 3684 tests := []struct { 3685 name string 3686 body []byte 3687 noDropBeforeReturn bool 3688 }{ 3689 { 3690 name: "i32.atomic.load8_u", 3691 body: []byte{ 3692 OpcodeI32Const, 0x0, 3693 OpcodeAtomicPrefix, OpcodeAtomicI32Load8U, 0x0, 0x8, // alignment=2^0, offset=8 3694 }, 3695 }, 3696 { 3697 name: "i32.atomic.load16_u", 3698 body: []byte{ 3699 OpcodeI32Const, 0x0, 3700 OpcodeAtomicPrefix, OpcodeAtomicI32Load16U, 0x1, 0x8, // alignment=2^1, offset=8 3701 }, 3702 }, 3703 { 3704 name: "i32.atomic.load", 3705 body: []byte{ 3706 OpcodeI32Const, 0x0, 3707 OpcodeAtomicPrefix, OpcodeAtomicI32Load, 0x2, 0x8, // alignment=2^2, offset=8 3708 }, 3709 }, 3710 { 3711 name: "i64.atomic.load8_u", 3712 body: []byte{ 3713 OpcodeI32Const, 0x0, 3714 OpcodeAtomicPrefix, OpcodeAtomicI64Load8U, 0x0, 0x8, // alignment=2^0, offset=8 3715 }, 3716 }, 3717 { 3718 name: "i64.atomic.load16_u", 3719 body: []byte{ 3720 OpcodeI32Const, 0x0, 3721 OpcodeAtomicPrefix, OpcodeAtomicI64Load16U, 0x1, 0x8, // alignment=2^1, offset=8 3722 }, 3723 }, 3724 { 3725 name: "i64.atomic.load32_u", 3726 body: []byte{ 3727 OpcodeI32Const, 0x0, 3728 OpcodeAtomicPrefix, OpcodeAtomicI64Load32U, 0x2, 0x8, // alignment=2^2, offset=8 3729 }, 3730 }, 3731 { 3732 name: "i64.atomic.load", 3733 body: []byte{ 3734 OpcodeI32Const, 0x0, 3735 OpcodeAtomicPrefix, OpcodeAtomicI64Load, 0x3, 0x8, // alignment=2^3, offset=8 3736 }, 3737 }, 3738 { 3739 name: "i32.atomic.store8", 3740 body: []byte{ 3741 OpcodeI32Const, 0x1, 3742 OpcodeI32Const, 0x0, 3743 OpcodeAtomicPrefix, OpcodeAtomicI32Store8, 0x0, 0x8, // alignment=2^0, offset=8 3744 }, 3745 noDropBeforeReturn: true, 3746 }, 3747 { 3748 name: "i32.atomic.store16", 3749 body: []byte{ 3750 OpcodeI32Const, 0x1, 3751 OpcodeI32Const, 0x0, 3752 OpcodeAtomicPrefix, OpcodeAtomicI32Store16, 0x1, 0x8, // alignment=2^1, offset=8 3753 }, 3754 noDropBeforeReturn: true, 3755 }, 3756 { 3757 name: "i32.atomic.store", 3758 body: []byte{ 3759 OpcodeI32Const, 0x1, 3760 OpcodeI32Const, 0x0, 3761 OpcodeAtomicPrefix, OpcodeAtomicI32Store, 0x2, 0x8, // alignment=2^2, offset=8 3762 }, 3763 noDropBeforeReturn: true, 3764 }, 3765 { 3766 name: "i64.atomic.store8", 3767 body: []byte{ 3768 OpcodeI32Const, 0x0, 3769 OpcodeI64Const, 0x1, 3770 OpcodeAtomicPrefix, OpcodeAtomicI64Store8, 0x0, 0x8, // alignment=2^0, offset=8 3771 }, 3772 noDropBeforeReturn: true, 3773 }, 3774 { 3775 name: "i64.atomic.store16", 3776 body: []byte{ 3777 OpcodeI32Const, 0x0, 3778 OpcodeI64Const, 0x1, 3779 OpcodeAtomicPrefix, OpcodeAtomicI64Store16, 0x1, 0x8, // alignment=2^1, offset=8 3780 }, 3781 noDropBeforeReturn: true, 3782 }, 3783 { 3784 name: "i64.atomic.store32", 3785 body: []byte{ 3786 OpcodeI32Const, 0x0, 3787 OpcodeI64Const, 0x1, 3788 OpcodeAtomicPrefix, OpcodeAtomicI64Store32, 0x2, 0x8, // alignment=2^2, offset=8 3789 }, 3790 noDropBeforeReturn: true, 3791 }, 3792 { 3793 name: "i64.atomic.store", 3794 body: []byte{ 3795 OpcodeI32Const, 0x0, 3796 OpcodeI64Const, 0x1, 3797 OpcodeAtomicPrefix, OpcodeAtomicI64Store, 0x3, 0x8, // alignment=2^3, offset=8 3798 }, 3799 noDropBeforeReturn: true, 3800 }, 3801 { 3802 name: "i32.atomic.rmw8.add_u", 3803 body: []byte{ 3804 OpcodeI32Const, 0x0, 3805 OpcodeI32Const, 0x1, 3806 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8AddU, 0x0, 0x8, // alignment=2^0, offset=8 3807 }, 3808 }, 3809 { 3810 name: "i32.atomic.rmw16.add_u", 3811 body: []byte{ 3812 OpcodeI32Const, 0x0, 3813 OpcodeI32Const, 0x1, 3814 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16AddU, 0x1, 0x8, // alignment=2^1, offset=8 3815 }, 3816 }, 3817 { 3818 name: "i32.atomic.rmw.add", 3819 body: []byte{ 3820 OpcodeI32Const, 0x0, 3821 OpcodeI32Const, 0x1, 3822 OpcodeAtomicPrefix, OpcodeAtomicI32RmwAdd, 0x2, 0x8, // alignment=2^2, offset=8 3823 }, 3824 }, 3825 { 3826 name: "i64.atomic.rmw8.add_u", 3827 body: []byte{ 3828 OpcodeI32Const, 0x0, 3829 OpcodeI64Const, 0x1, 3830 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8AddU, 0x0, 0x8, // alignment=2^0, offset=8 3831 }, 3832 }, 3833 { 3834 name: "i64.atomic.rmw16.add_u", 3835 body: []byte{ 3836 OpcodeI32Const, 0x0, 3837 OpcodeI64Const, 0x1, 3838 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16AddU, 0x1, 0x8, // alignment=2^1, offset=8 3839 }, 3840 }, 3841 { 3842 name: "i64.atomic.rmw32.add_u", 3843 body: []byte{ 3844 OpcodeI32Const, 0x0, 3845 OpcodeI64Const, 0x1, 3846 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32AddU, 0x2, 0x8, // alignment=2^2, offset=8 3847 }, 3848 }, 3849 { 3850 name: "i64.atomic.rmw.add", 3851 body: []byte{ 3852 OpcodeI32Const, 0x0, 3853 OpcodeI64Const, 0x1, 3854 OpcodeAtomicPrefix, OpcodeAtomicI64RmwAdd, 0x3, 0x8, // alignment=2^3, offset=8 3855 }, 3856 }, 3857 { 3858 name: "i32.atomic.rmw8.sub_u", 3859 body: []byte{ 3860 OpcodeI32Const, 0x0, 3861 OpcodeI32Const, 0x1, 3862 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8SubU, 0x0, 0x8, // alignment=2^0, offset=8 3863 }, 3864 }, 3865 { 3866 name: "i32.atomic.rmw16.sub_u", 3867 body: []byte{ 3868 OpcodeI32Const, 0x0, 3869 OpcodeI32Const, 0x1, 3870 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16SubU, 0x1, 0x8, // alignment=2^1, offset=8 3871 }, 3872 }, 3873 { 3874 name: "i32.atomic.rmw.sub", 3875 body: []byte{ 3876 OpcodeI32Const, 0x0, 3877 OpcodeI32Const, 0x1, 3878 OpcodeAtomicPrefix, OpcodeAtomicI32RmwSub, 0x2, 0x8, // alignment=2^2, offset=8 3879 }, 3880 }, 3881 { 3882 name: "i64.atomic.rmw8.sub_u", 3883 body: []byte{ 3884 OpcodeI32Const, 0x0, 3885 OpcodeI64Const, 0x1, 3886 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8SubU, 0x0, 0x8, // alignment=2^0, offset=8 3887 }, 3888 }, 3889 { 3890 name: "i64.atomic.rmw16.sub_u", 3891 body: []byte{ 3892 OpcodeI32Const, 0x0, 3893 OpcodeI64Const, 0x1, 3894 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16SubU, 0x1, 0x8, // alignment=2^1, offset=8 3895 }, 3896 }, 3897 { 3898 name: "i64.atomic.rmw32.sub_u", 3899 body: []byte{ 3900 OpcodeI32Const, 0x0, 3901 OpcodeI64Const, 0x1, 3902 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32SubU, 0x2, 0x8, // alignment=2^2, offset=8 3903 }, 3904 }, 3905 { 3906 name: "i64.atomic.rmw.sub", 3907 body: []byte{ 3908 OpcodeI32Const, 0x0, 3909 OpcodeI64Const, 0x1, 3910 OpcodeAtomicPrefix, OpcodeAtomicI64RmwSub, 0x3, 0x8, // alignment=2^3, offset=8 3911 }, 3912 }, 3913 { 3914 name: "i32.atomic.rmw8.and_u", 3915 body: []byte{ 3916 OpcodeI32Const, 0x0, 3917 OpcodeI32Const, 0x1, 3918 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8AndU, 0x0, 0x8, // alignment=2^0, offset=8 3919 }, 3920 }, 3921 { 3922 name: "i32.atomic.rmw16.and_u", 3923 body: []byte{ 3924 OpcodeI32Const, 0x0, 3925 OpcodeI32Const, 0x1, 3926 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16AndU, 0x1, 0x8, // alignment=2^1, offset=8 3927 }, 3928 }, 3929 { 3930 name: "i32.atomic.rmw.and", 3931 body: []byte{ 3932 OpcodeI32Const, 0x0, 3933 OpcodeI32Const, 0x1, 3934 OpcodeAtomicPrefix, OpcodeAtomicI32RmwAnd, 0x2, 0x8, // alignment=2^2, offset=8 3935 }, 3936 }, 3937 { 3938 name: "i64.atomic.rmw8.and_u", 3939 body: []byte{ 3940 OpcodeI32Const, 0x0, 3941 OpcodeI64Const, 0x1, 3942 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8AndU, 0x0, 0x8, // alignment=2^0, offset=8 3943 }, 3944 }, 3945 { 3946 name: "i64.atomic.rmw16.and_u", 3947 body: []byte{ 3948 OpcodeI32Const, 0x0, 3949 OpcodeI64Const, 0x1, 3950 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16AndU, 0x1, 0x8, // alignment=2^1, offset=8 3951 }, 3952 }, 3953 { 3954 name: "i64.atomic.rmw32.and_u", 3955 body: []byte{ 3956 OpcodeI32Const, 0x0, 3957 OpcodeI64Const, 0x1, 3958 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32AndU, 0x2, 0x8, // alignment=2^2, offset=8 3959 }, 3960 }, 3961 { 3962 name: "i64.atomic.rmw.and", 3963 body: []byte{ 3964 OpcodeI32Const, 0x0, 3965 OpcodeI64Const, 0x1, 3966 OpcodeAtomicPrefix, OpcodeAtomicI64RmwAnd, 0x3, 0x8, // alignment=2^3, offset=8 3967 }, 3968 }, 3969 { 3970 name: "i32.atomic.rmw8.or", 3971 body: []byte{ 3972 OpcodeI32Const, 0x0, 3973 OpcodeI32Const, 0x1, 3974 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8OrU, 0x0, 0x8, // alignment=2^0, offset=8 3975 }, 3976 }, 3977 { 3978 name: "i32.atomic.rmw16.or_u", 3979 body: []byte{ 3980 OpcodeI32Const, 0x0, 3981 OpcodeI32Const, 0x1, 3982 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16OrU, 0x1, 0x8, // alignment=2^1, offset=8 3983 }, 3984 }, 3985 { 3986 name: "i32.atomic.rmw.or", 3987 body: []byte{ 3988 OpcodeI32Const, 0x0, 3989 OpcodeI32Const, 0x1, 3990 OpcodeAtomicPrefix, OpcodeAtomicI32RmwOr, 0x2, 0x8, // alignment=2^2, offset=8 3991 }, 3992 }, 3993 { 3994 name: "i64.atomic.rmw8.or_u", 3995 body: []byte{ 3996 OpcodeI32Const, 0x0, 3997 OpcodeI64Const, 0x1, 3998 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8OrU, 0x0, 0x8, // alignment=2^0, offset=8 3999 }, 4000 }, 4001 { 4002 name: "i64.atomic.rmw16.or_u", 4003 body: []byte{ 4004 OpcodeI32Const, 0x0, 4005 OpcodeI64Const, 0x1, 4006 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16OrU, 0x1, 0x8, // alignment=2^1, offset=8 4007 }, 4008 }, 4009 { 4010 name: "i64.atomic.rmw32.or_u", 4011 body: []byte{ 4012 OpcodeI32Const, 0x0, 4013 OpcodeI64Const, 0x1, 4014 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32OrU, 0x2, 0x8, // alignment=2^2, offset=8 4015 }, 4016 }, 4017 { 4018 name: "i64.atomic.rmw.or", 4019 body: []byte{ 4020 OpcodeI32Const, 0x0, 4021 OpcodeI64Const, 0x1, 4022 OpcodeAtomicPrefix, OpcodeAtomicI64RmwOr, 0x3, 0x8, // alignment=2^3, offset=8 4023 }, 4024 }, 4025 { 4026 name: "i32.atomic.rmw8.xor_u", 4027 body: []byte{ 4028 OpcodeI32Const, 0x0, 4029 OpcodeI32Const, 0x1, 4030 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8XorU, 0x0, 0x8, // alignment=2^0, offset=8 4031 }, 4032 }, 4033 { 4034 name: "i32.atomic.rmw16.xor_u", 4035 body: []byte{ 4036 OpcodeI32Const, 0x0, 4037 OpcodeI32Const, 0x1, 4038 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16XorU, 0x1, 0x8, // alignment=2^1, offset=8 4039 }, 4040 }, 4041 { 4042 name: "i32.atomic.rmw.xor", 4043 body: []byte{ 4044 OpcodeI32Const, 0x0, 4045 OpcodeI32Const, 0x1, 4046 OpcodeAtomicPrefix, OpcodeAtomicI32RmwXor, 0x2, 0x8, // alignment=2^2, offset=8 4047 }, 4048 }, 4049 { 4050 name: "i64.atomic.rmw8.xor_u", 4051 body: []byte{ 4052 OpcodeI32Const, 0x0, 4053 OpcodeI64Const, 0x1, 4054 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8XorU, 0x0, 0x8, // alignment=2^0, offset=8 4055 }, 4056 }, 4057 { 4058 name: "i64.atomic.rmw16.xor_u", 4059 body: []byte{ 4060 OpcodeI32Const, 0x0, 4061 OpcodeI64Const, 0x1, 4062 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16XorU, 0x1, 0x8, // alignment=2^1, offset=8 4063 }, 4064 }, 4065 { 4066 name: "i64.atomic.rmw32.xor_u", 4067 body: []byte{ 4068 OpcodeI32Const, 0x0, 4069 OpcodeI64Const, 0x1, 4070 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32XorU, 0x2, 0x8, // alignment=2^2, offset=8 4071 }, 4072 }, 4073 { 4074 name: "i64.atomic.rmw.xor", 4075 body: []byte{ 4076 OpcodeI32Const, 0x0, 4077 OpcodeI64Const, 0x1, 4078 OpcodeAtomicPrefix, OpcodeAtomicI64RmwXor, 0x3, 0x8, // alignment=2^3, offset=8 4079 }, 4080 }, 4081 { 4082 name: "i32.atomic.rmw8.xchg_u", 4083 body: []byte{ 4084 OpcodeI32Const, 0x0, 4085 OpcodeI32Const, 0x1, 4086 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8XchgU, 0x0, 0x8, // alignment=2^0, offset=8 4087 }, 4088 }, 4089 { 4090 name: "i32.atomic.rmw16.xchg_u", 4091 body: []byte{ 4092 OpcodeI32Const, 0x0, 4093 OpcodeI32Const, 0x1, 4094 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16XchgU, 0x1, 0x8, // alignment=2^1, offset=8 4095 }, 4096 }, 4097 { 4098 name: "i32.atomic.rmw.xchg", 4099 body: []byte{ 4100 OpcodeI32Const, 0x0, 4101 OpcodeI32Const, 0x1, 4102 OpcodeAtomicPrefix, OpcodeAtomicI32RmwXchg, 0x2, 0x8, // alignment=2^2, offset=8 4103 }, 4104 }, 4105 { 4106 name: "i64.atomic.rmw8.xchg_u", 4107 body: []byte{ 4108 OpcodeI32Const, 0x0, 4109 OpcodeI64Const, 0x1, 4110 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8XchgU, 0x0, 0x8, // alignment=2^0, offset=8 4111 }, 4112 }, 4113 { 4114 name: "i64.atomic.rmw16.xchg_u", 4115 body: []byte{ 4116 OpcodeI32Const, 0x0, 4117 OpcodeI64Const, 0x1, 4118 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16XchgU, 0x1, 0x8, // alignment=2^1, offset=8 4119 }, 4120 }, 4121 { 4122 name: "i64.atomic.rmw32.xchg_u", 4123 body: []byte{ 4124 OpcodeI32Const, 0x0, 4125 OpcodeI64Const, 0x1, 4126 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32XchgU, 0x2, 0x8, // alignment=2^2, offset=8 4127 }, 4128 }, 4129 { 4130 name: "i64.atomic.rmw.xchg", 4131 body: []byte{ 4132 OpcodeI32Const, 0x0, 4133 OpcodeI64Const, 0x1, 4134 OpcodeAtomicPrefix, OpcodeAtomicI64RmwXchg, 0x3, 0x8, // alignment=2^3, offset=8 4135 }, 4136 }, 4137 { 4138 name: "i32.atomic.rmw8.cmpxchg_u", 4139 body: []byte{ 4140 OpcodeI32Const, 0x0, 4141 OpcodeI32Const, 0x1, 4142 OpcodeI32Const, 0x2, 4143 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8CmpxchgU, 0x0, 0x8, // alignment=2^0, offset=8 4144 }, 4145 }, 4146 { 4147 name: "i32.atomic.rmw16.cmpxchg_u", 4148 body: []byte{ 4149 OpcodeI32Const, 0x0, 4150 OpcodeI32Const, 0x1, 4151 OpcodeI32Const, 0x2, 4152 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16CmpxchgU, 0x1, 0x8, // alignment=2^1, offset=8 4153 }, 4154 }, 4155 { 4156 name: "i32.atomic.rmw.cmpxchg", 4157 body: []byte{ 4158 OpcodeI32Const, 0x0, 4159 OpcodeI32Const, 0x1, 4160 OpcodeI32Const, 0x2, 4161 OpcodeAtomicPrefix, OpcodeAtomicI32RmwCmpxchg, 0x2, 0x8, // alignment=2^2, offset=8 4162 }, 4163 }, 4164 { 4165 name: "i64.atomic.rmw8.xchg_u", 4166 body: []byte{ 4167 OpcodeI32Const, 0x0, 4168 OpcodeI64Const, 0x1, 4169 OpcodeI64Const, 0x2, 4170 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8CmpxchgU, 0x0, 0x8, // alignment=2^0, offset=8 4171 }, 4172 }, 4173 { 4174 name: "i64.atomic.rmw16.cmpxchg_u", 4175 body: []byte{ 4176 OpcodeI32Const, 0x0, 4177 OpcodeI64Const, 0x1, 4178 OpcodeI64Const, 0x2, 4179 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16CmpxchgU, 0x1, 0x8, // alignment=2^1, offset=8 4180 }, 4181 }, 4182 { 4183 name: "i64.atomic.rmw32.cmpxchg_u", 4184 body: []byte{ 4185 OpcodeI32Const, 0x0, 4186 OpcodeI64Const, 0x1, 4187 OpcodeI64Const, 0x1, 4188 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32CmpxchgU, 0x2, 0x8, // alignment=2^2, offset=8 4189 }, 4190 }, 4191 { 4192 name: "i64.atomic.rmw.cmpxchg", 4193 body: []byte{ 4194 OpcodeI32Const, 0x0, 4195 OpcodeI64Const, 0x1, 4196 OpcodeI64Const, 0x2, 4197 OpcodeAtomicPrefix, OpcodeAtomicI64RmwCmpxchg, 0x3, 0x8, // alignment=2^3, offset=8 4198 }, 4199 }, 4200 { 4201 name: "memory.atomic.wait32", 4202 body: []byte{ 4203 OpcodeI32Const, 0x0, 4204 OpcodeI32Const, 0x1, 4205 OpcodeI64Const, 0x2, 4206 OpcodeAtomicPrefix, OpcodeAtomicMemoryWait32, 0x2, 0x8, // alignment=2^2, offset=8 4207 }, 4208 }, 4209 { 4210 name: "memory.atomic.wait64", 4211 body: []byte{ 4212 OpcodeI32Const, 0x0, 4213 OpcodeI64Const, 0x1, 4214 OpcodeI64Const, 0x2, 4215 OpcodeAtomicPrefix, OpcodeAtomicMemoryWait64, 0x3, 0x8, // alignment=2^3, offset=8 4216 }, 4217 }, 4218 { 4219 name: "memory.atomic.notify", 4220 body: []byte{ 4221 OpcodeI32Const, 0x0, 4222 OpcodeI32Const, 0x1, 4223 OpcodeAtomicPrefix, OpcodeAtomicMemoryNotify, 0x2, 0x8, // alignment=2^2, offset=8 4224 }, 4225 }, 4226 { 4227 name: "memory.atomic.fence", 4228 body: []byte{ 4229 OpcodeAtomicPrefix, OpcodeAtomicFence, 0x0, 4230 }, 4231 noDropBeforeReturn: true, 4232 }, 4233 } 4234 4235 for _, tt := range tests { 4236 tc := tt 4237 t.Run(tc.name, func(t *testing.T) { 4238 body := append([]byte{}, tc.body...) 4239 if !tt.noDropBeforeReturn { 4240 body = append(body, OpcodeDrop) 4241 } 4242 body = append(body, OpcodeEnd) 4243 m := &Module{ 4244 TypeSection: []FunctionType{v_v}, 4245 FunctionSection: []Index{0}, 4246 CodeSection: []Code{{Body: body}}, 4247 } 4248 4249 t.Run("with memory", func(t *testing.T) { 4250 err := m.validateFunction(&stacks{}, api.CoreFeaturesV2, 4251 0, []Index{0}, nil, &Memory{}, []Table{}, nil, bytes.NewReader(nil)) 4252 require.NoError(t, err) 4253 }) 4254 4255 t.Run("without memory", func(t *testing.T) { 4256 err := m.validateFunction(&stacks{}, api.CoreFeaturesV2, 4257 0, []Index{0}, nil, nil, []Table{}, nil, bytes.NewReader(nil)) 4258 // Only fence doesn't require memory 4259 if tc.name == "memory.atomic.fence" { 4260 require.NoError(t, err) 4261 } else { 4262 require.Error(t, err, fmt.Sprintf("memory must exist for %s", tc.name)) 4263 } 4264 }) 4265 }) 4266 } 4267 }) 4268 4269 t.Run("atomic.fence bad immediate", func(t *testing.T) { 4270 body := []byte{ 4271 OpcodeAtomicPrefix, OpcodeAtomicFence, 0x1, 4272 OpcodeEnd, 4273 } 4274 m := &Module{ 4275 TypeSection: []FunctionType{v_v}, 4276 FunctionSection: []Index{0}, 4277 CodeSection: []Code{{Body: body}}, 4278 } 4279 err := m.validateFunction(&stacks{}, api.CoreFeaturesV2, 4280 0, []Index{0}, nil, &Memory{}, []Table{}, nil, bytes.NewReader(nil)) 4281 require.Error(t, err, "invalid immediate value for atomic.fence") 4282 }) 4283 4284 t.Run("bad alignment", func(t *testing.T) { 4285 tests := []struct { 4286 name string 4287 body []byte 4288 noDropBeforeReturn bool 4289 }{ 4290 { 4291 name: "i32.atomic.load8_u", 4292 body: []byte{ 4293 OpcodeI32Const, 0x0, 4294 OpcodeAtomicPrefix, OpcodeAtomicI32Load8U, 0x1, 0x8, // alignment=2^1, offset=8 4295 }, 4296 }, 4297 { 4298 name: "i32.atomic.load16_u", 4299 body: []byte{ 4300 OpcodeI32Const, 0x0, 4301 OpcodeAtomicPrefix, OpcodeAtomicI32Load16U, 0x2, 0x8, // alignment=2^2, offset=8 4302 }, 4303 }, 4304 { 4305 name: "i32.atomic.load", 4306 body: []byte{ 4307 OpcodeI32Const, 0x0, 4308 OpcodeAtomicPrefix, OpcodeAtomicI32Load, 0x3, 0x8, // alignment=2^3, offset=8 4309 }, 4310 }, 4311 { 4312 name: "i64.atomic.load8_u", 4313 body: []byte{ 4314 OpcodeI32Const, 0x0, 4315 OpcodeAtomicPrefix, OpcodeAtomicI64Load8U, 0x1, 0x8, // alignment=2^1, offset=8 4316 }, 4317 }, 4318 { 4319 name: "i64.atomic.load16_u", 4320 body: []byte{ 4321 OpcodeI32Const, 0x0, 4322 OpcodeAtomicPrefix, OpcodeAtomicI64Load16U, 0x2, 0x8, // alignment=2^2, offset=8 4323 }, 4324 }, 4325 { 4326 name: "i64.atomic.load32_u", 4327 body: []byte{ 4328 OpcodeI32Const, 0x0, 4329 OpcodeAtomicPrefix, OpcodeAtomicI64Load32U, 0x3, 0x8, // alignment=2^3, offset=8 4330 }, 4331 }, 4332 { 4333 name: "i64.atomic.load", 4334 body: []byte{ 4335 OpcodeI32Const, 0x0, 4336 OpcodeAtomicPrefix, OpcodeAtomicI64Load, 0x4, 0x8, // alignment=2^4, offset=8 4337 }, 4338 }, 4339 { 4340 name: "i32.atomic.store8", 4341 body: []byte{ 4342 OpcodeI32Const, 0x1, 4343 OpcodeI32Const, 0x0, 4344 OpcodeAtomicPrefix, OpcodeAtomicI32Store8, 0x1, 0x8, // alignment=2^1, offset=8 4345 }, 4346 noDropBeforeReturn: true, 4347 }, 4348 { 4349 name: "i32.atomic.store16", 4350 body: []byte{ 4351 OpcodeI32Const, 0x1, 4352 OpcodeI32Const, 0x0, 4353 OpcodeAtomicPrefix, OpcodeAtomicI32Store16, 0x2, 0x8, // alignment=2^2, offset=8 4354 }, 4355 noDropBeforeReturn: true, 4356 }, 4357 { 4358 name: "i32.atomic.store", 4359 body: []byte{ 4360 OpcodeI32Const, 0x1, 4361 OpcodeI32Const, 0x0, 4362 OpcodeAtomicPrefix, OpcodeAtomicI32Store, 0x3, 0x8, // alignment=2^3, offset=8 4363 }, 4364 noDropBeforeReturn: true, 4365 }, 4366 { 4367 name: "i64.atomic.store8", 4368 body: []byte{ 4369 OpcodeI32Const, 0x0, 4370 OpcodeI64Const, 0x1, 4371 OpcodeAtomicPrefix, OpcodeAtomicI64Store8, 0x1, 0x8, // alignment=2^1, offset=8 4372 }, 4373 noDropBeforeReturn: true, 4374 }, 4375 { 4376 name: "i64.atomic.store16", 4377 body: []byte{ 4378 OpcodeI32Const, 0x0, 4379 OpcodeI64Const, 0x1, 4380 OpcodeAtomicPrefix, OpcodeAtomicI64Store16, 0x2, 0x8, // alignment=2^2, offset=8 4381 }, 4382 noDropBeforeReturn: true, 4383 }, 4384 { 4385 name: "i64.atomic.store32", 4386 body: []byte{ 4387 OpcodeI32Const, 0x0, 4388 OpcodeI64Const, 0x1, 4389 OpcodeAtomicPrefix, OpcodeAtomicI64Store32, 0x3, 0x8, // alignment=2^3, offset=8 4390 }, 4391 noDropBeforeReturn: true, 4392 }, 4393 { 4394 name: "i64.atomic.store", 4395 body: []byte{ 4396 OpcodeI32Const, 0x0, 4397 OpcodeI64Const, 0x1, 4398 OpcodeAtomicPrefix, OpcodeAtomicI64Store, 0x4, 0x8, // alignment=2^4, offset=8 4399 }, 4400 noDropBeforeReturn: true, 4401 }, 4402 { 4403 name: "i32.atomic.rmw8.add_u", 4404 body: []byte{ 4405 OpcodeI32Const, 0x0, 4406 OpcodeI32Const, 0x1, 4407 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8AddU, 0x1, 0x8, // alignment=2^1, offset=8 4408 }, 4409 }, 4410 { 4411 name: "i32.atomic.rmw16.add_u", 4412 body: []byte{ 4413 OpcodeI32Const, 0x0, 4414 OpcodeI32Const, 0x1, 4415 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16AddU, 0x2, 0x8, // alignment=2^2, offset=8 4416 }, 4417 }, 4418 { 4419 name: "i32.atomic.rmw.add", 4420 body: []byte{ 4421 OpcodeI32Const, 0x0, 4422 OpcodeI32Const, 0x1, 4423 OpcodeAtomicPrefix, OpcodeAtomicI32RmwAdd, 0x3, 0x8, // alignment=2^3, offset=8 4424 }, 4425 }, 4426 { 4427 name: "i64.atomic.rmw8.add_u", 4428 body: []byte{ 4429 OpcodeI32Const, 0x0, 4430 OpcodeI64Const, 0x1, 4431 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8AddU, 0x1, 0x8, // alignment=2^1, offset=8 4432 }, 4433 }, 4434 { 4435 name: "i64.atomic.rmw16.add_u", 4436 body: []byte{ 4437 OpcodeI32Const, 0x0, 4438 OpcodeI64Const, 0x1, 4439 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16AddU, 0x2, 0x8, // alignment=2^2, offset=8 4440 }, 4441 }, 4442 { 4443 name: "i64.atomic.rmw32.add_u", 4444 body: []byte{ 4445 OpcodeI32Const, 0x0, 4446 OpcodeI64Const, 0x1, 4447 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32AddU, 0x3, 0x8, // alignment=2^3, offset=8 4448 }, 4449 }, 4450 { 4451 name: "i64.atomic.rmw.add", 4452 body: []byte{ 4453 OpcodeI32Const, 0x0, 4454 OpcodeI64Const, 0x1, 4455 OpcodeAtomicPrefix, OpcodeAtomicI64RmwAdd, 0x4, 0x8, // alignment=2^4, offset=8 4456 }, 4457 }, 4458 { 4459 name: "i32.atomic.rmw8.sub_u", 4460 body: []byte{ 4461 OpcodeI32Const, 0x0, 4462 OpcodeI32Const, 0x1, 4463 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8SubU, 0x1, 0x8, // alignment=2^1, offset=8 4464 }, 4465 }, 4466 { 4467 name: "i32.atomic.rmw16.sub_u", 4468 body: []byte{ 4469 OpcodeI32Const, 0x0, 4470 OpcodeI32Const, 0x1, 4471 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16SubU, 0x2, 0x8, // alignment=2^2, offset=8 4472 }, 4473 }, 4474 { 4475 name: "i32.atomic.rmw.sub", 4476 body: []byte{ 4477 OpcodeI32Const, 0x0, 4478 OpcodeI32Const, 0x1, 4479 OpcodeAtomicPrefix, OpcodeAtomicI32RmwSub, 0x3, 0x8, // alignment=2^3, offset=8 4480 }, 4481 }, 4482 { 4483 name: "i64.atomic.rmw8.sub_u", 4484 body: []byte{ 4485 OpcodeI32Const, 0x0, 4486 OpcodeI64Const, 0x1, 4487 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8SubU, 0x1, 0x8, // alignment=2^1, offset=8 4488 }, 4489 }, 4490 { 4491 name: "i64.atomic.rmw16.sub_u", 4492 body: []byte{ 4493 OpcodeI32Const, 0x0, 4494 OpcodeI64Const, 0x1, 4495 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16SubU, 0x2, 0x8, // alignment=2^2, offset=8 4496 }, 4497 }, 4498 { 4499 name: "i64.atomic.rmw32.sub_u", 4500 body: []byte{ 4501 OpcodeI32Const, 0x0, 4502 OpcodeI64Const, 0x1, 4503 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32SubU, 0x3, 0x8, // alignment=2^3, offset=8 4504 }, 4505 }, 4506 { 4507 name: "i64.atomic.rmw.sub", 4508 body: []byte{ 4509 OpcodeI32Const, 0x0, 4510 OpcodeI64Const, 0x1, 4511 OpcodeAtomicPrefix, OpcodeAtomicI64RmwSub, 0x4, 0x8, // alignment=2^4, offset=8 4512 }, 4513 }, 4514 { 4515 name: "i32.atomic.rmw8.and_u", 4516 body: []byte{ 4517 OpcodeI32Const, 0x0, 4518 OpcodeI32Const, 0x1, 4519 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8AndU, 0x1, 0x8, // alignment=2^1, offset=8 4520 }, 4521 }, 4522 { 4523 name: "i32.atomic.rmw16.and_u", 4524 body: []byte{ 4525 OpcodeI32Const, 0x0, 4526 OpcodeI32Const, 0x1, 4527 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16AndU, 0x2, 0x8, // alignment=2^2, offset=8 4528 }, 4529 }, 4530 { 4531 name: "i32.atomic.rmw.and", 4532 body: []byte{ 4533 OpcodeI32Const, 0x0, 4534 OpcodeI32Const, 0x1, 4535 OpcodeAtomicPrefix, OpcodeAtomicI32RmwAnd, 0x3, 0x8, // alignment=2^3, offset=8 4536 }, 4537 }, 4538 { 4539 name: "i64.atomic.rmw8.and_u", 4540 body: []byte{ 4541 OpcodeI32Const, 0x0, 4542 OpcodeI64Const, 0x1, 4543 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8AndU, 0x1, 0x8, // alignment=2^1, offset=8 4544 }, 4545 }, 4546 { 4547 name: "i64.atomic.rmw16.and_u", 4548 body: []byte{ 4549 OpcodeI32Const, 0x0, 4550 OpcodeI64Const, 0x1, 4551 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16AndU, 0x2, 0x8, // alignment=2^2, offset=8 4552 }, 4553 }, 4554 { 4555 name: "i64.atomic.rmw32.and_u", 4556 body: []byte{ 4557 OpcodeI32Const, 0x0, 4558 OpcodeI64Const, 0x1, 4559 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32AndU, 0x3, 0x8, // alignment=2^3, offset=8 4560 }, 4561 }, 4562 { 4563 name: "i64.atomic.rmw.and", 4564 body: []byte{ 4565 OpcodeI32Const, 0x0, 4566 OpcodeI64Const, 0x1, 4567 OpcodeAtomicPrefix, OpcodeAtomicI64RmwAnd, 0x4, 0x8, // alignment=2^4, offset=8 4568 }, 4569 }, 4570 { 4571 name: "i32.atomic.rmw8.or", 4572 body: []byte{ 4573 OpcodeI32Const, 0x0, 4574 OpcodeI32Const, 0x1, 4575 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8OrU, 0x1, 0x8, // alignment=2^1, offset=8 4576 }, 4577 }, 4578 { 4579 name: "i32.atomic.rmw16.or_u", 4580 body: []byte{ 4581 OpcodeI32Const, 0x0, 4582 OpcodeI32Const, 0x1, 4583 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16OrU, 0x2, 0x8, // alignment=2^2, offset=8 4584 }, 4585 }, 4586 { 4587 name: "i32.atomic.rmw.or", 4588 body: []byte{ 4589 OpcodeI32Const, 0x0, 4590 OpcodeI32Const, 0x1, 4591 OpcodeAtomicPrefix, OpcodeAtomicI32RmwOr, 0x3, 0x8, // alignment=2^3, offset=8 4592 }, 4593 }, 4594 { 4595 name: "i64.atomic.rmw8.or_u", 4596 body: []byte{ 4597 OpcodeI32Const, 0x0, 4598 OpcodeI64Const, 0x1, 4599 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8OrU, 0x1, 0x8, // alignment=2^1, offset=8 4600 }, 4601 }, 4602 { 4603 name: "i64.atomic.rmw16.or_u", 4604 body: []byte{ 4605 OpcodeI32Const, 0x0, 4606 OpcodeI64Const, 0x1, 4607 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16OrU, 0x2, 0x8, // alignment=2^2, offset=8 4608 }, 4609 }, 4610 { 4611 name: "i64.atomic.rmw32.or_u", 4612 body: []byte{ 4613 OpcodeI32Const, 0x0, 4614 OpcodeI64Const, 0x1, 4615 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32OrU, 0x3, 0x8, // alignment=2^3, offset=8 4616 }, 4617 }, 4618 { 4619 name: "i64.atomic.rmw.or", 4620 body: []byte{ 4621 OpcodeI32Const, 0x0, 4622 OpcodeI64Const, 0x1, 4623 OpcodeAtomicPrefix, OpcodeAtomicI64RmwOr, 0x4, 0x8, // alignment=2^4, offset=8 4624 }, 4625 }, 4626 { 4627 name: "i32.atomic.rmw8.xor_u", 4628 body: []byte{ 4629 OpcodeI32Const, 0x0, 4630 OpcodeI32Const, 0x1, 4631 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8XorU, 0x1, 0x8, // alignment=2^1, offset=8 4632 }, 4633 }, 4634 { 4635 name: "i32.atomic.rmw16.xor_u", 4636 body: []byte{ 4637 OpcodeI32Const, 0x0, 4638 OpcodeI32Const, 0x1, 4639 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16XorU, 0x2, 0x8, // alignment=2^2, offset=8 4640 }, 4641 }, 4642 { 4643 name: "i32.atomic.rmw.xor", 4644 body: []byte{ 4645 OpcodeI32Const, 0x0, 4646 OpcodeI32Const, 0x1, 4647 OpcodeAtomicPrefix, OpcodeAtomicI32RmwXor, 0x3, 0x8, // alignment=2^3, offset=8 4648 }, 4649 }, 4650 { 4651 name: "i64.atomic.rmw8.xor_u", 4652 body: []byte{ 4653 OpcodeI32Const, 0x0, 4654 OpcodeI64Const, 0x1, 4655 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8XorU, 0x1, 0x8, // alignment=2^1, offset=8 4656 }, 4657 }, 4658 { 4659 name: "i64.atomic.rmw16.xor_u", 4660 body: []byte{ 4661 OpcodeI32Const, 0x0, 4662 OpcodeI64Const, 0x1, 4663 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16XorU, 0x2, 0x8, // alignment=2^2, offset=8 4664 }, 4665 }, 4666 { 4667 name: "i64.atomic.rmw32.xor_u", 4668 body: []byte{ 4669 OpcodeI32Const, 0x0, 4670 OpcodeI64Const, 0x1, 4671 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32XorU, 0x3, 0x8, // alignment=2^3, offset=8 4672 }, 4673 }, 4674 { 4675 name: "i64.atomic.rmw.xor", 4676 body: []byte{ 4677 OpcodeI32Const, 0x0, 4678 OpcodeI64Const, 0x1, 4679 OpcodeAtomicPrefix, OpcodeAtomicI64RmwXor, 0x4, 0x8, // alignment=2^4, offset=8 4680 }, 4681 }, 4682 { 4683 name: "i32.atomic.rmw8.xchg_u", 4684 body: []byte{ 4685 OpcodeI32Const, 0x0, 4686 OpcodeI32Const, 0x1, 4687 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8XchgU, 0x1, 0x8, // alignment=2^1, offset=8 4688 }, 4689 }, 4690 { 4691 name: "i32.atomic.rmw16.xchg_u", 4692 body: []byte{ 4693 OpcodeI32Const, 0x0, 4694 OpcodeI32Const, 0x1, 4695 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16XchgU, 0x2, 0x8, // alignment=2^2, offset=8 4696 }, 4697 }, 4698 { 4699 name: "i32.atomic.rmw.xchg", 4700 body: []byte{ 4701 OpcodeI32Const, 0x0, 4702 OpcodeI32Const, 0x1, 4703 OpcodeAtomicPrefix, OpcodeAtomicI32RmwXchg, 0x3, 0x8, // alignment=2^3, offset=8 4704 }, 4705 }, 4706 { 4707 name: "i64.atomic.rmw8.xchg_u", 4708 body: []byte{ 4709 OpcodeI32Const, 0x0, 4710 OpcodeI64Const, 0x1, 4711 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8XchgU, 0x1, 0x8, // alignment=2^1, offset=8 4712 }, 4713 }, 4714 { 4715 name: "i64.atomic.rmw16.xchg_u", 4716 body: []byte{ 4717 OpcodeI32Const, 0x0, 4718 OpcodeI64Const, 0x1, 4719 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16XchgU, 0x2, 0x8, // alignment=2^2, offset=8 4720 }, 4721 }, 4722 { 4723 name: "i64.atomic.rmw32.xchg_u", 4724 body: []byte{ 4725 OpcodeI32Const, 0x0, 4726 OpcodeI64Const, 0x1, 4727 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32XchgU, 0x3, 0x8, // alignment=2^3, offset=8 4728 }, 4729 }, 4730 { 4731 name: "i64.atomic.rmw.xchg", 4732 body: []byte{ 4733 OpcodeI32Const, 0x0, 4734 OpcodeI64Const, 0x1, 4735 OpcodeAtomicPrefix, OpcodeAtomicI64RmwXchg, 0x4, 0x8, // alignment=2^4, offset=8 4736 }, 4737 }, 4738 { 4739 name: "i32.atomic.rmw8.cmpxchg_u", 4740 body: []byte{ 4741 OpcodeI32Const, 0x0, 4742 OpcodeI32Const, 0x1, 4743 OpcodeI32Const, 0x2, 4744 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8CmpxchgU, 0x1, 0x8, // alignment=2^1, offset=8 4745 }, 4746 }, 4747 { 4748 name: "i32.atomic.rmw16.cmpxchg_u", 4749 body: []byte{ 4750 OpcodeI32Const, 0x0, 4751 OpcodeI32Const, 0x1, 4752 OpcodeI32Const, 0x2, 4753 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16CmpxchgU, 0x2, 0x8, // alignment=2^2, offset=8 4754 }, 4755 }, 4756 { 4757 name: "i32.atomic.rmw.cmpxchg", 4758 body: []byte{ 4759 OpcodeI32Const, 0x0, 4760 OpcodeI32Const, 0x1, 4761 OpcodeI32Const, 0x2, 4762 OpcodeAtomicPrefix, OpcodeAtomicI32RmwCmpxchg, 0x3, 0x8, // alignment=2^3, offset=8 4763 }, 4764 }, 4765 { 4766 name: "i64.atomic.rmw8.xchg_u", 4767 body: []byte{ 4768 OpcodeI32Const, 0x0, 4769 OpcodeI64Const, 0x1, 4770 OpcodeI64Const, 0x2, 4771 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8CmpxchgU, 0x1, 0x8, // alignment=2^1, offset=8 4772 }, 4773 }, 4774 { 4775 name: "i64.atomic.rmw16.cmpxchg_u", 4776 body: []byte{ 4777 OpcodeI32Const, 0x0, 4778 OpcodeI64Const, 0x1, 4779 OpcodeI64Const, 0x2, 4780 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16CmpxchgU, 0x2, 0x8, // alignment=2^2, offset=8 4781 }, 4782 }, 4783 { 4784 name: "i64.atomic.rmw32.cmpxchg_u", 4785 body: []byte{ 4786 OpcodeI32Const, 0x0, 4787 OpcodeI64Const, 0x1, 4788 OpcodeI64Const, 0x1, 4789 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32CmpxchgU, 0x3, 0x8, // alignment=2^3, offset=8 4790 }, 4791 }, 4792 { 4793 name: "i64.atomic.rmw.cmpxchg", 4794 body: []byte{ 4795 OpcodeI32Const, 0x0, 4796 OpcodeI64Const, 0x1, 4797 OpcodeI64Const, 0x2, 4798 OpcodeAtomicPrefix, OpcodeAtomicI64RmwCmpxchg, 0x4, 0x8, // alignment=2^4, offset=8 4799 }, 4800 }, 4801 { 4802 name: "memory.atomic.wait32", 4803 body: []byte{ 4804 OpcodeI32Const, 0x0, 4805 OpcodeI32Const, 0x1, 4806 OpcodeI64Const, 0x2, 4807 OpcodeAtomicPrefix, OpcodeAtomicMemoryWait32, 0x3, 0x8, // alignment=2^3, offset=8 4808 }, 4809 }, 4810 { 4811 name: "memory.atomic.wait64", 4812 body: []byte{ 4813 OpcodeI32Const, 0x0, 4814 OpcodeI64Const, 0x1, 4815 OpcodeI64Const, 0x2, 4816 OpcodeAtomicPrefix, OpcodeAtomicMemoryWait64, 0x4, 0x8, // alignment=2^4, offset=8 4817 }, 4818 }, 4819 { 4820 name: "memory.atomic.notify", 4821 body: []byte{ 4822 OpcodeI32Const, 0x0, 4823 OpcodeI32Const, 0x1, 4824 OpcodeAtomicPrefix, OpcodeAtomicMemoryNotify, 0x3, 0x8, // alignment=2^3, offset=8 4825 }, 4826 }, 4827 } 4828 4829 for _, tt := range tests { 4830 tc := tt 4831 t.Run(tc.name, func(t *testing.T) { 4832 body := append([]byte{}, tc.body...) 4833 if !tt.noDropBeforeReturn { 4834 body = append(body, OpcodeDrop) 4835 } 4836 body = append(body, OpcodeEnd) 4837 m := &Module{ 4838 TypeSection: []FunctionType{v_v}, 4839 FunctionSection: []Index{0}, 4840 CodeSection: []Code{{Body: body}}, 4841 } 4842 err := m.validateFunction(&stacks{}, api.CoreFeaturesV2, 4843 0, []Index{0}, nil, &Memory{}, []Table{}, nil, bytes.NewReader(nil)) 4844 require.Error(t, err, "invalid memory alignment") 4845 }) 4846 } 4847 }) 4848 }