Various extensions to types
authorrossberg@chromium.org <rossberg@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 26 May 2014 13:10:52 +0000 (13:10 +0000)
committerrossberg@chromium.org <rossberg@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 26 May 2014 13:10:52 +0000 (13:10 +0000)
R=bmeurer@chromium.org
BUG=

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

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

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

index d6c99aa9f57e66fac5fceb9c2189cad70b00afa1..57a202d7641ae9ef13b6fe019539eac11b749c9a 100644 (file)
@@ -163,6 +163,17 @@ static inline bool IsInt32Double(double value) {
 }
 
 
+// UInteger32 is an integer that can be represented as an unsigned 32-bit
+// integer. It has to be in the range [0, 2^32 - 1].
+// We also have to check for negative 0 as it is not a UInteger32.
+static inline bool IsUint32Double(double value) {
+  return !IsMinusZero(value) &&
+         value >= 0 &&
+         value <= kMaxUInt32 &&
+         value == FastUI2D(FastD2UI(value));
+}
+
+
 // Convert from Number object to C integer.
 inline int32_t NumberToInt32(Object* number) {
   if (number->IsSmi()) return Smi::cast(number)->value();
index 6059a2a65317b2d9dfba4505ad2ca835e339523e..d7a9939cd0f17e2aef83d9f095ac7a05d2296941 100644 (file)
@@ -9503,7 +9503,7 @@ HValue* HGraphBuilder::TruncateToNumber(HValue* value, Type** expected) {
 
   if (expected_obj->Is(Type::Undefined(zone()))) {
     // This is already done by HChange.
-    *expected = Type::Union(expected_number, Type::Float(zone()), zone());
+    *expected = Type::Union(expected_number, Type::Number(zone()), zone());
     return value;
   }
 
index ca4f120c798d96ec39122f07d0fb8fade3b76bbb..7c2b246397dc0e0d6eda9c8f29c74519f54190c5 100644 (file)
@@ -20,7 +20,7 @@ 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() ||
-         t->IsUnion() || t->IsArray() || t->IsFunction());
+         t->IsUnion() || t->IsArray() || t->IsFunction() || t->IsContext());
   return t;
 }
 
index 5270c0ea6de09f4f4825f79f7cd3ebc08d14116c..d7a631d4ae18bc00e5b6a62380833baf9358cb5c 100644 (file)
@@ -148,6 +148,8 @@ int TypeImpl<Config>::BitsetType::Lub(TypeImpl* type) {
     return kArray;
   } else if (type->IsFunction()) {
     return kFunction;
+  } else if (type->IsContext()) {
+    return kInternal & kTaggedPtr;
   } else {
     UNREACHABLE();
     return kNone;
@@ -158,16 +160,43 @@ int TypeImpl<Config>::BitsetType::Lub(TypeImpl* type) {
 template<class Config>
 int TypeImpl<Config>::BitsetType::Lub(i::Object* value) {
   DisallowHeapAllocation no_allocation;
-  if (value->IsSmi()) return kSignedSmall & kTaggedInt;
-  i::Map* map = i::HeapObject::cast(value)->map();
-  if (map->instance_type() == HEAP_NUMBER_TYPE) {
-    int32_t i;
-    uint32_t u;
-    return kTaggedPtr & (
-        value->ToInt32(&i) ? (Smi::IsValid(i) ? kSignedSmall : kOtherSigned32) :
-        value->ToUint32(&u) ? kUnsigned32 : kFloat);
-  }
-  return Lub(map);
+  if (value->IsNumber()) {
+    return Lub(value->Number()) & (value->IsSmi() ? kTaggedInt : kTaggedPtr);
+  }
+  return Lub(i::HeapObject::cast(value)->map());
+}
+
+
+template<class Config>
+int TypeImpl<Config>::BitsetType::Lub(double value) {
+  DisallowHeapAllocation no_allocation;
+  if (i::IsMinusZero(value)) return kMinusZero;
+  if (std::isnan(value)) return kNaN;
+  if (IsUint32Double(value)) return Lub(FastD2UI(value));
+  if (IsInt32Double(value)) return Lub(FastD2I(value));
+  return kOtherNumber;
+}
+
+
+template<class Config>
+int TypeImpl<Config>::BitsetType::Lub(int32_t value) {
+  if (value >= 0x40000000) {
+    return i::SmiValuesAre31Bits() ? kOtherUnsigned31 : kUnsignedSmall;
+  }
+  if (value >= 0) return kUnsignedSmall;
+  if (value >= -0x40000000) return kOtherSignedSmall;
+  return i::SmiValuesAre31Bits() ? kOtherSigned32 : kOtherSignedSmall;
+}
+
+
+template<class Config>
+int TypeImpl<Config>::BitsetType::Lub(uint32_t value) {
+  DisallowHeapAllocation no_allocation;
+  if (value >= 0x80000000u) return kOtherUnsigned32;
+  if (value >= 0x40000000u) {
+    return i::SmiValuesAre31Bits() ? kOtherUnsigned31 : kUnsignedSmall;
+  }
+  return kUnsignedSmall;
 }
 
 
@@ -211,7 +240,7 @@ int TypeImpl<Config>::BitsetType::Lub(i::Map* map) {
       return kInternal & kTaggedPtr;
     }
     case HEAP_NUMBER_TYPE:
-      return kFloat & kTaggedPtr;
+      return kNumber & kTaggedPtr;
     case JS_VALUE_TYPE:
     case JS_DATE_TYPE:
     case JS_OBJECT_TYPE:
@@ -254,6 +283,7 @@ int TypeImpl<Config>::BitsetType::Lub(i::Map* map) {
       return kDetectable;
     case DECLARED_ACCESSOR_INFO_TYPE:
     case EXECUTABLE_ACCESSOR_INFO_TYPE:
+    case SHARED_FUNCTION_INFO_TYPE:
     case ACCESSOR_PAIR_TYPE:
     case FIXED_ARRAY_TYPE:
     case FOREIGN_TYPE:
@@ -296,6 +326,10 @@ bool TypeImpl<Config>::SlowIs(TypeImpl* that) {
     return this->IsConstant()
         && *this->AsConstant()->Value() == *that->AsConstant()->Value();
   }
+  if (that->IsContext()) {
+    return this->IsContext()
+        && this->AsContext()->Outer()->Equals(that->AsContext()->Outer());
+  }
   if (that->IsArray()) {
     return this->IsArray()
         && this->AsArray()->Element()->Equals(that->AsArray()->Element());
@@ -411,6 +445,9 @@ bool TypeImpl<Config>::Maybe(TypeImpl* that) {
     return that->IsConstant()
         && *this->AsConstant()->Value() == *that->AsConstant()->Value();
   }
+  if (this->IsContext()) {
+    return this->Equals(that);
+  }
   if (this->IsArray()) {
     // There is no variance!
     return this->Equals(that);
@@ -463,7 +500,8 @@ int TypeImpl<Config>::ExtendUnion(
   } else if (!type->IsBitset()) {
     // For all structural types, subtyping implies equivalence.
     ASSERT(type->IsClass() || type->IsConstant() ||
-           type->IsArray() || type->IsFunction());
+           type->IsArray() || type->IsFunction() ||
+           type->IsContext());
     if (!type->InUnion(result, old_size)) {
       result->Set(current_size++, type);
     }
@@ -539,7 +577,7 @@ int TypeImpl<Config>::ExtendIntersection(
   } else if (!type->IsBitset()) {
     // For all structural types, subtyping implies equivalence.
     ASSERT(type->IsClass() || type->IsConstant() ||
-           type->IsArray() || type->IsFunction());
+           type->IsArray() || type->IsFunction() || type->IsContext());
     if (type->Is(other) && !type->InUnion(result, old_size)) {
       result->Set(current_size++, type);
     }
@@ -608,6 +646,9 @@ typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Convert(
     return ClassType::New(type->AsClass()->Map(), region);
   } else if (type->IsConstant()) {
     return ConstantType::New(type->AsConstant()->Value(), region);
+  } else if (type->IsContext()) {
+    TypeHandle outer = Convert<OtherType>(type->AsContext()->Outer(), region);
+    return ContextType::New(outer, region);
   } else if (type->IsUnion()) {
     int length = type->AsUnion()->Length();
     UnionHandle unioned = UnionType::New(length, region);
@@ -646,27 +687,19 @@ Representation Representation::FromType(Type* type) {
 }
 
 
-template<class Config>
-void TypeImpl<Config>::TypePrint(PrintDimension dim) {
-  TypePrint(stdout, dim);
-  PrintF(stdout, "\n");
-  Flush(stdout);
-}
-
-
 template<class Config>
 const char* TypeImpl<Config>::BitsetType::Name(int bitset) {
   switch (bitset) {
-    case kAny & kRepresentation: return "Any";
-    #define PRINT_COMPOSED_TYPE(type, value) \
-    case k##type & kRepresentation: return #type;
-    REPRESENTATION_BITSET_TYPE_LIST(PRINT_COMPOSED_TYPE)
-    #undef PRINT_COMPOSED_TYPE
+    case REPRESENTATION(kAny): return "Any";
+    #define RETURN_NAMED_REPRESENTATION_TYPE(type, value) \
+    case REPRESENTATION(k##type): return #type;
+    REPRESENTATION_BITSET_TYPE_LIST(RETURN_NAMED_REPRESENTATION_TYPE)
+    #undef RETURN_NAMED_REPRESENTATION_TYPE
 
-    #define PRINT_COMPOSED_TYPE(type, value) \
-    case k##type & kSemantic: return #type;
-    SEMANTIC_BITSET_TYPE_LIST(PRINT_COMPOSED_TYPE)
-    #undef PRINT_COMPOSED_TYPE
+    #define RETURN_NAMED_SEMANTIC_TYPE(type, value) \
+    case SEMANTIC(k##type): return #type;
+    SEMANTIC_BITSET_TYPE_LIST(RETURN_NAMED_SEMANTIC_TYPE)
+    #undef RETURN_NAMED_SEMANTIC_TYPE
 
     default:
       return NULL;
@@ -675,97 +708,118 @@ const char* TypeImpl<Config>::BitsetType::Name(int bitset) {
 
 
 template<class Config>
-void TypeImpl<Config>::BitsetType::BitsetTypePrint(FILE* out, int bitset) {
+void TypeImpl<Config>::BitsetType::PrintTo(StringStream* stream, int bitset) {
   DisallowHeapAllocation no_allocation;
   const char* name = Name(bitset);
   if (name != NULL) {
-    PrintF(out, "%s", name);
+    stream->Add("%s", name);
   } else {
     static const int named_bitsets[] = {
-      #define BITSET_CONSTANT(type, value) k##type & kRepresentation,
+      #define BITSET_CONSTANT(type, value) REPRESENTATION(k##type),
       REPRESENTATION_BITSET_TYPE_LIST(BITSET_CONSTANT)
       #undef BITSET_CONSTANT
 
-      #define BITSET_CONSTANT(type, value) k##type & kSemantic,
+      #define BITSET_CONSTANT(type, value) SEMANTIC(k##type),
       SEMANTIC_BITSET_TYPE_LIST(BITSET_CONSTANT)
       #undef BITSET_CONSTANT
     };
 
     bool is_first = true;
-    PrintF(out, "(");
+    stream->Add("(");
     for (int i(ARRAY_SIZE(named_bitsets) - 1); bitset != 0 && i >= 0; --i) {
       int subset = named_bitsets[i];
       if ((bitset & subset) == subset) {
-        if (!is_first) PrintF(out, " | ");
+        if (!is_first) stream->Add(" | ");
         is_first = false;
-        PrintF(out, "%s", Name(subset));
+        stream->Add("%s", Name(subset));
         bitset -= subset;
       }
     }
     ASSERT(bitset == 0);
-    PrintF(out, ")");
+    stream->Add(")");
   }
 }
 
 
 template<class Config>
-void TypeImpl<Config>::TypePrint(FILE* out, PrintDimension dim) {
+void TypeImpl<Config>::PrintTo(StringStream* stream, PrintDimension dim) {
   DisallowHeapAllocation no_allocation;
   if (this->IsBitset()) {
     int bitset = this->AsBitset();
     switch (dim) {
       case BOTH_DIMS:
-        BitsetType::BitsetTypePrint(out, bitset & BitsetType::kSemantic);
-        PrintF(out, "/");
-        BitsetType::BitsetTypePrint(out, bitset & BitsetType::kRepresentation);
+        BitsetType::PrintTo(stream, SEMANTIC(bitset));
+        stream->Add("/");
+        BitsetType::PrintTo(stream, REPRESENTATION(bitset));
         break;
       case SEMANTIC_DIM:
-        BitsetType::BitsetTypePrint(out, bitset & BitsetType::kSemantic);
+        BitsetType::PrintTo(stream, SEMANTIC(bitset));
         break;
       case REPRESENTATION_DIM:
-        BitsetType::BitsetTypePrint(out, bitset & BitsetType::kRepresentation);
+        BitsetType::PrintTo(stream, REPRESENTATION(bitset));
         break;
     }
   } else if (this->IsConstant()) {
-    PrintF(out, "Constant(%p : ",
+    stream->Add("Constant(%p : ",
         static_cast<void*>(*this->AsConstant()->Value()));
-    BitsetType::New(BitsetType::Lub(this))->TypePrint(out, dim);
-    PrintF(out, ")");
+    BitsetType::New(BitsetType::Lub(this))->PrintTo(stream, dim);
+    stream->Add(")");
   } else if (this->IsClass()) {
-    PrintF(out, "Class(%p < ", static_cast<void*>(*this->AsClass()->Map()));
-    BitsetType::New(BitsetType::Lub(this))->TypePrint(out, dim);
-    PrintF(out, ")");
+    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()) {
-    PrintF(out, "(");
+    stream->Add("(");
     UnionHandle unioned = handle(this->AsUnion());
     for (int i = 0; i < unioned->Length(); ++i) {
       TypeHandle type_i = unioned->Get(i);
-      if (i > 0) PrintF(out, " | ");
-      type_i->TypePrint(out, dim);
+      if (i > 0) stream->Add(" | ");
+      type_i->PrintTo(stream, dim);
     }
-    PrintF(out, ")");
+    stream->Add(")");
   } else if (this->IsArray()) {
-    PrintF(out, "[");
-    AsArray()->Element()->TypePrint(out, dim);
-    PrintF(out, "]");
+    stream->Add("[");
+    AsArray()->Element()->PrintTo(stream, dim);
+    stream->Add("]");
   } else if (this->IsFunction()) {
     if (!this->AsFunction()->Receiver()->IsAny()) {
-      this->AsFunction()->Receiver()->TypePrint(out, dim);
-      PrintF(out, ".");
+      this->AsFunction()->Receiver()->PrintTo(stream, dim);
+      stream->Add(".");
     }
-    PrintF(out, "(");
+    stream->Add("(");
     for (int i = 0; i < this->AsFunction()->Arity(); ++i) {
-      if (i > 0) PrintF(out, ", ");
-      this->AsFunction()->Parameter(i)->TypePrint(out, dim);
+      if (i > 0) stream->Add(", ");
+      this->AsFunction()->Parameter(i)->PrintTo(stream, dim);
     }
-    PrintF(out, ")->");
-    this->AsFunction()->Result()->TypePrint(out, dim);
+    stream->Add(")->");
+    this->AsFunction()->Result()->PrintTo(stream, dim);
   } else {
     UNREACHABLE();
   }
 }
 
 
+template<class Config>
+void TypeImpl<Config>::TypePrint(FILE* out, PrintDimension dim) {
+  HeapStringAllocator allocator;
+  StringStream stream(&allocator);
+  PrintTo(&stream, dim);
+  stream.OutputToFile(out);
+}
+
+
+template<class Config>
+void TypeImpl<Config>::TypePrint(PrintDimension dim) {
+  TypePrint(stdout, dim);
+  PrintF(stdout, "\n");
+  Flush(stdout);
+}
+
+
 template class TypeImpl<ZoneTypeConfig>;
 template class TypeImpl<ZoneTypeConfig>::Iterator<i::Map>;
 template class TypeImpl<ZoneTypeConfig>::Iterator<i::Object>;
index 5ca3a81452c2fa3a10b789f3ed71b07630d96a75..1fdfdae5bfa662f15ef2cef1b1e04857c26ef79b 100644 (file)
@@ -45,10 +45,14 @@ namespace internal {
 //   Constant(x) < T  iff instance_type(map(x)) < T
 //   Array(T) < Array
 //   Function(R, S, T0, T1, ...) < Function
+//   Context(T) < Internal
 //
-// Both structural Array and Function types are invariant in all parameters.
-// Relaxing this would make Union and Intersect operations more involved.
-// Note that Constant(x) < Class(map(x)) does _not_ hold, since x's map can
+// Both structural Array and Function types are invariant in all parameters;
+// relaxing this would make Union and Intersect operations more involved.
+// There is no subtyping relation between Array, Function, or Context types
+// and respective Constant types, since these types cannot be reconstructed
+// for arbitrary heap values.
+// Note also that Constant(x) < Class(map(x)) does _not_ hold, since x's map can
 // change! (Its instance type cannot, however.)
 // TODO(rossberg): the latter is not currently true for proxies, because of fix,
 // but will hold once we implement direct proxies.
@@ -129,14 +133,15 @@ namespace internal {
 
 
 #define MASK_BITSET_TYPE_LIST(V) \
-  V(Representation, static_cast<int>(0xff800000)) \
-  V(Semantic,       static_cast<int>(0x007fffff))
+  V(Representation, static_cast<int>(0xffc00000)) \
+  V(Semantic,       static_cast<int>(0x003fffff))
 
-#define REPRESENTATION(k) ((k) & kRepresentation)
-#define SEMANTIC(k)       ((k) & kSemantic)
+#define REPRESENTATION(k) ((k) & BitsetType::kRepresentation)
+#define SEMANTIC(k)       ((k) & BitsetType::kSemantic)
 
 #define REPRESENTATION_BITSET_TYPE_LIST(V) \
   V(None,             0)                   \
+  V(UntaggedInt1,     1 << 22 | kSemantic) \
   V(UntaggedInt8,     1 << 23 | kSemantic) \
   V(UntaggedInt16,    1 << 24 | kSemantic) \
   V(UntaggedInt32,    1 << 25 | kSemantic) \
@@ -146,44 +151,54 @@ namespace internal {
   V(TaggedInt,        1 << 29 | kSemantic) \
   V(TaggedPtr,        -1 << 30 | kSemantic)  /* MSB has to be sign-extended */ \
   \
-  V(UntaggedInt,      kUntaggedInt8 | kUntaggedInt16 | kUntaggedInt32) \
-  V(UntaggedFloat,    kUntaggedFloat32 | kUntaggedFloat64)             \
-  V(UntaggedNumber,   kUntaggedInt | kUntaggedFloat)                   \
-  V(Untagged,         kUntaggedNumber | kUntaggedPtr)                  \
+  V(UntaggedInt,      kUntaggedInt1 | kUntaggedInt8 |      \
+                      kUntaggedInt16 | kUntaggedInt32)     \
+  V(UntaggedFloat,    kUntaggedFloat32 | kUntaggedFloat64) \
+  V(UntaggedNumber,   kUntaggedInt | kUntaggedFloat)       \
+  V(Untagged,         kUntaggedNumber | kUntaggedPtr)      \
   V(Tagged,           kTaggedInt | kTaggedPtr)
 
 #define SEMANTIC_BITSET_TYPE_LIST(V) \
   V(Null,                1 << 0  | REPRESENTATION(kTaggedPtr)) \
   V(Undefined,           1 << 1  | REPRESENTATION(kTaggedPtr)) \
   V(Boolean,             1 << 2  | REPRESENTATION(kTaggedPtr)) \
-  V(SignedSmall,         1 << 3  | REPRESENTATION(kTagged | kUntaggedNumber)) \
-  V(OtherSigned32,       1 << 4  | REPRESENTATION(kTagged | kUntaggedNumber)) \
-  V(Unsigned32,          1 << 5  | REPRESENTATION(kTagged | kUntaggedNumber)) \
-  V(Float,               1 << 6  | REPRESENTATION(kTagged | kUntaggedNumber)) \
-  V(Symbol,              1 << 7  | REPRESENTATION(kTaggedPtr)) \
-  V(InternalizedString,  1 << 8  | REPRESENTATION(kTaggedPtr)) \
-  V(OtherString,         1 << 9  | REPRESENTATION(kTaggedPtr)) \
-  V(Undetectable,        1 << 10 | REPRESENTATION(kTaggedPtr)) \
-  V(Array,               1 << 11 | REPRESENTATION(kTaggedPtr)) \
-  V(Function,            1 << 12 | REPRESENTATION(kTaggedPtr)) \
-  V(RegExp,              1 << 13 | REPRESENTATION(kTaggedPtr)) \
-  V(OtherObject,         1 << 14 | REPRESENTATION(kTaggedPtr)) \
-  V(Proxy,               1 << 15 | REPRESENTATION(kTaggedPtr)) \
-  V(Internal,            1 << 16 | REPRESENTATION(kTagged | kUntagged)) \
+  V(UnsignedSmall,       1 << 3  | REPRESENTATION(kTagged | kUntaggedNumber)) \
+  V(OtherSignedSmall,    1 << 4  | REPRESENTATION(kTagged | kUntaggedNumber)) \
+  V(OtherUnsigned31,     1 << 5  | REPRESENTATION(kTagged | kUntaggedNumber)) \
+  V(OtherUnsigned32,     1 << 6  | REPRESENTATION(kTagged | kUntaggedNumber)) \
+  V(OtherSigned32,       1 << 7  | REPRESENTATION(kTagged | kUntaggedNumber)) \
+  V(MinusZero,           1 << 8  | REPRESENTATION(kTagged | kUntaggedNumber)) \
+  V(NaN,                 1 << 9  | REPRESENTATION(kTagged | kUntaggedNumber)) \
+  V(OtherNumber,         1 << 10 | REPRESENTATION(kTagged | kUntaggedNumber)) \
+  V(Symbol,              1 << 11 | REPRESENTATION(kTaggedPtr)) \
+  V(InternalizedString,  1 << 12 | REPRESENTATION(kTaggedPtr)) \
+  V(OtherString,         1 << 13 | REPRESENTATION(kTaggedPtr)) \
+  V(Undetectable,        1 << 14 | REPRESENTATION(kTaggedPtr)) \
+  V(Array,               1 << 15 | REPRESENTATION(kTaggedPtr)) \
+  V(Buffer,              1 << 16 | REPRESENTATION(kTaggedPtr)) \
+  V(Function,            1 << 17 | REPRESENTATION(kTaggedPtr)) \
+  V(RegExp,              1 << 18 | REPRESENTATION(kTaggedPtr)) \
+  V(OtherObject,         1 << 19 | REPRESENTATION(kTaggedPtr)) \
+  V(Proxy,               1 << 20 | REPRESENTATION(kTaggedPtr)) \
+  V(Internal,            1 << 21 | REPRESENTATION(kTagged | kUntagged)) \
   \
-  V(Signed32,            kSignedSmall | kOtherSigned32)                 \
-  V(Number,              kSigned32 | kUnsigned32 | kFloat)              \
-  V(String,              kInternalizedString | kOtherString)            \
-  V(UniqueName,          kSymbol | kInternalizedString)                 \
-  V(Name,                kSymbol | kString)                             \
-  V(NumberOrString,      kNumber | kString)                             \
-  V(DetectableObject,    kArray | kFunction | kRegExp | kOtherObject)   \
-  V(DetectableReceiver,  kDetectableObject | kProxy)                    \
-  V(Detectable,          kDetectableReceiver | kNumber | kName)         \
-  V(Object,              kDetectableObject | kUndetectable)             \
-  V(Receiver,            kObject | kProxy)                              \
-  V(NonNumber,           kBoolean | kName | kNull | kReceiver |         \
-                         kUndefined | kInternal)                        \
+  V(SignedSmall,         kUnsignedSmall | kOtherSignedSmall) \
+  V(Signed32,            kSignedSmall | kOtherUnsigned31 | kOtherSigned32) \
+  V(Unsigned32,          kUnsignedSmall | kOtherUnsigned31 | kOtherUnsigned32) \
+  V(Integral32,          kSigned32 | kUnsigned32) \
+  V(Number,              kIntegral32 | kMinusZero | kNaN | kOtherNumber) \
+  V(String,              kInternalizedString | kOtherString) \
+  V(UniqueName,          kSymbol | kInternalizedString) \
+  V(Name,                kSymbol | kString) \
+  V(NumberOrString,      kNumber | kString) \
+  V(Primitive,           kNumber | kName | kBoolean | kNull | kUndefined) \
+  V(DetectableObject,    kArray | kFunction | kRegExp | kOtherObject) \
+  V(DetectableReceiver,  kDetectableObject | kProxy) \
+  V(Detectable,          kDetectableReceiver | kNumber | kName) \
+  V(Object,              kDetectableObject | kUndetectable) \
+  V(Receiver,            kObject | kProxy) \
+  V(NonNumber,           kBoolean | kName | kNull | kReceiver | \
+                         kUndefined | kInternal) \
   V(Any,                 -1)
 
 #define BITSET_TYPE_LIST(V) \
@@ -230,12 +245,14 @@ class TypeImpl : public Config::Base {
 
   class ClassType;
   class ConstantType;
+  class ContextType;
   class ArrayType;
   class FunctionType;
 
   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<ContextType>::type ContextHandle;
   typedef typename Config::template Handle<ArrayType>::type ArrayHandle;
   typedef typename Config::template Handle<FunctionType>::type FunctionHandle;
   typedef typename Config::template Handle<UnionType>::type UnionHandle;
@@ -255,6 +272,9 @@ class TypeImpl : public Config::Base {
   static TypeHandle Constant(i::Handle<i::Object> value, Region* region) {
     return ConstantType::New(value, region);
   }
+  static TypeHandle Context(TypeHandle outer, Region* region) {
+    return ContextType::New(outer, region);
+  }
   static TypeHandle Array(TypeHandle element, Region* region) {
     return ArrayType::New(element, region);
   }
@@ -278,10 +298,22 @@ class TypeImpl : public Config::Base {
     function->InitParameter(1, param1);
     return function;
   }
+  static TypeHandle Function(
+      TypeHandle result, TypeHandle param0, TypeHandle param1,
+      TypeHandle param2, Region* region) {
+    FunctionHandle function = Function(result, Any(region), 3, region);
+    function->InitParameter(0, param0);
+    function->InitParameter(1, param1);
+    function->InitParameter(2, param2);
+    return function;
+  }
 
   static TypeHandle Union(TypeHandle type1, TypeHandle type2, Region* reg);
   static TypeHandle Intersect(TypeHandle type1, TypeHandle type2, Region* reg);
 
+  static TypeHandle Of(double value, Region* region) {
+    return Config::from_bitset(BitsetType::Lub(value), region);
+  }
   static TypeHandle Of(i::Object* value, Region* region) {
     return Config::from_bitset(BitsetType::Lub(value), region);
   }
@@ -325,6 +357,9 @@ class TypeImpl : public Config::Base {
 
   bool IsClass() { return Config::is_class(this); }
   bool IsConstant() { return Config::is_constant(this); }
+  bool IsContext() {
+    return Config::is_struct(this, StructuralType::kContextTag);
+  }
   bool IsArray() { return Config::is_struct(this, StructuralType::kArrayTag); }
   bool IsFunction() {
     return Config::is_struct(this, StructuralType::kFunctionTag);
@@ -332,6 +367,7 @@ class TypeImpl : public Config::Base {
 
   ClassType* AsClass() { return ClassType::cast(this); }
   ConstantType* AsConstant() { return ConstantType::cast(this); }
+  ContextType* AsContext() { return ContextType::cast(this); }
   ArrayType* AsArray() { return ArrayType::cast(this); }
   FunctionType* AsFunction() { return FunctionType::cast(this); }
 
@@ -355,6 +391,7 @@ class TypeImpl : public Config::Base {
       typename OtherTypeImpl::TypeHandle type, Region* region);
 
   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);
 
@@ -419,10 +456,14 @@ class TypeImpl<Config>::BitsetType : public TypeImpl<Config> {
   static int Glb(TypeImpl* type);  // greatest lower bound that's a bitset
   static int Lub(TypeImpl* type);  // least upper bound that's a bitset
   static int Lub(i::Object* value);
+  static int Lub(double value);
+  static int Lub(int32_t value);
+  static int Lub(uint32_t value);
   static int Lub(i::Map* map);
 
   static const char* Name(int bitset);
-  static void BitsetTypePrint(FILE* out, int bitset);
+  static void PrintTo(StringStream* stream, int bitset);
+  using TypeImpl::PrintTo;
 };
 
 
@@ -438,6 +479,7 @@ class TypeImpl<Config>::StructuralType : public TypeImpl<Config> {
   enum Tag {
     kClassTag,
     kConstantTag,
+    kContextTag,
     kArrayTag,
     kFunctionTag,
     kUnionTag
@@ -496,6 +538,25 @@ class TypeImpl<Config>::ConstantType : public TypeImpl<Config> {
 };
 
 
+template<class Config>
+class TypeImpl<Config>::ContextType : public StructuralType {
+ public:
+  TypeHandle Outer() { return this->Get(0); }
+
+  static ContextHandle New(TypeHandle outer, Region* region) {
+    ContextHandle type = Config::template cast<ContextType>(
+        StructuralType::New(StructuralType::kContextTag, 1, region));
+    type->Set(0, outer);
+    return type;
+  }
+
+  static ContextType* cast(TypeImpl* type) {
+    ASSERT(type->IsContext());
+    return static_cast<ContextType*>(type);
+  }
+};
+
+
 // Internal
 // A union is a structured type with the following invariants:
 // - its length is at least 2
index 47868f6484b3e09fee9bf69d5fd9613296f74dff..e8f20be9b02d46ed10c2ca913f5740d636e80253 100644 (file)
@@ -43,9 +43,10 @@ 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 IsArray(Type* t) { return IsStruct(t, 2); }
-  static bool IsFunction(Type* t) { return IsStruct(t, 3); }
-  static bool IsUnion(Type* t) { return IsStruct(t, 4); }
+  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 Struct* AsStruct(Type* t) {
     return reinterpret_cast<Struct*>(t);
@@ -59,6 +60,9 @@ struct ZoneRep {
   static Object* AsConstant(Type* t) {
     return *static_cast<Object**>(AsStruct(t)[3]);
   }
+  static Type* AsContext(Type* t) {
+    return *static_cast<Type**>(AsStruct(t)[2]);
+  }
   static Struct* AsUnion(Type* t) {
     return AsStruct(t);
   }
@@ -79,9 +83,10 @@ struct HeapRep {
   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 IsArray(Handle<HeapType> t) { return IsStruct(t, 2); }
-  static bool IsFunction(Handle<HeapType> t) { return IsStruct(t, 3); }
-  static bool IsUnion(Handle<HeapType> t) { return IsStruct(t, 4); }
+  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 Struct* AsStruct(Handle<HeapType> t) { return FixedArray::cast(*t); }
   static int AsBitset(Handle<HeapType> t) { return Smi::cast(*t)->value(); }
@@ -89,6 +94,9 @@ struct HeapRep {
   static Object* AsConstant(Handle<HeapType> t) {
     return Box::cast(*t)->value();
   }
+  static HeapType* AsContext(Handle<HeapType> t) {
+    return HeapType::cast(AsStruct(t)->get(1));
+  }
   static Struct* AsUnion(Handle<HeapType> t) { return AsStruct(t); }
   static int Length(Struct* structured) { return structured->length() - 1; }
 
@@ -143,7 +151,7 @@ class Types {
       types.push_back(Type::Constant(*it, region));
     }
 
-    FloatArray = Type::Array(Float, region);
+    NumberArray = Type::Array(Number, region);
     StringArray = Type::Array(String, region);
     AnyArray = Type::Array(Any, region);
 
@@ -183,7 +191,7 @@ class Types {
   TypeHandle ArrayConstant;
   TypeHandle UninitializedConstant;
 
-  TypeHandle FloatArray;
+  TypeHandle NumberArray;
   TypeHandle StringArray;
   TypeHandle AnyArray;
 
@@ -272,13 +280,19 @@ class Types {
         int i = rng_.NextInt(static_cast<int>(values.size()));
         return Type::Constant(values[i], region_);
       }
-      case 3: {  // array
+      case 3: {  // context
+        int depth = rng_.NextInt(3);
+        TypeHandle type = Type::Internal(region_);
+        for (int i = 0; i < depth; ++i) type = Type::Context(type, region_);
+        return type;
+      }
+      case 4: {  // array
         TypeHandle element = Fuzz(depth / 2);
         return Type::Array(element, region_);
       }
-      case 4:
       case 5:
-      case 6: {  // function
+      case 6:
+      case 7: {  // function
         TypeHandle result = Fuzz(depth / 2);
         TypeHandle receiver = Fuzz(depth / 2);
         int arity = rng_.NextInt(3);
@@ -332,6 +346,7 @@ struct Tests : Rep {
         Rep::IsBitset(type1) == Rep::IsBitset(type2) &&
         Rep::IsClass(type1) == Rep::IsClass(type2) &&
         Rep::IsConstant(type1) == Rep::IsConstant(type2) &&
+        Rep::IsContext(type1) == Rep::IsContext(type2) &&
         Rep::IsUnion(type1) == Rep::IsUnion(type2) &&
         type1->NumClasses() == type2->NumClasses() &&
         type1->NumConstants() == type2->NumConstants() &&
@@ -507,6 +522,45 @@ struct Tests : Rep {
         CHECK(Equal(type1, type2) == (*value1 == *value2));
       }
     }
+
+    // Typing of numbers
+    Factory* fac = isolate->factory();
+    CHECK(T.Constant(fac->NewNumber(0))->Is(T.UnsignedSmall));
+    CHECK(T.Constant(fac->NewNumber(1))->Is(T.UnsignedSmall));
+    CHECK(T.Constant(fac->NewNumber(0x3fffffff))->Is(T.UnsignedSmall));
+    CHECK(T.Constant(fac->NewNumber(-1))->Is(T.OtherSignedSmall));
+    CHECK(T.Constant(fac->NewNumber(-0x3fffffff))->Is(T.OtherSignedSmall));
+    CHECK(T.Constant(fac->NewNumber(-0x40000000))->Is(T.OtherSignedSmall));
+    if (SmiValuesAre31Bits()) {
+      CHECK(T.Constant(fac->NewNumber(0x40000000))->Is(T.OtherUnsigned31));
+      CHECK(T.Constant(fac->NewNumber(0x7fffffff))->Is(T.OtherUnsigned31));
+      CHECK(T.Constant(fac->NewNumber(-0x40000001))->Is(T.OtherSigned32));
+      CHECK(T.Constant(fac->NewNumber(-0x7fffffff))->Is(T.OtherSigned32));
+      CHECK(T.Constant(fac->NewNumber(-0x7fffffff-1))->Is(T.OtherSigned32));
+    } else {
+      CHECK(SmiValuesAre32Bits());
+      CHECK(T.Constant(fac->NewNumber(0x40000000))->Is(T.UnsignedSmall));
+      CHECK(T.Constant(fac->NewNumber(0x7fffffff))->Is(T.UnsignedSmall));
+      CHECK(!T.Constant(fac->NewNumber(0x40000000))->Is(T.OtherUnsigned31));
+      CHECK(!T.Constant(fac->NewNumber(0x7fffffff))->Is(T.OtherUnsigned31));
+      CHECK(T.Constant(fac->NewNumber(-0x40000001))->Is(T.OtherSignedSmall));
+      CHECK(T.Constant(fac->NewNumber(-0x7fffffff))->Is(T.OtherSignedSmall));
+      CHECK(T.Constant(fac->NewNumber(-0x7fffffff-1))->Is(T.OtherSignedSmall));
+      CHECK(!T.Constant(fac->NewNumber(-0x40000001))->Is(T.OtherSigned32));
+      CHECK(!T.Constant(fac->NewNumber(-0x7fffffff))->Is(T.OtherSigned32));
+      CHECK(!T.Constant(fac->NewNumber(-0x7fffffff-1))->Is(T.OtherSigned32));
+    }
+    CHECK(T.Constant(fac->NewNumber(0x80000000u))->Is(T.OtherUnsigned32));
+    CHECK(T.Constant(fac->NewNumber(0xffffffffu))->Is(T.OtherUnsigned32));
+    CHECK(T.Constant(fac->NewNumber(0xffffffffu+1.0))->Is(T.OtherNumber));
+    CHECK(T.Constant(fac->NewNumber(-0x7fffffff-2.0))->Is(T.OtherNumber));
+    CHECK(T.Constant(fac->NewNumber(0.1))->Is(T.OtherNumber));
+    CHECK(T.Constant(fac->NewNumber(-10.1))->Is(T.OtherNumber));
+    CHECK(T.Constant(fac->NewNumber(10e60))->Is(T.OtherNumber));
+    CHECK(T.Constant(fac->NewNumber(-1.0*0.0))->Is(T.MinusZero));
+    CHECK(T.Constant(fac->NewNumber(0.0/0.0))->Is(T.NaN));
+    CHECK(T.Constant(fac->NewNumber(1.0/0.0))->Is(T.OtherNumber));
+    CHECK(T.Constant(fac->NewNumber(-1.0/0.0))->Is(T.OtherNumber));
   }
 
   void Array() {
@@ -772,10 +826,9 @@ struct Tests : Rep {
 
     CheckSub(T.SignedSmall, T.Number);
     CheckSub(T.Signed32, T.Number);
-    CheckSub(T.Float, T.Number);
     CheckSub(T.SignedSmall, T.Signed32);
-    CheckUnordered(T.SignedSmall, T.Float);
-    CheckUnordered(T.Signed32, T.Float);
+    CheckUnordered(T.SignedSmall, T.MinusZero);
+    CheckUnordered(T.Signed32, T.Unsigned32);
 
     CheckSub(T.UniqueName, T.Name);
     CheckSub(T.String, T.Name);
@@ -823,8 +876,8 @@ struct Tests : Rep {
     CheckUnordered(T.ObjectConstant2, T.ArrayClass);
     CheckUnordered(T.ArrayConstant, T.ObjectClass);
 
-    CheckSub(T.FloatArray, T.Array);
-    CheckSub(T.FloatArray, T.Object);
+    CheckSub(T.NumberArray, T.Array);
+    CheckSub(T.NumberArray, T.Object);
     CheckUnordered(T.StringArray, T.AnyArray);
 
     CheckSub(T.MethodFunction, T.Function);
@@ -1114,8 +1167,8 @@ struct Tests : Rep {
     CheckDisjoint(T.Boolean, T.Undefined, T.Semantic);
 
     CheckOverlap(T.SignedSmall, T.Number, T.Semantic);
-    CheckOverlap(T.Float, T.Number, T.Semantic);
-    CheckDisjoint(T.Signed32, T.Float, T.Semantic);
+    CheckOverlap(T.NaN, T.Number, T.Semantic);
+    CheckDisjoint(T.Signed32, T.NaN, T.Semantic);
 
     CheckOverlap(T.UniqueName, T.Name, T.Semantic);
     CheckOverlap(T.String, T.Name, T.Semantic);
@@ -1145,7 +1198,6 @@ struct Tests : Rep {
     CheckOverlap(T.SmiConstant, T.SignedSmall, T.Semantic);
     CheckOverlap(T.SmiConstant, T.Signed32, T.Semantic);
     CheckOverlap(T.SmiConstant, T.Number, T.Semantic);
-    CheckDisjoint(T.SmiConstant, T.Float, T.Semantic);
     CheckOverlap(T.ObjectConstant1, T.Object, T.Semantic);
     CheckOverlap(T.ObjectConstant2, T.Object, T.Semantic);
     CheckOverlap(T.ArrayConstant, T.Object, T.Semantic);
@@ -1160,9 +1212,9 @@ struct Tests : Rep {
     CheckDisjoint(T.ObjectConstant2, T.ArrayClass, T.Semantic);
     CheckDisjoint(T.ArrayConstant, T.ObjectClass, T.Semantic);
 
-    CheckOverlap(T.FloatArray, T.Array, T.Semantic);
-    CheckDisjoint(T.FloatArray, T.AnyArray, T.Semantic);
-    CheckDisjoint(T.FloatArray, T.StringArray, T.Semantic);
+    CheckOverlap(T.NumberArray, T.Array, T.Semantic);
+    CheckDisjoint(T.NumberArray, T.AnyArray, T.Semantic);
+    CheckDisjoint(T.NumberArray, T.StringArray, T.Semantic);
 
     CheckOverlap(T.MethodFunction, T.Function, T.Semantic);
     CheckDisjoint(T.SignedFunction1, T.NumberFunction1, T.Semantic);
@@ -1303,22 +1355,18 @@ struct Tests : Rep {
 
     // Bitset-array
     CHECK(this->IsBitset(T.Union(T.AnyArray, T.Array)));
-    CHECK(this->IsUnion(T.Union(T.FloatArray, T.Number)));
+    CHECK(this->IsUnion(T.Union(T.NumberArray, T.Number)));
 
     CheckEqual(T.Union(T.AnyArray, T.Array), T.Array);
-    CheckSub(T.None, T.Union(T.FloatArray, T.Number));
-    CheckSub(T.Union(T.FloatArray, T.Number), T.Any);
     CheckUnordered(T.Union(T.AnyArray, T.String), T.Array);
-    CheckOverlap(T.Union(T.FloatArray, T.String), T.Object, T.Semantic);
-    CheckDisjoint(T.Union(T.FloatArray, T.String), T.Number, T.Semantic);
+    CheckOverlap(T.Union(T.NumberArray, T.String), T.Object, T.Semantic);
+    CheckDisjoint(T.Union(T.NumberArray, T.String), T.Number, T.Semantic);
 
     // Bitset-function
     CHECK(this->IsBitset(T.Union(T.MethodFunction, T.Function)));
     CHECK(this->IsUnion(T.Union(T.NumberFunction1, T.Number)));
 
     CheckEqual(T.Union(T.MethodFunction, T.Function), T.Function);
-    CheckSub(T.None, T.Union(T.MethodFunction, T.Number));
-    CheckSub(T.Union(T.MethodFunction, T.Number), T.Any);
     CheckUnordered(T.Union(T.NumberFunction1, T.String), T.Function);
     CheckOverlap(T.Union(T.NumberFunction2, T.String), T.Object, T.Semantic);
     CheckDisjoint(T.Union(T.NumberFunction1, T.String), T.Number, T.Semantic);
@@ -1353,10 +1401,10 @@ struct Tests : Rep {
 
     // Bitset-union
     CheckSub(
-        T.Float,
+        T.NaN,
         T.Union(T.Union(T.ArrayClass, T.ObjectConstant1), T.Number));
     CheckSub(
-        T.Union(T.Union(T.ArrayClass, T.ObjectConstant1), T.Float),
+        T.Union(T.Union(T.ArrayClass, T.ObjectConstant1), T.Signed32),
         T.Union(T.ObjectConstant1, T.Union(T.Number, T.ArrayClass)));
 
     // Class-union
@@ -1380,9 +1428,9 @@ struct Tests : Rep {
 
     // Array-union
     CheckEqual(
-        T.Union(T.AnyArray, T.Union(T.FloatArray, T.AnyArray)),
-        T.Union(T.AnyArray, T.FloatArray));
-    CheckSub(T.Union(T.AnyArray, T.FloatArray), T.Array);
+        T.Union(T.AnyArray, T.Union(T.NumberArray, T.AnyArray)),
+        T.Union(T.AnyArray, T.NumberArray));
+    CheckSub(T.Union(T.AnyArray, T.NumberArray), T.Array);
 
     // Function-union
     CheckEqual(
@@ -1524,7 +1572,7 @@ struct Tests : Rep {
     CheckSub(T.Intersect(T.ObjectClass, T.Number), T.Representation);
 
     // Bitset-array
-    CheckEqual(T.Intersect(T.FloatArray, T.Object), T.FloatArray);
+    CheckEqual(T.Intersect(T.NumberArray, T.Object), T.NumberArray);
     CheckSub(T.Intersect(T.AnyArray, T.Function), T.Representation);
 
     // Bitset-function
@@ -1545,13 +1593,13 @@ struct Tests : Rep {
 
     // Array-union
     CheckEqual(
-        T.Intersect(T.FloatArray, T.Union(T.FloatArray, T.ArrayClass)),
-        T.FloatArray);
+        T.Intersect(T.NumberArray, T.Union(T.NumberArray, T.ArrayClass)),
+        T.NumberArray);
     CheckEqual(
         T.Intersect(T.AnyArray, T.Union(T.Object, T.SmiConstant)),
         T.AnyArray);
     CheckEqual(
-        T.Intersect(T.Union(T.AnyArray, T.ArrayConstant), T.FloatArray),
+        T.Intersect(T.Union(T.AnyArray, T.ArrayConstant), T.NumberArray),
         T.None);
 
     // Function-union