Index: src/types.cc |
diff --git a/src/types.cc b/src/types.cc |
index 394f7726791b8cd81a9c8ae17a838d6cc47703e3..eae5f38320d25ac58945f7d3639197a564718e43 100644 |
--- a/src/types.cc |
+++ b/src/types.cc |
@@ -139,11 +139,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()) { |
@@ -287,11 +315,15 @@ bool TypeImpl<Config>::SlowIs(TypeImpl* that) { |
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 +456,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 +464,138 @@ 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); |
Benedikt Meurer
2014/05/23 05:09:00
This function always returns true, so the return t
|
+ 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->IsBitset()) { |
+ return that->AsBitset() & this->InherentBitsetLub(); |
+ } else 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 BitsetType::kNone; |
+} |
+ |
+ |
+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 old_bound = type->BitsetLub(); |
+ int other_bound = type->BoundBy(other->unhandle()); |
+ 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. |
+// 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 +631,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); |
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 +681,8 @@ 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); |
if (size == 0) { |
return None(region); |
@@ -590,6 +690,7 @@ typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Intersect( |
return unioned->Get(0); |
} else { |
unioned->Shrink(size); |
+ ASSERT(unioned->Wellformed()); |
return unioned; |
} |
} |
@@ -602,9 +703,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 +719,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, |