Establish distributivity for type union & intersection
authorrossberg@chromium.org <rossberg@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 27 May 2014 13:52:31 +0000 (13:52 +0000)
committerrossberg@chromium.org <rossberg@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 27 May 2014 13:52:31 +0000 (13:52 +0000)
This requires introducing proper bounds on all leaf types, so that intersection between bitsets and these types can be accurately represented. Extending a union also becomes more involved.

(On the upside, the modified union/intersect algorithm would now allow support for proper variance for function types.)

Not sure if it is worth landing this. Distributivity isn't really a crucial property for our use cases. It seems fine if intersection is slightly lossy.

R=bmeurer@chromium.org, jarin@chromium.org
BUG=

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

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

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

index 353f8f58750c23fe8f51de8f3783847a28beebea..26f899136805663f0ff23f2029aa0fab9cae586b 100644 (file)
@@ -8,6 +8,7 @@
 #include "conversions.h"
 #include "objects.h"
 #include "property-details.h"
+#include "types.h"
 
 namespace v8 {
 namespace internal {
@@ -23,6 +24,16 @@ inline bool Representation::CanContainDouble(double value) {
   return false;
 }
 
+
+Representation Representation::FromType(Type* type) {
+  DisallowHeapAllocation no_allocation;
+  if (type->Is(Type::None())) return Representation::None();
+  if (type->Is(Type::SignedSmall())) return Representation::Smi();
+  if (type->Is(Type::Signed32())) return Representation::Integer32();
+  if (type->Is(Type::Number())) return Representation::Double();
+  return Representation::Tagged();
+}
+
 } }  // namespace v8::internal
 
 #endif  // V8_PROPERTY_DETAILS_INL_H_
index 7c2b246397dc0e0d6eda9c8f29c74519f54190c5..b1d60715ff1c06ecc38a8393032446a11dd404af 100644 (file)
@@ -13,7 +13,7 @@
 namespace v8 {
 namespace internal {
 
-// -------------------------------------------------------------------------- //
+// -----------------------------------------------------------------------------
 // TypeImpl
 
 template<class Config>
@@ -25,6 +25,18 @@ TypeImpl<Config>* TypeImpl<Config>::cast(typename Config::Base* object) {
 }
 
 
+// Most precise _current_ type of a value (usually its class).
+template<class Config>
+typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::NowOf(
+    i::Object* value, Region* region) {
+  if (value->IsSmi() ||
+      i::HeapObject::cast(value)->map()->instance_type() == HEAP_NUMBER_TYPE) {
+    return Of(value, region);
+  }
+  return Class(i::handle(i::HeapObject::cast(value)->map()), region);
+}
+
+
 template<class Config>
 bool TypeImpl<Config>::NowContains(i::Object* value) {
   DisallowHeapAllocation no_allocation;
@@ -39,7 +51,7 @@ bool TypeImpl<Config>::NowContains(i::Object* value) {
 }
 
 
-// -------------------------------------------------------------------------- //
+// -----------------------------------------------------------------------------
 // ZoneTypeConfig
 
 // static
@@ -70,13 +82,7 @@ bool ZoneTypeConfig::is_struct(Type* type, int tag) {
 
 // static
 bool ZoneTypeConfig::is_class(Type* type) {
-  return is_struct(type, Type::StructuralType::kClassTag);
-}
-
-
-// static
-bool ZoneTypeConfig::is_constant(Type* type) {
-  return is_struct(type, Type::StructuralType::kConstantTag);
+  return false;
 }
 
 
@@ -96,16 +102,8 @@ ZoneTypeConfig::Struct* ZoneTypeConfig::as_struct(Type* type) {
 
 // static
 i::Handle<i::Map> ZoneTypeConfig::as_class(Type* type) {
-  ASSERT(is_class(type));
-  return i::Handle<i::Map>(static_cast<i::Map**>(as_struct(type)[3]));
-}
-
-
-// static
-i::Handle<i::Object> ZoneTypeConfig::as_constant(Type* type) {
-  ASSERT(is_constant(type));
-  return i::Handle<i::Object>(
-      static_cast<i::Object**>(as_struct(type)[3]));
+  UNREACHABLE();
+  return i::Handle<i::Map>();
 }
 
 
@@ -122,84 +120,80 @@ ZoneTypeConfig::Type* ZoneTypeConfig::from_bitset(int bitset, Zone* Zone) {
 
 
 // static
-ZoneTypeConfig::Type* ZoneTypeConfig::from_struct(Struct* structured) {
-  return reinterpret_cast<Type*>(structured);
+ZoneTypeConfig::Type* ZoneTypeConfig::from_struct(Struct* structure) {
+  return reinterpret_cast<Type*>(structure);
 }
 
 
 // static
 ZoneTypeConfig::Type* ZoneTypeConfig::from_class(
-    i::Handle<i::Map> map, int lub, Zone* zone) {
-  Struct* structured = struct_create(Type::StructuralType::kClassTag, 2, zone);
-  structured[2] = from_bitset(lub);
-  structured[3] = map.location();
-  return from_struct(structured);
+    i::Handle<i::Map> map, Zone* zone) {
+  return from_bitset(0);
 }
 
 
 // static
-ZoneTypeConfig::Type* ZoneTypeConfig::from_constant(
-    i::Handle<i::Object> value, int lub, Zone* zone) {
-  Struct* structured =
-      struct_create(Type::StructuralType::kConstantTag, 2, zone);
-  structured[2] = from_bitset(lub);
-  structured[3] = value.location();
-  return from_struct(structured);
+ZoneTypeConfig::Struct* ZoneTypeConfig::struct_create(
+    int tag, int length, Zone* zone) {
+  Struct* structure = reinterpret_cast<Struct*>(
+      zone->New(sizeof(void*) * (length + 2)));  // NOLINT
+  structure[0] = reinterpret_cast<void*>(tag);
+  structure[1] = reinterpret_cast<void*>(length);
+  return structure;
 }
 
 
 // static
-ZoneTypeConfig::Struct* ZoneTypeConfig::struct_create(
-    int tag, int length, Zone* zone) {
-  Struct* structured = reinterpret_cast<Struct*>(
-      zone->New(sizeof(void*) * (length + 2)));  // NOLINT
-  structured[0] = reinterpret_cast<void*>(tag);
-  structured[1] = reinterpret_cast<void*>(length);
-  return structured;
+void ZoneTypeConfig::struct_shrink(Struct* structure, int length) {
+  ASSERT(0 <= length && length <= struct_length(structure));
+  structure[1] = reinterpret_cast<void*>(length);
 }
 
 
 // static
-void ZoneTypeConfig::struct_shrink(Struct* structured, int length) {
-  ASSERT(0 <= length && length <= struct_length(structured));
-  structured[1] = reinterpret_cast<void*>(length);
+int ZoneTypeConfig::struct_tag(Struct* structure) {
+  return static_cast<int>(reinterpret_cast<intptr_t>(structure[0]));
 }
 
 
 // static
-int ZoneTypeConfig::struct_tag(Struct* structured) {
-  return static_cast<int>(reinterpret_cast<intptr_t>(structured[0]));
+int ZoneTypeConfig::struct_length(Struct* structure) {
+  return static_cast<int>(reinterpret_cast<intptr_t>(structure[1]));
 }
 
 
 // static
-int ZoneTypeConfig::struct_length(Struct* structured) {
-  return static_cast<int>(reinterpret_cast<intptr_t>(structured[1]));
+Type* ZoneTypeConfig::struct_get(Struct* structure, int i) {
+  ASSERT(0 <= i && i <= struct_length(structure));
+  return static_cast<Type*>(structure[2 + i]);
 }
 
 
 // static
-Type* ZoneTypeConfig::struct_get(Struct* structured, int i) {
-  ASSERT(0 <= i && i <= struct_length(structured));
-  return static_cast<Type*>(structured[2 + i]);
+void ZoneTypeConfig::struct_set(Struct* structure, int i, Type* x) {
+  ASSERT(0 <= i && i <= struct_length(structure));
+  structure[2 + i] = x;
 }
 
 
 // static
-void ZoneTypeConfig::struct_set(Struct* structured, int i, Type* type) {
-  ASSERT(0 <= i && i <= struct_length(structured));
-  structured[2 + i] = type;
+template<class V>
+i::Handle<V> ZoneTypeConfig::struct_get_value(Struct* structure, int i) {
+  ASSERT(0 <= i && i <= struct_length(structure));
+  return i::Handle<V>(static_cast<V**>(structure[2 + i]));
 }
 
 
 // static
-int ZoneTypeConfig::lub_bitset(Type* type) {
-  ASSERT(is_class(type) || is_constant(type));
-  return as_bitset(struct_get(as_struct(type), 0));
+template<class V>
+void ZoneTypeConfig::struct_set_value(
+    Struct* structure, int i, i::Handle<V> x) {
+  ASSERT(0 <= i && i <= struct_length(structure));
+  structure[2 + i] = x.location();
 }
 
 
-// -------------------------------------------------------------------------- //
+// -----------------------------------------------------------------------------
 // HeapTypeConfig
 
 // static
@@ -228,12 +222,6 @@ bool HeapTypeConfig::is_class(Type* type) {
 }
 
 
-// static
-bool HeapTypeConfig::is_constant(Type* type) {
-  return type->IsBox();
-}
-
-
 // static
 bool HeapTypeConfig::is_struct(Type* type, int tag) {
   return type->IsFixedArray() && struct_tag(as_struct(type)) == tag;
@@ -252,13 +240,6 @@ i::Handle<i::Map> HeapTypeConfig::as_class(Type* type) {
 }
 
 
-// static
-i::Handle<i::Object> HeapTypeConfig::as_constant(Type* type) {
-  i::Box* box = i::Box::cast(type);
-  return i::handle(box->value(), box->GetIsolate());
-}
-
-
 // static
 i::Handle<HeapTypeConfig::Struct> HeapTypeConfig::as_struct(Type* type) {
   return i::handle(Struct::cast(type));
@@ -280,71 +261,74 @@ i::Handle<HeapTypeConfig::Type> HeapTypeConfig::from_bitset(
 
 // static
 i::Handle<HeapTypeConfig::Type> HeapTypeConfig::from_class(
-    i::Handle<i::Map> map, int lub, Isolate* isolate) {
+    i::Handle<i::Map> map, Isolate* isolate) {
   return i::Handle<Type>::cast(i::Handle<Object>::cast(map));
 }
 
 
-// static
-i::Handle<HeapTypeConfig::Type> HeapTypeConfig::from_constant(
-    i::Handle<i::Object> value, int lub, Isolate* isolate) {
-  i::Handle<Box> box = isolate->factory()->NewBox(value);
-  return i::Handle<Type>::cast(i::Handle<Object>::cast(box));
-}
-
-
 // static
 i::Handle<HeapTypeConfig::Type> HeapTypeConfig::from_struct(
-    i::Handle<Struct> structured) {
-  return i::Handle<Type>::cast(i::Handle<Object>::cast(structured));
+    i::Handle<Struct> structure) {
+  return i::Handle<Type>::cast(i::Handle<Object>::cast(structure));
 }
 
 
 // static
 i::Handle<HeapTypeConfig::Struct> HeapTypeConfig::struct_create(
     int tag, int length, Isolate* isolate) {
-  i::Handle<Struct> structured = isolate->factory()->NewFixedArray(length + 1);
-  structured->set(0, i::Smi::FromInt(tag));
-  return structured;
+  i::Handle<Struct> structure = isolate->factory()->NewFixedArray(length + 1);
+  structure->set(0, i::Smi::FromInt(tag));
+  return structure;
 }
 
 
 // static
-void HeapTypeConfig::struct_shrink(i::Handle<Struct> structured, int length) {
-  structured->Shrink(length + 1);
+void HeapTypeConfig::struct_shrink(i::Handle<Struct> structure, int length) {
+  structure->Shrink(length + 1);
 }
 
 
 // static
-int HeapTypeConfig::struct_tag(i::Handle<Struct> structured) {
-  return static_cast<i::Smi*>(structured->get(0))->value();
+int HeapTypeConfig::struct_tag(i::Handle<Struct> structure) {
+  return static_cast<i::Smi*>(structure->get(0))->value();
 }
 
 
 // static
-int HeapTypeConfig::struct_length(i::Handle<Struct> structured) {
-  return structured->length() - 1;
+int HeapTypeConfig::struct_length(i::Handle<Struct> structure) {
+  return structure->length() - 1;
 }
 
 
 // static
 i::Handle<HeapTypeConfig::Type> HeapTypeConfig::struct_get(
-    i::Handle<Struct> structured, int i) {
-  Type* type = static_cast<Type*>(structured->get(i + 1));
-  return i::handle(type, structured->GetIsolate());
+    i::Handle<Struct> structure, int i) {
+  Type* type = static_cast<Type*>(structure->get(i + 1));
+  return i::handle(type, structure->GetIsolate());
 }
 
 
 // static
 void HeapTypeConfig::struct_set(
-    i::Handle<Struct> structured, int i, i::Handle<Type> type) {
-  structured->set(i + 1, *type);
+    i::Handle<Struct> structure, int i, i::Handle<Type> type) {
+  structure->set(i + 1, *type);
+}
+
+
+// static
+template<class V>
+i::Handle<V> HeapTypeConfig::struct_get_value(
+    i::Handle<Struct> structure, int i) {
+  V* x = static_cast<V*>(structure->get(i + 1));
+  return i::handle(x, structure->GetIsolate());
 }
 
 
 // static
-int HeapTypeConfig::lub_bitset(Type* type) {
-  return 0;  // kNone, which causes recomputation.
+template<class V>
+void HeapTypeConfig::struct_set_value(
+    i::Handle<Struct> structure, int i, i::Handle<V> x) {
+  structure->set(i + 1, *x);
 }
 
 } }  // namespace v8::internal
index d7a631d4ae18bc00e5b6a62380833baf9358cb5c..87337dd14fc76544cea212b8f12b2a1b2f54e6a0 100644 (file)
 namespace v8 {
 namespace internal {
 
-template<class Config>
-int TypeImpl<Config>::NumClasses() {
-  DisallowHeapAllocation no_allocation;
-  if (this->IsClass()) {
-    return 1;
-  } else if (this->IsUnion()) {
-    UnionHandle unioned = handle(this->AsUnion());
-    int result = 0;
-    for (int i = 0; i < unioned->Length(); ++i) {
-      if (unioned->Get(i)->IsClass()) ++result;
-    }
-    return result;
-  } else {
-    return 0;
-  }
-}
-
+// -----------------------------------------------------------------------------
+// Glb and lub computation.
 
+// The largest bitset subsumed by this type.
 template<class Config>
-int TypeImpl<Config>::NumConstants() {
+int TypeImpl<Config>::BitsetType::Glb(TypeImpl* type) {
   DisallowHeapAllocation no_allocation;
-  if (this->IsConstant()) {
-    return 1;
-  } else if (this->IsUnion()) {
-    UnionHandle unioned = handle(this->AsUnion());
-    int result = 0;
+  if (type->IsBitset()) {
+    return type->AsBitset();
+  } else if (type->IsUnion()) {
+    UnionHandle unioned = handle(type->AsUnion());
+    int bitset = kNone;
     for (int i = 0; i < unioned->Length(); ++i) {
-      if (unioned->Get(i)->IsConstant()) ++result;
+      bitset |= unioned->Get(i)->BitsetGlb();
     }
-    return result;
+    return bitset;
+  } else if (type->IsClass()) {
+    // Little hack to avoid the need for a region for handlification here...
+    return REPRESENTATION(Config::is_class(type)
+        ? Lub(*Config::as_class(type))
+        : type->AsClass()->Bound(NULL)->AsBitset());
+  } else if (type->IsConstant()) {
+    return REPRESENTATION(type->AsConstant()->Bound()->AsBitset());
+  } else if (type->IsContext()) {
+    return REPRESENTATION(type->AsContext()->Bound()->AsBitset());
+  } else if (type->IsArray()) {
+    return REPRESENTATION(type->AsArray()->Bound()->AsBitset());
+  } else if (type->IsFunction()) {
+    return REPRESENTATION(type->AsFunction()->Bound()->AsBitset());
   } else {
-    return 0;
-  }
-}
-
-
-template<class Config> template<class T>
-typename TypeImpl<Config>::TypeHandle
-TypeImpl<Config>::Iterator<T>::get_type() {
-  ASSERT(!Done());
-  return type_->IsUnion() ? type_->AsUnion()->Get(index_) : type_;
-}
-
-
-// C++ cannot specialise nested templates, so we have to go through this
-// contortion with an auxiliary template to simulate it.
-template<class Config, class T>
-struct TypeImplIteratorAux {
-  static bool matches(typename TypeImpl<Config>::TypeHandle type);
-  static i::Handle<T> current(typename TypeImpl<Config>::TypeHandle type);
-};
-
-template<class Config>
-struct TypeImplIteratorAux<Config, i::Map> {
-  static bool matches(typename TypeImpl<Config>::TypeHandle type) {
-    return type->IsClass();
-  }
-  static i::Handle<i::Map> current(typename TypeImpl<Config>::TypeHandle type) {
-    return type->AsClass()->Map();
-  }
-};
-
-template<class Config>
-struct TypeImplIteratorAux<Config, i::Object> {
-  static bool matches(typename TypeImpl<Config>::TypeHandle type) {
-    return type->IsConstant();
-  }
-  static i::Handle<i::Object> current(
-      typename TypeImpl<Config>::TypeHandle type) {
-    return type->AsConstant()->Value();
-  }
-};
-
-template<class Config> template<class T>
-bool TypeImpl<Config>::Iterator<T>::matches(TypeHandle type) {
-  return TypeImplIteratorAux<Config, T>::matches(type);
-}
-
-template<class Config> template<class T>
-i::Handle<T> TypeImpl<Config>::Iterator<T>::Current() {
-  return TypeImplIteratorAux<Config, T>::current(get_type());
-}
-
-
-template<class Config> template<class T>
-void TypeImpl<Config>::Iterator<T>::Advance() {
-  DisallowHeapAllocation no_allocation;
-  ++index_;
-  if (type_->IsUnion()) {
-    UnionHandle unioned = handle(type_->AsUnion());
-    for (; index_ < unioned->Length(); ++index_) {
-      if (matches(unioned->Get(index_))) return;
-    }
-  } else if (index_ == 0 && matches(type_)) {
-    return;
+    UNREACHABLE();
+    return kNone;
   }
-  index_ = -1;
 }
 
 
-// Get the largest bitset subsumed by this type.
+// The smallest bitset subsuming this type.
 template<class Config>
-int TypeImpl<Config>::BitsetType::Glb(TypeImpl* type) {
+int TypeImpl<Config>::BitsetType::Lub(TypeImpl* type) {
   DisallowHeapAllocation no_allocation;
   if (type->IsBitset()) {
     return type->AsBitset();
   } else if (type->IsUnion()) {
-    // All but the first are non-bitsets and thus would yield kNone anyway.
-    return type->AsUnion()->Get(0)->BitsetGlb();
+    UnionHandle unioned = handle(type->AsUnion());
+    int bitset = kNone;
+    for (int i = 0; i < unioned->Length(); ++i) {
+      bitset |= unioned->Get(i)->BitsetLub();
+    }
+    return bitset;
+  } else if (type->IsClass()) {
+    // Little hack to avoid the need for a region for handlification here...
+    return Config::is_class(type) ? Lub(*Config::as_class(type)) :
+        type->AsClass()->Bound(NULL)->AsBitset();
+  } else if (type->IsConstant()) {
+    return type->AsConstant()->Bound()->AsBitset();
+  } else if (type->IsContext()) {
+    return type->AsContext()->Bound()->AsBitset();
+  } else if (type->IsArray()) {
+    return type->AsArray()->Bound()->AsBitset();
+  } else if (type->IsFunction()) {
+    return type->AsFunction()->Bound()->AsBitset();
   } else {
+    UNREACHABLE();
     return kNone;
   }
 }
 
 
-// Get the smallest bitset subsuming this type.
+// The smallest bitset subsuming this type, ignoring explicit bounds.
 template<class Config>
-int TypeImpl<Config>::BitsetType::Lub(TypeImpl* type) {
+int TypeImpl<Config>::BitsetType::InherentLub(TypeImpl* type) {
   DisallowHeapAllocation no_allocation;
   if (type->IsBitset()) {
     return type->AsBitset();
@@ -135,21 +88,19 @@ int TypeImpl<Config>::BitsetType::Lub(TypeImpl* type) {
     UnionHandle unioned = handle(type->AsUnion());
     int bitset = kNone;
     for (int i = 0; i < unioned->Length(); ++i) {
-      bitset |= unioned->Get(i)->BitsetLub();
+      bitset |= unioned->Get(i)->InherentBitsetLub();
     }
     return bitset;
   } else if (type->IsClass()) {
-    int bitset = Config::lub_bitset(type);
-    return bitset ? bitset : Lub(*type->AsClass()->Map());
+    return Lub(*type->AsClass()->Map());
   } else if (type->IsConstant()) {
-    int bitset = Config::lub_bitset(type);
-    return bitset ? bitset : Lub(*type->AsConstant()->Value());
+    return Lub(*type->AsConstant()->Value());
+  } else if (type->IsContext()) {
+    return kInternal & kTaggedPtr;
   } else if (type->IsArray()) {
     return kArray;
   } else if (type->IsFunction()) {
     return kFunction;
-  } else if (type->IsContext()) {
-    return kInternal & kTaggedPtr;
   } else {
     UNREACHABLE();
     return kNone;
@@ -295,17 +246,8 @@ int TypeImpl<Config>::BitsetType::Lub(i::Map* map) {
 }
 
 
-// Most precise _current_ type of a value (usually its class).
-template<class Config>
-typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::NowOf(
-    i::Object* value, Region* region) {
-  if (value->IsSmi() ||
-      i::HeapObject::cast(value)->map()->instance_type() == HEAP_NUMBER_TYPE) {
-    return Of(value, region);
-  }
-  return Class(i::handle(i::HeapObject::cast(value)->map()), region);
-}
-
+// -----------------------------------------------------------------------------
+// Predicates.
 
 // Check this <= that.
 template<class Config>
@@ -317,14 +259,23 @@ bool TypeImpl<Config>::SlowIs(TypeImpl* that) {
   if (that->IsBitset()) {
     return (BitsetType::Lub(this) | that->AsBitset()) == that->AsBitset();
   }
+  if (this->IsBitset() && SEMANTIC(this->AsBitset()) == BitsetType::kNone) {
+    // Bitsets only have non-bitset supertypes along the representation axis.
+    int that_bitset = that->BitsetGlb();
+    return (this->AsBitset() | that_bitset) == that_bitset;
+  }
 
   if (that->IsClass()) {
     return this->IsClass()
-        && *this->AsClass()->Map() == *that->AsClass()->Map();
+        && *this->AsClass()->Map() == *that->AsClass()->Map()
+        && ((Config::is_class(that) && Config::is_class(this)) ||
+            BitsetType::New(this->BitsetLub())->Is(
+                BitsetType::New(that->BitsetLub())));
   }
   if (that->IsConstant()) {
     return this->IsConstant()
-        && *this->AsConstant()->Value() == *that->AsConstant()->Value();
+        && *this->AsConstant()->Value() == *that->AsConstant()->Value()
+        && this->AsConstant()->Bound()->Is(that->AsConstant()->Bound());
   }
   if (that->IsContext()) {
     return this->IsContext()
@@ -461,10 +412,10 @@ bool TypeImpl<Config>::Maybe(TypeImpl* that) {
 }
 
 
+// Check if value is contained in (inhabits) type.
 template<class Config>
 bool TypeImpl<Config>::Contains(i::Object* value) {
   DisallowHeapAllocation no_allocation;
-
   for (Iterator<i::Object> it = this->Constants(); !it.Done(); it.Advance()) {
     if (*it.Current() == value) return true;
   }
@@ -473,44 +424,166 @@ bool TypeImpl<Config>::Contains(i::Object* value) {
 
 
 template<class Config>
-bool TypeImpl<Config>::InUnion(UnionHandle unioned, int current_size) {
+bool TypeImpl<Config>::UnionType::Wellformed() {
+  ASSERT(this->Length() >= 2);
+  for (int i = 0; i < this->Length(); ++i) {
+    ASSERT(!this->Get(i)->IsUnion());
+    if (i > 0) ASSERT(!this->Get(i)->IsBitset());
+    for (int j = 0; j < this->Length(); ++j) {
+      if (i != j) ASSERT(!this->Get(i)->Is(this->Get(j)));
+    }
+  }
+  return true;
+}
+
+
+// -----------------------------------------------------------------------------
+// Union and intersection
+
+template<class Config>
+typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Narrow(
+    int bitset, Region* region) {
+  TypeHandle bound = BitsetType::New(bitset, region);
+  if (this->IsClass()) {
+    return ClassType::New(this->AsClass()->Map(), bound, region);
+  } else if (this->IsConstant()) {
+    return ConstantType::New(this->AsConstant()->Value(), bound, region);
+  } else if (this->IsContext()) {
+    return ContextType::New(this->AsContext()->Outer(), bound, region);
+  } else if (this->IsArray()) {
+    return ArrayType::New(this->AsArray()->Element(), bound, region);
+  } else if (this->IsFunction()) {
+    FunctionType* function = this->AsFunction();
+    int arity = function->Arity();
+    FunctionHandle type = FunctionType::New(
+        function->Result(), function->Receiver(), bound, arity, region);
+    for (int i = 0; i < arity; ++i) {
+      type->InitParameter(i, function->Parameter(i));
+    }
+    return type;
+  }
+  UNREACHABLE();
+  return TypeHandle();
+}
+
+
+template<class Config>
+int TypeImpl<Config>::BoundBy(TypeImpl* that) {
+  ASSERT(!this->IsUnion());
+  if (that->IsUnion()) {
+    UnionType* unioned = that->AsUnion();
+    int length = unioned->Length();
+    int bitset = BitsetType::kNone;
+    for (int i = 0; i < length; ++i) {
+      bitset |= BoundBy(unioned->Get(i)->unhandle());
+    }
+    return bitset;
+  } else if (that->IsClass() && this->IsClass() &&
+      *this->AsClass()->Map() == *that->AsClass()->Map()) {
+    return that->BitsetLub();
+  } else if (that->IsConstant() && this->IsConstant() &&
+      *this->AsConstant()->Value() == *that->AsConstant()->Value()) {
+    return that->AsConstant()->Bound()->AsBitset();
+  } else if (that->IsContext() && this->IsContext() && this->Is(that)) {
+    return that->AsContext()->Bound()->AsBitset();
+  } else if (that->IsArray() && this->IsArray() && this->Is(that)) {
+    return that->AsArray()->Bound()->AsBitset();
+  } else if (that->IsFunction() && this->IsFunction() && this->Is(that)) {
+    return that->AsFunction()->Bound()->AsBitset();
+  }
+  return that->BitsetGlb();
+}
+
+
+template<class Config>
+int TypeImpl<Config>::IndexInUnion(
+    int bound, UnionHandle unioned, int current_size) {
   ASSERT(!this->IsUnion());
   for (int i = 0; i < current_size; ++i) {
-    if (this->Is(unioned->Get(i))) return true;
+    TypeHandle that = unioned->Get(i);
+    if (that->IsBitset()) {
+      if ((bound | that->AsBitset()) == that->AsBitset()) return i;
+    } else if (that->IsClass() && this->IsClass()) {
+      if (*this->AsClass()->Map() == *that->AsClass()->Map()) return i;
+    } else if (that->IsConstant() && this->IsConstant()) {
+      if (*this->AsConstant()->Value() == *that->AsConstant()->Value())
+        return i;
+    } else if (that->IsContext() && this->IsContext()) {
+      if (this->Is(that)) return i;
+    } else if (that->IsArray() && this->IsArray()) {
+      if (this->Is(that)) return i;
+    } else if (that->IsFunction() && this->IsFunction()) {
+      if (this->Is(that)) return i;
+    }
   }
-  return false;
+  return -1;
 }
 
 
-// Get non-bitsets from this which are not subsumed by union, store at result,
-// starting at index. Returns updated index.
+// Get non-bitsets from type, bounded by upper.
+// Store at result starting at index. Returns updated index.
 template<class Config>
 int TypeImpl<Config>::ExtendUnion(
-    UnionHandle result, TypeHandle type, int current_size) {
-  int old_size = current_size;
+    UnionHandle result, int size, TypeHandle type,
+    TypeHandle other, bool is_intersect, Region* region) {
+  int old_size = size;
   if (type->IsUnion()) {
     UnionHandle unioned = handle(type->AsUnion());
     for (int i = 0; i < unioned->Length(); ++i) {
-      TypeHandle type = unioned->Get(i);
-      ASSERT(i == 0 || !(type->IsBitset() || type->Is(unioned->Get(0))));
-      if (!type->IsBitset() && !type->InUnion(result, old_size)) {
-        result->Set(current_size++, type);
+      TypeHandle type_i = unioned->Get(i);
+      ASSERT(i == 0 || !(type_i->IsBitset() || type_i->Is(unioned->Get(0))));
+      if (!type_i->IsBitset()) {
+        size = ExtendUnion(result, size, type_i, other, is_intersect, region);
       }
     }
   } else if (!type->IsBitset()) {
-    // For all structural types, subtyping implies equivalence.
     ASSERT(type->IsClass() || type->IsConstant() ||
-           type->IsArray() || type->IsFunction() ||
-           type->IsContext());
-    if (!type->InUnion(result, old_size)) {
-      result->Set(current_size++, type);
+           type->IsArray() || type->IsFunction() || type->IsContext());
+    int inherent_bound = type->InherentBitsetLub();
+    int old_bound = type->BitsetLub();
+    int other_bound = type->BoundBy(other->unhandle()) & inherent_bound;
+    int new_bound =
+        is_intersect ? (old_bound & other_bound) : (old_bound | other_bound);
+    if (new_bound != BitsetType::kNone) {
+      int i = type->IndexInUnion(new_bound, result, old_size);
+      if (i == -1) {
+        i = size++;
+      } else if (result->Get(i)->IsBitset()) {
+        return size;  // Already fully subsumed.
+      } else {
+        int type_i_bound = result->Get(i)->BitsetLub();
+        new_bound |= type_i_bound;
+        if (new_bound == type_i_bound) return size;
+      }
+      if (new_bound != old_bound) type = type->Narrow(new_bound, region);
+      result->Set(i, type);
     }
   }
-  return current_size;
+  return size;
 }
 
 
-// Union is O(1) on simple bit unions, but O(n*m) on structured unions.
+// If bitset is subsumed by another entry in the result, remove it.
+// (Only bitsets with empty semantic axis can be subtypes of non-bitsets.)
+template<class Config>
+int TypeImpl<Config>::NormalizeUnion(UnionHandle result, int size, int bitset) {
+  if (bitset != BitsetType::kNone && SEMANTIC(bitset) == BitsetType::kNone) {
+    for (int i = 1; i < size; ++i) {
+      int glb = result->Get(i)->BitsetGlb();
+      if ((bitset | glb) == glb) {
+        for (int j = 1; j < size; ++j) {
+          result->Set(j - 1, result->Get(j));
+        }
+        --size;
+        break;
+      }
+    }
+  }
+  return size;
+}
+
+
+// Union is O(1) on simple bitsets, but O(n*m) on structured unions.
 template<class Config>
 typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Union(
     TypeHandle type1, TypeHandle type2, Region* region) {
@@ -546,47 +619,21 @@ typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Union(
   if (bitset != BitsetType::kNone) {
     unioned->Set(size++, BitsetType::New(bitset, region));
   }
-  size = ExtendUnion(unioned, type1, size);
-  size = ExtendUnion(unioned, type2, size);
+  size = ExtendUnion(unioned, size, type1, type2, false, region);
+  size = ExtendUnion(unioned, size, type2, type1, false, region);
+  size = NormalizeUnion(unioned, size, bitset);
 
   if (size == 1) {
     return unioned->Get(0);
   } else {
     unioned->Shrink(size);
+    ASSERT(unioned->Wellformed());
     return unioned;
   }
 }
 
 
-// Get non-bitsets from type which are also in other, store at result,
-// starting at index. Returns updated index.
-template<class Config>
-int TypeImpl<Config>::ExtendIntersection(
-    UnionHandle result, TypeHandle type, TypeHandle other, int current_size) {
-  int old_size = current_size;
-  if (type->IsUnion()) {
-    UnionHandle unioned = handle(type->AsUnion());
-    for (int i = 0; i < unioned->Length(); ++i) {
-      TypeHandle type = unioned->Get(i);
-      ASSERT(i == 0 || !(type->IsBitset() || type->Is(unioned->Get(0))));
-      if (!type->IsBitset() && type->Is(other) &&
-          !type->InUnion(result, old_size)) {
-        result->Set(current_size++, type);
-      }
-    }
-  } else if (!type->IsBitset()) {
-    // For all structural types, subtyping implies equivalence.
-    ASSERT(type->IsClass() || type->IsConstant() ||
-           type->IsArray() || type->IsFunction() || type->IsContext());
-    if (type->Is(other) && !type->InUnion(result, old_size)) {
-      result->Set(current_size++, type);
-    }
-  }
-  return current_size;
-}
-
-
-// Intersection is O(1) on simple bit unions, but O(n*m) on structured unions.
+// Intersection is O(1) on simple bitsets, but O(n*m) on structured unions.
 template<class Config>
 typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Intersect(
     TypeHandle type1, TypeHandle type2, Region* region) {
@@ -622,8 +669,9 @@ typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Intersect(
   if (bitset != BitsetType::kNone) {
     unioned->Set(size++, BitsetType::New(bitset, region));
   }
-  size = ExtendIntersection(unioned, type1, type2, size);
-  size = ExtendIntersection(unioned, type2, type1, size);
+  size = ExtendUnion(unioned, size, type1, type2, true, region);
+  size = ExtendUnion(unioned, size, type2, type1, true, region);
+  size = NormalizeUnion(unioned, size, bitset);
 
   if (size == 0) {
     return None(region);
@@ -631,11 +679,118 @@ typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Intersect(
     return unioned->Get(0);
   } else {
     unioned->Shrink(size);
+    ASSERT(unioned->Wellformed());
     return unioned;
   }
 }
 
 
+// -----------------------------------------------------------------------------
+// Iteration.
+
+template<class Config>
+int TypeImpl<Config>::NumClasses() {
+  DisallowHeapAllocation no_allocation;
+  if (this->IsClass()) {
+    return 1;
+  } else if (this->IsUnion()) {
+    UnionHandle unioned = handle(this->AsUnion());
+    int result = 0;
+    for (int i = 0; i < unioned->Length(); ++i) {
+      if (unioned->Get(i)->IsClass()) ++result;
+    }
+    return result;
+  } else {
+    return 0;
+  }
+}
+
+
+template<class Config>
+int TypeImpl<Config>::NumConstants() {
+  DisallowHeapAllocation no_allocation;
+  if (this->IsConstant()) {
+    return 1;
+  } else if (this->IsUnion()) {
+    UnionHandle unioned = handle(this->AsUnion());
+    int result = 0;
+    for (int i = 0; i < unioned->Length(); ++i) {
+      if (unioned->Get(i)->IsConstant()) ++result;
+    }
+    return result;
+  } else {
+    return 0;
+  }
+}
+
+
+template<class Config> template<class T>
+typename TypeImpl<Config>::TypeHandle
+TypeImpl<Config>::Iterator<T>::get_type() {
+  ASSERT(!Done());
+  return type_->IsUnion() ? type_->AsUnion()->Get(index_) : type_;
+}
+
+
+// C++ cannot specialise nested templates, so we have to go through this
+// contortion with an auxiliary template to simulate it.
+template<class Config, class T>
+struct TypeImplIteratorAux {
+  static bool matches(typename TypeImpl<Config>::TypeHandle type);
+  static i::Handle<T> current(typename TypeImpl<Config>::TypeHandle type);
+};
+
+template<class Config>
+struct TypeImplIteratorAux<Config, i::Map> {
+  static bool matches(typename TypeImpl<Config>::TypeHandle type) {
+    return type->IsClass();
+  }
+  static i::Handle<i::Map> current(typename TypeImpl<Config>::TypeHandle type) {
+    return type->AsClass()->Map();
+  }
+};
+
+template<class Config>
+struct TypeImplIteratorAux<Config, i::Object> {
+  static bool matches(typename TypeImpl<Config>::TypeHandle type) {
+    return type->IsConstant();
+  }
+  static i::Handle<i::Object> current(
+      typename TypeImpl<Config>::TypeHandle type) {
+    return type->AsConstant()->Value();
+  }
+};
+
+template<class Config> template<class T>
+bool TypeImpl<Config>::Iterator<T>::matches(TypeHandle type) {
+  return TypeImplIteratorAux<Config, T>::matches(type);
+}
+
+template<class Config> template<class T>
+i::Handle<T> TypeImpl<Config>::Iterator<T>::Current() {
+  return TypeImplIteratorAux<Config, T>::current(get_type());
+}
+
+
+template<class Config> template<class T>
+void TypeImpl<Config>::Iterator<T>::Advance() {
+  DisallowHeapAllocation no_allocation;
+  ++index_;
+  if (type_->IsUnion()) {
+    UnionHandle unioned = handle(type_->AsUnion());
+    for (; index_ < unioned->Length(); ++index_) {
+      if (matches(unioned->Get(index_))) return;
+    }
+  } else if (index_ == 0 && matches(type_)) {
+    return;
+  }
+  index_ = -1;
+}
+
+
+// -----------------------------------------------------------------------------
+// Conversion between low-level representations.
+
 template<class Config>
 template<class OtherType>
 typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Convert(
@@ -643,9 +798,13 @@ typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Convert(
   if (type->IsBitset()) {
     return BitsetType::New(type->AsBitset(), region);
   } else if (type->IsClass()) {
-    return ClassType::New(type->AsClass()->Map(), region);
+    return ClassType::New(
+        type->AsClass()->Map(),
+        BitsetType::New(type->BitsetLub(), region), region);
   } else if (type->IsConstant()) {
-    return ConstantType::New(type->AsConstant()->Value(), region);
+    return ConstantType::New(
+        type->AsConstant()->Value(),
+        Convert<OtherType>(type->AsConstant()->Bound(), region), region);
   } else if (type->IsContext()) {
     TypeHandle outer = Convert<OtherType>(type->AsContext()->Outer(), region);
     return ContextType::New(outer, region);
@@ -658,11 +817,13 @@ typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Convert(
     return unioned;
   } else if (type->IsArray()) {
     return ArrayType::New(
-        Convert<OtherType>(type->AsArray()->Element(), region), region);
+        Convert<OtherType>(type->AsArray()->Element(), region),
+        Convert<OtherType>(type->AsArray()->Bound(), region), region);
   } else if (type->IsFunction()) {
     FunctionHandle function = FunctionType::New(
         Convert<OtherType>(type->AsFunction()->Result(), region),
         Convert<OtherType>(type->AsFunction()->Receiver(), region),
+        Convert<OtherType>(type->AsFunction()->Bound(), region),
         type->AsFunction()->Arity(), region);
     for (int i = 0; i < function->Arity(); ++i) {
       function->InitParameter(i,
@@ -676,16 +837,8 @@ typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Convert(
 }
 
 
-// TODO(rossberg): this does not belong here.
-Representation Representation::FromType(Type* type) {
-  DisallowHeapAllocation no_allocation;
-  if (type->Is(Type::None())) return Representation::None();
-  if (type->Is(Type::SignedSmall())) return Representation::Smi();
-  if (type->Is(Type::Signed32())) return Representation::Integer32();
-  if (type->Is(Type::Number())) return Representation::Double();
-  return Representation::Tagged();
-}
-
+// -----------------------------------------------------------------------------
+// Printing.
 
 template<class Config>
 const char* TypeImpl<Config>::BitsetType::Name(int bitset) {
@@ -744,61 +897,59 @@ void TypeImpl<Config>::BitsetType::PrintTo(StringStream* stream, int bitset) {
 template<class Config>
 void TypeImpl<Config>::PrintTo(StringStream* stream, PrintDimension dim) {
   DisallowHeapAllocation no_allocation;
-  if (this->IsBitset()) {
-    int bitset = this->AsBitset();
-    switch (dim) {
-      case BOTH_DIMS:
-        BitsetType::PrintTo(stream, SEMANTIC(bitset));
-        stream->Add("/");
-        BitsetType::PrintTo(stream, REPRESENTATION(bitset));
-        break;
-      case SEMANTIC_DIM:
-        BitsetType::PrintTo(stream, SEMANTIC(bitset));
-        break;
-      case REPRESENTATION_DIM:
-        BitsetType::PrintTo(stream, REPRESENTATION(bitset));
-        break;
-    }
-  } else if (this->IsConstant()) {
-    stream->Add("Constant(%p : ",
-        static_cast<void*>(*this->AsConstant()->Value()));
-    BitsetType::New(BitsetType::Lub(this))->PrintTo(stream, dim);
-    stream->Add(")");
-  } else if (this->IsClass()) {
-    stream->Add("Class(%p < ", static_cast<void*>(*this->AsClass()->Map()));
-    BitsetType::New(BitsetType::Lub(this))->PrintTo(stream, dim);
-    stream->Add(")");
-  } else if (this->IsContext()) {
-    stream->Add("Context(");
-    this->AsContext()->Outer()->PrintTo(stream, dim);
-    stream->Add(")");
-  } else if (this->IsUnion()) {
-    stream->Add("(");
-    UnionHandle unioned = handle(this->AsUnion());
-    for (int i = 0; i < unioned->Length(); ++i) {
-      TypeHandle type_i = unioned->Get(i);
-      if (i > 0) stream->Add(" | ");
-      type_i->PrintTo(stream, dim);
-    }
-    stream->Add(")");
-  } else if (this->IsArray()) {
-    stream->Add("[");
-    AsArray()->Element()->PrintTo(stream, dim);
-    stream->Add("]");
-  } else if (this->IsFunction()) {
-    if (!this->AsFunction()->Receiver()->IsAny()) {
-      this->AsFunction()->Receiver()->PrintTo(stream, dim);
-      stream->Add(".");
-    }
-    stream->Add("(");
-    for (int i = 0; i < this->AsFunction()->Arity(); ++i) {
-      if (i > 0) stream->Add(", ");
-      this->AsFunction()->Parameter(i)->PrintTo(stream, dim);
+  if (dim != REPRESENTATION_DIM) {
+    if (this->IsBitset()) {
+      BitsetType::PrintTo(stream, SEMANTIC(this->AsBitset()));
+    } else if (this->IsClass()) {
+      stream->Add("Class(%p < ", static_cast<void*>(*this->AsClass()->Map()));
+      BitsetType::New(BitsetType::Lub(this))->PrintTo(stream, dim);
+      stream->Add(")");
+      return;
+    } else if (this->IsConstant()) {
+      stream->Add("Constant(%p : ",
+             static_cast<void*>(*this->AsConstant()->Value()));
+      BitsetType::New(BitsetType::Lub(this))->PrintTo(stream, dim);
+      stream->Add(")");
+      return;
+    } else if (this->IsContext()) {
+      stream->Add("Context(");
+      this->AsContext()->Outer()->PrintTo(stream, dim);
+      stream->Add(")");
+    } else if (this->IsUnion()) {
+      stream->Add("(");
+      UnionHandle unioned = handle(this->AsUnion());
+      for (int i = 0; i < unioned->Length(); ++i) {
+        TypeHandle type_i = unioned->Get(i);
+        if (i > 0) stream->Add(" | ");
+        type_i->PrintTo(stream, dim);
+      }
+      stream->Add(")");
+      return;
+    } else if (this->IsArray()) {
+      stream->Add("Array(");
+      AsArray()->Element()->PrintTo(stream, dim);
+      stream->Add(")");
+    } else if (this->IsFunction()) {
+      if (!this->AsFunction()->Receiver()->IsAny()) {
+        this->AsFunction()->Receiver()->PrintTo(stream, dim);
+        stream->Add(".");
+      }
+      stream->Add("(");
+      for (int i = 0; i < this->AsFunction()->Arity(); ++i) {
+        if (i > 0) stream->Add(", ");
+        this->AsFunction()->Parameter(i)->PrintTo(stream, dim);
+      }
+      stream->Add(")->");
+      this->AsFunction()->Result()->PrintTo(stream, dim);
+    } else {
+      UNREACHABLE();
     }
-    stream->Add(")->");
-    this->AsFunction()->Result()->PrintTo(stream, dim);
-  } else {
-    UNREACHABLE();
+  }
+  if (dim == BOTH_DIMS) {
+    stream->Add("/");
+  }
+  if (dim != SEMANTIC_DIM) {
+    BitsetType::PrintTo(stream, REPRESENTATION(this->BitsetLub()));
   }
 }
 
@@ -820,6 +971,9 @@ void TypeImpl<Config>::TypePrint(PrintDimension dim) {
 }
 
 
+// -----------------------------------------------------------------------------
+// Instantiations.
+
 template class TypeImpl<ZoneTypeConfig>;
 template class TypeImpl<ZoneTypeConfig>::Iterator<i::Map>;
 template class TypeImpl<ZoneTypeConfig>::Iterator<i::Object>;
index 1fdfdae5bfa662f15ef2cef1b1e04857c26ef79b..451ad1add948fe5119775715e0147243df5f9dbf 100644 (file)
@@ -132,6 +132,9 @@ namespace internal {
 // them. For zone types, no query method touches the heap, only constructors do.
 
 
+// -----------------------------------------------------------------------------
+// Values for bitset types
+
 #define MASK_BITSET_TYPE_LIST(V) \
   V(Representation, static_cast<int>(0xffc00000)) \
   V(Semantic,       static_cast<int>(0x003fffff))
@@ -207,6 +210,9 @@ namespace internal {
   SEMANTIC_BITSET_TYPE_LIST(V)
 
 
+// -----------------------------------------------------------------------------
+// The abstract Type class, parameterized over the low-level representation.
+
 // struct Config {
 //   typedef TypeImpl<Config> Type;
 //   typedef Base;
@@ -217,16 +223,13 @@ namespace internal {
 //   template<class T> static Handle<T>::type cast(Handle<Type>::type);
 //   static bool is_bitset(Type*);
 //   static bool is_class(Type*);
-//   static bool is_constant(Type*);
 //   static bool is_struct(Type*, int tag);
 //   static int as_bitset(Type*);
 //   static i::Handle<i::Map> as_class(Type*);
-//   static i::Handle<i::Object> as_constant(Type*);
 //   static Handle<Struct>::type as_struct(Type*);
 //   static Type* from_bitset(int bitset);
 //   static Handle<Type>::type from_bitset(int bitset, Region*);
-//   static Handle<Type>::type from_class(i::Handle<Map>, int lub, Region*);
-//   static Handle<Type>::type from_constant(i::Handle<Object>, int, 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*);
 //   static void struct_shrink(Handle<Struct>::type, int length);
@@ -234,11 +237,16 @@ namespace internal {
 //   static int struct_length(Handle<Struct>::type);
 //   static Handle<Type>::type struct_get(Handle<Struct>::type, int);
 //   static void struct_set(Handle<Struct>::type, int, Handle<Type>::type);
-//   static int lub_bitset(Type*);
+//   template<class V>
+//   static i::Handle<V> struct_get_value(Handle<Struct>::type, int);
+//   template<class V>
+//   static void struct_set_value(Handle<Struct>::type, int, i::Handle<V>);
 // }
 template<class Config>
 class TypeImpl : public Config::Base {
  public:
+  // Auxiliary types.
+
   class BitsetType;      // Internal
   class StructuralType;  // Internal
   class UnionType;       // Internal
@@ -258,6 +266,8 @@ class TypeImpl : public Config::Base {
   typedef typename Config::template Handle<UnionType>::type UnionHandle;
   typedef typename Config::Region Region;
 
+  // Constructors.
+
   #define DEFINE_TYPE_CONSTRUCTOR(type, value)                                \
     static TypeImpl* type() { return BitsetType::New(BitsetType::k##type); }  \
     static TypeHandle type(Region* region) {                                  \
@@ -321,9 +331,9 @@ class TypeImpl : public Config::Base {
     return Of(*value, region);
   }
 
-  bool IsInhabited() {
-    return !this->IsBitset() || BitsetType::IsInhabited(this->AsBitset());
-  }
+  // Predicates.
+
+  bool IsInhabited() { return BitsetType::IsInhabited(this->BitsetLub()); }
 
   bool Is(TypeImpl* that) { return this == that || this->SlowIs(that); }
   template<class TypeHandle>
@@ -341,9 +351,9 @@ class TypeImpl : public Config::Base {
   bool Contains(i::Object* val);
   bool Contains(i::Handle<i::Object> val) { return this->Contains(*val); }
 
-  // State-dependent versions of Of and Is that consider subtyping between
+  // State-dependent versions of the above that consider subtyping between
   // a constant and its map class.
-  static TypeHandle NowOf(i::Object* value, Region* region);
+  inline static TypeHandle NowOf(i::Object* value, Region* region);
   static TypeHandle NowOf(i::Handle<i::Object> value, Region* region) {
     return NowOf(*value, region);
   }
@@ -355,12 +365,21 @@ class TypeImpl : public Config::Base {
 
   bool NowStable();
 
-  bool IsClass() { return Config::is_class(this); }
-  bool IsConstant() { return Config::is_constant(this); }
+  // Inspection.
+
+  bool IsClass() {
+    return Config::is_class(this)
+        || Config::is_struct(this, StructuralType::kClassTag);
+  }
+  bool IsConstant() {
+    return Config::is_struct(this, StructuralType::kConstantTag);
+  }
   bool IsContext() {
     return Config::is_struct(this, StructuralType::kContextTag);
   }
-  bool IsArray() { return Config::is_struct(this, StructuralType::kArrayTag); }
+  bool IsArray() {
+    return Config::is_struct(this, StructuralType::kArrayTag);
+  }
   bool IsFunction() {
     return Config::is_struct(this, StructuralType::kFunctionTag);
   }
@@ -384,25 +403,37 @@ class TypeImpl : public Config::Base {
     return Iterator<i::Object>(Config::handle(this));
   }
 
+  // Casting and conversion.
+
   static inline TypeImpl* cast(typename Config::Base* object);
 
   template<class OtherTypeImpl>
   static TypeHandle Convert(
       typename OtherTypeImpl::TypeHandle type, Region* region);
 
+  // Printing.
+
   enum PrintDimension { BOTH_DIMS, SEMANTIC_DIM, REPRESENTATION_DIM };
+
   void PrintTo(StringStream* stream, PrintDimension = BOTH_DIMS);
   void TypePrint(PrintDimension = BOTH_DIMS);
   void TypePrint(FILE* out, PrintDimension = BOTH_DIMS);
 
  protected:
+  // Friends.
+
   template<class> friend class Iterator;
   template<class> friend class TypeImpl;
 
+  // Handle conversion.
+
   template<class T>
   static typename Config::template Handle<T>::type handle(T* type) {
     return Config::handle(type);
   }
+  TypeImpl* unhandle() { return this; }
+
+  // Internal inspection.
 
   bool IsNone() { return this == None(); }
   bool IsAny() { return this == Any(); }
@@ -415,19 +446,27 @@ class TypeImpl : public Config::Base {
   }
   UnionType* AsUnion() { return UnionType::cast(this); }
 
-  bool SlowIs(TypeImpl* that);
-
-  bool InUnion(UnionHandle unioned, int current_size);
-  static int ExtendUnion(
-      UnionHandle unioned, TypeHandle t, int current_size);
-  static int ExtendIntersection(
-      UnionHandle unioned, TypeHandle t, TypeHandle other, int current_size);
+  // Auxiliary functions.
 
   int BitsetGlb() { return BitsetType::Glb(this); }
   int BitsetLub() { return BitsetType::Lub(this); }
+  int InherentBitsetLub() { return BitsetType::InherentLub(this); }
+
+  bool SlowIs(TypeImpl* that);
+
+  TypeHandle Narrow(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 int NormalizeUnion(UnionHandle unioned, int current_size, int bitset);
 };
 
 
+// -----------------------------------------------------------------------------
+// Bitset types (internal).
+
 template<class Config>
 class TypeImpl<Config>::BitsetType : public TypeImpl<Config> {
  private:
@@ -442,7 +481,7 @@ class TypeImpl<Config>::BitsetType : public TypeImpl<Config> {
 
   int Bitset() { return Config::as_bitset(this); }
 
-  static BitsetType* New(int bitset) {
+  static TypeImpl* New(int bitset) {
     return static_cast<BitsetType*>(Config::from_bitset(bitset));
   }
   static TypeHandle New(int bitset, Region* region) {
@@ -460,6 +499,7 @@ 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 InherentLub(TypeImpl* type);
 
   static const char* Name(int bitset);
   static void PrintTo(StringStream* stream, int bitset);
@@ -467,8 +507,10 @@ class TypeImpl<Config>::BitsetType : public TypeImpl<Config> {
 };
 
 
-// Internal
-// A structured type contains a tag and a variable number of type fields.
+// -----------------------------------------------------------------------------
+// Superclass for non-bitset types (internal).
+// Contains a tag and a variable number of type or value fields.
+
 template<class Config>
 class TypeImpl<Config>::StructuralType : public TypeImpl<Config> {
  protected:
@@ -489,29 +531,92 @@ class TypeImpl<Config>::StructuralType : public TypeImpl<Config> {
     return Config::struct_length(Config::as_struct(this));
   }
   TypeHandle Get(int i) {
+    ASSERT(0 <= i && i < this->Length());
     return Config::struct_get(Config::as_struct(this), i);
   }
   void Set(int i, TypeHandle type) {
+    ASSERT(0 <= i && i < this->Length());
     Config::struct_set(Config::as_struct(this), i, type);
   }
   void Shrink(int length) {
+    ASSERT(2 <= length && length <= this->Length());
     Config::struct_shrink(Config::as_struct(this), length);
   }
+  template<class V> i::Handle<V> GetValue(int i) {
+    ASSERT(0 <= i && i < this->Length());
+    return Config::template struct_get_value<V>(Config::as_struct(this), i);
+  }
+  template<class V> void SetValue(int i, i::Handle<V> x) {
+    ASSERT(0 <= i && i < this->Length());
+    Config::struct_set_value(Config::as_struct(this), i, x);
+  }
 
   static TypeHandle New(Tag tag, int length, Region* region) {
+    ASSERT(1 <= length);
     return Config::from_struct(Config::struct_create(tag, length, region));
   }
 };
 
 
+// -----------------------------------------------------------------------------
+// Union types (internal).
+// A union is a structured type with the following invariants:
+// - its length is at least 2
+// - at most one field is a bitset, and it must go into index 0
+// - no field is a union
+// - no field is a subtype of any other field
 template<class Config>
-class TypeImpl<Config>::ClassType : public TypeImpl<Config> {
+class TypeImpl<Config>::UnionType : public StructuralType {
  public:
-  i::Handle<i::Map> Map() { return Config::as_class(this); }
+  static UnionHandle New(int length, Region* region) {
+    return Config::template cast<UnionType>(
+        StructuralType::New(StructuralType::kUnionTag, length, region));
+  }
+
+  static UnionType* cast(TypeImpl* type) {
+    ASSERT(type->IsUnion());
+    return static_cast<UnionType*>(type);
+  }
+
+  bool Wellformed();
+};
+
+
+// -----------------------------------------------------------------------------
+// Class types.
+
+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) {
+    ClassHandle type = Config::template cast<ClassType>(
+        StructuralType::New(StructuralType::kClassTag, 2, region));
+    type->Set(0, bound);
+    type->SetValue(1, map);
+    return type;
+  }
 
   static ClassHandle New(i::Handle<i::Map> map, Region* region) {
-    return Config::template cast<ClassType>(
-        Config::from_class(map, BitsetType::Lub(*map), 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);
+    }
   }
 
   static ClassType* cast(TypeImpl* type) {
@@ -521,14 +626,27 @@ class TypeImpl<Config>::ClassType : public TypeImpl<Config> {
 };
 
 
+// -----------------------------------------------------------------------------
+// Constant types.
+
 template<class Config>
-class TypeImpl<Config>::ConstantType : public TypeImpl<Config> {
+class TypeImpl<Config>::ConstantType : public StructuralType {
  public:
-  i::Handle<i::Object> Value() { return Config::as_constant(this); }
+  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) {
+    ConstantHandle type = Config::template cast<ConstantType>(
+        StructuralType::New(StructuralType::kConstantTag, 2, region));
+    type->Set(0, bound);
+    type->SetValue(1, value);
+    return type;
+  }
 
   static ConstantHandle New(i::Handle<i::Object> value, Region* region) {
-    return Config::template cast<ConstantType>(
-        Config::from_constant(value, BitsetType::Lub(*value), region));
+    TypeHandle bound = BitsetType::New(BitsetType::Lub(*value), region);
+    return New(value, bound, region);
   }
 
   static ConstantType* cast(TypeImpl* type) {
@@ -538,18 +656,29 @@ class TypeImpl<Config>::ConstantType : public TypeImpl<Config> {
 };
 
 
+// -----------------------------------------------------------------------------
+// Context types.
+
 template<class Config>
 class TypeImpl<Config>::ContextType : public StructuralType {
  public:
-  TypeHandle Outer() { return this->Get(0); }
+  TypeHandle Bound() { return this->Get(0); }
+  TypeHandle Outer() { return this->Get(1); }
 
-  static ContextHandle New(TypeHandle outer, Region* region) {
+  static ContextHandle New(TypeHandle outer, TypeHandle bound, Region* region) {
     ContextHandle type = Config::template cast<ContextType>(
-        StructuralType::New(StructuralType::kContextTag, 1, region));
-    type->Set(0, outer);
+        StructuralType::New(StructuralType::kContextTag, 2, region));
+    type->Set(0, bound);
+    type->Set(1, 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) {
     ASSERT(type->IsContext());
     return static_cast<ContextType*>(type);
@@ -557,38 +686,29 @@ class TypeImpl<Config>::ContextType : public StructuralType {
 };
 
 
-// Internal
-// A union is a structured type with the following invariants:
-// - its length is at least 2
-// - at most one field is a bitset, and it must go into index 0
-// - no field is a union
-template<class Config>
-class TypeImpl<Config>::UnionType : public StructuralType {
- public:
-  static UnionHandle New(int length, Region* region) {
-    return Config::template cast<UnionType>(
-        StructuralType::New(StructuralType::kUnionTag, length, region));
-  }
-
-  static UnionType* cast(TypeImpl* type) {
-    ASSERT(type->IsUnion());
-    return static_cast<UnionType*>(type);
-  }
-};
-
+// -----------------------------------------------------------------------------
+// Array types.
 
 template<class Config>
 class TypeImpl<Config>::ArrayType : public StructuralType {
  public:
-  TypeHandle Element() { return this->Get(0); }
+  TypeHandle Bound() { return this->Get(0); }
+  TypeHandle Element() { return this->Get(1); }
 
-  static ArrayHandle New(TypeHandle element, Region* region) {
+  static ArrayHandle New(TypeHandle element, TypeHandle bound, Region* region) {
+    ASSERT(SEMANTIC(bound->AsBitset()) == SEMANTIC(BitsetType::kArray));
     ArrayHandle type = Config::template cast<ArrayType>(
-        StructuralType::New(StructuralType::kArrayTag, 1, region));
-    type->Set(0, element);
+        StructuralType::New(StructuralType::kArrayTag, 2, region));
+    type->Set(0, bound);
+    type->Set(1, 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) {
     ASSERT(type->IsArray());
     return static_cast<ArrayType*>(type);
@@ -596,25 +716,38 @@ class TypeImpl<Config>::ArrayType : public StructuralType {
 };
 
 
+// -----------------------------------------------------------------------------
+// Function types.
+
 template<class Config>
 class TypeImpl<Config>::FunctionType : public StructuralType {
  public:
-  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); }
+  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); }
 
-  void InitParameter(int i, TypeHandle type) { this->Set(2 + i, type); }
+  void InitParameter(int i, TypeHandle type) { this->Set(3 + i, type); }
 
   static FunctionHandle New(
-      TypeHandle result, TypeHandle receiver, int arity, Region* region) {
+      TypeHandle result, TypeHandle receiver, TypeHandle bound,
+      int arity, Region* region) {
+    ASSERT(SEMANTIC(bound->AsBitset()) == SEMANTIC(BitsetType::kFunction));
     FunctionHandle type = Config::template cast<FunctionType>(
-        StructuralType::New(StructuralType::kFunctionTag, 2 + arity, region));
-    type->Set(0, result);
-    type->Set(1, receiver);
+        StructuralType::New(StructuralType::kFunctionTag, 3 + arity, region));
+    type->Set(0, bound);
+    type->Set(1, result);
+    type->Set(2, 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) {
     ASSERT(type->IsFunction());
     return static_cast<FunctionType*>(type);
@@ -622,6 +755,9 @@ class TypeImpl<Config>::FunctionType : public StructuralType {
 };
 
 
+// -----------------------------------------------------------------------------
+// Type iterators.
+
 template<class Config> template<class T>
 class TypeImpl<Config>::Iterator {
  public:
@@ -645,8 +781,10 @@ class TypeImpl<Config>::Iterator {
 };
 
 
-// Zone-allocated types are either (odd) integers to represent bitsets, or
+// -----------------------------------------------------------------------------
+// Zone-allocated types; they are either (odd) integers to represent bitsets, or
 // (even) pointers to structures for everything else.
+
 struct ZoneTypeConfig {
   typedef TypeImpl<ZoneTypeConfig> Type;
   class Base {};
@@ -659,36 +797,36 @@ struct ZoneTypeConfig {
 
   static inline bool is_bitset(Type* type);
   static inline bool is_class(Type* type);
-  static inline bool is_constant(Type* type);
   static inline bool is_struct(Type* type, int tag);
 
   static inline int as_bitset(Type* type);
-  static inline Struct* as_struct(Type* type);
   static inline i::Handle<i::Map> as_class(Type* type);
-  static inline i::Handle<i::Object> as_constant(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_class(i::Handle<i::Map> map, Zone* zone);
   static inline Type* from_struct(Struct* structured);
-  static inline Type* from_class(i::Handle<i::Map> map, int lub, Zone* zone);
-  static inline Type* from_constant(
-      i::Handle<i::Object> value, int lub, Zone* zone);
 
   static inline Struct* struct_create(int tag, int length, Zone* zone);
-  static inline void struct_shrink(Struct* structured, int length);
-  static inline int struct_tag(Struct* structured);
-  static inline int struct_length(Struct* structured);
-  static inline Type* struct_get(Struct* structured, int i);
-  static inline void struct_set(Struct* structured, int i, Type* type);
-
-  static inline int lub_bitset(Type* type);
+  static inline void struct_shrink(Struct* structure, int length);
+  static inline int struct_tag(Struct* structure);
+  static inline int struct_length(Struct* structure);
+  static inline Type* struct_get(Struct* structure, int i);
+  static inline void struct_set(Struct* structure, int i, Type* type);
+  template<class V>
+  static inline i::Handle<V> struct_get_value(Struct* structure, int i);
+  template<class V> static inline void struct_set_value(
+      Struct* structure, int i, i::Handle<V> x);
 };
 
 typedef TypeImpl<ZoneTypeConfig> Type;
 
 
-// Heap-allocated types are either smis for bitsets, maps for classes, boxes for
+// -----------------------------------------------------------------------------
+// Heap-allocated types; either smis for bitsets, maps for classes, boxes for
 // constants, or fixed arrays for unions.
+
 struct HeapTypeConfig {
   typedef TypeImpl<HeapTypeConfig> Type;
   typedef i::Object Base;
@@ -701,38 +839,40 @@ struct HeapTypeConfig {
 
   static inline bool is_bitset(Type* type);
   static inline bool is_class(Type* type);
-  static inline bool is_constant(Type* type);
   static inline bool is_struct(Type* type, int tag);
 
   static inline int as_bitset(Type* type);
   static inline i::Handle<i::Map> as_class(Type* type);
-  static inline i::Handle<i::Object> as_constant(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 i::Handle<Type> from_class(
-      i::Handle<i::Map> map, int lub, Isolate* isolate);
-  static inline i::Handle<Type> from_constant(
-      i::Handle<i::Object> value, int lub, Isolate* isolate);
-  static inline i::Handle<Type> from_struct(i::Handle<Struct> structured);
+      i::Handle<i::Map> map, Isolate* isolate);
+  static inline i::Handle<Type> from_struct(i::Handle<Struct> structure);
 
   static inline i::Handle<Struct> struct_create(
       int tag, int length, Isolate* isolate);
-  static inline void struct_shrink(i::Handle<Struct> structured, int length);
-  static inline int struct_tag(i::Handle<Struct> structured);
-  static inline int struct_length(i::Handle<Struct> structured);
-  static inline i::Handle<Type> struct_get(i::Handle<Struct> structured, int i);
+  static inline void struct_shrink(i::Handle<Struct> structure, int length);
+  static inline int struct_tag(i::Handle<Struct> structure);
+  static inline int struct_length(i::Handle<Struct> structure);
+  static inline i::Handle<Type> struct_get(i::Handle<Struct> structure, int i);
   static inline void struct_set(
-      i::Handle<Struct> structured, int i, i::Handle<Type> type);
-
-  static inline int lub_bitset(Type* type);
+      i::Handle<Struct> structure, int i, i::Handle<Type> type);
+  template<class V>
+  static inline i::Handle<V> struct_get_value(
+      i::Handle<Struct> structure, int i);
+  template<class V>
+  static inline void struct_set_value(
+      i::Handle<Struct> structure, int i, i::Handle<V> x);
 };
 
 typedef TypeImpl<HeapTypeConfig> HeapType;
 
 
-// A simple struct to represent a pair of lower/upper type bounds.
+// -----------------------------------------------------------------------------
+// Type bounds. A simple struct to represent a pair of lower/upper types.
+
 template<class Config>
 struct BoundsImpl {
   typedef TypeImpl<Config> Type;
index fa5d7d4c3ebdfa031368468f6835337756487cb2..4eeeec4e49997e581a9d8cc8280e0909f28b3f1a 100644 (file)
 
 #include <vector>
 
-#include "cctest.h"
+#define private public  /* To test private methods :) */
+#define protected public
 #include "types.h"
+#undef private
+#undef protected
+
+#include "cctest.h"
 #include "utils/random-number-generator.h"
 
 using namespace v8::internal;
@@ -81,8 +86,10 @@ struct HeapRep {
     return t->IsFixedArray() && Smi::cast(AsStruct(t)->get(0))->value() == tag;
   }
   static bool IsBitset(Handle<HeapType> t) { return t->IsSmi(); }
-  static bool IsClass(Handle<HeapType> t) { return t->IsMap(); }
-  static bool IsConstant(Handle<HeapType> t) { return t->IsBox(); }
+  static bool IsClass(Handle<HeapType> t) {
+    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); }
@@ -90,10 +97,10 @@ struct HeapRep {
 
   static Struct* AsStruct(Handle<HeapType> t) { return FixedArray::cast(*t); }
   static int AsBitset(Handle<HeapType> t) { return Smi::cast(*t)->value(); }
-  static Map* AsClass(Handle<HeapType> t) { return Map::cast(*t); }
-  static Object* AsConstant(Handle<HeapType> t) {
-    return Box::cast(*t)->value();
+  static Map* AsClass(Handle<HeapType> t) {
+    return t->IsMap() ? Map::cast(*t) : Map::cast(AsStruct(t)->get(2));
   }
+  static Object* AsConstant(Handle<HeapType> t) { return AsStruct(t)->get(2); }
   static HeapType* AsContext(Handle<HeapType> t) {
     return HeapType::cast(AsStruct(t)->get(1));
   }
@@ -315,6 +322,8 @@ class Types {
     UNREACHABLE();
   }
 
+  Region* region() { return region_; }
+
  private:
   Region* region_;
   RandomNumberGenerator rng_;
@@ -347,6 +356,8 @@ struct Tests : Rep {
         Rep::IsClass(type1) == Rep::IsClass(type2) &&
         Rep::IsConstant(type1) == Rep::IsConstant(type2) &&
         Rep::IsContext(type1) == Rep::IsContext(type2) &&
+        Rep::IsArray(type1) == Rep::IsArray(type2) &&
+        Rep::IsFunction(type1) == Rep::IsFunction(type2) &&
         Rep::IsUnion(type1) == Rep::IsUnion(type2) &&
         type1->NumClasses() == type2->NumClasses() &&
         type1->NumConstants() == type2->NumConstants() &&
@@ -356,7 +367,8 @@ struct Tests : Rep {
           Rep::AsClass(type1) == Rep::AsClass(type2)) &&
         (!Rep::IsConstant(type1) ||
           Rep::AsConstant(type1) == Rep::AsConstant(type2)) &&
-        (!Rep::IsUnion(type1) ||
+          // TODO(rossberg): Check details of arrays, functions, bounds.
+          (!Rep::IsUnion(type1) ||
           Rep::Length(Rep::AsUnion(type1)) == Rep::Length(Rep::AsUnion(type2)));
   }
 
@@ -723,6 +735,39 @@ struct Tests : Rep {
     }
   }
 
+  void Bounds() {
+    // Ordering: (T->BitsetGlb())->Is(T->BitsetLub())
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      TypeHandle glb = Type::BitsetType::New(type->BitsetGlb(), T.region());
+      TypeHandle lub = Type::BitsetType::New(type->BitsetLub(), T.region());
+      CHECK(glb->Is(lub));
+    }
+
+    // Lower bound: (T->BitsetGlb())->Is(T)
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      TypeHandle glb = Type::BitsetType::New(type->BitsetGlb(), T.region());
+      CHECK(glb->Is(type));
+    }
+
+    // Upper bound: T->Is(T->BitsetLub())
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      TypeHandle lub = Type::BitsetType::New(type->BitsetLub(), T.region());
+      CHECK(type->Is(lub));
+    }
+
+    // Inherent bound: (T->BitsetLub())->Is(T->InherentBitsetLub())
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      TypeHandle lub = Type::BitsetType::New(type->BitsetLub(), T.region());
+      TypeHandle inherent =
+          Type::BitsetType::New(type->InherentBitsetLub(), T.region());
+      CHECK(lub->Is(inherent));
+    }
+  }
+
   void Is() {
     // Least Element (Bottom): None->Is(T)
     for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
@@ -1583,13 +1628,13 @@ struct Tests : Rep {
     CheckEqual(
         T.Intersect(T.Object, T.Union(T.ObjectConstant1, T.ObjectClass)),
         T.Union(T.ObjectConstant1, T.ObjectClass));
-    CheckEqual(
-        T.Intersect(T.Union(T.ArrayClass, T.ObjectConstant1), T.Number),
-        T.None);
+    CHECK(
+        !T.Intersect(T.Union(T.ArrayClass, T.ObjectConstant1), T.Number)
+            ->IsInhabited());
 
     // Class-constant
-    CheckEqual(T.Intersect(T.ObjectConstant1, T.ObjectClass), T.None);
-    CheckEqual(T.Intersect(T.ArrayClass, T.ObjectConstant2), T.None);
+    CHECK(!T.Intersect(T.ObjectConstant1, T.ObjectClass)->IsInhabited());
+    CHECK(!T.Intersect(T.ArrayClass, T.ObjectConstant2)->IsInhabited());
 
     // Array-union
     CheckEqual(
@@ -1598,9 +1643,9 @@ struct Tests : Rep {
     CheckEqual(
         T.Intersect(T.AnyArray, T.Union(T.Object, T.SmiConstant)),
         T.AnyArray);
-    CheckEqual(
-        T.Intersect(T.Union(T.AnyArray, T.ArrayConstant), T.NumberArray),
-        T.None);
+    CHECK(
+        !T.Intersect(T.Union(T.AnyArray, T.ArrayConstant), T.NumberArray)
+            ->IsInhabited());
 
     // Function-union
     CheckEqual(
@@ -1609,9 +1654,9 @@ struct Tests : Rep {
     CheckEqual(
         T.Intersect(T.NumberFunction1, T.Union(T.Object, T.SmiConstant)),
         T.NumberFunction1);
-    CheckEqual(
-        T.Intersect(T.Union(T.MethodFunction, T.Name), T.NumberFunction2),
-        T.None);
+    CHECK(
+        !T.Intersect(T.Union(T.MethodFunction, T.Name), T.NumberFunction2)
+            ->IsInhabited());
 
     // Class-union
     CheckEqual(
@@ -1620,9 +1665,9 @@ struct Tests : Rep {
     CheckEqual(
         T.Intersect(T.ArrayClass, T.Union(T.Object, T.SmiConstant)),
         T.ArrayClass);
-    CheckEqual(
-        T.Intersect(T.Union(T.ObjectClass, T.ArrayConstant), T.ArrayClass),
-        T.None);
+    CHECK(
+        !T.Intersect(T.Union(T.ObjectClass, T.ArrayConstant), T.ArrayClass)
+            ->IsInhabited());
 
     // Constant-union
     CheckEqual(
@@ -1632,10 +1677,10 @@ struct Tests : Rep {
     CheckEqual(
         T.Intersect(T.SmiConstant, T.Union(T.Number, T.ObjectConstant2)),
         T.SmiConstant);
-    CheckEqual(
-        T.Intersect(
-            T.Union(T.ArrayConstant, T.ObjectClass), T.ObjectConstant1),
-        T.None);
+    CHECK(
+        !T.Intersect(
+            T.Union(T.ArrayConstant, T.ObjectClass), T.ObjectConstant1)
+                ->IsInhabited());
 
     // Union-union
     CheckEqual(
@@ -1663,6 +1708,44 @@ struct Tests : Rep {
         T.Union(T.ObjectConstant2, T.ObjectConstant1));
   }
 
+  void Distributivity() {
+    // Distributivity:
+    // Union(T1, Intersect(T2, T3)) = Intersect(Union(T1, T2), Union(T1, T3))
+    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;
+          TypeHandle union12 = T.Union(type1, type2);
+          TypeHandle union13 = T.Union(type1, type3);
+          TypeHandle intersect23 = T.Intersect(type2, type3);
+          TypeHandle union1_23 = T.Union(type1, intersect23);
+          TypeHandle intersect12_13 = T.Intersect(union12, union13);
+          CHECK(Equal(union1_23, intersect12_13));
+        }
+      }
+    }
+
+    // Distributivity:
+    // Intersect(T1, Union(T2, T3)) = Union(Intersect(T1, T2), Intersect(T1,T3))
+    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;
+          TypeHandle intersect12 = T.Intersect(type1, type2);
+          TypeHandle intersect13 = T.Intersect(type1, type3);
+          TypeHandle union23 = T.Union(type2, type3);
+          TypeHandle intersect1_23 = T.Intersect(type1, union23);
+          TypeHandle union12_13 = T.Union(intersect12, intersect13);
+          CHECK(Equal(intersect1_23, union12_13));
+        }
+      }
+    }
+  }
+
   template<class Type2, class TypeHandle2, class Region2, class Rep2>
   void Convert() {
     Types<Type2, TypeHandle2, Region2> T2(
@@ -1729,6 +1812,13 @@ TEST(NowOf) {
 }
 
 
+TEST(Bounds) {
+  CcTest::InitializeVM();
+  ZoneTests().Bounds();
+  HeapTests().Bounds();
+}
+
+
 TEST(Is) {
   CcTest::InitializeVM();
   ZoneTests().Is();
@@ -1792,6 +1882,13 @@ TEST(Intersect2) {
 }
 
 
+TEST(Distributivity) {
+  CcTest::InitializeVM();
+  ZoneTests().Distributivity();
+  HeapTests().Distributivity();
+}
+
+
 TEST(Convert) {
   CcTest::InitializeVM();
   ZoneTests().Convert<HeapType, Handle<HeapType>, Isolate, HeapRep>();