Commit eb099a1a authored by rossberg@chromium.org's avatar rossberg@chromium.org

Introduce Type::Intersect function

Also, fix bugs in Type::Union and Type::Maybe.

(This subsumes the in-flight fix for Union in https://codereview.chromium.org/16925008/, including test cases).

R=svenpanne@chromium.org
BUG=

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15224 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 0d409f52
......@@ -243,6 +243,7 @@ bool Type::Is(Type* that) {
// T <= (T1 \/ ... \/ Tn) <=> (T <= T1) \/ ... \/ (T <= Tn)
// (iff T is not a union)
ASSERT(!this->is_union());
if (that->is_union()) {
Handle<Unioned> unioned = that->as_union();
for (int i = 0; i < unioned->length(); ++i) {
......@@ -267,13 +268,6 @@ bool Type::Maybe(Type* that) {
return (this->LubBitset() & that->as_bitset()) != 0;
}
if (this->is_class()) {
return that->is_class() && *this->as_class() == *that->as_class();
}
if (this->is_constant()) {
return that->is_constant() && *this->as_constant() == *that->as_constant();
}
// (T1 \/ ... \/ Tn) overlaps T <=> (T1 overlaps T) \/ ... \/ (Tn overlaps T)
if (this->is_union()) {
Handle<Unioned> unioned = this->as_union();
......@@ -294,6 +288,14 @@ bool Type::Maybe(Type* that) {
return false;
}
ASSERT(!that->is_union());
if (this->is_class()) {
return that->is_class() && *this->as_class() == *that->as_class();
}
if (this->is_constant()) {
return that->is_constant() && *this->as_constant() == *that->as_constant();
}
return false;
}
......@@ -302,12 +304,12 @@ bool Type::InUnion(Handle<Unioned> unioned, int current_size) {
ASSERT(!this->is_union());
for (int i = 0; i < current_size; ++i) {
Handle<Type> type = union_get(unioned, i);
if (type->is_bitset() ? this->Is(type) : this == *type) return true;
if (this->Is(type)) return true;
}
return false;
}
// Get non-bitsets from this which are not subsumed by that, store at unioned,
// Get non-bitsets from this which are not subsumed by union, store at unioned,
// starting at index. Returns updated index.
int Type::ExtendUnion(Handle<Unioned> result, int current_size) {
int old_size = current_size;
......@@ -374,6 +376,79 @@ Type* Type::Union(Handle<Type> type1, Handle<Type> type2) {
}
// Get non-bitsets from this which are also in that, store at unioned,
// starting at index. Returns updated index.
int Type::ExtendIntersection(
Handle<Unioned> result, Handle<Type> that, int current_size) {
int old_size = current_size;
if (this->is_class() || this->is_constant()) {
if (this->Is(that) && !this->InUnion(result, old_size))
result->set(current_size++, this);
} else if (this->is_union()) {
Handle<Unioned> unioned = this->as_union();
for (int i = 0; i < unioned->length(); ++i) {
Handle<Type> type = union_get(unioned, i);
ASSERT(i == 0 || !(type->is_bitset() || type->Is(union_get(unioned, 0))));
if (type->is_bitset()) continue;
if (type->Is(that) && !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.
// TODO(rossberg): Should we use object sets somehow? Is it worth it?
Type* Type::Intersect(Handle<Type> type1, Handle<Type> type2) {
// Fast case: bit sets.
if (type1->is_bitset() && type2->is_bitset()) {
return from_bitset(type1->as_bitset() & type2->as_bitset());
}
// Semi-fast case: Unioned objects are neither involved nor produced.
if (!(type1->is_union() || type2->is_union())) {
if (type1->Is(type2)) return *type1;
if (type2->Is(type1)) return *type2;
}
// Slow case: may need to produce a Unioned object.
Isolate* isolate = NULL;
int size = 0;
if (!type1->is_bitset()) {
isolate = HeapObject::cast(*type1)->GetIsolate();
size = (type1->is_union() ? type1->as_union()->length() : 2);
}
if (!type2->is_bitset()) {
isolate = HeapObject::cast(*type2)->GetIsolate();
int size2 = (type2->is_union() ? type2->as_union()->length() : 2);
size = (size == 0 ? size2 : Min(size, size2));
}
ASSERT(isolate != NULL);
ASSERT(size >= 2);
Handle<Unioned> unioned = isolate->factory()->NewFixedArray(size);
size = 0;
int bitset = type1->GlbBitset() & type2->GlbBitset();
if (bitset != kNone) unioned->set(size++, from_bitset(bitset));
size = type1->ExtendIntersection(unioned, type2, size);
size = type2->ExtendIntersection(unioned, type1, size);
if (size == 0) {
return None();
} else if (size == 1) {
return *union_get(unioned, 0);
} else if (size == unioned->length()) {
return from_handle(unioned);
}
// There were dropped cases. Copy to smaller union.
Handle<Unioned> result = isolate->factory()->NewFixedArray(size);
for (int i = 0; i < size; ++i) result->set(i, unioned->get(i));
return from_handle(result);
}
Type* Type::Optional(Handle<Type> type) {
return type->is_bitset()
? from_bitset(type->as_bitset() | kUndefined)
......
......@@ -86,6 +86,7 @@ namespace internal {
// Internally, all 'primitive' types, and their unions, are represented as
// bitsets via smis. Class is a heap pointer to the respective map. Only
// Constant's, or unions containing Class'es or Constant's, require allocation.
// Note that the bitset representation is closed under both Union and Intersect.
//
// The type representation is heap-allocated, so cannot (currently) be used in
// a parallel compilation context.
......@@ -129,6 +130,7 @@ class Type : public Object {
}
static Type* Union(Handle<Type> type1, Handle<Type> type2);
static Type* Intersect(Handle<Type> type1, Handle<Type> type2);
static Type* Optional(Handle<Type> type); // type \/ Undefined
bool Is(Type* that);
......@@ -248,6 +250,8 @@ class Type : public Object {
int GlbBitset(); // greatest lower bound that's a bitset
bool InUnion(Handle<Unioned> unioned, int current_size);
int ExtendUnion(Handle<Unioned> unioned, int current_size);
int ExtendIntersection(
Handle<Unioned> unioned, Handle<Type> type, int current_size);
};
} } // namespace v8::internal
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment