Establish distributivity for type union & intersection

This requires introducing proper bounds on all leaf types, so that intersection between bitsets and these types can be accurately represented. Extending a union also becomes more involved.

(On the upside, the modified union/intersect algorithm would now allow support for proper variance for function types.)

Not sure if it is worth landing this. Distributivity isn't really a crucial property for our use cases. It seems fine if intersection is slightly lossy.

R=bmeurer@chromium.org, jarin@chromium.org
BUG=

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21528 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
rossberg@chromium.org 2014-05-27 13:52:31 +00:00
parent 276adeda1a
commit 7ac892c8bd
5 changed files with 873 additions and 487 deletions

View File

@ -8,6 +8,7 @@
#include "conversions.h"
#include "objects.h"
#include "property-details.h"
#include "types.h"
namespace v8 {
namespace internal {
@ -23,6 +24,16 @@ inline bool Representation::CanContainDouble(double value) {
return false;
}
Representation Representation::FromType(Type* type) {
DisallowHeapAllocation no_allocation;
if (type->Is(Type::None())) return Representation::None();
if (type->Is(Type::SignedSmall())) return Representation::Smi();
if (type->Is(Type::Signed32())) return Representation::Integer32();
if (type->Is(Type::Number())) return Representation::Double();
return Representation::Tagged();
}
} } // namespace v8::internal
#endif // V8_PROPERTY_DETAILS_INL_H_

View File

@ -13,7 +13,7 @@
namespace v8 {
namespace internal {
// -------------------------------------------------------------------------- //
// -----------------------------------------------------------------------------
// TypeImpl
template<class Config>
@ -25,6 +25,18 @@ TypeImpl<Config>* TypeImpl<Config>::cast(typename Config::Base* object) {
}
// Most precise _current_ type of a value (usually its class).
template<class Config>
typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::NowOf(
i::Object* value, Region* region) {
if (value->IsSmi() ||
i::HeapObject::cast(value)->map()->instance_type() == HEAP_NUMBER_TYPE) {
return Of(value, region);
}
return Class(i::handle(i::HeapObject::cast(value)->map()), region);
}
template<class Config>
bool TypeImpl<Config>::NowContains(i::Object* value) {
DisallowHeapAllocation no_allocation;
@ -39,7 +51,7 @@ bool TypeImpl<Config>::NowContains(i::Object* value) {
}
// -------------------------------------------------------------------------- //
// -----------------------------------------------------------------------------
// ZoneTypeConfig
// static
@ -70,13 +82,7 @@ bool ZoneTypeConfig::is_struct(Type* type, int tag) {
// static
bool ZoneTypeConfig::is_class(Type* type) {
return is_struct(type, Type::StructuralType::kClassTag);
}
// static
bool ZoneTypeConfig::is_constant(Type* type) {
return is_struct(type, Type::StructuralType::kConstantTag);
return false;
}
@ -96,16 +102,8 @@ ZoneTypeConfig::Struct* ZoneTypeConfig::as_struct(Type* type) {
// static
i::Handle<i::Map> ZoneTypeConfig::as_class(Type* type) {
ASSERT(is_class(type));
return i::Handle<i::Map>(static_cast<i::Map**>(as_struct(type)[3]));
}
// static
i::Handle<i::Object> ZoneTypeConfig::as_constant(Type* type) {
ASSERT(is_constant(type));
return i::Handle<i::Object>(
static_cast<i::Object**>(as_struct(type)[3]));
UNREACHABLE();
return i::Handle<i::Map>();
}
@ -122,84 +120,80 @@ ZoneTypeConfig::Type* ZoneTypeConfig::from_bitset(int bitset, Zone* Zone) {
// static
ZoneTypeConfig::Type* ZoneTypeConfig::from_struct(Struct* structured) {
return reinterpret_cast<Type*>(structured);
ZoneTypeConfig::Type* ZoneTypeConfig::from_struct(Struct* structure) {
return reinterpret_cast<Type*>(structure);
}
// static
ZoneTypeConfig::Type* ZoneTypeConfig::from_class(
i::Handle<i::Map> map, int lub, Zone* zone) {
Struct* structured = struct_create(Type::StructuralType::kClassTag, 2, zone);
structured[2] = from_bitset(lub);
structured[3] = map.location();
return from_struct(structured);
}
// static
ZoneTypeConfig::Type* ZoneTypeConfig::from_constant(
i::Handle<i::Object> value, int lub, Zone* zone) {
Struct* structured =
struct_create(Type::StructuralType::kConstantTag, 2, zone);
structured[2] = from_bitset(lub);
structured[3] = value.location();
return from_struct(structured);
i::Handle<i::Map> map, Zone* zone) {
return from_bitset(0);
}
// static
ZoneTypeConfig::Struct* ZoneTypeConfig::struct_create(
int tag, int length, Zone* zone) {
Struct* structured = reinterpret_cast<Struct*>(
Struct* structure = reinterpret_cast<Struct*>(
zone->New(sizeof(void*) * (length + 2))); // NOLINT
structured[0] = reinterpret_cast<void*>(tag);
structured[1] = reinterpret_cast<void*>(length);
return structured;
structure[0] = reinterpret_cast<void*>(tag);
structure[1] = reinterpret_cast<void*>(length);
return structure;
}
// static
void ZoneTypeConfig::struct_shrink(Struct* structured, int length) {
ASSERT(0 <= length && length <= struct_length(structured));
structured[1] = reinterpret_cast<void*>(length);
void ZoneTypeConfig::struct_shrink(Struct* structure, int length) {
ASSERT(0 <= length && length <= struct_length(structure));
structure[1] = reinterpret_cast<void*>(length);
}
// static
int ZoneTypeConfig::struct_tag(Struct* structured) {
return static_cast<int>(reinterpret_cast<intptr_t>(structured[0]));
int ZoneTypeConfig::struct_tag(Struct* structure) {
return static_cast<int>(reinterpret_cast<intptr_t>(structure[0]));
}
// static
int ZoneTypeConfig::struct_length(Struct* structured) {
return static_cast<int>(reinterpret_cast<intptr_t>(structured[1]));
int ZoneTypeConfig::struct_length(Struct* structure) {
return static_cast<int>(reinterpret_cast<intptr_t>(structure[1]));
}
// static
Type* ZoneTypeConfig::struct_get(Struct* structured, int i) {
ASSERT(0 <= i && i <= struct_length(structured));
return static_cast<Type*>(structured[2 + i]);
Type* ZoneTypeConfig::struct_get(Struct* structure, int i) {
ASSERT(0 <= i && i <= struct_length(structure));
return static_cast<Type*>(structure[2 + i]);
}
// static
void ZoneTypeConfig::struct_set(Struct* structured, int i, Type* type) {
ASSERT(0 <= i && i <= struct_length(structured));
structured[2 + i] = type;
void ZoneTypeConfig::struct_set(Struct* structure, int i, Type* x) {
ASSERT(0 <= i && i <= struct_length(structure));
structure[2 + i] = x;
}
// static
int ZoneTypeConfig::lub_bitset(Type* type) {
ASSERT(is_class(type) || is_constant(type));
return as_bitset(struct_get(as_struct(type), 0));
template<class V>
i::Handle<V> ZoneTypeConfig::struct_get_value(Struct* structure, int i) {
ASSERT(0 <= i && i <= struct_length(structure));
return i::Handle<V>(static_cast<V**>(structure[2 + i]));
}
// -------------------------------------------------------------------------- //
// static
template<class V>
void ZoneTypeConfig::struct_set_value(
Struct* structure, int i, i::Handle<V> x) {
ASSERT(0 <= i && i <= struct_length(structure));
structure[2 + i] = x.location();
}
// -----------------------------------------------------------------------------
// HeapTypeConfig
// static
@ -228,12 +222,6 @@ bool HeapTypeConfig::is_class(Type* type) {
}
// static
bool HeapTypeConfig::is_constant(Type* type) {
return type->IsBox();
}
// static
bool HeapTypeConfig::is_struct(Type* type, int tag) {
return type->IsFixedArray() && struct_tag(as_struct(type)) == tag;
@ -252,13 +240,6 @@ i::Handle<i::Map> HeapTypeConfig::as_class(Type* type) {
}
// static
i::Handle<i::Object> HeapTypeConfig::as_constant(Type* type) {
i::Box* box = i::Box::cast(type);
return i::handle(box->value(), box->GetIsolate());
}
// static
i::Handle<HeapTypeConfig::Struct> HeapTypeConfig::as_struct(Type* type) {
return i::handle(Struct::cast(type));
@ -280,71 +261,74 @@ i::Handle<HeapTypeConfig::Type> HeapTypeConfig::from_bitset(
// static
i::Handle<HeapTypeConfig::Type> HeapTypeConfig::from_class(
i::Handle<i::Map> map, int lub, Isolate* isolate) {
i::Handle<i::Map> map, Isolate* isolate) {
return i::Handle<Type>::cast(i::Handle<Object>::cast(map));
}
// static
i::Handle<HeapTypeConfig::Type> HeapTypeConfig::from_constant(
i::Handle<i::Object> value, int lub, Isolate* isolate) {
i::Handle<Box> box = isolate->factory()->NewBox(value);
return i::Handle<Type>::cast(i::Handle<Object>::cast(box));
}
// static
i::Handle<HeapTypeConfig::Type> HeapTypeConfig::from_struct(
i::Handle<Struct> structured) {
return i::Handle<Type>::cast(i::Handle<Object>::cast(structured));
i::Handle<Struct> structure) {
return i::Handle<Type>::cast(i::Handle<Object>::cast(structure));
}
// static
i::Handle<HeapTypeConfig::Struct> HeapTypeConfig::struct_create(
int tag, int length, Isolate* isolate) {
i::Handle<Struct> structured = isolate->factory()->NewFixedArray(length + 1);
structured->set(0, i::Smi::FromInt(tag));
return structured;
i::Handle<Struct> structure = isolate->factory()->NewFixedArray(length + 1);
structure->set(0, i::Smi::FromInt(tag));
return structure;
}
// static
void HeapTypeConfig::struct_shrink(i::Handle<Struct> structured, int length) {
structured->Shrink(length + 1);
void HeapTypeConfig::struct_shrink(i::Handle<Struct> structure, int length) {
structure->Shrink(length + 1);
}
// static
int HeapTypeConfig::struct_tag(i::Handle<Struct> structured) {
return static_cast<i::Smi*>(structured->get(0))->value();
int HeapTypeConfig::struct_tag(i::Handle<Struct> structure) {
return static_cast<i::Smi*>(structure->get(0))->value();
}
// static
int HeapTypeConfig::struct_length(i::Handle<Struct> structured) {
return structured->length() - 1;
int HeapTypeConfig::struct_length(i::Handle<Struct> structure) {
return structure->length() - 1;
}
// static
i::Handle<HeapTypeConfig::Type> HeapTypeConfig::struct_get(
i::Handle<Struct> structured, int i) {
Type* type = static_cast<Type*>(structured->get(i + 1));
return i::handle(type, structured->GetIsolate());
i::Handle<Struct> structure, int i) {
Type* type = static_cast<Type*>(structure->get(i + 1));
return i::handle(type, structure->GetIsolate());
}
// static
void HeapTypeConfig::struct_set(
i::Handle<Struct> structured, int i, i::Handle<Type> type) {
structured->set(i + 1, *type);
i::Handle<Struct> structure, int i, i::Handle<Type> type) {
structure->set(i + 1, *type);
}
// static
int HeapTypeConfig::lub_bitset(Type* type) {
return 0; // kNone, which causes recomputation.
template<class V>
i::Handle<V> HeapTypeConfig::struct_get_value(
i::Handle<Struct> structure, int i) {
V* x = static_cast<V*>(structure->get(i + 1));
return i::handle(x, structure->GetIsolate());
}
// static
template<class V>
void HeapTypeConfig::struct_set_value(
i::Handle<Struct> structure, int i, i::Handle<V> x) {
structure->set(i + 1, *x);
}
} } // namespace v8::internal

View File

@ -10,122 +10,43 @@
namespace v8 {
namespace internal {
template<class Config>
int TypeImpl<Config>::NumClasses() {
DisallowHeapAllocation no_allocation;
if (this->IsClass()) {
return 1;
} else if (this->IsUnion()) {
UnionHandle unioned = handle(this->AsUnion());
int result = 0;
for (int i = 0; i < unioned->Length(); ++i) {
if (unioned->Get(i)->IsClass()) ++result;
}
return result;
} else {
return 0;
}
}
// -----------------------------------------------------------------------------
// Glb and lub computation.
template<class Config>
int TypeImpl<Config>::NumConstants() {
DisallowHeapAllocation no_allocation;
if (this->IsConstant()) {
return 1;
} else if (this->IsUnion()) {
UnionHandle unioned = handle(this->AsUnion());
int result = 0;
for (int i = 0; i < unioned->Length(); ++i) {
if (unioned->Get(i)->IsConstant()) ++result;
}
return result;
} else {
return 0;
}
}
template<class Config> template<class T>
typename TypeImpl<Config>::TypeHandle
TypeImpl<Config>::Iterator<T>::get_type() {
ASSERT(!Done());
return type_->IsUnion() ? type_->AsUnion()->Get(index_) : type_;
}
// C++ cannot specialise nested templates, so we have to go through this
// contortion with an auxiliary template to simulate it.
template<class Config, class T>
struct TypeImplIteratorAux {
static bool matches(typename TypeImpl<Config>::TypeHandle type);
static i::Handle<T> current(typename TypeImpl<Config>::TypeHandle type);
};
template<class Config>
struct TypeImplIteratorAux<Config, i::Map> {
static bool matches(typename TypeImpl<Config>::TypeHandle type) {
return type->IsClass();
}
static i::Handle<i::Map> current(typename TypeImpl<Config>::TypeHandle type) {
return type->AsClass()->Map();
}
};
template<class Config>
struct TypeImplIteratorAux<Config, i::Object> {
static bool matches(typename TypeImpl<Config>::TypeHandle type) {
return type->IsConstant();
}
static i::Handle<i::Object> current(
typename TypeImpl<Config>::TypeHandle type) {
return type->AsConstant()->Value();
}
};
template<class Config> template<class T>
bool TypeImpl<Config>::Iterator<T>::matches(TypeHandle type) {
return TypeImplIteratorAux<Config, T>::matches(type);
}
template<class Config> template<class T>
i::Handle<T> TypeImpl<Config>::Iterator<T>::Current() {
return TypeImplIteratorAux<Config, T>::current(get_type());
}
template<class Config> template<class T>
void TypeImpl<Config>::Iterator<T>::Advance() {
DisallowHeapAllocation no_allocation;
++index_;
if (type_->IsUnion()) {
UnionHandle unioned = handle(type_->AsUnion());
for (; index_ < unioned->Length(); ++index_) {
if (matches(unioned->Get(index_))) return;
}
} else if (index_ == 0 && matches(type_)) {
return;
}
index_ = -1;
}
// Get the largest bitset subsumed by this type.
// The largest bitset subsumed by this type.
template<class Config>
int TypeImpl<Config>::BitsetType::Glb(TypeImpl* type) {
DisallowHeapAllocation no_allocation;
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->IsContext()) {
return REPRESENTATION(type->AsContext()->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;
}
}
// Get the smallest bitset subsuming this type.
// The smallest bitset subsuming this type.
template<class Config>
int TypeImpl<Config>::BitsetType::Lub(TypeImpl* type) {
DisallowHeapAllocation no_allocation;
@ -139,17 +60,47 @@ 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->IsContext()) {
return type->AsContext()->Bound()->AsBitset();
} else if (type->IsArray()) {
return type->AsArray()->Bound()->AsBitset();
} else if (type->IsFunction()) {
return type->AsFunction()->Bound()->AsBitset();
} else {
UNREACHABLE();
return kNone;
}
}
// The smallest bitset subsuming this type, ignoring explicit 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->IsContext()) {
return kInternal & kTaggedPtr;
} else if (type->IsArray()) {
return kArray;
} else if (type->IsFunction()) {
return kFunction;
} else if (type->IsContext()) {
return kInternal & kTaggedPtr;
} else {
UNREACHABLE();
return kNone;
@ -295,17 +246,8 @@ int TypeImpl<Config>::BitsetType::Lub(i::Map* map) {
}
// Most precise _current_ type of a value (usually its class).
template<class Config>
typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::NowOf(
i::Object* value, Region* region) {
if (value->IsSmi() ||
i::HeapObject::cast(value)->map()->instance_type() == HEAP_NUMBER_TYPE) {
return Of(value, region);
}
return Class(i::handle(i::HeapObject::cast(value)->map()), region);
}
// -----------------------------------------------------------------------------
// Predicates.
// Check this <= that.
template<class Config>
@ -317,14 +259,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->IsContext()) {
return this->IsContext()
@ -461,10 +412,10 @@ bool TypeImpl<Config>::Maybe(TypeImpl* that) {
}
// Check if value is contained in (inhabits) type.
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;
}
@ -473,44 +424,166 @@ bool TypeImpl<Config>::Contains(i::Object* value) {
template<class Config>
bool TypeImpl<Config>::InUnion(UnionHandle unioned, int current_size) {
ASSERT(!this->IsUnion());
for (int i = 0; i < current_size; ++i) {
if (this->Is(unioned->Get(i))) return true;
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 false;
return true;
}
// Get non-bitsets from this which are not subsumed by union, store at result,
// starting at index. Returns updated index.
// -----------------------------------------------------------------------------
// Union and intersection
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->IsContext()) {
return ContextType::New(this->AsContext()->Outer(), 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->IsContext() && this->IsContext() && this->Is(that)) {
return that->AsContext()->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) {
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->IsContext() && this->IsContext()) {
if (this->Is(that)) 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 -1;
}
// 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() ||
type->IsContext());
if (!type->InUnion(result, old_size)) {
result->Set(current_size++, type);
type->IsArray() || type->IsFunction() || type->IsContext());
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) {
@ -546,47 +619,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() || type->IsContext());
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) {
@ -622,8 +669,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);
@ -631,11 +679,118 @@ typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Intersect(
return unioned->Get(0);
} else {
unioned->Shrink(size);
ASSERT(unioned->Wellformed());
return unioned;
}
}
// -----------------------------------------------------------------------------
// Iteration.
template<class Config>
int TypeImpl<Config>::NumClasses() {
DisallowHeapAllocation no_allocation;
if (this->IsClass()) {
return 1;
} else if (this->IsUnion()) {
UnionHandle unioned = handle(this->AsUnion());
int result = 0;
for (int i = 0; i < unioned->Length(); ++i) {
if (unioned->Get(i)->IsClass()) ++result;
}
return result;
} else {
return 0;
}
}
template<class Config>
int TypeImpl<Config>::NumConstants() {
DisallowHeapAllocation no_allocation;
if (this->IsConstant()) {
return 1;
} else if (this->IsUnion()) {
UnionHandle unioned = handle(this->AsUnion());
int result = 0;
for (int i = 0; i < unioned->Length(); ++i) {
if (unioned->Get(i)->IsConstant()) ++result;
}
return result;
} else {
return 0;
}
}
template<class Config> template<class T>
typename TypeImpl<Config>::TypeHandle
TypeImpl<Config>::Iterator<T>::get_type() {
ASSERT(!Done());
return type_->IsUnion() ? type_->AsUnion()->Get(index_) : type_;
}
// C++ cannot specialise nested templates, so we have to go through this
// contortion with an auxiliary template to simulate it.
template<class Config, class T>
struct TypeImplIteratorAux {
static bool matches(typename TypeImpl<Config>::TypeHandle type);
static i::Handle<T> current(typename TypeImpl<Config>::TypeHandle type);
};
template<class Config>
struct TypeImplIteratorAux<Config, i::Map> {
static bool matches(typename TypeImpl<Config>::TypeHandle type) {
return type->IsClass();
}
static i::Handle<i::Map> current(typename TypeImpl<Config>::TypeHandle type) {
return type->AsClass()->Map();
}
};
template<class Config>
struct TypeImplIteratorAux<Config, i::Object> {
static bool matches(typename TypeImpl<Config>::TypeHandle type) {
return type->IsConstant();
}
static i::Handle<i::Object> current(
typename TypeImpl<Config>::TypeHandle type) {
return type->AsConstant()->Value();
}
};
template<class Config> template<class T>
bool TypeImpl<Config>::Iterator<T>::matches(TypeHandle type) {
return TypeImplIteratorAux<Config, T>::matches(type);
}
template<class Config> template<class T>
i::Handle<T> TypeImpl<Config>::Iterator<T>::Current() {
return TypeImplIteratorAux<Config, T>::current(get_type());
}
template<class Config> template<class T>
void TypeImpl<Config>::Iterator<T>::Advance() {
DisallowHeapAllocation no_allocation;
++index_;
if (type_->IsUnion()) {
UnionHandle unioned = handle(type_->AsUnion());
for (; index_ < unioned->Length(); ++index_) {
if (matches(unioned->Get(index_))) return;
}
} else if (index_ == 0 && matches(type_)) {
return;
}
index_ = -1;
}
// -----------------------------------------------------------------------------
// Conversion between low-level representations.
template<class Config>
template<class OtherType>
typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Convert(
@ -643,9 +798,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->IsContext()) {
TypeHandle outer = Convert<OtherType>(type->AsContext()->Outer(), region);
return ContextType::New(outer, region);
@ -658,11 +817,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,
@ -676,16 +837,8 @@ typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Convert(
}
// TODO(rossberg): this does not belong here.
Representation Representation::FromType(Type* type) {
DisallowHeapAllocation no_allocation;
if (type->Is(Type::None())) return Representation::None();
if (type->Is(Type::SignedSmall())) return Representation::Smi();
if (type->Is(Type::Signed32())) return Representation::Integer32();
if (type->Is(Type::Number())) return Representation::Double();
return Representation::Tagged();
}
// -----------------------------------------------------------------------------
// Printing.
template<class Config>
const char* TypeImpl<Config>::BitsetType::Name(int bitset) {
@ -744,61 +897,59 @@ void TypeImpl<Config>::BitsetType::PrintTo(StringStream* stream, int bitset) {
template<class Config>
void TypeImpl<Config>::PrintTo(StringStream* stream, PrintDimension dim) {
DisallowHeapAllocation no_allocation;
if (this->IsBitset()) {
int bitset = this->AsBitset();
switch (dim) {
case BOTH_DIMS:
BitsetType::PrintTo(stream, SEMANTIC(bitset));
stream->Add("/");
BitsetType::PrintTo(stream, REPRESENTATION(bitset));
break;
case SEMANTIC_DIM:
BitsetType::PrintTo(stream, SEMANTIC(bitset));
break;
case REPRESENTATION_DIM:
BitsetType::PrintTo(stream, REPRESENTATION(bitset));
break;
if (dim != REPRESENTATION_DIM) {
if (this->IsBitset()) {
BitsetType::PrintTo(stream, SEMANTIC(this->AsBitset()));
} else if (this->IsClass()) {
stream->Add("Class(%p < ", static_cast<void*>(*this->AsClass()->Map()));
BitsetType::New(BitsetType::Lub(this))->PrintTo(stream, dim);
stream->Add(")");
return;
} else if (this->IsConstant()) {
stream->Add("Constant(%p : ",
static_cast<void*>(*this->AsConstant()->Value()));
BitsetType::New(BitsetType::Lub(this))->PrintTo(stream, dim);
stream->Add(")");
return;
} else if (this->IsContext()) {
stream->Add("Context(");
this->AsContext()->Outer()->PrintTo(stream, dim);
stream->Add(")");
} else if (this->IsUnion()) {
stream->Add("(");
UnionHandle unioned = handle(this->AsUnion());
for (int i = 0; i < unioned->Length(); ++i) {
TypeHandle type_i = unioned->Get(i);
if (i > 0) stream->Add(" | ");
type_i->PrintTo(stream, dim);
}
stream->Add(")");
return;
} else if (this->IsArray()) {
stream->Add("Array(");
AsArray()->Element()->PrintTo(stream, dim);
stream->Add(")");
} else if (this->IsFunction()) {
if (!this->AsFunction()->Receiver()->IsAny()) {
this->AsFunction()->Receiver()->PrintTo(stream, dim);
stream->Add(".");
}
stream->Add("(");
for (int i = 0; i < this->AsFunction()->Arity(); ++i) {
if (i > 0) stream->Add(", ");
this->AsFunction()->Parameter(i)->PrintTo(stream, dim);
}
stream->Add(")->");
this->AsFunction()->Result()->PrintTo(stream, dim);
} else {
UNREACHABLE();
}
} else if (this->IsConstant()) {
stream->Add("Constant(%p : ",
static_cast<void*>(*this->AsConstant()->Value()));
BitsetType::New(BitsetType::Lub(this))->PrintTo(stream, dim);
stream->Add(")");
} else if (this->IsClass()) {
stream->Add("Class(%p < ", static_cast<void*>(*this->AsClass()->Map()));
BitsetType::New(BitsetType::Lub(this))->PrintTo(stream, dim);
stream->Add(")");
} else if (this->IsContext()) {
stream->Add("Context(");
this->AsContext()->Outer()->PrintTo(stream, dim);
stream->Add(")");
} else if (this->IsUnion()) {
stream->Add("(");
UnionHandle unioned = handle(this->AsUnion());
for (int i = 0; i < unioned->Length(); ++i) {
TypeHandle type_i = unioned->Get(i);
if (i > 0) stream->Add(" | ");
type_i->PrintTo(stream, dim);
}
stream->Add(")");
} else if (this->IsArray()) {
stream->Add("[");
AsArray()->Element()->PrintTo(stream, dim);
stream->Add("]");
} else if (this->IsFunction()) {
if (!this->AsFunction()->Receiver()->IsAny()) {
this->AsFunction()->Receiver()->PrintTo(stream, dim);
stream->Add(".");
}
stream->Add("(");
for (int i = 0; i < this->AsFunction()->Arity(); ++i) {
if (i > 0) stream->Add(", ");
this->AsFunction()->Parameter(i)->PrintTo(stream, dim);
}
stream->Add(")->");
this->AsFunction()->Result()->PrintTo(stream, dim);
} else {
UNREACHABLE();
}
if (dim == BOTH_DIMS) {
stream->Add("/");
}
if (dim != SEMANTIC_DIM) {
BitsetType::PrintTo(stream, REPRESENTATION(this->BitsetLub()));
}
}
@ -820,6 +971,9 @@ void TypeImpl<Config>::TypePrint(PrintDimension dim) {
}
// -----------------------------------------------------------------------------
// Instantiations.
template class TypeImpl<ZoneTypeConfig>;
template class TypeImpl<ZoneTypeConfig>::Iterator<i::Map>;
template class TypeImpl<ZoneTypeConfig>::Iterator<i::Object>;

View File

@ -132,6 +132,9 @@ namespace internal {
// them. For zone types, no query method touches the heap, only constructors do.
// -----------------------------------------------------------------------------
// Values for bitset types
#define MASK_BITSET_TYPE_LIST(V) \
V(Representation, static_cast<int>(0xffc00000)) \
V(Semantic, static_cast<int>(0x003fffff))
@ -207,6 +210,9 @@ namespace internal {
SEMANTIC_BITSET_TYPE_LIST(V)
// -----------------------------------------------------------------------------
// The abstract Type class, parameterized over the low-level representation.
// struct Config {
// typedef TypeImpl<Config> Type;
// typedef Base;
@ -217,16 +223,13 @@ namespace internal {
// template<class T> static Handle<T>::type cast(Handle<Type>::type);
// static bool is_bitset(Type*);
// static bool is_class(Type*);
// static bool is_constant(Type*);
// static bool is_struct(Type*, int tag);
// static int as_bitset(Type*);
// static i::Handle<i::Map> as_class(Type*);
// static i::Handle<i::Object> as_constant(Type*);
// static Handle<Struct>::type as_struct(Type*);
// static Type* from_bitset(int bitset);
// static Handle<Type>::type from_bitset(int bitset, Region*);
// static Handle<Type>::type from_class(i::Handle<Map>, int lub, Region*);
// static Handle<Type>::type from_constant(i::Handle<Object>, int, Region*);
// static Handle<Type>::type from_class(i::Handle<Map>, Region*);
// static Handle<Type>::type from_struct(Handle<Struct>::type, int tag);
// static Handle<Struct>::type struct_create(int tag, int length, Region*);
// static void struct_shrink(Handle<Struct>::type, int length);
@ -234,11 +237,16 @@ namespace internal {
// static int struct_length(Handle<Struct>::type);
// static Handle<Type>::type struct_get(Handle<Struct>::type, int);
// static void struct_set(Handle<Struct>::type, int, Handle<Type>::type);
// static int lub_bitset(Type*);
// template<class V>
// static i::Handle<V> struct_get_value(Handle<Struct>::type, int);
// template<class V>
// static void struct_set_value(Handle<Struct>::type, int, i::Handle<V>);
// }
template<class Config>
class TypeImpl : public Config::Base {
public:
// Auxiliary types.
class BitsetType; // Internal
class StructuralType; // Internal
class UnionType; // Internal
@ -258,6 +266,8 @@ class TypeImpl : public Config::Base {
typedef typename Config::template Handle<UnionType>::type UnionHandle;
typedef typename Config::Region Region;
// Constructors.
#define DEFINE_TYPE_CONSTRUCTOR(type, value) \
static TypeImpl* type() { return BitsetType::New(BitsetType::k##type); } \
static TypeHandle type(Region* region) { \
@ -321,9 +331,9 @@ class TypeImpl : public Config::Base {
return Of(*value, region);
}
bool IsInhabited() {
return !this->IsBitset() || BitsetType::IsInhabited(this->AsBitset());
}
// Predicates.
bool IsInhabited() { return BitsetType::IsInhabited(this->BitsetLub()); }
bool Is(TypeImpl* that) { return this == that || this->SlowIs(that); }
template<class TypeHandle>
@ -341,9 +351,9 @@ class TypeImpl : public Config::Base {
bool Contains(i::Object* val);
bool Contains(i::Handle<i::Object> val) { return this->Contains(*val); }
// State-dependent versions of Of and Is that consider subtyping between
// State-dependent versions of the above that consider subtyping between
// a constant and its map class.
static TypeHandle NowOf(i::Object* value, Region* region);
inline static TypeHandle NowOf(i::Object* value, Region* region);
static TypeHandle NowOf(i::Handle<i::Object> value, Region* region) {
return NowOf(*value, region);
}
@ -355,12 +365,21 @@ class TypeImpl : public Config::Base {
bool NowStable();
bool IsClass() { return Config::is_class(this); }
bool IsConstant() { return Config::is_constant(this); }
// Inspection.
bool IsClass() {
return Config::is_class(this)
|| Config::is_struct(this, StructuralType::kClassTag);
}
bool IsConstant() {
return Config::is_struct(this, StructuralType::kConstantTag);
}
bool IsContext() {
return Config::is_struct(this, StructuralType::kContextTag);
}
bool IsArray() { return Config::is_struct(this, StructuralType::kArrayTag); }
bool IsArray() {
return Config::is_struct(this, StructuralType::kArrayTag);
}
bool IsFunction() {
return Config::is_struct(this, StructuralType::kFunctionTag);
}
@ -384,25 +403,37 @@ class TypeImpl : public Config::Base {
return Iterator<i::Object>(Config::handle(this));
}
// Casting and conversion.
static inline TypeImpl* cast(typename Config::Base* object);
template<class OtherTypeImpl>
static TypeHandle Convert(
typename OtherTypeImpl::TypeHandle type, Region* region);
// Printing.
enum PrintDimension { BOTH_DIMS, SEMANTIC_DIM, REPRESENTATION_DIM };
void PrintTo(StringStream* stream, PrintDimension = BOTH_DIMS);
void TypePrint(PrintDimension = BOTH_DIMS);
void TypePrint(FILE* out, PrintDimension = BOTH_DIMS);
protected:
// Friends.
template<class> friend class Iterator;
template<class> friend class TypeImpl;
// Handle conversion.
template<class T>
static typename Config::template Handle<T>::type handle(T* type) {
return Config::handle(type);
}
TypeImpl* unhandle() { return this; }
// Internal inspection.
bool IsNone() { return this == None(); }
bool IsAny() { return this == Any(); }
@ -415,19 +446,27 @@ class TypeImpl : public Config::Base {
}
UnionType* AsUnion() { return UnionType::cast(this); }
bool SlowIs(TypeImpl* that);
bool InUnion(UnionHandle unioned, int current_size);
static int ExtendUnion(
UnionHandle unioned, TypeHandle t, int current_size);
static int ExtendIntersection(
UnionHandle unioned, TypeHandle t, TypeHandle other, int current_size);
// Auxiliary functions.
int BitsetGlb() { return BitsetType::Glb(this); }
int BitsetLub() { return BitsetType::Lub(this); }
int InherentBitsetLub() { return BitsetType::InherentLub(this); }
bool SlowIs(TypeImpl* that);
TypeHandle Narrow(int bitset, Region* region);
int BoundBy(TypeImpl* that);
int IndexInUnion(int bound, UnionHandle unioned, int current_size);
static int ExtendUnion(
UnionHandle unioned, int current_size, TypeHandle t,
TypeHandle other, bool is_intersect, Region* region);
static int NormalizeUnion(UnionHandle unioned, int current_size, int bitset);
};
// -----------------------------------------------------------------------------
// Bitset types (internal).
template<class Config>
class TypeImpl<Config>::BitsetType : public TypeImpl<Config> {
private:
@ -442,7 +481,7 @@ class TypeImpl<Config>::BitsetType : public TypeImpl<Config> {
int Bitset() { return Config::as_bitset(this); }
static BitsetType* New(int bitset) {
static TypeImpl* New(int bitset) {
return static_cast<BitsetType*>(Config::from_bitset(bitset));
}
static TypeHandle New(int bitset, Region* region) {
@ -460,6 +499,7 @@ class TypeImpl<Config>::BitsetType : public TypeImpl<Config> {
static int Lub(int32_t value);
static int Lub(uint32_t value);
static int Lub(i::Map* map);
static int InherentLub(TypeImpl* type);
static const char* Name(int bitset);
static void PrintTo(StringStream* stream, int bitset);
@ -467,8 +507,10 @@ class TypeImpl<Config>::BitsetType : public TypeImpl<Config> {
};
// Internal
// A structured type contains a tag and a variable number of type fields.
// -----------------------------------------------------------------------------
// Superclass for non-bitset types (internal).
// Contains a tag and a variable number of type or value fields.
template<class Config>
class TypeImpl<Config>::StructuralType : public TypeImpl<Config> {
protected:
@ -489,79 +531,40 @@ class TypeImpl<Config>::StructuralType : public TypeImpl<Config> {
return Config::struct_length(Config::as_struct(this));
}
TypeHandle Get(int i) {
ASSERT(0 <= i && i < this->Length());
return Config::struct_get(Config::as_struct(this), i);
}
void Set(int i, TypeHandle type) {
ASSERT(0 <= i && i < this->Length());
Config::struct_set(Config::as_struct(this), i, type);
}
void Shrink(int length) {
ASSERT(2 <= length && length <= this->Length());
Config::struct_shrink(Config::as_struct(this), length);
}
template<class V> i::Handle<V> GetValue(int i) {
ASSERT(0 <= i && i < this->Length());
return Config::template struct_get_value<V>(Config::as_struct(this), i);
}
template<class V> void SetValue(int i, i::Handle<V> x) {
ASSERT(0 <= i && i < this->Length());
Config::struct_set_value(Config::as_struct(this), i, x);
}
static TypeHandle New(Tag tag, int length, Region* region) {
ASSERT(1 <= length);
return Config::from_struct(Config::struct_create(tag, length, region));
}
};
template<class Config>
class TypeImpl<Config>::ClassType : public TypeImpl<Config> {
public:
i::Handle<i::Map> Map() { return Config::as_class(this); }
static ClassHandle New(i::Handle<i::Map> map, Region* region) {
return Config::template cast<ClassType>(
Config::from_class(map, BitsetType::Lub(*map), region));
}
static ClassType* cast(TypeImpl* type) {
ASSERT(type->IsClass());
return static_cast<ClassType*>(type);
}
};
template<class Config>
class TypeImpl<Config>::ConstantType : public TypeImpl<Config> {
public:
i::Handle<i::Object> Value() { return Config::as_constant(this); }
static ConstantHandle New(i::Handle<i::Object> value, Region* region) {
return Config::template cast<ConstantType>(
Config::from_constant(value, BitsetType::Lub(*value), region));
}
static ConstantType* cast(TypeImpl* type) {
ASSERT(type->IsConstant());
return static_cast<ConstantType*>(type);
}
};
template<class Config>
class TypeImpl<Config>::ContextType : public StructuralType {
public:
TypeHandle Outer() { return this->Get(0); }
static ContextHandle New(TypeHandle outer, Region* region) {
ContextHandle type = Config::template cast<ContextType>(
StructuralType::New(StructuralType::kContextTag, 1, region));
type->Set(0, outer);
return type;
}
static ContextType* cast(TypeImpl* type) {
ASSERT(type->IsContext());
return static_cast<ContextType*>(type);
}
};
// Internal
// -----------------------------------------------------------------------------
// Union types (internal).
// A union is a structured type with the following invariants:
// - its length is at least 2
// - at most one field is a bitset, and it must go into index 0
// - no field is a union
// - no field is a subtype of any other field
template<class Config>
class TypeImpl<Config>::UnionType : public StructuralType {
public:
@ -574,19 +577,136 @@ class TypeImpl<Config>::UnionType : public StructuralType {
ASSERT(type->IsUnion());
return static_cast<UnionType*>(type);
}
bool Wellformed();
};
// -----------------------------------------------------------------------------
// Class types.
template<class Config>
class TypeImpl<Config>::ClassType : public StructuralType {
public:
TypeHandle Bound(Region* region) {
return Config::is_class(this)
? BitsetType::New(BitsetType::Lub(*Config::as_class(this)), region)
: this->Get(0);
}
i::Handle<i::Map> Map() {
return Config::is_class(this)
? Config::as_class(this)
: this->template GetValue<i::Map>(1);
}
static ClassHandle New(
i::Handle<i::Map> map, TypeHandle bound, Region* region) {
ClassHandle type = Config::template cast<ClassType>(
StructuralType::New(StructuralType::kClassTag, 2, region));
type->Set(0, bound);
type->SetValue(1, map);
return type;
}
static ClassHandle New(i::Handle<i::Map> map, Region* region) {
ClassHandle type =
Config::template cast<ClassType>(Config::from_class(map, region));
if (type->IsClass()) {
return type;
} else {
TypeHandle bound = BitsetType::New(BitsetType::Lub(*map), region);
return New(map, bound, region);
}
}
static ClassType* cast(TypeImpl* type) {
ASSERT(type->IsClass());
return static_cast<ClassType*>(type);
}
};
// -----------------------------------------------------------------------------
// Constant types.
template<class Config>
class TypeImpl<Config>::ConstantType : public StructuralType {
public:
TypeHandle Bound() { return this->Get(0); }
i::Handle<i::Object> Value() { return this->template GetValue<i::Object>(1); }
static ConstantHandle New(
i::Handle<i::Object> value, TypeHandle bound, Region* region) {
ConstantHandle type = Config::template cast<ConstantType>(
StructuralType::New(StructuralType::kConstantTag, 2, region));
type->Set(0, bound);
type->SetValue(1, value);
return type;
}
static ConstantHandle New(i::Handle<i::Object> value, Region* region) {
TypeHandle bound = BitsetType::New(BitsetType::Lub(*value), region);
return New(value, bound, region);
}
static ConstantType* cast(TypeImpl* type) {
ASSERT(type->IsConstant());
return static_cast<ConstantType*>(type);
}
};
// -----------------------------------------------------------------------------
// Context types.
template<class Config>
class TypeImpl<Config>::ContextType : public StructuralType {
public:
TypeHandle Bound() { return this->Get(0); }
TypeHandle Outer() { return this->Get(1); }
static ContextHandle New(TypeHandle outer, TypeHandle bound, Region* region) {
ContextHandle type = Config::template cast<ContextType>(
StructuralType::New(StructuralType::kContextTag, 2, region));
type->Set(0, bound);
type->Set(1, outer);
return type;
}
static ContextHandle New(TypeHandle outer, Region* region) {
TypeHandle bound = BitsetType::New(
BitsetType::kInternal & BitsetType::kTaggedPtr, region);
return New(outer, bound, region);
}
static ContextType* cast(TypeImpl* type) {
ASSERT(type->IsContext());
return static_cast<ContextType*>(type);
}
};
// -----------------------------------------------------------------------------
// Array types.
template<class Config>
class TypeImpl<Config>::ArrayType : public StructuralType {
public:
TypeHandle Element() { return this->Get(0); }
TypeHandle Bound() { return this->Get(0); }
TypeHandle Element() { return this->Get(1); }
static ArrayHandle New(TypeHandle element, TypeHandle bound, Region* region) {
ASSERT(SEMANTIC(bound->AsBitset()) == SEMANTIC(BitsetType::kArray));
ArrayHandle type = Config::template cast<ArrayType>(
StructuralType::New(StructuralType::kArrayTag, 2, region));
type->Set(0, bound);
type->Set(1, element);
return type;
}
static ArrayHandle New(TypeHandle element, Region* region) {
ArrayHandle type = Config::template cast<ArrayType>(
StructuralType::New(StructuralType::kArrayTag, 1, region));
type->Set(0, element);
return type;
TypeHandle bound = BitsetType::New(BitsetType::kArray, region);
return New(element, bound, region);
}
static ArrayType* cast(TypeImpl* type) {
@ -596,23 +716,36 @@ class TypeImpl<Config>::ArrayType : public StructuralType {
};
// -----------------------------------------------------------------------------
// Function types.
template<class Config>
class TypeImpl<Config>::FunctionType : public StructuralType {
public:
int Arity() { return this->Length() - 2; }
TypeHandle Result() { return this->Get(0); }
TypeHandle Receiver() { return this->Get(1); }
TypeHandle Parameter(int i) { return this->Get(2 + i); }
int Arity() { return this->Length() - 3; }
TypeHandle Bound() { return this->Get(0); }
TypeHandle Result() { return this->Get(1); }
TypeHandle Receiver() { return this->Get(2); }
TypeHandle Parameter(int i) { return this->Get(3 + i); }
void InitParameter(int i, TypeHandle type) { this->Set(2 + i, type); }
void InitParameter(int i, TypeHandle type) { this->Set(3 + i, type); }
static FunctionHandle New(
TypeHandle result, TypeHandle receiver, TypeHandle bound,
int arity, Region* region) {
ASSERT(SEMANTIC(bound->AsBitset()) == SEMANTIC(BitsetType::kFunction));
FunctionHandle type = Config::template cast<FunctionType>(
StructuralType::New(StructuralType::kFunctionTag, 3 + arity, region));
type->Set(0, bound);
type->Set(1, result);
type->Set(2, receiver);
return type;
}
static FunctionHandle New(
TypeHandle result, TypeHandle receiver, int arity, Region* region) {
FunctionHandle type = Config::template cast<FunctionType>(
StructuralType::New(StructuralType::kFunctionTag, 2 + arity, region));
type->Set(0, result);
type->Set(1, receiver);
return type;
TypeHandle bound = BitsetType::New(BitsetType::kFunction, region);
return New(result, receiver, bound, arity, region);
}
static FunctionType* cast(TypeImpl* type) {
@ -622,6 +755,9 @@ class TypeImpl<Config>::FunctionType : public StructuralType {
};
// -----------------------------------------------------------------------------
// Type iterators.
template<class Config> template<class T>
class TypeImpl<Config>::Iterator {
public:
@ -645,8 +781,10 @@ class TypeImpl<Config>::Iterator {
};
// Zone-allocated types are either (odd) integers to represent bitsets, or
// -----------------------------------------------------------------------------
// Zone-allocated types; they are either (odd) integers to represent bitsets, or
// (even) pointers to structures for everything else.
struct ZoneTypeConfig {
typedef TypeImpl<ZoneTypeConfig> Type;
class Base {};
@ -659,36 +797,36 @@ struct ZoneTypeConfig {
static inline bool is_bitset(Type* type);
static inline bool is_class(Type* type);
static inline bool is_constant(Type* type);
static inline bool is_struct(Type* type, int tag);
static inline int as_bitset(Type* type);
static inline Struct* as_struct(Type* type);
static inline i::Handle<i::Map> as_class(Type* type);
static inline i::Handle<i::Object> as_constant(Type* type);
static inline Struct* as_struct(Type* type);
static inline Type* from_bitset(int bitset);
static inline Type* from_bitset(int bitset, Zone* zone);
static inline Type* from_class(i::Handle<i::Map> map, Zone* zone);
static inline Type* from_struct(Struct* structured);
static inline Type* from_class(i::Handle<i::Map> map, int lub, Zone* zone);
static inline Type* from_constant(
i::Handle<i::Object> value, int lub, Zone* zone);
static inline Struct* struct_create(int tag, int length, Zone* zone);
static inline void struct_shrink(Struct* structured, int length);
static inline int struct_tag(Struct* structured);
static inline int struct_length(Struct* structured);
static inline Type* struct_get(Struct* structured, int i);
static inline void struct_set(Struct* structured, int i, Type* type);
static inline int lub_bitset(Type* type);
static inline void struct_shrink(Struct* structure, int length);
static inline int struct_tag(Struct* structure);
static inline int struct_length(Struct* structure);
static inline Type* struct_get(Struct* structure, int i);
static inline void struct_set(Struct* structure, int i, Type* type);
template<class V>
static inline i::Handle<V> struct_get_value(Struct* structure, int i);
template<class V> static inline void struct_set_value(
Struct* structure, int i, i::Handle<V> x);
};
typedef TypeImpl<ZoneTypeConfig> Type;
// Heap-allocated types are either smis for bitsets, maps for classes, boxes for
// -----------------------------------------------------------------------------
// Heap-allocated types; either smis for bitsets, maps for classes, boxes for
// constants, or fixed arrays for unions.
struct HeapTypeConfig {
typedef TypeImpl<HeapTypeConfig> Type;
typedef i::Object Base;
@ -701,38 +839,40 @@ struct HeapTypeConfig {
static inline bool is_bitset(Type* type);
static inline bool is_class(Type* type);
static inline bool is_constant(Type* type);
static inline bool is_struct(Type* type, int tag);
static inline int as_bitset(Type* type);
static inline i::Handle<i::Map> as_class(Type* type);
static inline i::Handle<i::Object> as_constant(Type* type);
static inline i::Handle<Struct> as_struct(Type* type);
static inline Type* from_bitset(int bitset);
static inline i::Handle<Type> from_bitset(int bitset, Isolate* isolate);
static inline i::Handle<Type> from_class(
i::Handle<i::Map> map, int lub, Isolate* isolate);
static inline i::Handle<Type> from_constant(
i::Handle<i::Object> value, int lub, Isolate* isolate);
static inline i::Handle<Type> from_struct(i::Handle<Struct> structured);
i::Handle<i::Map> map, Isolate* isolate);
static inline i::Handle<Type> from_struct(i::Handle<Struct> structure);
static inline i::Handle<Struct> struct_create(
int tag, int length, Isolate* isolate);
static inline void struct_shrink(i::Handle<Struct> structured, int length);
static inline int struct_tag(i::Handle<Struct> structured);
static inline int struct_length(i::Handle<Struct> structured);
static inline i::Handle<Type> struct_get(i::Handle<Struct> structured, int i);
static inline void struct_shrink(i::Handle<Struct> structure, int length);
static inline int struct_tag(i::Handle<Struct> structure);
static inline int struct_length(i::Handle<Struct> structure);
static inline i::Handle<Type> struct_get(i::Handle<Struct> structure, int i);
static inline void struct_set(
i::Handle<Struct> structured, int i, i::Handle<Type> type);
static inline int lub_bitset(Type* type);
i::Handle<Struct> structure, int i, i::Handle<Type> type);
template<class V>
static inline i::Handle<V> struct_get_value(
i::Handle<Struct> structure, int i);
template<class V>
static inline void struct_set_value(
i::Handle<Struct> structure, int i, i::Handle<V> x);
};
typedef TypeImpl<HeapTypeConfig> HeapType;
// A simple struct to represent a pair of lower/upper type bounds.
// -----------------------------------------------------------------------------
// Type bounds. A simple struct to represent a pair of lower/upper types.
template<class Config>
struct BoundsImpl {
typedef TypeImpl<Config> Type;

View File

@ -27,8 +27,13 @@
#include <vector>
#include "cctest.h"
#define private public /* To test private methods :) */
#define protected public
#include "types.h"
#undef private
#undef protected
#include "cctest.h"
#include "utils/random-number-generator.h"
using namespace v8::internal;
@ -81,8 +86,10 @@ struct HeapRep {
return t->IsFixedArray() && Smi::cast(AsStruct(t)->get(0))->value() == tag;
}
static bool IsBitset(Handle<HeapType> t) { return t->IsSmi(); }
static bool IsClass(Handle<HeapType> t) { return t->IsMap(); }
static bool IsConstant(Handle<HeapType> t) { return t->IsBox(); }
static bool IsClass(Handle<HeapType> t) {
return t->IsMap() || IsStruct(t, 0);
}
static bool IsConstant(Handle<HeapType> t) { return IsStruct(t, 1); }
static bool IsContext(Handle<HeapType> t) { return IsStruct(t, 2); }
static bool IsArray(Handle<HeapType> t) { return IsStruct(t, 3); }
static bool IsFunction(Handle<HeapType> t) { return IsStruct(t, 4); }
@ -90,10 +97,10 @@ struct HeapRep {
static Struct* AsStruct(Handle<HeapType> t) { return FixedArray::cast(*t); }
static int AsBitset(Handle<HeapType> t) { return Smi::cast(*t)->value(); }
static Map* AsClass(Handle<HeapType> t) { return Map::cast(*t); }
static Object* AsConstant(Handle<HeapType> t) {
return Box::cast(*t)->value();
static Map* AsClass(Handle<HeapType> t) {
return t->IsMap() ? Map::cast(*t) : Map::cast(AsStruct(t)->get(2));
}
static Object* AsConstant(Handle<HeapType> t) { return AsStruct(t)->get(2); }
static HeapType* AsContext(Handle<HeapType> t) {
return HeapType::cast(AsStruct(t)->get(1));
}
@ -315,6 +322,8 @@ class Types {
UNREACHABLE();
}
Region* region() { return region_; }
private:
Region* region_;
RandomNumberGenerator rng_;
@ -347,6 +356,8 @@ struct Tests : Rep {
Rep::IsClass(type1) == Rep::IsClass(type2) &&
Rep::IsConstant(type1) == Rep::IsConstant(type2) &&
Rep::IsContext(type1) == Rep::IsContext(type2) &&
Rep::IsArray(type1) == Rep::IsArray(type2) &&
Rep::IsFunction(type1) == Rep::IsFunction(type2) &&
Rep::IsUnion(type1) == Rep::IsUnion(type2) &&
type1->NumClasses() == type2->NumClasses() &&
type1->NumConstants() == type2->NumConstants() &&
@ -356,7 +367,8 @@ struct Tests : Rep {
Rep::AsClass(type1) == Rep::AsClass(type2)) &&
(!Rep::IsConstant(type1) ||
Rep::AsConstant(type1) == Rep::AsConstant(type2)) &&
(!Rep::IsUnion(type1) ||
// TODO(rossberg): Check details of arrays, functions, bounds.
(!Rep::IsUnion(type1) ||
Rep::Length(Rep::AsUnion(type1)) == Rep::Length(Rep::AsUnion(type2)));
}
@ -723,6 +735,39 @@ struct Tests : Rep {
}
}
void Bounds() {
// Ordering: (T->BitsetGlb())->Is(T->BitsetLub())
for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
TypeHandle type = *it;
TypeHandle glb = Type::BitsetType::New(type->BitsetGlb(), T.region());
TypeHandle lub = Type::BitsetType::New(type->BitsetLub(), T.region());
CHECK(glb->Is(lub));
}
// Lower bound: (T->BitsetGlb())->Is(T)
for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
TypeHandle type = *it;
TypeHandle glb = Type::BitsetType::New(type->BitsetGlb(), T.region());
CHECK(glb->Is(type));
}
// Upper bound: T->Is(T->BitsetLub())
for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
TypeHandle type = *it;
TypeHandle lub = Type::BitsetType::New(type->BitsetLub(), T.region());
CHECK(type->Is(lub));
}
// Inherent bound: (T->BitsetLub())->Is(T->InherentBitsetLub())
for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
TypeHandle type = *it;
TypeHandle lub = Type::BitsetType::New(type->BitsetLub(), T.region());
TypeHandle inherent =
Type::BitsetType::New(type->InherentBitsetLub(), T.region());
CHECK(lub->Is(inherent));
}
}
void Is() {
// Least Element (Bottom): None->Is(T)
for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
@ -1583,13 +1628,13 @@ struct Tests : Rep {
CheckEqual(
T.Intersect(T.Object, T.Union(T.ObjectConstant1, T.ObjectClass)),
T.Union(T.ObjectConstant1, T.ObjectClass));
CheckEqual(
T.Intersect(T.Union(T.ArrayClass, T.ObjectConstant1), T.Number),
T.None);
CHECK(
!T.Intersect(T.Union(T.ArrayClass, T.ObjectConstant1), T.Number)
->IsInhabited());
// Class-constant
CheckEqual(T.Intersect(T.ObjectConstant1, T.ObjectClass), T.None);
CheckEqual(T.Intersect(T.ArrayClass, T.ObjectConstant2), T.None);
CHECK(!T.Intersect(T.ObjectConstant1, T.ObjectClass)->IsInhabited());
CHECK(!T.Intersect(T.ArrayClass, T.ObjectConstant2)->IsInhabited());
// Array-union
CheckEqual(
@ -1598,9 +1643,9 @@ struct Tests : Rep {
CheckEqual(
T.Intersect(T.AnyArray, T.Union(T.Object, T.SmiConstant)),
T.AnyArray);
CheckEqual(
T.Intersect(T.Union(T.AnyArray, T.ArrayConstant), T.NumberArray),
T.None);
CHECK(
!T.Intersect(T.Union(T.AnyArray, T.ArrayConstant), T.NumberArray)
->IsInhabited());
// Function-union
CheckEqual(
@ -1609,9 +1654,9 @@ struct Tests : Rep {
CheckEqual(
T.Intersect(T.NumberFunction1, T.Union(T.Object, T.SmiConstant)),
T.NumberFunction1);
CheckEqual(
T.Intersect(T.Union(T.MethodFunction, T.Name), T.NumberFunction2),
T.None);
CHECK(
!T.Intersect(T.Union(T.MethodFunction, T.Name), T.NumberFunction2)
->IsInhabited());
// Class-union
CheckEqual(
@ -1620,9 +1665,9 @@ struct Tests : Rep {
CheckEqual(
T.Intersect(T.ArrayClass, T.Union(T.Object, T.SmiConstant)),
T.ArrayClass);
CheckEqual(
T.Intersect(T.Union(T.ObjectClass, T.ArrayConstant), T.ArrayClass),
T.None);
CHECK(
!T.Intersect(T.Union(T.ObjectClass, T.ArrayConstant), T.ArrayClass)
->IsInhabited());
// Constant-union
CheckEqual(
@ -1632,10 +1677,10 @@ struct Tests : Rep {
CheckEqual(
T.Intersect(T.SmiConstant, T.Union(T.Number, T.ObjectConstant2)),
T.SmiConstant);
CheckEqual(
T.Intersect(
T.Union(T.ArrayConstant, T.ObjectClass), T.ObjectConstant1),
T.None);
CHECK(
!T.Intersect(
T.Union(T.ArrayConstant, T.ObjectClass), T.ObjectConstant1)
->IsInhabited());
// Union-union
CheckEqual(
@ -1663,6 +1708,44 @@ struct Tests : Rep {
T.Union(T.ObjectConstant2, T.ObjectConstant1));
}
void Distributivity() {
// Distributivity:
// Union(T1, Intersect(T2, T3)) = Intersect(Union(T1, T2), Union(T1, T3))
for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
for (TypeIterator it3 = T.types.begin(); it3 != T.types.end(); ++it3) {
TypeHandle type1 = *it1;
TypeHandle type2 = *it2;
TypeHandle type3 = *it3;
TypeHandle union12 = T.Union(type1, type2);
TypeHandle union13 = T.Union(type1, type3);
TypeHandle intersect23 = T.Intersect(type2, type3);
TypeHandle union1_23 = T.Union(type1, intersect23);
TypeHandle intersect12_13 = T.Intersect(union12, union13);
CHECK(Equal(union1_23, intersect12_13));
}
}
}
// Distributivity:
// Intersect(T1, Union(T2, T3)) = Union(Intersect(T1, T2), Intersect(T1,T3))
for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
for (TypeIterator it3 = T.types.begin(); it3 != T.types.end(); ++it3) {
TypeHandle type1 = *it1;
TypeHandle type2 = *it2;
TypeHandle type3 = *it3;
TypeHandle intersect12 = T.Intersect(type1, type2);
TypeHandle intersect13 = T.Intersect(type1, type3);
TypeHandle union23 = T.Union(type2, type3);
TypeHandle intersect1_23 = T.Intersect(type1, union23);
TypeHandle union12_13 = T.Union(intersect12, intersect13);
CHECK(Equal(intersect1_23, union12_13));
}
}
}
}
template<class Type2, class TypeHandle2, class Region2, class Rep2>
void Convert() {
Types<Type2, TypeHandle2, Region2> T2(
@ -1729,6 +1812,13 @@ TEST(NowOf) {
}
TEST(Bounds) {
CcTest::InitializeVM();
ZoneTests().Bounds();
HeapTests().Bounds();
}
TEST(Is) {
CcTest::InitializeVM();
ZoneTests().Is();
@ -1792,6 +1882,13 @@ TEST(Intersect2) {
}
TEST(Distributivity) {
CcTest::InitializeVM();
ZoneTests().Distributivity();
HeapTests().Distributivity();
}
TEST(Convert) {
CcTest::InitializeVM();
ZoneTests().Convert<HeapType, Handle<HeapType>, Isolate, HeapRep>();