github.com/tetratelabs/wazero@v1.7.3-0.20240513003603-48f702e154b5/internal/wasm/func_validation_test.go (about) 1 package wasm 2 3 import ( 4 "bytes" 5 "fmt" 6 "testing" 7 8 "github.com/tetratelabs/wazero/api" 9 "github.com/tetratelabs/wazero/experimental" 10 "github.com/tetratelabs/wazero/internal/leb128" 11 "github.com/tetratelabs/wazero/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, "unexpected end of function at pc=0x1") 3590 } 3591 3592 // TestFunctionValidation_redundantEnd is found in th validation fuzzing. 3593 func TestFunctionValidation_redundantElse(t *testing.T) { 3594 for _, tc := range []struct { 3595 body []byte 3596 expErr string 3597 }{ 3598 { 3599 body: []byte{OpcodeEnd, OpcodeElse}, 3600 expErr: "unexpected end of function at pc=0x1", 3601 }, 3602 { 3603 body: []byte{OpcodeElse, OpcodeEnd}, 3604 expErr: "else instruction must be used in if block: 0x0", 3605 }, 3606 { 3607 body: []byte{OpcodeBlock, 0, OpcodeElse, OpcodeEnd}, 3608 expErr: "else instruction must be used in if block: 0x2", 3609 }, 3610 { 3611 body: []byte{ 3612 OpcodeI32Const, 0, 3613 OpcodeIf, 0, OpcodeElse, OpcodeElse, OpcodeEnd, OpcodeEnd, 3614 }, 3615 expErr: "else instruction must be used in if block: 0x5", 3616 }, 3617 } { 3618 t.Run(tc.expErr, func(t *testing.T) { 3619 m := &Module{TypeSection: []FunctionType{{}}, FunctionSection: []Index{0}, CodeSection: []Code{{Body: tc.body}}} 3620 err := m.validateFunction(&stacks{}, api.CoreFeaturesV2, 3621 0, nil, nil, nil, nil, nil, bytes.NewReader(nil)) 3622 require.EqualError(t, err, tc.expErr) 3623 }) 3624 } 3625 } 3626 3627 func Test_SplitCallStack(t *testing.T) { 3628 oneToEight := []uint64{1, 2, 3, 4, 5, 6, 7, 8} 3629 3630 tests := []struct { 3631 name string 3632 ft *FunctionType 3633 stack, expectedParams, expectedResults []uint64 3634 expectedErr string 3635 }{ 3636 { 3637 name: "v_v", 3638 ft: &v_v, 3639 stack: oneToEight, 3640 expectedParams: nil, 3641 expectedResults: nil, 3642 }, 3643 { 3644 name: "v_v - stack nil", 3645 ft: &v_v, 3646 expectedParams: nil, 3647 expectedResults: nil, 3648 }, 3649 { 3650 name: "v_i32", 3651 ft: &v_i32, 3652 stack: oneToEight, 3653 expectedParams: nil, 3654 expectedResults: []uint64{1}, 3655 }, 3656 { 3657 name: "f32i32_v", 3658 ft: &f32i32_v, 3659 stack: oneToEight, 3660 expectedParams: []uint64{1, 2}, 3661 expectedResults: nil, 3662 }, 3663 { 3664 name: "f64f32_i64", 3665 ft: &f64f32_i64, 3666 stack: oneToEight, 3667 expectedParams: []uint64{1, 2}, 3668 expectedResults: []uint64{1}, 3669 }, 3670 { 3671 name: "f64i32_v128i64", 3672 ft: &f64i32_v128i64, 3673 stack: oneToEight, 3674 expectedParams: []uint64{1, 2}, 3675 expectedResults: []uint64{1, 2, 3}, 3676 }, 3677 { 3678 name: "not enough room for params", 3679 ft: &f64i32_v128i64, 3680 stack: oneToEight[0:1], 3681 expectedErr: "need 2 params, but stack size is 1", 3682 }, 3683 { 3684 name: "not enough room for results", 3685 ft: &f64i32_v128i64, 3686 stack: oneToEight[0:2], 3687 expectedErr: "need 3 results, but stack size is 2", 3688 }, 3689 } 3690 3691 for _, tt := range tests { 3692 tc := tt 3693 3694 t.Run(tc.name, func(t *testing.T) { 3695 params, results, err := SplitCallStack(tc.ft, tc.stack) 3696 if tc.expectedErr != "" { 3697 require.EqualError(t, err, tc.expectedErr) 3698 } else { 3699 require.Equal(t, tc.expectedParams, params) 3700 require.Equal(t, tc.expectedResults, results) 3701 } 3702 }) 3703 } 3704 } 3705 3706 func TestModule_funcValidation_Atomic(t *testing.T) { 3707 t.Run("valid bytecode", func(t *testing.T) { 3708 tests := []struct { 3709 name string 3710 body []byte 3711 noDropBeforeReturn bool 3712 }{ 3713 { 3714 name: "i32.atomic.load8_u", 3715 body: []byte{ 3716 OpcodeI32Const, 0x0, 3717 OpcodeAtomicPrefix, OpcodeAtomicI32Load8U, 0x0, 0x8, // alignment=2^0, offset=8 3718 }, 3719 }, 3720 { 3721 name: "i32.atomic.load16_u", 3722 body: []byte{ 3723 OpcodeI32Const, 0x0, 3724 OpcodeAtomicPrefix, OpcodeAtomicI32Load16U, 0x1, 0x8, // alignment=2^1, offset=8 3725 }, 3726 }, 3727 { 3728 name: "i32.atomic.load", 3729 body: []byte{ 3730 OpcodeI32Const, 0x0, 3731 OpcodeAtomicPrefix, OpcodeAtomicI32Load, 0x2, 0x8, // alignment=2^2, offset=8 3732 }, 3733 }, 3734 { 3735 name: "i64.atomic.load8_u", 3736 body: []byte{ 3737 OpcodeI32Const, 0x0, 3738 OpcodeAtomicPrefix, OpcodeAtomicI64Load8U, 0x0, 0x8, // alignment=2^0, offset=8 3739 }, 3740 }, 3741 { 3742 name: "i64.atomic.load16_u", 3743 body: []byte{ 3744 OpcodeI32Const, 0x0, 3745 OpcodeAtomicPrefix, OpcodeAtomicI64Load16U, 0x1, 0x8, // alignment=2^1, offset=8 3746 }, 3747 }, 3748 { 3749 name: "i64.atomic.load32_u", 3750 body: []byte{ 3751 OpcodeI32Const, 0x0, 3752 OpcodeAtomicPrefix, OpcodeAtomicI64Load32U, 0x2, 0x8, // alignment=2^2, offset=8 3753 }, 3754 }, 3755 { 3756 name: "i64.atomic.load", 3757 body: []byte{ 3758 OpcodeI32Const, 0x0, 3759 OpcodeAtomicPrefix, OpcodeAtomicI64Load, 0x3, 0x8, // alignment=2^3, offset=8 3760 }, 3761 }, 3762 { 3763 name: "i32.atomic.store8", 3764 body: []byte{ 3765 OpcodeI32Const, 0x1, 3766 OpcodeI32Const, 0x0, 3767 OpcodeAtomicPrefix, OpcodeAtomicI32Store8, 0x0, 0x8, // alignment=2^0, offset=8 3768 }, 3769 noDropBeforeReturn: true, 3770 }, 3771 { 3772 name: "i32.atomic.store16", 3773 body: []byte{ 3774 OpcodeI32Const, 0x1, 3775 OpcodeI32Const, 0x0, 3776 OpcodeAtomicPrefix, OpcodeAtomicI32Store16, 0x1, 0x8, // alignment=2^1, offset=8 3777 }, 3778 noDropBeforeReturn: true, 3779 }, 3780 { 3781 name: "i32.atomic.store", 3782 body: []byte{ 3783 OpcodeI32Const, 0x1, 3784 OpcodeI32Const, 0x0, 3785 OpcodeAtomicPrefix, OpcodeAtomicI32Store, 0x2, 0x8, // alignment=2^2, offset=8 3786 }, 3787 noDropBeforeReturn: true, 3788 }, 3789 { 3790 name: "i64.atomic.store8", 3791 body: []byte{ 3792 OpcodeI32Const, 0x0, 3793 OpcodeI64Const, 0x1, 3794 OpcodeAtomicPrefix, OpcodeAtomicI64Store8, 0x0, 0x8, // alignment=2^0, offset=8 3795 }, 3796 noDropBeforeReturn: true, 3797 }, 3798 { 3799 name: "i64.atomic.store16", 3800 body: []byte{ 3801 OpcodeI32Const, 0x0, 3802 OpcodeI64Const, 0x1, 3803 OpcodeAtomicPrefix, OpcodeAtomicI64Store16, 0x1, 0x8, // alignment=2^1, offset=8 3804 }, 3805 noDropBeforeReturn: true, 3806 }, 3807 { 3808 name: "i64.atomic.store32", 3809 body: []byte{ 3810 OpcodeI32Const, 0x0, 3811 OpcodeI64Const, 0x1, 3812 OpcodeAtomicPrefix, OpcodeAtomicI64Store32, 0x2, 0x8, // alignment=2^2, offset=8 3813 }, 3814 noDropBeforeReturn: true, 3815 }, 3816 { 3817 name: "i64.atomic.store", 3818 body: []byte{ 3819 OpcodeI32Const, 0x0, 3820 OpcodeI64Const, 0x1, 3821 OpcodeAtomicPrefix, OpcodeAtomicI64Store, 0x3, 0x8, // alignment=2^3, offset=8 3822 }, 3823 noDropBeforeReturn: true, 3824 }, 3825 { 3826 name: "i32.atomic.rmw8.add_u", 3827 body: []byte{ 3828 OpcodeI32Const, 0x0, 3829 OpcodeI32Const, 0x1, 3830 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8AddU, 0x0, 0x8, // alignment=2^0, offset=8 3831 }, 3832 }, 3833 { 3834 name: "i32.atomic.rmw16.add_u", 3835 body: []byte{ 3836 OpcodeI32Const, 0x0, 3837 OpcodeI32Const, 0x1, 3838 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16AddU, 0x1, 0x8, // alignment=2^1, offset=8 3839 }, 3840 }, 3841 { 3842 name: "i32.atomic.rmw.add", 3843 body: []byte{ 3844 OpcodeI32Const, 0x0, 3845 OpcodeI32Const, 0x1, 3846 OpcodeAtomicPrefix, OpcodeAtomicI32RmwAdd, 0x2, 0x8, // alignment=2^2, offset=8 3847 }, 3848 }, 3849 { 3850 name: "i64.atomic.rmw8.add_u", 3851 body: []byte{ 3852 OpcodeI32Const, 0x0, 3853 OpcodeI64Const, 0x1, 3854 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8AddU, 0x0, 0x8, // alignment=2^0, offset=8 3855 }, 3856 }, 3857 { 3858 name: "i64.atomic.rmw16.add_u", 3859 body: []byte{ 3860 OpcodeI32Const, 0x0, 3861 OpcodeI64Const, 0x1, 3862 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16AddU, 0x1, 0x8, // alignment=2^1, offset=8 3863 }, 3864 }, 3865 { 3866 name: "i64.atomic.rmw32.add_u", 3867 body: []byte{ 3868 OpcodeI32Const, 0x0, 3869 OpcodeI64Const, 0x1, 3870 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32AddU, 0x2, 0x8, // alignment=2^2, offset=8 3871 }, 3872 }, 3873 { 3874 name: "i64.atomic.rmw.add", 3875 body: []byte{ 3876 OpcodeI32Const, 0x0, 3877 OpcodeI64Const, 0x1, 3878 OpcodeAtomicPrefix, OpcodeAtomicI64RmwAdd, 0x3, 0x8, // alignment=2^3, offset=8 3879 }, 3880 }, 3881 { 3882 name: "i32.atomic.rmw8.sub_u", 3883 body: []byte{ 3884 OpcodeI32Const, 0x0, 3885 OpcodeI32Const, 0x1, 3886 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8SubU, 0x0, 0x8, // alignment=2^0, offset=8 3887 }, 3888 }, 3889 { 3890 name: "i32.atomic.rmw16.sub_u", 3891 body: []byte{ 3892 OpcodeI32Const, 0x0, 3893 OpcodeI32Const, 0x1, 3894 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16SubU, 0x1, 0x8, // alignment=2^1, offset=8 3895 }, 3896 }, 3897 { 3898 name: "i32.atomic.rmw.sub", 3899 body: []byte{ 3900 OpcodeI32Const, 0x0, 3901 OpcodeI32Const, 0x1, 3902 OpcodeAtomicPrefix, OpcodeAtomicI32RmwSub, 0x2, 0x8, // alignment=2^2, offset=8 3903 }, 3904 }, 3905 { 3906 name: "i64.atomic.rmw8.sub_u", 3907 body: []byte{ 3908 OpcodeI32Const, 0x0, 3909 OpcodeI64Const, 0x1, 3910 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8SubU, 0x0, 0x8, // alignment=2^0, offset=8 3911 }, 3912 }, 3913 { 3914 name: "i64.atomic.rmw16.sub_u", 3915 body: []byte{ 3916 OpcodeI32Const, 0x0, 3917 OpcodeI64Const, 0x1, 3918 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16SubU, 0x1, 0x8, // alignment=2^1, offset=8 3919 }, 3920 }, 3921 { 3922 name: "i64.atomic.rmw32.sub_u", 3923 body: []byte{ 3924 OpcodeI32Const, 0x0, 3925 OpcodeI64Const, 0x1, 3926 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32SubU, 0x2, 0x8, // alignment=2^2, offset=8 3927 }, 3928 }, 3929 { 3930 name: "i64.atomic.rmw.sub", 3931 body: []byte{ 3932 OpcodeI32Const, 0x0, 3933 OpcodeI64Const, 0x1, 3934 OpcodeAtomicPrefix, OpcodeAtomicI64RmwSub, 0x3, 0x8, // alignment=2^3, offset=8 3935 }, 3936 }, 3937 { 3938 name: "i32.atomic.rmw8.and_u", 3939 body: []byte{ 3940 OpcodeI32Const, 0x0, 3941 OpcodeI32Const, 0x1, 3942 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8AndU, 0x0, 0x8, // alignment=2^0, offset=8 3943 }, 3944 }, 3945 { 3946 name: "i32.atomic.rmw16.and_u", 3947 body: []byte{ 3948 OpcodeI32Const, 0x0, 3949 OpcodeI32Const, 0x1, 3950 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16AndU, 0x1, 0x8, // alignment=2^1, offset=8 3951 }, 3952 }, 3953 { 3954 name: "i32.atomic.rmw.and", 3955 body: []byte{ 3956 OpcodeI32Const, 0x0, 3957 OpcodeI32Const, 0x1, 3958 OpcodeAtomicPrefix, OpcodeAtomicI32RmwAnd, 0x2, 0x8, // alignment=2^2, offset=8 3959 }, 3960 }, 3961 { 3962 name: "i64.atomic.rmw8.and_u", 3963 body: []byte{ 3964 OpcodeI32Const, 0x0, 3965 OpcodeI64Const, 0x1, 3966 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8AndU, 0x0, 0x8, // alignment=2^0, offset=8 3967 }, 3968 }, 3969 { 3970 name: "i64.atomic.rmw16.and_u", 3971 body: []byte{ 3972 OpcodeI32Const, 0x0, 3973 OpcodeI64Const, 0x1, 3974 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16AndU, 0x1, 0x8, // alignment=2^1, offset=8 3975 }, 3976 }, 3977 { 3978 name: "i64.atomic.rmw32.and_u", 3979 body: []byte{ 3980 OpcodeI32Const, 0x0, 3981 OpcodeI64Const, 0x1, 3982 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32AndU, 0x2, 0x8, // alignment=2^2, offset=8 3983 }, 3984 }, 3985 { 3986 name: "i64.atomic.rmw.and", 3987 body: []byte{ 3988 OpcodeI32Const, 0x0, 3989 OpcodeI64Const, 0x1, 3990 OpcodeAtomicPrefix, OpcodeAtomicI64RmwAnd, 0x3, 0x8, // alignment=2^3, offset=8 3991 }, 3992 }, 3993 { 3994 name: "i32.atomic.rmw8.or", 3995 body: []byte{ 3996 OpcodeI32Const, 0x0, 3997 OpcodeI32Const, 0x1, 3998 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8OrU, 0x0, 0x8, // alignment=2^0, offset=8 3999 }, 4000 }, 4001 { 4002 name: "i32.atomic.rmw16.or_u", 4003 body: []byte{ 4004 OpcodeI32Const, 0x0, 4005 OpcodeI32Const, 0x1, 4006 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16OrU, 0x1, 0x8, // alignment=2^1, offset=8 4007 }, 4008 }, 4009 { 4010 name: "i32.atomic.rmw.or", 4011 body: []byte{ 4012 OpcodeI32Const, 0x0, 4013 OpcodeI32Const, 0x1, 4014 OpcodeAtomicPrefix, OpcodeAtomicI32RmwOr, 0x2, 0x8, // alignment=2^2, offset=8 4015 }, 4016 }, 4017 { 4018 name: "i64.atomic.rmw8.or_u", 4019 body: []byte{ 4020 OpcodeI32Const, 0x0, 4021 OpcodeI64Const, 0x1, 4022 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8OrU, 0x0, 0x8, // alignment=2^0, offset=8 4023 }, 4024 }, 4025 { 4026 name: "i64.atomic.rmw16.or_u", 4027 body: []byte{ 4028 OpcodeI32Const, 0x0, 4029 OpcodeI64Const, 0x1, 4030 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16OrU, 0x1, 0x8, // alignment=2^1, offset=8 4031 }, 4032 }, 4033 { 4034 name: "i64.atomic.rmw32.or_u", 4035 body: []byte{ 4036 OpcodeI32Const, 0x0, 4037 OpcodeI64Const, 0x1, 4038 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32OrU, 0x2, 0x8, // alignment=2^2, offset=8 4039 }, 4040 }, 4041 { 4042 name: "i64.atomic.rmw.or", 4043 body: []byte{ 4044 OpcodeI32Const, 0x0, 4045 OpcodeI64Const, 0x1, 4046 OpcodeAtomicPrefix, OpcodeAtomicI64RmwOr, 0x3, 0x8, // alignment=2^3, offset=8 4047 }, 4048 }, 4049 { 4050 name: "i32.atomic.rmw8.xor_u", 4051 body: []byte{ 4052 OpcodeI32Const, 0x0, 4053 OpcodeI32Const, 0x1, 4054 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8XorU, 0x0, 0x8, // alignment=2^0, offset=8 4055 }, 4056 }, 4057 { 4058 name: "i32.atomic.rmw16.xor_u", 4059 body: []byte{ 4060 OpcodeI32Const, 0x0, 4061 OpcodeI32Const, 0x1, 4062 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16XorU, 0x1, 0x8, // alignment=2^1, offset=8 4063 }, 4064 }, 4065 { 4066 name: "i32.atomic.rmw.xor", 4067 body: []byte{ 4068 OpcodeI32Const, 0x0, 4069 OpcodeI32Const, 0x1, 4070 OpcodeAtomicPrefix, OpcodeAtomicI32RmwXor, 0x2, 0x8, // alignment=2^2, offset=8 4071 }, 4072 }, 4073 { 4074 name: "i64.atomic.rmw8.xor_u", 4075 body: []byte{ 4076 OpcodeI32Const, 0x0, 4077 OpcodeI64Const, 0x1, 4078 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8XorU, 0x0, 0x8, // alignment=2^0, offset=8 4079 }, 4080 }, 4081 { 4082 name: "i64.atomic.rmw16.xor_u", 4083 body: []byte{ 4084 OpcodeI32Const, 0x0, 4085 OpcodeI64Const, 0x1, 4086 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16XorU, 0x1, 0x8, // alignment=2^1, offset=8 4087 }, 4088 }, 4089 { 4090 name: "i64.atomic.rmw32.xor_u", 4091 body: []byte{ 4092 OpcodeI32Const, 0x0, 4093 OpcodeI64Const, 0x1, 4094 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32XorU, 0x2, 0x8, // alignment=2^2, offset=8 4095 }, 4096 }, 4097 { 4098 name: "i64.atomic.rmw.xor", 4099 body: []byte{ 4100 OpcodeI32Const, 0x0, 4101 OpcodeI64Const, 0x1, 4102 OpcodeAtomicPrefix, OpcodeAtomicI64RmwXor, 0x3, 0x8, // alignment=2^3, offset=8 4103 }, 4104 }, 4105 { 4106 name: "i32.atomic.rmw8.xchg_u", 4107 body: []byte{ 4108 OpcodeI32Const, 0x0, 4109 OpcodeI32Const, 0x1, 4110 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8XchgU, 0x0, 0x8, // alignment=2^0, offset=8 4111 }, 4112 }, 4113 { 4114 name: "i32.atomic.rmw16.xchg_u", 4115 body: []byte{ 4116 OpcodeI32Const, 0x0, 4117 OpcodeI32Const, 0x1, 4118 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16XchgU, 0x1, 0x8, // alignment=2^1, offset=8 4119 }, 4120 }, 4121 { 4122 name: "i32.atomic.rmw.xchg", 4123 body: []byte{ 4124 OpcodeI32Const, 0x0, 4125 OpcodeI32Const, 0x1, 4126 OpcodeAtomicPrefix, OpcodeAtomicI32RmwXchg, 0x2, 0x8, // alignment=2^2, offset=8 4127 }, 4128 }, 4129 { 4130 name: "i64.atomic.rmw8.xchg_u", 4131 body: []byte{ 4132 OpcodeI32Const, 0x0, 4133 OpcodeI64Const, 0x1, 4134 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8XchgU, 0x0, 0x8, // alignment=2^0, offset=8 4135 }, 4136 }, 4137 { 4138 name: "i64.atomic.rmw16.xchg_u", 4139 body: []byte{ 4140 OpcodeI32Const, 0x0, 4141 OpcodeI64Const, 0x1, 4142 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16XchgU, 0x1, 0x8, // alignment=2^1, offset=8 4143 }, 4144 }, 4145 { 4146 name: "i64.atomic.rmw32.xchg_u", 4147 body: []byte{ 4148 OpcodeI32Const, 0x0, 4149 OpcodeI64Const, 0x1, 4150 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32XchgU, 0x2, 0x8, // alignment=2^2, offset=8 4151 }, 4152 }, 4153 { 4154 name: "i64.atomic.rmw.xchg", 4155 body: []byte{ 4156 OpcodeI32Const, 0x0, 4157 OpcodeI64Const, 0x1, 4158 OpcodeAtomicPrefix, OpcodeAtomicI64RmwXchg, 0x3, 0x8, // alignment=2^3, offset=8 4159 }, 4160 }, 4161 { 4162 name: "i32.atomic.rmw8.cmpxchg_u", 4163 body: []byte{ 4164 OpcodeI32Const, 0x0, 4165 OpcodeI32Const, 0x1, 4166 OpcodeI32Const, 0x2, 4167 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8CmpxchgU, 0x0, 0x8, // alignment=2^0, offset=8 4168 }, 4169 }, 4170 { 4171 name: "i32.atomic.rmw16.cmpxchg_u", 4172 body: []byte{ 4173 OpcodeI32Const, 0x0, 4174 OpcodeI32Const, 0x1, 4175 OpcodeI32Const, 0x2, 4176 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16CmpxchgU, 0x1, 0x8, // alignment=2^1, offset=8 4177 }, 4178 }, 4179 { 4180 name: "i32.atomic.rmw.cmpxchg", 4181 body: []byte{ 4182 OpcodeI32Const, 0x0, 4183 OpcodeI32Const, 0x1, 4184 OpcodeI32Const, 0x2, 4185 OpcodeAtomicPrefix, OpcodeAtomicI32RmwCmpxchg, 0x2, 0x8, // alignment=2^2, offset=8 4186 }, 4187 }, 4188 { 4189 name: "i64.atomic.rmw8.xchg_u", 4190 body: []byte{ 4191 OpcodeI32Const, 0x0, 4192 OpcodeI64Const, 0x1, 4193 OpcodeI64Const, 0x2, 4194 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8CmpxchgU, 0x0, 0x8, // alignment=2^0, offset=8 4195 }, 4196 }, 4197 { 4198 name: "i64.atomic.rmw16.cmpxchg_u", 4199 body: []byte{ 4200 OpcodeI32Const, 0x0, 4201 OpcodeI64Const, 0x1, 4202 OpcodeI64Const, 0x2, 4203 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16CmpxchgU, 0x1, 0x8, // alignment=2^1, offset=8 4204 }, 4205 }, 4206 { 4207 name: "i64.atomic.rmw32.cmpxchg_u", 4208 body: []byte{ 4209 OpcodeI32Const, 0x0, 4210 OpcodeI64Const, 0x1, 4211 OpcodeI64Const, 0x1, 4212 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32CmpxchgU, 0x2, 0x8, // alignment=2^2, offset=8 4213 }, 4214 }, 4215 { 4216 name: "i64.atomic.rmw.cmpxchg", 4217 body: []byte{ 4218 OpcodeI32Const, 0x0, 4219 OpcodeI64Const, 0x1, 4220 OpcodeI64Const, 0x2, 4221 OpcodeAtomicPrefix, OpcodeAtomicI64RmwCmpxchg, 0x3, 0x8, // alignment=2^3, offset=8 4222 }, 4223 }, 4224 { 4225 name: "memory.atomic.wait32", 4226 body: []byte{ 4227 OpcodeI32Const, 0x0, 4228 OpcodeI32Const, 0x1, 4229 OpcodeI64Const, 0x2, 4230 OpcodeAtomicPrefix, OpcodeAtomicMemoryWait32, 0x2, 0x8, // alignment=2^2, offset=8 4231 }, 4232 }, 4233 { 4234 name: "memory.atomic.wait64", 4235 body: []byte{ 4236 OpcodeI32Const, 0x0, 4237 OpcodeI64Const, 0x1, 4238 OpcodeI64Const, 0x2, 4239 OpcodeAtomicPrefix, OpcodeAtomicMemoryWait64, 0x3, 0x8, // alignment=2^3, offset=8 4240 }, 4241 }, 4242 { 4243 name: "memory.atomic.notify", 4244 body: []byte{ 4245 OpcodeI32Const, 0x0, 4246 OpcodeI32Const, 0x1, 4247 OpcodeAtomicPrefix, OpcodeAtomicMemoryNotify, 0x2, 0x8, // alignment=2^2, offset=8 4248 }, 4249 }, 4250 { 4251 name: "memory.atomic.fence", 4252 body: []byte{ 4253 OpcodeAtomicPrefix, OpcodeAtomicFence, 0x0, 4254 }, 4255 noDropBeforeReturn: true, 4256 }, 4257 } 4258 4259 for _, tt := range tests { 4260 tc := tt 4261 t.Run(tc.name, func(t *testing.T) { 4262 body := append([]byte{}, tc.body...) 4263 if !tt.noDropBeforeReturn { 4264 body = append(body, OpcodeDrop) 4265 } 4266 body = append(body, OpcodeEnd) 4267 m := &Module{ 4268 TypeSection: []FunctionType{v_v}, 4269 FunctionSection: []Index{0}, 4270 CodeSection: []Code{{Body: body}}, 4271 } 4272 4273 t.Run("with memory", func(t *testing.T) { 4274 err := m.validateFunction(&stacks{}, experimental.CoreFeaturesThreads, 4275 0, []Index{0}, nil, &Memory{}, []Table{}, nil, bytes.NewReader(nil)) 4276 require.NoError(t, err) 4277 }) 4278 4279 t.Run("without memory", func(t *testing.T) { 4280 err := m.validateFunction(&stacks{}, experimental.CoreFeaturesThreads, 4281 0, []Index{0}, nil, nil, []Table{}, nil, bytes.NewReader(nil)) 4282 // Only fence doesn't require memory 4283 if tc.name == "memory.atomic.fence" { 4284 require.NoError(t, err) 4285 } else { 4286 require.Error(t, err, fmt.Sprintf("memory must exist for %s", tc.name)) 4287 } 4288 }) 4289 }) 4290 } 4291 }) 4292 4293 t.Run("atomic.fence bad immediate", func(t *testing.T) { 4294 body := []byte{ 4295 OpcodeAtomicPrefix, OpcodeAtomicFence, 0x1, 4296 OpcodeEnd, 4297 } 4298 m := &Module{ 4299 TypeSection: []FunctionType{v_v}, 4300 FunctionSection: []Index{0}, 4301 CodeSection: []Code{{Body: body}}, 4302 } 4303 err := m.validateFunction(&stacks{}, experimental.CoreFeaturesThreads, 4304 0, []Index{0}, nil, &Memory{}, []Table{}, nil, bytes.NewReader(nil)) 4305 require.Error(t, err, "invalid immediate value for atomic.fence") 4306 }) 4307 4308 t.Run("bad alignment", func(t *testing.T) { 4309 tests := []struct { 4310 name string 4311 body []byte 4312 noDropBeforeReturn bool 4313 }{ 4314 { 4315 name: "i32.atomic.load8_u", 4316 body: []byte{ 4317 OpcodeI32Const, 0x0, 4318 OpcodeAtomicPrefix, OpcodeAtomicI32Load8U, 0x1, 0x8, // alignment=2^1, offset=8 4319 }, 4320 }, 4321 { 4322 name: "i32.atomic.load16_u", 4323 body: []byte{ 4324 OpcodeI32Const, 0x0, 4325 OpcodeAtomicPrefix, OpcodeAtomicI32Load16U, 0x2, 0x8, // alignment=2^2, offset=8 4326 }, 4327 }, 4328 { 4329 name: "i32.atomic.load", 4330 body: []byte{ 4331 OpcodeI32Const, 0x0, 4332 OpcodeAtomicPrefix, OpcodeAtomicI32Load, 0x3, 0x8, // alignment=2^3, offset=8 4333 }, 4334 }, 4335 { 4336 name: "i64.atomic.load8_u", 4337 body: []byte{ 4338 OpcodeI32Const, 0x0, 4339 OpcodeAtomicPrefix, OpcodeAtomicI64Load8U, 0x1, 0x8, // alignment=2^1, offset=8 4340 }, 4341 }, 4342 { 4343 name: "i64.atomic.load16_u", 4344 body: []byte{ 4345 OpcodeI32Const, 0x0, 4346 OpcodeAtomicPrefix, OpcodeAtomicI64Load16U, 0x2, 0x8, // alignment=2^2, offset=8 4347 }, 4348 }, 4349 { 4350 name: "i64.atomic.load32_u", 4351 body: []byte{ 4352 OpcodeI32Const, 0x0, 4353 OpcodeAtomicPrefix, OpcodeAtomicI64Load32U, 0x3, 0x8, // alignment=2^3, offset=8 4354 }, 4355 }, 4356 { 4357 name: "i64.atomic.load", 4358 body: []byte{ 4359 OpcodeI32Const, 0x0, 4360 OpcodeAtomicPrefix, OpcodeAtomicI64Load, 0x4, 0x8, // alignment=2^4, offset=8 4361 }, 4362 }, 4363 { 4364 name: "i32.atomic.store8", 4365 body: []byte{ 4366 OpcodeI32Const, 0x1, 4367 OpcodeI32Const, 0x0, 4368 OpcodeAtomicPrefix, OpcodeAtomicI32Store8, 0x1, 0x8, // alignment=2^1, offset=8 4369 }, 4370 noDropBeforeReturn: true, 4371 }, 4372 { 4373 name: "i32.atomic.store16", 4374 body: []byte{ 4375 OpcodeI32Const, 0x1, 4376 OpcodeI32Const, 0x0, 4377 OpcodeAtomicPrefix, OpcodeAtomicI32Store16, 0x2, 0x8, // alignment=2^2, offset=8 4378 }, 4379 noDropBeforeReturn: true, 4380 }, 4381 { 4382 name: "i32.atomic.store", 4383 body: []byte{ 4384 OpcodeI32Const, 0x1, 4385 OpcodeI32Const, 0x0, 4386 OpcodeAtomicPrefix, OpcodeAtomicI32Store, 0x3, 0x8, // alignment=2^3, offset=8 4387 }, 4388 noDropBeforeReturn: true, 4389 }, 4390 { 4391 name: "i64.atomic.store8", 4392 body: []byte{ 4393 OpcodeI32Const, 0x0, 4394 OpcodeI64Const, 0x1, 4395 OpcodeAtomicPrefix, OpcodeAtomicI64Store8, 0x1, 0x8, // alignment=2^1, offset=8 4396 }, 4397 noDropBeforeReturn: true, 4398 }, 4399 { 4400 name: "i64.atomic.store16", 4401 body: []byte{ 4402 OpcodeI32Const, 0x0, 4403 OpcodeI64Const, 0x1, 4404 OpcodeAtomicPrefix, OpcodeAtomicI64Store16, 0x2, 0x8, // alignment=2^2, offset=8 4405 }, 4406 noDropBeforeReturn: true, 4407 }, 4408 { 4409 name: "i64.atomic.store32", 4410 body: []byte{ 4411 OpcodeI32Const, 0x0, 4412 OpcodeI64Const, 0x1, 4413 OpcodeAtomicPrefix, OpcodeAtomicI64Store32, 0x3, 0x8, // alignment=2^3, offset=8 4414 }, 4415 noDropBeforeReturn: true, 4416 }, 4417 { 4418 name: "i64.atomic.store", 4419 body: []byte{ 4420 OpcodeI32Const, 0x0, 4421 OpcodeI64Const, 0x1, 4422 OpcodeAtomicPrefix, OpcodeAtomicI64Store, 0x4, 0x8, // alignment=2^4, offset=8 4423 }, 4424 noDropBeforeReturn: true, 4425 }, 4426 { 4427 name: "i32.atomic.rmw8.add_u", 4428 body: []byte{ 4429 OpcodeI32Const, 0x0, 4430 OpcodeI32Const, 0x1, 4431 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8AddU, 0x1, 0x8, // alignment=2^1, offset=8 4432 }, 4433 }, 4434 { 4435 name: "i32.atomic.rmw16.add_u", 4436 body: []byte{ 4437 OpcodeI32Const, 0x0, 4438 OpcodeI32Const, 0x1, 4439 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16AddU, 0x2, 0x8, // alignment=2^2, offset=8 4440 }, 4441 }, 4442 { 4443 name: "i32.atomic.rmw.add", 4444 body: []byte{ 4445 OpcodeI32Const, 0x0, 4446 OpcodeI32Const, 0x1, 4447 OpcodeAtomicPrefix, OpcodeAtomicI32RmwAdd, 0x3, 0x8, // alignment=2^3, offset=8 4448 }, 4449 }, 4450 { 4451 name: "i64.atomic.rmw8.add_u", 4452 body: []byte{ 4453 OpcodeI32Const, 0x0, 4454 OpcodeI64Const, 0x1, 4455 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8AddU, 0x1, 0x8, // alignment=2^1, offset=8 4456 }, 4457 }, 4458 { 4459 name: "i64.atomic.rmw16.add_u", 4460 body: []byte{ 4461 OpcodeI32Const, 0x0, 4462 OpcodeI64Const, 0x1, 4463 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16AddU, 0x2, 0x8, // alignment=2^2, offset=8 4464 }, 4465 }, 4466 { 4467 name: "i64.atomic.rmw32.add_u", 4468 body: []byte{ 4469 OpcodeI32Const, 0x0, 4470 OpcodeI64Const, 0x1, 4471 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32AddU, 0x3, 0x8, // alignment=2^3, offset=8 4472 }, 4473 }, 4474 { 4475 name: "i64.atomic.rmw.add", 4476 body: []byte{ 4477 OpcodeI32Const, 0x0, 4478 OpcodeI64Const, 0x1, 4479 OpcodeAtomicPrefix, OpcodeAtomicI64RmwAdd, 0x4, 0x8, // alignment=2^4, offset=8 4480 }, 4481 }, 4482 { 4483 name: "i32.atomic.rmw8.sub_u", 4484 body: []byte{ 4485 OpcodeI32Const, 0x0, 4486 OpcodeI32Const, 0x1, 4487 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8SubU, 0x1, 0x8, // alignment=2^1, offset=8 4488 }, 4489 }, 4490 { 4491 name: "i32.atomic.rmw16.sub_u", 4492 body: []byte{ 4493 OpcodeI32Const, 0x0, 4494 OpcodeI32Const, 0x1, 4495 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16SubU, 0x2, 0x8, // alignment=2^2, offset=8 4496 }, 4497 }, 4498 { 4499 name: "i32.atomic.rmw.sub", 4500 body: []byte{ 4501 OpcodeI32Const, 0x0, 4502 OpcodeI32Const, 0x1, 4503 OpcodeAtomicPrefix, OpcodeAtomicI32RmwSub, 0x3, 0x8, // alignment=2^3, offset=8 4504 }, 4505 }, 4506 { 4507 name: "i64.atomic.rmw8.sub_u", 4508 body: []byte{ 4509 OpcodeI32Const, 0x0, 4510 OpcodeI64Const, 0x1, 4511 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8SubU, 0x1, 0x8, // alignment=2^1, offset=8 4512 }, 4513 }, 4514 { 4515 name: "i64.atomic.rmw16.sub_u", 4516 body: []byte{ 4517 OpcodeI32Const, 0x0, 4518 OpcodeI64Const, 0x1, 4519 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16SubU, 0x2, 0x8, // alignment=2^2, offset=8 4520 }, 4521 }, 4522 { 4523 name: "i64.atomic.rmw32.sub_u", 4524 body: []byte{ 4525 OpcodeI32Const, 0x0, 4526 OpcodeI64Const, 0x1, 4527 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32SubU, 0x3, 0x8, // alignment=2^3, offset=8 4528 }, 4529 }, 4530 { 4531 name: "i64.atomic.rmw.sub", 4532 body: []byte{ 4533 OpcodeI32Const, 0x0, 4534 OpcodeI64Const, 0x1, 4535 OpcodeAtomicPrefix, OpcodeAtomicI64RmwSub, 0x4, 0x8, // alignment=2^4, offset=8 4536 }, 4537 }, 4538 { 4539 name: "i32.atomic.rmw8.and_u", 4540 body: []byte{ 4541 OpcodeI32Const, 0x0, 4542 OpcodeI32Const, 0x1, 4543 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8AndU, 0x1, 0x8, // alignment=2^1, offset=8 4544 }, 4545 }, 4546 { 4547 name: "i32.atomic.rmw16.and_u", 4548 body: []byte{ 4549 OpcodeI32Const, 0x0, 4550 OpcodeI32Const, 0x1, 4551 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16AndU, 0x2, 0x8, // alignment=2^2, offset=8 4552 }, 4553 }, 4554 { 4555 name: "i32.atomic.rmw.and", 4556 body: []byte{ 4557 OpcodeI32Const, 0x0, 4558 OpcodeI32Const, 0x1, 4559 OpcodeAtomicPrefix, OpcodeAtomicI32RmwAnd, 0x3, 0x8, // alignment=2^3, offset=8 4560 }, 4561 }, 4562 { 4563 name: "i64.atomic.rmw8.and_u", 4564 body: []byte{ 4565 OpcodeI32Const, 0x0, 4566 OpcodeI64Const, 0x1, 4567 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8AndU, 0x1, 0x8, // alignment=2^1, offset=8 4568 }, 4569 }, 4570 { 4571 name: "i64.atomic.rmw16.and_u", 4572 body: []byte{ 4573 OpcodeI32Const, 0x0, 4574 OpcodeI64Const, 0x1, 4575 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16AndU, 0x2, 0x8, // alignment=2^2, offset=8 4576 }, 4577 }, 4578 { 4579 name: "i64.atomic.rmw32.and_u", 4580 body: []byte{ 4581 OpcodeI32Const, 0x0, 4582 OpcodeI64Const, 0x1, 4583 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32AndU, 0x3, 0x8, // alignment=2^3, offset=8 4584 }, 4585 }, 4586 { 4587 name: "i64.atomic.rmw.and", 4588 body: []byte{ 4589 OpcodeI32Const, 0x0, 4590 OpcodeI64Const, 0x1, 4591 OpcodeAtomicPrefix, OpcodeAtomicI64RmwAnd, 0x4, 0x8, // alignment=2^4, offset=8 4592 }, 4593 }, 4594 { 4595 name: "i32.atomic.rmw8.or", 4596 body: []byte{ 4597 OpcodeI32Const, 0x0, 4598 OpcodeI32Const, 0x1, 4599 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8OrU, 0x1, 0x8, // alignment=2^1, offset=8 4600 }, 4601 }, 4602 { 4603 name: "i32.atomic.rmw16.or_u", 4604 body: []byte{ 4605 OpcodeI32Const, 0x0, 4606 OpcodeI32Const, 0x1, 4607 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16OrU, 0x2, 0x8, // alignment=2^2, offset=8 4608 }, 4609 }, 4610 { 4611 name: "i32.atomic.rmw.or", 4612 body: []byte{ 4613 OpcodeI32Const, 0x0, 4614 OpcodeI32Const, 0x1, 4615 OpcodeAtomicPrefix, OpcodeAtomicI32RmwOr, 0x3, 0x8, // alignment=2^3, offset=8 4616 }, 4617 }, 4618 { 4619 name: "i64.atomic.rmw8.or_u", 4620 body: []byte{ 4621 OpcodeI32Const, 0x0, 4622 OpcodeI64Const, 0x1, 4623 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8OrU, 0x1, 0x8, // alignment=2^1, offset=8 4624 }, 4625 }, 4626 { 4627 name: "i64.atomic.rmw16.or_u", 4628 body: []byte{ 4629 OpcodeI32Const, 0x0, 4630 OpcodeI64Const, 0x1, 4631 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16OrU, 0x2, 0x8, // alignment=2^2, offset=8 4632 }, 4633 }, 4634 { 4635 name: "i64.atomic.rmw32.or_u", 4636 body: []byte{ 4637 OpcodeI32Const, 0x0, 4638 OpcodeI64Const, 0x1, 4639 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32OrU, 0x3, 0x8, // alignment=2^3, offset=8 4640 }, 4641 }, 4642 { 4643 name: "i64.atomic.rmw.or", 4644 body: []byte{ 4645 OpcodeI32Const, 0x0, 4646 OpcodeI64Const, 0x1, 4647 OpcodeAtomicPrefix, OpcodeAtomicI64RmwOr, 0x4, 0x8, // alignment=2^4, offset=8 4648 }, 4649 }, 4650 { 4651 name: "i32.atomic.rmw8.xor_u", 4652 body: []byte{ 4653 OpcodeI32Const, 0x0, 4654 OpcodeI32Const, 0x1, 4655 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8XorU, 0x1, 0x8, // alignment=2^1, offset=8 4656 }, 4657 }, 4658 { 4659 name: "i32.atomic.rmw16.xor_u", 4660 body: []byte{ 4661 OpcodeI32Const, 0x0, 4662 OpcodeI32Const, 0x1, 4663 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16XorU, 0x2, 0x8, // alignment=2^2, offset=8 4664 }, 4665 }, 4666 { 4667 name: "i32.atomic.rmw.xor", 4668 body: []byte{ 4669 OpcodeI32Const, 0x0, 4670 OpcodeI32Const, 0x1, 4671 OpcodeAtomicPrefix, OpcodeAtomicI32RmwXor, 0x3, 0x8, // alignment=2^3, offset=8 4672 }, 4673 }, 4674 { 4675 name: "i64.atomic.rmw8.xor_u", 4676 body: []byte{ 4677 OpcodeI32Const, 0x0, 4678 OpcodeI64Const, 0x1, 4679 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8XorU, 0x1, 0x8, // alignment=2^1, offset=8 4680 }, 4681 }, 4682 { 4683 name: "i64.atomic.rmw16.xor_u", 4684 body: []byte{ 4685 OpcodeI32Const, 0x0, 4686 OpcodeI64Const, 0x1, 4687 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16XorU, 0x2, 0x8, // alignment=2^2, offset=8 4688 }, 4689 }, 4690 { 4691 name: "i64.atomic.rmw32.xor_u", 4692 body: []byte{ 4693 OpcodeI32Const, 0x0, 4694 OpcodeI64Const, 0x1, 4695 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32XorU, 0x3, 0x8, // alignment=2^3, offset=8 4696 }, 4697 }, 4698 { 4699 name: "i64.atomic.rmw.xor", 4700 body: []byte{ 4701 OpcodeI32Const, 0x0, 4702 OpcodeI64Const, 0x1, 4703 OpcodeAtomicPrefix, OpcodeAtomicI64RmwXor, 0x4, 0x8, // alignment=2^4, offset=8 4704 }, 4705 }, 4706 { 4707 name: "i32.atomic.rmw8.xchg_u", 4708 body: []byte{ 4709 OpcodeI32Const, 0x0, 4710 OpcodeI32Const, 0x1, 4711 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8XchgU, 0x1, 0x8, // alignment=2^1, offset=8 4712 }, 4713 }, 4714 { 4715 name: "i32.atomic.rmw16.xchg_u", 4716 body: []byte{ 4717 OpcodeI32Const, 0x0, 4718 OpcodeI32Const, 0x1, 4719 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16XchgU, 0x2, 0x8, // alignment=2^2, offset=8 4720 }, 4721 }, 4722 { 4723 name: "i32.atomic.rmw.xchg", 4724 body: []byte{ 4725 OpcodeI32Const, 0x0, 4726 OpcodeI32Const, 0x1, 4727 OpcodeAtomicPrefix, OpcodeAtomicI32RmwXchg, 0x3, 0x8, // alignment=2^3, offset=8 4728 }, 4729 }, 4730 { 4731 name: "i64.atomic.rmw8.xchg_u", 4732 body: []byte{ 4733 OpcodeI32Const, 0x0, 4734 OpcodeI64Const, 0x1, 4735 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8XchgU, 0x1, 0x8, // alignment=2^1, offset=8 4736 }, 4737 }, 4738 { 4739 name: "i64.atomic.rmw16.xchg_u", 4740 body: []byte{ 4741 OpcodeI32Const, 0x0, 4742 OpcodeI64Const, 0x1, 4743 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16XchgU, 0x2, 0x8, // alignment=2^2, offset=8 4744 }, 4745 }, 4746 { 4747 name: "i64.atomic.rmw32.xchg_u", 4748 body: []byte{ 4749 OpcodeI32Const, 0x0, 4750 OpcodeI64Const, 0x1, 4751 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32XchgU, 0x3, 0x8, // alignment=2^3, offset=8 4752 }, 4753 }, 4754 { 4755 name: "i64.atomic.rmw.xchg", 4756 body: []byte{ 4757 OpcodeI32Const, 0x0, 4758 OpcodeI64Const, 0x1, 4759 OpcodeAtomicPrefix, OpcodeAtomicI64RmwXchg, 0x4, 0x8, // alignment=2^4, offset=8 4760 }, 4761 }, 4762 { 4763 name: "i32.atomic.rmw8.cmpxchg_u", 4764 body: []byte{ 4765 OpcodeI32Const, 0x0, 4766 OpcodeI32Const, 0x1, 4767 OpcodeI32Const, 0x2, 4768 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8CmpxchgU, 0x1, 0x8, // alignment=2^1, offset=8 4769 }, 4770 }, 4771 { 4772 name: "i32.atomic.rmw16.cmpxchg_u", 4773 body: []byte{ 4774 OpcodeI32Const, 0x0, 4775 OpcodeI32Const, 0x1, 4776 OpcodeI32Const, 0x2, 4777 OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16CmpxchgU, 0x2, 0x8, // alignment=2^2, offset=8 4778 }, 4779 }, 4780 { 4781 name: "i32.atomic.rmw.cmpxchg", 4782 body: []byte{ 4783 OpcodeI32Const, 0x0, 4784 OpcodeI32Const, 0x1, 4785 OpcodeI32Const, 0x2, 4786 OpcodeAtomicPrefix, OpcodeAtomicI32RmwCmpxchg, 0x3, 0x8, // alignment=2^3, offset=8 4787 }, 4788 }, 4789 { 4790 name: "i64.atomic.rmw8.xchg_u", 4791 body: []byte{ 4792 OpcodeI32Const, 0x0, 4793 OpcodeI64Const, 0x1, 4794 OpcodeI64Const, 0x2, 4795 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8CmpxchgU, 0x1, 0x8, // alignment=2^1, offset=8 4796 }, 4797 }, 4798 { 4799 name: "i64.atomic.rmw16.cmpxchg_u", 4800 body: []byte{ 4801 OpcodeI32Const, 0x0, 4802 OpcodeI64Const, 0x1, 4803 OpcodeI64Const, 0x2, 4804 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16CmpxchgU, 0x2, 0x8, // alignment=2^2, offset=8 4805 }, 4806 }, 4807 { 4808 name: "i64.atomic.rmw32.cmpxchg_u", 4809 body: []byte{ 4810 OpcodeI32Const, 0x0, 4811 OpcodeI64Const, 0x1, 4812 OpcodeI64Const, 0x1, 4813 OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32CmpxchgU, 0x3, 0x8, // alignment=2^3, offset=8 4814 }, 4815 }, 4816 { 4817 name: "i64.atomic.rmw.cmpxchg", 4818 body: []byte{ 4819 OpcodeI32Const, 0x0, 4820 OpcodeI64Const, 0x1, 4821 OpcodeI64Const, 0x2, 4822 OpcodeAtomicPrefix, OpcodeAtomicI64RmwCmpxchg, 0x4, 0x8, // alignment=2^4, offset=8 4823 }, 4824 }, 4825 { 4826 name: "memory.atomic.wait32", 4827 body: []byte{ 4828 OpcodeI32Const, 0x0, 4829 OpcodeI32Const, 0x1, 4830 OpcodeI64Const, 0x2, 4831 OpcodeAtomicPrefix, OpcodeAtomicMemoryWait32, 0x3, 0x8, // alignment=2^3, offset=8 4832 }, 4833 }, 4834 { 4835 name: "memory.atomic.wait64", 4836 body: []byte{ 4837 OpcodeI32Const, 0x0, 4838 OpcodeI64Const, 0x1, 4839 OpcodeI64Const, 0x2, 4840 OpcodeAtomicPrefix, OpcodeAtomicMemoryWait64, 0x4, 0x8, // alignment=2^4, offset=8 4841 }, 4842 }, 4843 { 4844 name: "memory.atomic.notify", 4845 body: []byte{ 4846 OpcodeI32Const, 0x0, 4847 OpcodeI32Const, 0x1, 4848 OpcodeAtomicPrefix, OpcodeAtomicMemoryNotify, 0x3, 0x8, // alignment=2^3, offset=8 4849 }, 4850 }, 4851 } 4852 4853 for _, tt := range tests { 4854 tc := tt 4855 t.Run(tc.name, func(t *testing.T) { 4856 body := append([]byte{}, tc.body...) 4857 if !tt.noDropBeforeReturn { 4858 body = append(body, OpcodeDrop) 4859 } 4860 body = append(body, OpcodeEnd) 4861 m := &Module{ 4862 TypeSection: []FunctionType{v_v}, 4863 FunctionSection: []Index{0}, 4864 CodeSection: []Code{{Body: body}}, 4865 } 4866 err := m.validateFunction(&stacks{}, experimental.CoreFeaturesThreads, 4867 0, []Index{0}, nil, &Memory{}, []Table{}, nil, bytes.NewReader(nil)) 4868 require.Error(t, err, "invalid memory alignment") 4869 }) 4870 } 4871 }) 4872 }