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