ref-gvn.js (21131B)
1 // Tests that exercise GVN and LICM. The general pattern for these tests is to 2 // create values near the top of the function and then create situations where 3 // equivalent values are created below, including in loops. 4 5 // ref.null 6 { 7 let numAnyref = 0; 8 let numExternref = 0; 9 10 const { test1, test2 } = wasmEvalText(`(module 11 (import "" "dummy1" (func $dummy1 (param anyref))) 12 (import "" "dummy2" (func $dummy2 (param externref))) 13 (import "" "countAnyref" (func $countAnyref)) 14 (import "" "countExternref" (func $countExternref)) 15 16 (func (export "test1") 17 ;; Ensure that we keep two MWasmNullConstants with two different 18 ;; hierarchies at the top of the graph. 19 (call $dummy1 (ref.null none)) 20 (call $dummy2 (ref.null noextern)) 21 22 (ref.test anyref (ref.null none)) 23 if 24 call $countAnyref 25 end 26 27 ;; If you're not careful, this null might be GVN'd with the null from the 28 ;; other hierarchy, causing bad behavior. 29 (ref.test externref (ref.null noextern)) 30 if 31 call $countExternref 32 end 33 ) 34 (func (export "test2") 35 (local i32 anyref externref) 36 37 (local.tee 1 (ref.null none)) 38 call $dummy1 39 (local.tee 2 (ref.null noextern)) 40 call $dummy2 41 42 loop 43 (ref.test anyref (local.get 1)) 44 if 45 call $countAnyref 46 end 47 48 (ref.test externref (local.get 2)) 49 if 50 call $countExternref 51 end 52 53 (i32.ge_s (local.get 0) (i32.const 5)) 54 if 55 ;; Note that these use the top type instead of the bottom type. 56 (local.set 1 (ref.null any)) 57 (local.set 2 (ref.null extern)) 58 end 59 60 (local.tee 0 (i32.add (local.get 0) (i32.const 1))) 61 (i32.lt_s (i32.const 10)) 62 br_if 0 63 end 64 ) 65 )`, { 66 "": { 67 dummy1() {}, 68 dummy2() {}, 69 countAnyref() { 70 numAnyref += 1; 71 }, 72 countExternref() { 73 numExternref += 1; 74 }, 75 }, 76 }).exports; 77 78 for (let i = 0; i < 100; i++) { 79 test1(); 80 } 81 82 assertEq(numAnyref, 100); 83 assertEq(numExternref, 100); 84 85 for (let i = 0; i < 100; i++) { 86 test2(); 87 } 88 89 assertEq(numAnyref, 1100); 90 assertEq(numExternref, 1100); 91 } 92 93 // structs and struct fields 94 { 95 const counts = { 100: 0, 200: 0, 300: 0, 400: 0 }; 96 97 const { test1, test2 } = wasmEvalText(`(module 98 (type $a (struct (field i32))) 99 (type $s (struct (field (ref $a)) (field (ref $a)))) 100 101 (import "" "dummy" (func $dummy (param anyref))) 102 (import "" "count" (func $count (param i32))) 103 104 (func (export "test1") 105 (local anyref) 106 107 (struct.new $a (i32.const 100)) 108 (struct.new $a (i32.const 200)) 109 struct.new $s 110 local.tee 0 111 call $dummy 112 113 local.get 0 114 ref.cast (ref $s) 115 struct.get $s 0 116 ref.cast (ref $a) 117 struct.get $a 0 118 call $count 119 120 local.get 0 121 ref.cast (ref $s) 122 struct.get $s 1 123 ref.cast (ref $a) 124 struct.get $a 0 125 call $count 126 ) 127 (func (export "test2") 128 (local anyref i32) 129 130 (struct.new $a (i32.const 100)) 131 (struct.new $a (i32.const 200)) 132 struct.new $s 133 local.tee 0 134 call $dummy 135 136 loop 137 local.get 0 138 ref.cast (ref $s) 139 struct.get $s 0 140 ref.cast (ref $a) 141 struct.get $a 0 142 call $count 143 144 local.get 0 145 ref.cast (ref $s) 146 struct.get $s 1 147 ref.cast (ref $a) 148 struct.get $a 0 149 call $count 150 151 (i32.ge_s (local.get 1) (i32.const 4)) 152 if 153 (struct.new $a (i32.const 300)) 154 (struct.new $a (i32.const 400)) 155 struct.new $s 156 local.set 0 157 end 158 159 (local.tee 1 (i32.add (local.get 1) (i32.const 1))) 160 (i32.lt_s (i32.const 10)) 161 br_if 0 162 end 163 ) 164 )`, { 165 "": { 166 dummy() {}, 167 count(n) { 168 counts[n] += 1; 169 }, 170 }, 171 }).exports; 172 173 for (let i = 0; i < 100; i++) { 174 test1(); 175 } 176 177 assertEq(counts[100], 100); 178 assertEq(counts[200], 100); 179 assertEq(counts[300], 0); 180 assertEq(counts[400], 0); 181 182 for (let i = 0; i < 100; i++) { 183 test2(); 184 } 185 186 assertEq(counts[100], 600); 187 assertEq(counts[200], 600); 188 assertEq(counts[300], 500); 189 assertEq(counts[400], 500); 190 } 191 192 // arrays and array elems 193 { 194 const counts = { 100: 0, 200: 0, 300: 0, 400: 0 }; 195 196 const { test1, test2 } = wasmEvalText(`(module 197 (type $e (array i32)) 198 (type $a (array (ref $e))) 199 200 (import "" "dummy" (func $dummy (param anyref))) 201 (import "" "count" (func $count (param i32))) 202 203 (func (export "test1") 204 (local anyref) 205 206 (array.new_fixed $e 1 (i32.const 100)) 207 (array.new_fixed $e 1 (i32.const 200)) 208 array.new_fixed $a 2 209 local.tee 0 210 call $dummy 211 212 local.get 0 213 ref.cast (ref $a) 214 (array.get $a (i32.const 0)) 215 ref.cast (ref $e) 216 (array.get $e (i32.const 0)) 217 call $count 218 219 local.get 0 220 ref.cast (ref $a) 221 (array.get $a (i32.const 1)) 222 ref.cast (ref $e) 223 (array.get $e (i32.const 0)) 224 call $count 225 ) 226 (func (export "test2") 227 (local anyref i32) 228 229 (array.new_fixed $e 1 (i32.const 100)) 230 (array.new_fixed $e 1 (i32.const 200)) 231 array.new_fixed $a 2 232 local.tee 0 233 call $dummy 234 235 loop 236 local.get 0 237 ref.cast (ref $a) 238 (array.get $a (i32.const 0)) 239 ref.cast (ref $e) 240 (array.get $e (i32.const 0)) 241 call $count 242 243 local.get 0 244 ref.cast (ref $a) 245 (array.get $a (i32.const 1)) 246 ref.cast (ref $e) 247 (array.get $e (i32.const 0)) 248 call $count 249 250 (i32.ge_s (local.get 1) (i32.const 4)) 251 if 252 (array.new_fixed $e 1 (i32.const 300)) 253 (array.new_fixed $e 1 (i32.const 400)) 254 array.new_fixed $a 2 255 local.set 0 256 end 257 258 (local.tee 1 (i32.add (local.get 1) (i32.const 1))) 259 (i32.lt_s (i32.const 10)) 260 br_if 0 261 end 262 ) 263 )`, { 264 "": { 265 dummy() {}, 266 count(n) { 267 counts[n] += 1; 268 }, 269 }, 270 }).exports; 271 272 for (let i = 0; i < 100; i++) { 273 test1(); 274 } 275 276 assertEq(counts[100], 100); 277 assertEq(counts[200], 100); 278 assertEq(counts[300], 0); 279 assertEq(counts[400], 0); 280 281 for (let i = 0; i < 100; i++) { 282 test2(); 283 } 284 285 assertEq(counts[100], 600); 286 assertEq(counts[200], 600); 287 assertEq(counts[300], 500); 288 assertEq(counts[400], 500); 289 } 290 291 // table elems 292 { 293 const counts = { 100: 0, 200: 0, 300: 0, 400: 0 }; 294 295 const { test1, test2 } = wasmEvalText(`(module 296 (type $f (func)) 297 298 (import "" "dummy" (func $dummy (param anyref))) 299 (import "" "count" (func $count (param i32))) 300 301 (table funcref (elem (ref.func $count100) (ref.func $count200))) 302 (table (ref null $f) (elem (ref.func $count300) (ref.func $count400))) 303 304 (func $count100 (type $f) 305 (call $count (i32.const 100)) 306 ) 307 (func $count200 (type $f) 308 (call $count (i32.const 200)) 309 ) 310 (func $count300 (type $f) 311 (call $count (i32.const 300)) 312 ) 313 (func $count400 (type $f) 314 (call $count (i32.const 400)) 315 ) 316 317 (func (export "test1") 318 (table.get 0 (i32.const 0)) 319 ref.cast (ref null $f) 320 call_ref $f 321 322 (table.get 0 (i32.const 1)) 323 ref.cast (ref null $f) 324 call_ref $f 325 326 (table.get 1 (i32.const 0)) 327 ref.cast (ref null $f) 328 call_ref $f 329 330 (table.get 1 (i32.const 1)) 331 ref.cast (ref null $f) 332 call_ref $f 333 ) 334 (func (export "test2") 335 (local i32) 336 337 (table.get 0 (i32.const 0)) 338 ref.cast (ref null $f) 339 call_ref $f 340 341 (table.get 1 (i32.const 0)) 342 ref.cast (ref null $f) 343 call_ref $f 344 345 loop 346 (table.get 0 (i32.const 0)) 347 ref.cast (ref null $f) 348 call_ref $f 349 350 (table.get 0 (i32.const 1)) 351 ref.cast (ref null $f) 352 call_ref $f 353 354 (table.get 1 (i32.const 0)) 355 ref.cast (ref null $f) 356 call_ref $f 357 358 (table.get 1 (i32.const 1)) 359 ref.cast (ref null $f) 360 call_ref $f 361 362 (local.tee 0 (i32.add (local.get 0) (i32.const 1))) 363 (i32.lt_s (i32.const 10)) 364 br_if 0 365 end 366 ) 367 )`, { 368 "": { 369 dummy() {}, 370 count(n) { 371 counts[n] += 1; 372 }, 373 }, 374 }).exports; 375 376 for (let i = 0; i < 100; i++) { 377 test1(); 378 } 379 380 assertEq(counts[100], 100); 381 assertEq(counts[200], 100); 382 assertEq(counts[300], 100); 383 assertEq(counts[400], 100); 384 385 for (let i = 0; i < 100; i++) { 386 test2(); 387 } 388 389 assertEq(counts[100], 1200); 390 assertEq(counts[200], 1100); 391 assertEq(counts[300], 1200); 392 assertEq(counts[400], 1100); 393 } 394 395 // ref.i31 396 { 397 const countsI31 = { 100: 0, 200: 0, 300: 0 }; 398 const countsI32 = { 100: 0, 200: 0, 300: 0 }; 399 const countsU32 = { 100: 0, 200: 0, 300: 0 }; 400 401 const { test1, test2 } = wasmEvalText(`(module 402 (import "" "dummy" (func $dummy (param i31ref))) 403 (import "" "countI31" (func $countI31 (param i31ref))) 404 (import "" "countI32" (func $countI32 (param i32))) 405 (import "" "countU32" (func $countU32 (param i32))) 406 407 (func (export "test1") 408 (call $dummy (ref.i31 (i32.const 100))) 409 (call $dummy (ref.i31 (i32.const 200))) 410 411 (call $countI31 (ref.i31 (i32.const 100))) 412 (call $countI31 (ref.i31 (i32.const 200))) 413 (call $countI32 (i31.get_s (ref.i31 (i32.const 100)))) 414 (call $countI32 (i31.get_s (ref.i31 (i32.const 200)))) 415 (call $countU32 (i31.get_u (ref.i31 (i32.const 100)))) 416 (call $countU32 (i31.get_u (ref.i31 (i32.const 200)))) 417 ) 418 (func (export "test2") 419 (local i32 i31ref) 420 421 (call $dummy (ref.i31 (i32.const 100))) 422 (local.tee 1 (ref.i31 (i32.const 200))) 423 call $dummy 424 425 loop 426 (call $countI31 (ref.i31 (i32.const 100))) 427 (call $countI31 (local.get 1)) 428 (call $countI32 (i31.get_s (ref.i31 (i32.const 100)))) 429 (call $countI32 (i31.get_s (local.get 1))) 430 (call $countU32 (i31.get_u (ref.i31 (i32.const 100)))) 431 (call $countU32 (i31.get_u (local.get 1))) 432 433 (local.set 1 (ref.i31 (i32.const 300))) 434 435 (local.tee 0 (i32.add (local.get 0) (i32.const 1))) 436 (i32.lt_s (i32.const 10)) 437 br_if 0 438 end 439 ) 440 )`, { 441 "": { 442 dummy() {}, 443 countI31(n) { 444 countsI31[n] += 1; 445 }, 446 countI32(n) { 447 countsI32[n] += 1; 448 }, 449 countU32(n) { 450 countsU32[n] += 1; 451 }, 452 }, 453 }).exports; 454 455 for (let i = 0; i < 100; i++) { 456 test1(); 457 } 458 459 assertEq(countsI31[100], 100); 460 assertEq(countsI31[200], 100); 461 assertEq(countsI31[300], 0); 462 assertEq(countsI32[100], 100); 463 assertEq(countsI32[200], 100); 464 assertEq(countsI32[300], 0); 465 assertEq(countsU32[100], 100); 466 assertEq(countsU32[200], 100); 467 assertEq(countsU32[300], 0); 468 469 for (let i = 0; i < 100; i++) { 470 test2(); 471 } 472 473 assertEq(countsI31[100], 1100); 474 assertEq(countsI31[200], 200); 475 assertEq(countsI31[300], 900); 476 assertEq(countsI32[100], 1100); 477 assertEq(countsI32[200], 200); 478 assertEq(countsI32[300], 900); 479 assertEq(countsU32[100], 1100); 480 assertEq(countsU32[200], 200); 481 assertEq(countsU32[300], 900); 482 } 483 484 // parameters and calls 485 { 486 let numNull = 0; 487 let numNonNull = 0; 488 489 // Note that we are ok with inlining kicking in eventually (and have 490 // constructed these tests to trigger that). 491 const { test1, test2 } = wasmEvalText(`(module 492 (type $f_anyref (func (param anyref))) 493 (type $f_nullref (func (param nullref))) 494 495 (import "" "thing" (global $thing externref)) 496 (import "" "countNull" (func $countNull)) 497 (import "" "countNonNull" (func $countNonNull)) 498 499 (table funcref (elem 500 (ref.func $testNull_ref.is_null) 501 (ref.func $mustNull_ref.is_null) 502 (ref.func $testNull_ref.test) 503 (ref.func $mustNull_ref.test) 504 )) 505 506 (func $makeNull_Loose (result anyref) 507 ref.null any 508 ) 509 (func $makeNonNull_Loose (result anyref) 510 (any.convert_extern (global.get $thing)) 511 ) 512 (func $makeNull_Precise (result nullref) 513 ref.null none 514 ) 515 (func $makeNonNull_Precise (result (ref any)) 516 (ref.as_non_null (any.convert_extern (global.get $thing))) 517 ) 518 519 (func $testNull_ref.is_null (param anyref) 520 (ref.is_null (local.get 0)) 521 if 522 call $countNull 523 else 524 call $countNonNull 525 end 526 ) 527 (func $mustNull_ref.is_null (param nullref) 528 (ref.is_null (local.get 0)) ;; trivial! 529 if 530 call $countNull 531 end 532 ) 533 (func $testNull_ref.test (param anyref) 534 (ref.test nullref (local.get 0)) ;; trivial! 535 if 536 call $countNull 537 else 538 call $countNonNull 539 end 540 ) 541 (func $mustNull_ref.test (param nullref) 542 (ref.test nullref (local.get 0)) ;; trivial! 543 if 544 call $countNull 545 end 546 ) 547 548 (func (export "test1") 549 (local anyref) 550 551 (local.set 0 (call $makeNull_Loose)) 552 (call $testNull_ref.is_null (local.get 0)) 553 (call $testNull_ref.test (local.get 0)) 554 (call_indirect (type $f_anyref) (local.get 0) (i32.const 0)) 555 (call_indirect (type $f_anyref) (local.get 0) (i32.const 2)) 556 (ref.is_null (local.get 0)) ;; guaranteed to succeed 557 if 558 (call $mustNull_ref.is_null (ref.cast nullref (local.get 0))) 559 (call $mustNull_ref.test (ref.cast nullref (local.get 0))) 560 (call_indirect (type $f_nullref) (ref.cast nullref (local.get 0)) (i32.const 1)) 561 (call_indirect (type $f_nullref) (ref.cast nullref (local.get 0)) (i32.const 3)) 562 end 563 564 (local.set 0 (call $makeNull_Precise)) 565 (call $testNull_ref.is_null (local.get 0)) 566 (call $testNull_ref.test (local.get 0)) 567 (call_indirect (type $f_anyref) (local.get 0) (i32.const 0)) 568 (call_indirect (type $f_anyref) (local.get 0) (i32.const 2)) 569 (ref.is_null (local.get 0)) ;; guaranteed to succeed 570 if 571 (call $mustNull_ref.is_null (ref.cast nullref (local.get 0))) 572 (call $mustNull_ref.test (ref.cast nullref (local.get 0))) 573 (call_indirect (type $f_nullref) (ref.cast nullref (local.get 0)) (i32.const 1)) 574 (call_indirect (type $f_nullref) (ref.cast nullref (local.get 0)) (i32.const 3)) 575 end 576 577 (local.set 0 (call $makeNonNull_Loose)) 578 (call $testNull_ref.is_null (local.get 0)) 579 (call $testNull_ref.test (local.get 0)) 580 (call_indirect (type $f_anyref) (local.get 0) (i32.const 0)) 581 (call_indirect (type $f_anyref) (local.get 0) (i32.const 2)) 582 (ref.is_null (local.get 0)) ;; guaranteed to fail 583 if 584 (call $mustNull_ref.is_null (ref.cast nullref (local.get 0))) 585 (call $mustNull_ref.test (ref.cast nullref (local.get 0))) 586 (call_indirect (type $f_nullref) (ref.cast nullref (local.get 0)) (i32.const 1)) 587 (call_indirect (type $f_nullref) (ref.cast nullref (local.get 0)) (i32.const 3)) 588 end 589 590 (local.set 0 (call $makeNonNull_Precise)) 591 (call $testNull_ref.is_null (local.get 0)) 592 (call $testNull_ref.test (local.get 0)) 593 (call_indirect (type $f_anyref) (local.get 0) (i32.const 0)) 594 (call_indirect (type $f_anyref) (local.get 0) (i32.const 2)) 595 (ref.is_null (local.get 0)) ;; guaranteed to fail 596 if 597 (call $mustNull_ref.is_null (ref.cast nullref (local.get 0))) 598 (call $mustNull_ref.test (ref.cast nullref (local.get 0))) 599 (call_indirect (type $f_nullref) (ref.cast nullref (local.get 0)) (i32.const 1)) 600 (call_indirect (type $f_nullref) (ref.cast nullref (local.get 0)) (i32.const 3)) 601 end 602 ) 603 (func (export "test2") 604 (local anyref i32) 605 606 block 607 loop 608 (i32.eq (local.get 1) (i32.const 0)) 609 if 610 (local.set 0 (call $makeNull_Loose)) 611 else 612 (i32.eq (local.get 1) (i32.const 1)) 613 if 614 (local.set 0 (call $makeNull_Precise)) 615 else 616 (i32.eq (local.get 1) (i32.const 2)) 617 if 618 (local.set 0 (call $makeNonNull_Loose)) 619 else 620 (i32.eq (local.get 1) (i32.const 3)) 621 if 622 (local.set 0 (call $makeNonNull_Precise)) 623 else 624 return 625 end 626 end 627 end 628 end 629 630 (call $testNull_ref.is_null (local.get 0)) 631 (call $testNull_ref.test (local.get 0)) 632 (call_indirect (type $f_anyref) (local.get 0) (i32.const 0)) 633 (call_indirect (type $f_anyref) (local.get 0) (i32.const 2)) 634 (ref.is_null (local.get 0)) 635 if 636 (call $mustNull_ref.is_null (ref.cast nullref (local.get 0))) 637 (call $mustNull_ref.test (ref.cast nullref (local.get 0))) 638 (call_indirect (type $f_nullref) (ref.cast nullref (local.get 0)) (i32.const 1)) 639 (call_indirect (type $f_nullref) (ref.cast nullref (local.get 0)) (i32.const 3)) 640 end 641 642 (local.set 1 (i32.add (local.get 1) (i32.const 1))) 643 br 0 644 end 645 end 646 ) 647 )`, { 648 "": { 649 "thing": "hello I am extern guy", 650 countNull() { 651 numNull += 1; 652 }, 653 countNonNull() { 654 numNonNull += 1; 655 }, 656 }, 657 }).exports; 658 659 for (let i = 0; i < 100; i++) { 660 test1(); 661 } 662 663 assertEq(numNull, 1600); 664 assertEq(numNonNull, 800); 665 666 for (let i = 0; i < 100; i++) { 667 test2(); 668 } 669 670 assertEq(numNull, 3200); 671 assertEq(numNonNull, 1600); 672 } 673 674 // globals 675 { 676 const counts = { 100: 0, 200: 0 }; 677 678 const { test1, test2 } = wasmEvalText(`(module 679 (type $f (func)) 680 681 (import "" "dummy" (func $dummy (param anyref))) 682 (import "" "count" (func $count (param i32))) 683 684 (global $a (mut (ref $f)) (ref.func $count100)) 685 (global $b (mut (ref $f)) (ref.func $count200)) 686 687 (func $count100 (type $f) 688 (call $count (i32.const 100)) 689 ) 690 (func $count200 (type $f) 691 (call $count (i32.const 200)) 692 ) 693 694 (func (export "test1") 695 global.get $a 696 call_ref $f 697 698 global.get $b 699 call_ref $f 700 ) 701 (func (export "test2") 702 (local funcref i32) 703 704 (local.set 0 (global.get $a)) 705 706 loop 707 local.get 0 708 ref.cast (ref $f) 709 call_ref $f 710 711 (i32.ge_s (local.get 1) (i32.const 4)) 712 if 713 (local.set 0 (global.get $b)) 714 end 715 716 (local.tee 1 (i32.add (local.get 1) (i32.const 1))) 717 (i32.lt_s (i32.const 10)) 718 br_if 0 719 end 720 ) 721 )`, { 722 "": { 723 dummy() {}, 724 count(n) { 725 counts[n] += 1; 726 }, 727 }, 728 }).exports; 729 730 for (let i = 0; i < 100; i++) { 731 test1(); 732 } 733 734 assertEq(counts[100], 100); 735 assertEq(counts[200], 100); 736 737 for (let i = 0; i < 100; i++) { 738 test2(); 739 } 740 741 assertEq(counts[100], 600); 742 assertEq(counts[200], 600); 743 } 744 745 // any.convert_extern and extern.convert_any 746 { 747 let numAnyref = 0; 748 let numExternref = 0; 749 750 const { test1, test2 } = wasmEvalText(`(module 751 (import "" "thing" (global $extern1 externref)) 752 (import "" "thing" (global $extern2 externref)) 753 (import "" "dummy1" (func $dummy1 (param anyref))) 754 (import "" "dummy2" (func $dummy2 (param externref))) 755 (import "" "countAnyref" (func $countAnyref)) 756 (import "" "countExternref" (func $countExternref)) 757 758 (global $any1 anyref (any.convert_extern (global.get $extern1))) 759 (global $any2 anyref (any.convert_extern (global.get $extern2))) 760 761 (func (export "test1") 762 (call $dummy1 (any.convert_extern (global.get $extern1))) 763 (call $dummy2 (extern.convert_any (global.get $any1))) 764 765 ;; These tests are trivial. 766 767 (ref.test anyref (any.convert_extern (global.get $extern1))) 768 if 769 call $countAnyref 770 end 771 772 (ref.test externref (extern.convert_any (global.get $any1))) 773 if 774 call $countExternref 775 end 776 ) 777 (func (export "test2") 778 (local i32 anyref externref) 779 780 (local.tee 1 (any.convert_extern (global.get $extern1))) 781 call $dummy1 782 (local.tee 2 (extern.convert_any (global.get $any1))) 783 call $dummy2 784 785 loop 786 ;; These tests are again trivial. 787 788 (ref.test anyref (local.get 1)) 789 if 790 call $countAnyref 791 end 792 793 (ref.test externref (local.get 2)) 794 if 795 call $countExternref 796 end 797 798 (i32.ge_s (local.get 0) (i32.const 5)) 799 if 800 ;; These are different values but have the same type. It will not 801 ;; affect the types that flow into the tests. 802 (local.set 1 (any.convert_extern (global.get $extern2))) 803 (local.set 2 (extern.convert_any (global.get $any2))) 804 end 805 806 (local.tee 0 (i32.add (local.get 0) (i32.const 1))) 807 (i32.lt_s (i32.const 10)) 808 br_if 0 809 end 810 ) 811 )`, { 812 "": { 813 "thing": "hello I am extern guy", 814 dummy1() {}, 815 dummy2() {}, 816 countAnyref() { 817 numAnyref += 1; 818 }, 819 countExternref() { 820 numExternref += 1; 821 }, 822 }, 823 }).exports; 824 825 for (let i = 0; i < 100; i++) { 826 test1(); 827 } 828 829 assertEq(numAnyref, 100); 830 assertEq(numExternref, 100); 831 832 for (let i = 0; i < 100; i++) { 833 test2(); 834 } 835 836 assertEq(numAnyref, 1100); 837 assertEq(numExternref, 1100); 838 }