Chromium Code Reviews| Index: src/types.h |
| diff --git a/src/types.h b/src/types.h |
| index cca8b3167b4bb9b86773d7fcf40959490a9164f0..2f96c333f2f0446f991a845d855563578c660b41 100644 |
| --- a/src/types.h |
| +++ b/src/types.h |
| @@ -5,6 +5,7 @@ |
| #ifndef V8_TYPES_H_ |
| #define V8_TYPES_H_ |
| +#include "src/conversions.h" |
| #include "src/factory.h" |
| #include "src/handles.h" |
| #include "src/ostreams.h" |
| @@ -112,8 +113,8 @@ namespace internal { |
| // PROPERTIES |
| // |
| // Various formal properties hold for constructors, operators, and predicates |
| -// over types. For example, constructors are injective, subtyping is a complete |
| -// partial order, union and intersection satisfy the usual algebraic properties. |
| +// over types. For example, constructors are injective and subtyping is a |
| +// complete partial order. |
| // |
| // See test/cctest/test-types.cc for a comprehensive executable specification, |
| // especially with respect to the properties of the more exotic 'temporal' |
| @@ -208,11 +209,35 @@ namespace internal { |
| kUndefined | kInternal) \ |
| V(Any, -1) |
| -#define BITSET_TYPE_LIST(V) \ |
| - MASK_BITSET_TYPE_LIST(V) \ |
| +/* |
| + * The following diagrams show how integers (in the mathematical sense) are |
| + * divided among the different atomic numerical types. |
| + * |
| + * If SmiValuesAre31Bits(): |
| + * |
| + * ON OS32 OSS US OU31 OU32 ON |
| + * ______[_______[_______[_______[_______[_______[_______ |
| + * -2^31 -2^30 0 2^30 2^31 2^32 |
| + * |
| + * Otherwise: |
|
rossberg
2014/09/10 15:44:15
Nit: indentation off
neis1
2014/09/11 12:58:12
Done.
|
| + * |
| + * ON OSS US OU32 ON |
| + * ______[_______________[_______________[_______[_______ |
| + * -2^31 0 2^31 2^32 |
| + * |
| + * |
| + * E.g., OtherUnsigned32 (OU32) covers all integers from 2^31 to 2^32-1. |
| + * |
| + */ |
| + |
| +#define PROPER_BITSET_TYPE_LIST(V) \ |
| REPRESENTATION_BITSET_TYPE_LIST(V) \ |
| SEMANTIC_BITSET_TYPE_LIST(V) |
| +#define BITSET_TYPE_LIST(V) \ |
| + MASK_BITSET_TYPE_LIST(V) \ |
| + PROPER_BITSET_TYPE_LIST(V) |
| + |
| // ----------------------------------------------------------------------------- |
| // The abstract Type class, parameterized over the low-level representation. |
| @@ -279,17 +304,17 @@ class TypeImpl : public Config::Base { |
| static TypeHandle type(Region* region) { \ |
| return BitsetType::New(BitsetType::k##type, region); \ |
| } |
| - BITSET_TYPE_LIST(DEFINE_TYPE_CONSTRUCTOR) |
| + PROPER_BITSET_TYPE_LIST(DEFINE_TYPE_CONSTRUCTOR) |
| #undef DEFINE_TYPE_CONSTRUCTOR |
| static TypeHandle Class(i::Handle<i::Map> map, Region* region) { |
| return ClassType::New(map, region); |
| } |
| static TypeHandle Constant(i::Handle<i::Object> value, Region* region) { |
| - // TODO(neis): Return RangeType for numerical values. |
| return ConstantType::New(value, region); |
| } |
| - static TypeHandle Range(double min, double max, Region* region) { |
| + static TypeHandle Range( |
| + i::Handle<i::Object> min, i::Handle<i::Object> max, Region* region) { |
| return RangeType::New(min, max, region); |
| } |
| static TypeHandle Context(TypeHandle outer, Region* region) { |
| @@ -357,7 +382,7 @@ class TypeImpl : public Config::Base { |
| template<class TypeHandle> |
| bool Equals(TypeHandle that) { return this->Equals(*that); } |
| - // Equivalent to Constant(value)->Is(this), but avoiding allocation. |
| + // Equivalent to Constant(val)->Is(this), but avoiding allocation. |
| bool Contains(i::Object* val); |
| bool Contains(i::Handle<i::Object> val) { return this->Contains(*val); } |
| @@ -466,16 +491,42 @@ class TypeImpl : public Config::Base { |
| int BitsetGlb() { return BitsetType::Glb(this); } |
| int BitsetLub() { return BitsetType::Lub(this); } |
| - int InherentBitsetLub() { return BitsetType::InherentLub(this); } |
| bool SlowIs(TypeImpl* that); |
| - TypeHandle Rebound(int bitset, Region* region); |
| - int BoundBy(TypeImpl* that); |
| - int IndexInUnion(int bound, UnionHandle unioned, int current_size); |
| - static int ExtendUnion( |
| - UnionHandle unioned, int current_size, TypeHandle t, |
| - TypeHandle other, bool is_intersect, Region* region); |
| + 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()); |
| + } |
| + |
| + struct Limits { |
| + i::Handle<i::Object> min; |
| + i::Handle<i::Object> max; |
| + Limits(i::Handle<i::Object> min, i::Handle<i::Object> max) : |
| + min(min), max(max) {} |
| + explicit Limits(RangeType* range) : |
| + min(range->MinV()), max(range->MaxV()) {} |
| + }; |
| + |
| + static Limits intersect(Limits lhs, Limits rhs); |
| + static Limits union_(Limits lhs, Limits rhs); |
| + static bool overlap(RangeType* lhs, RangeType* rhs); |
| + static bool contains(RangeType* lhs, RangeType* rhs); |
| + static bool contains(RangeType* range, i::Object* val); |
| + |
| + RangeType* GetRange(); |
| + static int UpdateRange( |
| + RangeHandle type, UnionHandle result, int size, Region* region); |
| + |
| + bool SimplyEquals(TypeImpl* that); |
| + static int AddToUnion( |
| + TypeHandle type, UnionHandle result, int size, Region* region); |
| + static int IntersectAux( |
| + TypeHandle type, TypeHandle other, |
| + UnionHandle result, int size, Region* region); |
| + static TypeHandle NormalizeUnion(UnionHandle unioned, int size); |
| }; |
| @@ -497,9 +548,11 @@ class TypeImpl<Config>::BitsetType : public TypeImpl<Config> { |
| int Bitset() { return Config::as_bitset(this); } |
| static TypeImpl* New(int bitset) { |
| + DCHECK(bitset == kNone || IsInhabited(bitset)); |
| return static_cast<BitsetType*>(Config::from_bitset(bitset)); |
| } |
| static TypeHandle New(int bitset, Region* region) { |
| + DCHECK(bitset == kNone || IsInhabited(bitset)); |
| return Config::from_bitset(bitset, region); |
| } |
| @@ -518,12 +571,14 @@ class TypeImpl<Config>::BitsetType : public TypeImpl<Config> { |
| static int Lub(int32_t value); |
| static int Lub(uint32_t value); |
| static int Lub(i::Map* map); |
| - static int Lub(double min, double max); |
| - static int InherentLub(TypeImpl* type); |
| + static int Lub(Limits lim); |
| + static double Min(int bitset); |
| static const char* Name(int bitset); |
| static void Print(OStream& os, int bitset); // NOLINT |
| - using TypeImpl::PrintTo; |
| +#ifdef DEBUG |
| + static void Print(int bitset); |
| +#endif |
| }; |
| @@ -609,36 +664,21 @@ class TypeImpl<Config>::UnionType : public StructuralType { |
| template<class Config> |
| class TypeImpl<Config>::ClassType : public StructuralType { |
| public: |
| - TypeHandle Bound(Region* region) { |
| - return Config::is_class(this) |
| - ? BitsetType::New(BitsetType::Lub(*Config::as_class(this)), region) |
| - : this->Get(0); |
| - } |
| i::Handle<i::Map> Map() { |
| return Config::is_class(this) |
| ? Config::as_class(this) |
| - : this->template GetValue<i::Map>(1); |
| - } |
| - |
| - static ClassHandle New( |
| - i::Handle<i::Map> map, TypeHandle bound, Region* region) { |
| - DCHECK(BitsetType::Is(bound->AsBitset(), BitsetType::Lub(*map))); |
| - ClassHandle type = Config::template cast<ClassType>( |
| - StructuralType::New(StructuralType::kClassTag, 2, region)); |
| - type->Set(0, bound); |
| - type->SetValue(1, map); |
| - return type; |
| + : this->template GetValue<i::Map>(0); |
| } |
| static ClassHandle New(i::Handle<i::Map> map, Region* region) { |
| ClassHandle type = |
| Config::template cast<ClassType>(Config::from_class(map, region)); |
| - if (type->IsClass()) { |
| - return type; |
| - } else { |
| - TypeHandle bound = BitsetType::New(BitsetType::Lub(*map), region); |
| - return New(map, bound, region); |
| + if (!type->IsClass()) { |
| + type = Config::template cast<ClassType>( |
| + StructuralType::New(StructuralType::kClassTag, 1, region)); |
|
rossberg
2014/09/10 15:44:15
Nit: style guide wants +4 indentation for line con
neis1
2014/09/11 12:58:12
Done.
|
| + type->SetValue(0, map); |
| } |
| + return type; |
| } |
| static ClassType* cast(TypeImpl* type) { |
| @@ -654,22 +694,15 @@ class TypeImpl<Config>::ClassType : public StructuralType { |
| template<class Config> |
| class TypeImpl<Config>::ConstantType : public StructuralType { |
| public: |
| - TypeHandle Bound() { return this->Get(0); } |
| - i::Handle<i::Object> Value() { return this->template GetValue<i::Object>(1); } |
| - |
| - static ConstantHandle New( |
| - i::Handle<i::Object> value, TypeHandle bound, Region* region) { |
| - DCHECK(BitsetType::Is(bound->AsBitset(), BitsetType::Lub(*value))); |
| - ConstantHandle type = Config::template cast<ConstantType>( |
| - StructuralType::New(StructuralType::kConstantTag, 2, region)); |
| - type->Set(0, bound); |
| - type->SetValue(1, value); |
| - return type; |
| + i::Handle<i::Object> Value() { |
| + return this->template GetValue<i::Object>(0); |
|
rossberg
2014/09/10 15:44:15
Nit: probably fits on previous line
neis1
2014/09/11 12:58:12
Done.
|
| } |
| static ConstantHandle New(i::Handle<i::Object> value, Region* region) { |
| - TypeHandle bound = BitsetType::New(BitsetType::Lub(*value), region); |
| - return New(value, bound, region); |
| + ConstantHandle type = Config::template cast<ConstantType>( |
| + StructuralType::New(StructuralType::kConstantTag, 1, region)); |
| + type->SetValue(0, value); |
| + return type; |
| } |
| static ConstantType* cast(TypeImpl* type) { |
| @@ -681,31 +714,35 @@ class TypeImpl<Config>::ConstantType : public StructuralType { |
| // ----------------------------------------------------------------------------- |
| // Range types. |
| +// They represent continuous integer intervals in the form of a minimum |
|
rossberg
2014/09/10 15:44:15
This should go to the top, along with the other ex
neis1
2014/09/11 12:58:12
Done.
|
| +// and a maximum value. Either value might be an infinity. |
| +// |
| +// Constant(v) is considered a subtype of Range(x..y) if v happens to be an |
| +// integer between x and y. |
| template<class Config> |
| class TypeImpl<Config>::RangeType : public StructuralType { |
| public: |
| - TypeHandle Bound() { return this->Get(0); } |
| - double Min() { return this->template GetValue<i::HeapNumber>(1)->value(); } |
| - double Max() { return this->template GetValue<i::HeapNumber>(2)->value(); } |
| + i::Handle<i::Object> MinV() { return this->template GetValue<i::Object>(0); } |
| + i::Handle<i::Object> MaxV() { return this->template GetValue<i::Object>(1); } |
| + double Min() { return MinV()->Number(); } |
| + double Max() { return MaxV()->Number(); } |
|
rossberg
2014/09/10 15:44:15
Since we call the method to get a numeric value fr
neis1
2014/09/11 12:58:12
Not sure I'm following. Are you suggesting to exp
rossberg
2014/09/15 15:58:29
The latter. It's more consistent with our naming e
neis1
2014/09/16 10:03:59
But less consistent with the naming here, such as
rossberg
2014/09/16 14:04:40
OK, fair enough. Actually, I'd say, just remove th
neis1
2014/09/18 13:05:18
Done.
|
| static RangeHandle New( |
| - double min, double max, TypeHandle bound, Region* region) { |
| - DCHECK(BitsetType::Is(bound->AsBitset(), BitsetType::Lub(min, max))); |
| + i::Handle<i::Object> min, i::Handle<i::Object> max, Region* region) { |
| + DCHECK(min->Number() <= max->Number()); |
| RangeHandle type = Config::template cast<RangeType>( |
| - StructuralType::New(StructuralType::kRangeTag, 3, region)); |
| - type->Set(0, bound); |
| - Factory* factory = Config::isolate(region)->factory(); |
| - Handle<HeapNumber> minV = factory->NewHeapNumber(min); |
| - Handle<HeapNumber> maxV = factory->NewHeapNumber(max); |
| - type->SetValue(1, minV); |
| - type->SetValue(2, maxV); |
| + StructuralType::New(StructuralType::kRangeTag, 2, region)); |
| + type->SetValue(0, min); |
| + type->SetValue(1, max); |
| +#ifdef DEBUG |
|
rossberg
2014/09/10 15:44:15
Debugging left-overs?
neis1
2014/09/11 12:58:12
Done.
|
| + type->Print(); |
| +#endif |
| return type; |
| } |
| - static RangeHandle New(double min, double max, Region* region) { |
| - TypeHandle bound = BitsetType::New(BitsetType::Lub(min, max), region); |
| - return New(min, max, bound, region); |
| + static RangeHandle New(Limits lim, Region* region) { |
| + return New(lim.min, lim.max, region); |
| } |
| static RangeType* cast(TypeImpl* type) { |
| @@ -721,25 +758,15 @@ class TypeImpl<Config>::RangeType : public StructuralType { |
| template<class Config> |
| class TypeImpl<Config>::ContextType : public StructuralType { |
| public: |
| - TypeHandle Bound() { return this->Get(0); } |
| - TypeHandle Outer() { return this->Get(1); } |
| + TypeHandle Outer() { return this->Get(0); } |
| - static ContextHandle New(TypeHandle outer, TypeHandle bound, Region* region) { |
| - DCHECK(BitsetType::Is( |
| - bound->AsBitset(), BitsetType::kInternal & BitsetType::kTaggedPtr)); |
| + static ContextHandle New(TypeHandle outer, Region* region) { |
| ContextHandle type = Config::template cast<ContextType>( |
| - StructuralType::New(StructuralType::kContextTag, 2, region)); |
| - type->Set(0, bound); |
| - type->Set(1, outer); |
| + StructuralType::New(StructuralType::kContextTag, 1, region)); |
| + type->Set(0, outer); |
| return type; |
| } |
| - static ContextHandle New(TypeHandle outer, Region* region) { |
| - TypeHandle bound = BitsetType::New( |
| - BitsetType::kInternal & BitsetType::kTaggedPtr, region); |
| - return New(outer, bound, region); |
| - } |
| - |
| static ContextType* cast(TypeImpl* type) { |
| DCHECK(type->IsContext()); |
| return static_cast<ContextType*>(type); |
| @@ -753,23 +780,15 @@ class TypeImpl<Config>::ContextType : public StructuralType { |
| template<class Config> |
| class TypeImpl<Config>::ArrayType : public StructuralType { |
| public: |
| - TypeHandle Bound() { return this->Get(0); } |
| - TypeHandle Element() { return this->Get(1); } |
| + TypeHandle Element() { return this->Get(0); } |
| - static ArrayHandle New(TypeHandle element, TypeHandle bound, Region* region) { |
| - DCHECK(BitsetType::Is(bound->AsBitset(), BitsetType::kArray)); |
| + static ArrayHandle New(TypeHandle element, Region* region) { |
| ArrayHandle type = Config::template cast<ArrayType>( |
| - StructuralType::New(StructuralType::kArrayTag, 2, region)); |
| - type->Set(0, bound); |
| - type->Set(1, element); |
| + StructuralType::New(StructuralType::kArrayTag, 1, region)); |
| + type->Set(0, element); |
| return type; |
| } |
| - static ArrayHandle New(TypeHandle element, Region* region) { |
| - TypeHandle bound = BitsetType::New(BitsetType::kArray, region); |
| - return New(element, bound, region); |
| - } |
| - |
| static ArrayType* cast(TypeImpl* type) { |
| DCHECK(type->IsArray()); |
| return static_cast<ArrayType*>(type); |
| @@ -783,32 +802,22 @@ class TypeImpl<Config>::ArrayType : public StructuralType { |
| template<class Config> |
| class TypeImpl<Config>::FunctionType : public StructuralType { |
| public: |
| - int Arity() { return this->Length() - 3; } |
| - TypeHandle Bound() { return this->Get(0); } |
| - TypeHandle Result() { return this->Get(1); } |
| - TypeHandle Receiver() { return this->Get(2); } |
| - TypeHandle Parameter(int i) { return this->Get(3 + i); } |
| + int Arity() { return this->Length() - 2; } |
| + TypeHandle Result() { return this->Get(0); } |
| + TypeHandle Receiver() { return this->Get(1); } |
| + TypeHandle Parameter(int i) { return this->Get(2 + i); } |
| - void InitParameter(int i, TypeHandle type) { this->Set(3 + i, type); } |
| + void InitParameter(int i, TypeHandle type) { this->Set(2 + i, type); } |
| static FunctionHandle New( |
| - TypeHandle result, TypeHandle receiver, TypeHandle bound, |
| - int arity, Region* region) { |
| - DCHECK(BitsetType::Is(bound->AsBitset(), BitsetType::kFunction)); |
| + TypeHandle result, TypeHandle receiver, int arity, Region* region) { |
| FunctionHandle type = Config::template cast<FunctionType>( |
| - StructuralType::New(StructuralType::kFunctionTag, 3 + arity, region)); |
| - type->Set(0, bound); |
| - type->Set(1, result); |
| - type->Set(2, receiver); |
| + StructuralType::New(StructuralType::kFunctionTag, 2 + arity, region)); |
| + type->Set(0, result); |
| + type->Set(1, receiver); |
| return type; |
| } |
| - static FunctionHandle New( |
| - TypeHandle result, TypeHandle receiver, int arity, Region* region) { |
| - TypeHandle bound = BitsetType::New(BitsetType::kFunction, region); |
| - return New(result, receiver, bound, arity, region); |
| - } |
| - |
| static FunctionType* cast(TypeImpl* type) { |
| DCHECK(type->IsFunction()); |
| return static_cast<FunctionType*>(type); |
| @@ -853,11 +862,6 @@ struct ZoneTypeConfig { |
| typedef i::Zone Region; |
| template<class T> struct Handle { typedef T* type; }; |
| - // TODO(neis): This will be removed again once we have struct_get_double(). |
| - static inline i::Isolate* isolate(Region* region) { |
| - return region->isolate(); |
| - } |
| - |
| template<class T> static inline T* handle(T* type); |
| template<class T> static inline T* cast(Type* type); |
| @@ -900,11 +904,6 @@ struct HeapTypeConfig { |
| typedef i::Isolate Region; |
| template<class T> struct Handle { typedef i::Handle<T> type; }; |
| - // TODO(neis): This will be removed again once we have struct_get_double(). |
| - static inline i::Isolate* isolate(Region* region) { |
| - return region; |
| - } |
| - |
| template<class T> static inline i::Handle<T> handle(T* type); |
| template<class T> static inline i::Handle<T> cast(i::Handle<Type> type); |