Index: src/types.cc |
diff --git a/src/types.cc b/src/types.cc |
index 20e8a4c994541fc18f10e3cdbece64843645acd8..22a108b7206b0bd657ae57e90af4c20a11770190 100644 |
--- a/src/types.cc |
+++ b/src/types.cc |
@@ -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) |