Commit 7ac892c8 authored by rossberg@chromium.org's avatar rossberg@chromium.org

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
parent 276adeda
......@@ -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_
......@@ -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);
i::Handle<i::Map> map, Zone* zone) {
return from_bitset(0);
}
// 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);
ZoneTypeConfig::Struct* ZoneTypeConfig::struct_create(
int tag, int length, Zone* zone) {
Struct* structure = reinterpret_cast<Struct*>(
zone->New(sizeof(void*) * (length + 2))); // NOLINT
structure[0] = reinterpret_cast<void*>(tag);
structure[1] = reinterpret_cast<void*>(length);
return structure;
}
// static
ZoneTypeConfig::Struct* ZoneTypeConfig::struct_create(
int tag, int length, Zone* zone) {
Struct* structured = reinterpret_cast<Struct*>(
zone->New(sizeof(void*) * (length + 2))); // NOLINT
structured[0] = reinterpret_cast<void*>(tag);
structured[1] = reinterpret_cast<void*>(length);
return structured;
void ZoneTypeConfig::struct_shrink(Struct* structure, int length) {
ASSERT(0 <= length && length <= struct_length(structure));
structure[1] = reinterpret_cast<void*>(length);
}
// static
void ZoneTypeConfig::struct_shrink(Struct* structured, int length) {
ASSERT(0 <= length && length <= struct_length(structured));
structured[1] = reinterpret_cast<void*>(length);
int ZoneTypeConfig::struct_tag(Struct* structure) {
return static_cast<int>(reinterpret_cast<intptr_t>(structure[0]));
}
// static
int ZoneTypeConfig::struct_tag(Struct* structured) {
return static_cast<int>(reinterpret_cast<intptr_t>(structured[0]));
int ZoneTypeConfig::struct_length(Struct* structure) {
return static_cast<int>(reinterpret_cast<intptr_t>(structure[1]));
}
// static
int ZoneTypeConfig::struct_length(Struct* structured) {
return static_cast<int>(reinterpret_cast<intptr_t>(structured[1]));
Type* ZoneTypeConfig::struct_get(Struct* structure, int i) {
ASSERT(0 <= i && i <= struct_length(structure));
return static_cast<Type*>(structure[2 + i]);
}
// static
Type* ZoneTypeConfig::struct_get(Struct* structured, int i) {
ASSERT(0 <= i && i <= struct_length(structured));
return static_cast<Type*>(structured[2 + i]);
void ZoneTypeConfig::struct_set(Struct* structure, int i, Type* x) {
ASSERT(0 <= i && i <= struct_length(structure));
structure[2 + i] = x;
}
// static
void ZoneTypeConfig::struct_set(Struct* structured, int i, Type* type) {
ASSERT(0 <= i && i <= struct_length(structured));
structured[2 + i] = type;
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
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>
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
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
int HeapTypeConfig::lub_bitset(Type* type) {
return 0; // kNone, which causes recomputation.
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
......
This diff is collapsed.
This diff is collapsed.
......@@ -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>();
......
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