Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(197)

Unified Diff: src/types.h

Issue 558193003: Redesign of the internal type system. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Dito Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | src/types.cc » ('j') | src/types.cc » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/types.h
diff --git a/src/types.h b/src/types.h
index cca8b3167b4bb9b86773d7fcf40959490a9164f0..1099691d85663c3b436ba2524550d37cc4a72c40 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"
@@ -23,6 +24,7 @@ namespace internal {
// 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:
@@ -61,6 +63,7 @@ namespace internal {
// 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:
@@ -88,6 +91,16 @@ namespace internal {
// 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:
@@ -109,16 +122,18 @@ namespace internal {
// 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
@@ -208,11 +223,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:
+ *
+ * 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 +318,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 +396,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); }
@@ -404,6 +443,13 @@ class TypeImpl : public Config::Base {
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();
@@ -466,16 +512,45 @@ 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->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);
};
@@ -497,20 +572,27 @@ 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);
}
+ // 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);
+ return bitset & kSemantic;
}
static bool Is(int bitset1, int bitset2) {
return (bitset1 | bitset2) == bitset2;
}
+ static double Min(int bitset);
+ static double Max(int bitset);
+
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);
@@ -518,12 +600,29 @@ 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 const char* Name(int bitset);
static void Print(OStream& os, int bitset); // NOLINT
- using TypeImpl::PrintTo;
+#ifdef DEBUG
+ static void Print(int bitset);
+#endif
+
+ private:
+ struct BitsetMin{
+ int bitset;
+ 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.
+ }
};
@@ -609,36 +708,25 @@ 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);
+ int BitsetLub() {
rossberg 2014/09/23 15:20:38 This can't go here like this, as bitsets are an im
neis1 2014/09/24 07:21:38 Oops, forgot about that. I wanted to avoid the "l
+ return Config::is_class(this) ?
+ BitsetType::Lub(*Config::as_class(this)) : this->Get(0)->AsBitset();
}
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) {
@@ -654,29 +742,24 @@ class TypeImpl<Config>::ClassType : public StructuralType {
template<class Config>
class TypeImpl<Config>::ConstantType : public StructuralType {
public:
- TypeHandle Bound() { return this->Get(0); }
+ int BitsetLub() { return this->Get(0)->AsBitset(); }
rossberg 2014/09/23 15:20:38 Same here.
neis1 2014/09/24 07:21:38 Done.
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.
// -----------------------------------------------------------------------------
@@ -685,27 +768,23 @@ class TypeImpl<Config>::ConstantType : public StructuralType {
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(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(Limits(min, max)), 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) {
@@ -713,6 +792,8 @@ class TypeImpl<Config>::RangeType : public StructuralType {
return static_cast<RangeType*>(type);
}
};
+// TODO(neis): Also cache min and max values.
+// TODO(neis): Allow restricting the representation.
// -----------------------------------------------------------------------------
@@ -721,25 +802,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 +824,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 +846,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 +906,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 +948,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);
« no previous file with comments | « no previous file | src/types.cc » ('j') | src/types.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698