github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/internal/wasm/func_validation_test.go (about) 1 package wasm 2 3 import ( 4 "bytes" 5 "fmt" 6 "testing" 7 8 "github.com/wasilibs/wazerox/api" 9 "github.com/wasilibs/wazerox/experimental" 10 "github.com/wasilibs/wazerox/internal/leb128" 11 "github.com/wasilibs/wazerox/internal/testing/require" 12 ) 13 14 func TestModule_ValidateFunction_validateFunctionWithMaxStackValues(t *testing.T) { 15 const max = 100 16 const valuesNum = max + 1 17 18 // Compile a function which has max+1 const instructions. 19 var body []byte 20 for i := 0; i < valuesNum; i++ { 21 body = append(body, OpcodeI32Const, 1) 22 } 23 24 // Drop all the consts so that if the max is higher, this function body would be sound. 25 for i := 0; i < valuesNum; i++ { 26 body = append(body, OpcodeDrop) 27 } 28 29 // Plus all functions must end with End opcode. 30 body = append(body, OpcodeEnd) 31 32 m := &Module{ 33 TypeSection: []FunctionType{v_v}, 34 FunctionSection: []Index{0}, 35 CodeSection: []Code{{Body: body}}, 36 } 37 38 t.Run("not exceed", func(t *testing.T) { 39 err := m.validateFunctionWithMaxStackValues(&stacks{}, api.CoreFeaturesV1, 40 0, []Index{0}, nil, nil, nil, max+1, nil, bytes.NewReader(nil)) 41 require.NoError(t, err) 42 }) 43 t.Run("exceed", func(t *testing.T) { 44 err := m.validateFunctionWithMaxStackValues(&stacks{}, api.CoreFeaturesV1, 45 0, []Index{0}, nil, nil, nil, max, nil, bytes.NewReader(nil)) 46 require.Error(t, err) 47 expMsg := fmt.Sprintf("function may have %d stack values, which exceeds limit %d", valuesNum, max) 48 require.Equal(t, expMsg, err.Error()) 49 }) 50 } 51 52 func TestModule_ValidateFunction_SignExtensionOps(t *testing.T) { 53 tests := []struct { 54 input Opcode 55 expectedErrOnDisable string 56 }{ 57 { 58 input: OpcodeI32Extend8S, 59 expectedErrOnDisable: "i32.extend8_s invalid as feature \"sign-extension-ops\" is disabled", 60 }, 61 { 62 input: OpcodeI32Extend16S, 63 expectedErrOnDisable: "i32.extend16_s invalid as feature \"sign-extension-ops\" is disabled", 64 }, 65 { 66 input: OpcodeI64Extend8S, 67 expectedErrOnDisable: "i64.extend8_s invalid as feature \"sign-extension-ops\" is disabled", 68 }, 69 { 70 input: OpcodeI64Extend16S, 71 expectedErrOnDisable: "i64.extend16_s invalid as feature \"sign-extension-ops\" is disabled", 72 }, 73 { 74 input: OpcodeI64Extend32S, 75 expectedErrOnDisable: "i64.extend32_s invalid as feature \"sign-extension-ops\" is disabled", 76 }, 77 } 78 79 for _, tt := range tests { 80 tc := tt 81 t.Run(InstructionName(tc.input), func(t *testing.T) { 82 t.Run("disabled", func(t *testing.T) { 83 m := &Module{ 84 TypeSection: []FunctionType{v_v}, 85 FunctionSection: []Index{0}, 86 CodeSection: []Code{{Body: []byte{tc.input}}}, 87 } 88 err := m.validateFunction(&stacks{}, api.CoreFeaturesV1, 89 0, []Index{0}, nil, nil, nil, nil, 90 bytes.NewReader(nil)) 91 require.EqualError(t, err, tc.expectedErrOnDisable) 92 }) 93 t.Run("enabled", func(t *testing.T) { 94 is32bit := tc.input == OpcodeI32Extend8S || tc.input == OpcodeI32Extend16S 95 var body []byte 96 if is32bit { 97 body = append(body, OpcodeI32Const) 98 } else { 99 body = append(body, OpcodeI64Const) 100 } 101 body = append(body, tc.input, 123, OpcodeDrop, OpcodeEnd) 102 m := &Module{ 103 TypeSection: []FunctionType{v_v}, 104 FunctionSection: []Index{0}, 105 CodeSection: []Code{{Body: body}}, 106 } 107 err := m.validateFunction(&stacks{}, api.CoreFeatureSignExtensionOps, 108 0, []Index{0}, nil, nil, nil, 109 nil, bytes.NewReader(nil)) 110 require.NoError(t, err) 111 }) 112 }) 113 } 114 } 115 116 func TestModule_ValidateFunction_NonTrappingFloatToIntConversion(t *testing.T) { 117 tests := []struct { 118 input Opcode 119 expectedErrOnDisable string 120 }{ 121 { 122 input: OpcodeMiscI32TruncSatF32S, 123 expectedErrOnDisable: "i32.trunc_sat_f32_s invalid as feature \"nontrapping-float-to-int-conversion\" is disabled", 124 }, 125 { 126 input: OpcodeMiscI32TruncSatF32U, 127 expectedErrOnDisable: "i32.trunc_sat_f32_u invalid as feature \"nontrapping-float-to-int-conversion\" is disabled", 128 }, 129 { 130 input: OpcodeMiscI32TruncSatF64S, 131 expectedErrOnDisable: "i32.trunc_sat_f64_s invalid as feature \"nontrapping-float-to-int-conversion\" is disabled", 132 }, 133 { 134 input: OpcodeMiscI32TruncSatF64U, 135 expectedErrOnDisable: "i32.trunc_sat_f64_u invalid as feature \"nontrapping-float-to-int-conversion\" is disabled", 136 }, 137 { 138 input: OpcodeMiscI64TruncSatF32S, 139 expectedErrOnDisable: "i64.trunc_sat_f32_s invalid as feature \"nontrapping-float-to-int-conversion\" is disabled", 140 }, 141 { 142 input: OpcodeMiscI64TruncSatF32U, 143 expectedErrOnDisable: "i64.trunc_sat_f32_u invalid as feature \"nontrapping-float-to-int-conversion\" is disabled", 144 }, 145 { 146 input: OpcodeMiscI64TruncSatF64S, 147 expectedErrOnDisable: "i64.trunc_sat_f64_s invalid as feature \"nontrapping-float-to-int-conversion\" is disabled", 148 }, 149 { 150 input: OpcodeMiscI64TruncSatF64U, 151 expectedErrOnDisable: "i64.trunc_sat_f64_u invalid as feature \"nontrapping-float-to-int-conversion\" is disabled", 152 }, 153 } 154 155 for _, tt := range tests { 156 tc := tt 157 t.Run(InstructionName(tc.input), func(t *testing.T) { 158 t.Run("disabled", func(t *testing.T) { 159 m := &Module{ 160 TypeSection: []FunctionType{v_v}, 161 FunctionSection: []Index{0}, 162 CodeSection: []Code{{Body: []byte{OpcodeMiscPrefix, tc.input}}}, 163 } 164 err := m.validateFunction(&stacks{}, api.CoreFeaturesV1, 165 0, []Index{0}, nil, nil, nil, nil, bytes.NewReader(nil)) 166 require.EqualError(t, err, tc.expectedErrOnDisable) 167 }) 168 t.Run("enabled", func(t *testing.T) { 169 var body []byte 170 switch tc.input { 171 case OpcodeMiscI32TruncSatF32S, OpcodeMiscI32TruncSatF32U, OpcodeMiscI64TruncSatF32S, OpcodeMiscI64TruncSatF32U: 172 body = []byte{OpcodeF32Const, 1, 2, 3, 4} 173 case OpcodeMiscI32TruncSatF64S, OpcodeMiscI32TruncSatF64U, OpcodeMiscI64TruncSatF64S, OpcodeMiscI64TruncSatF64U: 174 body = []byte{OpcodeF64Const, 1, 2, 3, 4, 5, 6, 7, 8} 175 } 176 body = append(body, OpcodeMiscPrefix, tc.input, OpcodeDrop, OpcodeEnd) 177 178 m := &Module{ 179 TypeSection: []FunctionType{v_v}, 180 FunctionSection: []Index{0}, 181 CodeSection: []Code{{Body: body}}, 182 } 183 err := m.validateFunction(&stacks{}, api.CoreFeatureNonTrappingFloatToIntConversion, 184 0, []Index{0}, nil, nil, nil, nil, bytes.NewReader(nil)) 185 require.NoError(t, err) 186 }) 187 }) 188 } 189 } 190 191 // TestModule_ValidateFunction_MultiValue only tests what can't yet be detected during compilation. These examples are 192 // from test/core/if.wast from the commit that added "multi-value" support. 193 // 194 // See https://github.com/WebAssembly/spec/commit/484180ba3d9d7638ba1cb400b699ffede796927c 195 func TestModule_ValidateFunction_MultiValue(t *testing.T) { 196 tests := []struct { 197 name string 198 module *Module 199 expectedErrOnDisable string 200 }{ 201 { 202 name: "block with function type", 203 module: &Module{ 204 TypeSection: []FunctionType{v_f64f64}, 205 FunctionSection: []Index{0}, 206 CodeSection: []Code{{Body: []byte{ 207 OpcodeBlock, 0, // (block (result f64 f64) 208 OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0x10, 0x40, // (f64.const 4) 209 OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0x14, 0x40, // (f64.const 5) 210 OpcodeBr, 0, 211 OpcodeF64Add, 212 OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0x18, 0x40, // (f64.const 6) 213 OpcodeEnd, 214 OpcodeEnd, 215 }}}, 216 }, 217 expectedErrOnDisable: "read block: block with function type return invalid as feature \"multi-value\" is disabled", 218 }, 219 { 220 name: "if with function type", // a.k.a. "param" 221 module: &Module{ 222 TypeSection: []FunctionType{i32_i32}, // (func (param i32) (result i32) 223 FunctionSection: []Index{0}, 224 CodeSection: []Code{{Body: []byte{ 225 OpcodeI32Const, 1, // (i32.const 1) 226 OpcodeLocalGet, 0, OpcodeIf, 0, // (if (param i32) (result i32) (local.get 0) 227 OpcodeI32Const, 2, OpcodeI32Add, // (then (i32.const 2) (i32.add)) 228 OpcodeElse, OpcodeI32Const, 0x7e, OpcodeI32Add, // (else (i32.const -2) (i32.add)) 229 OpcodeEnd, // ) 230 OpcodeEnd, // ) 231 }}}, 232 }, 233 expectedErrOnDisable: "read block: block with function type return invalid as feature \"multi-value\" is disabled", 234 }, 235 { 236 name: "if with function type - br", // a.k.a. "params-break" 237 module: &Module{ 238 TypeSection: []FunctionType{ 239 i32_i32, // (func (param i32) (result i32) 240 i32i32_i32, // (if (param i32 i32) (result i32) 241 }, 242 FunctionSection: []Index{0}, 243 CodeSection: []Code{{Body: []byte{ 244 OpcodeI32Const, 1, // (i32.const 1) 245 OpcodeI32Const, 2, // (i32.const 2) 246 OpcodeLocalGet, 0, OpcodeIf, 1, // (if (param i32) (result i32) (local.get 0) 247 OpcodeI32Add, OpcodeBr, 0, // (then (i32.add) (br 0)) 248 OpcodeElse, OpcodeI32Sub, OpcodeBr, 0, // (else (i32.sub) (br 0)) 249 OpcodeEnd, // ) 250 OpcodeEnd, // ) 251 }}}, 252 }, 253 expectedErrOnDisable: "read block: block with function type return invalid as feature \"multi-value\" is disabled", 254 }, 255 } 256 257 for _, tt := range tests { 258 tc := tt 259 t.Run(tc.name, func(t *testing.T) { 260 t.Run("disabled", func(t *testing.T) { 261 err := tc.module.validateFunction(&stacks{}, api.CoreFeaturesV1, 262 0, []Index{0}, nil, nil, nil, nil, bytes.NewReader(nil)) 263 require.EqualError(t, err, tc.expectedErrOnDisable) 264 }) 265 t.Run("enabled", func(t *testing.T) { 266 err := tc.module.validateFunction(&stacks{}, api.CoreFeatureMultiValue, 267 0, []Index{0}, nil, nil, nil, nil, bytes.NewReader(nil)) 268 require.NoError(t, err) 269 }) 270 }) 271 } 272 } 273 274 func TestModule_ValidateFunction_BulkMemoryOperations(t *testing.T) { 275 t.Run("ok", func(t *testing.T) { 276 for _, op := range []OpcodeMisc{ 277 OpcodeMiscMemoryInit, OpcodeMiscDataDrop, OpcodeMiscMemoryCopy, 278 OpcodeMiscMemoryFill, OpcodeMiscTableInit, OpcodeMiscElemDrop, OpcodeMiscTableCopy, 279 } { 280 t.Run(MiscInstructionName(op), func(t *testing.T) { 281 var body []byte 282 if op != OpcodeMiscDataDrop && op != OpcodeMiscElemDrop { 283 body = append(body, OpcodeI32Const, 1, OpcodeI32Const, 2, OpcodeI32Const, 3) 284 } 285 286 body = append(body, OpcodeMiscPrefix, op) 287 if op != OpcodeMiscDataDrop && op != OpcodeMiscMemoryFill && op != OpcodeMiscElemDrop { 288 body = append(body, 0, 0) 289 } else { 290 body = append(body, 0) 291 } 292 293 body = append(body, OpcodeEnd) 294 295 c := uint32(0) 296 m := &Module{ 297 TypeSection: []FunctionType{v_v}, 298 FunctionSection: []Index{0}, 299 CodeSection: []Code{{Body: body}}, 300 DataSection: []DataSegment{{}}, 301 ElementSection: []ElementSegment{{}}, 302 DataCountSection: &c, 303 } 304 err := m.validateFunction(&stacks{}, api.CoreFeatureBulkMemoryOperations, 305 0, []Index{0}, nil, &Memory{}, []Table{{}, {}}, nil, bytes.NewReader(nil)) 306 require.NoError(t, err) 307 }) 308 } 309 }) 310 t.Run("errors", func(t *testing.T) { 311 tests := []struct { 312 body []byte 313 dataSection []DataSegment 314 elementSection []ElementSegment 315 dataCountSectionNil bool 316 memory *Memory 317 tables []Table 318 flag api.CoreFeatures 319 expectedErr string 320 }{ 321 // memory.init 322 { 323 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit}, 324 flag: api.CoreFeatureBulkMemoryOperations, 325 memory: nil, 326 expectedErr: "memory must exist for memory.init", 327 }, 328 { 329 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit}, 330 flag: api.CoreFeaturesV1, 331 expectedErr: `memory.init invalid as feature "bulk-memory-operations" is disabled`, 332 }, 333 { 334 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit}, 335 flag: api.CoreFeatureBulkMemoryOperations, 336 dataCountSectionNil: true, 337 expectedErr: `memory must exist for memory.init`, 338 }, 339 { 340 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit}, 341 flag: api.CoreFeatureBulkMemoryOperations, 342 memory: &Memory{}, 343 expectedErr: "failed to read data segment index for memory.init: EOF", 344 }, 345 { 346 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit, 100 /* data section out of range */}, 347 flag: api.CoreFeatureBulkMemoryOperations, 348 memory: &Memory{}, 349 dataSection: []DataSegment{{}}, 350 expectedErr: "index 100 out of range of data section(len=1)", 351 }, 352 { 353 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit, 0}, 354 flag: api.CoreFeatureBulkMemoryOperations, 355 memory: &Memory{}, 356 dataSection: []DataSegment{{}}, 357 expectedErr: "failed to read memory index for memory.init: EOF", 358 }, 359 { 360 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit, 0, 1}, 361 flag: api.CoreFeatureBulkMemoryOperations, 362 memory: &Memory{}, 363 dataSection: []DataSegment{{}}, 364 expectedErr: "memory.init reserved byte must be zero encoded with 1 byte", 365 }, 366 { 367 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit, 0, 0}, 368 flag: api.CoreFeatureBulkMemoryOperations, 369 memory: &Memory{}, 370 dataSection: []DataSegment{{}}, 371 expectedErr: "cannot pop the operand for memory.init: i32 missing", 372 }, 373 { 374 body: []byte{OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscMemoryInit, 0, 0}, 375 flag: api.CoreFeatureBulkMemoryOperations, 376 memory: &Memory{}, 377 dataSection: []DataSegment{{}}, 378 expectedErr: "cannot pop the operand for memory.init: i32 missing", 379 }, 380 { 381 body: []byte{OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscMemoryInit, 0, 0}, 382 flag: api.CoreFeatureBulkMemoryOperations, 383 memory: &Memory{}, 384 dataSection: []DataSegment{{}}, 385 expectedErr: "cannot pop the operand for memory.init: i32 missing", 386 }, 387 // data.drop 388 { 389 body: []byte{OpcodeMiscPrefix, OpcodeMiscDataDrop}, 390 flag: api.CoreFeaturesV1, 391 expectedErr: `data.drop invalid as feature "bulk-memory-operations" is disabled`, 392 }, 393 { 394 body: []byte{OpcodeMiscPrefix, OpcodeMiscDataDrop}, 395 dataCountSectionNil: true, 396 memory: &Memory{}, 397 flag: api.CoreFeatureBulkMemoryOperations, 398 expectedErr: `data.drop requires data count section`, 399 }, 400 { 401 body: []byte{OpcodeMiscPrefix, OpcodeMiscDataDrop}, 402 flag: api.CoreFeatureBulkMemoryOperations, 403 memory: &Memory{}, 404 expectedErr: "failed to read data segment index for data.drop: EOF", 405 }, 406 { 407 body: []byte{OpcodeMiscPrefix, OpcodeMiscDataDrop, 100 /* data section out of range */}, 408 flag: api.CoreFeatureBulkMemoryOperations, 409 memory: &Memory{}, 410 dataSection: []DataSegment{{}}, 411 expectedErr: "index 100 out of range of data section(len=1)", 412 }, 413 // memory.copy 414 { 415 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryCopy}, 416 flag: api.CoreFeatureBulkMemoryOperations, 417 memory: nil, 418 expectedErr: "memory must exist for memory.copy", 419 }, 420 { 421 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryCopy}, 422 flag: api.CoreFeaturesV1, 423 expectedErr: `memory.copy invalid as feature "bulk-memory-operations" is disabled`, 424 }, 425 { 426 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryCopy}, 427 flag: api.CoreFeatureBulkMemoryOperations, 428 memory: &Memory{}, 429 expectedErr: `failed to read memory index for memory.copy: EOF`, 430 }, 431 { 432 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryCopy, 0}, 433 flag: api.CoreFeatureBulkMemoryOperations, 434 memory: &Memory{}, 435 expectedErr: "failed to read memory index for memory.copy: EOF", 436 }, 437 { 438 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryCopy, 0, 1}, 439 flag: api.CoreFeatureBulkMemoryOperations, 440 memory: &Memory{}, 441 expectedErr: "memory.copy reserved byte must be zero encoded with 1 byte", 442 }, 443 { 444 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryCopy, 0, 0}, 445 flag: api.CoreFeatureBulkMemoryOperations, 446 memory: &Memory{}, 447 expectedErr: "cannot pop the operand for memory.copy: i32 missing", 448 }, 449 { 450 body: []byte{OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscMemoryCopy, 0, 0}, 451 flag: api.CoreFeatureBulkMemoryOperations, 452 memory: &Memory{}, 453 expectedErr: "cannot pop the operand for memory.copy: i32 missing", 454 }, 455 { 456 body: []byte{OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscMemoryCopy, 0, 0}, 457 flag: api.CoreFeatureBulkMemoryOperations, 458 memory: &Memory{}, 459 expectedErr: "cannot pop the operand for memory.copy: i32 missing", 460 }, 461 // memory.fill 462 { 463 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryFill}, 464 flag: api.CoreFeatureBulkMemoryOperations, 465 memory: nil, 466 expectedErr: "memory must exist for memory.fill", 467 }, 468 { 469 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryFill}, 470 flag: api.CoreFeaturesV1, 471 expectedErr: `memory.fill invalid as feature "bulk-memory-operations" is disabled`, 472 }, 473 { 474 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryFill}, 475 flag: api.CoreFeatureBulkMemoryOperations, 476 memory: &Memory{}, 477 expectedErr: `failed to read memory index for memory.fill: EOF`, 478 }, 479 { 480 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryFill, 1}, 481 flag: api.CoreFeatureBulkMemoryOperations, 482 memory: &Memory{}, 483 expectedErr: `memory.fill reserved byte must be zero encoded with 1 byte`, 484 }, 485 { 486 body: []byte{OpcodeMiscPrefix, OpcodeMiscMemoryFill, 0}, 487 flag: api.CoreFeatureBulkMemoryOperations, 488 memory: &Memory{}, 489 expectedErr: "cannot pop the operand for memory.fill: i32 missing", 490 }, 491 { 492 body: []byte{OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscMemoryFill, 0}, 493 flag: api.CoreFeatureBulkMemoryOperations, 494 memory: &Memory{}, 495 expectedErr: "cannot pop the operand for memory.fill: i32 missing", 496 }, 497 { 498 body: []byte{OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscMemoryFill, 0}, 499 flag: api.CoreFeatureBulkMemoryOperations, 500 memory: &Memory{}, 501 expectedErr: "cannot pop the operand for memory.fill: i32 missing", 502 }, 503 // table.init 504 { 505 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableInit}, 506 flag: api.CoreFeaturesV1, 507 tables: []Table{{}}, 508 expectedErr: `table.init invalid as feature "bulk-memory-operations" is disabled`, 509 }, 510 { 511 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableInit}, 512 flag: api.CoreFeatureBulkMemoryOperations, 513 tables: []Table{{}}, 514 expectedErr: "failed to read element segment index for table.init: EOF", 515 }, 516 { 517 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableInit, 100 /* data section out of range */}, 518 flag: api.CoreFeatureBulkMemoryOperations, 519 tables: []Table{{}}, 520 elementSection: []ElementSegment{{}}, 521 expectedErr: "index 100 out of range of element section(len=1)", 522 }, 523 { 524 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableInit, 0}, 525 flag: api.CoreFeatureBulkMemoryOperations, 526 tables: []Table{{}}, 527 elementSection: []ElementSegment{{}}, 528 expectedErr: "failed to read source table index for table.init: EOF", 529 }, 530 { 531 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableInit, 0, 10}, 532 flag: api.CoreFeatureBulkMemoryOperations, 533 tables: []Table{{}}, 534 elementSection: []ElementSegment{{}}, 535 expectedErr: "source table index must be zero for table.init as feature \"reference-types\" is disabled", 536 }, 537 { 538 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableInit, 0, 10}, 539 flag: api.CoreFeatureBulkMemoryOperations | api.CoreFeatureReferenceTypes, 540 tables: []Table{{}}, 541 elementSection: []ElementSegment{{}}, 542 expectedErr: "table of index 10 not found", 543 }, 544 { 545 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableInit, 0, 1}, 546 flag: api.CoreFeatureBulkMemoryOperations | api.CoreFeatureReferenceTypes, 547 tables: []Table{{}, {Type: RefTypeExternref}}, 548 elementSection: []ElementSegment{{Type: RefTypeFuncref}}, 549 expectedErr: "type mismatch for table.init: element type funcref does not match table type externref", 550 }, 551 { 552 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableInit, 0, 0}, 553 flag: api.CoreFeatureBulkMemoryOperations, 554 tables: []Table{{}}, 555 elementSection: []ElementSegment{{}}, 556 expectedErr: "cannot pop the operand for table.init: i32 missing", 557 }, 558 { 559 body: []byte{OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscTableInit, 0, 0}, 560 flag: api.CoreFeatureBulkMemoryOperations, 561 tables: []Table{{}}, 562 elementSection: []ElementSegment{{}}, 563 expectedErr: "cannot pop the operand for table.init: i32 missing", 564 }, 565 { 566 body: []byte{OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscTableInit, 0, 0}, 567 flag: api.CoreFeatureBulkMemoryOperations, 568 tables: []Table{{}}, 569 elementSection: []ElementSegment{{}}, 570 expectedErr: "cannot pop the operand for table.init: i32 missing", 571 }, 572 // elem.drop 573 { 574 body: []byte{OpcodeMiscPrefix, OpcodeMiscElemDrop}, 575 flag: api.CoreFeaturesV1, 576 tables: []Table{{}}, 577 expectedErr: `elem.drop invalid as feature "bulk-memory-operations" is disabled`, 578 }, 579 { 580 body: []byte{OpcodeMiscPrefix, OpcodeMiscElemDrop}, 581 flag: api.CoreFeatureBulkMemoryOperations, 582 tables: []Table{{}}, 583 expectedErr: "failed to read element segment index for elem.drop: EOF", 584 }, 585 { 586 body: []byte{OpcodeMiscPrefix, OpcodeMiscElemDrop, 100 /* element section out of range */}, 587 flag: api.CoreFeatureBulkMemoryOperations, 588 tables: []Table{{}}, 589 elementSection: []ElementSegment{{}}, 590 expectedErr: "index 100 out of range of element section(len=1)", 591 }, 592 // table.copy 593 { 594 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy}, 595 flag: api.CoreFeaturesV1, 596 tables: []Table{{}}, 597 expectedErr: `table.copy invalid as feature "bulk-memory-operations" is disabled`, 598 }, 599 { 600 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy}, 601 flag: api.CoreFeatureBulkMemoryOperations, 602 tables: []Table{{}}, 603 expectedErr: `failed to read destination table index for table.copy: EOF`, 604 }, 605 { 606 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy, 10}, 607 flag: api.CoreFeatureBulkMemoryOperations, 608 tables: []Table{{}}, 609 expectedErr: "destination table index must be zero for table.copy as feature \"reference-types\" is disabled", 610 }, 611 { 612 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy, 3}, 613 flag: api.CoreFeatureBulkMemoryOperations | api.CoreFeatureReferenceTypes, 614 tables: []Table{{}, {}}, 615 expectedErr: "table of index 3 not found", 616 }, 617 { 618 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy, 3}, 619 flag: api.CoreFeatureBulkMemoryOperations | api.CoreFeatureReferenceTypes, 620 tables: []Table{{}, {}, {}, {}}, 621 expectedErr: "failed to read source table index for table.copy: EOF", 622 }, 623 { 624 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy, 0, 3}, 625 flag: api.CoreFeatureBulkMemoryOperations, // Multiple tables require api.CoreFeatureReferenceTypes. 626 tables: []Table{{}, {}, {}, {}}, 627 expectedErr: "source table index must be zero for table.copy as feature \"reference-types\" is disabled", 628 }, 629 { 630 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy, 3, 1}, 631 flag: api.CoreFeatureBulkMemoryOperations | api.CoreFeatureReferenceTypes, 632 tables: []Table{{}, {Type: RefTypeFuncref}, {}, {Type: RefTypeExternref}}, 633 expectedErr: "table type mismatch for table.copy: funcref (src) != externref (dst)", 634 }, 635 { 636 body: []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy, 0, 0}, 637 flag: api.CoreFeatureBulkMemoryOperations, 638 tables: []Table{{}}, 639 expectedErr: "cannot pop the operand for table.copy: i32 missing", 640 }, 641 { 642 body: []byte{OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscTableCopy, 0, 0}, 643 flag: api.CoreFeatureBulkMemoryOperations, 644 tables: []Table{{}}, 645 expectedErr: "cannot pop the operand for table.copy: i32 missing", 646 }, 647 { 648 body: []byte{OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscTableCopy, 0, 0}, 649 flag: api.CoreFeatureBulkMemoryOperations, 650 tables: []Table{{}}, 651 expectedErr: "cannot pop the operand for table.copy: i32 missing", 652 }, 653 } 654 655 for _, tt := range tests { 656 tc := tt 657 t.Run(tc.expectedErr, func(t *testing.T) { 658 m := &Module{ 659 TypeSection: []FunctionType{v_v}, 660 FunctionSection: []Index{0}, 661 CodeSection: []Code{{Body: tc.body}}, 662 ElementSection: tc.elementSection, 663 DataSection: tc.dataSection, 664 } 665 if !tc.dataCountSectionNil { 666 c := uint32(0) 667 m.DataCountSection = &c 668 } 669 err := m.validateFunction(&stacks{}, tc.flag, 0, []Index{0}, nil, tc.memory, tc.tables, nil, bytes.NewReader(nil)) 670 require.EqualError(t, err, tc.expectedErr) 671 }) 672 } 673 }) 674 } 675 676 var ( 677 f32, f64, i32, i64, v128, externref = ValueTypeF32, ValueTypeF64, ValueTypeI32, ValueTypeI64, ValueTypeV128, ValueTypeExternref 678 f32i32_v = initFt([]ValueType{f32, i32}, nil) 679 f64f32_i64 = initFt([]ValueType{f64, f32}, []ValueType{i64}) 680 f64i32_v128i64 = initFt([]ValueType{f64, i32}, []ValueType{v128, i64}) 681 i32_i32 = initFt([]ValueType{i32}, []ValueType{i32}) 682 i32f64_v = initFt([]ValueType{i32, f64}, nil) 683 i32i32_i32 = initFt([]ValueType{i32, i32}, []ValueType{i32}) 684 i32_v = initFt([]ValueType{i32}, nil) 685 v_v = FunctionType{} 686 v_f32 = initFt(nil, []ValueType{f32}) 687 v_f32f32 = initFt(nil, []ValueType{f32, f32}) 688 v_f64i32 = initFt(nil, []ValueType{f64, i32}) 689 v_f64f64 = initFt(nil, []ValueType{f64, f64}) 690 v_i32 = initFt(nil, []ValueType{i32}) 691 v_i32i32 = initFt(nil, []ValueType{i32, i32}) 692 v_i32i64 = initFt(nil, []ValueType{i32, i64}) 693 v_i64i64 = initFt(nil, []ValueType{i64, i64}) 694 ) 695 696 func initFt(params, results []ValueType) FunctionType { 697 ft := FunctionType{Params: params, Results: results} 698 ft.CacheNumInUint64() 699 return ft 700 } 701 702 // TestModule_ValidateFunction_MultiValue_TypeMismatch are "type mismatch" tests when "multi-value" was merged. 703 // 704 // See https://github.com/WebAssembly/spec/commit/484180ba3d9d7638ba1cb400b699ffede796927c 705 func TestModule_ValidateFunction_MultiValue_TypeMismatch(t *testing.T) { 706 tests := []struct { 707 name string 708 module *Module 709 expectedErr string 710 enabledFeatures api.CoreFeatures 711 }{ 712 // test/core/func.wast 713 714 { 715 name: `func.wast - type-empty-f64-i32`, 716 module: &Module{ 717 TypeSection: []FunctionType{v_f64i32}, 718 FunctionSection: []Index{0}, 719 CodeSection: []Code{{Body: []byte{OpcodeEnd}}}, 720 }, 721 expectedErr: `not enough results 722 have () 723 want (f64, i32)`, 724 }, 725 { 726 name: `func.wast - type-value-void-vs-nums`, 727 module: &Module{ 728 TypeSection: []FunctionType{v_i32i32}, 729 FunctionSection: []Index{0}, 730 CodeSection: []Code{{Body: []byte{OpcodeNop, OpcodeEnd}}}, 731 }, 732 expectedErr: `not enough results 733 have () 734 want (i32, i32)`, 735 }, 736 { 737 name: `func.wast - type-value-nums-vs-void`, 738 module: &Module{ 739 TypeSection: []FunctionType{v_v}, 740 FunctionSection: []Index{0}, 741 CodeSection: []Code{{Body: []byte{OpcodeI32Const, 0, OpcodeI64Const, 0, OpcodeEnd}}}, 742 }, 743 expectedErr: `too many results 744 have (i32, i64) 745 want ()`, 746 }, 747 { 748 name: `func.wast - type-value-num-vs-nums - v_f32f32 -> f32`, 749 module: &Module{ 750 TypeSection: []FunctionType{v_f32f32}, 751 FunctionSection: []Index{0}, 752 CodeSection: []Code{{Body: []byte{ 753 OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0) 754 OpcodeEnd, // func 755 }}}, 756 }, 757 expectedErr: `not enough results 758 have (f32) 759 want (f32, f32)`, 760 }, 761 { 762 name: `func.wast - type-value-num-vs-nums - v_f32 -> f32f32`, 763 module: &Module{ 764 TypeSection: []FunctionType{v_f32}, 765 FunctionSection: []Index{0}, 766 CodeSection: []Code{{Body: []byte{ 767 OpcodeF32Const, 0, 0, 0, 0, OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0) (f32.const 0) 768 OpcodeEnd, // func 769 }}}, 770 }, 771 expectedErr: `too many results 772 have (f32, f32) 773 want (f32)`, 774 }, 775 { 776 name: `func.wast - type-return-last-empty-vs-nums`, 777 module: &Module{ 778 TypeSection: []FunctionType{v_f32f32}, 779 FunctionSection: []Index{0}, 780 CodeSection: []Code{{Body: []byte{OpcodeReturn, OpcodeEnd}}}, 781 }, 782 expectedErr: `not enough results 783 have () 784 want (f32, f32)`, 785 }, 786 { 787 name: `func.wast - type-return-last-void-vs-nums`, 788 module: &Module{ 789 TypeSection: []FunctionType{v_i32i64}, 790 FunctionSection: []Index{0}, 791 CodeSection: []Code{{Body: []byte{OpcodeNop, OpcodeReturn, OpcodeEnd}}}, // (return (nop)) 792 }, 793 expectedErr: `not enough results 794 have () 795 want (i32, i64)`, 796 }, 797 { 798 name: `func.wast - type-return-last-num-vs-nums`, 799 module: &Module{ 800 TypeSection: []FunctionType{v_i64i64}, 801 FunctionSection: []Index{0}, 802 CodeSection: []Code{{Body: []byte{ 803 OpcodeI64Const, 0, OpcodeReturn, // (return (i64.const 0)) 804 OpcodeEnd, // func 805 }}}, 806 }, 807 expectedErr: `not enough results 808 have (i64) 809 want (i64, i64)`, 810 }, 811 { 812 name: `func.wast - type-return-empty-vs-nums`, 813 // This should err because (return) precedes the values expected in the signature (i32i32): 814 // (module (func $type-return-empty-vs-nums (result i32 i32) 815 // (return) (i32.const 1) (i32.const 2) 816 // )) 817 module: &Module{ 818 TypeSection: []FunctionType{v_i32i32}, 819 FunctionSection: []Index{0}, 820 CodeSection: []Code{{Body: []byte{ 821 OpcodeReturn, OpcodeI32Const, 1, OpcodeI32Const, 2, 822 OpcodeEnd, // func 823 }}}, 824 }, 825 expectedErr: `not enough results 826 have () 827 want (i32, i32)`, 828 }, 829 { 830 name: `func.wast - type-return-partial-vs-nums`, 831 // This should err because (return) precedes one of the values expected in the signature (i32i32): 832 // (module (func $type-return-partial-vs-nums (result i32 i32) 833 // (i32.const 1) (return) (i32.const 2) 834 // )) 835 module: &Module{ 836 TypeSection: []FunctionType{v_i32i32}, 837 FunctionSection: []Index{0}, 838 CodeSection: []Code{{Body: []byte{ 839 OpcodeI32Const, 1, OpcodeReturn, OpcodeI32Const, 2, 840 OpcodeEnd, // func 841 }}}, 842 }, 843 expectedErr: `not enough results 844 have (i32) 845 want (i32, i32)`, 846 }, 847 { 848 name: `func.wast - type-return-void-vs-nums`, 849 // This should err because (return) is empty due to nop, but the signature requires i32i32: 850 // (module (func $type-return-void-vs-nums (result i32 i32) 851 // (return (nop)) (i32.const 1) 852 // )) 853 module: &Module{ 854 TypeSection: []FunctionType{v_i32i32}, 855 FunctionSection: []Index{0}, 856 CodeSection: []Code{{Body: []byte{ 857 OpcodeNop, OpcodeReturn, // (return (nop)) 858 OpcodeI32Const, 1, // (i32.const 1) 859 OpcodeEnd, // func 860 }}}, 861 }, 862 expectedErr: `not enough results 863 have () 864 want (i32, i32)`, 865 }, 866 867 { 868 name: `func.wast - type-return-num-vs-nums`, 869 module: &Module{ 870 TypeSection: []FunctionType{v_i32i32}, 871 FunctionSection: []Index{0}, 872 CodeSection: []Code{{Body: []byte{ 873 OpcodeI64Const, 1, OpcodeReturn, // (return (i64.const 1)) 874 OpcodeI32Const, 1, OpcodeI32Const, 2, // (i32.const 1) (i32.const 2) 875 OpcodeEnd, // func 876 }}}, 877 }, 878 expectedErr: `not enough results 879 have (i64) 880 want (i32, i32)`, 881 }, 882 { 883 name: `func.wast - type-return-first-num-vs-nums`, 884 // This should err because the return block doesn't return enough values. 885 // (module (func $type-return-first-num-vs-nums (result i32 i32) 886 // (return (i32.const 1)) (return (i32.const 1) (i32.const 2)) 887 // )) 888 module: &Module{ 889 TypeSection: []FunctionType{v_i32i32}, 890 FunctionSection: []Index{0}, 891 CodeSection: []Code{{Body: []byte{ 892 OpcodeI64Const, 1, OpcodeReturn, // (return (i64.const 1)) 893 OpcodeI32Const, 1, OpcodeI32Const, 2, OpcodeReturn, // (return (i32.const 1) (i32.const 2)) 894 OpcodeEnd, // func 895 }}}, 896 }, 897 expectedErr: `not enough results 898 have (i64) 899 want (i32, i32)`, 900 }, 901 { 902 name: `func.wast - type-break-last-num-vs-nums`, 903 module: &Module{ 904 TypeSection: []FunctionType{v_i32i32}, 905 FunctionSection: []Index{0}, 906 CodeSection: []Code{{Body: []byte{ 907 OpcodeI32Const, 0, OpcodeBr, 0, // (br 0 (i32.const 0)) 908 OpcodeEnd, // func 909 }}}, 910 }, 911 expectedErr: `not enough results in br block 912 have (i32) 913 want (i32, i32)`, 914 }, 915 { 916 name: `func.wast - type-break-void-vs-nums`, 917 // This should err because (br 0) returns no values, but its enclosing function requires two: 918 // (module (func $type-break-void-vs-nums (result i32 i32) 919 // (br 0) (i32.const 1) (i32.const 2) 920 // )) 921 module: &Module{ 922 TypeSection: []FunctionType{v_i32i32}, 923 FunctionSection: []Index{0}, 924 CodeSection: []Code{{Body: []byte{ 925 OpcodeBr, 0, // (br 0) 926 OpcodeI32Const, 1, OpcodeI32Const, 2, // (i32.const 1) (i32.const 2) 927 OpcodeEnd, // func 928 }}}, 929 }, 930 expectedErr: `not enough results in br block 931 have () 932 want (i32, i32)`, 933 }, 934 { 935 name: `func.wast - type-break-num-vs-nums`, 936 // This should err because (br 0) returns one value, but its enclosing function requires two: 937 // (module (func $type-break-num-vs-nums (result i32 i32) 938 // (br 0 (i32.const 1)) (i32.const 1) (i32.const 2) 939 // )) 940 module: &Module{ 941 TypeSection: []FunctionType{v_i32i32}, 942 FunctionSection: []Index{0}, 943 CodeSection: []Code{{Body: []byte{ 944 OpcodeI32Const, 1, OpcodeBr, 0, // (br 0 (i32.const 1)) 945 OpcodeI32Const, 1, OpcodeI32Const, 2, // (i32.const 1) (i32.const 2) 946 OpcodeEnd, // func 947 }}}, 948 }, 949 expectedErr: `not enough results in br block 950 have (i32) 951 want (i32, i32)`, 952 }, 953 { 954 name: `func.wast - type-break-nested-empty-vs-nums`, 955 // This should err because (br 1) doesn't return values, but its enclosing function does: 956 // (module (func $type-break-nested-empty-vs-nums (result i32 i32) 957 // (block (br 1)) (br 0 (i32.const 1) (i32.const 2)) 958 // )) 959 module: &Module{ 960 TypeSection: []FunctionType{v_i32i32}, 961 FunctionSection: []Index{0}, 962 CodeSection: []Code{{Body: []byte{ 963 OpcodeBlock, 0x40, OpcodeBr, 0x01, OpcodeEnd, // (block (br 1)) 964 OpcodeI32Const, 1, OpcodeI32Const, 2, OpcodeBr, 0, // (br 0 (i32.const 1) (i32.const 2)) 965 OpcodeEnd, // func 966 }}}, 967 }, 968 expectedErr: `not enough results in br block 969 have () 970 want (i32, i32)`, 971 }, 972 { 973 name: `func.wast - type-break-nested-void-vs-nums`, 974 // This should err because nop returns the empty type, but the enclosing function returns i32i32: 975 // (module (func $type-break-nested-void-vs-nums (result i32 i32) 976 // (block (br 1 (nop))) (br 0 (i32.const 1) (i32.const 2)) 977 // )) 978 module: &Module{ 979 TypeSection: []FunctionType{v_i32i32}, 980 FunctionSection: []Index{0}, 981 CodeSection: []Code{{Body: []byte{ 982 OpcodeBlock, 0x40, OpcodeNop, OpcodeBr, 0x01, OpcodeEnd, // (block (br 1 (nop))) 983 OpcodeI32Const, 1, OpcodeI32Const, 2, OpcodeBr, 0, // (br 0 (i32.const 1) (i32.const 2)) 984 OpcodeEnd, // func 985 }}}, 986 }, 987 expectedErr: `not enough results in br block 988 have () 989 want (i32, i32)`, 990 }, 991 { 992 name: `func.wast - type-break-nested-num-vs-nums`, 993 // This should err because the block signature is v_i32, but the enclosing function is v_i32i32: 994 // (module (func $type-break-nested-num-vs-nums (result i32 i32) 995 // (block (result i32) (br 1 (i32.const 1))) (br 0 (i32.const 1) (i32.const 2)) 996 // )) 997 module: &Module{ 998 TypeSection: []FunctionType{v_i32i32}, 999 FunctionSection: []Index{0}, 1000 CodeSection: []Code{{Body: []byte{ 1001 OpcodeBlock, 0x7f, OpcodeI32Const, 1, OpcodeBr, 1, OpcodeEnd, // (block (result i32) (br 1 (i32.const 1))) 1002 OpcodeI32Const, 1, OpcodeI32Const, 2, OpcodeBr, 0, // (br 0 (i32.const 1) (i32.const 2)) 1003 OpcodeEnd, // func 1004 }}}, 1005 }, 1006 expectedErr: `not enough results in br block 1007 have (i32) 1008 want (i32, i32)`, 1009 }, 1010 1011 // test/core/if.wast 1012 { 1013 name: `if.wast - wrong signature for if type use`, 1014 // This should err because (br 0) returns no values, but its enclosing function requires two: 1015 // (module 1016 // (type $sig (func)) 1017 // (func (i32.const 1) (if (type $sig) (i32.const 0) (then))) 1018 // ) 1019 module: &Module{ 1020 TypeSection: []FunctionType{v_v}, 1021 FunctionSection: []Index{0}, 1022 CodeSection: []Code{{Body: []byte{ 1023 OpcodeI32Const, 1, // (i32.const 1) 1024 OpcodeI32Const, 0, OpcodeIf, 0, // (if (type $sig) (i32.const 0) 1025 OpcodeEnd, // if 1026 OpcodeEnd, // func 1027 }}}, 1028 }, 1029 expectedErr: `too many results 1030 have (i32) 1031 want ()`, 1032 }, 1033 { 1034 name: `if.wast - type-then-value-nums-vs-void`, 1035 // This should err because (if) without a type use returns no values, but its (then) returns two: 1036 // (module (func $type-then-value-nums-vs-void 1037 // (if (i32.const 1) (then (i32.const 1) (i32.const 2))) 1038 // )) 1039 module: &Module{ 1040 TypeSection: []FunctionType{v_v}, 1041 FunctionSection: []Index{0}, 1042 CodeSection: []Code{{Body: []byte{ 1043 OpcodeI32Const, 1, OpcodeIf, 0x40, // (if (i32.const 1) 1044 OpcodeI32Const, 1, OpcodeI32Const, 2, // (then (i32.const 1) (i32.const 2)) 1045 OpcodeEnd, // if 1046 OpcodeEnd, // func 1047 }}}, 1048 }, 1049 expectedErr: `too many results in if block 1050 have (i32, i32) 1051 want ()`, 1052 }, 1053 { 1054 name: `if.wast - type-then-value-nums-vs-void-else`, 1055 // This should err because (if) without a type use returns no values, but its (then) returns two: 1056 // (module (func $type-then-value-nums-vs-void-else 1057 // (if (i32.const 1) (then (i32.const 1) (i32.const 2)) (else)) 1058 // )) 1059 module: &Module{ 1060 TypeSection: []FunctionType{v_v}, 1061 FunctionSection: []Index{0}, 1062 CodeSection: []Code{{Body: []byte{ 1063 OpcodeI32Const, 1, OpcodeIf, 0x40, // (if (i32.const 1) 1064 OpcodeI32Const, 1, OpcodeI32Const, 2, // (then (i32.const 1) (i32.const 2)) 1065 OpcodeElse, // (else) 1066 OpcodeEnd, // if 1067 OpcodeEnd, // func 1068 }}}, 1069 }, 1070 expectedErr: `too many results in if block 1071 have (i32, i32) 1072 want ()`, 1073 }, 1074 { 1075 name: `if.wast - type-else-value-nums-vs-void`, 1076 // This should err because (if) without a type use returns no values, but its (else) returns two: 1077 // (module (func $type-else-value-nums-vs-void 1078 // (if (i32.const 1) (then) (else (i32.const 1) (i32.const 2))) 1079 // )) 1080 module: &Module{ 1081 TypeSection: []FunctionType{v_v}, 1082 FunctionSection: []Index{0}, 1083 CodeSection: []Code{{Body: []byte{ 1084 OpcodeI32Const, 1, OpcodeIf, 0x40, // (if (i32.const 1) (then) 1085 OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 2, // (else (i32.const 1) (i32.const 2)) 1086 OpcodeEnd, // if 1087 OpcodeEnd, // func 1088 }}}, 1089 }, 1090 expectedErr: `too many results in else block 1091 have (i32, i32) 1092 want ()`, 1093 }, 1094 { 1095 name: `if.wast - type-both-value-nums-vs-void`, 1096 // This should err because (if) without a type use returns no values, each branch returns two: 1097 // (module (func $type-both-value-nums-vs-void 1098 // (if (i32.const 1) (then (i32.const 1) (i32.const 2)) (else (i32.const 2) (i32.const 1))) 1099 // )) 1100 module: &Module{ 1101 TypeSection: []FunctionType{v_v}, 1102 FunctionSection: []Index{0}, 1103 CodeSection: []Code{{Body: []byte{ 1104 OpcodeI32Const, 1, OpcodeIf, 0x40, // (if (i32.const 1) 1105 OpcodeI32Const, 1, OpcodeI32Const, 2, // (then (i32.const 1) (i32.const 2)) 1106 OpcodeElse, OpcodeI32Const, 2, OpcodeI32Const, 1, // (else (i32.const 2) (i32.const 1)) 1107 OpcodeEnd, // if 1108 OpcodeEnd, // func 1109 }}}, 1110 }, 1111 expectedErr: `too many results in if block 1112 have (i32, i32) 1113 want ()`, 1114 }, 1115 { 1116 name: `if.wast - type-then-value-empty-vs-nums`, 1117 // This should err because the if branch is empty, but its type use requires two i32s: 1118 // (module (func $type-then-value-empty-vs-nums (result i32 i32) 1119 // (if (result i32 i32) (i32.const 1) (then) (else (i32.const 0) (i32.const 2))) 1120 // )) 1121 module: &Module{ 1122 TypeSection: []FunctionType{v_v, v_i32i32}, 1123 FunctionSection: []Index{0}, 1124 CodeSection: []Code{{Body: []byte{ 1125 OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (result i32 i32) (i32.const 1) (then) 1126 OpcodeElse, OpcodeI32Const, 0, OpcodeI32Const, 2, // (else (i32.const 0) (i32.const 2))) 1127 OpcodeEnd, // if 1128 OpcodeEnd, // func 1129 }}}, 1130 }, 1131 expectedErr: `not enough results in if block 1132 have () 1133 want (i32, i32)`, 1134 }, 1135 { 1136 name: `if.wast - type-else-value-empty-vs-nums`, 1137 // This should err because the else branch is empty, but its type use requires two i32s: 1138 // (module (func $type-else-value-empty-vs-nums (result i32 i32) 1139 // (if (result i32 i32) (i32.const 1) (then (i32.const 0) (i32.const 1)) (else)) 1140 // )) 1141 module: &Module{ 1142 TypeSection: []FunctionType{v_v, v_i32i32}, 1143 FunctionSection: []Index{0}, 1144 CodeSection: []Code{{Body: []byte{ 1145 OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (result i32 i32) (i32.const 1) 1146 OpcodeI32Const, 0, OpcodeI32Const, 2, // (then (i32.const 0) (i32.const 1)) 1147 OpcodeElse, // (else) 1148 OpcodeEnd, // if 1149 OpcodeEnd, // func 1150 }}}, 1151 }, 1152 expectedErr: `not enough results in else block 1153 have () 1154 want (i32, i32)`, 1155 }, 1156 { 1157 name: `if.wast - type-both-value-empty-vs-nums`, 1158 // This should err because the both branches are empty, but the if type use requires two i32s: 1159 // (module (func $type-both-value-empty-vs-nums (result i32 i32) 1160 // (if (result i32 i32) (i32.const 1) (then) (else)) 1161 // )) 1162 module: &Module{ 1163 TypeSection: []FunctionType{v_v, v_i32i32}, 1164 FunctionSection: []Index{0}, 1165 CodeSection: []Code{{Body: []byte{ 1166 OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (result i32 i32) (i32.const 1) (then) 1167 OpcodeElse, // (else) 1168 OpcodeEnd, // if 1169 OpcodeEnd, // func 1170 }}}, 1171 }, 1172 expectedErr: `not enough results in if block 1173 have () 1174 want (i32, i32)`, 1175 }, 1176 { 1177 name: `if.wast - type-no-else-vs-nums`, 1178 // This should err because the else branch is missing, but its type use requires two i32s: 1179 // (module (func $type-no-else-vs-nums (result i32 i32) 1180 // (if (result i32 i32) (i32.const 1) (then (i32.const 1) (i32.const 1))) 1181 // )) 1182 module: &Module{ 1183 TypeSection: []FunctionType{v_v, v_i32i32}, 1184 FunctionSection: []Index{0}, 1185 CodeSection: []Code{{Body: []byte{ 1186 OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (result i32 i32) (i32.const 1) 1187 OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1)) 1188 OpcodeEnd, // if 1189 OpcodeEnd, // func 1190 }}}, 1191 }, 1192 expectedErr: `not enough results in else block 1193 have () 1194 want (i32, i32)`, 1195 }, 1196 { 1197 name: `if.wast - type-then-value-void-vs-nums`, 1198 // This should err because the then branch evaluates to empty, but its type use requires two i32s: 1199 // (module (func $type-then-value-void-vs-nums (result i32 i32) 1200 // (if (result i32 i32) (i32.const 1) (then (nop)) (else (i32.const 0) (i32.const 0))) 1201 // )) 1202 module: &Module{ 1203 TypeSection: []FunctionType{v_v, v_i32i32}, 1204 FunctionSection: []Index{0}, 1205 CodeSection: []Code{{Body: []byte{ 1206 OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (result i32 i32) (i32.const 1) 1207 OpcodeNop, // (then (nop)) 1208 OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1)) 1209 OpcodeEnd, // if 1210 OpcodeEnd, // func 1211 }}}, 1212 }, 1213 expectedErr: `not enough results in if block 1214 have () 1215 want (i32, i32)`, 1216 }, 1217 { 1218 name: `if.wast - type-then-value-void-vs-nums`, 1219 // This should err because the else branch evaluates to empty, but its type use requires two i32s: 1220 // (module (func $type-else-value-void-vs-nums (result i32 i32) 1221 // (if (result i32 i32) (i32.const 1) (then (i32.const 0) (i32.const 0)) (else (nop))) 1222 // )) 1223 module: &Module{ 1224 TypeSection: []FunctionType{v_i32i32}, 1225 FunctionSection: []Index{0}, 1226 CodeSection: []Code{{Body: []byte{ 1227 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1228 OpcodeI32Const, 0, OpcodeI32Const, 0, // (then (i32.const 0) (i32.const 0)) 1229 OpcodeElse, OpcodeNop, // (else (nop)) 1230 OpcodeEnd, // if 1231 OpcodeEnd, // func 1232 }}}, 1233 }, 1234 expectedErr: `not enough results in else block 1235 have () 1236 want (i32, i32)`, 1237 }, 1238 { 1239 name: `if.wast - type-both-value-void-vs-nums`, 1240 // This should err because the if branch evaluates to empty, but its type use requires two i32s: 1241 // (module (func $type-both-value-void-vs-nums (result i32 i32) 1242 // (if (result i32 i32) (i32.const 1) (then (nop)) (else (nop))) 1243 // )) 1244 module: &Module{ 1245 TypeSection: []FunctionType{v_i32i32}, 1246 FunctionSection: []Index{0}, 1247 CodeSection: []Code{{Body: []byte{ 1248 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1249 OpcodeNop, // (then (nop)) 1250 OpcodeElse, OpcodeNop, // (else (nop)) 1251 OpcodeEnd, // if 1252 OpcodeEnd, // func 1253 }}}, 1254 }, 1255 expectedErr: `not enough results in if block 1256 have () 1257 want (i32, i32)`, 1258 }, 1259 { 1260 name: `if.wast - type-then-value-num-vs-nums`, 1261 // This should err because the if branch returns one value, but its type use requires two: 1262 // (module (func $type-then-value-num-vs-nums (result i32 i32) 1263 // (if (result i32 i32) (i32.const 1) (then (i32.const 1)) (else (i32.const 1) (i32.const 1))) 1264 // )) 1265 module: &Module{ 1266 TypeSection: []FunctionType{v_i32i32}, 1267 FunctionSection: []Index{0}, 1268 CodeSection: []Code{{Body: []byte{ 1269 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1270 OpcodeI32Const, 1, // (then (i32.const 1)) 1271 OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1))) 1272 OpcodeEnd, // if 1273 OpcodeEnd, // func 1274 }}}, 1275 }, 1276 expectedErr: `not enough results in if block 1277 have (i32) 1278 want (i32, i32)`, 1279 }, 1280 { 1281 name: `if.wast - type-else-value-num-vs-nums`, 1282 // This should err because the else branch returns one value, but its type use requires two: 1283 // (module (func $type-else-value-num-vs-nums (result i32 i32) 1284 // (if (result i32 i32) (i32.const 1) (then (i32.const 1) (i32.const 1)) (else (i32.const 1))) 1285 // )) 1286 module: &Module{ 1287 TypeSection: []FunctionType{v_i32i32}, 1288 FunctionSection: []Index{0}, 1289 CodeSection: []Code{{Body: []byte{ 1290 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1291 OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1)) 1292 OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1))) 1293 OpcodeEnd, // if 1294 OpcodeEnd, // func 1295 }}}, 1296 }, 1297 expectedErr: `not enough results in else block 1298 have (i32) 1299 want (i32, i32)`, 1300 }, 1301 { 1302 name: `if.wast - type-both-value-num-vs-nums`, 1303 // This should err because the if branch returns one value, but its type use requires two: 1304 // (module (func $type-both-value-num-vs-nums (result i32 i32) 1305 // (if (result i32 i32) (i32.const 1) (then (i32.const 1)) (else (i32.const 1))) 1306 // )) 1307 module: &Module{ 1308 TypeSection: []FunctionType{v_i32i32}, 1309 FunctionSection: []Index{0}, 1310 CodeSection: []Code{{Body: []byte{ 1311 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1312 OpcodeI32Const, 1, // (then (i32.const 1)) 1313 OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1))) 1314 OpcodeEnd, // if 1315 OpcodeEnd, // func 1316 }}}, 1317 }, 1318 expectedErr: `not enough results in if block 1319 have (i32) 1320 want (i32, i32)`, 1321 }, 1322 { 1323 name: `if.wast - type-then-value-partial-vs-nums`, 1324 // This should err because the if branch returns one value, but its type use requires two: 1325 // (module (func $type-then-value-partial-vs-nums (result i32 i32) 1326 // (i32.const 0) 1327 // (if (result i32 i32) (i32.const 1) (then (i32.const 1)) (else (i32.const 1) (i32.const 1))) 1328 // )) 1329 module: &Module{ 1330 TypeSection: []FunctionType{v_i32i32}, 1331 FunctionSection: []Index{0}, 1332 CodeSection: []Code{{Body: []byte{ 1333 OpcodeI32Const, 0, // (i32.const 0) - NOTE: this is outside the (if) 1334 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1335 OpcodeI32Const, 1, // (then (i32.const 1)) 1336 OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1)) 1337 OpcodeEnd, // if 1338 OpcodeEnd, // func 1339 }}}, 1340 }, 1341 expectedErr: `not enough results in if block 1342 have (i32) 1343 want (i32, i32)`, 1344 }, 1345 { 1346 name: `if.wast - type-else-value-partial-vs-nums`, 1347 // This should err because the else branch returns one value, but its type use requires two: 1348 // (module (func $type-else-value-partial-vs-nums (result i32 i32) 1349 // (i32.const 0) 1350 // (if (result i32 i32) (i32.const 1) (then (i32.const 1) (i32.const 1)) (else (i32.const 1))) 1351 // )) 1352 module: &Module{ 1353 TypeSection: []FunctionType{v_i32i32}, 1354 FunctionSection: []Index{0}, 1355 CodeSection: []Code{{Body: []byte{ 1356 OpcodeI32Const, 0, // (i32.const 0) - NOTE: this is outside the (if) 1357 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1358 OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1)) 1359 OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1)) 1360 OpcodeEnd, // if 1361 OpcodeEnd, // func 1362 }}}, 1363 }, 1364 expectedErr: `not enough results in else block 1365 have (i32) 1366 want (i32, i32)`, 1367 }, 1368 { 1369 name: `if.wast - type-both-value-partial-vs-nums`, 1370 // This should err because the if branch returns one value, but its type use requires two: 1371 // (module (func $type-both-value-partial-vs-nums (result i32 i32) 1372 // (i32.const 0) 1373 // (if (result i32 i32) (i32.const 1) (then (i32.const 1)) (else (i32.const 1))) 1374 // )) 1375 module: &Module{ 1376 TypeSection: []FunctionType{v_i32i32}, 1377 FunctionSection: []Index{0}, 1378 CodeSection: []Code{{Body: []byte{ 1379 OpcodeI32Const, 0, // (i32.const 0) - NOTE: this is outside the (if) 1380 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1381 OpcodeI32Const, 1, // (then (i32.const 1)) 1382 OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1)) 1383 OpcodeEnd, // if 1384 OpcodeEnd, // func 1385 }}}, 1386 }, 1387 expectedErr: `not enough results in if block 1388 have (i32) 1389 want (i32, i32)`, 1390 }, 1391 { 1392 name: `if.wast - type-then-value-nums-vs-num`, 1393 // This should err because the if branch returns two values, but its type use requires one: 1394 // (module (func $type-then-value-nums-vs-num (result i32) 1395 // (if (result i32) (i32.const 1) (then (i32.const 1) (i32.const 1)) (else (i32.const 1))) 1396 // )) 1397 module: &Module{ 1398 TypeSection: []FunctionType{v_i32}, 1399 FunctionSection: []Index{0}, 1400 CodeSection: []Code{{Body: []byte{ 1401 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32) (i32.const 1) 1402 OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1)) 1403 OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1)) 1404 OpcodeEnd, // if 1405 OpcodeEnd, // func 1406 }}}, 1407 }, 1408 expectedErr: `too many results in if block 1409 have (i32, i32) 1410 want (i32)`, 1411 }, 1412 { 1413 name: `if.wast - type-else-value-nums-vs-num`, 1414 // This should err because the else branch returns two values, but its type use requires one: 1415 // (module (func $type-else-value-nums-vs-num (result i32) 1416 // (if (result i32) (i32.const 1) (then (i32.const 1)) (else (i32.const 1) (i32.const 1))) 1417 // )) 1418 module: &Module{ 1419 TypeSection: []FunctionType{v_i32}, 1420 FunctionSection: []Index{0}, 1421 CodeSection: []Code{{Body: []byte{ 1422 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32) (i32.const 1) 1423 OpcodeI32Const, 1, // (then (i32.const 1)) 1424 OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1)) 1425 OpcodeEnd, // if 1426 OpcodeEnd, // func 1427 }}}, 1428 }, 1429 expectedErr: `too many results in else block 1430 have (i32, i32) 1431 want (i32)`, 1432 }, 1433 { 1434 name: `if.wast - type-both-value-nums-vs-num`, 1435 // This should err because the if branch returns two values, but its type use requires one: 1436 // (module (func $type-both-value-nums-vs-num (result i32) 1437 // (if (result i32) (i32.const 1) (then (i32.const 1) (i32.const 1)) (else (i32.const 1) (i32.const 1))) 1438 // )) 1439 module: &Module{ 1440 TypeSection: []FunctionType{v_i32}, 1441 FunctionSection: []Index{0}, 1442 CodeSection: []Code{{Body: []byte{ 1443 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32) (i32.const 1) 1444 OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1)) 1445 OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1)) 1446 OpcodeEnd, // if 1447 OpcodeEnd, // func 1448 }}}, 1449 }, 1450 expectedErr: `too many results in if block 1451 have (i32, i32) 1452 want (i32)`, 1453 }, 1454 { 1455 name: `if.wast - type-both-different-value-nums-vs-nums`, 1456 // This should err because the if branch returns three values, but its type use requires two: 1457 // (module (func $type-both-different-value-nums-vs-nums (result i32 i32) 1458 // (if (result i32 i32) (i32.const 1) (then (i32.const 1) (i32.const 1) (i32.const 1)) (else (i32.const 1))) 1459 // )) 1460 module: &Module{ 1461 TypeSection: []FunctionType{v_i32i32}, 1462 FunctionSection: []Index{0}, 1463 CodeSection: []Code{{Body: []byte{ 1464 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1465 OpcodeI32Const, 1, OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1) (i32.const 1)) 1466 OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1)) 1467 OpcodeEnd, // if 1468 OpcodeEnd, // func 1469 }}}, 1470 }, 1471 expectedErr: `too many results in if block 1472 have (i32, i32, i32) 1473 want (i32, i32)`, 1474 }, 1475 { 1476 name: `if.wast - type-then-break-last-void-vs-nums`, 1477 // This should err because the branch in the if returns no values, but its type use requires two: 1478 // (module (func $type-then-break-last-void-vs-nums (result i32 i32) 1479 // (if (result i32 i32) (i32.const 1) (then (br 0)) (else (i32.const 1) (i32.const 1))) 1480 // )) 1481 module: &Module{ 1482 TypeSection: []FunctionType{v_i32i32}, 1483 FunctionSection: []Index{0}, 1484 CodeSection: []Code{{Body: []byte{ 1485 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1486 OpcodeBr, 0, // (then (br 0)) 1487 OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1))) 1488 OpcodeEnd, // if 1489 OpcodeEnd, // func 1490 }}}, 1491 }, 1492 expectedErr: `not enough results in br block 1493 have () 1494 want (i32, i32)`, 1495 }, 1496 { 1497 name: `if.wast - type-else-break-last-void-vs-nums`, 1498 // This should err because the branch in the else returns no values, but its type use requires two: 1499 // (module (func $type-else-break-last-void-vs-nums (result i32 i32) 1500 // (if (result i32 i32) (i32.const 1) (then (i32.const 1) (i32.const 1)) (else (br 0))) 1501 // )) 1502 module: &Module{ 1503 TypeSection: []FunctionType{v_i32i32}, 1504 FunctionSection: []Index{0}, 1505 CodeSection: []Code{{Body: []byte{ 1506 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1507 OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1)) 1508 OpcodeElse, OpcodeBr, 0, // (else (br 0)) 1509 OpcodeEnd, // if 1510 OpcodeEnd, // func 1511 }}}, 1512 }, 1513 expectedErr: `not enough results in br block 1514 have () 1515 want (i32, i32)`, 1516 }, 1517 { 1518 name: `if.wast - type-then-break-empty-vs-nums`, 1519 // This should err because the branch in the if returns no values, but its type use requires two: 1520 // (module (func $type-then-break-empty-vs-nums (result i32 i32) 1521 // (if (result i32 i32) (i32.const 1) 1522 // (then (br 0) (i32.const 1) (i32.const 1)) 1523 // (else (i32.const 1) (i32.const 1)) 1524 // ) 1525 // )) 1526 module: &Module{ 1527 TypeSection: []FunctionType{v_i32i32}, 1528 FunctionSection: []Index{0}, 1529 CodeSection: []Code{{Body: []byte{ 1530 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1531 OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (br 0) (i32.const 1) (i32.const 1)) 1532 // ^^ NOTE: consts are outside the br block 1533 OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1)) 1534 OpcodeEnd, // if 1535 OpcodeEnd, // func 1536 }}}, 1537 }, 1538 expectedErr: `not enough results in br block 1539 have () 1540 want (i32, i32)`, 1541 }, 1542 { 1543 name: `if.wast - type-else-break-empty-vs-nums`, 1544 // This should err because the branch in the else returns no values, but its type use requires two: 1545 // (module (func $type-else-break-empty-vs-nums (result i32 i32) 1546 // (if (result i32 i32) (i32.const 1) 1547 // (then (i32.const 1) (i32.const 1)) 1548 // (else (br 0) (i32.const 1) (i32.const 1)) 1549 // ) 1550 // )) 1551 module: &Module{ 1552 TypeSection: []FunctionType{v_i32i32}, 1553 FunctionSection: []Index{0}, 1554 CodeSection: []Code{{Body: []byte{ 1555 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1556 OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1)) 1557 OpcodeElse, OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (br 0) (i32.const 1) (i32.const 1)) 1558 // ^^ NOTE: consts are outside the br block 1559 OpcodeEnd, // if 1560 OpcodeEnd, // func 1561 }}}, 1562 }, 1563 expectedErr: `not enough results in br block 1564 have () 1565 want (i32, i32)`, 1566 }, 1567 { 1568 name: `if.wast - type-then-break-void-vs-nums`, 1569 // This should err because the branch in the if evaluates to no values, but its type use requires two: 1570 // (module (func $type-then-break-void-vs-nums (result i32 i32) 1571 // (if (result i32 i32) (i32.const 1) 1572 // (then (br 0 (nop)) (i32.const 1) (i32.const 1)) 1573 // (else (i32.const 1) (i32.const 1)) 1574 // ) 1575 // )) 1576 module: &Module{ 1577 TypeSection: []FunctionType{v_i32i32}, 1578 FunctionSection: []Index{0}, 1579 CodeSection: []Code{{Body: []byte{ 1580 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1581 OpcodeNop, OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (br 0 (nop)) (i32.const 1) (i32.const 1)) 1582 // ^^ NOTE: consts are outside the br block 1583 OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1)) 1584 OpcodeEnd, // if 1585 OpcodeEnd, // func 1586 }}}, 1587 }, 1588 expectedErr: `not enough results in br block 1589 have () 1590 want (i32, i32)`, 1591 }, 1592 { 1593 name: `if.wast - type-else-break-void-vs-nums`, 1594 // This should err because the branch in the else evaluates to no values, but its type use requires two: 1595 // (module (func $type-else-break-void-vs-nums (result i32 i32) 1596 // (if (result i32 i32) (i32.const 1) 1597 // (then (i32.const 1) (i32.const 1)) 1598 // (else (br 0 (nop)) (i32.const 1) (i32.const 1)) 1599 // ) 1600 // )) 1601 module: &Module{ 1602 TypeSection: []FunctionType{v_i32i32}, 1603 FunctionSection: []Index{0}, 1604 CodeSection: []Code{{Body: []byte{ 1605 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1606 OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1)) 1607 OpcodeElse, OpcodeNop, OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (br 0 (nop)) (i32.const 1) (i32.const 1)) 1608 // ^^ NOTE: consts are outside the br block 1609 OpcodeEnd, // if 1610 OpcodeEnd, // func 1611 }}}, 1612 }, 1613 expectedErr: `not enough results in br block 1614 have () 1615 want (i32, i32)`, 1616 }, 1617 { 1618 name: `if.wast - type-then-break-num-vs-nums`, 1619 // This should err because the branch in the if evaluates to one value, but its type use requires two: 1620 // (module (func $type-then-break-num-vs-nums (result i32 i32) 1621 // (if (result i32 i32) (i32.const 1) 1622 // (then (br 0 (i64.const 1)) (i32.const 1) (i32.const 1)) 1623 // (else (i32.const 1) (i32.const 1)) 1624 // ) 1625 // )) 1626 module: &Module{ 1627 TypeSection: []FunctionType{v_i32i32}, 1628 FunctionSection: []Index{0}, 1629 CodeSection: []Code{{Body: []byte{ 1630 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1631 OpcodeI64Const, 1, OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (br 0 (i64.const 1)) (i32.const 1) (i32.const 1)) 1632 // ^^ NOTE: only one (incorrect) const is inside the br block 1633 OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1)) 1634 OpcodeEnd, // if 1635 OpcodeEnd, // func 1636 }}}, 1637 }, 1638 expectedErr: `not enough results in br block 1639 have (i64) 1640 want (i32, i32)`, 1641 }, 1642 { 1643 name: `if.wast - type-else-break-num-vs-nums`, 1644 // This should err because the branch in the else evaluates to one value, but its type use requires two: 1645 // (module (func $type-else-break-num-vs-nums (result i32 i32) 1646 // (if (result i32 i32) (i32.const 1) 1647 // (then (i32.const 1) (i32.const 1)) 1648 // (else (br 0 (i64.const 1)) (i32.const 1) (i32.const 1)) 1649 // ) 1650 // )) 1651 module: &Module{ 1652 TypeSection: []FunctionType{v_i32i32}, 1653 FunctionSection: []Index{0}, 1654 CodeSection: []Code{{Body: []byte{ 1655 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1656 OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1)) 1657 OpcodeElse, OpcodeI64Const, 1, OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (br 0 (i64.const 1)) (i32.const 1) (i32.const 1)) 1658 // ^^ NOTE: only one (incorrect) const is inside the br block 1659 OpcodeEnd, // if 1660 OpcodeEnd, // func 1661 }}}, 1662 }, 1663 expectedErr: `not enough results in br block 1664 have (i64) 1665 want (i32, i32)`, 1666 }, 1667 { 1668 name: `if.wast - type-then-break-partial-vs-nums`, 1669 // This should err because the branch in the if evaluates to one value, but its type use requires two: 1670 // (module (func $type-then-break-partial-vs-nums (result i32 i32) 1671 // (i32.const 1) 1672 // (if (result i32 i32) (i32.const 1) 1673 // (then (br 0 (i64.const 1)) (i32.const 1)) 1674 // (else (i32.const 1)) 1675 // ) 1676 // )) 1677 module: &Module{ 1678 TypeSection: []FunctionType{v_i32i32}, 1679 FunctionSection: []Index{0}, 1680 CodeSection: []Code{{Body: []byte{ 1681 OpcodeI32Const, 1, // (i32.const 1) 1682 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1683 OpcodeI64Const, 1, OpcodeBr, 0, OpcodeI32Const, 1, // (then (br 0 (i64.const 1)) (i32.const 1)) 1684 // ^^ NOTE: only one (incorrect) const is inside the br block 1685 OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1)) 1686 OpcodeEnd, // if 1687 OpcodeEnd, // func 1688 }}}, 1689 }, 1690 expectedErr: `not enough results in br block 1691 have (i64) 1692 want (i32, i32)`, 1693 }, 1694 { 1695 name: `if.wast - type-else-break-partial-vs-nums`, 1696 // This should err because the branch in the if evaluates to one value, but its type use requires two: 1697 // (module (func $type-else-break-partial-vs-nums (result i32 i32) 1698 // (i32.const 1) 1699 // (if (result i32 i32) (i32.const 1) 1700 // (then (i32.const 1)) 1701 // (else (br 0 (i64.const 1)) (i32.const 1)) 1702 // ) 1703 // )) 1704 module: &Module{ 1705 TypeSection: []FunctionType{v_i32i32}, 1706 FunctionSection: []Index{0}, 1707 CodeSection: []Code{{Body: []byte{ 1708 OpcodeI32Const, 1, // (i32.const 1) 1709 OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1) 1710 OpcodeI32Const, 1, // (then (i32.const 1)) 1711 OpcodeElse, OpcodeI64Const, 1, OpcodeBr, 0, OpcodeI32Const, 1, // (else (br 0 (i64.const 1)) (i32.const 1)) 1712 // ^^ NOTE: only one (incorrect) const is inside the br block 1713 OpcodeEnd, // if 1714 OpcodeEnd, // func 1715 }}}, 1716 }, 1717 expectedErr: `not enough results in if block 1718 have (i32) 1719 want (i32, i32)`, 1720 }, 1721 { 1722 name: `if.wast - type-param-void-vs-num`, 1723 // This should err because the stack has no values, but the if type use requires two: 1724 // (module (func $type-param-void-vs-num 1725 // (if (param i32) (i32.const 1) (then (drop))) 1726 // )) 1727 module: &Module{ 1728 TypeSection: []FunctionType{v_v, i32_v}, 1729 FunctionSection: []Index{0}, 1730 CodeSection: []Code{{Body: []byte{ 1731 OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param i32) (i32.const 1) 1732 OpcodeDrop, // (then (drop))) 1733 OpcodeEnd, // if 1734 OpcodeEnd, // func 1735 }}}, 1736 }, 1737 expectedErr: `not enough params for if block 1738 have () 1739 want (i32)`, 1740 }, 1741 { 1742 name: `if.wast - type-param-void-vs-nums`, 1743 // This should err because the stack has no values, but the if type use requires two: 1744 // (module (func $type-param-void-vs-nums 1745 // (if (param i32 f64) (i32.const 1) (then (drop) (drop))) 1746 // )) 1747 module: &Module{ 1748 TypeSection: []FunctionType{v_v, i32f64_v}, 1749 FunctionSection: []Index{0}, 1750 CodeSection: []Code{{Body: []byte{ 1751 OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param i32 f64) (i32.const 1) 1752 OpcodeI32Const, 1, OpcodeDrop, // (then (drop) (drop)) 1753 OpcodeEnd, // if 1754 OpcodeEnd, // func 1755 }}}, 1756 }, 1757 expectedErr: `not enough params for if block 1758 have () 1759 want (i32, f64)`, 1760 }, 1761 { 1762 name: `if.wast - type-param-num-vs-num`, 1763 // This should err because the stack has a different value that what the if type use requires: 1764 // (module (func $type-param-num-vs-num 1765 // (f32.const 0) (if (param i32) (i32.const 1) (then (drop))) 1766 // )) 1767 module: &Module{ 1768 TypeSection: []FunctionType{v_v, i32_v}, 1769 FunctionSection: []Index{0}, 1770 CodeSection: []Code{{Body: []byte{ 1771 OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0) 1772 OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param i32) (i32.const 1) 1773 OpcodeDrop, // (then (drop)) 1774 OpcodeEnd, // if 1775 OpcodeEnd, // func 1776 }}}, 1777 }, 1778 expectedErr: "cannot use f32 in if block as param[0] type i32", 1779 }, 1780 { 1781 name: `if.wast - type-param-num-vs-nums`, 1782 // This should err because the stack has one value, but the if type use requires two: 1783 // (module (func $type-param-num-vs-nums 1784 // (f32.const 0) (if (param f32 i32) (i32.const 1) (then (drop) (drop))) 1785 // )) 1786 module: &Module{ 1787 TypeSection: []FunctionType{v_v, f32i32_v}, 1788 FunctionSection: []Index{0}, 1789 CodeSection: []Code{{Body: []byte{ 1790 OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0) 1791 OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param f32 i32) (i32.const 1) 1792 OpcodeDrop, OpcodeDrop, // (then (drop) (drop)) 1793 OpcodeEnd, // if 1794 OpcodeEnd, // func 1795 }}}, 1796 }, 1797 expectedErr: `not enough params for if block 1798 have (f32) 1799 want (f32, i32)`, 1800 }, 1801 { 1802 name: `if.wast - type-param-nested-void-vs-num`, 1803 // This should err because the stack has no values, but the if type use requires one: 1804 // (module (func $type-param-nested-void-vs-num 1805 // (block (if (param i32) (i32.const 1) (then (drop)))) 1806 // )) 1807 module: &Module{ 1808 TypeSection: []FunctionType{v_v, i32_v}, 1809 FunctionSection: []Index{0}, 1810 CodeSection: []Code{{Body: []byte{ 1811 OpcodeBlock, 0x40, // (block 1812 OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param i32) (i32.const 1) 1813 OpcodeDrop, // (then (drop)) 1814 OpcodeEnd, // block 1815 OpcodeEnd, // if 1816 OpcodeEnd, // func 1817 }}}, 1818 }, 1819 expectedErr: `not enough params for if block 1820 have () 1821 want (i32)`, 1822 }, 1823 { 1824 name: `if.wast - type-param-void-vs-nums`, 1825 // This should err because the stack has no values, but the if type use requires two: 1826 // (module (func $type-param-void-vs-nums 1827 // (block (if (param i32 f64) (i32.const 1) (then (drop) (drop)))) 1828 // )) 1829 module: &Module{ 1830 TypeSection: []FunctionType{v_v, i32f64_v}, 1831 FunctionSection: []Index{0}, 1832 CodeSection: []Code{{Body: []byte{ 1833 OpcodeBlock, 0x40, // (block 1834 OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param i32 f64) (i32.const 1) 1835 OpcodeDrop, // (then (drop) (drop)) 1836 OpcodeEnd, // block 1837 OpcodeEnd, // if 1838 OpcodeEnd, // func 1839 }}}, 1840 }, 1841 expectedErr: `not enough params for if block 1842 have () 1843 want (i32, f64)`, 1844 }, 1845 { 1846 name: `if.wast - type-param-num-vs-num`, 1847 // This should err because the stack has a different values than required by the if type use: 1848 // (module (func $type-param-num-vs-num 1849 // (block (f32.const 0) (if (param i32) (i32.const 1) (then (drop)))) 1850 // )) 1851 module: &Module{ 1852 TypeSection: []FunctionType{v_v, i32_v}, 1853 FunctionSection: []Index{0}, 1854 CodeSection: []Code{{Body: []byte{ 1855 OpcodeBlock, 0x40, // (block 1856 OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0) 1857 OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param i32) (i32.const 1) 1858 OpcodeDrop, // (then (drop)) 1859 OpcodeEnd, // block 1860 OpcodeEnd, // if 1861 OpcodeEnd, // func 1862 }}}, 1863 }, 1864 expectedErr: "cannot use f32 in if block as param[0] type i32", 1865 }, 1866 { 1867 name: `if.wast - type-param-num-vs-nums`, 1868 // This should err because the stack has one value, but the if type use requires two: 1869 // (module (func $type-param-num-vs-nums 1870 // (block (f32.const 0) (if (param f32 i32) (i32.const 1) (then (drop) (drop)))) 1871 // )) 1872 module: &Module{ 1873 TypeSection: []FunctionType{v_v, f32i32_v}, 1874 FunctionSection: []Index{0}, 1875 CodeSection: []Code{{Body: []byte{ 1876 OpcodeBlock, 0x40, // (block 1877 OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0) 1878 OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param f32 i32) (i32.const 1) 1879 OpcodeDrop, // (then (drop) (drop)) 1880 OpcodeEnd, // block 1881 OpcodeEnd, // if 1882 OpcodeEnd, // func 1883 }}}, 1884 }, 1885 expectedErr: `not enough params for if block 1886 have (f32) 1887 want (f32, i32)`, 1888 }, 1889 1890 // test/core/loop.wast 1891 { 1892 name: `loop.wast - wrong signature for loop type use`, 1893 // This should err because the loop type use returns no values, but its block returns one: 1894 // (module 1895 // (type $sig (func)) 1896 // (func (loop (type $sig) (i32.const 0))) 1897 // ) 1898 module: &Module{ 1899 TypeSection: []FunctionType{v_v}, 1900 FunctionSection: []Index{0}, 1901 CodeSection: []Code{{Body: []byte{ 1902 OpcodeLoop, 0, OpcodeI32Const, 0, // (loop (type $sig) (i32.const 0)) 1903 OpcodeEnd, // loop 1904 OpcodeEnd, // func 1905 }}}, 1906 }, 1907 expectedErr: `too many results in loop block 1908 have (i32) 1909 want ()`, 1910 }, 1911 { 1912 name: `loop.wast - type-value-nums-vs-void`, 1913 // This should err because the empty block type requires no values, but the loop returns two: 1914 // (module (func $type-value-nums-vs-void 1915 // (loop (i32.const 1) (i32.const 2)) 1916 // )) 1917 module: &Module{ 1918 TypeSection: []FunctionType{v_v}, 1919 FunctionSection: []Index{0}, 1920 CodeSection: []Code{{Body: []byte{ 1921 OpcodeLoop, 0x40, OpcodeI32Const, 1, OpcodeI32Const, 2, // (loop (i32.const 1) (i32.const 2)) 1922 OpcodeEnd, // loop 1923 OpcodeEnd, // func 1924 }}}, 1925 }, 1926 expectedErr: `too many results in loop block 1927 have (i32, i32) 1928 want ()`, 1929 }, 1930 { 1931 name: `loop.wast - type-value-empty-vs-nums`, 1932 // This should err because the loop type use returns two values, but the block returns none: 1933 // (module (func $type-value-empty-vs-nums (result i32 i32) 1934 // (loop (result i32 i32)) 1935 // )) 1936 module: &Module{ 1937 TypeSection: []FunctionType{v_i32i32}, 1938 FunctionSection: []Index{0}, 1939 CodeSection: []Code{{Body: []byte{ 1940 OpcodeLoop, 0x0, // (loop (result i32 i32)) - matches existing func type 1941 OpcodeEnd, // loop 1942 OpcodeEnd, // func 1943 }}}, 1944 }, 1945 expectedErr: `not enough results in loop block 1946 have () 1947 want (i32, i32)`, 1948 }, 1949 { 1950 name: `loop.wast - type-value-void-vs-nums`, 1951 // This should err because the loop type use returns two values, but the block returns none: 1952 // (module (func $type-value-void-vs-nums (result i32 i32) 1953 // (loop (result i32 i32) (nop)) 1954 // )) 1955 module: &Module{ 1956 TypeSection: []FunctionType{v_i32i32}, 1957 FunctionSection: []Index{0}, 1958 CodeSection: []Code{{Body: []byte{ 1959 OpcodeLoop, 0x0, // (loop (result i32 i32) - matches existing func type 1960 OpcodeNop, // (nop) 1961 OpcodeEnd, // loop 1962 OpcodeEnd, // func 1963 }}}, 1964 }, 1965 expectedErr: `not enough results in loop block 1966 have () 1967 want (i32, i32)`, 1968 }, 1969 { 1970 name: `loop.wast - type-value-num-vs-nums`, 1971 // This should err because the loop type use returns two values, but the block returns one: 1972 // (module (func $type-value-num-vs-nums (result i32 i32) 1973 // (loop (result i32 i32) (i32.const 0)) 1974 // )) 1975 module: &Module{ 1976 TypeSection: []FunctionType{v_i32i32}, 1977 FunctionSection: []Index{0}, 1978 CodeSection: []Code{{Body: []byte{ 1979 OpcodeLoop, 0x0, // (loop (result i32 i32) - matches existing func type 1980 OpcodeI32Const, 0, // (i32.const 0) 1981 OpcodeEnd, // loop 1982 OpcodeEnd, // func 1983 }}}, 1984 }, 1985 expectedErr: `not enough results in loop block 1986 have (i32) 1987 want (i32, i32)`, 1988 }, 1989 { 1990 name: `loop.wast - type-value-partial-vs-nums`, 1991 // This should err because the loop type use returns two values, but the block returns one: 1992 // (module (func $type-value-partial-vs-nums (result i32 i32) 1993 // (i32.const 1) (loop (result i32 i32) (i32.const 2)) 1994 // )) 1995 module: &Module{ 1996 TypeSection: []FunctionType{v_i32i32}, 1997 FunctionSection: []Index{0}, 1998 CodeSection: []Code{{Body: []byte{ 1999 OpcodeI32Const, 1, // (i32.const 1) - NOTE: outside the loop! 2000 OpcodeLoop, 0x0, // (loop (result i32 i32) - matches existing func type 2001 OpcodeI32Const, 2, // (i32.const 2) 2002 OpcodeEnd, // loop 2003 OpcodeEnd, // func 2004 }}}, 2005 }, 2006 expectedErr: `not enough results in loop block 2007 have (i32) 2008 want (i32, i32)`, 2009 }, 2010 { 2011 name: `loop.wast - type-value-nums-vs-num`, 2012 // This should err because the loop type use returns one value, but the block returns two: 2013 // (module (func $type-value-nums-vs-num (result i32) 2014 // (loop (result i32) (i32.const 1) (i32.const 2)) 2015 // )) 2016 module: &Module{ 2017 TypeSection: []FunctionType{v_i32}, 2018 FunctionSection: []Index{0}, 2019 CodeSection: []Code{{Body: []byte{ 2020 OpcodeLoop, 0x0, // (loop (result i32) - matches existing func type 2021 OpcodeI32Const, 1, OpcodeI32Const, 2, // (i32.const 1) (i32.const 2)) 2022 OpcodeEnd, // loop 2023 OpcodeEnd, // func 2024 }}}, 2025 }, 2026 expectedErr: `too many results in loop block 2027 have (i32, i32) 2028 want (i32)`, 2029 }, 2030 { 2031 name: `loop.wast - type-param-void-vs-num`, 2032 // This should err because the loop type use requires one param, but the stack has none: 2033 // (module (func $type-param-void-vs-num 2034 // (loop (param i32) (drop)) 2035 // )) 2036 module: &Module{ 2037 TypeSection: []FunctionType{v_v, i32_v}, 2038 FunctionSection: []Index{0}, 2039 CodeSection: []Code{{Body: []byte{ 2040 OpcodeLoop, 0x1, // (loop (param i32) 2041 OpcodeDrop, // (drop) 2042 OpcodeEnd, // loop 2043 OpcodeEnd, // func 2044 }}}, 2045 }, 2046 expectedErr: `not enough params for loop block 2047 have () 2048 want (i32)`, 2049 }, 2050 { 2051 name: `loop.wast - type-param-void-vs-nums`, 2052 // This should err because the loop type use requires two params, but the stack has none: 2053 // (module (func $type-param-void-vs-nums 2054 // (loop (param i32 f64) (drop) (drop)) 2055 // )) 2056 module: &Module{ 2057 TypeSection: []FunctionType{v_v, i32f64_v}, 2058 FunctionSection: []Index{0}, 2059 CodeSection: []Code{{Body: []byte{ 2060 OpcodeLoop, 0x1, // (loop (param i32 f64) 2061 OpcodeDrop, // (drop) 2062 OpcodeDrop, // (drop) 2063 OpcodeEnd, // loop 2064 OpcodeEnd, // func 2065 }}}, 2066 }, 2067 expectedErr: `not enough params for loop block 2068 have () 2069 want (i32, f64)`, 2070 }, 2071 { 2072 name: `loop.wast - type-param-num-vs-num`, 2073 // This should err because the loop type use requires a different param type than what's on the stack: 2074 // (module (func $type-param-num-vs-num 2075 // (f32.const 0) (loop (param i32) (drop)) 2076 // )) 2077 module: &Module{ 2078 TypeSection: []FunctionType{v_v, i32_v}, 2079 FunctionSection: []Index{0}, 2080 CodeSection: []Code{{Body: []byte{ 2081 OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0) 2082 OpcodeLoop, 0x1, // (loop (param i32) 2083 OpcodeDrop, // (drop) 2084 OpcodeEnd, // loop 2085 OpcodeEnd, // func 2086 }}}, 2087 }, 2088 expectedErr: "cannot use f32 in loop block as param[0] type i32", 2089 }, 2090 { 2091 name: `loop.wast - type-param-num-vs-num`, 2092 // This should err because the loop type use requires a more parameters than what's on the stack: 2093 // (module (func $type-param-num-vs-nums 2094 // (f32.const 0) (loop (param f32 i32) (drop) (drop)) 2095 // )) 2096 module: &Module{ 2097 TypeSection: []FunctionType{v_v, f32i32_v}, 2098 FunctionSection: []Index{0}, 2099 CodeSection: []Code{{Body: []byte{ 2100 OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0) 2101 OpcodeLoop, 0x1, // (loop (param f32 i32) 2102 OpcodeDrop, OpcodeDrop, // (drop) (drop) 2103 OpcodeEnd, // loop 2104 OpcodeEnd, // func 2105 }}}, 2106 }, 2107 expectedErr: `not enough params for loop block 2108 have (f32) 2109 want (f32, i32)`, 2110 }, 2111 { 2112 name: `loop.wast - type-param-nested-void-vs-num`, 2113 // This should err because the loop type use requires a more parameters than what's on the stack: 2114 // (module (func $type-param-nested-void-vs-num 2115 // (block (loop (param i32) (drop))) 2116 // )) 2117 module: &Module{ 2118 TypeSection: []FunctionType{v_v, i32_v}, 2119 FunctionSection: []Index{0}, 2120 CodeSection: []Code{{Body: []byte{ 2121 OpcodeBlock, 0x40, // (block 2122 OpcodeLoop, 0x1, // (loop (param i32) 2123 OpcodeDrop, // (drop) 2124 OpcodeEnd, // loop 2125 OpcodeEnd, // block 2126 OpcodeEnd, // func 2127 }}}, 2128 }, 2129 expectedErr: `not enough params for loop block 2130 have () 2131 want (i32)`, 2132 }, 2133 { 2134 name: `loop.wast - type-param-void-vs-nums`, 2135 // This should err because the loop type use requires a more parameters than what's on the stack: 2136 // (module (func $type-param-void-vs-nums 2137 // (block (loop (param i32 f64) (drop) (drop))) 2138 // )) 2139 module: &Module{ 2140 TypeSection: []FunctionType{v_v, i32f64_v}, 2141 FunctionSection: []Index{0}, 2142 CodeSection: []Code{{Body: []byte{ 2143 OpcodeBlock, 0x40, // (block 2144 OpcodeLoop, 0x1, // (loop (param i32 f64) 2145 OpcodeDrop, OpcodeDrop, // (drop) (drop) 2146 OpcodeEnd, // loop 2147 OpcodeEnd, // block 2148 OpcodeEnd, // func 2149 }}}, 2150 }, 2151 expectedErr: `not enough params for loop block 2152 have () 2153 want (i32, f64)`, 2154 }, 2155 { 2156 name: `loop.wast - type-param-void-vs-nums`, 2157 // This should err because the loop type use requires a different param type than what's on the stack: 2158 // (module (func $type-param-num-vs-num 2159 // (block (f32.const 0) (loop (param i32) (drop))) 2160 // )) 2161 module: &Module{ 2162 TypeSection: []FunctionType{v_v, i32_v}, 2163 FunctionSection: []Index{0}, 2164 CodeSection: []Code{{Body: []byte{ 2165 OpcodeBlock, 0x40, // (block 2166 OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0) 2167 OpcodeLoop, 0x1, // (loop (param i32) 2168 OpcodeDrop, // (drop) 2169 OpcodeEnd, // loop 2170 OpcodeEnd, // block 2171 OpcodeEnd, // func 2172 }}}, 2173 }, 2174 expectedErr: "cannot use f32 in loop block as param[0] type i32", 2175 }, 2176 { 2177 name: `loop.wast - type-param-void-vs-nums`, 2178 // This should err because the loop type use requires a more parameters than what's on the stack: 2179 // (module (func $type-param-num-vs-nums 2180 // (block (f32.const 0) (loop (param f32 i32) (drop) (drop))) 2181 // )) 2182 module: &Module{ 2183 TypeSection: []FunctionType{v_v, f32i32_v}, 2184 FunctionSection: []Index{0}, 2185 CodeSection: []Code{{Body: []byte{ 2186 OpcodeBlock, 0x40, // (block 2187 OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0) 2188 OpcodeLoop, 0x1, // (loop (param f32 i32) 2189 OpcodeDrop, OpcodeDrop, // (drop) (drop) 2190 OpcodeEnd, // loop 2191 OpcodeEnd, // block 2192 OpcodeEnd, // func 2193 }}}, 2194 }, 2195 expectedErr: `not enough params for loop block 2196 have (f32) 2197 want (f32, i32)`, 2198 }, 2199 } 2200 2201 for _, tt := range tests { 2202 tc := tt 2203 2204 t.Run(tc.name, func(t *testing.T) { 2205 err := tc.module.validateFunction(&stacks{}, api.CoreFeatureMultiValue, 2206 0, []Index{0}, nil, nil, nil, nil, bytes.NewReader(nil)) 2207 require.EqualError(t, err, tc.expectedErr) 2208 }) 2209 } 2210 } 2211 2212 func TestModule_funcValidation_CallIndirect(t *testing.T) { 2213 t.Run("ok", func(t *testing.T) { 2214 m := &Module{ 2215 TypeSection: []FunctionType{v_v}, 2216 FunctionSection: []Index{0}, 2217 CodeSection: []Code{{Body: []byte{ 2218 OpcodeI32Const, 1, 2219 OpcodeCallIndirect, 0, 0, 2220 OpcodeEnd, 2221 }}}, 2222 } 2223 err := m.validateFunction(&stacks{}, api.CoreFeatureReferenceTypes, 2224 0, []Index{0}, nil, &Memory{}, []Table{{Type: RefTypeFuncref}}, nil, bytes.NewReader(nil)) 2225 require.NoError(t, err) 2226 }) 2227 t.Run("non zero table index", func(t *testing.T) { 2228 m := &Module{ 2229 TypeSection: []FunctionType{v_v}, 2230 FunctionSection: []Index{0}, 2231 CodeSection: []Code{{Body: []byte{ 2232 OpcodeI32Const, 1, 2233 OpcodeCallIndirect, 0, 100, 2234 OpcodeEnd, 2235 }}}, 2236 } 2237 t.Run("disabled", func(t *testing.T) { 2238 err := m.validateFunction(&stacks{}, api.CoreFeaturesV1, 2239 0, []Index{0}, nil, &Memory{}, []Table{{}, {}}, nil, bytes.NewReader(nil)) 2240 require.EqualError(t, err, "table index must be zero but was 100: feature \"reference-types\" is disabled") 2241 }) 2242 t.Run("enabled but out of range", func(t *testing.T) { 2243 err := m.validateFunction(&stacks{}, api.CoreFeatureReferenceTypes, 2244 0, []Index{0}, nil, &Memory{}, []Table{{}, {}}, nil, bytes.NewReader(nil)) 2245 require.EqualError(t, err, "unknown table index: 100") 2246 }) 2247 }) 2248 t.Run("non funcref table", func(t *testing.T) { 2249 m := &Module{ 2250 TypeSection: []FunctionType{v_v}, 2251 FunctionSection: []Index{0}, 2252 CodeSection: []Code{{Body: []byte{ 2253 OpcodeI32Const, 1, 2254 OpcodeCallIndirect, 0, 0, 2255 OpcodeEnd, 2256 }}}, 2257 } 2258 err := m.validateFunction(&stacks{}, api.CoreFeatureReferenceTypes, 2259 0, []Index{0}, nil, &Memory{}, []Table{{Type: RefTypeExternref}}, nil, bytes.NewReader(nil)) 2260 require.EqualError(t, err, "table is not funcref type but was externref for call_indirect") 2261 }) 2262 } 2263 2264 func TestModule_funcValidation_RefTypes(t *testing.T) { 2265 tests := []struct { 2266 name string 2267 body []byte 2268 flag api.CoreFeatures 2269 declaredFunctionIndexes map[Index]struct{} 2270 expectedErr string 2271 }{ 2272 { 2273 name: "ref.null (funcref)", 2274 flag: api.CoreFeatureReferenceTypes, 2275 body: []byte{ 2276 OpcodeRefNull, ValueTypeFuncref, 2277 OpcodeDrop, OpcodeEnd, 2278 }, 2279 }, 2280 { 2281 name: "ref.null (externref)", 2282 flag: api.CoreFeatureReferenceTypes, 2283 body: []byte{ 2284 OpcodeRefNull, ValueTypeExternref, 2285 OpcodeDrop, OpcodeEnd, 2286 }, 2287 }, 2288 { 2289 name: "ref.null - disabled", 2290 flag: api.CoreFeaturesV1, 2291 body: []byte{ 2292 OpcodeRefNull, ValueTypeFuncref, 2293 OpcodeDrop, OpcodeEnd, 2294 }, 2295 expectedErr: "ref.null invalid as feature \"reference-types\" is disabled", 2296 }, 2297 { 2298 name: "ref.is_null", 2299 flag: api.CoreFeatureReferenceTypes, 2300 body: []byte{ 2301 OpcodeRefNull, ValueTypeFuncref, 2302 OpcodeRefIsNull, 2303 OpcodeDrop, OpcodeEnd, 2304 }, 2305 }, 2306 { 2307 name: "ref.is_null - disabled", 2308 flag: api.CoreFeaturesV1, 2309 body: []byte{ 2310 OpcodeRefIsNull, 2311 OpcodeDrop, OpcodeEnd, 2312 }, 2313 expectedErr: `ref.is_null invalid as feature "reference-types" is disabled`, 2314 }, 2315 { 2316 name: "ref.func", 2317 flag: api.CoreFeatureReferenceTypes, 2318 declaredFunctionIndexes: map[uint32]struct{}{0: {}}, 2319 body: []byte{ 2320 OpcodeRefFunc, 0, 2321 OpcodeDrop, OpcodeEnd, 2322 }, 2323 }, 2324 { 2325 name: "ref.func - undeclared function index", 2326 flag: api.CoreFeatureReferenceTypes, 2327 declaredFunctionIndexes: map[uint32]struct{}{0: {}}, 2328 body: []byte{ 2329 OpcodeRefFunc, 100, 2330 OpcodeDrop, OpcodeEnd, 2331 }, 2332 expectedErr: `undeclared function index 100 for ref.func`, 2333 }, 2334 { 2335 name: "ref.func", 2336 flag: api.CoreFeaturesV1, 2337 declaredFunctionIndexes: map[uint32]struct{}{0: {}}, 2338 body: []byte{ 2339 OpcodeRefFunc, 0, 2340 OpcodeDrop, OpcodeEnd, 2341 }, 2342 expectedErr: "ref.func invalid as feature \"reference-types\" is disabled", 2343 }, 2344 } 2345 2346 for _, tt := range tests { 2347 tc := tt 2348 t.Run(tc.name, func(t *testing.T) { 2349 m := &Module{ 2350 TypeSection: []FunctionType{v_v}, 2351 FunctionSection: []Index{0}, 2352 CodeSection: []Code{{Body: tc.body}}, 2353 } 2354 err := m.validateFunction(&stacks{}, tc.flag, 2355 0, []Index{0}, nil, nil, nil, tc.declaredFunctionIndexes, bytes.NewReader(nil)) 2356 if tc.expectedErr != "" { 2357 require.EqualError(t, err, tc.expectedErr) 2358 } else { 2359 require.NoError(t, err) 2360 } 2361 }) 2362 } 2363 } 2364 2365 func TestModule_funcValidation_TableGrowSizeFill(t *testing.T) { 2366 tables := []Table{{Type: RefTypeFuncref}, {Type: RefTypeExternref}} 2367 tests := []struct { 2368 name string 2369 body []byte 2370 flag api.CoreFeatures 2371 expectedErr string 2372 }{ 2373 { 2374 name: "table.grow (funcref)", 2375 body: []byte{ 2376 OpcodeRefNull, RefTypeFuncref, 2377 OpcodeI32Const, 1, // number of elements 2378 OpcodeMiscPrefix, OpcodeMiscTableGrow, 2379 0, // Table Index. 2380 OpcodeDrop, 2381 OpcodeEnd, 2382 }, 2383 flag: api.CoreFeatureReferenceTypes, 2384 }, 2385 { 2386 name: "table.grow (funcref) - type mismatch", 2387 body: []byte{ 2388 OpcodeRefNull, RefTypeFuncref, 2389 OpcodeI32Const, 1, // number of elements 2390 OpcodeMiscPrefix, OpcodeMiscTableGrow, 2391 1, // Table of externref type -> mismatch. 2392 OpcodeEnd, 2393 }, 2394 flag: api.CoreFeatureReferenceTypes, 2395 expectedErr: `cannot pop the operand for table.grow: type mismatch: expected externref, but was funcref`, 2396 }, 2397 { 2398 name: "table.grow (externref)", 2399 body: []byte{ 2400 OpcodeRefNull, RefTypeExternref, 2401 OpcodeI32Const, 1, // number of elements 2402 OpcodeMiscPrefix, OpcodeMiscTableGrow, 2403 1, // Table Index. 2404 OpcodeDrop, 2405 OpcodeEnd, 2406 }, 2407 flag: api.CoreFeatureReferenceTypes, 2408 }, 2409 { 2410 name: "table.grow (externref) type mismatch", 2411 body: []byte{ 2412 OpcodeRefNull, RefTypeExternref, 2413 OpcodeI32Const, 1, // number of elements 2414 OpcodeMiscPrefix, OpcodeMiscTableGrow, 2415 0, // Table of funcref type -> mismatch. 2416 OpcodeEnd, 2417 }, 2418 flag: api.CoreFeatureReferenceTypes, 2419 expectedErr: `cannot pop the operand for table.grow: type mismatch: expected funcref, but was externref`, 2420 }, 2421 { 2422 name: "table.grow - table not found", 2423 body: []byte{ 2424 OpcodeRefNull, RefTypeFuncref, 2425 OpcodeI32Const, 1, // number of elements 2426 OpcodeMiscPrefix, OpcodeMiscTableGrow, 2427 10, // Table Index. 2428 OpcodeEnd, 2429 }, 2430 flag: api.CoreFeatureReferenceTypes, 2431 expectedErr: `table of index 10 not found`, 2432 }, 2433 { 2434 name: "table.size - table not found", 2435 body: []byte{ 2436 OpcodeMiscPrefix, OpcodeMiscTableSize, 2437 10, // Table Index. 2438 OpcodeEnd, 2439 }, 2440 flag: api.CoreFeatureReferenceTypes, 2441 expectedErr: `table of index 10 not found`, 2442 }, 2443 { 2444 name: "table.size", 2445 body: []byte{ 2446 OpcodeMiscPrefix, OpcodeMiscTableSize, 2447 1, // Table Index. 2448 OpcodeDrop, 2449 OpcodeEnd, 2450 }, 2451 flag: api.CoreFeatureReferenceTypes, 2452 }, 2453 { 2454 name: "table.fill (funcref)", 2455 body: []byte{ 2456 OpcodeI32Const, 1, // offset 2457 OpcodeRefNull, RefTypeFuncref, 2458 OpcodeI32Const, 1, // number of elements 2459 OpcodeMiscPrefix, OpcodeMiscTableFill, 2460 0, // Table Index. 2461 OpcodeEnd, 2462 }, 2463 flag: api.CoreFeatureReferenceTypes, 2464 }, 2465 { 2466 name: "table.fill (funcref) - type mismatch", 2467 body: []byte{ 2468 OpcodeI32Const, 1, // offset 2469 OpcodeRefNull, RefTypeFuncref, 2470 OpcodeI32Const, 1, // number of elements 2471 OpcodeMiscPrefix, OpcodeMiscTableFill, 2472 1, // Table of externref type -> mismatch. 2473 OpcodeEnd, 2474 }, 2475 flag: api.CoreFeatureReferenceTypes, 2476 expectedErr: `cannot pop the operand for table.fill: type mismatch: expected externref, but was funcref`, 2477 }, 2478 { 2479 name: "table.fill (externref)", 2480 body: []byte{ 2481 OpcodeI32Const, 1, // offset 2482 OpcodeRefNull, RefTypeExternref, 2483 OpcodeI32Const, 1, // number of elements 2484 OpcodeMiscPrefix, OpcodeMiscTableFill, 2485 1, // Table Index. 2486 OpcodeEnd, 2487 }, 2488 flag: api.CoreFeatureReferenceTypes, 2489 }, 2490 { 2491 name: "table.fill (externref) - type mismatch", 2492 body: []byte{ 2493 OpcodeI32Const, 1, // offset 2494 OpcodeRefNull, RefTypeExternref, 2495 OpcodeI32Const, 1, // number of elements 2496 OpcodeMiscPrefix, OpcodeMiscTableFill, 2497 0, // Table of funcref type -> mismatch. 2498 OpcodeEnd, 2499 }, 2500 flag: api.CoreFeatureReferenceTypes, 2501 expectedErr: `cannot pop the operand for table.fill: type mismatch: expected funcref, but was externref`, 2502 }, 2503 { 2504 name: "table.fill - table not found", 2505 body: []byte{ 2506 OpcodeMiscPrefix, OpcodeMiscTableFill, 2507 10, // Table Index. 2508 OpcodeEnd, 2509 }, 2510 flag: api.CoreFeatureReferenceTypes, 2511 expectedErr: `table of index 10 not found`, 2512 }, 2513 } 2514 2515 for _, tt := range tests { 2516 tc := tt 2517 t.Run(tc.name, func(t *testing.T) { 2518 m := &Module{ 2519 TypeSection: []FunctionType{v_v}, 2520 FunctionSection: []Index{0}, 2521 CodeSection: []Code{{Body: tc.body}}, 2522 } 2523 err := m.validateFunction(&stacks{}, tc.flag, 2524 0, []Index{0}, nil, nil, tables, nil, bytes.NewReader(nil)) 2525 if tc.expectedErr != "" { 2526 require.EqualError(t, err, tc.expectedErr) 2527 } else { 2528 require.NoError(t, err) 2529 } 2530 }) 2531 } 2532 } 2533 2534 func TestModule_funcValidation_TableGetSet(t *testing.T) { 2535 tables := []Table{{Type: RefTypeFuncref}, {Type: RefTypeExternref}} 2536 tests := []struct { 2537 name string 2538 body []byte 2539 flag api.CoreFeatures 2540 expectedErr string 2541 }{ 2542 { 2543 name: "table.get (funcref)", 2544 body: []byte{ 2545 OpcodeI32Const, 0, 2546 OpcodeTableGet, 0, 2547 OpcodeRefIsNull, 2548 OpcodeDrop, 2549 OpcodeEnd, 2550 }, 2551 flag: api.CoreFeatureReferenceTypes, 2552 }, 2553 { 2554 name: "table.get (externref)", 2555 body: []byte{ 2556 OpcodeI32Const, 0, 2557 OpcodeTableGet, 1, 2558 OpcodeRefIsNull, 2559 OpcodeDrop, 2560 OpcodeEnd, 2561 }, 2562 flag: api.CoreFeatureReferenceTypes, 2563 }, 2564 { 2565 name: "table.get (disabled)", 2566 body: []byte{ 2567 OpcodeI32Const, 0, 2568 OpcodeTableGet, 0, 2569 OpcodeDrop, 2570 OpcodeEnd, 2571 }, 2572 flag: api.CoreFeaturesV1, 2573 expectedErr: `table.get is invalid as feature "reference-types" is disabled`, 2574 }, 2575 { 2576 name: "table.set (funcref)", 2577 body: []byte{ 2578 OpcodeI32Const, 0, 2579 OpcodeRefNull, ValueTypeFuncref, 2580 OpcodeTableSet, 0, 2581 OpcodeEnd, 2582 }, 2583 flag: api.CoreFeatureReferenceTypes, 2584 }, 2585 { 2586 name: "table.set type mismatch (src=funcref, dst=externref)", 2587 body: []byte{ 2588 OpcodeI32Const, 0, 2589 OpcodeRefNull, ValueTypeFuncref, 2590 OpcodeTableSet, 1, 2591 OpcodeEnd, 2592 }, 2593 flag: api.CoreFeatureReferenceTypes, 2594 expectedErr: `cannot pop the operand for table.set: type mismatch: expected externref, but was funcref`, 2595 }, 2596 { 2597 name: "table.set (externref)", 2598 body: []byte{ 2599 OpcodeI32Const, 0, 2600 OpcodeRefNull, ValueTypeExternref, 2601 OpcodeTableSet, 1, 2602 OpcodeEnd, 2603 }, 2604 flag: api.CoreFeatureReferenceTypes, 2605 }, 2606 { 2607 name: "table.set type mismatch (src=externref, dst=funcref)", 2608 body: []byte{ 2609 OpcodeI32Const, 0, 2610 OpcodeRefNull, ValueTypeExternref, 2611 OpcodeTableSet, 0, 2612 OpcodeEnd, 2613 }, 2614 flag: api.CoreFeatureReferenceTypes, 2615 expectedErr: `cannot pop the operand for table.set: type mismatch: expected funcref, but was externref`, 2616 }, 2617 { 2618 name: "table.set (disabled)", 2619 body: []byte{ 2620 OpcodeTableSet, 1, 2621 OpcodeEnd, 2622 }, 2623 flag: api.CoreFeaturesV1, 2624 expectedErr: `table.set is invalid as feature "reference-types" is disabled`, 2625 }, 2626 } 2627 2628 for _, tt := range tests { 2629 tc := tt 2630 t.Run(tc.name, func(t *testing.T) { 2631 m := &Module{ 2632 TypeSection: []FunctionType{v_v}, 2633 FunctionSection: []Index{0}, 2634 CodeSection: []Code{{Body: tc.body}}, 2635 } 2636 err := m.validateFunction(&stacks{}, tc.flag, 2637 0, []Index{0}, nil, nil, tables, nil, bytes.NewReader(nil)) 2638 if tc.expectedErr != "" { 2639 require.EqualError(t, err, tc.expectedErr) 2640 } else { 2641 require.NoError(t, err) 2642 } 2643 }) 2644 } 2645 } 2646 2647 func TestModule_funcValidation_Select_error(t *testing.T) { 2648 tests := []struct { 2649 name string 2650 body []byte 2651 flag api.CoreFeatures 2652 expectedErr string 2653 }{ 2654 { 2655 name: "typed_select (disabled)", 2656 body: []byte{ 2657 OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeI32Const, 0, 2658 OpcodeTypedSelect, 1, ValueTypeI32, // immediate vector's size must be one 2659 OpcodeDrop, 2660 OpcodeEnd, 2661 }, 2662 flag: api.CoreFeaturesV1, 2663 expectedErr: "typed_select is invalid as feature \"reference-types\" is disabled", 2664 }, 2665 { 2666 name: "typed_select (too many immediate types)", 2667 body: []byte{ 2668 OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeI32Const, 0, 2669 OpcodeTypedSelect, 2, // immediate vector's size must be one 2670 }, 2671 flag: api.CoreFeatureReferenceTypes, 2672 expectedErr: `too many type immediates for typed_select`, 2673 }, 2674 { 2675 name: "typed_select (immediate type not found)", 2676 body: []byte{ 2677 OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeI32Const, 0, 2678 OpcodeTypedSelect, 1, 0, 2679 OpcodeEnd, 2680 }, 2681 flag: api.CoreFeatureReferenceTypes, 2682 expectedErr: `invalid type unknown for typed_select`, 2683 }, 2684 } 2685 2686 for _, tt := range tests { 2687 tc := tt 2688 t.Run(tc.name, func(t *testing.T) { 2689 m := &Module{ 2690 TypeSection: []FunctionType{v_v}, 2691 FunctionSection: []Index{0}, 2692 CodeSection: []Code{{Body: tc.body}}, 2693 } 2694 err := m.validateFunction(&stacks{}, tc.flag, 2695 0, []Index{0}, nil, nil, nil, nil, bytes.NewReader(nil)) 2696 require.EqualError(t, err, tc.expectedErr) 2697 }) 2698 } 2699 } 2700 2701 func TestModule_funcValidation_SIMD(t *testing.T) { 2702 addV128Const := func(in []byte) []byte { 2703 return append(in, OpcodeVecPrefix, 2704 OpcodeVecV128Const, 2705 1, 1, 1, 1, 1, 1, 1, 1, 2706 1, 1, 1, 1, 1, 1, 1, 1) 2707 } 2708 vv2v := func(vec OpcodeVec) (ret []byte) { 2709 ret = addV128Const(ret) 2710 ret = addV128Const(ret) 2711 return append(ret, 2712 OpcodeVecPrefix, 2713 vec, 2714 OpcodeDrop, 2715 OpcodeEnd, 2716 ) 2717 } 2718 vvv2v := func(vec OpcodeVec) (ret []byte) { 2719 ret = addV128Const(ret) 2720 ret = addV128Const(ret) 2721 ret = addV128Const(ret) 2722 return append(ret, 2723 OpcodeVecPrefix, 2724 vec, 2725 OpcodeDrop, 2726 OpcodeEnd, 2727 ) 2728 } 2729 2730 v2v := func(vec OpcodeVec) (ret []byte) { 2731 ret = addV128Const(ret) 2732 return append(ret, 2733 OpcodeVecPrefix, 2734 vec, 2735 OpcodeDrop, 2736 OpcodeEnd, 2737 ) 2738 } 2739 2740 vi2v := func(vec OpcodeVec) (ret []byte) { 2741 ret = addV128Const(ret) 2742 return append(ret, 2743 OpcodeI32Const, 1, 2744 OpcodeVecPrefix, 2745 vec, 2746 OpcodeDrop, 2747 OpcodeEnd, 2748 ) 2749 } 2750 2751 load := func(vec OpcodeVec, offset, align uint32) (ret []byte) { 2752 ret = []byte{ 2753 OpcodeI32Const, 1, 2754 OpcodeVecPrefix, 2755 vec, 2756 } 2757 2758 ret = append(ret, leb128.EncodeUint32(align)...) 2759 ret = append(ret, leb128.EncodeUint32(offset)...) 2760 ret = append(ret, 2761 OpcodeDrop, 2762 OpcodeEnd, 2763 ) 2764 return 2765 } 2766 2767 loadLane := func(vec OpcodeVec, offset, align uint32, lane byte) (ret []byte) { 2768 ret = addV128Const([]byte{OpcodeI32Const, 1}) 2769 ret = append(ret, 2770 OpcodeVecPrefix, 2771 vec, 2772 ) 2773 2774 ret = append(ret, leb128.EncodeUint32(align)...) 2775 ret = append(ret, leb128.EncodeUint32(offset)...) 2776 ret = append(ret, 2777 lane, 2778 OpcodeDrop, 2779 OpcodeEnd, 2780 ) 2781 return 2782 } 2783 2784 storeLane := func(vec OpcodeVec, offset, align uint32, lane byte) (ret []byte) { 2785 ret = addV128Const([]byte{OpcodeI32Const, 1}) 2786 ret = append(ret, 2787 OpcodeVecPrefix, 2788 vec, 2789 ) 2790 ret = append(ret, leb128.EncodeUint32(align)...) 2791 ret = append(ret, leb128.EncodeUint32(offset)...) 2792 ret = append(ret, 2793 lane, 2794 OpcodeEnd, 2795 ) 2796 return 2797 } 2798 2799 extractLane := func(vec OpcodeVec, lane byte) (ret []byte) { 2800 ret = addV128Const(ret) 2801 ret = append(ret, 2802 OpcodeVecPrefix, 2803 vec, 2804 lane, 2805 OpcodeDrop, 2806 OpcodeEnd, 2807 ) 2808 return 2809 } 2810 2811 replaceLane := func(vec OpcodeVec, lane byte) (ret []byte) { 2812 ret = addV128Const(ret) 2813 2814 switch vec { 2815 case OpcodeVecI8x16ReplaceLane, OpcodeVecI16x8ReplaceLane, OpcodeVecI32x4ReplaceLane: 2816 ret = append(ret, OpcodeI32Const, 0) 2817 case OpcodeVecI64x2ReplaceLane: 2818 ret = append(ret, OpcodeI64Const, 0) 2819 case OpcodeVecF32x4ReplaceLane: 2820 ret = append(ret, OpcodeF32Const, 0, 0, 0, 0) 2821 case OpcodeVecF64x2ReplaceLane: 2822 ret = append(ret, OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0, 0) 2823 } 2824 2825 ret = append(ret, 2826 OpcodeVecPrefix, 2827 vec, 2828 lane, 2829 OpcodeDrop, 2830 OpcodeEnd, 2831 ) 2832 return 2833 } 2834 2835 splat := func(vec OpcodeVec) (ret []byte) { 2836 switch vec { 2837 case OpcodeVecI8x16Splat, OpcodeVecI16x8Splat, OpcodeVecI32x4Splat: 2838 ret = append(ret, OpcodeI32Const, 0, 0, 0, 0) 2839 case OpcodeVecI64x2Splat: 2840 ret = append(ret, OpcodeI64Const, 0, 0, 0, 0, 0, 0, 0, 0) 2841 case OpcodeVecF32x4Splat: 2842 ret = append(ret, OpcodeF32Const, 0, 0, 0, 0) 2843 case OpcodeVecF64x2Splat: 2844 ret = append(ret, OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0, 0) 2845 } 2846 2847 ret = append(ret, 2848 OpcodeVecPrefix, 2849 vec, 2850 OpcodeDrop, 2851 OpcodeEnd, 2852 ) 2853 return 2854 } 2855 2856 tests := []struct { 2857 name string 2858 body []byte 2859 expectedErr string 2860 }{ 2861 { 2862 name: "v128.const", 2863 body: []byte{ 2864 OpcodeVecPrefix, 2865 OpcodeVecV128Const, 2866 1, 1, 1, 1, 1, 1, 1, 1, 2867 1, 1, 1, 1, 1, 1, 1, 1, 2868 OpcodeDrop, 2869 OpcodeEnd, 2870 }, 2871 }, 2872 {name: OpcodeVecI8x16AddName, body: vv2v(OpcodeVecI8x16Add)}, 2873 {name: OpcodeVecI16x8AddName, body: vv2v(OpcodeVecI16x8Add)}, 2874 {name: OpcodeVecI32x4AddName, body: vv2v(OpcodeVecI32x4Add)}, 2875 {name: OpcodeVecI64x2AddName, body: vv2v(OpcodeVecI64x2Add)}, 2876 {name: OpcodeVecI8x16SubName, body: vv2v(OpcodeVecI8x16Sub)}, 2877 {name: OpcodeVecI16x8SubName, body: vv2v(OpcodeVecI16x8Sub)}, 2878 {name: OpcodeVecI32x4SubName, body: vv2v(OpcodeVecI32x4Sub)}, 2879 {name: OpcodeVecI64x2SubName, body: vv2v(OpcodeVecI64x2Sub)}, 2880 {name: OpcodeVecV128AnyTrueName, body: v2v(OpcodeVecV128AnyTrue)}, 2881 {name: OpcodeVecI8x16AllTrueName, body: v2v(OpcodeVecI8x16AllTrue)}, 2882 {name: OpcodeVecI16x8AllTrueName, body: v2v(OpcodeVecI16x8AllTrue)}, 2883 {name: OpcodeVecI32x4AllTrueName, body: v2v(OpcodeVecI32x4AllTrue)}, 2884 {name: OpcodeVecI64x2AllTrueName, body: v2v(OpcodeVecI64x2AllTrue)}, 2885 {name: OpcodeVecI8x16BitMaskName, body: v2v(OpcodeVecI8x16BitMask)}, 2886 {name: OpcodeVecI16x8BitMaskName, body: v2v(OpcodeVecI16x8BitMask)}, 2887 {name: OpcodeVecI32x4BitMaskName, body: v2v(OpcodeVecI32x4BitMask)}, 2888 {name: OpcodeVecI64x2BitMaskName, body: v2v(OpcodeVecI64x2BitMask)}, 2889 {name: OpcodeVecV128LoadName, body: load(OpcodeVecV128Load, 0, 0)}, 2890 {name: OpcodeVecV128LoadName + "/align=4", body: load(OpcodeVecV128Load, 0, 4)}, 2891 {name: OpcodeVecV128Load8x8SName, body: load(OpcodeVecV128Load8x8s, 1, 0)}, 2892 {name: OpcodeVecV128Load8x8SName + "/align=1", body: load(OpcodeVecV128Load8x8s, 0, 1)}, 2893 {name: OpcodeVecV128Load8x8UName, body: load(OpcodeVecV128Load8x8u, 0, 0)}, 2894 {name: OpcodeVecV128Load8x8UName + "/align=1", body: load(OpcodeVecV128Load8x8u, 0, 1)}, 2895 {name: OpcodeVecV128Load16x4SName, body: load(OpcodeVecV128Load16x4s, 1, 0)}, 2896 {name: OpcodeVecV128Load16x4SName + "/align=2", body: load(OpcodeVecV128Load16x4s, 0, 2)}, 2897 {name: OpcodeVecV128Load16x4UName, body: load(OpcodeVecV128Load16x4u, 0, 0)}, 2898 {name: OpcodeVecV128Load16x4UName + "/align=2", body: load(OpcodeVecV128Load16x4u, 0, 2)}, 2899 {name: OpcodeVecV128Load32x2SName, body: load(OpcodeVecV128Load32x2s, 1, 0)}, 2900 {name: OpcodeVecV128Load32x2SName + "/align=3", body: load(OpcodeVecV128Load32x2s, 0, 3)}, 2901 {name: OpcodeVecV128Load32x2UName, body: load(OpcodeVecV128Load32x2u, 0, 0)}, 2902 {name: OpcodeVecV128Load32x2UName + "/align=3", body: load(OpcodeVecV128Load32x2u, 0, 3)}, 2903 {name: OpcodeVecV128Load8SplatName, body: load(OpcodeVecV128Load8Splat, 2, 0)}, 2904 {name: OpcodeVecV128Load16SplatName, body: load(OpcodeVecV128Load16Splat, 0, 1)}, 2905 {name: OpcodeVecV128Load32SplatName, body: load(OpcodeVecV128Load32Splat, 3, 2)}, 2906 {name: OpcodeVecV128Load64SplatName, body: load(OpcodeVecV128Load64Splat, 0, 3)}, 2907 {name: OpcodeVecV128Load32zeroName, body: load(OpcodeVecV128Load32zero, 0, 2)}, 2908 {name: OpcodeVecV128Load64zeroName, body: load(OpcodeVecV128Load64zero, 5, 3)}, 2909 {name: OpcodeVecV128Load8LaneName, body: loadLane(OpcodeVecV128Load8Lane, 5, 0, 10)}, 2910 {name: OpcodeVecV128Load16LaneName, body: loadLane(OpcodeVecV128Load16Lane, 100, 1, 7)}, 2911 {name: OpcodeVecV128Load32LaneName, body: loadLane(OpcodeVecV128Load32Lane, 0, 2, 3)}, 2912 {name: OpcodeVecV128Load64LaneName, body: loadLane(OpcodeVecV128Load64Lane, 0, 3, 1)}, 2913 { 2914 name: OpcodeVecV128StoreName, body: []byte{ 2915 OpcodeI32Const, 2916 1, 1, 1, 1, 2917 OpcodeVecPrefix, 2918 OpcodeVecV128Const, 2919 1, 1, 1, 1, 1, 1, 1, 1, 2920 1, 1, 1, 1, 1, 1, 1, 1, 2921 OpcodeVecPrefix, 2922 OpcodeVecV128Store, 2923 4, // alignment 2924 10, // offset 2925 OpcodeEnd, 2926 }, 2927 }, 2928 {name: OpcodeVecV128Store8LaneName, body: storeLane(OpcodeVecV128Store8Lane, 0, 0, 0)}, 2929 {name: OpcodeVecV128Store8LaneName + "/lane=15", body: storeLane(OpcodeVecV128Store8Lane, 100, 0, 15)}, 2930 {name: OpcodeVecV128Store16LaneName, body: storeLane(OpcodeVecV128Store16Lane, 0, 0, 0)}, 2931 {name: OpcodeVecV128Store16LaneName + "/lane=7/align=1", body: storeLane(OpcodeVecV128Store16Lane, 100, 1, 7)}, 2932 {name: OpcodeVecV128Store32LaneName, body: storeLane(OpcodeVecV128Store32Lane, 0, 0, 0)}, 2933 {name: OpcodeVecV128Store32LaneName + "/lane=3/align=2", body: storeLane(OpcodeVecV128Store32Lane, 100, 2, 3)}, 2934 {name: OpcodeVecV128Store64LaneName, body: storeLane(OpcodeVecV128Store64Lane, 0, 0, 0)}, 2935 {name: OpcodeVecV128Store64LaneName + "/lane=1/align=3", body: storeLane(OpcodeVecV128Store64Lane, 50, 3, 1)}, 2936 {name: OpcodeVecI8x16ExtractLaneSName, body: extractLane(OpcodeVecI8x16ExtractLaneS, 0)}, 2937 {name: OpcodeVecI8x16ExtractLaneSName + "/lane=15", body: extractLane(OpcodeVecI8x16ExtractLaneS, 15)}, 2938 {name: OpcodeVecI8x16ExtractLaneUName, body: extractLane(OpcodeVecI8x16ExtractLaneU, 0)}, 2939 {name: OpcodeVecI8x16ExtractLaneUName + "/lane=15", body: extractLane(OpcodeVecI8x16ExtractLaneU, 15)}, 2940 {name: OpcodeVecI16x8ExtractLaneSName, body: extractLane(OpcodeVecI16x8ExtractLaneS, 0)}, 2941 {name: OpcodeVecI16x8ExtractLaneSName + "/lane=7", body: extractLane(OpcodeVecI16x8ExtractLaneS, 7)}, 2942 {name: OpcodeVecI16x8ExtractLaneUName, body: extractLane(OpcodeVecI16x8ExtractLaneU, 0)}, 2943 {name: OpcodeVecI16x8ExtractLaneUName + "/lane=8", body: extractLane(OpcodeVecI16x8ExtractLaneU, 7)}, 2944 {name: OpcodeVecI32x4ExtractLaneName, body: extractLane(OpcodeVecI32x4ExtractLane, 0)}, 2945 {name: OpcodeVecI32x4ExtractLaneName + "/lane=3", body: extractLane(OpcodeVecI32x4ExtractLane, 3)}, 2946 {name: OpcodeVecI64x2ExtractLaneName, body: extractLane(OpcodeVecI64x2ExtractLane, 0)}, 2947 {name: OpcodeVecI64x2ExtractLaneName + "/lane=1", body: extractLane(OpcodeVecI64x2ExtractLane, 1)}, 2948 {name: OpcodeVecF32x4ExtractLaneName, body: extractLane(OpcodeVecF32x4ExtractLane, 0)}, 2949 {name: OpcodeVecF32x4ExtractLaneName + "/lane=3", body: extractLane(OpcodeVecF32x4ExtractLane, 3)}, 2950 {name: OpcodeVecF64x2ExtractLaneName, body: extractLane(OpcodeVecF64x2ExtractLane, 0)}, 2951 {name: OpcodeVecF64x2ExtractLaneName + "/lane=1", body: extractLane(OpcodeVecF64x2ExtractLane, 1)}, 2952 {name: OpcodeVecI8x16ReplaceLaneName, body: replaceLane(OpcodeVecI8x16ReplaceLane, 0)}, 2953 {name: OpcodeVecI8x16ReplaceLaneName + "/lane=15", body: replaceLane(OpcodeVecI8x16ReplaceLane, 15)}, 2954 {name: OpcodeVecI16x8ReplaceLaneName, body: replaceLane(OpcodeVecI16x8ReplaceLane, 0)}, 2955 {name: OpcodeVecI16x8ReplaceLaneName + "/lane=7", body: replaceLane(OpcodeVecI16x8ReplaceLane, 7)}, 2956 {name: OpcodeVecI32x4ReplaceLaneName, body: replaceLane(OpcodeVecI32x4ReplaceLane, 0)}, 2957 {name: OpcodeVecI32x4ReplaceLaneName + "/lane=3", body: replaceLane(OpcodeVecI32x4ReplaceLane, 3)}, 2958 {name: OpcodeVecI64x2ReplaceLaneName, body: replaceLane(OpcodeVecI64x2ReplaceLane, 0)}, 2959 {name: OpcodeVecI64x2ReplaceLaneName + "/lane=1", body: replaceLane(OpcodeVecI64x2ReplaceLane, 1)}, 2960 {name: OpcodeVecF32x4ReplaceLaneName, body: replaceLane(OpcodeVecF32x4ReplaceLane, 0)}, 2961 {name: OpcodeVecF32x4ReplaceLaneName + "/lane=3", body: replaceLane(OpcodeVecF32x4ReplaceLane, 3)}, 2962 {name: OpcodeVecF64x2ReplaceLaneName, body: replaceLane(OpcodeVecF64x2ReplaceLane, 0)}, 2963 {name: OpcodeVecF64x2ReplaceLaneName + "/lane=1", body: replaceLane(OpcodeVecF64x2ReplaceLane, 1)}, 2964 {name: OpcodeVecI8x16SplatName, body: splat(OpcodeVecI8x16Splat)}, 2965 {name: OpcodeVecI16x8SplatName, body: splat(OpcodeVecI16x8Splat)}, 2966 {name: OpcodeVecI32x4SplatName, body: splat(OpcodeVecI32x4Splat)}, 2967 {name: OpcodeVecI64x2SplatName, body: splat(OpcodeVecI64x2Splat)}, 2968 {name: OpcodeVecF32x4SplatName, body: splat(OpcodeVecF32x4Splat)}, 2969 {name: OpcodeVecF64x2SplatName, body: splat(OpcodeVecF64x2Splat)}, 2970 {name: OpcodeVecI8x16SwizzleName, body: vv2v(OpcodeVecI8x16Swizzle)}, 2971 { 2972 name: OpcodeVecV128i8x16ShuffleName, body: []byte{ 2973 OpcodeVecPrefix, 2974 OpcodeVecV128Const, 2975 1, 1, 1, 1, 1, 1, 1, 1, 2976 1, 1, 1, 1, 1, 1, 1, 1, 2977 OpcodeVecPrefix, 2978 OpcodeVecV128Const, 2979 1, 1, 1, 1, 1, 1, 1, 1, 2980 1, 1, 1, 1, 1, 1, 1, 1, 2981 OpcodeVecPrefix, 2982 OpcodeVecV128i8x16Shuffle, 2983 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 2984 OpcodeDrop, 2985 OpcodeEnd, 2986 }, 2987 }, 2988 {name: OpcodeVecV128NotName, body: v2v(OpcodeVecV128Not)}, 2989 {name: OpcodeVecV128AndName, body: vv2v(OpcodeVecV128And)}, 2990 {name: OpcodeVecV128AndNotName, body: vv2v(OpcodeVecV128AndNot)}, 2991 {name: OpcodeVecV128OrName, body: vv2v(OpcodeVecV128Or)}, 2992 {name: OpcodeVecV128XorName, body: vv2v(OpcodeVecV128Xor)}, 2993 {name: OpcodeVecV128BitselectName, body: vvv2v(OpcodeVecV128Bitselect)}, 2994 {name: OpcodeVecI8x16ShlName, body: vi2v(OpcodeVecI8x16Shl)}, 2995 {name: OpcodeVecI8x16ShrSName, body: vi2v(OpcodeVecI8x16ShrS)}, 2996 {name: OpcodeVecI8x16ShrUName, body: vi2v(OpcodeVecI8x16ShrU)}, 2997 {name: OpcodeVecI16x8ShlName, body: vi2v(OpcodeVecI16x8Shl)}, 2998 {name: OpcodeVecI16x8ShrSName, body: vi2v(OpcodeVecI16x8ShrS)}, 2999 {name: OpcodeVecI16x8ShrUName, body: vi2v(OpcodeVecI16x8ShrU)}, 3000 {name: OpcodeVecI32x4ShlName, body: vi2v(OpcodeVecI32x4Shl)}, 3001 {name: OpcodeVecI32x4ShrSName, body: vi2v(OpcodeVecI32x4ShrS)}, 3002 {name: OpcodeVecI32x4ShrUName, body: vi2v(OpcodeVecI32x4ShrU)}, 3003 {name: OpcodeVecI64x2ShlName, body: vi2v(OpcodeVecI64x2Shl)}, 3004 {name: OpcodeVecI64x2ShrSName, body: vi2v(OpcodeVecI64x2ShrS)}, 3005 {name: OpcodeVecI64x2ShrUName, body: vi2v(OpcodeVecI64x2ShrU)}, 3006 {name: OpcodeVecI8x16EqName, body: vv2v(OpcodeVecI8x16Eq)}, 3007 {name: OpcodeVecI8x16NeName, body: vv2v(OpcodeVecI8x16Ne)}, 3008 {name: OpcodeVecI8x16LtSName, body: vv2v(OpcodeVecI8x16LtS)}, 3009 {name: OpcodeVecI8x16LtUName, body: vv2v(OpcodeVecI8x16LtU)}, 3010 {name: OpcodeVecI8x16GtSName, body: vv2v(OpcodeVecI8x16GtS)}, 3011 {name: OpcodeVecI8x16GtUName, body: vv2v(OpcodeVecI8x16GtU)}, 3012 {name: OpcodeVecI8x16LeSName, body: vv2v(OpcodeVecI8x16LeS)}, 3013 {name: OpcodeVecI8x16LeUName, body: vv2v(OpcodeVecI8x16LeU)}, 3014 {name: OpcodeVecI8x16GeSName, body: vv2v(OpcodeVecI8x16GeS)}, 3015 {name: OpcodeVecI8x16GeUName, body: vv2v(OpcodeVecI8x16GeU)}, 3016 {name: OpcodeVecI16x8EqName, body: vv2v(OpcodeVecI16x8Eq)}, 3017 {name: OpcodeVecI16x8NeName, body: vv2v(OpcodeVecI16x8Ne)}, 3018 {name: OpcodeVecI16x8LtSName, body: vv2v(OpcodeVecI16x8LtS)}, 3019 {name: OpcodeVecI16x8LtUName, body: vv2v(OpcodeVecI16x8LtU)}, 3020 {name: OpcodeVecI16x8GtSName, body: vv2v(OpcodeVecI16x8GtS)}, 3021 {name: OpcodeVecI16x8GtUName, body: vv2v(OpcodeVecI16x8GtU)}, 3022 {name: OpcodeVecI16x8LeSName, body: vv2v(OpcodeVecI16x8LeS)}, 3023 {name: OpcodeVecI16x8LeUName, body: vv2v(OpcodeVecI16x8LeU)}, 3024 {name: OpcodeVecI16x8GeSName, body: vv2v(OpcodeVecI16x8GeS)}, 3025 {name: OpcodeVecI16x8GeUName, body: vv2v(OpcodeVecI16x8GeU)}, 3026 {name: OpcodeVecI32x4EqName, body: vv2v(OpcodeVecI32x4Eq)}, 3027 {name: OpcodeVecI32x4NeName, body: vv2v(OpcodeVecI32x4Ne)}, 3028 {name: OpcodeVecI32x4LtSName, body: vv2v(OpcodeVecI32x4LtS)}, 3029 {name: OpcodeVecI32x4LtUName, body: vv2v(OpcodeVecI32x4LtU)}, 3030 {name: OpcodeVecI32x4GtSName, body: vv2v(OpcodeVecI32x4GtS)}, 3031 {name: OpcodeVecI32x4GtUName, body: vv2v(OpcodeVecI32x4GtU)}, 3032 {name: OpcodeVecI32x4LeSName, body: vv2v(OpcodeVecI32x4LeS)}, 3033 {name: OpcodeVecI32x4LeUName, body: vv2v(OpcodeVecI32x4LeU)}, 3034 {name: OpcodeVecI32x4GeSName, body: vv2v(OpcodeVecI32x4GeS)}, 3035 {name: OpcodeVecI32x4GeUName, body: vv2v(OpcodeVecI32x4GeU)}, 3036 {name: OpcodeVecI64x2EqName, body: vv2v(OpcodeVecI64x2Eq)}, 3037 {name: OpcodeVecI64x2NeName, body: vv2v(OpcodeVecI64x2Ne)}, 3038 {name: OpcodeVecI64x2LtSName, body: vv2v(OpcodeVecI64x2LtS)}, 3039 {name: OpcodeVecI64x2GtSName, body: vv2v(OpcodeVecI64x2GtS)}, 3040 {name: OpcodeVecI64x2LeSName, body: vv2v(OpcodeVecI64x2LeS)}, 3041 {name: OpcodeVecI64x2GeSName, body: vv2v(OpcodeVecI64x2GeS)}, 3042 {name: OpcodeVecF32x4EqName, body: vv2v(OpcodeVecF32x4Eq)}, 3043 {name: OpcodeVecF32x4NeName, body: vv2v(OpcodeVecF32x4Ne)}, 3044 {name: OpcodeVecF32x4LtName, body: vv2v(OpcodeVecF32x4Lt)}, 3045 {name: OpcodeVecF32x4GtName, body: vv2v(OpcodeVecF32x4Gt)}, 3046 {name: OpcodeVecF32x4LeName, body: vv2v(OpcodeVecF32x4Le)}, 3047 {name: OpcodeVecF32x4GeName, body: vv2v(OpcodeVecF32x4Ge)}, 3048 {name: OpcodeVecF64x2EqName, body: vv2v(OpcodeVecF64x2Eq)}, 3049 {name: OpcodeVecF64x2NeName, body: vv2v(OpcodeVecF64x2Ne)}, 3050 {name: OpcodeVecF64x2LtName, body: vv2v(OpcodeVecF64x2Lt)}, 3051 {name: OpcodeVecF64x2GtName, body: vv2v(OpcodeVecF64x2Gt)}, 3052 {name: OpcodeVecF64x2LeName, body: vv2v(OpcodeVecF64x2Le)}, 3053 {name: OpcodeVecF64x2GeName, body: vv2v(OpcodeVecF64x2Ge)}, 3054 {name: OpcodeVecI8x16AddName, body: vv2v(OpcodeVecI8x16Add)}, 3055 {name: OpcodeVecI8x16AddSatSName, body: vv2v(OpcodeVecI8x16AddSatS)}, 3056 {name: OpcodeVecI8x16AddSatUName, body: vv2v(OpcodeVecI8x16AddSatU)}, 3057 {name: OpcodeVecI8x16SubName, body: vv2v(OpcodeVecI8x16Sub)}, 3058 {name: OpcodeVecI8x16SubSatSName, body: vv2v(OpcodeVecI8x16SubSatS)}, 3059 {name: OpcodeVecI8x16SubSatUName, body: vv2v(OpcodeVecI8x16SubSatU)}, 3060 {name: OpcodeVecI16x8AddName, body: vv2v(OpcodeVecI16x8Add)}, 3061 {name: OpcodeVecI16x8AddSatSName, body: vv2v(OpcodeVecI16x8AddSatS)}, 3062 {name: OpcodeVecI16x8AddSatUName, body: vv2v(OpcodeVecI16x8AddSatU)}, 3063 {name: OpcodeVecI16x8SubName, body: vv2v(OpcodeVecI16x8Sub)}, 3064 {name: OpcodeVecI16x8SubSatSName, body: vv2v(OpcodeVecI16x8SubSatS)}, 3065 {name: OpcodeVecI16x8SubSatUName, body: vv2v(OpcodeVecI16x8SubSatU)}, 3066 {name: OpcodeVecI16x8MulName, body: vv2v(OpcodeVecI16x8Mul)}, 3067 {name: OpcodeVecI32x4AddName, body: vv2v(OpcodeVecI32x4Add)}, 3068 {name: OpcodeVecI32x4SubName, body: vv2v(OpcodeVecI32x4Sub)}, 3069 {name: OpcodeVecI32x4MulName, body: vv2v(OpcodeVecI32x4Mul)}, 3070 {name: OpcodeVecI64x2AddName, body: vv2v(OpcodeVecI64x2Add)}, 3071 {name: OpcodeVecI64x2SubName, body: vv2v(OpcodeVecI64x2Sub)}, 3072 {name: OpcodeVecI64x2MulName, body: vv2v(OpcodeVecI64x2Mul)}, 3073 {name: OpcodeVecF32x4AddName, body: vv2v(OpcodeVecF32x4Add)}, 3074 {name: OpcodeVecF32x4SubName, body: vv2v(OpcodeVecF32x4Sub)}, 3075 {name: OpcodeVecF32x4MulName, body: vv2v(OpcodeVecF32x4Mul)}, 3076 {name: OpcodeVecF32x4DivName, body: vv2v(OpcodeVecF32x4Div)}, 3077 {name: OpcodeVecF64x2AddName, body: vv2v(OpcodeVecF64x2Add)}, 3078 {name: OpcodeVecF64x2SubName, body: vv2v(OpcodeVecF64x2Sub)}, 3079 {name: OpcodeVecF64x2MulName, body: vv2v(OpcodeVecF64x2Mul)}, 3080 {name: OpcodeVecF64x2DivName, body: vv2v(OpcodeVecF64x2Div)}, 3081 {name: OpcodeVecI8x16NegName, body: v2v(OpcodeVecI8x16Neg)}, 3082 {name: OpcodeVecI16x8NegName, body: v2v(OpcodeVecI16x8Neg)}, 3083 {name: OpcodeVecI32x4NegName, body: v2v(OpcodeVecI32x4Neg)}, 3084 {name: OpcodeVecI64x2NegName, body: v2v(OpcodeVecI64x2Neg)}, 3085 {name: OpcodeVecF32x4NegName, body: v2v(OpcodeVecF32x4Neg)}, 3086 {name: OpcodeVecF64x2NegName, body: v2v(OpcodeVecF64x2Neg)}, 3087 {name: OpcodeVecF32x4SqrtName, body: v2v(OpcodeVecF32x4Sqrt)}, 3088 {name: OpcodeVecF64x2SqrtName, body: v2v(OpcodeVecF64x2Sqrt)}, 3089 {name: OpcodeVecI8x16MinSName, body: vv2v(OpcodeVecI8x16MinS)}, 3090 {name: OpcodeVecI8x16MinUName, body: vv2v(OpcodeVecI8x16MinU)}, 3091 {name: OpcodeVecI8x16MaxSName, body: vv2v(OpcodeVecI8x16MaxS)}, 3092 {name: OpcodeVecI8x16MaxUName, body: vv2v(OpcodeVecI8x16MaxU)}, 3093 {name: OpcodeVecI8x16AvgrUName, body: vv2v(OpcodeVecI8x16AvgrU)}, 3094 {name: OpcodeVecI8x16AbsName, body: v2v(OpcodeVecI8x16Abs)}, 3095 {name: OpcodeVecI8x16PopcntName, body: v2v(OpcodeVecI8x16Popcnt)}, 3096 {name: OpcodeVecI16x8MinSName, body: vv2v(OpcodeVecI16x8MinS)}, 3097 {name: OpcodeVecI16x8MinUName, body: vv2v(OpcodeVecI16x8MinU)}, 3098 {name: OpcodeVecI16x8MaxSName, body: vv2v(OpcodeVecI16x8MaxS)}, 3099 {name: OpcodeVecI16x8MaxUName, body: vv2v(OpcodeVecI16x8MaxU)}, 3100 {name: OpcodeVecI16x8AvgrUName, body: vv2v(OpcodeVecI16x8AvgrU)}, 3101 {name: OpcodeVecI16x8AbsName, body: v2v(OpcodeVecI16x8Abs)}, 3102 {name: OpcodeVecI32x4MinSName, body: vv2v(OpcodeVecI32x4MinS)}, 3103 {name: OpcodeVecI32x4MinUName, body: vv2v(OpcodeVecI32x4MinU)}, 3104 {name: OpcodeVecI32x4MaxSName, body: vv2v(OpcodeVecI32x4MaxS)}, 3105 {name: OpcodeVecI32x4MaxUName, body: vv2v(OpcodeVecI32x4MaxU)}, 3106 {name: OpcodeVecI32x4AbsName, body: v2v(OpcodeVecI32x4Abs)}, 3107 {name: OpcodeVecI64x2AbsName, body: v2v(OpcodeVecI64x2Abs)}, 3108 {name: OpcodeVecF32x4AbsName, body: v2v(OpcodeVecF32x4Abs)}, 3109 {name: OpcodeVecF64x2AbsName, body: v2v(OpcodeVecF64x2Abs)}, 3110 {name: OpcodeVecF32x4MinName, body: vv2v(OpcodeVecF32x4Min)}, 3111 {name: OpcodeVecF32x4MaxName, body: vv2v(OpcodeVecF32x4Max)}, 3112 {name: OpcodeVecF64x2MinName, body: vv2v(OpcodeVecF64x2Min)}, 3113 {name: OpcodeVecF64x2MaxName, body: vv2v(OpcodeVecF64x2Max)}, 3114 {name: OpcodeVecF32x4CeilName, body: v2v(OpcodeVecF32x4Ceil)}, 3115 {name: OpcodeVecF32x4FloorName, body: v2v(OpcodeVecF32x4Floor)}, 3116 {name: OpcodeVecF32x4TruncName, body: v2v(OpcodeVecF32x4Trunc)}, 3117 {name: OpcodeVecF32x4NearestName, body: v2v(OpcodeVecF32x4Nearest)}, 3118 {name: OpcodeVecF64x2CeilName, body: v2v(OpcodeVecF64x2Ceil)}, 3119 {name: OpcodeVecF64x2FloorName, body: v2v(OpcodeVecF64x2Floor)}, 3120 {name: OpcodeVecF64x2TruncName, body: v2v(OpcodeVecF64x2Trunc)}, 3121 {name: OpcodeVecF64x2NearestName, body: v2v(OpcodeVecF64x2Nearest)}, 3122 {name: OpcodeVecF32x4MinName, body: vv2v(OpcodeVecF32x4Pmin)}, 3123 {name: OpcodeVecF32x4MaxName, body: vv2v(OpcodeVecF32x4Pmax)}, 3124 {name: OpcodeVecF64x2MinName, body: vv2v(OpcodeVecF64x2Pmin)}, 3125 {name: OpcodeVecF64x2MaxName, body: vv2v(OpcodeVecF64x2Pmax)}, 3126 {name: OpcodeVecI16x8ExtendLowI8x16SName, body: v2v(OpcodeVecI16x8ExtendLowI8x16S)}, 3127 {name: OpcodeVecI16x8ExtendHighI8x16SName, body: v2v(OpcodeVecI16x8ExtendHighI8x16S)}, 3128 {name: OpcodeVecI16x8ExtendLowI8x16UName, body: v2v(OpcodeVecI16x8ExtendLowI8x16U)}, 3129 {name: OpcodeVecI16x8ExtendHighI8x16UName, body: v2v(OpcodeVecI16x8ExtendHighI8x16U)}, 3130 {name: OpcodeVecI32x4ExtendLowI16x8SName, body: v2v(OpcodeVecI32x4ExtendLowI16x8S)}, 3131 {name: OpcodeVecI32x4ExtendHighI16x8SName, body: v2v(OpcodeVecI32x4ExtendHighI16x8S)}, 3132 {name: OpcodeVecI32x4ExtendLowI16x8UName, body: v2v(OpcodeVecI32x4ExtendLowI16x8U)}, 3133 {name: OpcodeVecI32x4ExtendHighI16x8UName, body: v2v(OpcodeVecI32x4ExtendHighI16x8U)}, 3134 {name: OpcodeVecI64x2ExtendLowI32x4SName, body: v2v(OpcodeVecI64x2ExtendLowI32x4S)}, 3135 {name: OpcodeVecI64x2ExtendHighI32x4SName, body: v2v(OpcodeVecI64x2ExtendHighI32x4S)}, 3136 {name: OpcodeVecI64x2ExtendLowI32x4UName, body: v2v(OpcodeVecI64x2ExtendLowI32x4U)}, 3137 {name: OpcodeVecI64x2ExtendHighI32x4UName, body: v2v(OpcodeVecI64x2ExtendHighI32x4U)}, 3138 {name: OpcodeVecI16x8Q15mulrSatSName, body: vv2v(OpcodeVecI16x8Q15mulrSatS)}, 3139 {name: OpcodeVecI16x8ExtMulLowI8x16SName, body: vv2v(OpcodeVecI16x8ExtMulLowI8x16S)}, 3140 {name: OpcodeVecI16x8ExtMulHighI8x16SName, body: vv2v(OpcodeVecI16x8ExtMulHighI8x16S)}, 3141 {name: OpcodeVecI16x8ExtMulLowI8x16UName, body: vv2v(OpcodeVecI16x8ExtMulLowI8x16U)}, 3142 {name: OpcodeVecI16x8ExtMulHighI8x16UName, body: vv2v(OpcodeVecI16x8ExtMulHighI8x16U)}, 3143 {name: OpcodeVecI32x4ExtMulLowI16x8SName, body: vv2v(OpcodeVecI32x4ExtMulLowI16x8S)}, 3144 {name: OpcodeVecI32x4ExtMulHighI16x8SName, body: vv2v(OpcodeVecI32x4ExtMulHighI16x8S)}, 3145 {name: OpcodeVecI32x4ExtMulLowI16x8UName, body: vv2v(OpcodeVecI32x4ExtMulLowI16x8U)}, 3146 {name: OpcodeVecI32x4ExtMulHighI16x8UName, body: vv2v(OpcodeVecI32x4ExtMulHighI16x8U)}, 3147 {name: OpcodeVecI64x2ExtMulLowI32x4SName, body: vv2v(OpcodeVecI64x2ExtMulLowI32x4S)}, 3148 {name: OpcodeVecI64x2ExtMulHighI32x4SName, body: vv2v(OpcodeVecI64x2ExtMulHighI32x4S)}, 3149 {name: OpcodeVecI64x2ExtMulLowI32x4UName, body: vv2v(OpcodeVecI64x2ExtMulLowI32x4U)}, 3150 {name: OpcodeVecI64x2ExtMulHighI32x4UName, body: vv2v(OpcodeVecI64x2ExtMulHighI32x4U)}, 3151 {name: OpcodeVecI16x8ExtaddPairwiseI8x16SName, body: v2v(OpcodeVecI16x8ExtaddPairwiseI8x16S)}, 3152 {name: OpcodeVecI16x8ExtaddPairwiseI8x16UName, body: v2v(OpcodeVecI16x8ExtaddPairwiseI8x16U)}, 3153 {name: OpcodeVecI32x4ExtaddPairwiseI16x8SName, body: v2v(OpcodeVecI32x4ExtaddPairwiseI16x8S)}, 3154 {name: OpcodeVecI32x4ExtaddPairwiseI16x8UName, body: v2v(OpcodeVecI32x4ExtaddPairwiseI16x8U)}, 3155 {name: OpcodeVecF64x2PromoteLowF32x4ZeroName, body: v2v(OpcodeVecF64x2PromoteLowF32x4Zero)}, 3156 {name: OpcodeVecF32x4DemoteF64x2ZeroName, body: v2v(OpcodeVecF32x4DemoteF64x2Zero)}, 3157 {name: OpcodeVecF32x4ConvertI32x4SName, body: v2v(OpcodeVecF32x4ConvertI32x4S)}, 3158 {name: OpcodeVecF32x4ConvertI32x4UName, body: v2v(OpcodeVecF32x4ConvertI32x4U)}, 3159 {name: OpcodeVecF64x2ConvertLowI32x4SName, body: v2v(OpcodeVecF64x2ConvertLowI32x4S)}, 3160 {name: OpcodeVecF64x2ConvertLowI32x4UName, body: v2v(OpcodeVecF64x2ConvertLowI32x4U)}, 3161 {name: OpcodeVecI32x4DotI16x8SName, body: vv2v(OpcodeVecI32x4DotI16x8S)}, 3162 {name: OpcodeVecI8x16NarrowI16x8SName, body: vv2v(OpcodeVecI8x16NarrowI16x8S)}, 3163 {name: OpcodeVecI8x16NarrowI16x8UName, body: vv2v(OpcodeVecI8x16NarrowI16x8U)}, 3164 {name: OpcodeVecI16x8NarrowI32x4SName, body: vv2v(OpcodeVecI16x8NarrowI32x4S)}, 3165 {name: OpcodeVecI16x8NarrowI32x4UName, body: vv2v(OpcodeVecI16x8NarrowI32x4U)}, 3166 {name: OpcodeVecI32x4TruncSatF32x4SName, body: v2v(OpcodeVecI32x4TruncSatF32x4S)}, 3167 {name: OpcodeVecI32x4TruncSatF32x4UName, body: v2v(OpcodeVecI32x4TruncSatF32x4U)}, 3168 {name: OpcodeVecI32x4TruncSatF64x2SZeroName, body: v2v(OpcodeVecI32x4TruncSatF64x2SZero)}, 3169 {name: OpcodeVecI32x4TruncSatF64x2UZeroName, body: v2v(OpcodeVecI32x4TruncSatF64x2UZero)}, 3170 } 3171 3172 for _, tt := range tests { 3173 tc := tt 3174 t.Run(tc.name, func(t *testing.T) { 3175 m := &Module{ 3176 TypeSection: []FunctionType{v_v}, 3177 FunctionSection: []Index{0}, 3178 CodeSection: []Code{{Body: tc.body}}, 3179 } 3180 err := m.validateFunction(&stacks{}, api.CoreFeatureSIMD, 3181 0, []Index{0}, nil, &Memory{}, nil, nil, bytes.NewReader(nil)) 3182 require.NoError(t, err) 3183 }) 3184 } 3185 } 3186 3187 func TestModule_funcValidation_SIMD_error(t *testing.T) { 3188 type testCase struct { 3189 name string 3190 body []byte 3191 flag api.CoreFeatures 3192 expectedErr string 3193 } 3194 3195 tests := []testCase{ 3196 { 3197 name: "simd disabled", 3198 body: []byte{ 3199 OpcodeVecPrefix, 3200 OpcodeVecF32x4Abs, 3201 }, 3202 flag: api.CoreFeaturesV1, 3203 expectedErr: "f32x4.abs invalid as feature \"simd\" is disabled", 3204 }, 3205 { 3206 name: "v128.const immediate", 3207 body: []byte{ 3208 OpcodeVecPrefix, 3209 OpcodeVecV128Const, 3210 1, 1, 1, 1, 1, 1, 1, 1, 3211 1, 1, 1, 1, 1, 1, 1, 3212 }, 3213 flag: api.CoreFeatureSIMD, 3214 expectedErr: "cannot read constant vector value for v128.const", 3215 }, 3216 { 3217 name: "i32x4.add operand", 3218 body: []byte{ 3219 OpcodeVecPrefix, 3220 OpcodeVecV128Const, 3221 1, 1, 1, 1, 1, 1, 1, 1, 3222 1, 1, 1, 1, 1, 1, 1, 1, 3223 OpcodeVecPrefix, 3224 OpcodeVecI32x4Add, 3225 OpcodeDrop, 3226 OpcodeEnd, 3227 }, 3228 flag: api.CoreFeatureSIMD, 3229 expectedErr: "cannot pop the operand for i32x4.add: v128 missing", 3230 }, 3231 { 3232 name: "i64x2.add operand", 3233 body: []byte{ 3234 OpcodeVecPrefix, 3235 OpcodeVecV128Const, 3236 1, 1, 1, 1, 1, 1, 1, 1, 3237 1, 1, 1, 1, 1, 1, 1, 1, 3238 OpcodeVecPrefix, 3239 OpcodeVecI64x2Add, 3240 OpcodeDrop, 3241 OpcodeEnd, 3242 }, 3243 flag: api.CoreFeatureSIMD, 3244 expectedErr: "cannot pop the operand for i64x2.add: v128 missing", 3245 }, 3246 { 3247 name: "shuffle lane index not found", 3248 flag: api.CoreFeatureSIMD, 3249 body: []byte{ 3250 OpcodeVecPrefix, 3251 OpcodeVecV128i8x16Shuffle, 3252 }, 3253 expectedErr: "16 lane indexes for v128.shuffle not found", 3254 }, 3255 { 3256 name: "shuffle lane index not found", 3257 flag: api.CoreFeatureSIMD, 3258 body: []byte{ 3259 OpcodeVecPrefix, 3260 OpcodeVecV128i8x16Shuffle, 3261 0xff, 0, 0, 0, 0, 0, 0, 0, 3262 0, 0, 0, 0, 0, 0, 0, 0, 3263 }, 3264 expectedErr: "invalid lane index[0] 255 >= 32 for v128.shuffle", 3265 }, 3266 } 3267 3268 addExtractOrReplaceLaneOutOfIndexCase := func(op OpcodeVec, lane, laneCeil byte) { 3269 n := VectorInstructionName(op) 3270 tests = append(tests, testCase{ 3271 name: n + "/lane index out of range", 3272 flag: api.CoreFeatureSIMD, 3273 body: []byte{ 3274 OpcodeVecPrefix, op, lane, 3275 }, 3276 expectedErr: fmt.Sprintf("invalid lane index %d >= %d for %s", lane, laneCeil, n), 3277 }) 3278 } 3279 3280 addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI8x16ExtractLaneS, 16, 16) 3281 addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI8x16ExtractLaneU, 20, 16) 3282 addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI16x8ExtractLaneS, 8, 8) 3283 addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI16x8ExtractLaneU, 8, 8) 3284 addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI32x4ExtractLane, 4, 4) 3285 addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecF32x4ExtractLane, 4, 4) 3286 addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI64x2ExtractLane, 2, 2) 3287 addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecF64x2ExtractLane, 2, 2) 3288 addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI8x16ReplaceLane, 16, 16) 3289 addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI16x8ReplaceLane, 8, 8) 3290 addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI32x4ReplaceLane, 4, 4) 3291 addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI64x2ReplaceLane, 2, 2) 3292 addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecF32x4ReplaceLane, 10, 4) 3293 addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecF64x2ReplaceLane, 3, 2) 3294 3295 addStoreOrLoadLaneOutOfIndexCase := func(op OpcodeVec, lane, laneCeil byte) { 3296 n := VectorInstructionName(op) 3297 tests = append(tests, testCase{ 3298 name: n + "/lane index out of range", 3299 flag: api.CoreFeatureSIMD, 3300 body: []byte{ 3301 OpcodeVecPrefix, op, 3302 0, 0, // align and offset. 3303 lane, 3304 }, 3305 expectedErr: fmt.Sprintf("invalid lane index %d >= %d for %s", lane, laneCeil, n), 3306 }) 3307 } 3308 3309 addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Load8Lane, 16, 16) 3310 addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Load16Lane, 8, 8) 3311 addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Load32Lane, 4, 4) 3312 addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Load64Lane, 2, 2) 3313 addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Store8Lane, 16, 16) 3314 addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Store16Lane, 8, 8) 3315 addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Store32Lane, 4, 4) 3316 addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Store64Lane, 2, 2) 3317 3318 for _, tt := range tests { 3319 tc := tt 3320 t.Run(tc.name, func(t *testing.T) { 3321 m := &Module{ 3322 TypeSection: []FunctionType{v_v}, 3323 FunctionSection: []Index{0}, 3324 CodeSection: []Code{{Body: tc.body}}, 3325 } 3326 err := m.validateFunction(&stacks{}, tc.flag, 3327 0, []Index{0}, nil, &Memory{}, nil, nil, bytes.NewReader(nil)) 3328 require.EqualError(t, err, tc.expectedErr) 3329 }) 3330 } 3331 } 3332 3333 func TestDecodeBlockType(t *testing.T) { 3334 t.Run("primitive", func(t *testing.T) { 3335 for _, tc := range []struct { 3336 name string 3337 in byte 3338 exp ValueType 3339 expResultNumInUint64 int 3340 }{ 3341 {name: "nil", in: 0x40}, 3342 {name: "i32", in: 0x7f, exp: ValueTypeI32, expResultNumInUint64: 1}, 3343 {name: "i64", in: 0x7e, exp: ValueTypeI64, expResultNumInUint64: 1}, 3344 {name: "f32", in: 0x7d, exp: ValueTypeF32, expResultNumInUint64: 1}, 3345 {name: "f64", in: 0x7c, exp: ValueTypeF64, expResultNumInUint64: 1}, 3346 {name: "v128", in: 0x7b, exp: ValueTypeV128, expResultNumInUint64: 2}, 3347 {name: "funcref", in: 0x70, exp: ValueTypeFuncref, expResultNumInUint64: 1}, 3348 {name: "externref", in: 0x6f, exp: ValueTypeExternref, expResultNumInUint64: 1}, 3349 } { 3350 tc := tc 3351 t.Run(tc.name, func(t *testing.T) { 3352 actual, read, err := DecodeBlockType(nil, bytes.NewReader([]byte{tc.in}), api.CoreFeaturesV2) 3353 require.NoError(t, err) 3354 require.Equal(t, uint64(1), read) 3355 require.Equal(t, 0, len(actual.Params)) 3356 require.Equal(t, tc.expResultNumInUint64, actual.ResultNumInUint64) 3357 require.Equal(t, 0, actual.ParamNumInUint64) 3358 if tc.exp == 0 { 3359 require.Equal(t, 0, len(actual.Results)) 3360 } else { 3361 require.Equal(t, 1, len(actual.Results)) 3362 require.Equal(t, tc.exp, actual.Results[0]) 3363 } 3364 }) 3365 } 3366 }) 3367 t.Run("function type", func(t *testing.T) { 3368 types := []FunctionType{ 3369 {}, 3370 {Params: []ValueType{ValueTypeI32}}, 3371 {Results: []ValueType{ValueTypeI32}}, 3372 {Params: []ValueType{ValueTypeF32, ValueTypeV128}, Results: []ValueType{ValueTypeI32}}, 3373 {Params: []ValueType{ValueTypeF32, ValueTypeV128}, Results: []ValueType{ValueTypeI32, ValueTypeF32, ValueTypeV128}}, 3374 } 3375 for index := range types { 3376 expected := &types[index] 3377 actual, read, err := DecodeBlockType(types, bytes.NewReader([]byte{byte(index)}), api.CoreFeatureMultiValue) 3378 require.NoError(t, err) 3379 require.Equal(t, uint64(1), read) 3380 require.Equal(t, expected, actual) 3381 } 3382 }) 3383 } 3384 3385 // TestFuncValidation_UnreachableBrTable_NotModifyTypes ensures that we do not modify the 3386 // original function type during the function validation with the presence of unreachable br_table 3387 // targeting the function return label. 3388 func TestFuncValidation_UnreachableBrTable_NotModifyTypes(t *testing.T) { 3389 funcType := FunctionType{Results: []ValueType{i32, i64}, Params: []ValueType{i32}} 3390 copiedFuncType := FunctionType{ 3391 Params: make([]ValueType, len(funcType.Params)), 3392 Results: make([]ValueType, len(funcType.Results)), 3393 } 3394 3395 copy(copiedFuncType.Results, funcType.Results) 3396 copy(copiedFuncType.Params, funcType.Params) 3397 3398 for _, tc := range []struct { 3399 name string 3400 m *Module 3401 }{ 3402 { 3403 name: "on function return", 3404 m: &Module{ 3405 TypeSection: []FunctionType{funcType}, 3406 FunctionSection: []Index{0}, 3407 CodeSection: []Code{ 3408 {Body: []byte{ 3409 OpcodeUnreachable, 3410 // Having br_table in unreachable state. 3411 OpcodeI32Const, 1, 3412 // Setting the destination as labels of index 0 which 3413 // is the function return. 3414 OpcodeBrTable, 2, 0, 0, 0, 3415 OpcodeEnd, 3416 }}, 3417 }, 3418 }, 3419 }, 3420 { 3421 name: "on loop return", 3422 m: &Module{ 3423 TypeSection: []FunctionType{funcType}, 3424 FunctionSection: []Index{0}, 3425 CodeSection: []Code{ 3426 {Body: []byte{ 3427 OpcodeUnreachable, 3428 OpcodeLoop, 0, // indicates that loop has funcType as its block type 3429 OpcodeUnreachable, 3430 // Having br_table in unreachable state. 3431 OpcodeI32Const, 1, 3432 // Setting the destination as labels of index 0 which 3433 // is the loop return. 3434 OpcodeBrTable, 2, 0, 0, 0, 3435 OpcodeEnd, // End of loop 3436 OpcodeEnd, 3437 }}, 3438 }, 3439 }, 3440 }, 3441 } { 3442 tc := tc 3443 t.Run(tc.name, func(t *testing.T) { 3444 err := tc.m.validateFunction(&stacks{}, api.CoreFeaturesV2, 3445 0, nil, nil, nil, nil, nil, bytes.NewReader(nil)) 3446 require.NoError(t, err) 3447 3448 // Ensures that funcType has remained intact. 3449 require.Equal(t, copiedFuncType, funcType) 3450 }) 3451 } 3452 } 3453 3454 func TestModule_funcValidation_loopWithParams(t *testing.T) { 3455 tests := []struct { 3456 name string 3457 body []byte 3458 expErr string 3459 }{ 3460 { 3461 name: "br", 3462 body: []byte{ 3463 OpcodeI32Const, 1, 3464 OpcodeLoop, 1, // loop (param i32) 3465 OpcodeBr, 0, 3466 OpcodeEnd, 3467 OpcodeUnreachable, 3468 OpcodeEnd, 3469 }, 3470 }, 3471 { 3472 name: "br_if", 3473 body: []byte{ 3474 OpcodeI32Const, 1, 3475 OpcodeLoop, 1, // loop (param i32) 3476 OpcodeI32Const, 1, // operand for br_if 3477 OpcodeBrIf, 0, 3478 OpcodeUnreachable, 3479 OpcodeEnd, 3480 OpcodeUnreachable, 3481 OpcodeEnd, 3482 }, 3483 }, 3484 { 3485 name: "br_table", 3486 body: []byte{ 3487 OpcodeI32Const, 1, 3488 OpcodeLoop, 1, // loop (param i32) 3489 OpcodeI32Const, 4, // Operand for br_table. 3490 OpcodeBrTable, 2, 0, 0, 0, 0, // Jump into the loop header anyway. 3491 OpcodeEnd, 3492 OpcodeUnreachable, 3493 OpcodeEnd, 3494 }, 3495 }, 3496 { 3497 name: "br_table - nested", 3498 body: []byte{ 3499 OpcodeI32Const, 1, 3500 OpcodeLoop, 1, // loop (param i32) 3501 OpcodeLoop, 1, // loop (param i32) 3502 OpcodeI32Const, 4, // Operand for br_table. 3503 OpcodeBrTable, 2, 0, 1, 0, // Jump into the loop header anyway. 3504 OpcodeEnd, 3505 OpcodeEnd, 3506 OpcodeUnreachable, 3507 OpcodeEnd, 3508 }, 3509 }, 3510 { 3511 name: "br / mismatch", 3512 body: []byte{ 3513 OpcodeI32Const, 1, 3514 OpcodeLoop, 1, // loop (param i32) 3515 OpcodeDrop, 3516 OpcodeBr, 0, // trying to jump the loop head after dropping the value which causes the type mismatch. 3517 OpcodeEnd, 3518 OpcodeUnreachable, 3519 OpcodeEnd, 3520 }, 3521 expErr: `not enough results in br block 3522 have () 3523 want (i32)`, 3524 }, 3525 { 3526 name: "br_if / mismatch", 3527 body: []byte{ 3528 OpcodeI32Const, 1, 3529 OpcodeLoop, 1, // loop (param i32) 3530 // Use up the param for the br_if, therefore at the time of jumping, we don't have any param to the header. 3531 OpcodeBrIf, 0, // trying to jump the loop head after dropping the value which causes the type mismatch. 3532 OpcodeUnreachable, 3533 OpcodeEnd, 3534 OpcodeUnreachable, 3535 OpcodeEnd, 3536 }, 3537 expErr: `not enough results in br_if block 3538 have () 3539 want (i32)`, 3540 }, 3541 { 3542 name: "br_table", 3543 body: []byte{ 3544 OpcodeI32Const, 1, 3545 OpcodeLoop, 1, // loop (param i32) 3546 // Use up the param for the br_table, therefore at the time of jumping, we don't have any param to the header. 3547 OpcodeBrTable, 2, 0, 0, 0, // Jump into the loop header anyway. 3548 OpcodeEnd, 3549 OpcodeUnreachable, 3550 OpcodeEnd, 3551 }, 3552 expErr: `not enough results in br_table block 3553 have () 3554 want (i32)`, 3555 }, 3556 } 3557 3558 for _, tt := range tests { 3559 tc := tt 3560 t.Run(tc.name, func(t *testing.T) { 3561 m := &Module{ 3562 TypeSection: []FunctionType{ 3563 v_i32, 3564 i32_v, 3565 }, 3566 FunctionSection: []Index{0}, 3567 CodeSection: []Code{{Body: tc.body}}, 3568 } 3569 err := m.validateFunction(&stacks{}, api.CoreFeatureMultiValue, 3570 0, []Index{0}, nil, nil, nil, nil, bytes.NewReader(nil)) 3571 if tc.expErr != "" { 3572 require.EqualError(t, err, tc.expErr) 3573 } else { 3574 require.NoError(t, err) 3575 } 3576 }) 3577 } 3578 } 3579 3580 // TestFunctionValidation_redundantEnd is found in th validation fuzzing #879. 3581 func TestFunctionValidation_redundantEnd(t *testing.T) { 3582 m := &Module{ 3583 TypeSection: []FunctionType{{}}, 3584 FunctionSection: []Index{0}, 3585 CodeSection: []Code{{Body: []byte{OpcodeEnd, OpcodeEnd}}}, 3586 } 3587 err := m.validateFunction(&stacks{}, api.CoreFeaturesV2, 3588 0, nil, nil, nil, nil, nil, bytes.NewReader(nil)) 3589 require.EqualError(t, err, "redundant End instruction at 0x1") 3590 } 3591 3592 // TestFunctionValidation_redundantEnd is found in th validation fuzzing. 3593 func TestFunctionValidation_redundantElse(t *testing.T) { 3594 m := &Module{ 3595 TypeSection: []FunctionType{{}}, 3596 FunctionSection: []Index{0}, 3597 CodeSection: []Code{{Body: []byte{OpcodeEnd, OpcodeElse}}}, 3598 } 3599 err := m.validateFunction(&stacks{}, api.CoreFeaturesV2, 3600 0, nil, nil, nil, nil, nil, bytes.NewReader(nil)) 3601 require.EqualError(t, err, "redundant Else instruction at 0x1") 3602 } 3603 3604 func Test_SplitCallStack(t *testing.T) { 3605 oneToEight := []uint64{1, 2, 3, 4, 5, 6, 7, 8} 3606 3607 tests := []struct { 3608 name string 3609 ft *FunctionType 3610 stack, expectedParams, expectedResults []uint64 3611 expectedErr string 3612 }{ 3613 { 3614 name: "v_v", 3615 ft: &v_v, 3616 stack: oneToEight, 3617 expectedParams: nil, 3618 expectedResults: nil, 3619 }, 3620 { 3621 name: "v_v - stack nil", 3622 ft: &v_v, 3623 expectedParams: nil, 3624 expectedResults: nil, 3625 }, 3626 { 3627 name: "v_i32", 3628 ft: &v_i32, 3629 stack: oneToEight, 3630 expectedParams: nil, 3631 expectedResults: []uint64{1}, 3632 }, 3633 { 3634 name: "f32i32_v", 3635 ft: &f32i32_v, 3636 stack: oneToEight, 3637 expectedParams: []uint64{1, 2}, 3638 expectedResults: nil, 3639 }, 3640 { 3641 name: "f64f32_i64", 3642 ft: &f64f32_i64, 3643 stack: oneToEight, 3644 expectedParams: []uint64{1, 2}, 3645 expectedResults: []uint64{1}, 3646 }, 3647 { 3648 name: "f64i32_v128i64", 3649 ft: &f64i32_v128i64, 3650 stack: oneToEight, 3651 expectedParams: []uint64{1, 2}, 3652 expectedResults: []uint64{1, 2, 3}, 3653 }, 3654 { 3655 name: "not enough room for params", 3656 ft: &f64i32_v128i64, 3657 stack: oneToEight[0:1], 3658 expectedErr: "need 2 params, but stack size is 1", 3659 }, 3660 { 3661 name: "not enough room for results", 3662 ft: &f64i32_v128i64, 3663 stack: oneToEight[0:2], 3664 expectedErr: "need 3 results, but stack size is 2", 3665 }, 3666 } 3667 3668 for _, tt := range tests { 3669 tc := tt 3670 3671 t.Run(tc.name, func(t *testing.T) { 3672 params, results, err := SplitCallStack(tc.ft, tc.stack) 3673 if tc.expectedErr != "" { 3674 require.EqualError(t, err, tc.expectedErr) 3675 } else { 3676 require.Equal(t, tc.expectedParams, params) 3677 require.Equal(t, tc.expectedResults, results) 3678 } 3679 }) 3680 } 3681 } 3682 3683 func TestModule_funcValidation_Atomic(t *testing.T) { 3684 t.Run("valid bytecode", func(t *testing.T) { 3685 tests := []struct { 3686 name string 3687 body []byte 3688 noDropBeforeReturn bool 3689 }{ 3690 { 3691 name: "i32.atomic.load8_u", 3692 body: []byte{ 3693 OpcodeI32Const, 0x0, 3694 OpcodeAtomicPrefix, OpcodeAtomicI32Load8U, 0x0, 0x8, // alignment=2^0, offset=8 3695 }, 3696 }, 3697 { 3698 name: "i32.atomic.load16_u", 3699 body: []byte{ 3700 OpcodeI32Const, 0x0, 3701 OpcodeAtomicPrefix, OpcodeAtomicI32Load16U, 0x1, 0x8, // alignment=2^1, offset=8 3702 }, 3703 }, 3704 { 3705 name: "i32.atomic.load", 3706 body: []byte{ 3707 OpcodeI32Const, 0x0, 3708 OpcodeAtomicPrefix, OpcodeAtomicI32Load, 0x2, 0x8, // alignment=2^2, offset=8 3709 }, 3710 }, 3711 { 3712 name: "i64.atomic.load8_u", 3713 body: []byte{ 3714 OpcodeI32Const, 0x0, 3715 OpcodeAtomicPrefix, OpcodeAtomicI64Load8U, 0x0, 0x8, // alignment=2^0, offset=8 3716 }, 3717 }, 3718 { 3719 name: "i64.atomic.load16_u", 3720 body: []byte{ 3721 OpcodeI32Const, 0x0, 3722 OpcodeAtomicPrefix, OpcodeAtomicI64Load16U, 0x1, 0x8, // alignment=2^1, offset=8 3723 }, 3724 }, 3725 { 3726 name: "i64.atomic.load32_u", 3727 body: []byte{ 3728 OpcodeI32Const, 0x0, 3729 OpcodeAtomicPrefix, OpcodeAtomicI64Load32U, 0x2, 0x8, // alignment=2^2, offset=8 3730 }, 3731 }, 3732 { 3733 name: "i64.atomic.load", 3734 body: []byte{ 3735 OpcodeI32Const, 0x0, 3736 OpcodeAtomicPrefix, OpcodeAtomicI64Load, 0x3, 0x8, // alignment=2^3, offset=8 3737 }, 3738 }, 3739 { 3740 name: "i32.atomic.store8", 3741 body: []byte{ 3742 OpcodeI32Const, 0x1, 3743 OpcodeI32Const, 0x0, 3744 OpcodeAtomicPrefix, OpcodeAtomicI32Store8, 0x0, 0x8, // alignment=2^0, offset=8 3745 }, 3746 noDropBeforeReturn: true, 3747 }, 3748 { 3749 name: "i32.atomic.store16", 3750 body: []byte{ 3751 OpcodeI32Const, 0x1, 3752 OpcodeI32Const, 0x0, 3753 OpcodeAtomicPrefix, OpcodeAtomicI32Store16, 0x1, 0x8, // alignment=2^1, offset=8 3754 }, 3755 noDropBeforeReturn: true, 3756 }, 3757 { 3758 name: "i32.atomic.store", 3759 body: []byte{ 3760 OpcodeI32Const, 0x1, 3761 OpcodeI32Const, 0x0, 3762 OpcodeAtomicPrefix, OpcodeAtomicI32Store, 0x2, 0x8, // alignment=2^2, offset=8 3763 }, 3764 noDropBeforeReturn: true, 3765 }, 3766 { 3767 name: "i64.atomic.store8", 3768 body: []byte{ 3769 OpcodeI32Const, 0x0, 3770 OpcodeI64Const, 0x1, 3771 OpcodeAtomicPrefix, OpcodeAtomicI64Store8, 0x0, 0x8, // alignment=2^0, offset=8 3772 }, 3773 noDropBeforeReturn: true, 3774 }, 3775 { 3776 name: "i64.atomic.store16", 3777 body: []byte{ 3778 OpcodeI32Const, 0x0, 3779 OpcodeI64Const, 0x1, 3780 OpcodeAtomicPrefix, OpcodeAtomicI64Store16, 0x1, 0x8, // alignment=2^1, offset=8 3781 }, 3782 noDropBeforeReturn: true, 3783 }, 3784 { 3785 name: "i64.atomic.store32", 3786 body: []byte{ 3787 OpcodeI32Const, 0x0, 3788 OpcodeI64Const, 0x1, 3789 OpcodeAtomicPrefix, OpcodeAtomicI64Store32, 0x2, 0x8, // alignment=2^2, offset=8 3790 }, 3791 noDropBeforeReturn: true, 3792 }, 3793 { 3794 name: "i64.atomic.store", 3795 body: []byte{ 3796 OpcodeI32Const, 0x0, 3797 OpcodeI64Const, 0x1, 3798 OpcodeAtomicPrefix, OpcodeAtomicI64Store, 0x3, 0x8, // alignment=2^3, offset=8 3799 }, 3800 noDropBeforeReturn: true, 3801 }, 3802 { 3803 name: "i32.atomic.rmw8.add_u", 3804 body: []byte{ 3805 OpcodeI32Const, 0x0, 3806 OpcodeI32Const, 0x1, 3807 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8AddU, 0x0, 0x8, // alignment=2^0, offset=8 3808 }, 3809 }, 3810 { 3811 name: "i32.atomic.rmw16.add_u", 3812 body: []byte{ 3813 OpcodeI32Const, 0x0, 3814 OpcodeI32Const, 0x1, 3815 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16AddU, 0x1, 0x8, // alignment=2^1, offset=8 3816 }, 3817 }, 3818 { 3819 name: "i32.atomic.rmw.add", 3820 body: []byte{ 3821 OpcodeI32Const, 0x0, 3822 OpcodeI32Const, 0x1, 3823 OpcodeAtomicPrefix, OpcodeAtomicI32RmwAdd, 0x2, 0x8, // alignment=2^2, offset=8 3824 }, 3825 }, 3826 { 3827 name: "i64.atomic.rmw8.add_u", 3828 body: []byte{ 3829 OpcodeI32Const, 0x0, 3830 OpcodeI64Const, 0x1, 3831 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8AddU, 0x0, 0x8, // alignment=2^0, offset=8 3832 }, 3833 }, 3834 { 3835 name: "i64.atomic.rmw16.add_u", 3836 body: []byte{ 3837 OpcodeI32Const, 0x0, 3838 OpcodeI64Const, 0x1, 3839 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16AddU, 0x1, 0x8, // alignment=2^1, offset=8 3840 }, 3841 }, 3842 { 3843 name: "i64.atomic.rmw32.add_u", 3844 body: []byte{ 3845 OpcodeI32Const, 0x0, 3846 OpcodeI64Const, 0x1, 3847 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32AddU, 0x2, 0x8, // alignment=2^2, offset=8 3848 }, 3849 }, 3850 { 3851 name: "i64.atomic.rmw.add", 3852 body: []byte{ 3853 OpcodeI32Const, 0x0, 3854 OpcodeI64Const, 0x1, 3855 OpcodeAtomicPrefix, OpcodeAtomicI64RmwAdd, 0x3, 0x8, // alignment=2^3, offset=8 3856 }, 3857 }, 3858 { 3859 name: "i32.atomic.rmw8.sub_u", 3860 body: []byte{ 3861 OpcodeI32Const, 0x0, 3862 OpcodeI32Const, 0x1, 3863 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8SubU, 0x0, 0x8, // alignment=2^0, offset=8 3864 }, 3865 }, 3866 { 3867 name: "i32.atomic.rmw16.sub_u", 3868 body: []byte{ 3869 OpcodeI32Const, 0x0, 3870 OpcodeI32Const, 0x1, 3871 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16SubU, 0x1, 0x8, // alignment=2^1, offset=8 3872 }, 3873 }, 3874 { 3875 name: "i32.atomic.rmw.sub", 3876 body: []byte{ 3877 OpcodeI32Const, 0x0, 3878 OpcodeI32Const, 0x1, 3879 OpcodeAtomicPrefix, OpcodeAtomicI32RmwSub, 0x2, 0x8, // alignment=2^2, offset=8 3880 }, 3881 }, 3882 { 3883 name: "i64.atomic.rmw8.sub_u", 3884 body: []byte{ 3885 OpcodeI32Const, 0x0, 3886 OpcodeI64Const, 0x1, 3887 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8SubU, 0x0, 0x8, // alignment=2^0, offset=8 3888 }, 3889 }, 3890 { 3891 name: "i64.atomic.rmw16.sub_u", 3892 body: []byte{ 3893 OpcodeI32Const, 0x0, 3894 OpcodeI64Const, 0x1, 3895 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16SubU, 0x1, 0x8, // alignment=2^1, offset=8 3896 }, 3897 }, 3898 { 3899 name: "i64.atomic.rmw32.sub_u", 3900 body: []byte{ 3901 OpcodeI32Const, 0x0, 3902 OpcodeI64Const, 0x1, 3903 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32SubU, 0x2, 0x8, // alignment=2^2, offset=8 3904 }, 3905 }, 3906 { 3907 name: "i64.atomic.rmw.sub", 3908 body: []byte{ 3909 OpcodeI32Const, 0x0, 3910 OpcodeI64Const, 0x1, 3911 OpcodeAtomicPrefix, OpcodeAtomicI64RmwSub, 0x3, 0x8, // alignment=2^3, offset=8 3912 }, 3913 }, 3914 { 3915 name: "i32.atomic.rmw8.and_u", 3916 body: []byte{ 3917 OpcodeI32Const, 0x0, 3918 OpcodeI32Const, 0x1, 3919 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8AndU, 0x0, 0x8, // alignment=2^0, offset=8 3920 }, 3921 }, 3922 { 3923 name: "i32.atomic.rmw16.and_u", 3924 body: []byte{ 3925 OpcodeI32Const, 0x0, 3926 OpcodeI32Const, 0x1, 3927 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16AndU, 0x1, 0x8, // alignment=2^1, offset=8 3928 }, 3929 }, 3930 { 3931 name: "i32.atomic.rmw.and", 3932 body: []byte{ 3933 OpcodeI32Const, 0x0, 3934 OpcodeI32Const, 0x1, 3935 OpcodeAtomicPrefix, OpcodeAtomicI32RmwAnd, 0x2, 0x8, // alignment=2^2, offset=8 3936 }, 3937 }, 3938 { 3939 name: "i64.atomic.rmw8.and_u", 3940 body: []byte{ 3941 OpcodeI32Const, 0x0, 3942 OpcodeI64Const, 0x1, 3943 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8AndU, 0x0, 0x8, // alignment=2^0, offset=8 3944 }, 3945 }, 3946 { 3947 name: "i64.atomic.rmw16.and_u", 3948 body: []byte{ 3949 OpcodeI32Const, 0x0, 3950 OpcodeI64Const, 0x1, 3951 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16AndU, 0x1, 0x8, // alignment=2^1, offset=8 3952 }, 3953 }, 3954 { 3955 name: "i64.atomic.rmw32.and_u", 3956 body: []byte{ 3957 OpcodeI32Const, 0x0, 3958 OpcodeI64Const, 0x1, 3959 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32AndU, 0x2, 0x8, // alignment=2^2, offset=8 3960 }, 3961 }, 3962 { 3963 name: "i64.atomic.rmw.and", 3964 body: []byte{ 3965 OpcodeI32Const, 0x0, 3966 OpcodeI64Const, 0x1, 3967 OpcodeAtomicPrefix, OpcodeAtomicI64RmwAnd, 0x3, 0x8, // alignment=2^3, offset=8 3968 }, 3969 }, 3970 { 3971 name: "i32.atomic.rmw8.or", 3972 body: []byte{ 3973 OpcodeI32Const, 0x0, 3974 OpcodeI32Const, 0x1, 3975 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8OrU, 0x0, 0x8, // alignment=2^0, offset=8 3976 }, 3977 }, 3978 { 3979 name: "i32.atomic.rmw16.or_u", 3980 body: []byte{ 3981 OpcodeI32Const, 0x0, 3982 OpcodeI32Const, 0x1, 3983 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16OrU, 0x1, 0x8, // alignment=2^1, offset=8 3984 }, 3985 }, 3986 { 3987 name: "i32.atomic.rmw.or", 3988 body: []byte{ 3989 OpcodeI32Const, 0x0, 3990 OpcodeI32Const, 0x1, 3991 OpcodeAtomicPrefix, OpcodeAtomicI32RmwOr, 0x2, 0x8, // alignment=2^2, offset=8 3992 }, 3993 }, 3994 { 3995 name: "i64.atomic.rmw8.or_u", 3996 body: []byte{ 3997 OpcodeI32Const, 0x0, 3998 OpcodeI64Const, 0x1, 3999 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8OrU, 0x0, 0x8, // alignment=2^0, offset=8 4000 }, 4001 }, 4002 { 4003 name: "i64.atomic.rmw16.or_u", 4004 body: []byte{ 4005 OpcodeI32Const, 0x0, 4006 OpcodeI64Const, 0x1, 4007 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16OrU, 0x1, 0x8, // alignment=2^1, offset=8 4008 }, 4009 }, 4010 { 4011 name: "i64.atomic.rmw32.or_u", 4012 body: []byte{ 4013 OpcodeI32Const, 0x0, 4014 OpcodeI64Const, 0x1, 4015 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32OrU, 0x2, 0x8, // alignment=2^2, offset=8 4016 }, 4017 }, 4018 { 4019 name: "i64.atomic.rmw.or", 4020 body: []byte{ 4021 OpcodeI32Const, 0x0, 4022 OpcodeI64Const, 0x1, 4023 OpcodeAtomicPrefix, OpcodeAtomicI64RmwOr, 0x3, 0x8, // alignment=2^3, offset=8 4024 }, 4025 }, 4026 { 4027 name: "i32.atomic.rmw8.xor_u", 4028 body: []byte{ 4029 OpcodeI32Const, 0x0, 4030 OpcodeI32Const, 0x1, 4031 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8XorU, 0x0, 0x8, // alignment=2^0, offset=8 4032 }, 4033 }, 4034 { 4035 name: "i32.atomic.rmw16.xor_u", 4036 body: []byte{ 4037 OpcodeI32Const, 0x0, 4038 OpcodeI32Const, 0x1, 4039 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16XorU, 0x1, 0x8, // alignment=2^1, offset=8 4040 }, 4041 }, 4042 { 4043 name: "i32.atomic.rmw.xor", 4044 body: []byte{ 4045 OpcodeI32Const, 0x0, 4046 OpcodeI32Const, 0x1, 4047 OpcodeAtomicPrefix, OpcodeAtomicI32RmwXor, 0x2, 0x8, // alignment=2^2, offset=8 4048 }, 4049 }, 4050 { 4051 name: "i64.atomic.rmw8.xor_u", 4052 body: []byte{ 4053 OpcodeI32Const, 0x0, 4054 OpcodeI64Const, 0x1, 4055 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8XorU, 0x0, 0x8, // alignment=2^0, offset=8 4056 }, 4057 }, 4058 { 4059 name: "i64.atomic.rmw16.xor_u", 4060 body: []byte{ 4061 OpcodeI32Const, 0x0, 4062 OpcodeI64Const, 0x1, 4063 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16XorU, 0x1, 0x8, // alignment=2^1, offset=8 4064 }, 4065 }, 4066 { 4067 name: "i64.atomic.rmw32.xor_u", 4068 body: []byte{ 4069 OpcodeI32Const, 0x0, 4070 OpcodeI64Const, 0x1, 4071 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32XorU, 0x2, 0x8, // alignment=2^2, offset=8 4072 }, 4073 }, 4074 { 4075 name: "i64.atomic.rmw.xor", 4076 body: []byte{ 4077 OpcodeI32Const, 0x0, 4078 OpcodeI64Const, 0x1, 4079 OpcodeAtomicPrefix, OpcodeAtomicI64RmwXor, 0x3, 0x8, // alignment=2^3, offset=8 4080 }, 4081 }, 4082 { 4083 name: "i32.atomic.rmw8.xchg_u", 4084 body: []byte{ 4085 OpcodeI32Const, 0x0, 4086 OpcodeI32Const, 0x1, 4087 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8XchgU, 0x0, 0x8, // alignment=2^0, offset=8 4088 }, 4089 }, 4090 { 4091 name: "i32.atomic.rmw16.xchg_u", 4092 body: []byte{ 4093 OpcodeI32Const, 0x0, 4094 OpcodeI32Const, 0x1, 4095 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16XchgU, 0x1, 0x8, // alignment=2^1, offset=8 4096 }, 4097 }, 4098 { 4099 name: "i32.atomic.rmw.xchg", 4100 body: []byte{ 4101 OpcodeI32Const, 0x0, 4102 OpcodeI32Const, 0x1, 4103 OpcodeAtomicPrefix, OpcodeAtomicI32RmwXchg, 0x2, 0x8, // alignment=2^2, offset=8 4104 }, 4105 }, 4106 { 4107 name: "i64.atomic.rmw8.xchg_u", 4108 body: []byte{ 4109 OpcodeI32Const, 0x0, 4110 OpcodeI64Const, 0x1, 4111 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8XchgU, 0x0, 0x8, // alignment=2^0, offset=8 4112 }, 4113 }, 4114 { 4115 name: "i64.atomic.rmw16.xchg_u", 4116 body: []byte{ 4117 OpcodeI32Const, 0x0, 4118 OpcodeI64Const, 0x1, 4119 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16XchgU, 0x1, 0x8, // alignment=2^1, offset=8 4120 }, 4121 }, 4122 { 4123 name: "i64.atomic.rmw32.xchg_u", 4124 body: []byte{ 4125 OpcodeI32Const, 0x0, 4126 OpcodeI64Const, 0x1, 4127 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32XchgU, 0x2, 0x8, // alignment=2^2, offset=8 4128 }, 4129 }, 4130 { 4131 name: "i64.atomic.rmw.xchg", 4132 body: []byte{ 4133 OpcodeI32Const, 0x0, 4134 OpcodeI64Const, 0x1, 4135 OpcodeAtomicPrefix, OpcodeAtomicI64RmwXchg, 0x3, 0x8, // alignment=2^3, offset=8 4136 }, 4137 }, 4138 { 4139 name: "i32.atomic.rmw8.cmpxchg_u", 4140 body: []byte{ 4141 OpcodeI32Const, 0x0, 4142 OpcodeI32Const, 0x1, 4143 OpcodeI32Const, 0x2, 4144 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8CmpxchgU, 0x0, 0x8, // alignment=2^0, offset=8 4145 }, 4146 }, 4147 { 4148 name: "i32.atomic.rmw16.cmpxchg_u", 4149 body: []byte{ 4150 OpcodeI32Const, 0x0, 4151 OpcodeI32Const, 0x1, 4152 OpcodeI32Const, 0x2, 4153 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16CmpxchgU, 0x1, 0x8, // alignment=2^1, offset=8 4154 }, 4155 }, 4156 { 4157 name: "i32.atomic.rmw.cmpxchg", 4158 body: []byte{ 4159 OpcodeI32Const, 0x0, 4160 OpcodeI32Const, 0x1, 4161 OpcodeI32Const, 0x2, 4162 OpcodeAtomicPrefix, OpcodeAtomicI32RmwCmpxchg, 0x2, 0x8, // alignment=2^2, offset=8 4163 }, 4164 }, 4165 { 4166 name: "i64.atomic.rmw8.xchg_u", 4167 body: []byte{ 4168 OpcodeI32Const, 0x0, 4169 OpcodeI64Const, 0x1, 4170 OpcodeI64Const, 0x2, 4171 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8CmpxchgU, 0x0, 0x8, // alignment=2^0, offset=8 4172 }, 4173 }, 4174 { 4175 name: "i64.atomic.rmw16.cmpxchg_u", 4176 body: []byte{ 4177 OpcodeI32Const, 0x0, 4178 OpcodeI64Const, 0x1, 4179 OpcodeI64Const, 0x2, 4180 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16CmpxchgU, 0x1, 0x8, // alignment=2^1, offset=8 4181 }, 4182 }, 4183 { 4184 name: "i64.atomic.rmw32.cmpxchg_u", 4185 body: []byte{ 4186 OpcodeI32Const, 0x0, 4187 OpcodeI64Const, 0x1, 4188 OpcodeI64Const, 0x1, 4189 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32CmpxchgU, 0x2, 0x8, // alignment=2^2, offset=8 4190 }, 4191 }, 4192 { 4193 name: "i64.atomic.rmw.cmpxchg", 4194 body: []byte{ 4195 OpcodeI32Const, 0x0, 4196 OpcodeI64Const, 0x1, 4197 OpcodeI64Const, 0x2, 4198 OpcodeAtomicPrefix, OpcodeAtomicI64RmwCmpxchg, 0x3, 0x8, // alignment=2^3, offset=8 4199 }, 4200 }, 4201 { 4202 name: "memory.atomic.wait32", 4203 body: []byte{ 4204 OpcodeI32Const, 0x0, 4205 OpcodeI32Const, 0x1, 4206 OpcodeI64Const, 0x2, 4207 OpcodeAtomicPrefix, OpcodeAtomicMemoryWait32, 0x2, 0x8, // alignment=2^2, offset=8 4208 }, 4209 }, 4210 { 4211 name: "memory.atomic.wait64", 4212 body: []byte{ 4213 OpcodeI32Const, 0x0, 4214 OpcodeI64Const, 0x1, 4215 OpcodeI64Const, 0x2, 4216 OpcodeAtomicPrefix, OpcodeAtomicMemoryWait64, 0x3, 0x8, // alignment=2^3, offset=8 4217 }, 4218 }, 4219 { 4220 name: "memory.atomic.notify", 4221 body: []byte{ 4222 OpcodeI32Const, 0x0, 4223 OpcodeI32Const, 0x1, 4224 OpcodeAtomicPrefix, OpcodeAtomicMemoryNotify, 0x2, 0x8, // alignment=2^2, offset=8 4225 }, 4226 }, 4227 { 4228 name: "memory.atomic.fence", 4229 body: []byte{ 4230 OpcodeAtomicPrefix, OpcodeAtomicFence, 0x0, 4231 }, 4232 noDropBeforeReturn: true, 4233 }, 4234 } 4235 4236 for _, tt := range tests { 4237 tc := tt 4238 t.Run(tc.name, func(t *testing.T) { 4239 body := append([]byte{}, tc.body...) 4240 if !tt.noDropBeforeReturn { 4241 body = append(body, OpcodeDrop) 4242 } 4243 body = append(body, OpcodeEnd) 4244 m := &Module{ 4245 TypeSection: []FunctionType{v_v}, 4246 FunctionSection: []Index{0}, 4247 CodeSection: []Code{{Body: body}}, 4248 } 4249 4250 t.Run("with memory", func(t *testing.T) { 4251 err := m.validateFunction(&stacks{}, experimental.CoreFeaturesThreads, 4252 0, []Index{0}, nil, &Memory{}, []Table{}, nil, bytes.NewReader(nil)) 4253 require.NoError(t, err) 4254 }) 4255 4256 t.Run("without memory", func(t *testing.T) { 4257 err := m.validateFunction(&stacks{}, experimental.CoreFeaturesThreads, 4258 0, []Index{0}, nil, nil, []Table{}, nil, bytes.NewReader(nil)) 4259 // Only fence doesn't require memory 4260 if tc.name == "memory.atomic.fence" { 4261 require.NoError(t, err) 4262 } else { 4263 require.Error(t, err, fmt.Sprintf("memory must exist for %s", tc.name)) 4264 } 4265 }) 4266 }) 4267 } 4268 }) 4269 4270 t.Run("atomic.fence bad immediate", func(t *testing.T) { 4271 body := []byte{ 4272 OpcodeAtomicPrefix, OpcodeAtomicFence, 0x1, 4273 OpcodeEnd, 4274 } 4275 m := &Module{ 4276 TypeSection: []FunctionType{v_v}, 4277 FunctionSection: []Index{0}, 4278 CodeSection: []Code{{Body: body}}, 4279 } 4280 err := m.validateFunction(&stacks{}, experimental.CoreFeaturesThreads, 4281 0, []Index{0}, nil, &Memory{}, []Table{}, nil, bytes.NewReader(nil)) 4282 require.Error(t, err, "invalid immediate value for atomic.fence") 4283 }) 4284 4285 t.Run("bad alignment", func(t *testing.T) { 4286 tests := []struct { 4287 name string 4288 body []byte 4289 noDropBeforeReturn bool 4290 }{ 4291 { 4292 name: "i32.atomic.load8_u", 4293 body: []byte{ 4294 OpcodeI32Const, 0x0, 4295 OpcodeAtomicPrefix, OpcodeAtomicI32Load8U, 0x1, 0x8, // alignment=2^1, offset=8 4296 }, 4297 }, 4298 { 4299 name: "i32.atomic.load16_u", 4300 body: []byte{ 4301 OpcodeI32Const, 0x0, 4302 OpcodeAtomicPrefix, OpcodeAtomicI32Load16U, 0x2, 0x8, // alignment=2^2, offset=8 4303 }, 4304 }, 4305 { 4306 name: "i32.atomic.load", 4307 body: []byte{ 4308 OpcodeI32Const, 0x0, 4309 OpcodeAtomicPrefix, OpcodeAtomicI32Load, 0x3, 0x8, // alignment=2^3, offset=8 4310 }, 4311 }, 4312 { 4313 name: "i64.atomic.load8_u", 4314 body: []byte{ 4315 OpcodeI32Const, 0x0, 4316 OpcodeAtomicPrefix, OpcodeAtomicI64Load8U, 0x1, 0x8, // alignment=2^1, offset=8 4317 }, 4318 }, 4319 { 4320 name: "i64.atomic.load16_u", 4321 body: []byte{ 4322 OpcodeI32Const, 0x0, 4323 OpcodeAtomicPrefix, OpcodeAtomicI64Load16U, 0x2, 0x8, // alignment=2^2, offset=8 4324 }, 4325 }, 4326 { 4327 name: "i64.atomic.load32_u", 4328 body: []byte{ 4329 OpcodeI32Const, 0x0, 4330 OpcodeAtomicPrefix, OpcodeAtomicI64Load32U, 0x3, 0x8, // alignment=2^3, offset=8 4331 }, 4332 }, 4333 { 4334 name: "i64.atomic.load", 4335 body: []byte{ 4336 OpcodeI32Const, 0x0, 4337 OpcodeAtomicPrefix, OpcodeAtomicI64Load, 0x4, 0x8, // alignment=2^4, offset=8 4338 }, 4339 }, 4340 { 4341 name: "i32.atomic.store8", 4342 body: []byte{ 4343 OpcodeI32Const, 0x1, 4344 OpcodeI32Const, 0x0, 4345 OpcodeAtomicPrefix, OpcodeAtomicI32Store8, 0x1, 0x8, // alignment=2^1, offset=8 4346 }, 4347 noDropBeforeReturn: true, 4348 }, 4349 { 4350 name: "i32.atomic.store16", 4351 body: []byte{ 4352 OpcodeI32Const, 0x1, 4353 OpcodeI32Const, 0x0, 4354 OpcodeAtomicPrefix, OpcodeAtomicI32Store16, 0x2, 0x8, // alignment=2^2, offset=8 4355 }, 4356 noDropBeforeReturn: true, 4357 }, 4358 { 4359 name: "i32.atomic.store", 4360 body: []byte{ 4361 OpcodeI32Const, 0x1, 4362 OpcodeI32Const, 0x0, 4363 OpcodeAtomicPrefix, OpcodeAtomicI32Store, 0x3, 0x8, // alignment=2^3, offset=8 4364 }, 4365 noDropBeforeReturn: true, 4366 }, 4367 { 4368 name: "i64.atomic.store8", 4369 body: []byte{ 4370 OpcodeI32Const, 0x0, 4371 OpcodeI64Const, 0x1, 4372 OpcodeAtomicPrefix, OpcodeAtomicI64Store8, 0x1, 0x8, // alignment=2^1, offset=8 4373 }, 4374 noDropBeforeReturn: true, 4375 }, 4376 { 4377 name: "i64.atomic.store16", 4378 body: []byte{ 4379 OpcodeI32Const, 0x0, 4380 OpcodeI64Const, 0x1, 4381 OpcodeAtomicPrefix, OpcodeAtomicI64Store16, 0x2, 0x8, // alignment=2^2, offset=8 4382 }, 4383 noDropBeforeReturn: true, 4384 }, 4385 { 4386 name: "i64.atomic.store32", 4387 body: []byte{ 4388 OpcodeI32Const, 0x0, 4389 OpcodeI64Const, 0x1, 4390 OpcodeAtomicPrefix, OpcodeAtomicI64Store32, 0x3, 0x8, // alignment=2^3, offset=8 4391 }, 4392 noDropBeforeReturn: true, 4393 }, 4394 { 4395 name: "i64.atomic.store", 4396 body: []byte{ 4397 OpcodeI32Const, 0x0, 4398 OpcodeI64Const, 0x1, 4399 OpcodeAtomicPrefix, OpcodeAtomicI64Store, 0x4, 0x8, // alignment=2^4, offset=8 4400 }, 4401 noDropBeforeReturn: true, 4402 }, 4403 { 4404 name: "i32.atomic.rmw8.add_u", 4405 body: []byte{ 4406 OpcodeI32Const, 0x0, 4407 OpcodeI32Const, 0x1, 4408 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8AddU, 0x1, 0x8, // alignment=2^1, offset=8 4409 }, 4410 }, 4411 { 4412 name: "i32.atomic.rmw16.add_u", 4413 body: []byte{ 4414 OpcodeI32Const, 0x0, 4415 OpcodeI32Const, 0x1, 4416 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16AddU, 0x2, 0x8, // alignment=2^2, offset=8 4417 }, 4418 }, 4419 { 4420 name: "i32.atomic.rmw.add", 4421 body: []byte{ 4422 OpcodeI32Const, 0x0, 4423 OpcodeI32Const, 0x1, 4424 OpcodeAtomicPrefix, OpcodeAtomicI32RmwAdd, 0x3, 0x8, // alignment=2^3, offset=8 4425 }, 4426 }, 4427 { 4428 name: "i64.atomic.rmw8.add_u", 4429 body: []byte{ 4430 OpcodeI32Const, 0x0, 4431 OpcodeI64Const, 0x1, 4432 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8AddU, 0x1, 0x8, // alignment=2^1, offset=8 4433 }, 4434 }, 4435 { 4436 name: "i64.atomic.rmw16.add_u", 4437 body: []byte{ 4438 OpcodeI32Const, 0x0, 4439 OpcodeI64Const, 0x1, 4440 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16AddU, 0x2, 0x8, // alignment=2^2, offset=8 4441 }, 4442 }, 4443 { 4444 name: "i64.atomic.rmw32.add_u", 4445 body: []byte{ 4446 OpcodeI32Const, 0x0, 4447 OpcodeI64Const, 0x1, 4448 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32AddU, 0x3, 0x8, // alignment=2^3, offset=8 4449 }, 4450 }, 4451 { 4452 name: "i64.atomic.rmw.add", 4453 body: []byte{ 4454 OpcodeI32Const, 0x0, 4455 OpcodeI64Const, 0x1, 4456 OpcodeAtomicPrefix, OpcodeAtomicI64RmwAdd, 0x4, 0x8, // alignment=2^4, offset=8 4457 }, 4458 }, 4459 { 4460 name: "i32.atomic.rmw8.sub_u", 4461 body: []byte{ 4462 OpcodeI32Const, 0x0, 4463 OpcodeI32Const, 0x1, 4464 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8SubU, 0x1, 0x8, // alignment=2^1, offset=8 4465 }, 4466 }, 4467 { 4468 name: "i32.atomic.rmw16.sub_u", 4469 body: []byte{ 4470 OpcodeI32Const, 0x0, 4471 OpcodeI32Const, 0x1, 4472 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16SubU, 0x2, 0x8, // alignment=2^2, offset=8 4473 }, 4474 }, 4475 { 4476 name: "i32.atomic.rmw.sub", 4477 body: []byte{ 4478 OpcodeI32Const, 0x0, 4479 OpcodeI32Const, 0x1, 4480 OpcodeAtomicPrefix, OpcodeAtomicI32RmwSub, 0x3, 0x8, // alignment=2^3, offset=8 4481 }, 4482 }, 4483 { 4484 name: "i64.atomic.rmw8.sub_u", 4485 body: []byte{ 4486 OpcodeI32Const, 0x0, 4487 OpcodeI64Const, 0x1, 4488 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8SubU, 0x1, 0x8, // alignment=2^1, offset=8 4489 }, 4490 }, 4491 { 4492 name: "i64.atomic.rmw16.sub_u", 4493 body: []byte{ 4494 OpcodeI32Const, 0x0, 4495 OpcodeI64Const, 0x1, 4496 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16SubU, 0x2, 0x8, // alignment=2^2, offset=8 4497 }, 4498 }, 4499 { 4500 name: "i64.atomic.rmw32.sub_u", 4501 body: []byte{ 4502 OpcodeI32Const, 0x0, 4503 OpcodeI64Const, 0x1, 4504 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32SubU, 0x3, 0x8, // alignment=2^3, offset=8 4505 }, 4506 }, 4507 { 4508 name: "i64.atomic.rmw.sub", 4509 body: []byte{ 4510 OpcodeI32Const, 0x0, 4511 OpcodeI64Const, 0x1, 4512 OpcodeAtomicPrefix, OpcodeAtomicI64RmwSub, 0x4, 0x8, // alignment=2^4, offset=8 4513 }, 4514 }, 4515 { 4516 name: "i32.atomic.rmw8.and_u", 4517 body: []byte{ 4518 OpcodeI32Const, 0x0, 4519 OpcodeI32Const, 0x1, 4520 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8AndU, 0x1, 0x8, // alignment=2^1, offset=8 4521 }, 4522 }, 4523 { 4524 name: "i32.atomic.rmw16.and_u", 4525 body: []byte{ 4526 OpcodeI32Const, 0x0, 4527 OpcodeI32Const, 0x1, 4528 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16AndU, 0x2, 0x8, // alignment=2^2, offset=8 4529 }, 4530 }, 4531 { 4532 name: "i32.atomic.rmw.and", 4533 body: []byte{ 4534 OpcodeI32Const, 0x0, 4535 OpcodeI32Const, 0x1, 4536 OpcodeAtomicPrefix, OpcodeAtomicI32RmwAnd, 0x3, 0x8, // alignment=2^3, offset=8 4537 }, 4538 }, 4539 { 4540 name: "i64.atomic.rmw8.and_u", 4541 body: []byte{ 4542 OpcodeI32Const, 0x0, 4543 OpcodeI64Const, 0x1, 4544 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8AndU, 0x1, 0x8, // alignment=2^1, offset=8 4545 }, 4546 }, 4547 { 4548 name: "i64.atomic.rmw16.and_u", 4549 body: []byte{ 4550 OpcodeI32Const, 0x0, 4551 OpcodeI64Const, 0x1, 4552 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16AndU, 0x2, 0x8, // alignment=2^2, offset=8 4553 }, 4554 }, 4555 { 4556 name: "i64.atomic.rmw32.and_u", 4557 body: []byte{ 4558 OpcodeI32Const, 0x0, 4559 OpcodeI64Const, 0x1, 4560 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32AndU, 0x3, 0x8, // alignment=2^3, offset=8 4561 }, 4562 }, 4563 { 4564 name: "i64.atomic.rmw.and", 4565 body: []byte{ 4566 OpcodeI32Const, 0x0, 4567 OpcodeI64Const, 0x1, 4568 OpcodeAtomicPrefix, OpcodeAtomicI64RmwAnd, 0x4, 0x8, // alignment=2^4, offset=8 4569 }, 4570 }, 4571 { 4572 name: "i32.atomic.rmw8.or", 4573 body: []byte{ 4574 OpcodeI32Const, 0x0, 4575 OpcodeI32Const, 0x1, 4576 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8OrU, 0x1, 0x8, // alignment=2^1, offset=8 4577 }, 4578 }, 4579 { 4580 name: "i32.atomic.rmw16.or_u", 4581 body: []byte{ 4582 OpcodeI32Const, 0x0, 4583 OpcodeI32Const, 0x1, 4584 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16OrU, 0x2, 0x8, // alignment=2^2, offset=8 4585 }, 4586 }, 4587 { 4588 name: "i32.atomic.rmw.or", 4589 body: []byte{ 4590 OpcodeI32Const, 0x0, 4591 OpcodeI32Const, 0x1, 4592 OpcodeAtomicPrefix, OpcodeAtomicI32RmwOr, 0x3, 0x8, // alignment=2^3, offset=8 4593 }, 4594 }, 4595 { 4596 name: "i64.atomic.rmw8.or_u", 4597 body: []byte{ 4598 OpcodeI32Const, 0x0, 4599 OpcodeI64Const, 0x1, 4600 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8OrU, 0x1, 0x8, // alignment=2^1, offset=8 4601 }, 4602 }, 4603 { 4604 name: "i64.atomic.rmw16.or_u", 4605 body: []byte{ 4606 OpcodeI32Const, 0x0, 4607 OpcodeI64Const, 0x1, 4608 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16OrU, 0x2, 0x8, // alignment=2^2, offset=8 4609 }, 4610 }, 4611 { 4612 name: "i64.atomic.rmw32.or_u", 4613 body: []byte{ 4614 OpcodeI32Const, 0x0, 4615 OpcodeI64Const, 0x1, 4616 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32OrU, 0x3, 0x8, // alignment=2^3, offset=8 4617 }, 4618 }, 4619 { 4620 name: "i64.atomic.rmw.or", 4621 body: []byte{ 4622 OpcodeI32Const, 0x0, 4623 OpcodeI64Const, 0x1, 4624 OpcodeAtomicPrefix, OpcodeAtomicI64RmwOr, 0x4, 0x8, // alignment=2^4, offset=8 4625 }, 4626 }, 4627 { 4628 name: "i32.atomic.rmw8.xor_u", 4629 body: []byte{ 4630 OpcodeI32Const, 0x0, 4631 OpcodeI32Const, 0x1, 4632 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8XorU, 0x1, 0x8, // alignment=2^1, offset=8 4633 }, 4634 }, 4635 { 4636 name: "i32.atomic.rmw16.xor_u", 4637 body: []byte{ 4638 OpcodeI32Const, 0x0, 4639 OpcodeI32Const, 0x1, 4640 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16XorU, 0x2, 0x8, // alignment=2^2, offset=8 4641 }, 4642 }, 4643 { 4644 name: "i32.atomic.rmw.xor", 4645 body: []byte{ 4646 OpcodeI32Const, 0x0, 4647 OpcodeI32Const, 0x1, 4648 OpcodeAtomicPrefix, OpcodeAtomicI32RmwXor, 0x3, 0x8, // alignment=2^3, offset=8 4649 }, 4650 }, 4651 { 4652 name: "i64.atomic.rmw8.xor_u", 4653 body: []byte{ 4654 OpcodeI32Const, 0x0, 4655 OpcodeI64Const, 0x1, 4656 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8XorU, 0x1, 0x8, // alignment=2^1, offset=8 4657 }, 4658 }, 4659 { 4660 name: "i64.atomic.rmw16.xor_u", 4661 body: []byte{ 4662 OpcodeI32Const, 0x0, 4663 OpcodeI64Const, 0x1, 4664 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16XorU, 0x2, 0x8, // alignment=2^2, offset=8 4665 }, 4666 }, 4667 { 4668 name: "i64.atomic.rmw32.xor_u", 4669 body: []byte{ 4670 OpcodeI32Const, 0x0, 4671 OpcodeI64Const, 0x1, 4672 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32XorU, 0x3, 0x8, // alignment=2^3, offset=8 4673 }, 4674 }, 4675 { 4676 name: "i64.atomic.rmw.xor", 4677 body: []byte{ 4678 OpcodeI32Const, 0x0, 4679 OpcodeI64Const, 0x1, 4680 OpcodeAtomicPrefix, OpcodeAtomicI64RmwXor, 0x4, 0x8, // alignment=2^4, offset=8 4681 }, 4682 }, 4683 { 4684 name: "i32.atomic.rmw8.xchg_u", 4685 body: []byte{ 4686 OpcodeI32Const, 0x0, 4687 OpcodeI32Const, 0x1, 4688 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8XchgU, 0x1, 0x8, // alignment=2^1, offset=8 4689 }, 4690 }, 4691 { 4692 name: "i32.atomic.rmw16.xchg_u", 4693 body: []byte{ 4694 OpcodeI32Const, 0x0, 4695 OpcodeI32Const, 0x1, 4696 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16XchgU, 0x2, 0x8, // alignment=2^2, offset=8 4697 }, 4698 }, 4699 { 4700 name: "i32.atomic.rmw.xchg", 4701 body: []byte{ 4702 OpcodeI32Const, 0x0, 4703 OpcodeI32Const, 0x1, 4704 OpcodeAtomicPrefix, OpcodeAtomicI32RmwXchg, 0x3, 0x8, // alignment=2^3, offset=8 4705 }, 4706 }, 4707 { 4708 name: "i64.atomic.rmw8.xchg_u", 4709 body: []byte{ 4710 OpcodeI32Const, 0x0, 4711 OpcodeI64Const, 0x1, 4712 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8XchgU, 0x1, 0x8, // alignment=2^1, offset=8 4713 }, 4714 }, 4715 { 4716 name: "i64.atomic.rmw16.xchg_u", 4717 body: []byte{ 4718 OpcodeI32Const, 0x0, 4719 OpcodeI64Const, 0x1, 4720 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16XchgU, 0x2, 0x8, // alignment=2^2, offset=8 4721 }, 4722 }, 4723 { 4724 name: "i64.atomic.rmw32.xchg_u", 4725 body: []byte{ 4726 OpcodeI32Const, 0x0, 4727 OpcodeI64Const, 0x1, 4728 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32XchgU, 0x3, 0x8, // alignment=2^3, offset=8 4729 }, 4730 }, 4731 { 4732 name: "i64.atomic.rmw.xchg", 4733 body: []byte{ 4734 OpcodeI32Const, 0x0, 4735 OpcodeI64Const, 0x1, 4736 OpcodeAtomicPrefix, OpcodeAtomicI64RmwXchg, 0x4, 0x8, // alignment=2^4, offset=8 4737 }, 4738 }, 4739 { 4740 name: "i32.atomic.rmw8.cmpxchg_u", 4741 body: []byte{ 4742 OpcodeI32Const, 0x0, 4743 OpcodeI32Const, 0x1, 4744 OpcodeI32Const, 0x2, 4745 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8CmpxchgU, 0x1, 0x8, // alignment=2^1, offset=8 4746 }, 4747 }, 4748 { 4749 name: "i32.atomic.rmw16.cmpxchg_u", 4750 body: []byte{ 4751 OpcodeI32Const, 0x0, 4752 OpcodeI32Const, 0x1, 4753 OpcodeI32Const, 0x2, 4754 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16CmpxchgU, 0x2, 0x8, // alignment=2^2, offset=8 4755 }, 4756 }, 4757 { 4758 name: "i32.atomic.rmw.cmpxchg", 4759 body: []byte{ 4760 OpcodeI32Const, 0x0, 4761 OpcodeI32Const, 0x1, 4762 OpcodeI32Const, 0x2, 4763 OpcodeAtomicPrefix, OpcodeAtomicI32RmwCmpxchg, 0x3, 0x8, // alignment=2^3, offset=8 4764 }, 4765 }, 4766 { 4767 name: "i64.atomic.rmw8.xchg_u", 4768 body: []byte{ 4769 OpcodeI32Const, 0x0, 4770 OpcodeI64Const, 0x1, 4771 OpcodeI64Const, 0x2, 4772 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8CmpxchgU, 0x1, 0x8, // alignment=2^1, offset=8 4773 }, 4774 }, 4775 { 4776 name: "i64.atomic.rmw16.cmpxchg_u", 4777 body: []byte{ 4778 OpcodeI32Const, 0x0, 4779 OpcodeI64Const, 0x1, 4780 OpcodeI64Const, 0x2, 4781 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16CmpxchgU, 0x2, 0x8, // alignment=2^2, offset=8 4782 }, 4783 }, 4784 { 4785 name: "i64.atomic.rmw32.cmpxchg_u", 4786 body: []byte{ 4787 OpcodeI32Const, 0x0, 4788 OpcodeI64Const, 0x1, 4789 OpcodeI64Const, 0x1, 4790 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32CmpxchgU, 0x3, 0x8, // alignment=2^3, offset=8 4791 }, 4792 }, 4793 { 4794 name: "i64.atomic.rmw.cmpxchg", 4795 body: []byte{ 4796 OpcodeI32Const, 0x0, 4797 OpcodeI64Const, 0x1, 4798 OpcodeI64Const, 0x2, 4799 OpcodeAtomicPrefix, OpcodeAtomicI64RmwCmpxchg, 0x4, 0x8, // alignment=2^4, offset=8 4800 }, 4801 }, 4802 { 4803 name: "memory.atomic.wait32", 4804 body: []byte{ 4805 OpcodeI32Const, 0x0, 4806 OpcodeI32Const, 0x1, 4807 OpcodeI64Const, 0x2, 4808 OpcodeAtomicPrefix, OpcodeAtomicMemoryWait32, 0x3, 0x8, // alignment=2^3, offset=8 4809 }, 4810 }, 4811 { 4812 name: "memory.atomic.wait64", 4813 body: []byte{ 4814 OpcodeI32Const, 0x0, 4815 OpcodeI64Const, 0x1, 4816 OpcodeI64Const, 0x2, 4817 OpcodeAtomicPrefix, OpcodeAtomicMemoryWait64, 0x4, 0x8, // alignment=2^4, offset=8 4818 }, 4819 }, 4820 { 4821 name: "memory.atomic.notify", 4822 body: []byte{ 4823 OpcodeI32Const, 0x0, 4824 OpcodeI32Const, 0x1, 4825 OpcodeAtomicPrefix, OpcodeAtomicMemoryNotify, 0x3, 0x8, // alignment=2^3, offset=8 4826 }, 4827 }, 4828 } 4829 4830 for _, tt := range tests { 4831 tc := tt 4832 t.Run(tc.name, func(t *testing.T) { 4833 body := append([]byte{}, tc.body...) 4834 if !tt.noDropBeforeReturn { 4835 body = append(body, OpcodeDrop) 4836 } 4837 body = append(body, OpcodeEnd) 4838 m := &Module{ 4839 TypeSection: []FunctionType{v_v}, 4840 FunctionSection: []Index{0}, 4841 CodeSection: []Code{{Body: body}}, 4842 } 4843 err := m.validateFunction(&stacks{}, experimental.CoreFeaturesThreads, 4844 0, []Index{0}, nil, &Memory{}, []Table{}, nil, bytes.NewReader(nil)) 4845 require.Error(t, err, "invalid memory alignment") 4846 }) 4847 } 4848 }) 4849 }