1// Copyright 2018 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5// Test line comment 6/* Test mulitline 7 comment 8*/ 9/*multiline_without_whitespace*/ 10 11namespace test { 12macro ElementsKindTestHelper1(kind: constexpr ElementsKind): bool { 13 if constexpr ( 14 kind == ElementsKind::UINT8_ELEMENTS || 15 kind == ElementsKind::UINT16_ELEMENTS) { 16 return true; 17 } else { 18 return false; 19 } 20} 21 22macro ElementsKindTestHelper2(kind: constexpr ElementsKind): constexpr bool { 23 return kind == ElementsKind::UINT8_ELEMENTS || 24 kind == ElementsKind::UINT16_ELEMENTS; 25} 26 27macro LabelTestHelper1(): never 28 labels Label1 { 29 goto Label1; 30} 31 32macro LabelTestHelper2(): never 33 labels Label2(Smi) { 34 goto Label2(42); 35} 36 37macro LabelTestHelper3(): never 38 labels Label3(Oddball, Smi) { 39 goto Label3(Null, 7); 40} 41 42@export 43macro TestConstexpr1(): void { 44 check(FromConstexpr<bool>( 45 IsFastElementsKind(ElementsKind::PACKED_SMI_ELEMENTS))); 46} 47 48@export 49macro TestConstexprIf(): void { 50 check(ElementsKindTestHelper1(ElementsKind::UINT8_ELEMENTS)); 51 check(ElementsKindTestHelper1(ElementsKind::UINT16_ELEMENTS)); 52 check(!ElementsKindTestHelper1(ElementsKind::UINT32_ELEMENTS)); 53} 54 55@export 56macro TestConstexprReturn(): void { 57 check(FromConstexpr<bool>( 58 ElementsKindTestHelper2(ElementsKind::UINT8_ELEMENTS))); 59 check(FromConstexpr<bool>( 60 ElementsKindTestHelper2(ElementsKind::UINT16_ELEMENTS))); 61 check(!FromConstexpr<bool>( 62 ElementsKindTestHelper2(ElementsKind::UINT32_ELEMENTS))); 63 check(FromConstexpr<bool>( 64 !ElementsKindTestHelper2(ElementsKind::UINT32_ELEMENTS))); 65} 66 67@export 68macro TestGotoLabel(): Boolean { 69 try { 70 LabelTestHelper1() otherwise Label1; 71 } label Label1 { 72 return True; 73 } 74} 75 76@export 77macro TestGotoLabelWithOneParameter(): Boolean { 78 try { 79 LabelTestHelper2() otherwise Label2; 80 } label Label2(smi: Smi) { 81 check(smi == 42); 82 return True; 83 } 84} 85 86@export 87macro TestGotoLabelWithTwoParameters(): Boolean { 88 try { 89 LabelTestHelper3() otherwise Label3; 90 } label Label3(o: Oddball, smi: Smi) { 91 check(o == Null); 92 check(smi == 7); 93 return True; 94 } 95} 96 97builtin GenericBuiltinTest<T: type>(_param: T): JSAny { 98 return Null; 99} 100 101GenericBuiltinTest<JSAny>(param: JSAny): JSAny { 102 return param; 103} 104 105@export 106macro TestBuiltinSpecialization(): void { 107 check(GenericBuiltinTest<Smi>(0) == Null); 108 check(GenericBuiltinTest<Smi>(1) == Null); 109 check(GenericBuiltinTest<JSAny>(Undefined) == Undefined); 110 check(GenericBuiltinTest<JSAny>(Undefined) == Undefined); 111} 112 113macro LabelTestHelper4(flag: constexpr bool): never 114 labels Label4, Label5 { 115 if constexpr (flag) { 116 goto Label4; 117 } else { 118 goto Label5; 119 } 120} 121 122macro CallLabelTestHelper4(flag: constexpr bool): bool { 123 try { 124 LabelTestHelper4(flag) otherwise Label4, Label5; 125 } label Label4 { 126 return true; 127 } label Label5 { 128 return false; 129 } 130} 131 132@export 133macro TestPartiallyUnusedLabel(): Boolean { 134 const r1: bool = CallLabelTestHelper4(true); 135 const r2: bool = CallLabelTestHelper4(false); 136 137 if (r1 && !r2) { 138 return True; 139 } else { 140 return False; 141 } 142} 143 144macro GenericMacroTest<T: type>(_param: T): Object { 145 return Undefined; 146} 147 148GenericMacroTest<Object>(param2: Object): Object { 149 return param2; 150} 151 152macro GenericMacroTestWithLabels<T: type>(_param: T): Object 153labels _X { 154 return Undefined; 155} 156 157GenericMacroTestWithLabels<Object>(param2: Object): Object 158 labels Y { 159 return Cast<Smi>(param2) otherwise Y; 160} 161 162@export 163macro TestMacroSpecialization(): void { 164 try { 165 const _smi0: Smi = 0; 166 check(GenericMacroTest<Smi>(0) == Undefined); 167 check(GenericMacroTest<Smi>(1) == Undefined); 168 check(GenericMacroTest<Object>(Null) == Null); 169 check(GenericMacroTest<Object>(False) == False); 170 check(GenericMacroTest<Object>(True) == True); 171 check((GenericMacroTestWithLabels<Smi>(0) otherwise Fail) == Undefined); 172 check((GenericMacroTestWithLabels<Smi>(0) otherwise Fail) == Undefined); 173 try { 174 GenericMacroTestWithLabels<Object>(False) otherwise Expected; 175 } label Expected {} 176 } label Fail { 177 unreachable; 178 } 179} 180 181builtin TestHelperPlus1(x: Smi): Smi { 182 return x + 1; 183} 184builtin TestHelperPlus2(x: Smi): Smi { 185 return x + 2; 186} 187 188@export 189macro TestFunctionPointers(implicit context: Context)(): Boolean { 190 let fptr: builtin(Smi) => Smi = TestHelperPlus1; 191 check(fptr(42) == 43); 192 fptr = TestHelperPlus2; 193 check(fptr(42) == 44); 194 return True; 195} 196 197@export 198macro TestVariableRedeclaration(implicit context: Context)(): Boolean { 199 let _var1: int31 = FromConstexpr<bool>(42 == 0) ? FromConstexpr<int31>(0) : 1; 200 let _var2: int31 = FromConstexpr<bool>(42 == 0) ? FromConstexpr<int31>(1) : 0; 201 return True; 202} 203 204@export 205macro TestTernaryOperator(x: Smi): Smi { 206 const b: bool = x < 0 ? true : false; 207 return b ? x - 10 : x + 100; 208} 209 210@export 211macro TestFunctionPointerToGeneric(): void { 212 const fptr1: builtin(Smi) => JSAny = GenericBuiltinTest<Smi>; 213 const fptr2: builtin(JSAny) => JSAny = GenericBuiltinTest<JSAny>; 214 215 check(fptr1(0) == Null); 216 check(fptr1(1) == Null); 217 check(fptr2(Undefined) == Undefined); 218 check(fptr2(Undefined) == Undefined); 219} 220 221type ObjectToObject = builtin(Context, JSAny) => JSAny; 222@export 223macro TestTypeAlias(x: ObjectToObject): BuiltinPtr { 224 return x; 225} 226 227@export 228macro TestUnsafeCast(implicit context: Context)(n: Number): Boolean { 229 if (TaggedIsSmi(n)) { 230 const m: Smi = UnsafeCast<Smi>(n); 231 232 check(TestHelperPlus1(m) == 11); 233 return True; 234 } 235 return False; 236} 237 238@export 239macro TestHexLiteral(): void { 240 check(Convert<intptr>(0xffff) + 1 == 0x10000); 241 check(Convert<intptr>(-0xffff) == -65535); 242} 243 244@export 245macro TestLargeIntegerLiterals(implicit c: Context)(): void { 246 let _x: int32 = 0x40000000; 247 let _y: int32 = 0x7fffffff; 248} 249 250@export 251macro TestMultilineAssert(): void { 252 const someVeryLongVariableNameThatWillCauseLineBreaks: Smi = 5; 253 check( 254 someVeryLongVariableNameThatWillCauseLineBreaks > 0 && 255 someVeryLongVariableNameThatWillCauseLineBreaks < 10); 256} 257 258@export 259macro TestNewlineInString(): void { 260 Print('Hello, World!\n'); 261} 262 263const kConstexprConst: constexpr int31 = 5; 264const kIntptrConst: intptr = 4; 265const kSmiConst: Smi = 3; 266 267@export 268macro TestModuleConstBindings(): void { 269 check(kConstexprConst == Int32Constant(5)); 270 check(kIntptrConst == 4); 271 check(kSmiConst == 3); 272} 273 274@export 275macro TestLocalConstBindings(): void { 276 const x: constexpr int31 = 3; 277 const xSmi: Smi = x; 278 { 279 const x: Smi = x + FromConstexpr<Smi>(1); 280 check(x == xSmi + 1); 281 const xSmi: Smi = x; 282 check(x == xSmi); 283 check(x == 4); 284 } 285 check(xSmi == 3); 286 check(x == xSmi); 287} 288 289struct TestStructA { 290 indexes: FixedArray; 291 i: Smi; 292 k: Number; 293} 294 295struct TestStructB { 296 x: TestStructA; 297 y: Smi; 298} 299 300@export 301macro TestStruct1(i: TestStructA): Smi { 302 return i.i; 303} 304 305@export 306macro TestStruct2(implicit context: Context)(): TestStructA { 307 return TestStructA{ 308 indexes: UnsafeCast<FixedArray>(kEmptyFixedArray), 309 i: 27, 310 k: 31 311 }; 312} 313 314@export 315macro TestStruct3(implicit context: Context)(): TestStructA { 316 let a: TestStructA = 317 TestStructA{indexes: UnsafeCast<FixedArray>(kEmptyFixedArray), i: 13, k: 5}; 318 let _b: TestStructA = a; 319 const c: TestStructA = TestStruct2(); 320 a.i = TestStruct1(c); 321 a.k = a.i; 322 let d: TestStructB; 323 d.x = a; 324 d = TestStructB{x: a, y: 7}; 325 let _e: TestStructA = d.x; 326 let f: Smi = TestStructA{ 327 indexes: UnsafeCast<FixedArray>(kEmptyFixedArray), 328 i: 27, 329 k: 31 330 }.i; 331 f = TestStruct2().i; 332 return a; 333} 334 335struct TestStructC { 336 x: TestStructA; 337 y: TestStructA; 338} 339 340@export 341macro TestStruct4(implicit context: Context)(): TestStructC { 342 return TestStructC{x: TestStruct2(), y: TestStruct2()}; 343} 344 345macro TestStructInLabel(implicit context: Context)(): never labels 346Foo(TestStructA) { 347 goto Foo(TestStruct2()); 348} 349@export // Silence unused warning. 350macro CallTestStructInLabel(implicit context: Context)(): void { 351 try { 352 TestStructInLabel() otherwise Foo; 353 } label Foo(_s: TestStructA) {} 354} 355 356// This macro tests different versions of the for-loop where some parts 357// are (not) present. 358@export 359macro TestForLoop(): void { 360 let sum: Smi = 0; 361 for (let i: Smi = 0; i < 5; ++i) sum += i; 362 check(sum == 10); 363 364 sum = 0; 365 let j: Smi = 0; 366 for (; j < 5; ++j) sum += j; 367 check(sum == 10); 368 369 sum = 0; 370 j = 0; 371 for (; j < 5;) sum += j++; 372 check(sum == 10); 373 374 // Check that break works. No test expression. 375 sum = 0; 376 for (let i: Smi = 0;; ++i) { 377 if (i == 5) break; 378 sum += i; 379 } 380 check(sum == 10); 381 382 sum = 0; 383 j = 0; 384 for (;;) { 385 if (j == 5) break; 386 sum += j; 387 j++; 388 } 389 check(sum == 10); 390 391 // The following tests are the same as above, but use continue to skip 392 // index 3. 393 sum = 0; 394 for (let i: Smi = 0; i < 5; ++i) { 395 if (i == 3) continue; 396 sum += i; 397 } 398 check(sum == 7); 399 400 sum = 0; 401 j = 0; 402 for (; j < 5; ++j) { 403 if (j == 3) continue; 404 sum += j; 405 } 406 check(sum == 7); 407 408 sum = 0; 409 j = 0; 410 for (; j < 5;) { 411 if (j == 3) { 412 j++; 413 continue; 414 } 415 sum += j; 416 j++; 417 } 418 check(sum == 7); 419 420 sum = 0; 421 for (let i: Smi = 0;; ++i) { 422 if (i == 3) continue; 423 if (i == 5) break; 424 sum += i; 425 } 426 check(sum == 7); 427 428 sum = 0; 429 j = 0; 430 for (;;) { 431 if (j == 3) { 432 j++; 433 continue; 434 } 435 436 if (j == 5) break; 437 sum += j; 438 j++; 439 } 440 check(sum == 7); 441 442 j = 0; 443 try { 444 for (;;) { 445 if (++j == 10) goto Exit; 446 } 447 } label Exit { 448 check(j == 10); 449 } 450 451 // Test if we can handle uninitialized values on the stack. 452 let _i: Smi; 453 for (let j: Smi = 0; j < 10; ++j) { 454 } 455} 456 457@export 458macro TestSubtyping(x: Smi): void { 459 const _foo: JSAny = x; 460} 461 462macro IncrementIfSmi<A: type>(x: A): A { 463 typeswitch (x) { 464 case (x: Smi): { 465 return x + 1; 466 } 467 case (o: A): { 468 return o; 469 } 470 } 471} 472 473type NumberOrFixedArray = Number|FixedArray; 474macro TypeswitchExample(implicit context: Context)(x: NumberOrFixedArray): 475 int32 { 476 let result: int32 = 0; 477 typeswitch (IncrementIfSmi(x)) { 478 case (_x: FixedArray): { 479 result = result + 1; 480 } 481 case (Number): { 482 result = result + 2; 483 } 484 } 485 486 result = result * 10; 487 488 typeswitch (IncrementIfSmi(x)) { 489 case (x: Smi): { 490 result = result + Convert<int32>(x); 491 } 492 case (a: FixedArray): { 493 result = result + Convert<int32>(a.length); 494 } 495 case (_x: HeapNumber): { 496 result = result + 7; 497 } 498 } 499 500 return result; 501} 502 503@export 504macro TestTypeswitch(implicit context: Context)(): void { 505 check(TypeswitchExample(FromConstexpr<Smi>(5)) == 26); 506 const a: FixedArray = AllocateZeroedFixedArray(3); 507 check(TypeswitchExample(a) == 13); 508 check(TypeswitchExample(FromConstexpr<Number>(0.5)) == 27); 509} 510 511@export 512macro TestTypeswitchAsanLsanFailure(implicit context: Context)(obj: Object): 513 void { 514 typeswitch (obj) { 515 case (_o: Smi): { 516 } 517 case (_o: JSTypedArray): { 518 } 519 case (_o: JSReceiver): { 520 } 521 case (_o: HeapObject): { 522 } 523 } 524} 525 526macro ExampleGenericOverload<A: type>(o: Object): A { 527 return o; 528} 529macro ExampleGenericOverload<A: type>(o: Smi): A { 530 return o + 1; 531} 532 533@export 534macro TestGenericOverload(implicit context: Context)(): void { 535 const xSmi: Smi = 5; 536 const xObject: Object = xSmi; 537 check(ExampleGenericOverload<Smi>(xSmi) == 6); 538 check(UnsafeCast<Smi>(ExampleGenericOverload<Object>(xObject)) == 5); 539} 540 541@export 542macro TestEquality(implicit context: Context)(): void { 543 const notEqual: bool = 544 AllocateHeapNumberWithValue(0.5) != AllocateHeapNumberWithValue(0.5); 545 check(!notEqual); 546 const equal: bool = 547 AllocateHeapNumberWithValue(0.5) == AllocateHeapNumberWithValue(0.5); 548 check(equal); 549} 550 551@export 552macro TestOrAnd(x: bool, y: bool, z: bool): bool { 553 return x || y && z ? true : false; 554} 555 556@export 557macro TestAndOr(x: bool, y: bool, z: bool): bool { 558 return x && y || z ? true : false; 559} 560 561@export 562macro TestLogicalOperators(): void { 563 check(TestAndOr(true, true, true)); 564 check(TestAndOr(true, true, false)); 565 check(TestAndOr(true, false, true)); 566 check(!TestAndOr(true, false, false)); 567 check(TestAndOr(false, true, true)); 568 check(!TestAndOr(false, true, false)); 569 check(TestAndOr(false, false, true)); 570 check(!TestAndOr(false, false, false)); 571 check(TestOrAnd(true, true, true)); 572 check(TestOrAnd(true, true, false)); 573 check(TestOrAnd(true, false, true)); 574 check(TestOrAnd(true, false, false)); 575 check(TestOrAnd(false, true, true)); 576 check(!TestOrAnd(false, true, false)); 577 check(!TestOrAnd(false, false, true)); 578 check(!TestOrAnd(false, false, false)); 579} 580 581@export 582macro TestCall(i: Smi): Smi labels A { 583 if (i < 5) return i; 584 goto A; 585} 586 587@export 588macro TestOtherwiseWithCode1(): void { 589 let v: Smi = 0; 590 let s: Smi = 1; 591 try { 592 TestCall(10) otherwise goto B(++s); 593 } label B(v1: Smi) { 594 v = v1; 595 } 596 dcheck(v == 2); 597} 598 599@export 600macro TestOtherwiseWithCode2(): void { 601 let s: Smi = 0; 602 for (let i: Smi = 0; i < 10; ++i) { 603 TestCall(i) otherwise break; 604 ++s; 605 } 606 dcheck(s == 5); 607} 608 609@export 610macro TestOtherwiseWithCode3(): void { 611 let s: Smi = 0; 612 for (let i: Smi = 0; i < 10; ++i) { 613 s += TestCall(i) otherwise break; 614 } 615 dcheck(s == 10); 616} 617 618@export 619macro TestForwardLabel(): void { 620 try { 621 goto A; 622 } label A { 623 goto B(5); 624 } label B(b: Smi) { 625 dcheck(b == 5); 626 } 627} 628 629@export 630macro TestQualifiedAccess(implicit context: Context)(): void { 631 const s: Smi = 0; 632 check(!Is<JSArray>(s)); 633} 634 635@export 636macro TestCatch1(implicit context: Context)(): Smi { 637 let r: Smi = 0; 638 try { 639 ThrowTypeError(MessageTemplate::kInvalidArrayLength); 640 } catch (_e, _message) { 641 r = 1; 642 return r; 643 } 644} 645 646@export 647macro TestCatch2Wrapper(implicit context: Context)(): never { 648 ThrowTypeError(MessageTemplate::kInvalidArrayLength); 649} 650 651@export 652macro TestCatch2(implicit context: Context)(): Smi { 653 let r: Smi = 0; 654 try { 655 TestCatch2Wrapper(); 656 } catch (_e, _message) { 657 r = 2; 658 return r; 659 } 660} 661 662@export 663macro TestCatch3WrapperWithLabel(implicit context: Context)(): 664 never labels _Abort { 665 ThrowTypeError(MessageTemplate::kInvalidArrayLength); 666} 667 668@export 669macro TestCatch3(implicit context: Context)(): Smi { 670 let r: Smi = 0; 671 try { 672 TestCatch3WrapperWithLabel() otherwise Abort; 673 } catch (_e, _message) { 674 r = 2; 675 return r; 676 } label Abort { 677 return -1; 678 } 679} 680 681// This test doesn't actually test the functionality of iterators, 682// it's only purpose is to make sure tha the CSA macros in the 683// IteratorBuiltinsAssembler match the signatures provided in 684// iterator.tq. 685@export 686transitioning macro TestIterator(implicit context: Context)( 687 o: JSReceiver, map: Map): void { 688 try { 689 const t1: JSAny = iterator::GetIteratorMethod(o); 690 const t2: iterator::IteratorRecord = iterator::GetIterator(o); 691 692 const _t3: JSAny = iterator::IteratorStep(t2) otherwise Fail; 693 const _t4: JSAny = iterator::IteratorStep(t2, map) otherwise Fail; 694 695 const _t5: JSAny = iterator::IteratorValue(o); 696 const _t6: JSAny = iterator::IteratorValue(o, map); 697 698 const _t7: JSArray = iterator::IterableToList(t1, t1); 699 700 iterator::IteratorCloseOnException(t2); 701 } label Fail {} 702} 703 704@export 705macro TestFrame1(implicit context: Context)(): void { 706 const f: Frame = LoadFramePointer(); 707 const frameType: FrameType = 708 Cast<FrameType>(f.context_or_frame_type) otherwise unreachable; 709 dcheck(frameType == STUB_FRAME); 710 dcheck(f.caller == LoadParentFramePointer()); 711 typeswitch (f) { 712 case (_f: StandardFrame): { 713 unreachable; 714 } 715 case (_f: StubFrame): { 716 } 717 } 718} 719 720@export 721macro TestNew(implicit context: Context)(): void { 722 const f: JSArray = NewJSArray(); 723 check(f.IsEmpty()); 724 f.length = 0; 725} 726 727struct TestInner { 728 macro SetX(newValue: int32): void { 729 this.x = newValue; 730 } 731 macro GetX(): int32 { 732 return this.x; 733 } 734 x: int32; 735 y: int32; 736} 737 738struct TestOuter { 739 a: int32; 740 b: TestInner; 741 c: int32; 742} 743 744@export 745macro TestStructConstructor(implicit context: Context)(): void { 746 // Test default constructor 747 let a: TestOuter = TestOuter{a: 5, b: TestInner{x: 6, y: 7}, c: 8}; 748 check(a.a == 5); 749 check(a.b.x == 6); 750 check(a.b.y == 7); 751 check(a.c == 8); 752 a.b.x = 1; 753 check(a.b.x == 1); 754 a.b.SetX(2); 755 check(a.b.x == 2); 756 check(a.b.GetX() == 2); 757} 758 759class InternalClass extends HeapObject { 760 macro Flip(): void labels NotASmi { 761 const tmp = Cast<Smi>(this.b) otherwise NotASmi; 762 this.b = this.a; 763 this.a = tmp; 764 } 765 a: Smi; 766 b: Number; 767} 768 769macro NewInternalClass(x: Smi): InternalClass { 770 return new InternalClass{a: x, b: x + 1}; 771} 772 773@export 774macro TestInternalClass(implicit context: Context)(): void { 775 const o = NewInternalClass(5); 776 o.Flip() otherwise unreachable; 777 check(o.a == 6); 778 check(o.b == 5); 779} 780 781struct StructWithConst { 782 macro TestMethod1(): int32 { 783 return this.b; 784 } 785 macro TestMethod2(): Object { 786 return this.a; 787 } 788 a: Object; 789 const b: int32; 790} 791 792@export 793macro TestConstInStructs(): void { 794 const x = StructWithConst{a: Null, b: 1}; 795 let y = StructWithConst{a: Null, b: 1}; 796 y.a = Undefined; 797 const _copy = x; 798 799 check(x.TestMethod1() == 1); 800 check(x.TestMethod2() == Null); 801} 802 803@export 804macro TestParentFrameArguments(implicit context: Context)(): void { 805 const parentFrame = LoadParentFramePointer(); 806 const castFrame = Cast<StandardFrame>(parentFrame) otherwise unreachable; 807 const arguments = GetFrameArguments(castFrame, 1); 808 ArgumentsIterator{arguments, current: 0}; 809} 810 811struct TestIterator { 812 macro Next(): Object labels NoMore { 813 if (this.count-- == 0) goto NoMore; 814 return TheHole; 815 } 816 count: Smi; 817} 818 819@export 820macro TestNewFixedArrayFromSpread(implicit context: Context)(): Object { 821 let i = TestIterator{count: 5}; 822 return new FixedArray{map: kFixedArrayMap, length: 5, objects: ...i}; 823} 824 825class SmiPair extends HeapObject { 826 macro GetA():&Smi { 827 return &this.a; 828 } 829 a: Smi; 830 b: Smi; 831} 832 833macro Swap<T: type>(a:&T, b:&T): void { 834 const tmp = *a; 835 *a = *b; 836 *b = tmp; 837} 838 839@export 840macro TestReferences(): void { 841 const array = new SmiPair{a: 7, b: 2}; 842 const ref:&Smi = &array.a; 843 *ref = 3 + *ref; 844 -- *ref; 845 Swap(&array.b, array.GetA()); 846 check(array.a == 2); 847 check(array.b == 9); 848} 849 850@export 851macro TestSlices(): void { 852 const it = TestIterator{count: 3}; 853 const a = new FixedArray{map: kFixedArrayMap, length: 3, objects: ...it}; 854 check(a.length == 3); 855 856 const oneTwoThree = Convert<Smi>(123); 857 a.objects[0] = oneTwoThree; 858 const firstRef:&Object = &a.objects[0]; 859 check(TaggedEqual(*firstRef, oneTwoThree)); 860 861 const slice: MutableSlice<Object> = &a.objects; 862 const firstRefAgain:&Object = slice.TryAtIndex(0) otherwise unreachable; 863 check(TaggedEqual(*firstRefAgain, oneTwoThree)); 864 865 const threeTwoOne = Convert<Smi>(321); 866 *firstRefAgain = threeTwoOne; 867 check(TaggedEqual(a.objects[0], threeTwoOne)); 868 869 // *slice; // error, not allowed 870 // a.objects; // error, not allowed 871 // a.objects = slice; // error, not allowed 872 873 // TODO(gsps): Currently errors, but should be allowed: 874 // const _sameSlice: MutableSlice<Object> = &(*slice); 875 // (*slice)[0] : Smi 876} 877 878@export 879macro TestSliceEnumeration(implicit context: Context)(): Undefined { 880 const fixedArray: FixedArray = AllocateZeroedFixedArray(3); 881 for (let i: intptr = 0; i < 3; i++) { 882 check(UnsafeCast<Smi>(fixedArray.objects[i]) == 0); 883 fixedArray.objects[i] = Convert<Smi>(i) + 3; 884 } 885 886 let slice = &fixedArray.objects; 887 for (let i: intptr = 0; i < slice.length; i++) { 888 let ref = slice.TryAtIndex(i) otherwise unreachable; 889 const value = UnsafeCast<Smi>(*ref); 890 check(value == Convert<Smi>(i) + 3); 891 *ref = value + 4; 892 } 893 894 let it = slice.Iterator(); 895 let count: Smi = 0; 896 while (true) { 897 const value = UnsafeCast<Smi>(it.Next() otherwise break); 898 check(value == count + 7); 899 count++; 900 } 901 check(count == 3); 902 check(it.Empty()); 903 904 return Undefined; 905} 906 907@export 908macro TestStaticAssert(): void { 909 static_assert(1 + 2 == 3); 910 911 static_assert(Convert<uintptr>(5) < Convert<uintptr>(6)); 912 static_assert(!(Convert<uintptr>(5) < Convert<uintptr>(5))); 913 static_assert(!(Convert<uintptr>(6) < Convert<uintptr>(5))); 914 static_assert(Convert<uintptr>(5) <= Convert<uintptr>(5)); 915 static_assert(Convert<uintptr>(5) <= Convert<uintptr>(6)); 916 static_assert(!(Convert<uintptr>(6) <= Convert<uintptr>(5))); 917 918 static_assert(Convert<intptr>(-6) < Convert<intptr>(-5)); 919 static_assert(!(Convert<intptr>(-5) < Convert<intptr>(-5))); 920 static_assert(!(Convert<intptr>(-5) < Convert<intptr>(-6))); 921 static_assert(Convert<intptr>(-5) <= Convert<intptr>(-5)); 922 static_assert(Convert<intptr>(-6) <= Convert<intptr>(-5)); 923 static_assert(!(Convert<intptr>(-5) <= Convert<intptr>(-6))); 924} 925 926class SmiBox extends HeapObject { 927 value: Smi; 928 unrelated: Smi; 929} 930 931builtin NewSmiBox(implicit context: Context)(value: Smi): SmiBox { 932 return new SmiBox{value, unrelated: 0}; 933} 934 935@export 936macro TestLoadEliminationFixed(implicit context: Context)(): void { 937 const box = NewSmiBox(123); 938 const v1 = box.value; 939 box.unrelated = 999; 940 const v2 = (box.unrelated == 0) ? box.value : box.value; 941 static_assert(TaggedEqual(v1, v2)); 942 943 box.value = 11; 944 const v3 = box.value; 945 const eleven: Smi = 11; 946 static_assert(TaggedEqual(v3, eleven)); 947} 948 949@export 950macro TestLoadEliminationVariable(implicit context: Context)(): void { 951 const a = UnsafeCast<FixedArray>(kEmptyFixedArray); 952 const box = NewSmiBox(1); 953 const v1 = a.objects[box.value]; 954 const u1 = a.objects[box.value + 2]; 955 const v2 = a.objects[box.value]; 956 const u2 = a.objects[box.value + 2]; 957 static_assert(TaggedEqual(v1, v2)); 958 static_assert(TaggedEqual(u1, u2)); 959} 960 961@export 962macro TestRedundantArrayElementCheck(implicit context: Context)(): Smi { 963 const a = kEmptyFixedArray; 964 for (let i: Smi = 0; i < a.length; i++) { 965 if (a.objects[i] == TheHole) { 966 if (a.objects[i] == TheHole) { 967 return -1; 968 } else { 969 static_assert(false); 970 } 971 } 972 } 973 return 1; 974} 975 976@export 977macro TestRedundantSmiCheck(implicit context: Context)(): Smi { 978 const a = kEmptyFixedArray; 979 const x = a.objects[1]; 980 typeswitch (x) { 981 case (Smi): { 982 Cast<Smi>(x) otherwise VerifiedUnreachable(); 983 return -1; 984 } 985 case (Object): { 986 } 987 } 988 return 1; 989} 990 991struct SBox<T: type> { 992 value: T; 993} 994 995@export 996macro TestGenericStruct1(): intptr { 997 const i: intptr = 123; 998 let box = SBox{value: i}; 999 let boxbox: SBox<SBox<intptr>> = SBox{value: box}; 1000 check(box.value == 123); 1001 boxbox.value.value *= 2; 1002 check(boxbox.value.value == 246); 1003 return boxbox.value.value; 1004} 1005 1006struct TestTuple<T1: type, T2: type> { 1007 const fst: T1; 1008 const snd: T2; 1009} 1010 1011macro TupleSwap<T1: type, T2: type>(tuple: TestTuple<T1, T2>): 1012 TestTuple<T2, T1> { 1013 return TestTuple{fst: tuple.snd, snd: tuple.fst}; 1014} 1015 1016@export 1017macro TestGenericStruct2(): 1018 TestTuple<TestTuple<intptr, Smi>, TestTuple<Smi, intptr>> { 1019 const intptrAndSmi = TestTuple<intptr, Smi>{fst: 1, snd: 2}; 1020 const smiAndIntptr = TupleSwap(intptrAndSmi); 1021 check(intptrAndSmi.fst == smiAndIntptr.snd); 1022 check(intptrAndSmi.snd == smiAndIntptr.fst); 1023 const tupleTuple = 1024 TestTuple<TestTuple<intptr, Smi>>{fst: intptrAndSmi, snd: smiAndIntptr}; 1025 return tupleTuple; 1026} 1027 1028macro BranchAndWriteResult(x: Smi, box: SmiBox): bool { 1029 if (x > 5 || x < 0) { 1030 box.value = 1; 1031 return true; 1032 } else { 1033 box.value = 2; 1034 return false; 1035 } 1036} 1037 1038@export 1039macro TestBranchOnBoolOptimization(implicit context: Context)(input: Smi): 1040 void { 1041 const box = NewSmiBox(1); 1042 // If the two branches get combined into one, we should be able to determine 1043 // the value of {box} statically. 1044 if (BranchAndWriteResult(input, box)) { 1045 static_assert(box.value == 1); 1046 } else { 1047 static_assert(box.value == 2); 1048 } 1049} 1050 1051bitfield struct TestBitFieldStruct extends uint8 { 1052 a: bool: 1 bit; 1053 b: uint16: 3 bit; 1054 c: uint32: 3 bit; 1055 d: bool: 1 bit; 1056} 1057 1058@export 1059macro TestBitFieldLoad( 1060 val: TestBitFieldStruct, expectedA: bool, expectedB: uint16, 1061 expectedC: uint32, expectedD: bool): void { 1062 check(val.a == expectedA); 1063 check(val.b == expectedB); 1064 check(val.c == expectedC); 1065 check(val.d == expectedD); 1066} 1067 1068@export 1069macro TestBitFieldStore(val: TestBitFieldStruct): void { 1070 let val: TestBitFieldStruct = val; // Get a mutable local copy. 1071 const a: bool = val.a; 1072 const b: uint16 = val.b; 1073 let c: uint32 = val.c; 1074 const d: bool = val.d; 1075 1076 val.a = !a; 1077 TestBitFieldLoad(val, !a, b, c, d); 1078 1079 c = Unsigned(7 - Signed(val.c)); 1080 val.c = c; 1081 TestBitFieldLoad(val, !a, b, c, d); 1082 1083 val.d = val.b == val.c; 1084 TestBitFieldLoad(val, !a, b, c, b == c); 1085} 1086 1087@export 1088macro TestBitFieldInit(a: bool, b: uint16, c: uint32, d: bool): void { 1089 const val: TestBitFieldStruct = TestBitFieldStruct{a: a, b: b, c: c, d: d}; 1090 TestBitFieldLoad(val, a, b, c, d); 1091} 1092 1093// Some other bitfield structs, to verify getting uintptr values out of word32 1094// structs and vice versa. 1095bitfield struct TestBitFieldStruct2 extends uint32 { 1096 a: uintptr: 5 bit; 1097 b: uintptr: 6 bit; 1098} 1099bitfield struct TestBitFieldStruct3 extends uintptr { 1100 c: bool: 1 bit; 1101 d: uint32: 9 bit; 1102 e: uintptr: 17 bit; 1103} 1104 1105@export 1106macro TestBitFieldUintptrOps( 1107 val2: TestBitFieldStruct2, val3: TestBitFieldStruct3): void { 1108 let val2: TestBitFieldStruct2 = val2; // Get a mutable local copy. 1109 let val3: TestBitFieldStruct3 = val3; // Get a mutable local copy. 1110 1111 // Caller is expected to provide these exact values, so we can verify 1112 // reading values before starting to write anything. 1113 check(val2.a == 3); 1114 check(val2.b == 61); 1115 check(val3.c); 1116 check(val3.d == 500); 1117 check(val3.e == 0x1cc); 1118 1119 val2.b = 16; 1120 check(val2.a == 3); 1121 check(val2.b == 16); 1122 1123 val2.b++; 1124 check(val2.a == 3); 1125 check(val2.b == 17); 1126 1127 val3.d = 99; 1128 val3.e = 1234; 1129 check(val3.c); 1130 check(val3.d == 99); 1131 check(val3.e == 1234); 1132} 1133 1134bitfield struct TestBitFieldStruct4 extends uint31 { 1135 a: bool: 1 bit; 1136 b: int32: 3 bit; 1137 c: bool: 1 bit; 1138} 1139 1140bitfield struct TestBitFieldStruct5 extends uint31 { 1141 b: int32: 19 bit; 1142 a: bool: 1 bit; 1143 c: bool: 1 bit; 1144} 1145 1146@export 1147macro TestBitFieldMultipleFlags(a: bool, b: int32, c: bool): void { 1148 const f = TestBitFieldStruct4{a: a, b: b, c: c}; 1149 let simpleExpression = f.a & f.b == 3 & !f.c; 1150 let expectedReduction = (Signed(f) & 0x1f) == Convert<int32>(1 | 3 << 1); 1151 static_assert(simpleExpression == expectedReduction); 1152 simpleExpression = !f.a & f.b == 4 & f.c; 1153 expectedReduction = (Signed(f) & 0x1f) == Convert<int32>(4 << 1 | 1 << 4); 1154 static_assert(simpleExpression == expectedReduction); 1155 simpleExpression = f.b == 0 & f.c; 1156 expectedReduction = (Signed(f) & 0x1e) == Convert<int32>(1 << 4); 1157 static_assert(simpleExpression == expectedReduction); 1158 simpleExpression = f.a & f.c; 1159 expectedReduction = (Signed(f) & 0x11) == Convert<int32>(1 | 1 << 4); 1160 static_assert(simpleExpression == expectedReduction); 1161 const f2 = TestBitFieldStruct5{b: b, a: a, c: c}; 1162 simpleExpression = !f2.a & f2.b == 1234 & f2.c; 1163 expectedReduction = (Signed(f2) & 0x1fffff) == Convert<int32>(1234 | 1 << 20); 1164 static_assert(simpleExpression == expectedReduction); 1165 simpleExpression = !f2.a & !f2.c; 1166 expectedReduction = (Signed(f2) & 0x180000) == Convert<int32>(0); 1167 static_assert(simpleExpression == expectedReduction); 1168} 1169 1170@export 1171class ExportedSubClass extends ExportedSubClassBase { 1172 c_field: int32; 1173 d_field: int32; 1174 e_field: Smi; 1175} 1176 1177@export 1178class ExportedSubClassBase extends HeapObject { 1179 a: HeapObject; 1180 b: HeapObject; 1181} 1182 1183@abstract 1184class AbstractInternalClass extends HeapObject { 1185} 1186 1187class AbstractInternalClassSubclass1 extends AbstractInternalClass {} 1188 1189class AbstractInternalClassSubclass2 extends AbstractInternalClass {} 1190 1191class InternalClassWithSmiElements extends FixedArrayBase { 1192 data: Smi; 1193 object: Oddball; 1194 entries[length]: Smi; 1195} 1196 1197struct InternalClassStructElement { 1198 a: Smi; 1199 b: Smi; 1200} 1201 1202class InternalClassWithStructElements extends HeapObject { 1203 dummy1: int32; 1204 dummy2: int32; 1205 const count: Smi; 1206 data: Smi; 1207 object: Object; 1208 entries[count]: Smi; 1209 more_entries[count]: InternalClassStructElement; 1210} 1211 1212struct SmiGeneratorIterator { 1213 macro Next(): Smi labels _NoMore { 1214 return this.value++; 1215 } 1216 value: Smi; 1217} 1218 1219struct InternalClassStructElementGeneratorIterator { 1220 macro Next(): InternalClassStructElement labels _NoMore { 1221 return InternalClassStructElement{a: this.value++, b: this.value++}; 1222 } 1223 value: Smi; 1224} 1225 1226@export 1227macro TestFullyGeneratedClassWithElements(): void { 1228 // Test creation, initialization and access of a fully generated class with 1229 // simple (Smi) elements 1230 const length: Smi = Convert<Smi>(3); 1231 const object1 = new InternalClassWithSmiElements{ 1232 length, 1233 data: 0, 1234 object: Undefined, 1235 entries: ...SmiGeneratorIterator { 1236 value: 11 1237 } 1238 }; 1239 dcheck(object1.length == 3); 1240 dcheck(object1.data == 0); 1241 dcheck(object1.object == Undefined); 1242 dcheck(object1.entries[0] == 11); 1243 dcheck(object1.entries[1] == 12); 1244 dcheck(object1.entries[2] == 13); 1245 1246 // Test creation, initialization and access of a fully generated class 1247 // with elements that are a struct. 1248 const object2 = new InternalClassWithStructElements{ 1249 dummy1: 44, 1250 dummy2: 45, 1251 count: length, 1252 data: 55, 1253 object: Undefined, 1254 entries: ...SmiGeneratorIterator{value: 3}, 1255 more_entries: ...InternalClassStructElementGeneratorIterator { 1256 value: 1 1257 } 1258 }; 1259 1260 dcheck(object2.dummy1 == 44); 1261 dcheck(object2.dummy2 == 45); 1262 dcheck(object2.count == 3); 1263 dcheck(object2.data == 55); 1264 dcheck(object2.object == Undefined); 1265 dcheck(object2.entries[0] == 3); 1266 dcheck(object2.entries[1] == 4); 1267 dcheck(object2.entries[2] == 5); 1268 dcheck(object2.more_entries[0].a == 1); 1269 dcheck(object2.more_entries[0].b == 2); 1270 dcheck(object2.more_entries[1].a == 3); 1271 dcheck(object2.more_entries[1].b == 4); 1272 dcheck(object2.more_entries[2].a == 5); 1273 dcheck(object2.more_entries[2].b == 6); 1274} 1275 1276@export 1277macro TestFullyGeneratedClassFromCpp(): ExportedSubClass { 1278 return new 1279 ExportedSubClass{a: Null, b: Null, c_field: 7, d_field: 8, e_field: 9}; 1280} 1281 1282@export 1283class ExportedSubClass2 extends ExportedSubClassBase { 1284 x_field: int32; 1285 y_field: int32; 1286 z_field: Smi; 1287} 1288 1289@export 1290macro TestGeneratedCastOperators(implicit context: Context)(): void { 1291 const a = new 1292 ExportedSubClass{a: Null, b: Null, c_field: 3, d_field: 4, e_field: 5}; 1293 const b = new ExportedSubClassBase{a: Undefined, b: Null}; 1294 const c = new 1295 ExportedSubClass2{a: Null, b: Null, x_field: 3, y_field: 4, z_field: 5}; 1296 const aO: Object = a; 1297 const bO: Object = b; 1298 const cO: Object = c; 1299 dcheck(Is<ExportedSubClassBase>(aO)); 1300 dcheck(Is<ExportedSubClass>(aO)); 1301 dcheck(!Is<ExportedSubClass2>(aO)); 1302 dcheck(Is<ExportedSubClassBase>(bO)); 1303 dcheck(!Is<ExportedSubClass>(bO)); 1304 dcheck(Is<ExportedSubClassBase>(cO)); 1305 dcheck(!Is<ExportedSubClass>(cO)); 1306 dcheck(Is<ExportedSubClass2>(cO)); 1307 1308 const jsf: JSFunction = 1309 *NativeContextSlot(ContextSlot::REGEXP_FUNCTION_INDEX); 1310 dcheck(!Is<JSSloppyArgumentsObject>(jsf)); 1311 1312 const parameterValues = NewFixedArray(0, ConstantIterator(TheHole)); 1313 const elements = NewSloppyArgumentsElements( 1314 0, context, parameterValues, ConstantIterator(TheHole)); 1315 const fastArgs = arguments::NewJSFastAliasedArgumentsObject( 1316 elements, Convert<Smi>(0), jsf); 1317 dcheck(Is<JSArgumentsObject>(fastArgs)); 1318} 1319 1320extern runtime InYoungGeneration(implicit context: Context)(HeapObject): 1321 Boolean; 1322 1323@export 1324macro TestNewPretenured(implicit context: Context)(): void { 1325 const obj = new (Pretenured) ExportedSubClassBase{a: Undefined, b: Null}; 1326 dcheck(Is<ExportedSubClassBase>(obj)); 1327 dcheck(InYoungGeneration(obj) == False); 1328} 1329 1330@export 1331macro TestWord8Phi(): void { 1332 for (let i: intptr = -5; i < 5; ++i) { 1333 let x: int8; 1334 if (i == -1) { 1335 x = -1; 1336 } else { 1337 x = Convert<int8>(i); 1338 } 1339 check(x == Convert<int8>(i)); 1340 } 1341} 1342 1343@export 1344macro TestOffHeapSlice(ptr: RawPtr<char8>, length: intptr): void { 1345 const string = UnsafeCast<SeqOneByteString>(Convert<String>('Hello World!')); 1346 1347 check(*torque_internal::unsafe::NewOffHeapReference(ptr) == string.chars[0]); 1348 1349 let offHeapSlice = torque_internal::unsafe::NewOffHeapConstSlice(ptr, length); 1350 let onHeapSlice = &string.chars; 1351 for (let i: intptr = 0; i < onHeapSlice.length; ++i) { 1352 check(*onHeapSlice.AtIndex(i) == *offHeapSlice.AtIndex(i)); 1353 } 1354} 1355 1356struct TwoValues { 1357 a: Smi; 1358 b: Map; 1359} 1360 1361builtin ReturnTwoValues(implicit context: Context)( 1362 value: Smi, obj: HeapObject): TwoValues { 1363 return TwoValues{a: value + 1, b: obj.map}; 1364} 1365 1366@export 1367macro TestCallMultiReturnBuiltin(implicit context: Context)(): void { 1368 const result = ReturnTwoValues(444, FromConstexpr<String>('hi')); 1369 check(result.a == 445); 1370 check(result.b == FromConstexpr<String>('hi').map); 1371} 1372 1373@export 1374macro TestRunLazyTwice(lazySmi: Lazy<Smi>): Smi { 1375 const firstResult = RunLazy(lazySmi); 1376 const secondResult = RunLazy(lazySmi); 1377 return firstResult + secondResult; 1378} 1379 1380macro GetLazySmi(): Smi { 1381 return 3; 1382} 1383 1384macro AddTwoSmiValues(a: Smi, b: Smi): Smi { 1385 return a + b; 1386} 1387 1388macro AddSmiAndConstexprValues(a: Smi, b: constexpr int31): Smi { 1389 return a + b; 1390} 1391 1392@export 1393macro TestCreateLazyNodeFromTorque(): void { 1394 const lazy = %MakeLazy<Smi>('GetLazySmi'); 1395 const result = TestRunLazyTwice(lazy); 1396 check(result == 6); 1397 1398 // The macro can also be referred to using namespace qualifications. 1399 const lazy2 = %MakeLazy<Smi>('test::GetLazySmi'); 1400 const result2 = TestRunLazyTwice(lazy2); 1401 check(result2 == 6); 1402 1403 // We can save params to the macro. The most common usage is likely a 1404 // single-arg macro that just returns the arg, but we can use any number of 1405 // params. 1406 const lazy3 = %MakeLazy<Smi>('AddTwoSmiValues', 5, 6); 1407 const result3 = TestRunLazyTwice(lazy3); 1408 check(result3 == 22); 1409 1410 // It's okay if some of the params are constexpr and some aren't. 1411 const lazy4 = %MakeLazy<Smi>('AddSmiAndConstexprValues', 7, 8); 1412 const result4 = TestRunLazyTwice(lazy4); 1413 check(result4 == 30); 1414} 1415} 1416