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() { 44 check(FromConstexpr<bool>( 45 IsFastElementsKind(ElementsKind::PACKED_SMI_ELEMENTS))); 46} 47 48@export 49macro TestConstexprIf() { 50 check(ElementsKindTestHelper1(ElementsKind::UINT8_ELEMENTS)); 51 check(ElementsKindTestHelper1(ElementsKind::UINT16_ELEMENTS)); 52 check(!ElementsKindTestHelper1(ElementsKind::UINT32_ELEMENTS)); 53} 54 55@export 56macro TestConstexprReturn() { 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() { 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() { 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) ? 0 : 1; 200 let _var2: int31 = FromConstexpr<bool>(42 == 0) ? 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() { 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() { 240 check(Convert<intptr>(0xffff) + 1 == 0x10000); 241 check(Convert<intptr>(-0xffff) == -65535); 242} 243 244@export 245macro TestLargeIntegerLiterals(implicit c: Context)() { 246 let _x: int32 = 0x40000000; 247 let _y: int32 = 0x7fffffff; 248} 249 250@export 251macro TestMultilineAssert() { 252 const someVeryLongVariableNameThatWillCauseLineBreaks: Smi = 5; 253 check( 254 someVeryLongVariableNameThatWillCauseLineBreaks > 0 && 255 someVeryLongVariableNameThatWillCauseLineBreaks < 10); 256} 257 258@export 259macro TestNewlineInString() { 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() { 269 check(kConstexprConst == Int32Constant(5)); 270 check(kIntptrConst == 4); 271 check(kSmiConst == 3); 272} 273 274@export 275macro TestLocalConstBindings() { 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)() { 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() { 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) { 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)() { 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 typeswitch (obj) { 514 case (_o: Smi): { 515 } 516 case (_o: JSTypedArray): { 517 } 518 case (_o: JSReceiver): { 519 } 520 case (_o: HeapObject): { 521 } 522 } 523} 524 525macro ExampleGenericOverload<A: type>(o: Object): A { 526 return o; 527} 528macro ExampleGenericOverload<A: type>(o: Smi): A { 529 return o + 1; 530} 531 532@export 533macro TestGenericOverload(implicit context: Context)() { 534 const xSmi: Smi = 5; 535 const xObject: Object = xSmi; 536 check(ExampleGenericOverload<Smi>(xSmi) == 6); 537 check(UnsafeCast<Smi>(ExampleGenericOverload<Object>(xObject)) == 5); 538} 539 540@export 541macro TestEquality(implicit context: Context)() { 542 const notEqual: bool = 543 AllocateHeapNumberWithValue(0.5) != AllocateHeapNumberWithValue(0.5); 544 check(!notEqual); 545 const equal: bool = 546 AllocateHeapNumberWithValue(0.5) == AllocateHeapNumberWithValue(0.5); 547 check(equal); 548} 549 550@export 551macro TestOrAnd(x: bool, y: bool, z: bool): bool { 552 return x || y && z ? true : false; 553} 554 555@export 556macro TestAndOr(x: bool, y: bool, z: bool): bool { 557 return x && y || z ? true : false; 558} 559 560@export 561macro TestLogicalOperators() { 562 check(TestAndOr(true, true, true)); 563 check(TestAndOr(true, true, false)); 564 check(TestAndOr(true, false, true)); 565 check(!TestAndOr(true, false, false)); 566 check(TestAndOr(false, true, true)); 567 check(!TestAndOr(false, true, false)); 568 check(TestAndOr(false, false, true)); 569 check(!TestAndOr(false, false, false)); 570 check(TestOrAnd(true, true, true)); 571 check(TestOrAnd(true, true, false)); 572 check(TestOrAnd(true, false, true)); 573 check(TestOrAnd(true, false, false)); 574 check(TestOrAnd(false, true, true)); 575 check(!TestOrAnd(false, true, false)); 576 check(!TestOrAnd(false, false, true)); 577 check(!TestOrAnd(false, false, false)); 578} 579 580@export 581macro TestCall(i: Smi): Smi labels A { 582 if (i < 5) return i; 583 goto A; 584} 585 586@export 587macro TestOtherwiseWithCode1() { 588 let v: Smi = 0; 589 let s: Smi = 1; 590 try { 591 TestCall(10) otherwise goto B(++s); 592 } label B(v1: Smi) { 593 v = v1; 594 } 595 assert(v == 2); 596} 597 598@export 599macro TestOtherwiseWithCode2() { 600 let s: Smi = 0; 601 for (let i: Smi = 0; i < 10; ++i) { 602 TestCall(i) otherwise break; 603 ++s; 604 } 605 assert(s == 5); 606} 607 608@export 609macro TestOtherwiseWithCode3() { 610 let s: Smi = 0; 611 for (let i: Smi = 0; i < 10; ++i) { 612 s += TestCall(i) otherwise break; 613 } 614 assert(s == 10); 615} 616 617@export 618macro TestForwardLabel() { 619 try { 620 goto A; 621 } label A { 622 goto B(5); 623 } label B(b: Smi) { 624 assert(b == 5); 625 } 626} 627 628@export 629macro TestQualifiedAccess(implicit context: Context)() { 630 const s: Smi = 0; 631 check(!Is<JSArray>(s)); 632} 633 634@export 635macro TestCatch1(implicit context: Context)(): Smi { 636 let r: Smi = 0; 637 try { 638 ThrowTypeError(MessageTemplate::kInvalidArrayLength); 639 } catch (_e) { 640 r = 1; 641 return r; 642 } 643} 644 645@export 646macro TestCatch2Wrapper(implicit context: Context)(): never { 647 ThrowTypeError(MessageTemplate::kInvalidArrayLength); 648} 649 650@export 651macro TestCatch2(implicit context: Context)(): Smi { 652 let r: Smi = 0; 653 try { 654 TestCatch2Wrapper(); 655 } catch (_e) { 656 r = 2; 657 return r; 658 } 659} 660 661@export 662macro TestCatch3WrapperWithLabel(implicit context: Context)(): 663 never labels _Abort { 664 ThrowTypeError(MessageTemplate::kInvalidArrayLength); 665} 666 667@export 668macro TestCatch3(implicit context: Context)(): Smi { 669 let r: Smi = 0; 670 try { 671 TestCatch3WrapperWithLabel() otherwise Abort; 672 } catch (_e) { 673 r = 2; 674 return r; 675 } label Abort { 676 return -1; 677 } 678} 679 680// This test doesn't actually test the functionality of iterators, 681// it's only purpose is to make sure tha the CSA macros in the 682// IteratorBuiltinsAssembler match the signatures provided in 683// iterator.tq. 684@export 685transitioning macro TestIterator(implicit context: Context)( 686 o: JSReceiver, map: Map) { 687 try { 688 const t1: JSAny = iterator::GetIteratorMethod(o); 689 const t2: iterator::IteratorRecord = iterator::GetIterator(o); 690 691 const _t3: JSAny = iterator::IteratorStep(t2) otherwise Fail; 692 const _t4: JSAny = iterator::IteratorStep(t2, map) otherwise Fail; 693 694 const _t5: JSAny = iterator::IteratorValue(o); 695 const _t6: JSAny = iterator::IteratorValue(o, map); 696 697 const _t7: JSArray = iterator::IterableToList(t1, t1); 698 699 iterator::IteratorCloseOnException(t2); 700 } label Fail {} 701} 702 703@export 704macro TestFrame1(implicit context: Context)() { 705 const f: Frame = LoadFramePointer(); 706 const frameType: FrameType = 707 Cast<FrameType>(f.context_or_frame_type) otherwise unreachable; 708 assert(frameType == STUB_FRAME); 709 assert(f.caller == LoadParentFramePointer()); 710 typeswitch (f) { 711 case (_f: StandardFrame): { 712 unreachable; 713 } 714 case (_f: ArgumentsAdaptorFrame): { 715 unreachable; 716 } 717 case (_f: StubFrame): { 718 } 719 } 720} 721 722@export 723macro TestNew(implicit context: Context)() { 724 const f: JSArray = NewJSArray(); 725 check(f.IsEmpty()); 726 f.length = 0; 727} 728 729struct TestInner { 730 macro SetX(newValue: int32) { 731 this.x = newValue; 732 } 733 macro GetX(): int32 { 734 return this.x; 735 } 736 x: int32; 737 y: int32; 738} 739 740struct TestOuter { 741 a: int32; 742 b: TestInner; 743 c: int32; 744} 745 746@export 747macro TestStructConstructor(implicit context: Context)() { 748 // Test default constructor 749 let a: TestOuter = TestOuter{a: 5, b: TestInner{x: 6, y: 7}, c: 8}; 750 check(a.a == 5); 751 check(a.b.x == 6); 752 check(a.b.y == 7); 753 check(a.c == 8); 754 a.b.x = 1; 755 check(a.b.x == 1); 756 a.b.SetX(2); 757 check(a.b.x == 2); 758 check(a.b.GetX() == 2); 759} 760 761class InternalClass extends HeapObject { 762 macro Flip() labels NotASmi { 763 const tmp = Cast<Smi>(this.b) otherwise NotASmi; 764 this.b = this.a; 765 this.a = tmp; 766 } 767 a: Smi; 768 b: Number; 769} 770 771macro NewInternalClass(x: Smi): InternalClass { 772 return new InternalClass{a: x, b: x + 1}; 773} 774 775@export 776macro TestInternalClass(implicit context: Context)() { 777 const o = NewInternalClass(5); 778 o.Flip() otherwise unreachable; 779 check(o.a == 6); 780 check(o.b == 5); 781} 782 783struct StructWithConst { 784 macro TestMethod1(): int32 { 785 return this.b; 786 } 787 macro TestMethod2(): Object { 788 return this.a; 789 } 790 a: Object; 791 const b: int32; 792} 793 794@export 795macro TestConstInStructs() { 796 const x = StructWithConst{a: Null, b: 1}; 797 let y = StructWithConst{a: Null, b: 1}; 798 y.a = Undefined; 799 const _copy = x; 800 801 check(x.TestMethod1() == 1); 802 check(x.TestMethod2() == Null); 803} 804 805@export 806macro TestParentFrameArguments(implicit context: Context)() { 807 const parentFrame = LoadParentFramePointer(); 808 const castFrame = Cast<StandardFrame>(parentFrame) otherwise unreachable; 809 const arguments = GetFrameArguments(castFrame, 1); 810 ArgumentsIterator{arguments, current: 0}; 811} 812 813struct TestIterator { 814 macro Next(): Object labels NoMore { 815 if (this.count-- == 0) goto NoMore; 816 return TheHole; 817 } 818 count: Smi; 819} 820 821@export 822macro TestNewFixedArrayFromSpread(implicit context: Context)(): Object { 823 let i = TestIterator{count: 5}; 824 return new FixedArray{map: kFixedArrayMap, length: 5, objects: ...i}; 825} 826 827class SmiPair extends HeapObject { 828 macro GetA():&Smi { 829 return &this.a; 830 } 831 a: Smi; 832 b: Smi; 833} 834 835macro Swap<T: type>(a:&T, b:&T) { 836 const tmp = *a; 837 *a = *b; 838 *b = tmp; 839} 840 841@export 842macro TestReferences() { 843 const array = new SmiPair{a: 7, b: 2}; 844 const ref:&Smi = &array.a; 845 *ref = 3 + *ref; 846 -- *ref; 847 Swap(&array.b, array.GetA()); 848 check(array.a == 2); 849 check(array.b == 9); 850} 851 852@export 853macro TestSlices() { 854 const it = TestIterator{count: 3}; 855 const a = new FixedArray{map: kFixedArrayMap, length: 3, objects: ...it}; 856 check(a.length == 3); 857 858 const oneTwoThree = Convert<Smi>(123); 859 a.objects[0] = oneTwoThree; 860 const firstRef:&Object = &a.objects[0]; 861 check(TaggedEqual(*firstRef, oneTwoThree)); 862 863 const slice: torque_internal::Slice<Object> = &a.objects; 864 const firstRefAgain:&Object = slice.TryAtIndex(0) otherwise unreachable; 865 check(TaggedEqual(*firstRefAgain, oneTwoThree)); 866 867 const threeTwoOne = Convert<Smi>(321); 868 *firstRefAgain = threeTwoOne; 869 check(TaggedEqual(a.objects[0], threeTwoOne)); 870 871 // *slice; // error, not allowed 872 // a.objects; // error, not allowed 873 // a.objects = slice; // error, not allowed 874 875 // TODO(gsps): Currently errors, but should be allowed: 876 // const _sameSlice: torque_internal::Slice<Object> = &(*slice); 877 // (*slice)[0] : Smi 878} 879 880@export 881macro TestSliceEnumeration(implicit context: Context)(): Undefined { 882 const fixedArray: FixedArray = AllocateZeroedFixedArray(3); 883 for (let i: intptr = 0; i < 3; i++) { 884 check(UnsafeCast<Smi>(fixedArray.objects[i]) == 0); 885 fixedArray.objects[i] = Convert<Smi>(i) + 3; 886 } 887 888 let slice = &fixedArray.objects; 889 for (let i: intptr = 0; i < slice.length; i++) { 890 let ref = slice.TryAtIndex(i) otherwise unreachable; 891 const value = UnsafeCast<Smi>(*ref); 892 check(value == Convert<Smi>(i) + 3); 893 *ref = value + 4; 894 } 895 896 let it = slice.Iterator(); 897 let count: Smi = 0; 898 while (true) { 899 const value = UnsafeCast<Smi>(it.Next() otherwise break); 900 check(value == count + 7); 901 count++; 902 } 903 check(count == 3); 904 check(it.Empty()); 905 906 return Undefined; 907} 908 909@export 910macro TestStaticAssert() { 911 static_assert(1 + 2 == 3); 912 913 static_assert(Convert<uintptr>(5) < Convert<uintptr>(6)); 914 static_assert(!(Convert<uintptr>(5) < Convert<uintptr>(5))); 915 static_assert(!(Convert<uintptr>(6) < Convert<uintptr>(5))); 916 static_assert(Convert<uintptr>(5) <= Convert<uintptr>(5)); 917 static_assert(Convert<uintptr>(5) <= Convert<uintptr>(6)); 918 static_assert(!(Convert<uintptr>(6) <= Convert<uintptr>(5))); 919 920 static_assert(Convert<intptr>(-6) < Convert<intptr>(-5)); 921 static_assert(!(Convert<intptr>(-5) < Convert<intptr>(-5))); 922 static_assert(!(Convert<intptr>(-5) < Convert<intptr>(-6))); 923 static_assert(Convert<intptr>(-5) <= Convert<intptr>(-5)); 924 static_assert(Convert<intptr>(-6) <= Convert<intptr>(-5)); 925 static_assert(!(Convert<intptr>(-5) <= Convert<intptr>(-6))); 926} 927 928class SmiBox extends HeapObject { 929 value: Smi; 930 unrelated: Smi; 931} 932 933builtin NewSmiBox(implicit context: Context)(value: Smi): SmiBox { 934 return new SmiBox{value, unrelated: 0}; 935} 936 937@export 938macro TestLoadEliminationFixed(implicit context: Context)() { 939 const box = NewSmiBox(123); 940 const v1 = box.value; 941 box.unrelated = 999; 942 const v2 = (box.unrelated == 0) ? box.value : box.value; 943 static_assert(TaggedEqual(v1, v2)); 944 945 box.value = 11; 946 const v3 = box.value; 947 const eleven: Smi = 11; 948 static_assert(TaggedEqual(v3, eleven)); 949} 950 951@export 952macro TestLoadEliminationVariable(implicit context: Context)() { 953 const a = UnsafeCast<FixedArray>(kEmptyFixedArray); 954 const box = NewSmiBox(1); 955 const v1 = a.objects[box.value]; 956 const u1 = a.objects[box.value + 2]; 957 const v2 = a.objects[box.value]; 958 const u2 = a.objects[box.value + 2]; 959 static_assert(TaggedEqual(v1, v2)); 960 static_assert(TaggedEqual(u1, u2)); 961} 962 963@export 964macro TestRedundantArrayElementCheck(implicit context: Context)(): Smi { 965 const a = kEmptyFixedArray; 966 for (let i: Smi = 0; i < a.length; i++) { 967 if (a.objects[i] == TheHole) { 968 if (a.objects[i] == TheHole) { 969 return -1; 970 } else { 971 static_assert(false); 972 } 973 } 974 } 975 return 1; 976} 977 978@export 979macro TestRedundantSmiCheck(implicit context: Context)(): Smi { 980 const a = kEmptyFixedArray; 981 const x = a.objects[1]; 982 typeswitch (x) { 983 case (Smi): { 984 Cast<Smi>(x) otherwise VerifiedUnreachable(); 985 return -1; 986 } 987 case (Object): { 988 } 989 } 990 return 1; 991} 992 993struct SBox<T: type> { 994 value: T; 995} 996 997@export 998macro TestGenericStruct1(): intptr { 999 const i: intptr = 123; 1000 let box = SBox{value: i}; 1001 let boxbox: SBox<SBox<intptr>> = SBox{value: box}; 1002 check(box.value == 123); 1003 boxbox.value.value *= 2; 1004 check(boxbox.value.value == 246); 1005 return boxbox.value.value; 1006} 1007 1008struct TestTuple<T1: type, T2: type> { 1009 const fst: T1; 1010 const snd: T2; 1011} 1012 1013macro TupleSwap<T1: type, T2: type>(tuple: TestTuple<T1, T2>): 1014 TestTuple<T2, T1> { 1015 return TestTuple{fst: tuple.snd, snd: tuple.fst}; 1016} 1017 1018@export 1019macro TestGenericStruct2(): 1020 TestTuple<TestTuple<intptr, Smi>, TestTuple<Smi, intptr>> { 1021 const intptrAndSmi = TestTuple<intptr, Smi>{fst: 1, snd: 2}; 1022 const smiAndIntptr = TupleSwap(intptrAndSmi); 1023 check(intptrAndSmi.fst == smiAndIntptr.snd); 1024 check(intptrAndSmi.snd == smiAndIntptr.fst); 1025 const tupleTuple = 1026 TestTuple<TestTuple<intptr, Smi>>{fst: intptrAndSmi, snd: smiAndIntptr}; 1027 return tupleTuple; 1028} 1029 1030macro BranchAndWriteResult(x: Smi, box: SmiBox): bool { 1031 if (x > 5 || x < 0) { 1032 box.value = 1; 1033 return true; 1034 } else { 1035 box.value = 2; 1036 return false; 1037 } 1038} 1039 1040@export 1041macro TestBranchOnBoolOptimization(implicit context: Context)(input: Smi) { 1042 const box = NewSmiBox(1); 1043 // If the two branches get combined into one, we should be able to determine 1044 // the value of {box} statically. 1045 if (BranchAndWriteResult(input, box)) { 1046 static_assert(box.value == 1); 1047 } else { 1048 static_assert(box.value == 2); 1049 } 1050} 1051 1052bitfield struct TestBitFieldStruct extends uint8 { 1053 a: bool: 1 bit; 1054 b: uint16: 3 bit; 1055 c: uint32: 3 bit; 1056 d: bool: 1 bit; 1057} 1058 1059@export 1060macro TestBitFieldLoad( 1061 val: TestBitFieldStruct, expectedA: bool, expectedB: uint16, 1062 expectedC: uint32, expectedD: bool) { 1063 check(val.a == expectedA); 1064 check(val.b == expectedB); 1065 check(val.c == expectedC); 1066 check(val.d == expectedD); 1067} 1068 1069@export 1070macro TestBitFieldStore(val: TestBitFieldStruct) { 1071 let val: TestBitFieldStruct = val; // Get a mutable local copy. 1072 const a: bool = val.a; 1073 const b: uint16 = val.b; 1074 let c: uint32 = val.c; 1075 const d: bool = val.d; 1076 1077 val.a = !a; 1078 TestBitFieldLoad(val, !a, b, c, d); 1079 1080 c = Unsigned(7 - Signed(val.c)); 1081 val.c = c; 1082 TestBitFieldLoad(val, !a, b, c, d); 1083 1084 val.d = val.b == val.c; 1085 TestBitFieldLoad(val, !a, b, c, b == c); 1086} 1087 1088@export 1089macro TestBitFieldInit(a: bool, b: uint16, c: uint32, d: bool) { 1090 const val: TestBitFieldStruct = TestBitFieldStruct{a: a, b: b, c: c, d: d}; 1091 TestBitFieldLoad(val, a, b, c, d); 1092} 1093 1094// Some other bitfield structs, to verify getting uintptr values out of word32 1095// structs and vice versa. 1096bitfield struct TestBitFieldStruct2 extends uint32 { 1097 a: uintptr: 5 bit; 1098 b: uintptr: 6 bit; 1099} 1100bitfield struct TestBitFieldStruct3 extends uintptr { 1101 c: bool: 1 bit; 1102 d: uint32: 9 bit; 1103 e: uintptr: 17 bit; 1104} 1105 1106@export 1107macro TestBitFieldUintptrOps( 1108 val2: TestBitFieldStruct2, val3: TestBitFieldStruct3) { 1109 let val2: TestBitFieldStruct2 = val2; // Get a mutable local copy. 1110 let val3: TestBitFieldStruct3 = val3; // Get a mutable local copy. 1111 1112 // Caller is expected to provide these exact values, so we can verify 1113 // reading values before starting to write anything. 1114 check(val2.a == 3); 1115 check(val2.b == 61); 1116 check(val3.c); 1117 check(val3.d == 500); 1118 check(val3.e == 0x1cc); 1119 1120 val2.b = 16; 1121 check(val2.a == 3); 1122 check(val2.b == 16); 1123 1124 val2.b++; 1125 check(val2.a == 3); 1126 check(val2.b == 17); 1127 1128 val3.d = 99; 1129 val3.e = 1234; 1130 check(val3.c); 1131 check(val3.d == 99); 1132 check(val3.e == 1234); 1133} 1134 1135bitfield struct TestBitFieldStruct4 extends uint31 { 1136 a: bool: 1 bit; 1137 b: int32: 3 bit; 1138 c: bool: 1 bit; 1139} 1140 1141bitfield struct TestBitFieldStruct5 extends uint31 { 1142 b: int32: 19 bit; 1143 a: bool: 1 bit; 1144 c: bool: 1 bit; 1145} 1146 1147@export 1148macro TestBitFieldMultipleFlags(a: bool, b: int32, c: bool) { 1149 const f = TestBitFieldStruct4{a: a, b: b, c: c}; 1150 let simpleExpression = f.a & f.b == 3 & !f.c; 1151 let expectedReduction = (Signed(f) & 0x1f) == Convert<int32>(1 | 3 << 1); 1152 static_assert(simpleExpression == expectedReduction); 1153 simpleExpression = !f.a & f.b == 4 & f.c; 1154 expectedReduction = (Signed(f) & 0x1f) == Convert<int32>(4 << 1 | 1 << 4); 1155 static_assert(simpleExpression == expectedReduction); 1156 simpleExpression = f.b == 0 & f.c; 1157 expectedReduction = (Signed(f) & 0x1e) == Convert<int32>(1 << 4); 1158 static_assert(simpleExpression == expectedReduction); 1159 simpleExpression = f.a & f.c; 1160 expectedReduction = (Signed(f) & 0x11) == Convert<int32>(1 | 1 << 4); 1161 static_assert(simpleExpression == expectedReduction); 1162 const f2 = TestBitFieldStruct5{b: b, a: a, c: c}; 1163 simpleExpression = !f2.a & f2.b == 1234 & f2.c; 1164 expectedReduction = (Signed(f2) & 0x1fffff) == Convert<int32>(1234 | 1 << 20); 1165 static_assert(simpleExpression == expectedReduction); 1166 simpleExpression = !f2.a & !f2.c; 1167 expectedReduction = (Signed(f2) & 0x180000) == Convert<int32>(0); 1168 static_assert(simpleExpression == expectedReduction); 1169} 1170 1171@export 1172class ExportedSubClass extends ExportedSubClassBase { 1173 c_field: int32; 1174 d_field: int32; 1175 e_field: Smi; 1176} 1177 1178@export 1179class ExportedSubClassBase extends HeapObject { 1180 a: HeapObject; 1181 b: HeapObject; 1182} 1183 1184@abstract 1185class AbstractInternalClass extends HeapObject { 1186} 1187 1188class AbstractInternalClassSubclass1 extends AbstractInternalClass {} 1189 1190class AbstractInternalClassSubclass2 extends AbstractInternalClass {} 1191 1192class InternalClassWithSmiElements extends FixedArrayBase { 1193 data: Smi; 1194 object: Oddball; 1195 entries[length]: Smi; 1196} 1197 1198struct InternalClassStructElement { 1199 a: Smi; 1200 b: Smi; 1201} 1202 1203class InternalClassWithStructElements extends HeapObject { 1204 dummy1: int32; 1205 dummy2: int32; 1206 const count: Smi; 1207 data: Smi; 1208 object: Object; 1209 entries[count]: Smi; 1210 more_entries[count]: InternalClassStructElement; 1211} 1212 1213struct SmiGeneratorIterator { 1214 macro Next(): Smi labels _NoMore { 1215 return this.value++; 1216 } 1217 value: Smi; 1218} 1219 1220struct InternalClassStructElementGeneratorIterator { 1221 macro Next(): InternalClassStructElement labels _NoMore { 1222 return InternalClassStructElement{a: this.value++, b: this.value++}; 1223 } 1224 value: Smi; 1225} 1226 1227@export 1228macro TestFullyGeneratedClassWithElements() { 1229 // Test creation, initialization and access of a fully generated class with 1230 // simple (Smi) elements 1231 const length: Smi = Convert<Smi>(3); 1232 const object1 = new InternalClassWithSmiElements{ 1233 length, 1234 data: 0, 1235 object: Undefined, 1236 entries: ...SmiGeneratorIterator { 1237 value: 11 1238 } 1239 }; 1240 assert(object1.length == 3); 1241 assert(object1.data == 0); 1242 assert(object1.object == Undefined); 1243 assert(object1.entries[0] == 11); 1244 assert(object1.entries[1] == 12); 1245 assert(object1.entries[2] == 13); 1246 1247 // Test creation, initialization and access of a fully generated class 1248 // with elements that are a struct. 1249 const object2 = new InternalClassWithStructElements{ 1250 dummy1: 44, 1251 dummy2: 45, 1252 count: length, 1253 data: 55, 1254 object: Undefined, 1255 entries: ...SmiGeneratorIterator{value: 3}, 1256 more_entries: ...InternalClassStructElementGeneratorIterator { 1257 value: 1 1258 } 1259 }; 1260 1261 assert(object2.dummy1 == 44); 1262 assert(object2.dummy2 == 45); 1263 assert(object2.count == 3); 1264 assert(object2.data == 55); 1265 assert(object2.object == Undefined); 1266 assert(object2.entries[0] == 3); 1267 assert(object2.entries[1] == 4); 1268 assert(object2.entries[2] == 5); 1269 assert(object2.more_entries[0].a == 1); 1270 assert(object2.more_entries[0].b == 2); 1271 assert(object2.more_entries[1].a == 3); 1272 assert(object2.more_entries[1].b == 4); 1273 assert(object2.more_entries[2].a == 5); 1274 assert(object2.more_entries[2].b == 6); 1275} 1276 1277@export 1278macro TestFullyGeneratedClassFromCpp(): ExportedSubClass { 1279 return new 1280 ExportedSubClass{a: Null, b: Null, c_field: 7, d_field: 8, e_field: 9}; 1281} 1282 1283@export 1284class ExportedSubClass2 extends ExportedSubClassBase { 1285 x_field: int32; 1286 y_field: int32; 1287 z_field: Smi; 1288} 1289 1290@export 1291macro TestGeneratedCastOperators(implicit context: Context)() { 1292 const a = new 1293 ExportedSubClass{a: Null, b: Null, c_field: 3, d_field: 4, e_field: 5}; 1294 const b = new ExportedSubClassBase{a: Undefined, b: Null}; 1295 const c = new 1296 ExportedSubClass2{a: Null, b: Null, x_field: 3, y_field: 4, z_field: 5}; 1297 const aO: Object = a; 1298 const bO: Object = b; 1299 const cO: Object = c; 1300 assert(Is<ExportedSubClassBase>(aO)); 1301 assert(Is<ExportedSubClass>(aO)); 1302 assert(!Is<ExportedSubClass2>(aO)); 1303 assert(Is<ExportedSubClassBase>(bO)); 1304 assert(!Is<ExportedSubClass>(bO)); 1305 assert(Is<ExportedSubClassBase>(cO)); 1306 assert(!Is<ExportedSubClass>(cO)); 1307 assert(Is<ExportedSubClass2>(cO)); 1308 1309 const jsf: JSFunction = 1310 *NativeContextSlot(ContextSlot::REGEXP_FUNCTION_INDEX); 1311 assert(!Is<JSSloppyArgumentsObject>(jsf)); 1312 1313 const parameterValues = NewFixedArray(0, ConstantIterator(TheHole)); 1314 const elements = NewSloppyArgumentsElements( 1315 0, context, parameterValues, ConstantIterator(TheHole)); 1316 const fastArgs = arguments::NewJSFastAliasedArgumentsObject( 1317 elements, Convert<Smi>(0), jsf); 1318 assert(Is<JSArgumentsObject>(fastArgs)); 1319} 1320 1321extern runtime InYoungGeneration(implicit context: Context)(HeapObject): 1322 Boolean; 1323 1324@export 1325macro TestNewPretenured(implicit context: Context)() { 1326 const obj = new (Pretenured) ExportedSubClassBase{a: Undefined, b: Null}; 1327 assert(Is<ExportedSubClassBase>(obj)); 1328 assert(InYoungGeneration(obj) == False); 1329} 1330 1331@export 1332macro TestWord8Phi() { 1333 for (let i: intptr = -5; i < 5; ++i) { 1334 let x: int8; 1335 if (i == -1) { 1336 x = -1; 1337 } else { 1338 x = Convert<int8>(i); 1339 } 1340 check(x == Convert<int8>(i)); 1341 } 1342} 1343} 1344