• 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() {
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