diff --git a/src/conversions.h b/src/conversions.h index d6c99aa9f5..57a202d764 100644 --- a/src/conversions.h +++ b/src/conversions.h @@ -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(); diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 6059a2a653..d7a9939cd0 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -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; } diff --git a/src/types-inl.h b/src/types-inl.h index ca4f120c79..7c2b246397 100644 --- a/src/types-inl.h +++ b/src/types-inl.h @@ -20,7 +20,7 @@ template TypeImpl* TypeImpl::cast(typename Config::Base* object) { TypeImpl* t = static_cast(object); ASSERT(t->IsBitset() || t->IsClass() || t->IsConstant() || - t->IsUnion() || t->IsArray() || t->IsFunction()); + t->IsUnion() || t->IsArray() || t->IsFunction() || t->IsContext()); return t; } diff --git a/src/types.cc b/src/types.cc index 5270c0ea6d..d7a631d4ae 100644 --- a/src/types.cc +++ b/src/types.cc @@ -148,6 +148,8 @@ int TypeImpl::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::BitsetType::Lub(TypeImpl* type) { template int TypeImpl::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); + if (value->IsNumber()) { + return Lub(value->Number()) & (value->IsSmi() ? kTaggedInt : kTaggedPtr); } - return Lub(map); + return Lub(i::HeapObject::cast(value)->map()); +} + + +template +int TypeImpl::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 +int TypeImpl::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 +int TypeImpl::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::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::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::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::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::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::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::TypeHandle TypeImpl::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(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 -void TypeImpl::TypePrint(PrintDimension dim) { - TypePrint(stdout, dim); - PrintF(stdout, "\n"); - Flush(stdout); -} - - template const char* TypeImpl::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,94 +708,115 @@ const char* TypeImpl::BitsetType::Name(int bitset) { template -void TypeImpl::BitsetType::BitsetTypePrint(FILE* out, int bitset) { +void TypeImpl::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 +void TypeImpl::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(*this->AsConstant()->Value())); + BitsetType::New(BitsetType::Lub(this))->PrintTo(stream, dim); + stream->Add(")"); + } else if (this->IsClass()) { + stream->Add("Class(%p < ", static_cast(*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); + } + stream->Add(")->"); + this->AsFunction()->Result()->PrintTo(stream, dim); + } else { + UNREACHABLE(); } } template void TypeImpl::TypePrint(FILE* out, 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); - break; - case SEMANTIC_DIM: - BitsetType::BitsetTypePrint(out, bitset & BitsetType::kSemantic); - break; - case REPRESENTATION_DIM: - BitsetType::BitsetTypePrint(out, bitset & BitsetType::kRepresentation); - break; - } - } else if (this->IsConstant()) { - PrintF(out, "Constant(%p : ", - static_cast(*this->AsConstant()->Value())); - BitsetType::New(BitsetType::Lub(this))->TypePrint(out, dim); - PrintF(out, ")"); - } else if (this->IsClass()) { - PrintF(out, "Class(%p < ", static_cast(*this->AsClass()->Map())); - BitsetType::New(BitsetType::Lub(this))->TypePrint(out, dim); - PrintF(out, ")"); - } else if (this->IsUnion()) { - PrintF(out, "("); - 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); - } - PrintF(out, ")"); - } else if (this->IsArray()) { - PrintF(out, "["); - AsArray()->Element()->TypePrint(out, dim); - PrintF(out, "]"); - } else if (this->IsFunction()) { - if (!this->AsFunction()->Receiver()->IsAny()) { - this->AsFunction()->Receiver()->TypePrint(out, dim); - PrintF(out, "."); - } - PrintF(out, "("); - for (int i = 0; i < this->AsFunction()->Arity(); ++i) { - if (i > 0) PrintF(out, ", "); - this->AsFunction()->Parameter(i)->TypePrint(out, dim); - } - PrintF(out, ")->"); - this->AsFunction()->Result()->TypePrint(out, dim); - } else { - UNREACHABLE(); - } + HeapStringAllocator allocator; + StringStream stream(&allocator); + PrintTo(&stream, dim); + stream.OutputToFile(out); +} + + +template +void TypeImpl::TypePrint(PrintDimension dim) { + TypePrint(stdout, dim); + PrintF(stdout, "\n"); + Flush(stdout); } diff --git a/src/types.h b/src/types.h index 5ca3a81452..1fdfdae5bf 100644 --- a/src/types.h +++ b/src/types.h @@ -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(0xff800000)) \ - V(Semantic, static_cast(0x007fffff)) + V(Representation, static_cast(0xffc00000)) \ + V(Semantic, static_cast(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::type TypeHandle; typedef typename Config::template Handle::type ClassHandle; typedef typename Config::template Handle::type ConstantHandle; + typedef typename Config::template Handle::type ContextHandle; typedef typename Config::template Handle::type ArrayHandle; typedef typename Config::template Handle::type FunctionHandle; typedef typename Config::template Handle::type UnionHandle; @@ -255,6 +272,9 @@ class TypeImpl : public Config::Base { static TypeHandle Constant(i::Handle 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::BitsetType : public TypeImpl { 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::StructuralType : public TypeImpl { enum Tag { kClassTag, kConstantTag, + kContextTag, kArrayTag, kFunctionTag, kUnionTag @@ -496,6 +538,25 @@ class TypeImpl::ConstantType : public TypeImpl { }; +template +class TypeImpl::ContextType : public StructuralType { + public: + TypeHandle Outer() { return this->Get(0); } + + static ContextHandle New(TypeHandle outer, Region* region) { + ContextHandle type = Config::template cast( + StructuralType::New(StructuralType::kContextTag, 1, region)); + type->Set(0, outer); + return type; + } + + static ContextType* cast(TypeImpl* type) { + ASSERT(type->IsContext()); + return static_cast(type); + } +}; + + // Internal // A union is a structured type with the following invariants: // - its length is at least 2 diff --git a/test/cctest/test-types.cc b/test/cctest/test-types.cc index 47868f6484..e8f20be9b0 100644 --- a/test/cctest/test-types.cc +++ b/test/cctest/test-types.cc @@ -43,9 +43,10 @@ struct ZoneRep { static bool IsBitset(Type* t) { return reinterpret_cast(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(t); @@ -59,6 +60,9 @@ struct ZoneRep { static Object* AsConstant(Type* t) { return *static_cast(AsStruct(t)[3]); } + static Type* AsContext(Type* t) { + return *static_cast(AsStruct(t)[2]); + } static Struct* AsUnion(Type* t) { return AsStruct(t); } @@ -79,9 +83,10 @@ struct HeapRep { static bool IsBitset(Handle t) { return t->IsSmi(); } static bool IsClass(Handle t) { return t->IsMap(); } static bool IsConstant(Handle t) { return t->IsBox(); } - static bool IsArray(Handle t) { return IsStruct(t, 2); } - static bool IsFunction(Handle t) { return IsStruct(t, 3); } - static bool IsUnion(Handle t) { return IsStruct(t, 4); } + static bool IsContext(Handle t) { return IsStruct(t, 2); } + static bool IsArray(Handle t) { return IsStruct(t, 3); } + static bool IsFunction(Handle t) { return IsStruct(t, 4); } + static bool IsUnion(Handle t) { return IsStruct(t, 5); } static Struct* AsStruct(Handle t) { return FixedArray::cast(*t); } static int AsBitset(Handle t) { return Smi::cast(*t)->value(); } @@ -89,6 +94,9 @@ struct HeapRep { static Object* AsConstant(Handle t) { return Box::cast(*t)->value(); } + static HeapType* AsContext(Handle t) { + return HeapType::cast(AsStruct(t)->get(1)); + } static Struct* AsUnion(Handle 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(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