| 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)
|
|
|