v8/test/torque/test-torque.tq
Tobias Tebbi 0dc9b63ed3 [torque] explicit exports of macros to CSA
Macros are now inaccessible from CSA except if their declaration is
marked with the "export" keyword. The implicit field accessors for class
fields are always exported.

In this CL, unwarranted access from CSA is prevented by appending a
pseudo-random suffix to non-exported names. This is to be replaced by
something more principled, namely by not including these macros at all in
the headers included from CSA.

Bug: v8:7793
Change-Id: I3ffb2e91a616623f81b4b4508e001ad0cf65d2c2
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1615258
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Reviewed-by: Simon Zünd <szuend@chromium.org>
Reviewed-by: Sigurd Schneider <sigurds@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61672}
2019-05-20 22:53:35 +00:00

978 lines
22 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.
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(Oddball, Smi) {
goto Label3(Null, 7);
}
@export
macro TestConstexpr1() {
check(FromConstexpr<bool>(IsFastElementsKind(PACKED_SMI_ELEMENTS)));
}
@export
macro TestConstexprIf() {
check(ElementsKindTestHelper1(UINT8_ELEMENTS));
check(ElementsKindTestHelper1(UINT16_ELEMENTS));
check(!ElementsKindTestHelper1(UINT32_ELEMENTS));
}
@export
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)));
}
@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>(c: Context, param: T): Object {
return Null;
}
GenericBuiltinTest<Object>(c: Context, param: Object): Object {
return param;
}
@export
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;
}
}
@export
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;
}
@export
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);
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;
}
@export
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;
}
@export
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;
}
@export
macro TestTernaryOperator(x: Smi): Smi {
let b: bool = x < 0 ? true : false;
return b ? x - 10 : x + 100;
}
@export
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;
@export
macro TestTypeAlias(x: ObjectToObject): BuiltinPtr {
return x;
}
@export
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;
}
@export
macro TestHexLiteral() {
check(Convert<intptr>(0xffff) + 1 == 0x10000);
check(Convert<intptr>(-0xffff) == -65535);
}
@export
macro TestLargeIntegerLiterals(implicit c: Context)() {
let x: int32 = 0x40000000;
let y: int32 = 0x7fffffff;
}
@export
macro TestMultilineAssert() {
let someVeryLongVariableNameThatWillCauseLineBreaks: Smi = 5;
check(
someVeryLongVariableNameThatWillCauseLineBreaks > 0 &&
someVeryLongVariableNameThatWillCauseLineBreaks < 10);
}
@export
macro TestNewlineInString() {
Print('Hello, World!\n');
}
const kConstexprConst: constexpr int31 = 5;
const kIntptrConst: intptr = 4;
const kSmiConst: Smi = 3;
@export
macro TestModuleConstBindings() {
check(kConstexprConst == Int32Constant(5));
check(kIntptrConst == 4);
check(kSmiConst == 3);
}
@export
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;
}
@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;
let 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()};
}
@export
macro TestStructInLabel(implicit context: Context)(): never labels
Foo(TestStructA) {
goto Foo(TestStruct2());
}
macro CallTestStructInLabel(implicit context: Context)() {
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() {
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) {
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;
}
@export
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);
}
@export
macro TestTypeswitchAsanLsanFailure(implicit context: Context)(obj: Object) {
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)() {
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)() {
const notEqual: bool =
AllocateHeapNumberWithValue(0.5) != AllocateHeapNumberWithValue(0.5);
check(!notEqual);
const equal: bool =
AllocateHeapNumberWithValue(0.5) == AllocateHeapNumberWithValue(0.5);
check(equal);
}
macro BoolToBranch(x: bool): never
labels Taken, NotTaken {
if (x) {
goto Taken;
} else {
goto NotTaken;
}
}
@export
macro TestOrAnd1(x: bool, y: bool, z: bool): bool {
return BoolToBranch(x) || y && z ? true : false;
}
@export
macro TestOrAnd2(x: bool, y: bool, z: bool): bool {
return x || BoolToBranch(y) && z ? true : false;
}
@export
macro TestOrAnd3(x: bool, y: bool, z: bool): bool {
return x || y && BoolToBranch(z) ? true : false;
}
@export
macro TestAndOr1(x: bool, y: bool, z: bool): bool {
return BoolToBranch(x) && y || z ? true : false;
}
@export
macro TestAndOr2(x: bool, y: bool, z: bool): bool {
return x && BoolToBranch(y) || z ? true : false;
}
@export
macro TestAndOr3(x: bool, y: bool, z: bool): bool {
return x && y || BoolToBranch(z) ? true : false;
}
@export
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));
}
@export
macro TestCall(i: Smi): Smi labels A {
if (i < 5) return i;
goto A;
}
@export
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);
}
@export
macro TestOtherwiseWithCode2() {
let s: Smi = 0;
for (let i: Smi = 0; i < 10; ++i) {
TestCall(i) otherwise break;
++s;
}
assert(s == 5);
}
@export
macro TestOtherwiseWithCode3() {
let s: Smi = 0;
for (let i: Smi = 0; i < 10; ++i) {
s += TestCall(i) otherwise break;
}
assert(s == 10);
}
@export
macro TestForwardLabel() {
try {
goto A;
}
label A {
goto B(5);
}
label B(b: Smi) {
assert(b == 5);
}
}
@export
macro TestQualifiedAccess(implicit context: Context)() {
let s: Smi = 0;
check(!array::IsJSArray(s));
}
@export
macro TestCatch1(implicit context: Context)(): Smi {
let r: Smi = 0;
try {
ThrowTypeError(kInvalidArrayLength);
} catch (e) {
r = 1;
return r;
}
}
@export
macro TestCatch2Wrapper(implicit context: Context)(): never {
ThrowTypeError(kInvalidArrayLength);
}
@export
macro TestCatch2(implicit context: Context)(): Smi {
let r: Smi = 0;
try {
TestCatch2Wrapper();
} catch (e) {
r = 2;
return r;
}
}
@export
macro TestCatch3WrapperWithLabel(implicit context: Context)():
never labels Abort {
ThrowTypeError(kInvalidArrayLength);
}
@export
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.
@export
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 {}
}
@export
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): {
}
}
}
@export
macro TestNew(implicit context: Context)() {
const f: JSArray = NewJSArray();
assert(f.IsEmpty());
f.length = 0;
}
struct TestInner {
SetX(newValue: int32) {
this.x = newValue;
}
GetX(): int32 {
return this.x;
}
x: int32;
y: int32;
}
struct TestOuter {
a: int32;
b: TestInner;
c: int32;
}
@export
macro TestStructConstructor(implicit context: Context)() {
// Test default constructor
let a: TestOuter = TestOuter{a: 5, b: TestInner{x: 6, y: 7}, c: 8};
assert(a.a == 5);
assert(a.b.x == 6);
assert(a.b.y == 7);
assert(a.c == 8);
a.b.x = 1;
assert(a.b.x == 1);
a.b.SetX(2);
assert(a.b.x == 2);
assert(a.b.GetX() == 2);
}
@noVerifier
extern class TestClassWithAllTypes extends JSObject {
a: int8;
b: uint8;
b2: uint8;
b3: uint8;
c: int16;
d: uint16;
e: int32;
f: uint32;
g: RawPtr;
h: intptr;
i: uintptr;
}
// This class should throw alignment errors if @if decorators aren't
// working.
@noVerifier
extern class PreprocessingTest extends JSObject {
@if(FALSE_FOR_TESTING) a: int8;
@if(TRUE_FOR_TESTING) a: int16;
b: int16;
d: int32;
@ifnot(TRUE_FOR_TESTING) e: int8;
@ifnot(FALSE_FOR_TESTING) f: int16;
g: int16;
h: int32;
}
@export
macro TestClassWithAllTypesLoadsAndStores(
t: TestClassWithAllTypes, r: RawPtr, v1: int8, v2: uint8, v3: int16,
v4: uint16) {
t.a = v1;
t.b = v2;
t.c = v3;
t.d = v4;
t.e = 0;
t.f = 0;
t.g = r;
t.h = 0;
t.i = 0;
t.a = t.a;
t.b = t.b;
t.c = t.c;
t.d = t.d;
t.e = t.e;
t.f = t.f;
t.g = t.g;
t.h = t.h;
t.i = t.i;
}
class InternalClass {
Flip() 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)() {
const o = NewInternalClass(5);
o.Flip() otherwise unreachable;
check(o.a == 6);
check(o.b == 5);
}
struct StructWithConst {
TestMethod1(): int32 {
return this.b;
}
TestMethod2(): Object {
return this.a;
}
a: Object;
const b: int32;
}
@export
macro TestConstInStructs() {
const x = StructWithConst{a: Null, b: 1};
let y = StructWithConst{a: Null, b: 1};
y.a = Undefined;
const copy = x;
}
struct TestIterator {
Next(): Object labels NoMore {
if (this.count-- == 0) goto NoMore;
return Hole;
}
count: Smi;
}
@export
macro TestNewFixedArrayFromSpread(implicit context: Context)(): Object {
const i = TestIterator{count: 5};
return new FixedArray{map: kFixedArrayMap, length: 5, objects: ...i};
}
class SmiPair {
GetA():&Smi {
return & this.a;
}
a: Smi;
b: Smi;
}
macro Swap<T: type>(a:&T, b:&T) {
const tmp = * a;
* a = * b;
* b = tmp;
}
@export
macro TestReferences() {
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);
}
type Baztype = Foo | FooType;
@abstract
@noVerifier
extern class Foo extends JSObject {
fooField: FooType;
}
@noVerifier
extern class Bar extends Foo {
barField: Bartype;
bazfield: Baztype;
}
type Bartype = FooType;
type FooType = Smi | Bar;
}