Chromium Code Reviews| Index: src/types.h |
| diff --git a/src/types.h b/src/types.h |
| index 48b39335b63dcd5c4da0f468f30afd4efaa409d4..d9dc1e915c691e438361b598a340c62fc600a881 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,65 +72,121 @@ 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 |
| -// bitsets via smis. Class is a heap pointer to the respective map. Only |
| -// Constant's, or unions containing Class'es or Constant's, require allocation. |
| +// bitsets. Class is a heap pointer to the respective map. Only Constant's, or |
| +// unions containing Class'es or Constant's, currently require allocation. |
| // Note that the bitset representation is closed under both Union and Intersect. |
| // |
| -// The type representation is heap-allocated, so cannot (currently) be used in |
| -// a concurrent compilation context. |
| - |
| - |
| -#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) \ |
| +// There are two type representations, using different allocation: |
| +// |
| +// - class Type (zone-allocated, for compiler and concurrent compilation) |
| +// - class HeapType (heap-allocated, for persistent types) |
| +// |
| +// Both provide the same API, and the Convert method can be used to interconvert |
| +// them. |
| + |
| + |
| +#define MASK_BITSET_TYPE_LIST(V) \ |
| + V(Representation, static_cast<int>(0xff800000)) \ |
| + V(Semantic, static_cast<int>(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 */ \ |
|
Michael Starzinger
2014/03/04 15:02:25
I would be fine with this. If either Benedikt or S
Sven Panne
2014/03/05 07:22:36
As already discussed yesterday, I consider this si
Benedikt Meurer
2014/03/05 07:28:07
I agree. We should not introduce hacks like this u
rossberg
2014/03/14 10:37:37
Michael yesterday (after you had left) expressed v
Michael Starzinger
2014/03/14 10:49:36
So just to clarify: My strong disagreement is agai
|
| + \ |
| + 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 { |
| @@ -248,8 +306,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: |
| @@ -286,6 +345,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 |
| @@ -300,6 +363,7 @@ class TypeImpl : public Config::Base { |
| #ifdef OBJECT_PRINT |
| static const char* bitset_name(int bitset); |
| + static void BitsetTypePrint(FILE* out, int bitset); |
| #endif |
| }; |