#ifndef V8_TYPES_H_
#define V8_TYPES_H_
+#include "src/conversions.h"
#include "src/factory.h"
#include "src/handles.h"
#include "src/ostreams.h"
// Types consist of two dimensions: semantic (value range) and representation.
// Both are related through subtyping.
//
+//
// SEMANTIC DIMENSION
//
// The following equations and inequations hold for the semantic axis:
// However, we also define a 'temporal' variant of the subtyping relation that
// considers the _current_ state only, i.e., Constant(x) <_now Class(map(x)).
//
+//
// REPRESENTATIONAL DIMENSION
//
// For the representation axis, the following holds:
// SignedSmall /\ TaggedInt (a 'smi')
// Number /\ TaggedPtr (a heap number)
//
+//
+// RANGE TYPES
+//
+// A range type represents a continuous integer interval by its minimum and
+// 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.
+//
+//
// PREDICATES
//
// There are two main functions for testing types:
// Any compilation decision based on such temporary properties requires runtime
// guarding!
//
+//
// 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'
// constructors and predicates (those prefixed 'Now').
//
+//
// IMPLEMENTATION
//
// Internally, all 'primitive' types, and their unions, are represented as
-// bitsets. Class is a heap pointer to the respective map. Only Constant's, or
-// unions containing Class'es or Constant's, currently require allocation.
+// bitsets. Bit 0 is reserved for tagging. Class is a heap pointer to the
+// respective map. Only structured types require allocation.
// Note that the bitset representation is closed under both Union and Intersect.
//
// There are two type representations, using different allocation:
// Values for bitset types
#define MASK_BITSET_TYPE_LIST(V) \
- V(Representation, static_cast<int>(0xffc00000)) \
- V(Semantic, static_cast<int>(0x003fffff))
+ V(Representation, 0xff800000u) \
+ V(Semantic, 0x007ffffeu)
#define REPRESENTATION(k) ((k) & BitsetType::kRepresentation)
#define SEMANTIC(k) ((k) & BitsetType::kSemantic)
#define REPRESENTATION_BITSET_TYPE_LIST(V) \
V(None, 0) \
- V(UntaggedInt1, 1 << 22 | kSemantic) \
- 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) \
- /* MSB has to be sign-extended */ \
- V(TaggedPtr, static_cast<int>(~0u << 30) | kSemantic) \
+ V(UntaggedInt1, 1u << 23 | kSemantic) \
+ V(UntaggedInt8, 1u << 24 | kSemantic) \
+ V(UntaggedInt16, 1u << 25 | kSemantic) \
+ V(UntaggedInt32, 1u << 26 | kSemantic) \
+ V(UntaggedFloat32, 1u << 27 | kSemantic) \
+ V(UntaggedFloat64, 1u << 28 | kSemantic) \
+ V(UntaggedPtr, 1u << 29 | kSemantic) \
+ V(TaggedInt, 1u << 30 | kSemantic) \
+ V(TaggedPtr, 1u << 31 | kSemantic) \
\
V(UntaggedInt, kUntaggedInt1 | kUntaggedInt8 | \
kUntaggedInt16 | kUntaggedInt32) \
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(UnsignedSmall, 1 << 3 | REPRESENTATION(kTagged | kUntaggedNumber)) \
- V(OtherSignedSmall, 1 << 4 | REPRESENTATION(kTagged | kUntaggedNumber)) \
- V(OtherUnsigned31, 1 << 5 | REPRESENTATION(kTagged | kUntaggedNumber)) \
- V(OtherUnsigned32, 1 << 6 | REPRESENTATION(kTagged | kUntaggedNumber)) \
- V(OtherSigned32, 1 << 7 | REPRESENTATION(kTagged | kUntaggedNumber)) \
- V(MinusZero, 1 << 8 | REPRESENTATION(kTagged | kUntaggedNumber)) \
- V(NaN, 1 << 9 | REPRESENTATION(kTagged | kUntaggedNumber)) \
- V(OtherNumber, 1 << 10 | REPRESENTATION(kTagged | kUntaggedNumber)) \
- V(Symbol, 1 << 11 | REPRESENTATION(kTaggedPtr)) \
- V(InternalizedString, 1 << 12 | REPRESENTATION(kTaggedPtr)) \
- V(OtherString, 1 << 13 | REPRESENTATION(kTaggedPtr)) \
- V(Undetectable, 1 << 14 | REPRESENTATION(kTaggedPtr)) \
- V(Array, 1 << 15 | REPRESENTATION(kTaggedPtr)) \
- V(Buffer, 1 << 16 | REPRESENTATION(kTaggedPtr)) \
- V(Function, 1 << 17 | REPRESENTATION(kTaggedPtr)) \
- V(RegExp, 1 << 18 | REPRESENTATION(kTaggedPtr)) \
- V(OtherObject, 1 << 19 | REPRESENTATION(kTaggedPtr)) \
- V(Proxy, 1 << 20 | REPRESENTATION(kTaggedPtr)) \
- V(Internal, 1 << 21 | REPRESENTATION(kTagged | kUntagged)) \
+ V(Null, 1u << 1 | REPRESENTATION(kTaggedPtr)) \
+ V(Undefined, 1u << 2 | REPRESENTATION(kTaggedPtr)) \
+ V(Boolean, 1u << 3 | REPRESENTATION(kTaggedPtr)) \
+ V(UnsignedSmall, 1u << 4 | REPRESENTATION(kTagged | kUntaggedNumber)) \
+ V(OtherSignedSmall, 1u << 5 | REPRESENTATION(kTagged | kUntaggedNumber)) \
+ V(OtherUnsigned31, 1u << 6 | REPRESENTATION(kTagged | kUntaggedNumber)) \
+ V(OtherUnsigned32, 1u << 7 | REPRESENTATION(kTagged | kUntaggedNumber)) \
+ V(OtherSigned32, 1u << 8 | REPRESENTATION(kTagged | kUntaggedNumber)) \
+ V(MinusZero, 1u << 9 | REPRESENTATION(kTagged | kUntaggedNumber)) \
+ V(NaN, 1u << 10 | REPRESENTATION(kTagged | kUntaggedNumber)) \
+ V(OtherNumber, 1u << 11 | REPRESENTATION(kTagged | kUntaggedNumber)) \
+ V(Symbol, 1u << 12 | REPRESENTATION(kTaggedPtr)) \
+ V(InternalizedString, 1u << 13 | REPRESENTATION(kTaggedPtr)) \
+ V(OtherString, 1u << 14 | REPRESENTATION(kTaggedPtr)) \
+ V(Undetectable, 1u << 15 | REPRESENTATION(kTaggedPtr)) \
+ V(Array, 1u << 16 | REPRESENTATION(kTaggedPtr)) \
+ V(Buffer, 1u << 17 | REPRESENTATION(kTaggedPtr)) \
+ V(Function, 1u << 18 | REPRESENTATION(kTaggedPtr)) \
+ V(RegExp, 1u << 19 | REPRESENTATION(kTaggedPtr)) \
+ V(OtherObject, 1u << 20 | REPRESENTATION(kTaggedPtr)) \
+ V(Proxy, 1u << 21 | REPRESENTATION(kTaggedPtr)) \
+ V(Internal, 1u << 22 | REPRESENTATION(kTagged | kUntagged)) \
\
V(SignedSmall, kUnsignedSmall | kOtherSignedSmall) \
V(Signed32, kSignedSmall | kOtherUnsigned31 | kOtherSigned32) \
V(Unsigned32, kUnsignedSmall | kOtherUnsigned31 | kOtherUnsigned32) \
V(Integral32, kSigned32 | kUnsigned32) \
- V(Number, kIntegral32 | kMinusZero | kNaN | kOtherNumber) \
+ V(OrderedNumber, kIntegral32 | kMinusZero | kOtherNumber) \
+ V(Number, kOrderedNumber | kNaN) \
V(String, kInternalizedString | kOtherString) \
V(UniqueName, kSymbol | kInternalizedString) \
V(Name, kSymbol | kString) \
V(Detectable, kDetectableReceiver | kNumber | kName) \
V(Object, kDetectableObject | kUndetectable) \
V(Receiver, kObject | kProxy) \
- V(NonNumber, kBoolean | kName | kNull | kReceiver | \
- kUndefined | kInternal) \
- V(Any, -1)
+ V(Unique, kBoolean | kUniqueName | kNull | kUndefined | \
+ kReceiver) \
+ V(NonNumber, kUnique | kString | kInternal) \
+ V(Any, 0xfffffffeu)
+
+/*
+ * 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:
+ *
+ * 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.
+ *
+ * NOTE: OtherSigned32 (OS32) and OU31 (OtherUnsigned31) are empty if Smis are
+ * 32-bit wide. They should thus never be used directly, only indirectly
+ * via e.g. Number.
+ */
+
+#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) \
- REPRESENTATION_BITSET_TYPE_LIST(V) \
- SEMANTIC_BITSET_TYPE_LIST(V)
+ PROPER_BITSET_TYPE_LIST(V)
// -----------------------------------------------------------------------------
// typedef Struct;
// typedef Region;
// template<class> struct Handle { typedef type; } // No template typedefs...
+// template<class T> static Handle<T>::type null_handle();
// template<class T> static Handle<T>::type handle(T* t); // !is_bitset(t)
// template<class T> static Handle<T>::type cast(Handle<Type>::type);
// static bool is_bitset(Type*);
// static bool is_class(Type*);
// static bool is_struct(Type*, int tag);
-// static int as_bitset(Type*);
+// static bitset as_bitset(Type*);
// static i::Handle<i::Map> as_class(Type*);
// static Handle<Struct>::type as_struct(Type*);
-// static Type* from_bitset(int bitset);
-// static Handle<Type>::type from_bitset(int bitset, Region*);
+// static Type* from_bitset(bitset);
+// static Handle<Type>::type from_bitset(bitset, Region*);
// static Handle<Type>::type from_class(i::Handle<Map>, Region*);
// static Handle<Type>::type from_struct(Handle<Struct>::type, int tag);
// static Handle<Struct>::type struct_create(int tag, int length, Region*);
public:
// Auxiliary types.
- class BitsetType; // Internal
- class StructuralType; // Internal
- class UnionType; // Internal
+ typedef uint32_t bitset; // Internal
+ class BitsetType; // Internal
+ class StructuralType; // Internal
+ class UnionType; // Internal
class ClassType;
class ConstantType;
// Constructors.
#define DEFINE_TYPE_CONSTRUCTOR(type, value) \
- static TypeImpl* type() { return BitsetType::New(BitsetType::k##type); } \
+ static TypeImpl* type() { \
+ return BitsetType::New(BitsetType::k##type); \
+ } \
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) {
static TypeHandle Union(TypeHandle type1, TypeHandle type2, Region* reg);
static TypeHandle Intersect(TypeHandle type1, TypeHandle type2, Region* reg);
+ static TypeImpl* Union(TypeImpl* type1, TypeImpl* type2) {
+ return BitsetType::New(type1->AsBitset() | type2->AsBitset());
+ }
+ static TypeImpl* Intersect(TypeImpl* type1, TypeImpl* type2) {
+ return BitsetType::New(type1->AsBitset() & type2->AsBitset());
+ }
static TypeHandle Of(double value, Region* region) {
return Config::from_bitset(BitsetType::Lub(value), region);
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); }
ArrayType* AsArray() { return ArrayType::cast(this); }
FunctionType* AsFunction() { return FunctionType::cast(this); }
+ // Minimum and maximum of a numeric type.
+ // These functions do not distinguish between -0 and +0. If the type equals
+ // kNaN, they return NaN; otherwise kNaN is ignored. Only call these
+ // functions on subtypes of Number.
+ double Min();
+ double Max();
+
int NumClasses();
int NumConstants();
enum PrintDimension { BOTH_DIMS, SEMANTIC_DIM, REPRESENTATION_DIM };
- void PrintTo(OStream& os, PrintDimension dim = BOTH_DIMS); // NOLINT
+ void PrintTo(std::ostream& os, PrintDimension dim = BOTH_DIMS); // NOLINT
#ifdef DEBUG
void Print();
bool IsBitset() { return Config::is_bitset(this); }
bool IsUnion() { return Config::is_struct(this, StructuralType::kUnionTag); }
- int AsBitset() {
+ bitset AsBitset() {
DCHECK(this->IsBitset());
return static_cast<BitsetType*>(this)->Bitset();
}
// Auxiliary functions.
- int BitsetGlb() { return BitsetType::Glb(this); }
- int BitsetLub() { return BitsetType::Lub(this); }
- int InherentBitsetLub() { return BitsetType::InherentLub(this); }
+ bitset BitsetGlb() { return BitsetType::Glb(this); }
+ bitset BitsetLub() { return BitsetType::Lub(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->Min()), max(range->Max()) {}
+ };
+
+ 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);
+ template<class TypeHandle>
+ bool SimplyEquals(TypeHandle that) { return this->SimplyEquals(*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);
};
kUnusedEOL = 0
};
- int Bitset() { return Config::as_bitset(this); }
+ bitset Bitset() { return Config::as_bitset(this); }
- static TypeImpl* New(int bitset) {
- return static_cast<BitsetType*>(Config::from_bitset(bitset));
+ static TypeImpl* New(bitset bits) {
+ DCHECK(bits == kNone || IsInhabited(bits));
+ return Config::from_bitset(bits);
}
- static TypeHandle New(int bitset, Region* region) {
- return Config::from_bitset(bitset, region);
+ static TypeHandle New(bitset bits, Region* region) {
+ DCHECK(bits == kNone || IsInhabited(bits));
+ return Config::from_bitset(bits, region);
}
+ // TODO(neis): Eventually allow again for types with empty semantics
+ // part and modify intersection and possibly subtyping accordingly.
- static bool IsInhabited(int bitset) {
- return (bitset & kRepresentation) && (bitset & kSemantic);
+ static bool IsInhabited(bitset bits) {
+ return bits & kSemantic;
}
- static bool Is(int bitset1, int bitset2) {
- return (bitset1 | bitset2) == bitset2;
+ static bool Is(bitset bits1, bitset bits2) {
+ return (bits1 | bits2) == bits2;
}
- static int Glb(TypeImpl* type); // greatest lower bound that's a bitset
- static int Lub(TypeImpl* type); // least upper bound that's a bitset
- static int Lub(i::Object* value);
- static int Lub(double value);
- 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 double Min(bitset);
+ static double Max(bitset);
- static const char* Name(int bitset);
- static void Print(OStream& os, int bitset); // NOLINT
- using TypeImpl::PrintTo;
+ static bitset Glb(TypeImpl* type); // greatest lower bound that's a bitset
+ static bitset Lub(TypeImpl* type); // least upper bound that's a bitset
+ static bitset Lub(i::Map* map);
+ static bitset Lub(i::Object* value);
+ static bitset Lub(double value);
+ static bitset Lub(double min, double max);
+
+ static const char* Name(bitset);
+ static void Print(std::ostream& os, bitset); // NOLINT
+#ifdef DEBUG
+ static void Print(bitset);
+#endif
+
+ private:
+ struct BitsetMin{
+ bitset bits;
+ double min;
+ };
+ static const BitsetMin BitsetMins31[];
+ static const BitsetMin BitsetMins32[];
+ static const BitsetMin* BitsetMins() {
+ return i::SmiValuesAre31Bits() ? BitsetMins31 : BitsetMins32;
+ }
+ static size_t BitsetMinsSize() {
+ return i::SmiValuesAre31Bits() ? 7 : 5;
+ /* arraysize(BitsetMins31) : arraysize(BitsetMins32); */
+ // Using arraysize here doesn't compile on Windows.
+ }
};
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);
+ 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;
+ return Config::is_class(this) ? Config::as_class(this) :
+ this->template GetValue<i::Map>(1);
}
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, 2, region));
+ type->Set(0, BitsetType::New(BitsetType::Lub(*map), region));
+ type->SetValue(1, map);
}
+ return type;
}
static ClassType* cast(TypeImpl* type) {
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)));
+ static ConstantHandle New(i::Handle<i::Object> value, Region* region) {
ConstantHandle type = Config::template cast<ConstantType>(
StructuralType::New(StructuralType::kConstantTag, 2, region));
- type->Set(0, bound);
+ type->Set(0, BitsetType::New(BitsetType::Lub(*value), region));
type->SetValue(1, value);
return type;
}
- static ConstantHandle New(i::Handle<i::Object> value, Region* region) {
- TypeHandle bound = BitsetType::New(BitsetType::Lub(*value), region);
- return New(value, bound, region);
- }
-
static ConstantType* cast(TypeImpl* type) {
DCHECK(type->IsConstant());
return static_cast<ConstantType*>(type);
}
};
+// TODO(neis): Also cache value if numerical.
+// TODO(neis): Allow restricting the representation.
// -----------------------------------------------------------------------------
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(); }
+ int BitsetLub() { return this->Get(0)->AsBitset(); }
+ i::Handle<i::Object> Min() { return this->template GetValue<i::Object>(1); }
+ i::Handle<i::Object> Max() { return this->template GetValue<i::Object>(2); }
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(IsInteger(min->Number()) && IsInteger(max->Number()));
+ 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);
+ type->Set(0, BitsetType::New(
+ BitsetType::Lub(min->Number(), max->Number()), region));
+ type->SetValue(1, min);
+ type->SetValue(2, max);
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) {
return static_cast<RangeType*>(type);
}
};
+// TODO(neis): Also cache min and max values.
+// TODO(neis): Allow restricting the representation.
// -----------------------------------------------------------------------------
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);
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);
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);
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* null_handle();
template<class T> static inline T* handle(T* type);
template<class T> static inline T* cast(Type* type);
static inline bool is_class(Type* type);
static inline bool is_struct(Type* type, int tag);
- static inline int as_bitset(Type* type);
+ static inline Type::bitset as_bitset(Type* type);
static inline i::Handle<i::Map> as_class(Type* type);
static inline Struct* as_struct(Type* type);
- static inline Type* from_bitset(int bitset);
- static inline Type* from_bitset(int bitset, Zone* zone);
+ static inline Type* from_bitset(Type::bitset);
+ static inline Type* from_bitset(Type::bitset, Zone* zone);
static inline Type* from_class(i::Handle<i::Map> map, Zone* zone);
static inline Type* from_struct(Struct* structured);
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> null_handle();
template<class T> static inline i::Handle<T> handle(T* type);
template<class T> static inline i::Handle<T> cast(i::Handle<Type> type);
static inline bool is_class(Type* type);
static inline bool is_struct(Type* type, int tag);
- static inline int as_bitset(Type* type);
+ static inline Type::bitset as_bitset(Type* type);
static inline i::Handle<i::Map> as_class(Type* type);
static inline i::Handle<Struct> as_struct(Type* type);
- static inline Type* from_bitset(int bitset);
- static inline i::Handle<Type> from_bitset(int bitset, Isolate* isolate);
+ static inline Type* from_bitset(Type::bitset);
+ static inline i::Handle<Type> from_bitset(Type::bitset, Isolate* isolate);
static inline i::Handle<Type> from_class(
i::Handle<i::Map> map, Isolate* isolate);
static inline i::Handle<Type> from_struct(i::Handle<Struct> structure);
TypeHandle lower;
TypeHandle upper;
- BoundsImpl() {}
+ BoundsImpl() : // Make sure accessing uninitialized bounds crashes big-time.
+ lower(Config::template null_handle<Type>()),
+ upper(Config::template null_handle<Type>()) {}
explicit BoundsImpl(TypeHandle t) : lower(t), upper(t) {}
BoundsImpl(TypeHandle l, TypeHandle u) : lower(l), upper(u) {
DCHECK(lower->Is(upper));