| Index: test/cctest/test-types.cc
|
| diff --git a/test/cctest/test-types.cc b/test/cctest/test-types.cc
|
| index 0cd24728c38cecd21321eea51e029af783d28bb5..5b493cab9fb35ec8ce7489b888380f22539c4d8a 100644
|
| --- a/test/cctest/test-types.cc
|
| +++ b/test/cctest/test-types.cc
|
| @@ -11,9 +11,23 @@
|
|
|
| using namespace v8::internal;
|
|
|
| +
|
| // Testing auxiliaries (breaking the Type abstraction).
|
| +
|
| +
|
| +static bool IsInteger(double x) {
|
| + return nearbyint(x) == x && !i::IsMinusZero(x); // Allows for infinities.
|
| +}
|
| +
|
| +
|
| +static bool IsInteger(i::Object* x) {
|
| + return x->IsNumber() && IsInteger(x->Number());
|
| +}
|
| +
|
| +
|
| typedef uint32_t bitset;
|
|
|
| +
|
| struct ZoneRep {
|
| typedef void* Struct;
|
|
|
| @@ -619,6 +633,33 @@ struct Tests : Rep {
|
| }
|
| }
|
|
|
| + void Context() {
|
| + // Constructor
|
| + for (int i = 0; i < 20; ++i) {
|
| + TypeHandle type = T.Random();
|
| + TypeHandle context = T.Context(type);
|
| + CHECK(context->Iscontext());
|
| + }
|
| +
|
| + // Attributes
|
| + for (int i = 0; i < 20; ++i) {
|
| + TypeHandle type = T.Random();
|
| + TypeHandle context = T.Context(type);
|
| + CheckEqual(type, context->AsContext()->Outer());
|
| + }
|
| +
|
| + // Functionality & Injectivity: Context(T1) = Context(T2) iff T1 = T2
|
| + for (int i = 0; i < 20; ++i) {
|
| + for (int j = 0; j < 20; ++j) {
|
| + TypeHandle type1 = T.Random();
|
| + TypeHandle type2 = T.Random();
|
| + TypeHandle context1 = T.Context(type1);
|
| + TypeHandle context2 = T.Context(type2);
|
| + CHECK(Equal(context1, context2) == Equal(type1, type2));
|
| + }
|
| + }
|
| + }
|
| +
|
| void Array() {
|
| // Constructor
|
| for (int i = 0; i < 20; ++i) {
|
| @@ -803,6 +844,56 @@ struct Tests : Rep {
|
| }
|
| }
|
|
|
| + void MinMax() {
|
| + // If b is regular numeric bitset, then Range(b->Min(), b->Max())->Is(b).
|
| + // TODO(neis): Need to ignore representation for this to be true.
|
| + /*
|
| + for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
|
| + TypeHandle type = *it;
|
| + if (this->IsBitset(type) && type->Is(T.Number) &&
|
| + !type->Is(T.None) && !type->Is(T.NaN)) {
|
| + TypeHandle range = T.Range(
|
| + isolate->factory()->NewNumber(type->Min()),
|
| + isolate->factory()->NewNumber(type->Max()));
|
| + CHECK(range->Is(type));
|
| + }
|
| + }
|
| + */
|
| +
|
| + // If b is regular numeric bitset, then b->Min() and b->Max() are integers.
|
| + for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
|
| + TypeHandle type = *it;
|
| + if (this->IsBitset(type) && type->Is(T.Number) &&
|
| + !type->Is(T.None) && !type->Is(T.NaN)) {
|
| + CHECK(IsInteger(type->Min()) && IsInteger(type->Max()));
|
| + }
|
| + }
|
| +
|
| + // If b1 and b2 are regular numeric bitsets with b1->Is(b2), then
|
| + // b1->Min() >= b2->Min() and b1->Max() <= b2->Max().
|
| + for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
|
| + for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
|
| + TypeHandle type1 = *it1;
|
| + TypeHandle type2 = *it2;
|
| + if (this->IsBitset(type1) && type1->Is(type2) && type2->Is(T.Number) &&
|
| + !type1->Is(T.NaN) && !type2->Is(T.NaN)) {
|
| + CHECK(type1->Min() >= type2->Min());
|
| + CHECK(type1->Max() <= type2->Max());
|
| + }
|
| + }
|
| + }
|
| +
|
| + // Lub(Range(x,y))->Min() <= x and y <= Lub(Range(x,y))->Max()
|
| + for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
|
| + TypeHandle type = *it;
|
| + if (type->IsRange()) {
|
| + TypeHandle lub = Rep::BitsetType::New(
|
| + Rep::BitsetType::Lub(type), T.region());
|
| + CHECK(lub->Min() <= type->Min() && type->Max() <= lub->Max());
|
| + }
|
| + }
|
| + }
|
| +
|
| void BitsetGlb() {
|
| // Lower: (T->BitsetGlb())->Is(T)
|
| for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
|
| @@ -871,7 +962,7 @@ struct Tests : Rep {
|
| }
|
| }
|
|
|
| - void Is() {
|
| + void Is1() {
|
| // Least Element (Bottom): None->Is(T)
|
| for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
|
| TypeHandle type = *it;
|
| @@ -923,6 +1014,26 @@ struct Tests : Rep {
|
| }
|
| }
|
|
|
| + // (In-)Compatibilities.
|
| + for (TypeIterator i = T.types.begin(); i != T.types.end(); ++i) {
|
| + for (TypeIterator j = T.types.begin(); j != T.types.end(); ++j) {
|
| + TypeHandle type1 = *i;
|
| + TypeHandle type2 = *j;
|
| + CHECK(!type1->Is(type2) || this->IsBitset(type2) ||
|
| + this->IsUnion(type2) || this->IsUnion(type1) ||
|
| + (type1->IsClass() && type2->IsClass()) ||
|
| + (type1->IsConstant() && type2->IsConstant()) ||
|
| + (type1->IsConstant() && type2->IsRange()) ||
|
| + (type1->IsRange() && type2->IsRange()) ||
|
| + (type1->IsContext() && type2->IsContext()) ||
|
| + (type1->IsArray() && type2->IsArray()) ||
|
| + (type1->IsFunction() && type2->IsFunction()) ||
|
| + type1->Equals(T.None));
|
| + }
|
| + }
|
| + }
|
| +
|
| + void Is2() {
|
| // Class(M1)->Is(Class(M2)) iff M1 = M2
|
| for (MapIterator mt1 = T.maps.begin(); mt1 != T.maps.end(); ++mt1) {
|
| for (MapIterator mt2 = T.maps.begin(); mt2 != T.maps.end(); ++mt2) {
|
| @@ -934,26 +1045,14 @@ struct Tests : Rep {
|
| }
|
| }
|
|
|
| - // Constant(V1)->Is(Constant(V2)) iff V1 = V2
|
| - for (ValueIterator vt1 = T.values.begin(); vt1 != T.values.end(); ++vt1) {
|
| - for (ValueIterator vt2 = T.values.begin(); vt2 != T.values.end(); ++vt2) {
|
| - Handle<i::Object> value1 = *vt1;
|
| - Handle<i::Object> value2 = *vt2;
|
| - TypeHandle const_type1 = T.Constant(value1);
|
| - TypeHandle const_type2 = T.Constant(value2);
|
| - CHECK(const_type1->Is(const_type2) == (*value1 == *value2));
|
| - }
|
| - }
|
| -
|
| - // Range(min1, max1)->Is(Range(min2, max2)) iff
|
| - // min1 >= min2 /\ max1 <= max2
|
| + // Range(X1, Y1)->Is(Range(X2, Y2)) iff X1 >= X2 /\ Y1 <= Y2
|
| for (ValueIterator i1 = T.integers.begin();
|
| i1 != T.integers.end(); ++i1) {
|
| - for (ValueIterator j1 = T.integers.begin();
|
| + for (ValueIterator j1 = i1;
|
| j1 != T.integers.end(); ++j1) {
|
| for (ValueIterator i2 = T.integers.begin();
|
| i2 != T.integers.end(); ++i2) {
|
| - for (ValueIterator j2 = T.integers.begin();
|
| + for (ValueIterator j2 = i2;
|
| j2 != T.integers.end(); ++j2) {
|
| i::Handle<i::Object> min1 = *i1;
|
| i::Handle<i::Object> max1 = *j1;
|
| @@ -964,13 +1063,24 @@ struct Tests : Rep {
|
| TypeHandle type1 = T.Range(min1, max1);
|
| TypeHandle type2 = T.Range(min2, max2);
|
| CHECK(type1->Is(type2) ==
|
| - (min2->Number() <= min1->Number() &&
|
| + (min1->Number() >= min2->Number() &&
|
| max1->Number() <= max2->Number()));
|
| }
|
| }
|
| }
|
| }
|
|
|
| + // Constant(V1)->Is(Constant(V2)) iff V1 = V2
|
| + for (ValueIterator vt1 = T.values.begin(); vt1 != T.values.end(); ++vt1) {
|
| + for (ValueIterator vt2 = T.values.begin(); vt2 != T.values.end(); ++vt2) {
|
| + Handle<i::Object> value1 = *vt1;
|
| + Handle<i::Object> value2 = *vt2;
|
| + TypeHandle const_type1 = T.Constant(value1);
|
| + TypeHandle const_type2 = T.Constant(value2);
|
| + CHECK(const_type1->Is(const_type2) == (*value1 == *value2));
|
| + }
|
| + }
|
| +
|
| // Context(T1)->Is(Context(T2)) iff T1 = T2
|
| for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
|
| for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
|
| @@ -1007,25 +1117,45 @@ struct Tests : Rep {
|
| }
|
| }
|
|
|
| - // (In-)Compatibilities.
|
| - for (TypeIterator i = T.types.begin(); i != T.types.end(); ++i) {
|
| - for (TypeIterator j = T.types.begin(); j != T.types.end(); ++j) {
|
| - TypeHandle type1 = *i;
|
| - TypeHandle type2 = *j;
|
| - CHECK(!type1->Is(type2) || this->IsBitset(type2) ||
|
| - this->IsUnion(type2) || this->IsUnion(type1) ||
|
| - (type1->IsClass() && type2->IsClass()) ||
|
| - (type1->IsConstant() && type2->IsConstant()) ||
|
| - (type1->IsConstant() && type2->IsRange()) ||
|
| - (type1->IsRange() && type2->IsRange()) ||
|
| - (type1->IsContext() && type2->IsContext()) ||
|
| - (type1->IsArray() && type2->IsArray()) ||
|
| - (type1->IsFunction() && type2->IsFunction()) ||
|
| - type1->Equals(T.None));
|
| +
|
| + // Range-specific subtyping
|
| +
|
| + // If IsInteger(v) then Constant(v)->Is(Range(v, v)).
|
| + for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
|
| + TypeHandle type = *it;
|
| + if (type->IsConstant() && IsInteger(*type->AsConstant()->Value())) {
|
| + CHECK(type->Is(
|
| + T.Range(type->AsConstant()->Value(), type->AsConstant()->Value())));
|
| }
|
| }
|
|
|
| - // Basic types
|
| + // If Constant(x)->Is(Range(min,max)) then IsInteger(v) and min <= x <= max.
|
| + for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
|
| + for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
|
| + TypeHandle type1 = *it1;
|
| + TypeHandle type2 = *it2;
|
| + if (type1->IsConstant() && type2->IsRange() && type1->Is(type2)) {
|
| + double x = type1->AsConstant()->Value()->Number();
|
| + double min = type2->AsRange()->Min()->Number();
|
| + double max = type2->AsRange()->Max()->Number();
|
| + CHECK(IsInteger(x) && min <= x && x <= max);
|
| + }
|
| + }
|
| + }
|
| +
|
| + // Lub(Range(x,y))->Is(T.Union(T.Integral32, T.OtherNumber))
|
| + for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
|
| + TypeHandle type = *it;
|
| + if (type->IsRange()) {
|
| + TypeHandle lub = Rep::BitsetType::New(
|
| + Rep::BitsetType::Lub(type), T.region());
|
| + CHECK(lub->Is(T.Union(T.Integral32, T.OtherNumber)));
|
| + }
|
| + }
|
| +
|
| +
|
| + // Subtyping between concrete basic types
|
| +
|
| CheckUnordered(T.Boolean, T.Null);
|
| CheckUnordered(T.Undefined, T.Null);
|
| CheckUnordered(T.Boolean, T.Undefined);
|
| @@ -1054,7 +1184,9 @@ struct Tests : Rep {
|
| CheckUnordered(T.Object, T.Proxy);
|
| CheckUnordered(T.Array, T.Function);
|
|
|
| - // Structural types
|
| +
|
| + // Subtyping between concrete structural types
|
| +
|
| CheckSub(T.ObjectClass, T.Object);
|
| CheckSub(T.ArrayClass, T.Object);
|
| CheckSub(T.ArrayClass, T.Array);
|
| @@ -1443,7 +1575,9 @@ struct Tests : Rep {
|
| }
|
|
|
| // Associativity: Union(T1, Union(T2, T3)) = Union(Union(T1, T2), T3)
|
| - // This does NOT hold!
|
| + // This does NOT hold! For example:
|
| + // (Unsigned32 \/ Range(0,5)) \/ Range(-5,0) = Unsigned32 \/ Range(-5,0)
|
| + // Unsigned32 \/ (Range(0,5) \/ Range(-5,0)) = Unsigned32 \/ Range(-5,5)
|
| /*
|
| for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
|
| for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
|
| @@ -1483,7 +1617,9 @@ struct Tests : Rep {
|
| }
|
|
|
| // Monotonicity: T1->Is(T2) implies Union(T1, T3)->Is(Union(T2, T3))
|
| - // This does NOT hold.
|
| + // This does NOT hold. For example:
|
| + // Range(-5,-1) <= Signed32
|
| + // Range(-5,-1) \/ Range(1,5) = Range(-5,5) </= Signed32 \/ Range(1,5)
|
| /*
|
| for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
|
| for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
|
| @@ -1502,8 +1638,10 @@ struct Tests : Rep {
|
|
|
| void Union2() {
|
| // Monotonicity: T1->Is(T3) and T2->Is(T3) implies Union(T1, T2)->Is(T3)
|
| - // This does NOT hold. TODO(neis): Could fix this by splitting
|
| - // OtherNumber into a negative and a positive part.
|
| + // This does NOT hold. For example:
|
| + // Range(-2^33, -2^33) <= OtherNumber
|
| + // Range(2^33, 2^33) <= OtherNumber
|
| + // Range(-2^33, 2^33) </= OtherNumber
|
| /*
|
| for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
|
| for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
|
| @@ -1685,7 +1823,11 @@ struct Tests : Rep {
|
|
|
| // Associativity:
|
| // Intersect(T1, Intersect(T2, T3)) = Intersect(Intersect(T1, T2), T3)
|
| - // This does NOT hold.
|
| + // This does NOT hold. For example:
|
| + // (Class(..stringy1..) /\ Class(..stringy2..)) /\ Constant(..string..) =
|
| + // None
|
| + // Class(..stringy1..) /\ (Class(..stringy2..) /\ Constant(..string..)) =
|
| + // Constant(..string..)
|
| /*
|
| for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
|
| for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
|
| @@ -1704,7 +1846,11 @@ struct Tests : Rep {
|
| */
|
|
|
| // Join: Intersect(T1, T2)->Is(T1) and Intersect(T1, T2)->Is(T2)
|
| - // This does NOT hold. Not even the disjunction.
|
| + // This does NOT hold. For example:
|
| + // Class(..stringy..) /\ Constant(..string..) = Constant(..string..)
|
| + // Currently, not even the disjunction holds:
|
| + // Class(Internal/TaggedPtr) /\ (Any/Untagged \/ Context(..)) =
|
| + // Class(Internal/TaggedPtr) \/ Context(..)
|
| /*
|
| for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
|
| for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
|
| @@ -1728,7 +1874,10 @@ struct Tests : Rep {
|
| }
|
|
|
| // Monotonicity: T1->Is(T2) implies Intersect(T1, T3)->Is(Intersect(T2, T3))
|
| - // This does NOT hold.
|
| + // This does NOT hold. For example:
|
| + // Class(OtherObject/TaggedPtr) <= Any/TaggedPtr
|
| + // Class(OtherObject/TaggedPtr) /\ Any/UntaggedInt1 = Class(..)
|
| + // Any/TaggedPtr /\ Any/UntaggedInt1 = None
|
| /*
|
| for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
|
| for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
|
| @@ -1745,7 +1894,10 @@ struct Tests : Rep {
|
| */
|
|
|
| // Monotonicity: T1->Is(T3) or T2->Is(T3) implies Intersect(T1, T2)->Is(T3)
|
| - // This does NOT hold.
|
| + // This does NOT hold. For example:
|
| + // Class(..stringy..) <= Class(..stringy..)
|
| + // Class(..stringy..) /\ Constant(..string..) = Constant(..string..)
|
| + // Constant(..string..) </= Class(..stringy..)
|
| /*
|
| for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
|
| for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
|
| @@ -1762,8 +1914,6 @@ struct Tests : Rep {
|
| */
|
|
|
| // Monotonicity: T1->Is(T2) and T1->Is(T3) implies T1->Is(Intersect(T2, T3))
|
| - // This does NOT hold.
|
| - /*
|
| for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
|
| for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
|
| for (TypeIterator it3 = T.types.begin(); it3 != T.types.end(); ++it3) {
|
| @@ -1776,7 +1926,6 @@ struct Tests : Rep {
|
| }
|
| }
|
| }
|
| - */
|
|
|
| // Bitset-class
|
| CheckEqual(T.Intersect(T.ObjectClass, T.Object), T.ObjectClass);
|
| @@ -1880,7 +2029,11 @@ struct Tests : Rep {
|
|
|
| void Distributivity() {
|
| // Union(T1, Intersect(T2, T3)) = Intersect(Union(T1, T2), Union(T1, T3))
|
| - // This does NOT hold.
|
| + // This does NOT hold. For example:
|
| + // Untagged \/ (Untagged /\ Class(../Tagged)) = Untagged \/ Class(../Tagged)
|
| + // (Untagged \/ Untagged) /\ (Untagged \/ Class(../Tagged)) =
|
| + // Untagged /\ (Untagged \/ Class(../Tagged)) = Untagged
|
| + // because Untagged <= Untagged \/ Class(../Tagged)
|
| /*
|
| for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
|
| for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
|
| @@ -1900,7 +2053,10 @@ struct Tests : Rep {
|
| */
|
|
|
| // Intersect(T1, Union(T2, T3)) = Union(Intersect(T1, T2), Intersect(T1,T3))
|
| - // This does NOT hold.
|
| + // This does NOT hold. For example:
|
| + // Untagged /\ (Untagged \/ Class(../Tagged)) = Untagged
|
| + // (Untagged /\ Untagged) \/ (Untagged /\ Class(../Tagged)) =
|
| + // Untagged \/ Class(../Tagged)
|
| /*
|
| for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
|
| for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
|
| @@ -2026,10 +2182,17 @@ TEST(BitsetLub) {
|
| }
|
|
|
|
|
| -TEST(Is) {
|
| +TEST(Is1) {
|
| CcTest::InitializeVM();
|
| - ZoneTests().Is();
|
| - HeapTests().Is();
|
| + ZoneTests().Is1();
|
| + HeapTests().Is1();
|
| +}
|
| +
|
| +
|
| +TEST(Is2) {
|
| + CcTest::InitializeVM();
|
| + ZoneTests().Is2();
|
| + HeapTests().Is2();
|
| }
|
|
|
|
|
| @@ -2098,13 +2261,11 @@ TEST(Intersect) {
|
| }
|
|
|
|
|
| -/*
|
| TEST(Distributivity) {
|
| CcTest::InitializeVM();
|
| ZoneTests().Distributivity();
|
| HeapTests().Distributivity();
|
| }
|
| -*/
|
|
|
|
|
| TEST(Convert) {
|
|
|