| Index: src/types.cc
|
| diff --git a/src/types.cc b/src/types.cc
|
| index 394f7726791b8cd81a9c8ae17a838d6cc47703e3..788ae0fb41eb57a09806da2fb86d6a13e979456d 100644
|
| --- a/src/types.cc
|
| +++ b/src/types.cc
|
| @@ -117,9 +117,25 @@ int TypeImpl<Config>::BitsetType::Glb(TypeImpl* type) {
|
| if (type->IsBitset()) {
|
| return type->AsBitset();
|
| } else if (type->IsUnion()) {
|
| - // All but the first are non-bitsets and thus would yield kNone anyway.
|
| - return type->AsUnion()->Get(0)->BitsetGlb();
|
| + UnionHandle unioned = handle(type->AsUnion());
|
| + int bitset = kNone;
|
| + for (int i = 0; i < unioned->Length(); ++i) {
|
| + bitset |= unioned->Get(i)->BitsetGlb();
|
| + }
|
| + return bitset;
|
| + } else if (type->IsClass()) {
|
| + // Little hack to avoid the need for a region for handlification here...
|
| + return REPRESENTATION(Config::is_class(type)
|
| + ? Lub(*Config::as_class(type))
|
| + : type->AsClass()->Bound(NULL)->AsBitset());
|
| + } else if (type->IsConstant()) {
|
| + return REPRESENTATION(type->AsConstant()->Bound()->AsBitset());
|
| + } else if (type->IsArray()) {
|
| + return REPRESENTATION(type->AsArray()->Bound()->AsBitset());
|
| + } else if (type->IsFunction()) {
|
| + return REPRESENTATION(type->AsFunction()->Bound()->AsBitset());
|
| } else {
|
| + UNREACHABLE();
|
| return kNone;
|
| }
|
| }
|
| @@ -139,11 +155,39 @@ int TypeImpl<Config>::BitsetType::Lub(TypeImpl* type) {
|
| }
|
| return bitset;
|
| } else if (type->IsClass()) {
|
| - int bitset = Config::lub_bitset(type);
|
| - return bitset ? bitset : Lub(*type->AsClass()->Map());
|
| + // Little hack to avoid the need for a region for handlification here...
|
| + return Config::is_class(type) ? Lub(*Config::as_class(type)) :
|
| + type->AsClass()->Bound(NULL)->AsBitset();
|
| } else if (type->IsConstant()) {
|
| - int bitset = Config::lub_bitset(type);
|
| - return bitset ? bitset : Lub(*type->AsConstant()->Value());
|
| + return type->AsConstant()->Bound()->AsBitset();
|
| + } else if (type->IsArray()) {
|
| + return type->AsArray()->Bound()->AsBitset();
|
| + } else if (type->IsFunction()) {
|
| + return type->AsFunction()->Bound()->AsBitset();
|
| + } else {
|
| + UNREACHABLE();
|
| + return kNone;
|
| + }
|
| +}
|
| +
|
| +
|
| +// Get the smallest bitset subsuming this type, ignoring current bounds.
|
| +template<class Config>
|
| +int TypeImpl<Config>::BitsetType::InherentLub(TypeImpl* type) {
|
| + DisallowHeapAllocation no_allocation;
|
| + if (type->IsBitset()) {
|
| + return type->AsBitset();
|
| + } else if (type->IsUnion()) {
|
| + UnionHandle unioned = handle(type->AsUnion());
|
| + int bitset = kNone;
|
| + for (int i = 0; i < unioned->Length(); ++i) {
|
| + bitset |= unioned->Get(i)->InherentBitsetLub();
|
| + }
|
| + return bitset;
|
| + } else if (type->IsClass()) {
|
| + return Lub(*type->AsClass()->Map());
|
| + } else if (type->IsConstant()) {
|
| + return Lub(*type->AsConstant()->Value());
|
| } else if (type->IsArray()) {
|
| return kArray;
|
| } else if (type->IsFunction()) {
|
| @@ -284,14 +328,23 @@ bool TypeImpl<Config>::SlowIs(TypeImpl* that) {
|
| if (that->IsBitset()) {
|
| return (BitsetType::Lub(this) | that->AsBitset()) == that->AsBitset();
|
| }
|
| + if (this->IsBitset() && SEMANTIC(this->AsBitset()) == BitsetType::kNone) {
|
| + // Bitsets only have non-bitset supertypes along the representation axis.
|
| + int that_bitset = that->BitsetGlb();
|
| + return (this->AsBitset() | that_bitset) == that_bitset;
|
| + }
|
|
|
| if (that->IsClass()) {
|
| return this->IsClass()
|
| - && *this->AsClass()->Map() == *that->AsClass()->Map();
|
| + && *this->AsClass()->Map() == *that->AsClass()->Map()
|
| + && ((Config::is_class(that) && Config::is_class(this)) ||
|
| + BitsetType::New(this->BitsetLub())->Is(
|
| + BitsetType::New(that->BitsetLub())));
|
| }
|
| if (that->IsConstant()) {
|
| return this->IsConstant()
|
| - && *this->AsConstant()->Value() == *that->AsConstant()->Value();
|
| + && *this->AsConstant()->Value() == *that->AsConstant()->Value()
|
| + && this->AsConstant()->Bound()->Is(that->AsConstant()->Bound());
|
| }
|
| if (that->IsArray()) {
|
| return this->IsArray()
|
| @@ -424,7 +477,6 @@ bool TypeImpl<Config>::Maybe(TypeImpl* that) {
|
| template<class Config>
|
| bool TypeImpl<Config>::Contains(i::Object* value) {
|
| DisallowHeapAllocation no_allocation;
|
| -
|
| for (Iterator<i::Object> it = this->Constants(); !it.Done(); it.Advance()) {
|
| if (*it.Current() == value) return true;
|
| }
|
| @@ -433,43 +485,157 @@ bool TypeImpl<Config>::Contains(i::Object* value) {
|
|
|
|
|
| template<class Config>
|
| -bool TypeImpl<Config>::InUnion(UnionHandle unioned, int current_size) {
|
| +bool TypeImpl<Config>::UnionType::Wellformed() {
|
| + ASSERT(this->Length() >= 2);
|
| + for (int i = 0; i < this->Length(); ++i) {
|
| + ASSERT(!this->Get(i)->IsUnion());
|
| + if (i > 0) ASSERT(!this->Get(i)->IsBitset());
|
| + for (int j = 0; j < this->Length(); ++j) {
|
| + if (i != j) ASSERT(!this->Get(i)->Is(this->Get(j)));
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +
|
| +template<class Config>
|
| +typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Narrow(
|
| + int bitset, Region* region) {
|
| + TypeHandle bound = BitsetType::New(bitset, region);
|
| + if (this->IsClass()) {
|
| + return ClassType::New(this->AsClass()->Map(), bound, region);
|
| + } else if (this->IsConstant()) {
|
| + return ConstantType::New(this->AsConstant()->Value(), bound, region);
|
| + } else if (this->IsArray()) {
|
| + return ArrayType::New(this->AsArray()->Element(), bound, region);
|
| + } else if (this->IsFunction()) {
|
| + FunctionType* function = this->AsFunction();
|
| + int arity = function->Arity();
|
| + FunctionHandle type = FunctionType::New(
|
| + function->Result(), function->Receiver(), bound, arity, region);
|
| + for (int i = 0; i < arity; ++i) {
|
| + type->InitParameter(i, function->Parameter(i));
|
| + }
|
| + return type;
|
| + }
|
| + UNREACHABLE();
|
| + return TypeHandle();
|
| +}
|
| +
|
| +
|
| +template<class Config>
|
| +int TypeImpl<Config>::BoundBy(TypeImpl* that) {
|
| + ASSERT(!this->IsUnion());
|
| + if (that->IsUnion()) {
|
| + UnionType* unioned = that->AsUnion();
|
| + int length = unioned->Length();
|
| + int bitset = BitsetType::kNone;
|
| + for (int i = 0; i < length; ++i) {
|
| + bitset |= BoundBy(unioned->Get(i)->unhandle());
|
| + }
|
| + return bitset;
|
| + } else if (that->IsClass() && this->IsClass() &&
|
| + *this->AsClass()->Map() == *that->AsClass()->Map()) {
|
| + return that->BitsetLub();
|
| + } else if (that->IsConstant() && this->IsConstant() &&
|
| + *this->AsConstant()->Value() == *that->AsConstant()->Value()) {
|
| + return that->AsConstant()->Bound()->AsBitset();
|
| + } else if (that->IsArray() && this->IsArray() && this->Is(that)) {
|
| + return that->AsArray()->Bound()->AsBitset();
|
| + } else if (that->IsFunction() && this->IsFunction() && this->Is(that)) {
|
| + return that->AsFunction()->Bound()->AsBitset();
|
| + }
|
| + return that->BitsetGlb();
|
| +}
|
| +
|
| +
|
| +template<class Config>
|
| +int TypeImpl<Config>::IndexInUnion(
|
| + int bound, UnionHandle unioned, int current_size) {
|
| ASSERT(!this->IsUnion());
|
| for (int i = 0; i < current_size; ++i) {
|
| - if (this->Is(unioned->Get(i))) return true;
|
| + TypeHandle that = unioned->Get(i);
|
| + if (that->IsBitset()) {
|
| + if ((bound | that->AsBitset()) == that->AsBitset()) return i;
|
| + } else if (that->IsClass() && this->IsClass()) {
|
| + if (*this->AsClass()->Map() == *that->AsClass()->Map()) return i;
|
| + } else if (that->IsConstant() && this->IsConstant()) {
|
| + if (*this->AsConstant()->Value() == *that->AsConstant()->Value())
|
| + return i;
|
| + } else if (that->IsArray() && this->IsArray()) {
|
| + if (this->Is(that)) return i;
|
| + } else if (that->IsFunction() && this->IsFunction()) {
|
| + if (this->Is(that)) return i;
|
| + }
|
| }
|
| - return false;
|
| + return -1;
|
| }
|
|
|
|
|
| -// Get non-bitsets from this which are not subsumed by union, store at result,
|
| -// starting at index. Returns updated index.
|
| +// Get non-bitsets from type, bounded by upper.
|
| +// Store at result starting at index. Returns updated index.
|
| template<class Config>
|
| int TypeImpl<Config>::ExtendUnion(
|
| - UnionHandle result, TypeHandle type, int current_size) {
|
| - int old_size = current_size;
|
| + UnionHandle result, int size, TypeHandle type,
|
| + TypeHandle other, bool is_intersect, Region* region) {
|
| + int old_size = size;
|
| if (type->IsUnion()) {
|
| UnionHandle unioned = handle(type->AsUnion());
|
| for (int i = 0; i < unioned->Length(); ++i) {
|
| - TypeHandle type = unioned->Get(i);
|
| - ASSERT(i == 0 || !(type->IsBitset() || type->Is(unioned->Get(0))));
|
| - if (!type->IsBitset() && !type->InUnion(result, old_size)) {
|
| - result->Set(current_size++, type);
|
| + TypeHandle type_i = unioned->Get(i);
|
| + ASSERT(i == 0 || !(type_i->IsBitset() || type_i->Is(unioned->Get(0))));
|
| + if (!type_i->IsBitset()) {
|
| + size = ExtendUnion(result, size, type_i, other, is_intersect, region);
|
| }
|
| }
|
| } else if (!type->IsBitset()) {
|
| - // For all structural types, subtyping implies equivalence.
|
| ASSERT(type->IsClass() || type->IsConstant() ||
|
| type->IsArray() || type->IsFunction());
|
| - if (!type->InUnion(result, old_size)) {
|
| - result->Set(current_size++, type);
|
| + int inherent_bound = type->InherentBitsetLub();
|
| + int old_bound = type->BitsetLub();
|
| + int other_bound = type->BoundBy(other->unhandle()) & inherent_bound;
|
| + int new_bound =
|
| + is_intersect ? (old_bound & other_bound) : (old_bound | other_bound);
|
| + if (new_bound != BitsetType::kNone) {
|
| + int i = type->IndexInUnion(new_bound, result, old_size);
|
| + if (i == -1) {
|
| + i = size++;
|
| + } else if (result->Get(i)->IsBitset()) {
|
| + return size; // Already fully subsumed.
|
| + } else {
|
| + int type_i_bound = result->Get(i)->BitsetLub();
|
| + new_bound |= type_i_bound;
|
| + if (new_bound == type_i_bound) return size;
|
| + }
|
| + if (new_bound != old_bound) type = type->Narrow(new_bound, region);
|
| + result->Set(i, type);
|
| }
|
| }
|
| - return current_size;
|
| + return size;
|
| }
|
|
|
|
|
| -// Union is O(1) on simple bit unions, but O(n*m) on structured unions.
|
| +// If bitset is subsumed by another entry in the result, remove it.
|
| +// (Only bitsets with empty semantic axis can be subtypes of non-bitsets.)
|
| +template<class Config>
|
| +int TypeImpl<Config>::NormalizeUnion(UnionHandle result, int size, int bitset) {
|
| + if (bitset != BitsetType::kNone && SEMANTIC(bitset) == BitsetType::kNone) {
|
| + for (int i = 1; i < size; ++i) {
|
| + int glb = result->Get(i)->BitsetGlb();
|
| + if ((bitset | glb) == glb) {
|
| + for (int j = 1; j < size; ++j) {
|
| + result->Set(j - 1, result->Get(j));
|
| + }
|
| + --size;
|
| + break;
|
| + }
|
| + }
|
| + }
|
| + return size;
|
| +}
|
| +
|
| +
|
| +// Union is O(1) on simple bitsets, but O(n*m) on structured unions.
|
| template<class Config>
|
| typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Union(
|
| TypeHandle type1, TypeHandle type2, Region* region) {
|
| @@ -505,47 +671,21 @@ typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Union(
|
| if (bitset != BitsetType::kNone) {
|
| unioned->Set(size++, BitsetType::New(bitset, region));
|
| }
|
| - size = ExtendUnion(unioned, type1, size);
|
| - size = ExtendUnion(unioned, type2, size);
|
| + size = ExtendUnion(unioned, size, type1, type2, false, region);
|
| + size = ExtendUnion(unioned, size, type2, type1, false, region);
|
| + size = NormalizeUnion(unioned, size, bitset);
|
|
|
| if (size == 1) {
|
| return unioned->Get(0);
|
| } else {
|
| unioned->Shrink(size);
|
| + ASSERT(unioned->Wellformed());
|
| return unioned;
|
| }
|
| }
|
|
|
|
|
| -// Get non-bitsets from type which are also in other, store at result,
|
| -// starting at index. Returns updated index.
|
| -template<class Config>
|
| -int TypeImpl<Config>::ExtendIntersection(
|
| - UnionHandle result, TypeHandle type, TypeHandle other, int current_size) {
|
| - int old_size = current_size;
|
| - if (type->IsUnion()) {
|
| - UnionHandle unioned = handle(type->AsUnion());
|
| - for (int i = 0; i < unioned->Length(); ++i) {
|
| - TypeHandle type = unioned->Get(i);
|
| - ASSERT(i == 0 || !(type->IsBitset() || type->Is(unioned->Get(0))));
|
| - if (!type->IsBitset() && type->Is(other) &&
|
| - !type->InUnion(result, old_size)) {
|
| - result->Set(current_size++, type);
|
| - }
|
| - }
|
| - } else if (!type->IsBitset()) {
|
| - // For all structural types, subtyping implies equivalence.
|
| - ASSERT(type->IsClass() || type->IsConstant() ||
|
| - type->IsArray() || type->IsFunction());
|
| - if (type->Is(other) && !type->InUnion(result, old_size)) {
|
| - result->Set(current_size++, type);
|
| - }
|
| - }
|
| - return current_size;
|
| -}
|
| -
|
| -
|
| -// Intersection is O(1) on simple bit unions, but O(n*m) on structured unions.
|
| +// Intersection is O(1) on simple bitsets, but O(n*m) on structured unions.
|
| template<class Config>
|
| typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Intersect(
|
| TypeHandle type1, TypeHandle type2, Region* region) {
|
| @@ -581,8 +721,9 @@ typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Intersect(
|
| if (bitset != BitsetType::kNone) {
|
| unioned->Set(size++, BitsetType::New(bitset, region));
|
| }
|
| - size = ExtendIntersection(unioned, type1, type2, size);
|
| - size = ExtendIntersection(unioned, type2, type1, size);
|
| + size = ExtendUnion(unioned, size, type1, type2, true, region);
|
| + size = ExtendUnion(unioned, size, type2, type1, true, region);
|
| + size = NormalizeUnion(unioned, size, bitset);
|
|
|
| if (size == 0) {
|
| return None(region);
|
| @@ -590,6 +731,7 @@ typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Intersect(
|
| return unioned->Get(0);
|
| } else {
|
| unioned->Shrink(size);
|
| + ASSERT(unioned->Wellformed());
|
| return unioned;
|
| }
|
| }
|
| @@ -602,9 +744,13 @@ typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Convert(
|
| if (type->IsBitset()) {
|
| return BitsetType::New(type->AsBitset(), region);
|
| } else if (type->IsClass()) {
|
| - return ClassType::New(type->AsClass()->Map(), region);
|
| + return ClassType::New(
|
| + type->AsClass()->Map(),
|
| + BitsetType::New(type->BitsetLub(), region), region);
|
| } else if (type->IsConstant()) {
|
| - return ConstantType::New(type->AsConstant()->Value(), region);
|
| + return ConstantType::New(
|
| + type->AsConstant()->Value(),
|
| + Convert<OtherType>(type->AsConstant()->Bound(), region), region);
|
| } else if (type->IsUnion()) {
|
| int length = type->AsUnion()->Length();
|
| UnionHandle unioned = UnionType::New(length, region);
|
| @@ -614,11 +760,13 @@ typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Convert(
|
| return unioned;
|
| } else if (type->IsArray()) {
|
| return ArrayType::New(
|
| - Convert<OtherType>(type->AsArray()->Element(), region), region);
|
| + Convert<OtherType>(type->AsArray()->Element(), region),
|
| + Convert<OtherType>(type->AsArray()->Bound(), region), region);
|
| } else if (type->IsFunction()) {
|
| FunctionHandle function = FunctionType::New(
|
| Convert<OtherType>(type->AsFunction()->Result(), region),
|
| Convert<OtherType>(type->AsFunction()->Receiver(), region),
|
| + Convert<OtherType>(type->AsFunction()->Bound(), region),
|
| type->AsFunction()->Arity(), region);
|
| for (int i = 0; i < function->Arity(); ++i) {
|
| function->InitParameter(i,
|
| @@ -708,57 +856,55 @@ void TypeImpl<Config>::BitsetType::BitsetTypePrint(FILE* out, int bitset) {
|
| 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);
|
| + if (dim != REPRESENTATION_DIM) {
|
| + if (this->IsBitset()) {
|
| + BitsetType::BitsetTypePrint(out, SEMANTIC(this->AsBitset()));
|
| + } else if (this->IsConstant()) {
|
| + PrintF(out, "Constant(%p : ",
|
| + static_cast<void*>(*this->AsConstant()->Value()));
|
| + BitsetType::New(BitsetType::Lub(this))->TypePrint(out, dim);
|
| + PrintF(out, ")");
|
| + return;
|
| + } else if (this->IsClass()) {
|
| + PrintF(out, "Class(%p < ", static_cast<void*>(*this->AsClass()->Map()));
|
| + BitsetType::New(BitsetType::Lub(this))->TypePrint(out, dim);
|
| + PrintF(out, ")");
|
| + return;
|
| + } 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, ")");
|
| + return;
|
| + } else if (this->IsArray()) {
|
| + PrintF(out, "Array(");
|
| + 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();
|
| }
|
| - PrintF(out, ")->");
|
| - this->AsFunction()->Result()->TypePrint(out, dim);
|
| - } else {
|
| - UNREACHABLE();
|
| + }
|
| + if (dim == BOTH_DIMS) {
|
| + PrintF(out, "/");
|
| + }
|
| + if (dim != SEMANTIC_DIM) {
|
| + BitsetType::BitsetTypePrint(out, REPRESENTATION(this->BitsetLub()));
|
| }
|
| }
|
|
|
|
|