| // Copyright 2018 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| module test { |
| macro ElementsKindTestHelper1(kind: constexpr ElementsKind): bool { |
| if constexpr((kind == UINT8_ELEMENTS) || (kind == UINT16_ELEMENTS)) { |
| return true; |
| } |
| else { |
| return false; |
| } |
| } |
| |
| macro ElementsKindTestHelper2(kind: constexpr ElementsKind): bool { |
| return ((kind == UINT8_ELEMENTS) || (kind == UINT16_ELEMENTS)); |
| } |
| |
| macro ElementsKindTestHelper3(kind: constexpr ElementsKind): constexpr bool { |
| return ((kind == UINT8_ELEMENTS) || (kind == UINT16_ELEMENTS)); |
| } |
| |
| macro LabelTestHelper1(): never |
| labels Label1 { |
| goto Label1; |
| } |
| |
| macro LabelTestHelper2(): never |
| labels Label2(Smi) { |
| goto Label2(42); |
| } |
| |
| macro LabelTestHelper3(): never |
| labels Label3(String, Smi) { |
| goto Label3('foo', 7); |
| } |
| |
| macro TestConstexpr1() { |
| check(from_constexpr<bool>(IsFastElementsKind(PACKED_SMI_ELEMENTS))); |
| } |
| |
| macro TestConstexprIf() { |
| check(ElementsKindTestHelper1(UINT8_ELEMENTS)); |
| check(ElementsKindTestHelper1(UINT16_ELEMENTS)); |
| check(!ElementsKindTestHelper1(UINT32_ELEMENTS)); |
| } |
| |
| macro TestConstexprReturn() { |
| check(from_constexpr<bool>(ElementsKindTestHelper3(UINT8_ELEMENTS))); |
| check(from_constexpr<bool>(ElementsKindTestHelper3(UINT16_ELEMENTS))); |
| check(!from_constexpr<bool>(ElementsKindTestHelper3(UINT32_ELEMENTS))); |
| check(from_constexpr<bool>(!ElementsKindTestHelper3(UINT32_ELEMENTS))); |
| } |
| |
| macro TestGotoLabel(): Boolean { |
| try { |
| LabelTestHelper1() otherwise Label1; |
| } |
| label Label1 { |
| return True; |
| } |
| } |
| |
| macro TestGotoLabelWithOneParameter(): Boolean { |
| try { |
| LabelTestHelper2() otherwise Label2; |
| } |
| label Label2(smi: Smi) { |
| check(smi == 42); |
| return True; |
| } |
| } |
| |
| macro TestGotoLabelWithTwoParameters(): Boolean { |
| try { |
| LabelTestHelper3() otherwise Label3; |
| } |
| label Label3(str: String, smi: Smi) { |
| check(str == 'foo'); |
| check(smi == 7); |
| return True; |
| } |
| } |
| |
| builtin GenericBuiltinTest<T : type>(c: Context, param: T): Object { |
| return Null; |
| } |
| |
| GenericBuiltinTest<Object>(c: Context, param: Object): Object { |
| return param; |
| } |
| |
| macro TestBuiltinSpecialization(c: Context) { |
| check(GenericBuiltinTest<Smi>(c, 0) == Null); |
| check(GenericBuiltinTest<Smi>(c, 1) == Null); |
| check(GenericBuiltinTest<Object>(c, Undefined) == Undefined); |
| check(GenericBuiltinTest<Object>(c, Undefined) == Undefined); |
| } |
| |
| macro LabelTestHelper4(flag: constexpr bool): never labels Label4, Label5 { |
| if constexpr(flag) { |
| goto Label4; |
| } else { |
| goto Label5; |
| } |
| } |
| |
| macro CallLabelTestHelper4(flag: constexpr bool): bool { |
| try { |
| LabelTestHelper4(flag) otherwise Label4, Label5; |
| } |
| label Label4 { |
| return true; |
| } |
| label Label5 { |
| return false; |
| } |
| } |
| |
| macro TestPartiallyUnusedLabel(): Boolean { |
| let r1: bool = CallLabelTestHelper4(true); |
| let r2: bool = CallLabelTestHelper4(false); |
| |
| if (r1 && !r2) { |
| return True; |
| } else { |
| return False; |
| } |
| } |
| |
| macro GenericMacroTest<T : type>(param: T): Object { |
| return Undefined; |
| } |
| |
| GenericMacroTest<Object>(param2: Object): Object { |
| return param2; |
| } |
| |
| macro GenericMacroTestWithLabels<T : type>(param: T): Object labels X { |
| return Undefined; |
| } |
| |
| GenericMacroTestWithLabels<Object>(param2: Object): Object labels Y { |
| return param2; |
| } |
| |
| macro TestMacroSpecialization() { |
| try { |
| check(GenericMacroTest<Smi>(0) == Undefined); |
| check(GenericMacroTest<Smi>(1) == Undefined); |
| check(GenericMacroTest<Object>(Null) == Null); |
| check(GenericMacroTest<Object>(False) == False); |
| check(GenericMacroTest<Object>(True) == True); |
| check(GenericMacroTestWithLabels<Smi>(0) otherwise Fail == Undefined); |
| check(GenericMacroTestWithLabels<Smi>(0) otherwise Fail == Undefined); |
| check(GenericMacroTestWithLabels<Object>(Null) otherwise Fail == Null); |
| check(GenericMacroTestWithLabels<Object>(False) otherwise Fail == False); |
| } |
| label Fail { |
| unreachable; |
| } |
| } |
| |
| builtin TestHelperPlus1(context: Context, x: Smi): Smi { |
| return x + 1; |
| } |
| builtin TestHelperPlus2(context: Context, x: Smi): Smi { |
| return x + 2; |
| } |
| |
| macro TestFunctionPointers(context: Context): Boolean { |
| let fptr: builtin(Context, Smi) => Smi = TestHelperPlus1; |
| check(fptr(context, 42) == 43); |
| fptr = TestHelperPlus2; |
| check(fptr(context, 42) == 44); |
| return True; |
| } |
| |
| macro TestVariableRedeclaration(context: Context): Boolean { |
| let var1: int31 = from_constexpr<bool>(42 == 0) ? 0 : 1; |
| let var2: int31 = from_constexpr<bool>(42 == 0) ? 1 : 0; |
| return True; |
| } |
| |
| macro TestTernaryOperator(x: Smi): Smi { |
| let b: bool = x < 0 ? true : false; |
| return b ? x - 10 : x + 100; |
| } |
| |
| macro TestFunctionPointerToGeneric(c: Context) { |
| let fptr1: builtin(Context, Smi) => Object = GenericBuiltinTest<Smi>; |
| let fptr2: builtin(Context, Object) => Object = GenericBuiltinTest<Object>; |
| |
| check(fptr1(c, 0) == Null); |
| check(fptr1(c, 1) == Null); |
| check(fptr2(c, Undefined) == Undefined); |
| check(fptr2(c, Undefined) == Undefined); |
| } |
| |
| type SmiToSmi = builtin(Smi) => Smi; |
| macro TestTypeAlias(x: SmiToSmi): Code { |
| return x; |
| } |
| |
| macro TestUnsafeCast(c: Context, n: Number): Boolean { |
| if (TaggedIsSmi(n)) { |
| let m: Smi = unsafe_cast<Smi>(n); |
| |
| check(TestHelperPlus1(c, m) == 11); |
| return True; |
| } |
| return False; |
| } |
| |
| macro TestHexLiteral() { |
| check(convert<intptr>(0xffff) + 1 == 0x10000); |
| check(convert<intptr>(-0xffff) == -65535); |
| } |
| |
| macro TestLargeIntegerLiterals(c: Context) { |
| let x: int32 = 0x40000000; |
| let y: int32 = 0x7fffffff; |
| } |
| |
| macro TestMultilineAssert() { |
| let someVeryLongVariableNameThatWillCauseLineBreaks: Smi = 5; |
| check( |
| someVeryLongVariableNameThatWillCauseLineBreaks > 0 && |
| someVeryLongVariableNameThatWillCauseLineBreaks < 10); |
| } |
| |
| macro TestNewlineInString() { |
| Print('Hello, World!\n'); |
| } |
| |
| const kConstexprConst: constexpr int31 = 5; |
| const kIntptrConst: intptr = 4; |
| const kSmiConst: Smi = 3; |
| |
| macro TestModuleConstBindings() { |
| check(kConstexprConst == Int32Constant(5)); |
| check(kIntptrConst == 4); |
| check(kSmiConst == 3); |
| } |
| |
| macro TestLocalConstBindings() { |
| const x : constexpr int31 = 3; |
| const x_smi : Smi = x; |
| { |
| const x : Smi = x + from_constexpr<Smi>(1); |
| check(x == x_smi + 1); |
| const x_smi : Smi = x; |
| check(x == x_smi); |
| check(x == 4); |
| } |
| check(x_smi == 3); |
| check(x == x_smi); |
| } |
| |
| struct TestStructA { |
| indexes: FixedArray; |
| i: Smi; |
| k: Number; |
| } |
| |
| struct TestStructB { |
| x: TestStructA; |
| y: Smi; |
| } |
| |
| macro TestStruct1(i: TestStructA): Smi { |
| return i.i; |
| } |
| |
| macro TestStruct2(): TestStructA { |
| return TestStructA{unsafe_cast<FixedArray>(kEmptyFixedArray), 27, 31}; |
| } |
| |
| macro TestStruct3(): TestStructA { |
| let a: TestStructA = |
| TestStructA{unsafe_cast<FixedArray>(kEmptyFixedArray), 13, 5}; |
| let b: TestStructA = a; |
| let c: TestStructA = TestStruct2(); |
| a.i = TestStruct1(c); |
| a.k = a.i; |
| let d: TestStructB; |
| d.x = a; |
| d = TestStructB{a, 7}; |
| let e: TestStructA = d.x; |
| let f: Smi = TestStructA{unsafe_cast<FixedArray>(kEmptyFixedArray), 27, 31}.i; |
| f = TestStruct2().i; |
| return a; |
| } |
| |
| struct TestStructC { |
| x : TestStructA; |
| y : TestStructA; |
| } |
| |
| macro TestStruct4(): TestStructC { |
| return TestStructC{TestStruct2(), TestStruct2()}; |
| } |
| |
| // This macro tests different versions of the for-loop where some parts |
| // are (not) present. |
| macro TestForLoop() { |
| let sum: Smi = 0; |
| for (let i: Smi = 0; i < 5; ++i) sum += i; |
| check(sum == 10); |
| |
| sum = 0; |
| let j: Smi = 0; |
| for (; j < 5; ++j) sum += j; |
| check(sum == 10); |
| |
| sum = 0; |
| j = 0; |
| for (; j < 5;) sum += j++; |
| check(sum == 10); |
| |
| // Check that break works. No test expression. |
| sum = 0; |
| for (let i: Smi = 0;; ++i) { |
| if (i == 5) break; |
| sum += i; |
| } |
| check(sum == 10); |
| |
| sum = 0; |
| j = 0; |
| for (;;) { |
| if (j == 5) break; |
| sum += j; |
| j++; |
| } |
| check(sum == 10); |
| |
| // The following tests are the same as above, but use continue to skip |
| // index 3. |
| sum = 0; |
| for (let i: Smi = 0; i < 5; ++i) { |
| if (i == 3) continue; |
| sum += i; |
| } |
| check(sum == 7); |
| |
| sum = 0; |
| j = 0; |
| for (; j < 5; ++j) { |
| if (j == 3) continue; |
| sum += j; |
| } |
| check(sum == 7); |
| |
| sum = 0; |
| j = 0; |
| for (; j < 5;) { |
| if (j == 3) { |
| j++; |
| continue; |
| } |
| sum += j; |
| j++; |
| } |
| check(sum == 7); |
| |
| sum = 0; |
| for (let i: Smi = 0;; ++i) { |
| if (i == 3) continue; |
| if (i == 5) break; |
| sum += i; |
| } |
| check(sum == 7); |
| |
| sum = 0; |
| j = 0; |
| for (;;) { |
| if (j == 3) { |
| j++; |
| continue; |
| } |
| |
| if (j == 5) break; |
| sum += j; |
| j++; |
| } |
| check(sum == 7); |
| } |
| |
| macro TestSubtyping(x : Smi) { |
| const foo : Object = x; |
| } |
| |
| macro IncrementIfSmi<A : type>(x : A) : A { |
| typeswitch (x) { |
| case (x : Smi) { |
| return x + 1; |
| } case (o : A) { |
| return o; |
| } |
| } |
| } |
| |
| macro TypeswitchExample(x : Number | FixedArray) : int32 { |
| let result : int32 = 0; |
| typeswitch (IncrementIfSmi<(Number|FixedArray)>(x)) { |
| case (x : FixedArray) { |
| result = result + 1; |
| } case (Number) { |
| result = result + 2; |
| } |
| } |
| |
| result = result * 10; |
| |
| typeswitch (IncrementIfSmi<(Number|FixedArray)>(x)) { |
| case (x : Smi) { |
| result = result + convert<int32>(x); |
| } case (a : FixedArray) { |
| result = result + convert<int32>(a.length); |
| } case (x : HeapNumber) { |
| result = result + 7; |
| } |
| } |
| |
| return result; |
| } |
| |
| macro TestTypeswitch() { |
| check(TypeswitchExample(from_constexpr<Smi>(5)) == 26); |
| const a : FixedArray = AllocateZeroedFixedArray(3); |
| check(TypeswitchExample(a) == 13); |
| check(TypeswitchExample(from_constexpr<Number>(0.5)) == 27); |
| } |
| |
| macro ExampleGenericOverload<A: type>(o : Object) : A { |
| return o; |
| } |
| macro ExampleGenericOverload<A: type>(o : Smi) : A { |
| return o + 1; |
| } |
| |
| macro TestGenericOverload() { |
| const x_smi : Smi = 5; |
| const x_object : Object = x_smi; |
| check(ExampleGenericOverload<Smi>(x_smi) == 6); |
| check(unsafe_cast<Smi>(ExampleGenericOverload<Object>(x_object)) == 5); |
| } |
| } |