Add constructor for range types.
authorneis@chromium.org <neis@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 22 Jul 2014 17:33:22 +0000 (17:33 +0000)
committerneis@chromium.org <neis@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 22 Jul 2014 17:33:22 +0000 (17:33 +0000)
R=rossberg@chromium.org
BUG=

Review URL: https://codereview.chromium.org/409543004

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22535 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/types-inl.h
src/types.cc
src/types.h
test/cctest/test-types.cc

index 0bdd463..f086e8b 100644 (file)
@@ -19,7 +19,7 @@ namespace internal {
 template<class Config>
 TypeImpl<Config>* TypeImpl<Config>::cast(typename Config::Base* object) {
   TypeImpl* t = static_cast<TypeImpl*>(object);
-  ASSERT(t->IsBitset() || t->IsClass() || t->IsConstant() ||
+  ASSERT(t->IsBitset() || t->IsClass() || t->IsConstant() || t->IsRange() ||
          t->IsUnion() || t->IsArray() || t->IsFunction() || t->IsContext());
   return t;
 }
index 3cd349b..db638ed 100644 (file)
@@ -911,6 +911,11 @@ void TypeImpl<Config>::PrintTo(OStream& os, PrintDimension dim) {  // NOLINT
          << " : ";
       BitsetType::New(BitsetType::Lub(this))->PrintTo(os, dim);
       os << ")";
+    } else if (this->IsRange()) {
+      os << "Range(" << this->AsRange()->Min()
+         << ".." << this->AsRange()->Max() << " : ";
+      BitsetType::New(BitsetType::Lub(this))->PrintTo(os, dim);
+      os << ")";
     } else if (this->IsContext()) {
       os << "Context(";
       this->AsContext()->Outer()->PrintTo(os, dim);
index 79a29e0..1b2cf66 100644 (file)
@@ -5,6 +5,7 @@
 #ifndef V8_TYPES_H_
 #define V8_TYPES_H_
 
+#include "src/factory.h"
 #include "src/handles.h"
 #include "src/ostreams.h"
 
@@ -254,6 +255,7 @@ class TypeImpl : public Config::Base {
 
   class ClassType;
   class ConstantType;
+  class RangeType;
   class ContextType;
   class ArrayType;
   class FunctionType;
@@ -261,6 +263,7 @@ class TypeImpl : public Config::Base {
   typedef typename Config::template Handle<TypeImpl>::type TypeHandle;
   typedef typename Config::template Handle<ClassType>::type ClassHandle;
   typedef typename Config::template Handle<ConstantType>::type ConstantHandle;
+  typedef typename Config::template Handle<RangeType>::type RangeHandle;
   typedef typename Config::template Handle<ContextType>::type ContextHandle;
   typedef typename Config::template Handle<ArrayType>::type ArrayHandle;
   typedef typename Config::template Handle<FunctionType>::type FunctionHandle;
@@ -281,8 +284,12 @@ class TypeImpl : public Config::Base {
     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) {
+    return RangeType::New(min, max, region);
+  }
   static TypeHandle Context(TypeHandle outer, Region* region) {
     return ContextType::New(outer, region);
   }
@@ -375,6 +382,9 @@ class TypeImpl : public Config::Base {
   bool IsConstant() {
     return Config::is_struct(this, StructuralType::kConstantTag);
   }
+  bool IsRange() {
+    return Config::is_struct(this, StructuralType::kRangeTag);
+  }
   bool IsContext() {
     return Config::is_struct(this, StructuralType::kContextTag);
   }
@@ -387,6 +397,7 @@ class TypeImpl : public Config::Base {
 
   ClassType* AsClass() { return ClassType::cast(this); }
   ConstantType* AsConstant() { return ConstantType::cast(this); }
+  RangeType* AsRange() { return RangeType::cast(this); }
   ContextType* AsContext() { return ContextType::cast(this); }
   ArrayType* AsArray() { return ArrayType::cast(this); }
   FunctionType* AsFunction() { return FunctionType::cast(this); }
@@ -520,6 +531,7 @@ class TypeImpl<Config>::StructuralType : public TypeImpl<Config> {
   enum Tag {
     kClassTag,
     kConstantTag,
+    kRangeTag,
     kContextTag,
     kArrayTag,
     kFunctionTag,
@@ -656,6 +668,42 @@ class TypeImpl<Config>::ConstantType : public StructuralType {
 
 
 // -----------------------------------------------------------------------------
+// Range types.
+
+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(); }
+
+  static RangeHandle New(
+      double min, double max, TypeHandle bound, Region* region) {
+    ASSERT(SEMANTIC(bound->AsBitset() | BitsetType::kNumber)
+           == SEMANTIC(BitsetType::kNumber));
+    ASSERT(!std::isnan(min) && !std::isnan(max) && min <= max);
+    RangeHandle type = Config::template cast<RangeType>(
+        StructuralType::New(StructuralType::kRangeTag, 3, region));
+    type->Set(0, bound);
+    Factory* factory = Config::isolate(region)->factory();
+    type->SetValue(1, factory->NewHeapNumber(min));
+    type->SetValue(2, factory->NewHeapNumber(max));
+    return type;
+  }
+
+  static RangeHandle New(double min, double max, Region* region) {
+    TypeHandle bound = BitsetType::New(BitsetType::kNumber, region);
+    return New(min, max, bound, region);
+  }
+
+  static RangeType* cast(TypeImpl* type) {
+    ASSERT(type->IsRange());
+    return static_cast<RangeType*>(type);
+  }
+};
+
+
+// -----------------------------------------------------------------------------
 // Context types.
 
 template<class Config>
@@ -791,6 +839,11 @@ 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);
 
@@ -833,6 +886,11 @@ 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);
 
index 8120a6d..5c6a059 100644 (file)
@@ -21,10 +21,11 @@ struct ZoneRep {
   static bool IsBitset(Type* t) { return reinterpret_cast<intptr_t>(t) & 1; }
   static bool IsClass(Type* t) { return IsStruct(t, 0); }
   static bool IsConstant(Type* t) { return IsStruct(t, 1); }
-  static bool IsContext(Type* t) { return IsStruct(t, 2); }
-  static bool IsArray(Type* t) { return IsStruct(t, 3); }
-  static bool IsFunction(Type* t) { return IsStruct(t, 4); }
-  static bool IsUnion(Type* t) { return IsStruct(t, 5); }
+  static bool IsRange(Type* t) { return IsStruct(t, 2); }
+  static bool IsContext(Type* t) { return IsStruct(t, 3); }
+  static bool IsArray(Type* t) { return IsStruct(t, 4); }
+  static bool IsFunction(Type* t) { return IsStruct(t, 5); }
+  static bool IsUnion(Type* t) { return IsStruct(t, 6); }
 
   static Struct* AsStruct(Type* t) {
     return reinterpret_cast<Struct*>(t);
@@ -70,10 +71,11 @@ struct HeapRep {
     return t->IsMap() || IsStruct(t, 0);
   }
   static bool IsConstant(Handle<HeapType> t) { return IsStruct(t, 1); }
-  static bool IsContext(Handle<HeapType> t) { return IsStruct(t, 2); }
-  static bool IsArray(Handle<HeapType> t) { return IsStruct(t, 3); }
-  static bool IsFunction(Handle<HeapType> t) { return IsStruct(t, 4); }
-  static bool IsUnion(Handle<HeapType> t) { return IsStruct(t, 5); }
+  static bool IsRange(Handle<HeapType> t) { return IsStruct(t, 2); }
+  static bool IsContext(Handle<HeapType> t) { return IsStruct(t, 3); }
+  static bool IsArray(Handle<HeapType> t) { return IsStruct(t, 4); }
+  static bool IsFunction(Handle<HeapType> t) { return IsStruct(t, 5); }
+  static bool IsUnion(Handle<HeapType> t) { return IsStruct(t, 6); }
 
   static Struct* AsStruct(Handle<HeapType> t) { return FixedArray::cast(*t); }
   static int AsBitset(Handle<HeapType> t) { return Smi::cast(*t)->value(); }
@@ -149,6 +151,15 @@ class Types {
       types.push_back(Type::Constant(*it, region));
     }
 
+    doubles.push_back(-0.0);
+    doubles.push_back(+0.0);
+    doubles.push_back(-std::numeric_limits<double>::infinity());
+    doubles.push_back(+std::numeric_limits<double>::infinity());
+    for (int i = 0; i < 10; ++i) {
+      doubles.push_back(rng_->NextInt());
+      doubles.push_back(rng_->NextDouble() * rng_->NextInt());
+    }
+
     NumberArray = Type::Array(Number, region);
     StringArray = Type::Array(String, region);
     AnyArray = Type::Array(Any, region);
@@ -201,9 +212,12 @@ class Types {
   typedef std::vector<TypeHandle> TypeVector;
   typedef std::vector<Handle<i::Map> > MapVector;
   typedef std::vector<Handle<i::Object> > ValueVector;
+  typedef std::vector<double> DoubleVector;
+
   TypeVector types;
   MapVector maps;
   ValueVector values;
+  DoubleVector doubles;
 
   TypeHandle Of(Handle<i::Object> value) {
     return Type::Of(value, region_);
@@ -217,6 +231,10 @@ class Types {
     return Type::Constant(value, region_);
   }
 
+  TypeHandle Range(double min, double max) {
+    return Type::Range(min, max, region_);
+  }
+
   TypeHandle Class(Handle<i::Map> map) {
     return Type::Class(map, region_);
   }
@@ -327,6 +345,7 @@ struct Tests : Rep {
   typedef typename TypesInstance::TypeVector::iterator TypeIterator;
   typedef typename TypesInstance::MapVector::iterator MapIterator;
   typedef typename TypesInstance::ValueVector::iterator ValueIterator;
+  typedef typename TypesInstance::DoubleVector::iterator DoubleIterator;
 
   Isolate* isolate;
   HandleScope scope;
@@ -346,6 +365,7 @@ struct Tests : Rep {
         Rep::IsBitset(type1) == Rep::IsBitset(type2) &&
         Rep::IsClass(type1) == Rep::IsClass(type2) &&
         Rep::IsConstant(type1) == Rep::IsConstant(type2) &&
+        Rep::IsRange(type1) == Rep::IsRange(type2) &&
         Rep::IsContext(type1) == Rep::IsContext(type2) &&
         Rep::IsArray(type1) == Rep::IsArray(type2) &&
         Rep::IsFunction(type1) == Rep::IsFunction(type2) &&
@@ -358,8 +378,11 @@ struct Tests : Rep {
           Rep::AsClass(type1) == Rep::AsClass(type2)) &&
         (!Rep::IsConstant(type1) ||
           Rep::AsConstant(type1) == Rep::AsConstant(type2)) &&
+        (!Rep::IsRange(type1) ||
+          (type1->AsRange()->Min() == type2->AsRange()->Min() &&
+           type1->AsRange()->Max() == type2->AsRange()->Max())) &&
           // TODO(rossberg): Check details of arrays, functions, bounds.
-          (!Rep::IsUnion(type1) ||
+        (!Rep::IsUnion(type1) ||
           Rep::Length(Rep::AsUnion(type1)) == Rep::Length(Rep::AsUnion(type2)));
   }
 
@@ -566,6 +589,50 @@ struct Tests : Rep {
     CHECK(T.Constant(fac->NewNumber(-V8_INFINITY))->Is(T.OtherNumber));
   }
 
+  void Range() {
+    // Constructor
+    for (DoubleIterator i = T.doubles.begin(); i != T.doubles.end(); ++i) {
+      for (DoubleIterator j = T.doubles.begin(); j != T.doubles.end(); ++j) {
+        double min = std::min(*i, *j);
+        double max = std::max(*i, *j);
+        TypeHandle type = T.Range(min, max);
+        CHECK(this->IsRange(type));
+      }
+    }
+
+    // Range attributes
+    for (DoubleIterator i = T.doubles.begin(); i != T.doubles.end(); ++i) {
+      for (DoubleIterator j = T.doubles.begin(); j != T.doubles.end(); ++j) {
+        double min = std::min(*i, *j);
+        double max = std::max(*i, *j);
+        TypeHandle type = T.Range(min, max);
+        CHECK(min == type->AsRange()->Min());
+        CHECK(max == type->AsRange()->Max());
+      }
+    }
+
+// TODO(neis): enable once subtyping is updated.
+//  // Functionality & Injectivity: Range(min1, max1) = Range(min2, max2) <=>
+//  //                              min1 = min2 /\ max1 = max2
+//  for (DoubleIterator i1 = T.doubles.begin(); i1 != T.doubles.end(); ++i1) {
+//    for (DoubleIterator j1 = T.doubles.begin(); j1 != T.doubles.end(); ++j1) {
+//      for (DoubleIterator i2 = T.doubles.begin();
+//           i2 != T.doubles.end(); ++i2) {
+//        for (DoubleIterator j2 = T.doubles.begin();
+//             j2 != T.doubles.end(); ++j2) {
+//          double min1 = std::min(*i1, *j1);
+//          double max1 = std::max(*i1, *j1);
+//          double min2 = std::min(*i2, *j2);
+//          double max2 = std::max(*i2, *j2);
+//          TypeHandle type1 = T.Range(min1, max1);
+//          TypeHandle type2 = T.Range(min2, max2);
+//          CHECK(Equal(type1, type2) == (min1 == min2 && max1 == max2));
+//        }
+//      }
+//    }
+//  }
+  }
+
   void Array() {
     // Constructor
     for (int i = 0; i < 20; ++i) {
@@ -1794,6 +1861,13 @@ TEST(ConstantType) {
 }
 
 
+TEST(RangeType) {
+  CcTest::InitializeVM();
+  ZoneTests().Range();
+  HeapTests().Range();
+}
+
+
 TEST(ArrayType) {
   CcTest::InitializeVM();
   ZoneTests().Array();