| // 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. |
| |
| namespace 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(FromConstexpr<bool>(IsFastElementsKind(PACKED_SMI_ELEMENTS))); |
| } |
| |
| macro TestConstexprIf() { |
| check(ElementsKindTestHelper1(UINT8_ELEMENTS)); |
| check(ElementsKindTestHelper1(UINT16_ELEMENTS)); |
| check(!ElementsKindTestHelper1(UINT32_ELEMENTS)); |
| } |
| |
| macro TestConstexprReturn() { |
| check(FromConstexpr<bool>(ElementsKindTestHelper3(UINT8_ELEMENTS))); |
| check(FromConstexpr<bool>(ElementsKindTestHelper3(UINT16_ELEMENTS))); |
| check(!FromConstexpr<bool>(ElementsKindTestHelper3(UINT32_ELEMENTS))); |
| check(FromConstexpr<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 Cast<Smi>(param2) otherwise Y; |
| } |
| |
| macro TestMacroSpecialization() { |
| try { |
| const smi0: Smi = 0; |
| 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>(smi0) otherwise Fail) == smi0); |
| try { |
| GenericMacroTestWithLabels<Object>(False) otherwise Expected; |
| } |
| label Expected {} |
| } |
| 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(implicit 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(implicit context: Context)(): Boolean { |
| let var1: int31 = FromConstexpr<bool>(42 == 0) ? 0 : 1; |
| let var2: int31 = FromConstexpr<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 ObjectToObject = builtin(Context, Object) => Object; |
| macro TestTypeAlias(x: ObjectToObject): BuiltinPtr { |
| return x; |
| } |
| |
| macro TestUnsafeCast(implicit context: Context)(n: Number): Boolean { |
| if (TaggedIsSmi(n)) { |
| let m: Smi = UnsafeCast<Smi>(n); |
| |
| check(TestHelperPlus1(context, m) == 11); |
| return True; |
| } |
| return False; |
| } |
| |
| macro TestHexLiteral() { |
| check(Convert<intptr>(0xffff) + 1 == 0x10000); |
| check(Convert<intptr>(-0xffff) == -65535); |
| } |
| |
| macro TestLargeIntegerLiterals(implicit 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 xSmi: Smi = x; |
| { |
| const x: Smi = x + FromConstexpr<Smi>(1); |
| check(x == xSmi + 1); |
| const xSmi: Smi = x; |
| check(x == xSmi); |
| check(x == 4); |
| } |
| check(xSmi == 3); |
| check(x == xSmi); |
| } |
| |
| struct TestStructA { |
| indexes: FixedArray; |
| i: Smi; |
| k: Number; |
| } |
| |
| struct TestStructB { |
| x: TestStructA; |
| y: Smi; |
| } |
| |
| macro TestStruct1(i: TestStructA): Smi { |
| return i.i; |
| } |
| |
| macro TestStruct2(implicit context: Context)(): TestStructA { |
| return TestStructA{UnsafeCast<FixedArray>(kEmptyFixedArray), 27, 31}; |
| } |
| |
| macro TestStruct3(implicit context: Context)(): TestStructA { |
| let a: TestStructA = |
| TestStructA{UnsafeCast<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{UnsafeCast<FixedArray>(kEmptyFixedArray), 27, 31}.i; |
| f = TestStruct2().i; |
| return a; |
| } |
| |
| struct TestStructC { |
| x: TestStructA; |
| y: TestStructA; |
| } |
| |
| macro TestStruct4(implicit context: Context)(): 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); |
| |
| j = 0; |
| try { |
| for (;;) { |
| if (++j == 10) goto Exit; |
| } |
| } |
| label Exit { |
| check(j == 10); |
| } |
| } |
| |
| 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; |
| } |
| } |
| } |
| |
| type NumberOrFixedArray = Number | FixedArray; |
| macro TypeswitchExample(implicit context: Context)(x: NumberOrFixedArray): |
| int32 { |
| let result: int32 = 0; |
| typeswitch (IncrementIfSmi(x)) { |
| case (x: FixedArray): { |
| result = result + 1; |
| } |
| case (Number): { |
| result = result + 2; |
| } |
| } |
| |
| result = result * 10; |
| |
| typeswitch (IncrementIfSmi(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(implicit context: Context)() { |
| check(TypeswitchExample(FromConstexpr<Smi>(5)) == 26); |
| const a: FixedArray = AllocateZeroedFixedArray(3); |
| check(TypeswitchExample(a) == 13); |
| check(TypeswitchExample(FromConstexpr<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(implicit context: Context)() { |
| const xSmi: Smi = 5; |
| const xObject: Object = xSmi; |
| check(ExampleGenericOverload<Smi>(xSmi) == 6); |
| check(UnsafeCast<Smi>(ExampleGenericOverload<Object>(xObject)) == 5); |
| } |
| |
| macro BoolToBranch(x: bool): never |
| labels Taken, NotTaken { |
| if (x) { |
| goto Taken; |
| } else { |
| goto NotTaken; |
| } |
| } |
| |
| macro TestOrAnd1(x: bool, y: bool, z: bool): bool { |
| return BoolToBranch(x) || y && z ? true : false; |
| } |
| |
| macro TestOrAnd2(x: bool, y: bool, z: bool): bool { |
| return x || BoolToBranch(y) && z ? true : false; |
| } |
| |
| macro TestOrAnd3(x: bool, y: bool, z: bool): bool { |
| return x || y && BoolToBranch(z) ? true : false; |
| } |
| |
| macro TestAndOr1(x: bool, y: bool, z: bool): bool { |
| return BoolToBranch(x) && y || z ? true : false; |
| } |
| |
| macro TestAndOr2(x: bool, y: bool, z: bool): bool { |
| return x && BoolToBranch(y) || z ? true : false; |
| } |
| |
| macro TestAndOr3(x: bool, y: bool, z: bool): bool { |
| return x && y || BoolToBranch(z) ? true : false; |
| } |
| |
| macro TestLogicalOperators() { |
| check(TestAndOr1(true, true, true)); |
| check(TestAndOr2(true, true, true)); |
| check(TestAndOr3(true, true, true)); |
| check(TestAndOr1(true, true, false)); |
| check(TestAndOr2(true, true, false)); |
| check(TestAndOr3(true, true, false)); |
| check(TestAndOr1(true, false, true)); |
| check(TestAndOr2(true, false, true)); |
| check(TestAndOr3(true, false, true)); |
| check(!TestAndOr1(true, false, false)); |
| check(!TestAndOr2(true, false, false)); |
| check(!TestAndOr3(true, false, false)); |
| check(TestAndOr1(false, true, true)); |
| check(TestAndOr2(false, true, true)); |
| check(TestAndOr3(false, true, true)); |
| check(!TestAndOr1(false, true, false)); |
| check(!TestAndOr2(false, true, false)); |
| check(!TestAndOr3(false, true, false)); |
| check(TestAndOr1(false, false, true)); |
| check(TestAndOr2(false, false, true)); |
| check(TestAndOr3(false, false, true)); |
| check(!TestAndOr1(false, false, false)); |
| check(!TestAndOr2(false, false, false)); |
| check(!TestAndOr3(false, false, false)); |
| check(TestOrAnd1(true, true, true)); |
| check(TestOrAnd2(true, true, true)); |
| check(TestOrAnd3(true, true, true)); |
| check(TestOrAnd1(true, true, false)); |
| check(TestOrAnd2(true, true, false)); |
| check(TestOrAnd3(true, true, false)); |
| check(TestOrAnd1(true, false, true)); |
| check(TestOrAnd2(true, false, true)); |
| check(TestOrAnd3(true, false, true)); |
| check(TestOrAnd1(true, false, false)); |
| check(TestOrAnd2(true, false, false)); |
| check(TestOrAnd3(true, false, false)); |
| check(TestOrAnd1(false, true, true)); |
| check(TestOrAnd2(false, true, true)); |
| check(TestOrAnd3(false, true, true)); |
| check(!TestOrAnd1(false, true, false)); |
| check(!TestOrAnd2(false, true, false)); |
| check(!TestOrAnd3(false, true, false)); |
| check(!TestOrAnd1(false, false, true)); |
| check(!TestOrAnd2(false, false, true)); |
| check(!TestOrAnd3(false, false, true)); |
| check(!TestOrAnd1(false, false, false)); |
| check(!TestOrAnd2(false, false, false)); |
| check(!TestOrAnd3(false, false, false)); |
| } |
| |
| macro TestCall(i: Smi): Smi |
| labels A { |
| if (i < 5) return i; |
| goto A; |
| } |
| |
| macro TestOtherwiseWithCode1() { |
| let v: Smi = 0; |
| let s: Smi = 1; |
| try { |
| TestCall(10) otherwise goto B(++s); |
| } |
| label B(v1: Smi) { |
| v = v1; |
| } |
| assert(v == 2); |
| } |
| |
| macro TestOtherwiseWithCode2() { |
| let s: Smi = 0; |
| for (let i: Smi = 0; i < 10; ++i) { |
| TestCall(i) otherwise break; |
| ++s; |
| } |
| assert(s == 5); |
| } |
| |
| macro TestOtherwiseWithCode3() { |
| let s: Smi = 0; |
| for (let i: Smi = 0; i < 10; ++i) { |
| s += TestCall(i) otherwise break; |
| } |
| assert(s == 10); |
| } |
| |
| macro TestForwardLabel() { |
| try { |
| goto A; |
| } |
| label A { |
| goto B(5); |
| } |
| label B(b: Smi) { |
| assert(b == 5); |
| } |
| } |
| |
| macro TestQualifiedAccess(implicit context: Context)() { |
| let s: Smi = 0; |
| check(!array::IsJSArray(s)); |
| } |
| |
| macro TestCatch1(implicit context: Context)(): Smi { |
| let r: Smi = 0; |
| try { |
| ThrowTypeError(context, kInvalidArrayLength); |
| } catch (e) { |
| r = 1; |
| return r; |
| } |
| } |
| |
| macro TestCatch2Wrapper(implicit context: Context)(): never { |
| ThrowTypeError(context, kInvalidArrayLength); |
| } |
| |
| macro TestCatch2(implicit context: Context)(): Smi { |
| let r: Smi = 0; |
| try { |
| TestCatch2Wrapper(); |
| } catch (e) { |
| r = 2; |
| return r; |
| } |
| } |
| |
| macro TestCatch3WrapperWithLabel(implicit context: Context)(): never |
| labels Abort { |
| ThrowTypeError(context, kInvalidArrayLength); |
| } |
| |
| macro TestCatch3(implicit context: Context)(): Smi { |
| let r: Smi = 0; |
| try { |
| TestCatch3WrapperWithLabel() otherwise Abort; |
| } |
| label Abort { |
| return -1; |
| } |
| catch (e) { |
| r = 2; |
| return r; |
| } |
| } |
| |
| // This test doesn't actually test the functionality of iterators, |
| // it's only purpose is to make sure tha the CSA macros in the |
| // IteratorBuiltinsAssembler match the signatures provided in |
| // iterator.tq. |
| macro TestIterator(implicit context: Context)(o: Object, map: Map) { |
| try { |
| const t1: Object = iterator::GetIteratorMethod(o); |
| const t2: iterator::IteratorRecord = iterator::GetIterator(o); |
| |
| const t3: Object = iterator::IteratorStep(t2) otherwise Fail; |
| const t4: Object = iterator::IteratorStep(t2, map) otherwise Fail; |
| |
| const t5: Object = iterator::IteratorValue(t4); |
| const t6: Object = iterator::IteratorValue(t4, map); |
| |
| const t7: JSArray = iterator::IterableToList(t1, t1); |
| |
| iterator::IteratorCloseOnException(t2, t5); |
| } |
| label Fail {} |
| } |
| |
| macro TestFrame1(implicit context: Context)() { |
| const f: Frame = LoadFramePointer(); |
| const frameType: FrameType = |
| Cast<FrameType>(f.context_or_frame_type) otherwise unreachable; |
| assert(frameType == STUB_FRAME); |
| assert(f.caller == LoadParentFramePointer()); |
| typeswitch (f) { |
| case (f: StandardFrame): { |
| unreachable; |
| } |
| case (f: ArgumentsAdaptorFrame): { |
| unreachable; |
| } |
| case (f: StubFrame): { |
| } |
| } |
| } |
| |
| } |