From: rossberg@chromium.org Date: Tue, 18 Mar 2014 11:50:18 +0000 (+0000) Subject: Introduce representation types X-Git-Tag: upstream/4.7.83~10202 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=9b28aed3f6a944bdb9b332f1f4530ca22b76112a;p=platform%2Fupstream%2Fv8.git Introduce representation types Also: - improve type pretty-printing, - update doc comments, - some renamings for consistency. R=mstarzinger@chromium.org BUG= Review URL: https://codereview.chromium.org/176843006 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20025 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc index e38efca..3f4997f 100644 --- a/src/code-stubs-hydrogen.cc +++ b/src/code-stubs-hydrogen.cc @@ -941,7 +941,7 @@ HValue* CodeStubGraphBuilder::BuildCodeInitializedStub() { // If we encounter a generic argument, the number conversion is // observable, thus we cannot afford to bail out after the fact. if (!state.HasSideEffects()) { - if (result_type->Is(Type::Smi())) { + if (result_type->Is(Type::SignedSmall())) { if (state.op() == Token::SHR) { // TODO(olivf) Replace this by a SmiTagU Instruction. // 0x40000000: this number would convert to negative when interpreting diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 8237cbb..cbd53ee 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -1674,7 +1674,7 @@ HValue* HGraphBuilder::BuildNumberToString(HValue* object, Type* type) { } if_objectissmi.Else(); { - if (type->Is(Type::Smi())) { + if (type->Is(Type::SignedSmall())) { if_objectissmi.Deopt("Expected smi"); } else { // Check if the object is a heap number. @@ -8980,7 +8980,7 @@ bool CanBeZero(HValue* right) { HValue* HGraphBuilder::EnforceNumberType(HValue* number, Type* expected) { - if (expected->Is(Type::Smi())) { + if (expected->Is(Type::SignedSmall())) { return AddUncasted(number, Representation::Smi()); } if (expected->Is(Type::Signed32())) { @@ -9023,7 +9023,7 @@ HValue* HGraphBuilder::TruncateToNumber(HValue* value, Type** expected) { if (expected_obj->Is(Type::Undefined(zone()))) { // This is already done by HChange. - *expected = Type::Union(expected_number, Type::Double(zone()), zone()); + *expected = Type::Union(expected_number, Type::Float(zone()), zone()); return value; } diff --git a/src/ic.cc b/src/ic.cc index 5392fbc..f7d668f 100644 --- a/src/ic.cc +++ b/src/ic.cc @@ -2372,7 +2372,7 @@ const char* BinaryOpIC::State::KindToString(Kind kind) { Type* BinaryOpIC::State::KindToType(Kind kind, Zone* zone) { switch (kind) { case NONE: return Type::None(zone); - case SMI: return Type::Smi(zone); + case SMI: return Type::SignedSmall(zone); case INT32: return Type::Signed32(zone); case NUMBER: return Type::Number(zone); case STRING: return Type::String(zone); @@ -2518,7 +2518,7 @@ Type* CompareIC::StateToType( Handle map) { switch (state) { case CompareIC::UNINITIALIZED: return Type::None(zone); - case CompareIC::SMI: return Type::Smi(zone); + case CompareIC::SMI: return Type::SignedSmall(zone); case CompareIC::NUMBER: return Type::Number(zone); case CompareIC::STRING: return Type::String(zone); case CompareIC::INTERNALIZED_STRING: return Type::InternalizedString(zone); diff --git a/src/types.cc b/src/types.cc index cf41bb5..e269582 100644 --- a/src/types.cc +++ b/src/types.cc @@ -152,14 +152,14 @@ int TypeImpl::LubBitset() { template int TypeImpl::LubBitset(i::Object* value) { - if (value->IsSmi()) return kSmi; + if (value->IsSmi()) return kSignedSmall & kTaggedInt; i::Map* map = i::HeapObject::cast(value)->map(); if (map->instance_type() == HEAP_NUMBER_TYPE) { int32_t i; uint32_t u; - if (value->ToInt32(&i)) return Smi::IsValid(i) ? kSmi : kOtherSigned32; - if (value->ToUint32(&u)) return kUnsigned32; - return kDouble; + return kTaggedPtr & ( + value->ToInt32(&i) ? (Smi::IsValid(i) ? kSignedSmall : kOtherSigned32) : + value->ToUint32(&u) ? kUnsigned32 : kFloat); } if (map->instance_type() == ODDBALL_TYPE) { if (value->IsUndefined()) return kUndefined; @@ -204,7 +204,7 @@ int TypeImpl::LubBitset(i::Map* map) { case ODDBALL_TYPE: return kOddball; case HEAP_NUMBER_TYPE: - return kDouble; + return kFloat & kTaggedPtr; case JS_VALUE_TYPE: case JS_DATE_TYPE: case JS_OBJECT_TYPE: @@ -247,7 +247,7 @@ int TypeImpl::LubBitset(i::Map* map) { case EXECUTABLE_ACCESSOR_INFO_TYPE: case ACCESSOR_PAIR_TYPE: case FIXED_ARRAY_TYPE: - return kInternal; + return kInternal & kTaggedPtr; default: UNREACHABLE(); return kNone; @@ -273,13 +273,12 @@ int TypeImpl::GlbBitset() { template typename TypeImpl::TypeHandle TypeImpl::OfCurrently( i::Handle value, Region* region) { - if (value->IsSmi()) return Smi(region); - i::Map* map = i::HeapObject::cast(*value)->map(); - if (map->instance_type() == HEAP_NUMBER_TYPE || - map->instance_type() == ODDBALL_TYPE) { + if (value->IsSmi() || + i::HeapObject::cast(*value)->map()->instance_type() == HEAP_NUMBER_TYPE || + i::HeapObject::cast(*value)->map()->instance_type() == ODDBALL_TYPE) { return Of(value, region); } - return Class(i::handle(map), region); + return Class(i::handle(i::HeapObject::cast(*value)->map()), region); } @@ -340,10 +339,10 @@ template bool TypeImpl::Maybe(TypeImpl* that) { // Fast path for bitsets. if (this->IsBitset()) { - return (this->AsBitset() & that->LubBitset()) != 0; + return IsInhabited(this->AsBitset() & that->LubBitset()); } if (that->IsBitset()) { - return (this->LubBitset() & that->AsBitset()) != 0; + return IsInhabited(this->LubBitset() & that->AsBitset()); } // (T1 \/ ... \/ Tn) overlaps T <=> (T1 overlaps T) \/ ... \/ (Tn overlaps T) @@ -570,7 +569,7 @@ typename TypeImpl::TypeHandle TypeImpl::Convert( // TODO(rossberg): this does not belong here. Representation Representation::FromType(Type* type) { if (type->Is(Type::None())) return Representation::None(); - if (type->Is(Type::Smi())) return Representation::Smi(); + if (type->Is(Type::SignedSmall())) return Representation::Smi(); if (type->Is(Type::Signed32())) return Representation::Integer32(); if (type->Is(Type::Number())) return Representation::Double(); return Representation::Tagged(); @@ -579,8 +578,8 @@ Representation Representation::FromType(Type* type) { #ifdef OBJECT_PRINT template -void TypeImpl::TypePrint() { - TypePrint(stdout); +void TypeImpl::TypePrint(PrintDimension dim) { + TypePrint(stdout, dim); PrintF(stdout, "\n"); Flush(stdout); } @@ -589,9 +588,17 @@ void TypeImpl::TypePrint() { template const char* TypeImpl::bitset_name(int bitset) { switch (bitset) { - #define PRINT_COMPOSED_TYPE(type, value) case k##type: return #type; - BITSET_TYPE_LIST(PRINT_COMPOSED_TYPE) + case kAny & kRepresentation: return "Any"; + #define PRINT_COMPOSED_TYPE(type, value) \ + case k##type & kRepresentation: return #type; + REPRESENTATION_BITSET_TYPE_LIST(PRINT_COMPOSED_TYPE) #undef PRINT_COMPOSED_TYPE + + #define PRINT_COMPOSED_TYPE(type, value) \ + case k##type & kSemantic: return #type; + SEMANTIC_BITSET_TYPE_LIST(PRINT_COMPOSED_TYPE) + #undef PRINT_COMPOSED_TYPE + default: return NULL; } @@ -599,23 +606,54 @@ const char* TypeImpl::bitset_name(int bitset) { template -void TypeImpl::TypePrint(FILE* out) { +void TypeImpl::BitsetTypePrint(FILE* out, int bitset) { + const char* name = bitset_name(bitset); + if (name != NULL) { + PrintF(out, "%s", name); + } else { + static const int named_bitsets[] = { + #define BITSET_CONSTANT(type, value) k##type & kRepresentation, + REPRESENTATION_BITSET_TYPE_LIST(BITSET_CONSTANT) + #undef BITSET_CONSTANT + + #define BITSET_CONSTANT(type, value) k##type & kSemantic, + SEMANTIC_BITSET_TYPE_LIST(BITSET_CONSTANT) + #undef BITSET_CONSTANT + }; + + bool is_first = true; + PrintF(out, "("); + for (int i(ARRAY_SIZE(named_bitsets) - 1); bitset != 0 && i >= 0; --i) { + int subset = named_bitsets[i]; + if ((bitset & subset) == subset) { + if (!is_first) PrintF(out, " | "); + is_first = false; + PrintF(out, "%s", bitset_name(subset)); + bitset -= subset; + } + } + ASSERT(bitset == 0); + PrintF(out, ")"); + } +} + + +template +void TypeImpl::TypePrint(FILE* out, PrintDimension dim) { if (this->IsBitset()) { int bitset = this->AsBitset(); - const char* name = bitset_name(bitset); - if (name != NULL) { - PrintF(out, "%s", name); - } else { - bool is_first = true; - PrintF(out, "("); - for (int mask = 1; mask != 0; mask = mask << 1) { - if ((bitset & mask) != 0) { - if (!is_first) PrintF(out, " | "); - is_first = false; - PrintF(out, "%s", bitset_name(mask)); - } - } - PrintF(out, ")"); + switch (dim) { + case BOTH_DIMS: + BitsetTypePrint(out, bitset & kSemantic); + PrintF("/"); + BitsetTypePrint(out, bitset & kRepresentation); + break; + case SEMANTIC_DIM: + BitsetTypePrint(out, bitset & kSemantic); + break; + case REPRESENTATION_DIM: + BitsetTypePrint(out, bitset & kRepresentation); + break; } } else if (this->IsConstant()) { PrintF(out, "Constant(%p : ", static_cast(*this->AsConstant())); diff --git a/src/types.h b/src/types.h index 20371a9..4569d13 100644 --- a/src/types.h +++ b/src/types.h @@ -42,7 +42,10 @@ namespace internal { // can express class types (a.k.a. specific maps) and singleton types (i.e., // concrete constants). // -// The following equations and inequations hold: +// Types consist of two dimensions: semantic (value range) and representation. +// Both are related through subtyping. +// +// The following equations and inequations hold for the semantic axis: // // None <= T // T <= Any @@ -54,13 +57,12 @@ namespace internal { // UniqueName = InternalizedString \/ Symbol // InternalizedString < String // -// Allocated = Receiver \/ Number \/ Name -// Detectable = Allocated - Undetectable -// Undetectable < Object // Receiver = Object \/ Proxy // Array < Object // Function < Object // RegExp < Object +// Undetectable < Object +// Detectable = Receiver \/ Number \/ Name - Undetectable // // Class(map) < T iff instance_type(map) < T // Constant(x) < T iff instance_type(map(x)) < T @@ -70,20 +72,43 @@ namespace internal { // TODO(rossberg): the latter is not currently true for proxies, because of fix, // but will hold once we implement direct proxies. // +// For the representation axis, the following holds: +// +// None <= R +// R <= Any +// +// UntaggedInt <= UntaggedInt8 \/ UntaggedInt16 \/ UntaggedInt32) +// UntaggedFloat <= UntaggedFloat32 \/ UntaggedFloat64 +// UntaggedNumber <= UntaggedInt \/ UntaggedFloat +// Untagged <= UntaggedNumber \/ UntaggedPtr +// Tagged <= TaggedInt \/ TaggedPtr +// +// Subtyping relates the two dimensions, for example: +// +// Number <= Tagged \/ UntaggedNumber +// Object <= TaggedPtr \/ UntaggedPtr +// +// That holds because the semantic type constructors defined by the API create +// types that allow for all possible representations, and dually, the ones for +// representation types initially include all semantic ranges. Representations +// can then e.g. be narrowed for a given semantic type using intersection: +// +// SignedSmall /\ TaggedInt (a 'smi') +// Number /\ TaggedPtr (a heap number) +// // There are two main functions for testing types: // // T1->Is(T2) -- tests whether T1 is included in T2 (i.e., T1 <= T2) // T1->Maybe(T2) -- tests whether T1 and T2 overlap (i.e., T1 /\ T2 =/= 0) // // Typically, the former is to be used to select representations (e.g., via -// T->Is(Integer31())), and the to check whether a specific case needs handling -// (e.g., via T->Maybe(Number())). +// T->Is(SignedSmall())), and the latter to check whether a specific case needs +// handling (e.g., via T->Maybe(Number())). // // There is no functionality to discover whether a type is a leaf in the // lattice. That is intentional. It should always be possible to refine the // lattice (e.g., splitting up number types further) without invalidating any // existing assumptions or tests. -// // Consequently, do not use pointer equality for type tests, always use Is! // // Internally, all 'primitive' types, and their unions, are represented as @@ -100,40 +125,68 @@ namespace internal { // them. For zone types, no query method touches the heap, only constructors do. -#define BITSET_TYPE_LIST(V) \ - V(None, 0) \ - V(Null, 1 << 0) \ - V(Undefined, 1 << 1) \ - V(Boolean, 1 << 2) \ - V(Smi, 1 << 3) \ - V(OtherSigned32, 1 << 4) \ - V(Unsigned32, 1 << 5) \ - V(Double, 1 << 6) \ - V(Symbol, 1 << 7) \ - V(InternalizedString, 1 << 8) \ - V(OtherString, 1 << 9) \ - V(Undetectable, 1 << 10) \ - V(Array, 1 << 11) \ - V(Function, 1 << 12) \ - V(RegExp, 1 << 13) \ - V(OtherObject, 1 << 14) \ - V(Proxy, 1 << 15) \ - V(Internal, 1 << 16) \ +#define MASK_BITSET_TYPE_LIST(V) \ + V(Representation, static_cast(0xff800000)) \ + V(Semantic, static_cast(0x007fffff)) + +#define REPRESENTATION(k) ((k) & kRepresentation) +#define SEMANTIC(k) ((k) & kSemantic) + +#define REPRESENTATION_BITSET_TYPE_LIST(V) \ + V(None, 0) \ + V(UntaggedInt8, 1 << 23 | kSemantic) \ + V(UntaggedInt16, 1 << 24 | kSemantic) \ + V(UntaggedInt32, 1 << 25 | kSemantic) \ + V(UntaggedFloat32, 1 << 26 | kSemantic) \ + V(UntaggedFloat64, 1 << 27 | kSemantic) \ + V(UntaggedPtr, 1 << 28 | kSemantic) \ + V(TaggedInt, 1 << 29 | kSemantic) \ + V(TaggedPtr, -1 << 30 | kSemantic) /* MSB has to be sign-extended */ \ + \ + V(UntaggedInt, kUntaggedInt8 | kUntaggedInt16 | kUntaggedInt32) \ + V(UntaggedFloat, kUntaggedFloat32 | kUntaggedFloat64) \ + V(UntaggedNumber, kUntaggedInt | kUntaggedFloat) \ + V(Untagged, kUntaggedNumber | kUntaggedPtr) \ + V(Tagged, kTaggedInt | kTaggedPtr) + +#define SEMANTIC_BITSET_TYPE_LIST(V) \ + V(Null, 1 << 0 | REPRESENTATION(kTaggedPtr)) \ + V(Undefined, 1 << 1 | REPRESENTATION(kTaggedPtr)) \ + V(Boolean, 1 << 2 | REPRESENTATION(kTaggedPtr)) \ + V(SignedSmall, 1 << 3 | REPRESENTATION(kTagged | kUntaggedNumber)) \ + V(OtherSigned32, 1 << 4 | REPRESENTATION(kTagged | kUntaggedNumber)) \ + V(Unsigned32, 1 << 5 | REPRESENTATION(kTagged | kUntaggedNumber)) \ + V(Float, 1 << 6 | REPRESENTATION(kTagged | kUntaggedNumber)) \ + V(Symbol, 1 << 7 | REPRESENTATION(kTaggedPtr)) \ + V(InternalizedString, 1 << 8 | REPRESENTATION(kTaggedPtr)) \ + V(OtherString, 1 << 9 | REPRESENTATION(kTaggedPtr)) \ + V(Undetectable, 1 << 10 | REPRESENTATION(kTaggedPtr)) \ + V(Array, 1 << 11 | REPRESENTATION(kTaggedPtr)) \ + V(Function, 1 << 12 | REPRESENTATION(kTaggedPtr)) \ + V(RegExp, 1 << 13 | REPRESENTATION(kTaggedPtr)) \ + V(OtherObject, 1 << 14 | REPRESENTATION(kTaggedPtr)) \ + V(Proxy, 1 << 15 | REPRESENTATION(kTaggedPtr)) \ + V(Internal, 1 << 16 | REPRESENTATION(kTagged | kUntagged)) \ \ - V(Oddball, kBoolean | kNull | kUndefined) \ - V(Signed32, kSmi | kOtherSigned32) \ - V(Number, kSigned32 | kUnsigned32 | kDouble) \ - V(String, kInternalizedString | kOtherString) \ - V(UniqueName, kSymbol | kInternalizedString) \ - V(Name, kSymbol | kString) \ - V(NumberOrString, kNumber | kString) \ - V(Object, kUndetectable | kArray | kFunction | \ - kRegExp | kOtherObject) \ - V(Receiver, kObject | kProxy) \ - V(Allocated, kDouble | kName | kReceiver) \ - V(Any, kOddball | kNumber | kAllocated | kInternal) \ - V(NonNumber, kAny - kNumber) \ - V(Detectable, kAllocated - kUndetectable) + V(Oddball, kBoolean | kNull | kUndefined) \ + V(Signed32, kSignedSmall | kOtherSigned32) \ + V(Number, kSigned32 | kUnsigned32 | kFloat) \ + V(String, kInternalizedString | kOtherString) \ + V(UniqueName, kSymbol | kInternalizedString) \ + V(Name, kSymbol | kString) \ + V(NumberOrString, kNumber | kString) \ + V(DetectableObject, kArray | kFunction | kRegExp | kOtherObject) \ + V(DetectableReceiver, kDetectableObject | kProxy) \ + V(Detectable, kDetectableReceiver | kNumber | kName) \ + V(Object, kDetectableObject | kUndetectable) \ + V(Receiver, kObject | kProxy) \ + V(NonNumber, kOddball | kName | kReceiver | kInternal) \ + V(Any, kNumber | kNonNumber) + +#define BITSET_TYPE_LIST(V) \ + MASK_BITSET_TYPE_LIST(V) \ + REPRESENTATION_BITSET_TYPE_LIST(V) \ + SEMANTIC_BITSET_TYPE_LIST(V) // struct Config { @@ -254,8 +307,9 @@ class TypeImpl : public Config::Base { typename OtherTypeImpl::TypeHandle type, Region* region); #ifdef OBJECT_PRINT - void TypePrint(); - void TypePrint(FILE* out); + enum PrintDimension { BOTH_DIMS, SEMANTIC_DIM, REPRESENTATION_DIM }; + void TypePrint(PrintDimension = BOTH_DIMS); + void TypePrint(FILE* out, PrintDimension = BOTH_DIMS); #endif private: @@ -292,6 +346,10 @@ class TypeImpl : public Config::Base { bool SlowIs(TypeImpl* that); + static bool IsInhabited(int bitset) { + return (bitset & kRepresentation) && (bitset & kSemantic); + } + int LubBitset(); // least upper bound that's a bitset int GlbBitset(); // greatest lower bound that's a bitset @@ -306,6 +364,7 @@ class TypeImpl : public Config::Base { #ifdef OBJECT_PRINT static const char* bitset_name(int bitset); + static void BitsetTypePrint(FILE* out, int bitset); #endif }; diff --git a/src/typing.cc b/src/typing.cc index a88ca8c..2a581e2 100644 --- a/src/typing.cc +++ b/src/typing.cc @@ -612,7 +612,7 @@ void AstTyper::VisitCountOperation(CountOperation* expr) { RECURSE(Visit(expr->expression())); - NarrowType(expr, Bounds(Type::Smi(zone()), Type::Number(zone()))); + NarrowType(expr, Bounds(Type::SignedSmall(zone()), Type::Number(zone()))); VariableProxy* proxy = expr->expression()->AsVariableProxy(); if (proxy != NULL && proxy->var()->IsStackAllocated()) { @@ -668,7 +668,7 @@ void AstTyper::VisitBinaryOperation(BinaryOperation* expr) { Type* upper = Type::Union( expr->left()->bounds().upper, expr->right()->bounds().upper, zone()); if (!upper->Is(Type::Signed32())) upper = Type::Signed32(zone()); - Type* lower = Type::Intersect(Type::Smi(zone()), upper, zone()); + Type* lower = Type::Intersect(Type::SignedSmall(zone()), upper, zone()); NarrowType(expr, Bounds(lower, upper)); break; } @@ -677,7 +677,8 @@ void AstTyper::VisitBinaryOperation(BinaryOperation* expr) { case Token::SAR: RECURSE(Visit(expr->left())); RECURSE(Visit(expr->right())); - NarrowType(expr, Bounds(Type::Smi(zone()), Type::Signed32(zone()))); + NarrowType(expr, + Bounds(Type::SignedSmall(zone()), Type::Signed32(zone()))); break; case Token::SHR: RECURSE(Visit(expr->left())); @@ -685,7 +686,7 @@ void AstTyper::VisitBinaryOperation(BinaryOperation* expr) { // TODO(rossberg): The upper bound would be Unsigned32, but since there // is no 'positive Smi' type for the lower bound, we use the smallest // union of Smi and Unsigned32 as upper bound instead. - NarrowType(expr, Bounds(Type::Smi(zone()), Type::Number(zone()))); + NarrowType(expr, Bounds(Type::SignedSmall(zone()), Type::Number(zone()))); break; case Token::ADD: { RECURSE(Visit(expr->left())); @@ -698,7 +699,7 @@ void AstTyper::VisitBinaryOperation(BinaryOperation* expr) { l.lower->Is(Type::String()) || r.lower->Is(Type::String()) ? Type::String(zone()) : l.lower->Is(Type::Number()) && r.lower->Is(Type::Number()) ? - Type::Smi(zone()) : Type::None(zone()); + Type::SignedSmall(zone()) : Type::None(zone()); Type* upper = l.upper->Is(Type::String()) || r.upper->Is(Type::String()) ? Type::String(zone()) : @@ -713,7 +714,7 @@ void AstTyper::VisitBinaryOperation(BinaryOperation* expr) { case Token::MOD: RECURSE(Visit(expr->left())); RECURSE(Visit(expr->right())); - NarrowType(expr, Bounds(Type::Smi(zone()), Type::Number(zone()))); + NarrowType(expr, Bounds(Type::SignedSmall(zone()), Type::Number(zone()))); break; default: UNREACHABLE(); diff --git a/test/cctest/test-types.cc b/test/cctest/test-types.cc index 57f0b27..326bd1b 100644 --- a/test/cctest/test-types.cc +++ b/test/cctest/test-types.cc @@ -34,6 +34,8 @@ template class Types { public: Types(Region* region, Isolate* isolate) : + Representation(Type::Representation(region)), + Semantic(Type::Semantic(region)), None(Type::None(region)), Any(Type::Any(region)), Oddball(Type::Oddball(region)), @@ -41,9 +43,9 @@ class Types { Null(Type::Null(region)), Undefined(Type::Undefined(region)), Number(Type::Number(region)), - Smi(Type::Smi(region)), + SignedSmall(Type::SignedSmall(region)), Signed32(Type::Signed32(region)), - Double(Type::Double(region)), + Float(Type::Float(region)), Name(Type::Name(region)), UniqueName(Type::UniqueName(region)), String(Type::String(region)), @@ -72,6 +74,8 @@ class Types { ArrayConstant2 = Type::Constant(array, region); } + TypeHandle Representation; + TypeHandle Semantic; TypeHandle None; TypeHandle Any; TypeHandle Oddball; @@ -79,9 +83,9 @@ class Types { TypeHandle Null; TypeHandle Undefined; TypeHandle Number; - TypeHandle Smi; + TypeHandle SignedSmall; TypeHandle Signed32; - TypeHandle Double; + TypeHandle Float; TypeHandle Name; TypeHandle UniqueName; TypeHandle String; @@ -236,7 +240,7 @@ struct Tests : Rep { T(Rep::ToRegion(&zone, isolate), isolate) { } - static void CheckEqual(TypeHandle type1, TypeHandle type2) { + void CheckEqual(TypeHandle type1, TypeHandle type2) { CHECK_EQ(Rep::IsBitset(type1), Rep::IsBitset(type2)); CHECK_EQ(Rep::IsClass(type1), Rep::IsClass(type2)); CHECK_EQ(Rep::IsConstant(type1), Rep::IsConstant(type2)); @@ -256,7 +260,7 @@ struct Tests : Rep { CHECK(type2->Is(type1)); } - static void CheckSub(TypeHandle type1, TypeHandle type2) { + void CheckSub(TypeHandle type1, TypeHandle type2) { CHECK(type1->Is(type2)); CHECK(!type2->Is(type1)); if (Rep::IsBitset(type1) && Rep::IsBitset(type2)) { @@ -264,7 +268,7 @@ struct Tests : Rep { } } - static void CheckUnordered(TypeHandle type1, TypeHandle type2) { + void CheckUnordered(TypeHandle type1, TypeHandle type2) { CHECK(!type1->Is(type2)); CHECK(!type2->Is(type1)); if (Rep::IsBitset(type1) && Rep::IsBitset(type2)) { @@ -272,21 +276,23 @@ struct Tests : Rep { } } - static void CheckOverlap(TypeHandle type1, TypeHandle type2) { + void CheckOverlap(TypeHandle type1, TypeHandle type2, TypeHandle mask) { CHECK(type1->Maybe(type2)); CHECK(type2->Maybe(type1)); if (Rep::IsBitset(type1) && Rep::IsBitset(type2)) { - CHECK_NE(0, Rep::AsBitset(type1) & Rep::AsBitset(type2)); + CHECK_NE(0, + Rep::AsBitset(type1) & Rep::AsBitset(type2) & Rep::AsBitset(mask)); } } - static void CheckDisjoint(TypeHandle type1, TypeHandle type2) { + void CheckDisjoint(TypeHandle type1, TypeHandle type2, TypeHandle mask) { CHECK(!type1->Is(type2)); CHECK(!type2->Is(type1)); CHECK(!type1->Maybe(type2)); CHECK(!type2->Maybe(type1)); if (Rep::IsBitset(type1) && Rep::IsBitset(type2)) { - CHECK_EQ(0, Rep::AsBitset(type1) & Rep::AsBitset(type2)); + CHECK_EQ(0, + Rep::AsBitset(type1) & Rep::AsBitset(type2) & Rep::AsBitset(mask)); } } @@ -300,10 +306,12 @@ struct Tests : Rep { CHECK(this->IsBitset(T.Union(T.String, T.Receiver))); CHECK_EQ(0, this->AsBitset(T.None)); - CHECK_EQ(this->AsBitset(T.Number) | this->AsBitset(T.String), - this->AsBitset(T.Union(T.String, T.Number))); - CHECK_EQ(this->AsBitset(T.Receiver), - this->AsBitset(T.Union(T.Receiver, T.Object))); + CHECK_EQ( + this->AsBitset(T.Number) | this->AsBitset(T.String), + this->AsBitset(T.Union(T.String, T.Number))); + CHECK_EQ( + this->AsBitset(T.Receiver), + this->AsBitset(T.Union(T.Receiver, T.Object))); } void Class() { @@ -352,12 +360,12 @@ struct Tests : Rep { CheckUnordered(T.Boolean, T.Undefined); CheckSub(T.Number, T.Any); - CheckSub(T.Smi, T.Number); + CheckSub(T.SignedSmall, T.Number); CheckSub(T.Signed32, T.Number); - CheckSub(T.Double, T.Number); - CheckSub(T.Smi, T.Signed32); - CheckUnordered(T.Smi, T.Double); - CheckUnordered(T.Signed32, T.Double); + CheckSub(T.Float, T.Number); + CheckSub(T.SignedSmall, T.Signed32); + CheckUnordered(T.SignedSmall, T.Float); + CheckUnordered(T.Signed32, T.Float); CheckSub(T.Name, T.Any); CheckSub(T.UniqueName, T.Any); @@ -391,7 +399,7 @@ struct Tests : Rep { CheckSub(T.ArrayClass, T.Object); CheckUnordered(T.ObjectClass, T.ArrayClass); - CheckSub(T.SmiConstant, T.Smi); + CheckSub(T.SmiConstant, T.SignedSmall); CheckSub(T.SmiConstant, T.Signed32); CheckSub(T.SmiConstant, T.Number); CheckSub(T.ObjectConstant1, T.Object); @@ -409,71 +417,71 @@ struct Tests : Rep { } void Maybe() { - CheckOverlap(T.Any, T.Any); - CheckOverlap(T.Object, T.Object); - - CheckOverlap(T.Oddball, T.Any); - CheckOverlap(T.Boolean, T.Oddball); - CheckOverlap(T.Null, T.Oddball); - CheckOverlap(T.Undefined, T.Oddball); - CheckDisjoint(T.Boolean, T.Null); - CheckDisjoint(T.Undefined, T.Null); - CheckDisjoint(T.Boolean, T.Undefined); - - CheckOverlap(T.Number, T.Any); - CheckOverlap(T.Smi, T.Number); - CheckOverlap(T.Double, T.Number); - CheckDisjoint(T.Signed32, T.Double); - - CheckOverlap(T.Name, T.Any); - CheckOverlap(T.UniqueName, T.Any); - CheckOverlap(T.UniqueName, T.Name); - CheckOverlap(T.String, T.Name); - CheckOverlap(T.InternalizedString, T.String); - CheckOverlap(T.InternalizedString, T.UniqueName); - CheckOverlap(T.InternalizedString, T.Name); - CheckOverlap(T.Symbol, T.UniqueName); - CheckOverlap(T.Symbol, T.Name); - CheckOverlap(T.String, T.UniqueName); - CheckDisjoint(T.String, T.Symbol); - CheckDisjoint(T.InternalizedString, T.Symbol); - - CheckOverlap(T.Receiver, T.Any); - CheckOverlap(T.Object, T.Any); - CheckOverlap(T.Object, T.Receiver); - CheckOverlap(T.Array, T.Object); - CheckOverlap(T.Function, T.Object); - CheckOverlap(T.Proxy, T.Receiver); - CheckDisjoint(T.Object, T.Proxy); - CheckDisjoint(T.Array, T.Function); - - CheckOverlap(T.ObjectClass, T.Any); - CheckOverlap(T.ObjectConstant1, T.Any); - - CheckOverlap(T.ObjectClass, T.Object); - CheckOverlap(T.ArrayClass, T.Object); - CheckOverlap(T.ObjectClass, T.ObjectClass); - CheckOverlap(T.ArrayClass, T.ArrayClass); - CheckDisjoint(T.ObjectClass, T.ArrayClass); - - CheckOverlap(T.SmiConstant, T.Smi); - CheckOverlap(T.SmiConstant, T.Signed32); - CheckOverlap(T.SmiConstant, T.Number); - CheckDisjoint(T.SmiConstant, T.Double); - CheckOverlap(T.ObjectConstant1, T.Object); - CheckOverlap(T.ObjectConstant2, T.Object); - CheckOverlap(T.ArrayConstant1, T.Object); - CheckOverlap(T.ArrayConstant1, T.Array); - CheckOverlap(T.ArrayConstant1, T.ArrayConstant2); - CheckOverlap(T.ObjectConstant1, T.ObjectConstant1); - CheckDisjoint(T.ObjectConstant1, T.ObjectConstant2); - CheckDisjoint(T.ObjectConstant1, T.ArrayConstant1); - - CheckDisjoint(T.ObjectConstant1, T.ObjectClass); - CheckDisjoint(T.ObjectConstant2, T.ObjectClass); - CheckDisjoint(T.ObjectConstant1, T.ArrayClass); - CheckDisjoint(T.ObjectConstant2, T.ArrayClass); - CheckDisjoint(T.ArrayConstant1, T.ObjectClass); + CheckOverlap(T.Any, T.Any, T.Semantic); + CheckOverlap(T.Object, T.Object, T.Semantic); + + CheckOverlap(T.Oddball, T.Any, T.Semantic); + CheckOverlap(T.Boolean, T.Oddball, T.Semantic); + CheckOverlap(T.Null, T.Oddball, T.Semantic); + CheckOverlap(T.Undefined, T.Oddball, T.Semantic); + CheckDisjoint(T.Boolean, T.Null, T.Semantic); + CheckDisjoint(T.Undefined, T.Null, T.Semantic); + CheckDisjoint(T.Boolean, T.Undefined, T.Semantic); + + CheckOverlap(T.Number, T.Any, T.Semantic); + CheckOverlap(T.SignedSmall, T.Number, T.Semantic); + CheckOverlap(T.Float, T.Number, T.Semantic); + CheckDisjoint(T.Signed32, T.Float, T.Semantic); + + CheckOverlap(T.Name, T.Any, T.Semantic); + CheckOverlap(T.UniqueName, T.Any, T.Semantic); + CheckOverlap(T.UniqueName, T.Name, T.Semantic); + CheckOverlap(T.String, T.Name, T.Semantic); + CheckOverlap(T.InternalizedString, T.String, T.Semantic); + CheckOverlap(T.InternalizedString, T.UniqueName, T.Semantic); + CheckOverlap(T.InternalizedString, T.Name, T.Semantic); + CheckOverlap(T.Symbol, T.UniqueName, T.Semantic); + CheckOverlap(T.Symbol, T.Name, T.Semantic); + CheckOverlap(T.String, T.UniqueName, T.Semantic); + CheckDisjoint(T.String, T.Symbol, T.Semantic); + CheckDisjoint(T.InternalizedString, T.Symbol, T.Semantic); + + CheckOverlap(T.Receiver, T.Any, T.Semantic); + CheckOverlap(T.Object, T.Any, T.Semantic); + CheckOverlap(T.Object, T.Receiver, T.Semantic); + CheckOverlap(T.Array, T.Object, T.Semantic); + CheckOverlap(T.Function, T.Object, T.Semantic); + CheckOverlap(T.Proxy, T.Receiver, T.Semantic); + CheckDisjoint(T.Object, T.Proxy, T.Semantic); + CheckDisjoint(T.Array, T.Function, T.Semantic); + + CheckOverlap(T.ObjectClass, T.Any, T.Semantic); + CheckOverlap(T.ObjectConstant1, T.Any, T.Semantic); + + CheckOverlap(T.ObjectClass, T.Object, T.Semantic); + CheckOverlap(T.ArrayClass, T.Object, T.Semantic); + CheckOverlap(T.ObjectClass, T.ObjectClass, T.Semantic); + CheckOverlap(T.ArrayClass, T.ArrayClass, T.Semantic); + CheckDisjoint(T.ObjectClass, T.ArrayClass, T.Semantic); + + CheckOverlap(T.SmiConstant, T.SignedSmall, T.Semantic); + CheckOverlap(T.SmiConstant, T.Signed32, T.Semantic); + CheckOverlap(T.SmiConstant, T.Number, T.Semantic); + CheckDisjoint(T.SmiConstant, T.Float, T.Semantic); + CheckOverlap(T.ObjectConstant1, T.Object, T.Semantic); + CheckOverlap(T.ObjectConstant2, T.Object, T.Semantic); + CheckOverlap(T.ArrayConstant1, T.Object, T.Semantic); + CheckOverlap(T.ArrayConstant1, T.Array, T.Semantic); + CheckOverlap(T.ArrayConstant1, T.ArrayConstant2, T.Semantic); + CheckOverlap(T.ObjectConstant1, T.ObjectConstant1, T.Semantic); + CheckDisjoint(T.ObjectConstant1, T.ObjectConstant2, T.Semantic); + CheckDisjoint(T.ObjectConstant1, T.ArrayConstant1, T.Semantic); + + CheckDisjoint(T.ObjectConstant1, T.ObjectClass, T.Semantic); + CheckDisjoint(T.ObjectConstant2, T.ObjectClass, T.Semantic); + CheckDisjoint(T.ObjectConstant1, T.ArrayClass, T.Semantic); + CheckDisjoint(T.ObjectConstant2, T.ArrayClass, T.Semantic); + CheckDisjoint(T.ArrayConstant1, T.ObjectClass, T.Semantic); } void Union() { @@ -498,8 +506,8 @@ struct Tests : Rep { CheckSub(T.ArrayClass, T.Union(T.ObjectClass, T.ArrayClass)); CheckSub(T.Union(T.ObjectClass, T.ArrayClass), T.Object); CheckUnordered(T.Union(T.ObjectClass, T.ArrayClass), T.Array); - CheckOverlap(T.Union(T.ObjectClass, T.ArrayClass), T.Array); - CheckDisjoint(T.Union(T.ObjectClass, T.ArrayClass), T.Number); + CheckOverlap(T.Union(T.ObjectClass, T.ArrayClass), T.Array, T.Semantic); + CheckDisjoint(T.Union(T.ObjectClass, T.ArrayClass), T.Number, T.Semantic); // Constant-constant CHECK(this->IsConstant(T.Union(T.ObjectConstant1, T.ObjectConstant1))); @@ -520,11 +528,16 @@ struct Tests : Rep { CheckUnordered( T.Union(T.ObjectConstant1, T.ObjectConstant2), T.ObjectClass); CheckUnordered(T.Union(T.ObjectConstant1, T.ArrayConstant1), T.Array); - CheckOverlap(T.Union(T.ObjectConstant1, T.ArrayConstant1), T.Array); CheckOverlap( - T.Union(T.ObjectConstant1, T.ArrayConstant1), T.ArrayConstant2); - CheckDisjoint(T.Union(T.ObjectConstant1, T.ArrayConstant1), T.Number); - CheckDisjoint(T.Union(T.ObjectConstant1, T.ArrayConstant1), T.ObjectClass); + T.Union(T.ObjectConstant1, T.ArrayConstant1), T.Array, T.Semantic); + CheckOverlap( + T.Union(T.ObjectConstant1, T.ArrayConstant1), T.ArrayConstant2, + T.Semantic); + CheckDisjoint( + T.Union(T.ObjectConstant1, T.ArrayConstant1), T.Number, T.Semantic); + CheckDisjoint( + T.Union(T.ObjectConstant1, T.ArrayConstant1), T.ObjectClass, + T.Semantic); // Bitset-class CHECK(this->IsBitset(T.Union(T.ObjectClass, T.Object))); @@ -533,11 +546,12 @@ struct Tests : Rep { CheckEqual(T.Union(T.ObjectClass, T.Object), T.Object); CheckSub(T.None, T.Union(T.ObjectClass, T.Number)); CheckSub(T.Union(T.ObjectClass, T.Number), T.Any); - CheckSub(T.Union(T.ObjectClass, T.Smi), T.Union(T.Object, T.Number)); + CheckSub( + T.Union(T.ObjectClass, T.SignedSmall), T.Union(T.Object, T.Number)); CheckSub(T.Union(T.ObjectClass, T.Array), T.Object); CheckUnordered(T.Union(T.ObjectClass, T.String), T.Array); - CheckOverlap(T.Union(T.ObjectClass, T.String), T.Object); - CheckDisjoint(T.Union(T.ObjectClass, T.String), T.Number); + CheckOverlap(T.Union(T.ObjectClass, T.String), T.Object, T.Semantic); + CheckDisjoint(T.Union(T.ObjectClass, T.String), T.Number, T.Semantic); // Bitset-constant CHECK(this->IsBitset(T.Union(T.SmiConstant, T.Number))); @@ -552,8 +566,8 @@ struct Tests : Rep { T.Union(T.ObjectConstant1, T.Signed32), T.Union(T.Object, T.Number)); CheckSub(T.Union(T.ObjectConstant1, T.Array), T.Object); CheckUnordered(T.Union(T.ObjectConstant1, T.String), T.Array); - CheckOverlap(T.Union(T.ObjectConstant1, T.String), T.Object); - CheckDisjoint(T.Union(T.ObjectConstant1, T.String), T.Number); + CheckOverlap(T.Union(T.ObjectConstant1, T.String), T.Object, T.Semantic); + CheckDisjoint(T.Union(T.ObjectConstant1, T.String), T.Number, T.Semantic); CheckEqual(T.Union(T.Signed32, T.Signed32Constant), T.Signed32); // Class-constant @@ -569,8 +583,11 @@ struct Tests : Rep { CheckSub( T.Union(T.ObjectConstant1, T.ArrayClass), T.Union(T.Array, T.Object)); CheckUnordered(T.Union(T.ObjectConstant1, T.ArrayClass), T.ArrayConstant1); - CheckDisjoint(T.Union(T.ObjectConstant1, T.ArrayClass), T.ObjectConstant2); - CheckDisjoint(T.Union(T.ObjectConstant1, T.ArrayClass), T.ObjectClass); + CheckDisjoint( + T.Union(T.ObjectConstant1, T.ArrayClass), T.ObjectConstant2, + T.Semantic); + CheckDisjoint( + T.Union(T.ObjectConstant1, T.ArrayClass), T.ObjectClass, T.Semantic); // Bitset-union CHECK(this->IsBitset( @@ -585,19 +602,19 @@ struct Tests : Rep { T.Union(T.Union(T.ArrayClass, T.ObjectConstant1), T.Number), T.Union(T.ObjectConstant1, T.Union(T.Number, T.ArrayClass))); CheckSub( - T.Double, + T.Float, T.Union(T.Union(T.ArrayClass, T.ObjectConstant1), T.Number)); CheckSub( T.ObjectConstant1, - T.Union(T.Union(T.ArrayClass, T.ObjectConstant1), T.Double)); + T.Union(T.Union(T.ArrayClass, T.ObjectConstant1), T.Float)); CheckSub( T.None, - T.Union(T.Union(T.ArrayClass, T.ObjectConstant1), T.Double)); + T.Union(T.Union(T.ArrayClass, T.ObjectConstant1), T.Float)); CheckSub( - T.Union(T.Union(T.ArrayClass, T.ObjectConstant1), T.Double), + T.Union(T.Union(T.ArrayClass, T.ObjectConstant1), T.Float), T.Any); CheckSub( - T.Union(T.Union(T.ArrayClass, T.ObjectConstant1), T.Double), + T.Union(T.Union(T.ArrayClass, T.ObjectConstant1), T.Float), T.Union(T.ObjectConstant1, T.Union(T.Number, T.ArrayClass))); // Class-union @@ -661,7 +678,9 @@ struct Tests : Rep { T.Union(T.ObjectConstant1, T.ObjectConstant2), T.ArrayConstant1)); CheckEqual( - T.Union(T.Union(T.Number, T.ArrayClass), T.Union(T.Smi, T.Array)), + T.Union( + T.Union(T.Number, T.ArrayClass), + T.Union(T.SignedSmall, T.Array)), T.Union(T.Number, T.Array)); } @@ -672,7 +691,7 @@ struct Tests : Rep { CHECK(this->IsBitset(T.Intersect(T.Any, T.None))); CheckEqual(T.Intersect(T.None, T.Number), T.None); - CheckEqual(T.Intersect(T.Object, T.Proxy), T.None); + CheckSub(T.Intersect(T.Object, T.Proxy), T.Representation); CheckEqual(T.Intersect(T.Name, T.String), T.Intersect(T.String, T.Name)); CheckEqual(T.Intersect(T.UniqueName, T.String), T.InternalizedString); @@ -699,15 +718,15 @@ struct Tests : Rep { CHECK(this->IsBitset(T.Intersect(T.ObjectClass, T.Number))); CheckEqual(T.Intersect(T.ObjectClass, T.Object), T.ObjectClass); - CheckEqual(T.Intersect(T.ObjectClass, T.Array), T.None); - CheckEqual(T.Intersect(T.ObjectClass, T.Number), T.None); + CheckSub(T.Intersect(T.ObjectClass, T.Array), T.Representation); + CheckSub(T.Intersect(T.ObjectClass, T.Number), T.Representation); // Bitset-constant - CHECK(this->IsBitset(T.Intersect(T.Smi, T.Number))); + CHECK(this->IsBitset(T.Intersect(T.SignedSmall, T.Number))); CHECK(this->IsConstant(T.Intersect(T.SmiConstant, T.Number))); CHECK(this->IsConstant(T.Intersect(T.ObjectConstant1, T.Object))); - CheckEqual(T.Intersect(T.Smi, T.Number), T.Smi); + CheckEqual(T.Intersect(T.SignedSmall, T.Number), T.SignedSmall); CheckEqual(T.Intersect(T.SmiConstant, T.Number), T.SmiConstant); CheckEqual(T.Intersect(T.ObjectConstant1, T.Object), T.ObjectConstant1); @@ -778,8 +797,8 @@ struct Tests : Rep { CheckEqual( T.Intersect( T.Union(T.Number, T.ArrayClass), - T.Union(T.Smi, T.Array)), - T.Union(T.Smi, T.ArrayClass)); + T.Union(T.SignedSmall, T.Array)), + T.Union(T.SignedSmall, T.ArrayClass)); CheckEqual( T.Intersect( T.Union(T.Number, T.ObjectClass),