Various extensions to types

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
This commit is contained in:
rossberg@chromium.org 2014-05-26 13:10:52 +00:00
parent 6ed0102b1d
commit dbf7d8528c
6 changed files with 343 additions and 169 deletions

View 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();

View 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;
}

View 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;
}

View 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);
if (value->IsNumber()) {
return Lub(value->Number()) & (value->IsSmi() ? kTaggedInt : kTaggedPtr);
}
return Lub(map);
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,94 +708,115 @@ 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>::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);
}
stream->Add(")->");
this->AsFunction()->Result()->PrintTo(stream, dim);
} else {
UNREACHABLE();
}
}
template<class Config>
void TypeImpl<Config>::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<void*>(*this->AsConstant()->Value()));
BitsetType::New(BitsetType::Lub(this))->TypePrint(out, dim);
PrintF(out, ")");
} else if (this->IsClass()) {
PrintF(out, "Class(%p < ", static_cast<void*>(*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<class Config>
void TypeImpl<Config>::TypePrint(PrintDimension dim) {
TypePrint(stdout, dim);
PrintF(stdout, "\n");
Flush(stdout);
}

View 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

View 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