Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1517)

Unified Diff: src/types.cc

Issue 251753005: Establish distributivity for type union & intersection (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Accurate representation glb & intersection; renaming Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/types.h ('k') | src/types-inl.h » ('j') | test/cctest/test-types.cc » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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()));
}
}
« no previous file with comments | « src/types.h ('k') | src/types-inl.h » ('j') | test/cctest/test-types.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698