• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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