362b30eb1e
This is a reland of 517ed4ad00
Original change's description:
> Reland "[Torque] Generalize Torque literals to larger size"
>
> Previously, literals in Torque were stored as double values, which
> made it impossible to precisely represent 64 bit integer values.
> This CL replaces the old literal expression with an integer and
> floating point literal expression that are unbounded in size. We
> allow implicit conversion of these literals to arbitary integer
> and floating point types respectively and insert a corresponding
> bounds check into generated CSA.
>
> Changes in the reland: Simplified IntegerLiteral to single digit.
>
> Bug: v8:7793, chromium:1289282
> Change-Id: I31c762c2f31165c7a1d0b07842b764e5851ce189
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3406750
> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
> Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
> Commit-Queue: Nico Hartmann <nicohartmann@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#78811}
Bug: v8:7793, chromium:1289282
Change-Id: I7aadc4d2c9494f03eae85e94949c8f4cab7a075c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3437047
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
Commit-Queue: Nico Hartmann <nicohartmann@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78939}
1416 lines
33 KiB
Plaintext
1416 lines
33 KiB
Plaintext
// 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.
|
|
|
|
// Test line comment
|
|
/* Test mulitline
|
|
comment
|
|
*/
|
|
/*multiline_without_whitespace*/
|
|
|
|
namespace test {
|
|
macro ElementsKindTestHelper1(kind: constexpr ElementsKind): bool {
|
|
if constexpr (
|
|
kind == ElementsKind::UINT8_ELEMENTS ||
|
|
kind == ElementsKind::UINT16_ELEMENTS) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
macro ElementsKindTestHelper2(kind: constexpr ElementsKind): constexpr bool {
|
|
return kind == ElementsKind::UINT8_ELEMENTS ||
|
|
kind == ElementsKind::UINT16_ELEMENTS;
|
|
}
|
|
|
|
macro LabelTestHelper1(): never
|
|
labels Label1 {
|
|
goto Label1;
|
|
}
|
|
|
|
macro LabelTestHelper2(): never
|
|
labels Label2(Smi) {
|
|
goto Label2(42);
|
|
}
|
|
|
|
macro LabelTestHelper3(): never
|
|
labels Label3(Oddball, Smi) {
|
|
goto Label3(Null, 7);
|
|
}
|
|
|
|
@export
|
|
macro TestConstexpr1(): void {
|
|
check(FromConstexpr<bool>(
|
|
IsFastElementsKind(ElementsKind::PACKED_SMI_ELEMENTS)));
|
|
}
|
|
|
|
@export
|
|
macro TestConstexprIf(): void {
|
|
check(ElementsKindTestHelper1(ElementsKind::UINT8_ELEMENTS));
|
|
check(ElementsKindTestHelper1(ElementsKind::UINT16_ELEMENTS));
|
|
check(!ElementsKindTestHelper1(ElementsKind::UINT32_ELEMENTS));
|
|
}
|
|
|
|
@export
|
|
macro TestConstexprReturn(): void {
|
|
check(FromConstexpr<bool>(
|
|
ElementsKindTestHelper2(ElementsKind::UINT8_ELEMENTS)));
|
|
check(FromConstexpr<bool>(
|
|
ElementsKindTestHelper2(ElementsKind::UINT16_ELEMENTS)));
|
|
check(!FromConstexpr<bool>(
|
|
ElementsKindTestHelper2(ElementsKind::UINT32_ELEMENTS)));
|
|
check(FromConstexpr<bool>(
|
|
!ElementsKindTestHelper2(ElementsKind::UINT32_ELEMENTS)));
|
|
}
|
|
|
|
@export
|
|
macro TestGotoLabel(): Boolean {
|
|
try {
|
|
LabelTestHelper1() otherwise Label1;
|
|
} label Label1 {
|
|
return True;
|
|
}
|
|
}
|
|
|
|
@export
|
|
macro TestGotoLabelWithOneParameter(): Boolean {
|
|
try {
|
|
LabelTestHelper2() otherwise Label2;
|
|
} label Label2(smi: Smi) {
|
|
check(smi == 42);
|
|
return True;
|
|
}
|
|
}
|
|
|
|
@export
|
|
macro TestGotoLabelWithTwoParameters(): Boolean {
|
|
try {
|
|
LabelTestHelper3() otherwise Label3;
|
|
} label Label3(o: Oddball, smi: Smi) {
|
|
check(o == Null);
|
|
check(smi == 7);
|
|
return True;
|
|
}
|
|
}
|
|
|
|
builtin GenericBuiltinTest<T: type>(_param: T): JSAny {
|
|
return Null;
|
|
}
|
|
|
|
GenericBuiltinTest<JSAny>(param: JSAny): JSAny {
|
|
return param;
|
|
}
|
|
|
|
@export
|
|
macro TestBuiltinSpecialization(): void {
|
|
check(GenericBuiltinTest<Smi>(0) == Null);
|
|
check(GenericBuiltinTest<Smi>(1) == Null);
|
|
check(GenericBuiltinTest<JSAny>(Undefined) == Undefined);
|
|
check(GenericBuiltinTest<JSAny>(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;
|
|
}
|
|
}
|
|
|
|
@export
|
|
macro TestPartiallyUnusedLabel(): Boolean {
|
|
const r1: bool = CallLabelTestHelper4(true);
|
|
const 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;
|
|
}
|
|
|
|
@export
|
|
macro TestMacroSpecialization(): void {
|
|
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);
|
|
try {
|
|
GenericMacroTestWithLabels<Object>(False) otherwise Expected;
|
|
} label Expected {}
|
|
} label Fail {
|
|
unreachable;
|
|
}
|
|
}
|
|
|
|
builtin TestHelperPlus1(x: Smi): Smi {
|
|
return x + 1;
|
|
}
|
|
builtin TestHelperPlus2(x: Smi): Smi {
|
|
return x + 2;
|
|
}
|
|
|
|
@export
|
|
macro TestFunctionPointers(implicit context: Context)(): Boolean {
|
|
let fptr: builtin(Smi) => Smi = TestHelperPlus1;
|
|
check(fptr(42) == 43);
|
|
fptr = TestHelperPlus2;
|
|
check(fptr(42) == 44);
|
|
return True;
|
|
}
|
|
|
|
@export
|
|
macro TestVariableRedeclaration(implicit context: Context)(): Boolean {
|
|
let _var1: int31 = FromConstexpr<bool>(42 == 0) ? FromConstexpr<int31>(0) : 1;
|
|
let _var2: int31 = FromConstexpr<bool>(42 == 0) ? FromConstexpr<int31>(1) : 0;
|
|
return True;
|
|
}
|
|
|
|
@export
|
|
macro TestTernaryOperator(x: Smi): Smi {
|
|
const b: bool = x < 0 ? true : false;
|
|
return b ? x - 10 : x + 100;
|
|
}
|
|
|
|
@export
|
|
macro TestFunctionPointerToGeneric(): void {
|
|
const fptr1: builtin(Smi) => JSAny = GenericBuiltinTest<Smi>;
|
|
const fptr2: builtin(JSAny) => JSAny = GenericBuiltinTest<JSAny>;
|
|
|
|
check(fptr1(0) == Null);
|
|
check(fptr1(1) == Null);
|
|
check(fptr2(Undefined) == Undefined);
|
|
check(fptr2(Undefined) == Undefined);
|
|
}
|
|
|
|
type ObjectToObject = builtin(Context, JSAny) => JSAny;
|
|
@export
|
|
macro TestTypeAlias(x: ObjectToObject): BuiltinPtr {
|
|
return x;
|
|
}
|
|
|
|
@export
|
|
macro TestUnsafeCast(implicit context: Context)(n: Number): Boolean {
|
|
if (TaggedIsSmi(n)) {
|
|
const m: Smi = UnsafeCast<Smi>(n);
|
|
|
|
check(TestHelperPlus1(m) == 11);
|
|
return True;
|
|
}
|
|
return False;
|
|
}
|
|
|
|
@export
|
|
macro TestHexLiteral(): void {
|
|
check(Convert<intptr>(0xffff) + 1 == 0x10000);
|
|
check(Convert<intptr>(-0xffff) == -65535);
|
|
}
|
|
|
|
@export
|
|
macro TestLargeIntegerLiterals(implicit c: Context)(): void {
|
|
let _x: int32 = 0x40000000;
|
|
let _y: int32 = 0x7fffffff;
|
|
}
|
|
|
|
@export
|
|
macro TestMultilineAssert(): void {
|
|
const someVeryLongVariableNameThatWillCauseLineBreaks: Smi = 5;
|
|
check(
|
|
someVeryLongVariableNameThatWillCauseLineBreaks > 0 &&
|
|
someVeryLongVariableNameThatWillCauseLineBreaks < 10);
|
|
}
|
|
|
|
@export
|
|
macro TestNewlineInString(): void {
|
|
Print('Hello, World!\n');
|
|
}
|
|
|
|
const kConstexprConst: constexpr int31 = 5;
|
|
const kIntptrConst: intptr = 4;
|
|
const kSmiConst: Smi = 3;
|
|
|
|
@export
|
|
macro TestModuleConstBindings(): void {
|
|
check(kConstexprConst == Int32Constant(5));
|
|
check(kIntptrConst == 4);
|
|
check(kSmiConst == 3);
|
|
}
|
|
|
|
@export
|
|
macro TestLocalConstBindings(): void {
|
|
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;
|
|
}
|
|
|
|
@export
|
|
macro TestStruct1(i: TestStructA): Smi {
|
|
return i.i;
|
|
}
|
|
|
|
@export
|
|
macro TestStruct2(implicit context: Context)(): TestStructA {
|
|
return TestStructA{
|
|
indexes: UnsafeCast<FixedArray>(kEmptyFixedArray),
|
|
i: 27,
|
|
k: 31
|
|
};
|
|
}
|
|
|
|
@export
|
|
macro TestStruct3(implicit context: Context)(): TestStructA {
|
|
let a: TestStructA =
|
|
TestStructA{indexes: UnsafeCast<FixedArray>(kEmptyFixedArray), i: 13, k: 5};
|
|
let _b: TestStructA = a;
|
|
const c: TestStructA = TestStruct2();
|
|
a.i = TestStruct1(c);
|
|
a.k = a.i;
|
|
let d: TestStructB;
|
|
d.x = a;
|
|
d = TestStructB{x: a, y: 7};
|
|
let _e: TestStructA = d.x;
|
|
let f: Smi = TestStructA{
|
|
indexes: UnsafeCast<FixedArray>(kEmptyFixedArray),
|
|
i: 27,
|
|
k: 31
|
|
}.i;
|
|
f = TestStruct2().i;
|
|
return a;
|
|
}
|
|
|
|
struct TestStructC {
|
|
x: TestStructA;
|
|
y: TestStructA;
|
|
}
|
|
|
|
@export
|
|
macro TestStruct4(implicit context: Context)(): TestStructC {
|
|
return TestStructC{x: TestStruct2(), y: TestStruct2()};
|
|
}
|
|
|
|
macro TestStructInLabel(implicit context: Context)(): never labels
|
|
Foo(TestStructA) {
|
|
goto Foo(TestStruct2());
|
|
}
|
|
@export // Silence unused warning.
|
|
macro CallTestStructInLabel(implicit context: Context)(): void {
|
|
try {
|
|
TestStructInLabel() otherwise Foo;
|
|
} label Foo(_s: TestStructA) {}
|
|
}
|
|
|
|
// This macro tests different versions of the for-loop where some parts
|
|
// are (not) present.
|
|
@export
|
|
macro TestForLoop(): void {
|
|
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);
|
|
}
|
|
|
|
// Test if we can handle uninitialized values on the stack.
|
|
let _i: Smi;
|
|
for (let j: Smi = 0; j < 10; ++j) {
|
|
}
|
|
}
|
|
|
|
@export
|
|
macro TestSubtyping(x: Smi): void {
|
|
const _foo: JSAny = 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;
|
|
}
|
|
|
|
@export
|
|
macro TestTypeswitch(implicit context: Context)(): void {
|
|
check(TypeswitchExample(FromConstexpr<Smi>(5)) == 26);
|
|
const a: FixedArray = AllocateZeroedFixedArray(3);
|
|
check(TypeswitchExample(a) == 13);
|
|
check(TypeswitchExample(FromConstexpr<Number>(0.5)) == 27);
|
|
}
|
|
|
|
@export
|
|
macro TestTypeswitchAsanLsanFailure(implicit context: Context)(obj: Object):
|
|
void {
|
|
typeswitch (obj) {
|
|
case (_o: Smi): {
|
|
}
|
|
case (_o: JSTypedArray): {
|
|
}
|
|
case (_o: JSReceiver): {
|
|
}
|
|
case (_o: HeapObject): {
|
|
}
|
|
}
|
|
}
|
|
|
|
macro ExampleGenericOverload<A: type>(o: Object): A {
|
|
return o;
|
|
}
|
|
macro ExampleGenericOverload<A: type>(o: Smi): A {
|
|
return o + 1;
|
|
}
|
|
|
|
@export
|
|
macro TestGenericOverload(implicit context: Context)(): void {
|
|
const xSmi: Smi = 5;
|
|
const xObject: Object = xSmi;
|
|
check(ExampleGenericOverload<Smi>(xSmi) == 6);
|
|
check(UnsafeCast<Smi>(ExampleGenericOverload<Object>(xObject)) == 5);
|
|
}
|
|
|
|
@export
|
|
macro TestEquality(implicit context: Context)(): void {
|
|
const notEqual: bool =
|
|
AllocateHeapNumberWithValue(0.5) != AllocateHeapNumberWithValue(0.5);
|
|
check(!notEqual);
|
|
const equal: bool =
|
|
AllocateHeapNumberWithValue(0.5) == AllocateHeapNumberWithValue(0.5);
|
|
check(equal);
|
|
}
|
|
|
|
@export
|
|
macro TestOrAnd(x: bool, y: bool, z: bool): bool {
|
|
return x || y && z ? true : false;
|
|
}
|
|
|
|
@export
|
|
macro TestAndOr(x: bool, y: bool, z: bool): bool {
|
|
return x && y || z ? true : false;
|
|
}
|
|
|
|
@export
|
|
macro TestLogicalOperators(): void {
|
|
check(TestAndOr(true, true, true));
|
|
check(TestAndOr(true, true, false));
|
|
check(TestAndOr(true, false, true));
|
|
check(!TestAndOr(true, false, false));
|
|
check(TestAndOr(false, true, true));
|
|
check(!TestAndOr(false, true, false));
|
|
check(TestAndOr(false, false, true));
|
|
check(!TestAndOr(false, false, false));
|
|
check(TestOrAnd(true, true, true));
|
|
check(TestOrAnd(true, true, false));
|
|
check(TestOrAnd(true, false, true));
|
|
check(TestOrAnd(true, false, false));
|
|
check(TestOrAnd(false, true, true));
|
|
check(!TestOrAnd(false, true, false));
|
|
check(!TestOrAnd(false, false, true));
|
|
check(!TestOrAnd(false, false, false));
|
|
}
|
|
|
|
@export
|
|
macro TestCall(i: Smi): Smi labels A {
|
|
if (i < 5) return i;
|
|
goto A;
|
|
}
|
|
|
|
@export
|
|
macro TestOtherwiseWithCode1(): void {
|
|
let v: Smi = 0;
|
|
let s: Smi = 1;
|
|
try {
|
|
TestCall(10) otherwise goto B(++s);
|
|
} label B(v1: Smi) {
|
|
v = v1;
|
|
}
|
|
dcheck(v == 2);
|
|
}
|
|
|
|
@export
|
|
macro TestOtherwiseWithCode2(): void {
|
|
let s: Smi = 0;
|
|
for (let i: Smi = 0; i < 10; ++i) {
|
|
TestCall(i) otherwise break;
|
|
++s;
|
|
}
|
|
dcheck(s == 5);
|
|
}
|
|
|
|
@export
|
|
macro TestOtherwiseWithCode3(): void {
|
|
let s: Smi = 0;
|
|
for (let i: Smi = 0; i < 10; ++i) {
|
|
s += TestCall(i) otherwise break;
|
|
}
|
|
dcheck(s == 10);
|
|
}
|
|
|
|
@export
|
|
macro TestForwardLabel(): void {
|
|
try {
|
|
goto A;
|
|
} label A {
|
|
goto B(5);
|
|
} label B(b: Smi) {
|
|
dcheck(b == 5);
|
|
}
|
|
}
|
|
|
|
@export
|
|
macro TestQualifiedAccess(implicit context: Context)(): void {
|
|
const s: Smi = 0;
|
|
check(!Is<JSArray>(s));
|
|
}
|
|
|
|
@export
|
|
macro TestCatch1(implicit context: Context)(): Smi {
|
|
let r: Smi = 0;
|
|
try {
|
|
ThrowTypeError(MessageTemplate::kInvalidArrayLength);
|
|
} catch (_e, _message) {
|
|
r = 1;
|
|
return r;
|
|
}
|
|
}
|
|
|
|
@export
|
|
macro TestCatch2Wrapper(implicit context: Context)(): never {
|
|
ThrowTypeError(MessageTemplate::kInvalidArrayLength);
|
|
}
|
|
|
|
@export
|
|
macro TestCatch2(implicit context: Context)(): Smi {
|
|
let r: Smi = 0;
|
|
try {
|
|
TestCatch2Wrapper();
|
|
} catch (_e, _message) {
|
|
r = 2;
|
|
return r;
|
|
}
|
|
}
|
|
|
|
@export
|
|
macro TestCatch3WrapperWithLabel(implicit context: Context)():
|
|
never labels _Abort {
|
|
ThrowTypeError(MessageTemplate::kInvalidArrayLength);
|
|
}
|
|
|
|
@export
|
|
macro TestCatch3(implicit context: Context)(): Smi {
|
|
let r: Smi = 0;
|
|
try {
|
|
TestCatch3WrapperWithLabel() otherwise Abort;
|
|
} catch (_e, _message) {
|
|
r = 2;
|
|
return r;
|
|
} label Abort {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
// 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.
|
|
@export
|
|
transitioning macro TestIterator(implicit context: Context)(
|
|
o: JSReceiver, map: Map): void {
|
|
try {
|
|
const t1: JSAny = iterator::GetIteratorMethod(o);
|
|
const t2: iterator::IteratorRecord = iterator::GetIterator(o);
|
|
|
|
const _t3: JSAny = iterator::IteratorStep(t2) otherwise Fail;
|
|
const _t4: JSAny = iterator::IteratorStep(t2, map) otherwise Fail;
|
|
|
|
const _t5: JSAny = iterator::IteratorValue(o);
|
|
const _t6: JSAny = iterator::IteratorValue(o, map);
|
|
|
|
const _t7: JSArray = iterator::IterableToList(t1, t1);
|
|
|
|
iterator::IteratorCloseOnException(t2);
|
|
} label Fail {}
|
|
}
|
|
|
|
@export
|
|
macro TestFrame1(implicit context: Context)(): void {
|
|
const f: Frame = LoadFramePointer();
|
|
const frameType: FrameType =
|
|
Cast<FrameType>(f.context_or_frame_type) otherwise unreachable;
|
|
dcheck(frameType == STUB_FRAME);
|
|
dcheck(f.caller == LoadParentFramePointer());
|
|
typeswitch (f) {
|
|
case (_f: StandardFrame): {
|
|
unreachable;
|
|
}
|
|
case (_f: StubFrame): {
|
|
}
|
|
}
|
|
}
|
|
|
|
@export
|
|
macro TestNew(implicit context: Context)(): void {
|
|
const f: JSArray = NewJSArray();
|
|
check(f.IsEmpty());
|
|
f.length = 0;
|
|
}
|
|
|
|
struct TestInner {
|
|
macro SetX(newValue: int32): void {
|
|
this.x = newValue;
|
|
}
|
|
macro GetX(): int32 {
|
|
return this.x;
|
|
}
|
|
x: int32;
|
|
y: int32;
|
|
}
|
|
|
|
struct TestOuter {
|
|
a: int32;
|
|
b: TestInner;
|
|
c: int32;
|
|
}
|
|
|
|
@export
|
|
macro TestStructConstructor(implicit context: Context)(): void {
|
|
// Test default constructor
|
|
let a: TestOuter = TestOuter{a: 5, b: TestInner{x: 6, y: 7}, c: 8};
|
|
check(a.a == 5);
|
|
check(a.b.x == 6);
|
|
check(a.b.y == 7);
|
|
check(a.c == 8);
|
|
a.b.x = 1;
|
|
check(a.b.x == 1);
|
|
a.b.SetX(2);
|
|
check(a.b.x == 2);
|
|
check(a.b.GetX() == 2);
|
|
}
|
|
|
|
class InternalClass extends HeapObject {
|
|
macro Flip(): void labels NotASmi {
|
|
const tmp = Cast<Smi>(this.b) otherwise NotASmi;
|
|
this.b = this.a;
|
|
this.a = tmp;
|
|
}
|
|
a: Smi;
|
|
b: Number;
|
|
}
|
|
|
|
macro NewInternalClass(x: Smi): InternalClass {
|
|
return new InternalClass{a: x, b: x + 1};
|
|
}
|
|
|
|
@export
|
|
macro TestInternalClass(implicit context: Context)(): void {
|
|
const o = NewInternalClass(5);
|
|
o.Flip() otherwise unreachable;
|
|
check(o.a == 6);
|
|
check(o.b == 5);
|
|
}
|
|
|
|
struct StructWithConst {
|
|
macro TestMethod1(): int32 {
|
|
return this.b;
|
|
}
|
|
macro TestMethod2(): Object {
|
|
return this.a;
|
|
}
|
|
a: Object;
|
|
const b: int32;
|
|
}
|
|
|
|
@export
|
|
macro TestConstInStructs(): void {
|
|
const x = StructWithConst{a: Null, b: 1};
|
|
let y = StructWithConst{a: Null, b: 1};
|
|
y.a = Undefined;
|
|
const _copy = x;
|
|
|
|
check(x.TestMethod1() == 1);
|
|
check(x.TestMethod2() == Null);
|
|
}
|
|
|
|
@export
|
|
macro TestParentFrameArguments(implicit context: Context)(): void {
|
|
const parentFrame = LoadParentFramePointer();
|
|
const castFrame = Cast<StandardFrame>(parentFrame) otherwise unreachable;
|
|
const arguments = GetFrameArguments(castFrame, 1);
|
|
ArgumentsIterator{arguments, current: 0};
|
|
}
|
|
|
|
struct TestIterator {
|
|
macro Next(): Object labels NoMore {
|
|
if (this.count-- == 0) goto NoMore;
|
|
return TheHole;
|
|
}
|
|
count: Smi;
|
|
}
|
|
|
|
@export
|
|
macro TestNewFixedArrayFromSpread(implicit context: Context)(): Object {
|
|
let i = TestIterator{count: 5};
|
|
return new FixedArray{map: kFixedArrayMap, length: 5, objects: ...i};
|
|
}
|
|
|
|
class SmiPair extends HeapObject {
|
|
macro GetA():&Smi {
|
|
return &this.a;
|
|
}
|
|
a: Smi;
|
|
b: Smi;
|
|
}
|
|
|
|
macro Swap<T: type>(a:&T, b:&T): void {
|
|
const tmp = *a;
|
|
*a = *b;
|
|
*b = tmp;
|
|
}
|
|
|
|
@export
|
|
macro TestReferences(): void {
|
|
const array = new SmiPair{a: 7, b: 2};
|
|
const ref:&Smi = &array.a;
|
|
*ref = 3 + *ref;
|
|
-- *ref;
|
|
Swap(&array.b, array.GetA());
|
|
check(array.a == 2);
|
|
check(array.b == 9);
|
|
}
|
|
|
|
@export
|
|
macro TestSlices(): void {
|
|
const it = TestIterator{count: 3};
|
|
const a = new FixedArray{map: kFixedArrayMap, length: 3, objects: ...it};
|
|
check(a.length == 3);
|
|
|
|
const oneTwoThree = Convert<Smi>(123);
|
|
a.objects[0] = oneTwoThree;
|
|
const firstRef:&Object = &a.objects[0];
|
|
check(TaggedEqual(*firstRef, oneTwoThree));
|
|
|
|
const slice: MutableSlice<Object> = &a.objects;
|
|
const firstRefAgain:&Object = slice.TryAtIndex(0) otherwise unreachable;
|
|
check(TaggedEqual(*firstRefAgain, oneTwoThree));
|
|
|
|
const threeTwoOne = Convert<Smi>(321);
|
|
*firstRefAgain = threeTwoOne;
|
|
check(TaggedEqual(a.objects[0], threeTwoOne));
|
|
|
|
// *slice; // error, not allowed
|
|
// a.objects; // error, not allowed
|
|
// a.objects = slice; // error, not allowed
|
|
|
|
// TODO(gsps): Currently errors, but should be allowed:
|
|
// const _sameSlice: MutableSlice<Object> = &(*slice);
|
|
// (*slice)[0] : Smi
|
|
}
|
|
|
|
@export
|
|
macro TestSliceEnumeration(implicit context: Context)(): Undefined {
|
|
const fixedArray: FixedArray = AllocateZeroedFixedArray(3);
|
|
for (let i: intptr = 0; i < 3; i++) {
|
|
check(UnsafeCast<Smi>(fixedArray.objects[i]) == 0);
|
|
fixedArray.objects[i] = Convert<Smi>(i) + 3;
|
|
}
|
|
|
|
let slice = &fixedArray.objects;
|
|
for (let i: intptr = 0; i < slice.length; i++) {
|
|
let ref = slice.TryAtIndex(i) otherwise unreachable;
|
|
const value = UnsafeCast<Smi>(*ref);
|
|
check(value == Convert<Smi>(i) + 3);
|
|
*ref = value + 4;
|
|
}
|
|
|
|
let it = slice.Iterator();
|
|
let count: Smi = 0;
|
|
while (true) {
|
|
const value = UnsafeCast<Smi>(it.Next() otherwise break);
|
|
check(value == count + 7);
|
|
count++;
|
|
}
|
|
check(count == 3);
|
|
check(it.Empty());
|
|
|
|
return Undefined;
|
|
}
|
|
|
|
@export
|
|
macro TestStaticAssert(): void {
|
|
static_assert(1 + 2 == 3);
|
|
|
|
static_assert(Convert<uintptr>(5) < Convert<uintptr>(6));
|
|
static_assert(!(Convert<uintptr>(5) < Convert<uintptr>(5)));
|
|
static_assert(!(Convert<uintptr>(6) < Convert<uintptr>(5)));
|
|
static_assert(Convert<uintptr>(5) <= Convert<uintptr>(5));
|
|
static_assert(Convert<uintptr>(5) <= Convert<uintptr>(6));
|
|
static_assert(!(Convert<uintptr>(6) <= Convert<uintptr>(5)));
|
|
|
|
static_assert(Convert<intptr>(-6) < Convert<intptr>(-5));
|
|
static_assert(!(Convert<intptr>(-5) < Convert<intptr>(-5)));
|
|
static_assert(!(Convert<intptr>(-5) < Convert<intptr>(-6)));
|
|
static_assert(Convert<intptr>(-5) <= Convert<intptr>(-5));
|
|
static_assert(Convert<intptr>(-6) <= Convert<intptr>(-5));
|
|
static_assert(!(Convert<intptr>(-5) <= Convert<intptr>(-6)));
|
|
}
|
|
|
|
class SmiBox extends HeapObject {
|
|
value: Smi;
|
|
unrelated: Smi;
|
|
}
|
|
|
|
builtin NewSmiBox(implicit context: Context)(value: Smi): SmiBox {
|
|
return new SmiBox{value, unrelated: 0};
|
|
}
|
|
|
|
@export
|
|
macro TestLoadEliminationFixed(implicit context: Context)(): void {
|
|
const box = NewSmiBox(123);
|
|
const v1 = box.value;
|
|
box.unrelated = 999;
|
|
const v2 = (box.unrelated == 0) ? box.value : box.value;
|
|
static_assert(TaggedEqual(v1, v2));
|
|
|
|
box.value = 11;
|
|
const v3 = box.value;
|
|
const eleven: Smi = 11;
|
|
static_assert(TaggedEqual(v3, eleven));
|
|
}
|
|
|
|
@export
|
|
macro TestLoadEliminationVariable(implicit context: Context)(): void {
|
|
const a = UnsafeCast<FixedArray>(kEmptyFixedArray);
|
|
const box = NewSmiBox(1);
|
|
const v1 = a.objects[box.value];
|
|
const u1 = a.objects[box.value + 2];
|
|
const v2 = a.objects[box.value];
|
|
const u2 = a.objects[box.value + 2];
|
|
static_assert(TaggedEqual(v1, v2));
|
|
static_assert(TaggedEqual(u1, u2));
|
|
}
|
|
|
|
@export
|
|
macro TestRedundantArrayElementCheck(implicit context: Context)(): Smi {
|
|
const a = kEmptyFixedArray;
|
|
for (let i: Smi = 0; i < a.length; i++) {
|
|
if (a.objects[i] == TheHole) {
|
|
if (a.objects[i] == TheHole) {
|
|
return -1;
|
|
} else {
|
|
static_assert(false);
|
|
}
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
@export
|
|
macro TestRedundantSmiCheck(implicit context: Context)(): Smi {
|
|
const a = kEmptyFixedArray;
|
|
const x = a.objects[1];
|
|
typeswitch (x) {
|
|
case (Smi): {
|
|
Cast<Smi>(x) otherwise VerifiedUnreachable();
|
|
return -1;
|
|
}
|
|
case (Object): {
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
struct SBox<T: type> {
|
|
value: T;
|
|
}
|
|
|
|
@export
|
|
macro TestGenericStruct1(): intptr {
|
|
const i: intptr = 123;
|
|
let box = SBox{value: i};
|
|
let boxbox: SBox<SBox<intptr>> = SBox{value: box};
|
|
check(box.value == 123);
|
|
boxbox.value.value *= 2;
|
|
check(boxbox.value.value == 246);
|
|
return boxbox.value.value;
|
|
}
|
|
|
|
struct TestTuple<T1: type, T2: type> {
|
|
const fst: T1;
|
|
const snd: T2;
|
|
}
|
|
|
|
macro TupleSwap<T1: type, T2: type>(tuple: TestTuple<T1, T2>):
|
|
TestTuple<T2, T1> {
|
|
return TestTuple{fst: tuple.snd, snd: tuple.fst};
|
|
}
|
|
|
|
@export
|
|
macro TestGenericStruct2():
|
|
TestTuple<TestTuple<intptr, Smi>, TestTuple<Smi, intptr>> {
|
|
const intptrAndSmi = TestTuple<intptr, Smi>{fst: 1, snd: 2};
|
|
const smiAndIntptr = TupleSwap(intptrAndSmi);
|
|
check(intptrAndSmi.fst == smiAndIntptr.snd);
|
|
check(intptrAndSmi.snd == smiAndIntptr.fst);
|
|
const tupleTuple =
|
|
TestTuple<TestTuple<intptr, Smi>>{fst: intptrAndSmi, snd: smiAndIntptr};
|
|
return tupleTuple;
|
|
}
|
|
|
|
macro BranchAndWriteResult(x: Smi, box: SmiBox): bool {
|
|
if (x > 5 || x < 0) {
|
|
box.value = 1;
|
|
return true;
|
|
} else {
|
|
box.value = 2;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
@export
|
|
macro TestBranchOnBoolOptimization(implicit context: Context)(input: Smi):
|
|
void {
|
|
const box = NewSmiBox(1);
|
|
// If the two branches get combined into one, we should be able to determine
|
|
// the value of {box} statically.
|
|
if (BranchAndWriteResult(input, box)) {
|
|
static_assert(box.value == 1);
|
|
} else {
|
|
static_assert(box.value == 2);
|
|
}
|
|
}
|
|
|
|
bitfield struct TestBitFieldStruct extends uint8 {
|
|
a: bool: 1 bit;
|
|
b: uint16: 3 bit;
|
|
c: uint32: 3 bit;
|
|
d: bool: 1 bit;
|
|
}
|
|
|
|
@export
|
|
macro TestBitFieldLoad(
|
|
val: TestBitFieldStruct, expectedA: bool, expectedB: uint16,
|
|
expectedC: uint32, expectedD: bool): void {
|
|
check(val.a == expectedA);
|
|
check(val.b == expectedB);
|
|
check(val.c == expectedC);
|
|
check(val.d == expectedD);
|
|
}
|
|
|
|
@export
|
|
macro TestBitFieldStore(val: TestBitFieldStruct): void {
|
|
let val: TestBitFieldStruct = val; // Get a mutable local copy.
|
|
const a: bool = val.a;
|
|
const b: uint16 = val.b;
|
|
let c: uint32 = val.c;
|
|
const d: bool = val.d;
|
|
|
|
val.a = !a;
|
|
TestBitFieldLoad(val, !a, b, c, d);
|
|
|
|
c = Unsigned(7 - Signed(val.c));
|
|
val.c = c;
|
|
TestBitFieldLoad(val, !a, b, c, d);
|
|
|
|
val.d = val.b == val.c;
|
|
TestBitFieldLoad(val, !a, b, c, b == c);
|
|
}
|
|
|
|
@export
|
|
macro TestBitFieldInit(a: bool, b: uint16, c: uint32, d: bool): void {
|
|
const val: TestBitFieldStruct = TestBitFieldStruct{a: a, b: b, c: c, d: d};
|
|
TestBitFieldLoad(val, a, b, c, d);
|
|
}
|
|
|
|
// Some other bitfield structs, to verify getting uintptr values out of word32
|
|
// structs and vice versa.
|
|
bitfield struct TestBitFieldStruct2 extends uint32 {
|
|
a: uintptr: 5 bit;
|
|
b: uintptr: 6 bit;
|
|
}
|
|
bitfield struct TestBitFieldStruct3 extends uintptr {
|
|
c: bool: 1 bit;
|
|
d: uint32: 9 bit;
|
|
e: uintptr: 17 bit;
|
|
}
|
|
|
|
@export
|
|
macro TestBitFieldUintptrOps(
|
|
val2: TestBitFieldStruct2, val3: TestBitFieldStruct3): void {
|
|
let val2: TestBitFieldStruct2 = val2; // Get a mutable local copy.
|
|
let val3: TestBitFieldStruct3 = val3; // Get a mutable local copy.
|
|
|
|
// Caller is expected to provide these exact values, so we can verify
|
|
// reading values before starting to write anything.
|
|
check(val2.a == 3);
|
|
check(val2.b == 61);
|
|
check(val3.c);
|
|
check(val3.d == 500);
|
|
check(val3.e == 0x1cc);
|
|
|
|
val2.b = 16;
|
|
check(val2.a == 3);
|
|
check(val2.b == 16);
|
|
|
|
val2.b++;
|
|
check(val2.a == 3);
|
|
check(val2.b == 17);
|
|
|
|
val3.d = 99;
|
|
val3.e = 1234;
|
|
check(val3.c);
|
|
check(val3.d == 99);
|
|
check(val3.e == 1234);
|
|
}
|
|
|
|
bitfield struct TestBitFieldStruct4 extends uint31 {
|
|
a: bool: 1 bit;
|
|
b: int32: 3 bit;
|
|
c: bool: 1 bit;
|
|
}
|
|
|
|
bitfield struct TestBitFieldStruct5 extends uint31 {
|
|
b: int32: 19 bit;
|
|
a: bool: 1 bit;
|
|
c: bool: 1 bit;
|
|
}
|
|
|
|
@export
|
|
macro TestBitFieldMultipleFlags(a: bool, b: int32, c: bool): void {
|
|
const f = TestBitFieldStruct4{a: a, b: b, c: c};
|
|
let simpleExpression = f.a & f.b == 3 & !f.c;
|
|
let expectedReduction = (Signed(f) & 0x1f) == Convert<int32>(1 | 3 << 1);
|
|
static_assert(simpleExpression == expectedReduction);
|
|
simpleExpression = !f.a & f.b == 4 & f.c;
|
|
expectedReduction = (Signed(f) & 0x1f) == Convert<int32>(4 << 1 | 1 << 4);
|
|
static_assert(simpleExpression == expectedReduction);
|
|
simpleExpression = f.b == 0 & f.c;
|
|
expectedReduction = (Signed(f) & 0x1e) == Convert<int32>(1 << 4);
|
|
static_assert(simpleExpression == expectedReduction);
|
|
simpleExpression = f.a & f.c;
|
|
expectedReduction = (Signed(f) & 0x11) == Convert<int32>(1 | 1 << 4);
|
|
static_assert(simpleExpression == expectedReduction);
|
|
const f2 = TestBitFieldStruct5{b: b, a: a, c: c};
|
|
simpleExpression = !f2.a & f2.b == 1234 & f2.c;
|
|
expectedReduction = (Signed(f2) & 0x1fffff) == Convert<int32>(1234 | 1 << 20);
|
|
static_assert(simpleExpression == expectedReduction);
|
|
simpleExpression = !f2.a & !f2.c;
|
|
expectedReduction = (Signed(f2) & 0x180000) == Convert<int32>(0);
|
|
static_assert(simpleExpression == expectedReduction);
|
|
}
|
|
|
|
@export
|
|
class ExportedSubClass extends ExportedSubClassBase {
|
|
c_field: int32;
|
|
d_field: int32;
|
|
e_field: Smi;
|
|
}
|
|
|
|
@export
|
|
class ExportedSubClassBase extends HeapObject {
|
|
a: HeapObject;
|
|
b: HeapObject;
|
|
}
|
|
|
|
@abstract
|
|
class AbstractInternalClass extends HeapObject {
|
|
}
|
|
|
|
class AbstractInternalClassSubclass1 extends AbstractInternalClass {}
|
|
|
|
class AbstractInternalClassSubclass2 extends AbstractInternalClass {}
|
|
|
|
class InternalClassWithSmiElements extends FixedArrayBase {
|
|
data: Smi;
|
|
object: Oddball;
|
|
entries[length]: Smi;
|
|
}
|
|
|
|
struct InternalClassStructElement {
|
|
a: Smi;
|
|
b: Smi;
|
|
}
|
|
|
|
class InternalClassWithStructElements extends HeapObject {
|
|
dummy1: int32;
|
|
dummy2: int32;
|
|
const count: Smi;
|
|
data: Smi;
|
|
object: Object;
|
|
entries[count]: Smi;
|
|
more_entries[count]: InternalClassStructElement;
|
|
}
|
|
|
|
struct SmiGeneratorIterator {
|
|
macro Next(): Smi labels _NoMore {
|
|
return this.value++;
|
|
}
|
|
value: Smi;
|
|
}
|
|
|
|
struct InternalClassStructElementGeneratorIterator {
|
|
macro Next(): InternalClassStructElement labels _NoMore {
|
|
return InternalClassStructElement{a: this.value++, b: this.value++};
|
|
}
|
|
value: Smi;
|
|
}
|
|
|
|
@export
|
|
macro TestFullyGeneratedClassWithElements(): void {
|
|
// Test creation, initialization and access of a fully generated class with
|
|
// simple (Smi) elements
|
|
const length: Smi = Convert<Smi>(3);
|
|
const object1 = new InternalClassWithSmiElements{
|
|
length,
|
|
data: 0,
|
|
object: Undefined,
|
|
entries: ...SmiGeneratorIterator {
|
|
value: 11
|
|
}
|
|
};
|
|
dcheck(object1.length == 3);
|
|
dcheck(object1.data == 0);
|
|
dcheck(object1.object == Undefined);
|
|
dcheck(object1.entries[0] == 11);
|
|
dcheck(object1.entries[1] == 12);
|
|
dcheck(object1.entries[2] == 13);
|
|
|
|
// Test creation, initialization and access of a fully generated class
|
|
// with elements that are a struct.
|
|
const object2 = new InternalClassWithStructElements{
|
|
dummy1: 44,
|
|
dummy2: 45,
|
|
count: length,
|
|
data: 55,
|
|
object: Undefined,
|
|
entries: ...SmiGeneratorIterator{value: 3},
|
|
more_entries: ...InternalClassStructElementGeneratorIterator {
|
|
value: 1
|
|
}
|
|
};
|
|
|
|
dcheck(object2.dummy1 == 44);
|
|
dcheck(object2.dummy2 == 45);
|
|
dcheck(object2.count == 3);
|
|
dcheck(object2.data == 55);
|
|
dcheck(object2.object == Undefined);
|
|
dcheck(object2.entries[0] == 3);
|
|
dcheck(object2.entries[1] == 4);
|
|
dcheck(object2.entries[2] == 5);
|
|
dcheck(object2.more_entries[0].a == 1);
|
|
dcheck(object2.more_entries[0].b == 2);
|
|
dcheck(object2.more_entries[1].a == 3);
|
|
dcheck(object2.more_entries[1].b == 4);
|
|
dcheck(object2.more_entries[2].a == 5);
|
|
dcheck(object2.more_entries[2].b == 6);
|
|
}
|
|
|
|
@export
|
|
macro TestFullyGeneratedClassFromCpp(): ExportedSubClass {
|
|
return new
|
|
ExportedSubClass{a: Null, b: Null, c_field: 7, d_field: 8, e_field: 9};
|
|
}
|
|
|
|
@export
|
|
class ExportedSubClass2 extends ExportedSubClassBase {
|
|
x_field: int32;
|
|
y_field: int32;
|
|
z_field: Smi;
|
|
}
|
|
|
|
@export
|
|
macro TestGeneratedCastOperators(implicit context: Context)(): void {
|
|
const a = new
|
|
ExportedSubClass{a: Null, b: Null, c_field: 3, d_field: 4, e_field: 5};
|
|
const b = new ExportedSubClassBase{a: Undefined, b: Null};
|
|
const c = new
|
|
ExportedSubClass2{a: Null, b: Null, x_field: 3, y_field: 4, z_field: 5};
|
|
const aO: Object = a;
|
|
const bO: Object = b;
|
|
const cO: Object = c;
|
|
dcheck(Is<ExportedSubClassBase>(aO));
|
|
dcheck(Is<ExportedSubClass>(aO));
|
|
dcheck(!Is<ExportedSubClass2>(aO));
|
|
dcheck(Is<ExportedSubClassBase>(bO));
|
|
dcheck(!Is<ExportedSubClass>(bO));
|
|
dcheck(Is<ExportedSubClassBase>(cO));
|
|
dcheck(!Is<ExportedSubClass>(cO));
|
|
dcheck(Is<ExportedSubClass2>(cO));
|
|
|
|
const jsf: JSFunction =
|
|
*NativeContextSlot(ContextSlot::REGEXP_FUNCTION_INDEX);
|
|
dcheck(!Is<JSSloppyArgumentsObject>(jsf));
|
|
|
|
const parameterValues = NewFixedArray(0, ConstantIterator(TheHole));
|
|
const elements = NewSloppyArgumentsElements(
|
|
0, context, parameterValues, ConstantIterator(TheHole));
|
|
const fastArgs = arguments::NewJSFastAliasedArgumentsObject(
|
|
elements, Convert<Smi>(0), jsf);
|
|
dcheck(Is<JSArgumentsObject>(fastArgs));
|
|
}
|
|
|
|
extern runtime InYoungGeneration(implicit context: Context)(HeapObject):
|
|
Boolean;
|
|
|
|
@export
|
|
macro TestNewPretenured(implicit context: Context)(): void {
|
|
const obj = new (Pretenured) ExportedSubClassBase{a: Undefined, b: Null};
|
|
dcheck(Is<ExportedSubClassBase>(obj));
|
|
dcheck(InYoungGeneration(obj) == False);
|
|
}
|
|
|
|
@export
|
|
macro TestWord8Phi(): void {
|
|
for (let i: intptr = -5; i < 5; ++i) {
|
|
let x: int8;
|
|
if (i == -1) {
|
|
x = -1;
|
|
} else {
|
|
x = Convert<int8>(i);
|
|
}
|
|
check(x == Convert<int8>(i));
|
|
}
|
|
}
|
|
|
|
@export
|
|
macro TestOffHeapSlice(ptr: RawPtr<char8>, length: intptr): void {
|
|
const string = UnsafeCast<SeqOneByteString>(Convert<String>('Hello World!'));
|
|
|
|
check(*torque_internal::unsafe::NewOffHeapReference(ptr) == string.chars[0]);
|
|
|
|
let offHeapSlice = torque_internal::unsafe::NewOffHeapConstSlice(ptr, length);
|
|
let onHeapSlice = &string.chars;
|
|
for (let i: intptr = 0; i < onHeapSlice.length; ++i) {
|
|
check(*onHeapSlice.AtIndex(i) == *offHeapSlice.AtIndex(i));
|
|
}
|
|
}
|
|
|
|
struct TwoValues {
|
|
a: Smi;
|
|
b: Map;
|
|
}
|
|
|
|
builtin ReturnTwoValues(implicit context: Context)(
|
|
value: Smi, obj: HeapObject): TwoValues {
|
|
return TwoValues{a: value + 1, b: obj.map};
|
|
}
|
|
|
|
@export
|
|
macro TestCallMultiReturnBuiltin(implicit context: Context)(): void {
|
|
const result = ReturnTwoValues(444, FromConstexpr<String>('hi'));
|
|
check(result.a == 445);
|
|
check(result.b == FromConstexpr<String>('hi').map);
|
|
}
|
|
|
|
@export
|
|
macro TestRunLazyTwice(lazySmi: Lazy<Smi>): Smi {
|
|
const firstResult = RunLazy(lazySmi);
|
|
const secondResult = RunLazy(lazySmi);
|
|
return firstResult + secondResult;
|
|
}
|
|
|
|
macro GetLazySmi(): Smi {
|
|
return 3;
|
|
}
|
|
|
|
macro AddTwoSmiValues(a: Smi, b: Smi): Smi {
|
|
return a + b;
|
|
}
|
|
|
|
macro AddSmiAndConstexprValues(a: Smi, b: constexpr int31): Smi {
|
|
return a + b;
|
|
}
|
|
|
|
@export
|
|
macro TestCreateLazyNodeFromTorque(): void {
|
|
const lazy = %MakeLazy<Smi>('GetLazySmi');
|
|
const result = TestRunLazyTwice(lazy);
|
|
check(result == 6);
|
|
|
|
// The macro can also be referred to using namespace qualifications.
|
|
const lazy2 = %MakeLazy<Smi>('test::GetLazySmi');
|
|
const result2 = TestRunLazyTwice(lazy2);
|
|
check(result2 == 6);
|
|
|
|
// We can save params to the macro. The most common usage is likely a
|
|
// single-arg macro that just returns the arg, but we can use any number of
|
|
// params.
|
|
const lazy3 = %MakeLazy<Smi>('AddTwoSmiValues', 5, 6);
|
|
const result3 = TestRunLazyTwice(lazy3);
|
|
check(result3 == 22);
|
|
|
|
// It's okay if some of the params are constexpr and some aren't.
|
|
const lazy4 = %MakeLazy<Smi>('AddSmiAndConstexprValues', 7, 8);
|
|
const result4 = TestRunLazyTwice(lazy4);
|
|
check(result4 == 30);
|
|
}
|
|
}
|