Fix various bugs in the type systems, and improve test coverage.
authorbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 9 Apr 2014 11:12:15 +0000 (11:12 +0000)
committerbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 9 Apr 2014 11:12:15 +0000 (11:12 +0000)
R=rossberg@chromium.org

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

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

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

index 2f91d87..f6a430b 100644 (file)
@@ -306,10 +306,14 @@ bool TypeImpl<Config>::SlowIs(TypeImpl* that) {
 
 template<class Config>
 bool TypeImpl<Config>::NowIs(TypeImpl* that) {
-  return this->Is(that) ||
-      (this->IsConstant() && that->IsClass() &&
-       this->AsConstant()->IsHeapObject() &&
-       i::HeapObject::cast(*this->AsConstant())->map() == *that->AsClass());
+  if (this->Is(that)) return true;
+  if (this->IsConstant() && this->AsConstant()->IsHeapObject()) {
+    i::Handle<i::Map> map(i::HeapObject::cast(*this->AsConstant())->map());
+    for (Iterator<i::Map> it = that->Classes(); !it.Done(); it.Advance()) {
+      if (*it.Current() == *map) return true;
+    }
+  }
+  return false;
 }
 
 
@@ -358,8 +362,8 @@ bool TypeImpl<Config>::Maybe(TypeImpl* that) {
 
 template<class Config>
 bool TypeImpl<Config>::Contains(i::Object* value) {
-  if (this->IsConstant()) {
-    return *this->AsConstant() == value;
+  for (Iterator<i::Object> it = this->Constants(); !it.Done(); it.Advance()) {
+    if (*it.Current() == value) return true;
   }
   return Config::from_bitset(LubBitset(value))->Is(this);
 }
index 0161582..16d80b8 100644 (file)
@@ -154,7 +154,7 @@ namespace internal {
   V(Receiver,            kObject | kProxy)                              \
   V(NonNumber,           kBoolean | kName | kNull | kReceiver |         \
                          kUndefined | kInternal)                        \
-  V(Any,                 kNumber | kNonNumber)
+  V(Any,                 -1)
 
 #define BITSET_TYPE_LIST(V) \
   MASK_BITSET_TYPE_LIST(V) \
@@ -220,6 +220,10 @@ class TypeImpl : public Config::Base {
     return Of(*value, region);
   }
 
+  bool IsInhabited() {
+    return !this->IsBitset() || IsInhabited(this->AsBitset());
+  }
+
   bool Is(TypeImpl* that) { return this == that || this->SlowIs(that); }
   template<class TypeHandle>
   bool Is(TypeHandle that) { return this->Is(*that); }
index 445a9e1..3448a84 100644 (file)
@@ -25,6 +25,8 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+#include <list>
+
 #include "cctest.h"
 #include "types.h"
 
@@ -71,6 +73,43 @@ class Types {
     ObjectConstant2 = Type::Constant(object2, region);
     ArrayConstant1 = Type::Constant(array, region);
     ArrayConstant2 = Type::Constant(array, region);
+
+    types.push_back(None);
+    types.push_back(Any);
+    types.push_back(Boolean);
+    types.push_back(Null);
+    types.push_back(Undefined);
+    types.push_back(Number);
+    types.push_back(SignedSmall);
+    types.push_back(Signed32);
+    types.push_back(Float);
+    types.push_back(Name);
+    types.push_back(UniqueName);
+    types.push_back(String);
+    types.push_back(InternalizedString);
+    types.push_back(Symbol);
+    types.push_back(Receiver);
+    types.push_back(Object);
+    types.push_back(Array);
+    types.push_back(Function);
+    types.push_back(Proxy);
+    types.push_back(ObjectClass);
+    types.push_back(ArrayClass);
+    types.push_back(SmiConstant);
+    types.push_back(Signed32Constant);
+    types.push_back(ObjectConstant1);
+    types.push_back(ObjectConstant2);
+    types.push_back(ArrayConstant1);
+    types.push_back(ArrayConstant2);
+    for (int i = 0; i < 300; ++i) {
+      types.push_back(Fuzz());
+    }
+
+    objects.push_back(smi);
+    objects.push_back(signed32);
+    objects.push_back(object1);
+    objects.push_back(object2);
+    objects.push_back(array);
   }
 
   TypeHandle Representation;
@@ -114,6 +153,20 @@ class Types {
   Handle<i::JSObject> object2;
   Handle<i::JSArray> array;
 
+  typedef std::list<TypeHandle> TypeList;
+  TypeList types;
+
+  typedef std::list<Handle<i::Object> > ObjectList;
+  ObjectList objects;
+
+  TypeHandle Of(Handle<i::Object> obj) {
+    return Type::Of(obj, region_);
+  }
+
+  TypeHandle Constant(Handle<i::Object> obj) {
+    return Type::Constant(obj, region_);
+  }
+
   TypeHandle Union(TypeHandle t1, TypeHandle t2) {
     return Type::Union(t1, t2, region_);
   }
@@ -239,6 +292,10 @@ struct Tests : Rep {
   HandleScope scope;
   Zone zone;
   Types<Type, TypeHandle, Region> T;
+  typedef typename Types<Type, TypeHandle, Region>::TypeList::iterator
+      TypeIterator;
+  typedef typename Types<Type, TypeHandle, Region>::ObjectList::iterator
+      ObjectIterator;
 
   Tests() :
       isolate(CcTest::i_isolate()),
@@ -346,14 +403,49 @@ struct Tests : Rep {
   }
 
   void Is() {
+    // T->Is(None) implies T = None for all T
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      if (type->Is(T.None)) CheckEqual(type, T.None);
+    }
+
+    // None->Is(T) for all T
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      CHECK(T.None->Is(type));
+    }
+
+    // Any->Is(T) implies T = Any for all T
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      if (T.Any->Is(type)) CheckEqual(type, T.Any);
+    }
+
+    // T->Is(Any) for all T
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      CHECK(type->Is(T.Any));
+    }
+
     // Reflexivity
-    CHECK(T.None->Is(T.None));
-    CHECK(T.Any->Is(T.Any));
-    CHECK(T.Object->Is(T.Object));
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      CHECK(type->Is(type));
+    }
 
-    CHECK(T.ObjectClass->Is(T.ObjectClass));
-    CHECK(T.ObjectConstant1->Is(T.ObjectConstant1));
-    CHECK(T.ArrayConstant1->Is(T.ArrayConstant2));
+    // Transitivity
+    for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
+      for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
+        for (TypeIterator it3 = T.types.begin(); it3 != T.types.end(); ++it3) {
+          TypeHandle type1 = *it1;
+          TypeHandle type2 = *it2;
+          TypeHandle type3 = *it3;
+          CHECK(!type1->Is(type2) ||
+                !type2->Is(type3) ||
+                type1->Is(type3));
+        }
+      }
+    }
 
     // Symmetry and Transitivity
     CheckSub(T.None, T.Number);
@@ -420,7 +512,111 @@ struct Tests : Rep {
     CheckUnordered(T.ArrayConstant1, T.ObjectClass);
   }
 
+  void NowIs() {
+    // T->NowIs(None) implies T = None for all T
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      if (type->NowIs(T.None)) CheckEqual(type, T.None);
+    }
+
+    // None->NowIs(T) for all T
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      CHECK(T.None->NowIs(type));
+    }
+
+    // Any->NowIs(T) implies T = Any for all T
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      if (T.Any->NowIs(type)) CheckEqual(type, T.Any);
+    }
+
+    // T->NowIs(Any) for all T
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      CHECK(type->NowIs(T.Any));
+    }
+
+    // Reflexivity
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      CHECK(type->NowIs(type));
+    }
+
+    // Transitivity
+    for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
+      for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
+        for (TypeIterator it3 = T.types.begin(); it3 != T.types.end(); ++it3) {
+          TypeHandle type1 = *it1;
+          TypeHandle type2 = *it2;
+          TypeHandle type3 = *it3;
+          CHECK(!type1->NowIs(type2) ||
+                !type2->NowIs(type3) ||
+                type1->NowIs(type3));
+        }
+      }
+    }
+
+    // T1->Is(T2) implies T1->NowIs(T2) for all T1,T2
+    for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
+      for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
+        TypeHandle type1 = *it1;
+        TypeHandle type2 = *it2;
+        CHECK(!type1->Is(type2) || type1->NowIs(type2));
+      }
+    }
+
+    CHECK(T.ObjectConstant1->NowIs(T.ObjectClass));
+    CHECK(T.ObjectConstant2->NowIs(T.ObjectClass));
+  }
+
+  void Contains() {
+    // T->Contains(O) iff Constant(O)->Is(T) for all T,O
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      for (ObjectIterator ot = T.objects.begin(); ot != T.objects.end(); ++ot) {
+        TypeHandle type = *it;
+        Handle<i::Object> obj = *ot;
+        CHECK(type->Contains(obj) == T.Constant(obj)->Is(type));
+      }
+    }
+
+    // Of(O)->Is(T) implies T->Contains(O) for all T,O
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      for (ObjectIterator ot = T.objects.begin(); ot != T.objects.end(); ++ot) {
+        TypeHandle type = *it;
+        Handle<i::Object> obj = *ot;
+        CHECK(!T.Of(obj)->Is(type) || type->Contains(obj));
+      }
+    }
+  }
+
   void Maybe() {
+    // T->Maybe(T) for all inhabited T
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      CHECK(type->Maybe(type) || !type->IsInhabited());
+    }
+
+    // Commutativity
+    for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
+      for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
+        TypeHandle type1 = *it1;
+        TypeHandle type2 = *it2;
+        CHECK(type1->Maybe(type2) == type2->Maybe(type1));
+      }
+    }
+
+    // T1->Is(T2) implies T1->Maybe(T2) or T1 is uninhabited for all T1,T2
+    for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
+      for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
+        TypeHandle type1 = *it1;
+        TypeHandle type2 = *it2;
+        CHECK(!type1->Is(type2) ||
+              type1->Maybe(type2) ||
+              !type1->IsInhabited());
+      }
+    }
+
     CheckOverlap(T.Any, T.Any, T.Semantic);
     CheckOverlap(T.Object, T.Object, T.Semantic);
 
@@ -868,6 +1064,20 @@ TEST(Is) {
 }
 
 
+TEST(NowIs) {
+  CcTest::InitializeVM();
+  ZoneTests().NowIs();
+  HeapTests().NowIs();
+}
+
+
+TEST(Contains) {
+  CcTest::InitializeVM();
+  ZoneTests().Contains();
+  HeapTests().Contains();
+}
+
+
 TEST(Maybe) {
   CcTest::InitializeVM();
   ZoneTests().Maybe();