[turbofan] Remove the representation dimension from Type.
Adding this back in because it's not part of the stability issue. BUG=chromium:649967 TBR=jarin@chromium.org Review-Url: https://codereview.chromium.org/2365373004 Cr-Commit-Position: refs/heads/master@{#39761}
This commit is contained in:
parent
8fea775784
commit
c9cc3d164d
@ -196,7 +196,7 @@ Node* RepresentationChanger::GetTaggedSignedRepresentationFor(
|
|||||||
}
|
}
|
||||||
// Select the correct X -> Tagged operator.
|
// Select the correct X -> Tagged operator.
|
||||||
const Operator* op;
|
const Operator* op;
|
||||||
if (Type::Semantic(output_type, jsgraph()->zone())->Is(Type::None())) {
|
if (output_type->Is(Type::None())) {
|
||||||
// This is an impossible value; it should not be used at runtime.
|
// This is an impossible value; it should not be used at runtime.
|
||||||
// We just provide a dummy value here.
|
// We just provide a dummy value here.
|
||||||
return jsgraph()->Constant(0);
|
return jsgraph()->Constant(0);
|
||||||
@ -293,7 +293,7 @@ Node* RepresentationChanger::GetTaggedPointerRepresentationFor(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Select the correct X -> Tagged operator.
|
// Select the correct X -> Tagged operator.
|
||||||
if (Type::Semantic(output_type, jsgraph()->zone())->Is(Type::None())) {
|
if (output_type->Is(Type::None())) {
|
||||||
// This is an impossible value; it should not be used at runtime.
|
// This is an impossible value; it should not be used at runtime.
|
||||||
// We just provide a dummy value here.
|
// We just provide a dummy value here.
|
||||||
return jsgraph()->TheHoleConstant();
|
return jsgraph()->TheHoleConstant();
|
||||||
@ -338,7 +338,7 @@ Node* RepresentationChanger::GetTaggedRepresentationFor(
|
|||||||
}
|
}
|
||||||
// Select the correct X -> Tagged operator.
|
// Select the correct X -> Tagged operator.
|
||||||
const Operator* op;
|
const Operator* op;
|
||||||
if (Type::Semantic(output_type, jsgraph()->zone())->Is(Type::None())) {
|
if (output_type->Is(Type::None())) {
|
||||||
// This is an impossible value; it should not be used at runtime.
|
// This is an impossible value; it should not be used at runtime.
|
||||||
// We just provide a dummy value here.
|
// We just provide a dummy value here.
|
||||||
return jsgraph()->TheHoleConstant();
|
return jsgraph()->TheHoleConstant();
|
||||||
@ -420,7 +420,7 @@ Node* RepresentationChanger::GetFloat32RepresentationFor(
|
|||||||
}
|
}
|
||||||
// Select the correct X -> Float32 operator.
|
// Select the correct X -> Float32 operator.
|
||||||
const Operator* op = nullptr;
|
const Operator* op = nullptr;
|
||||||
if (Type::Semantic(output_type, jsgraph()->zone())->Is(Type::None())) {
|
if (output_type->Is(Type::None())) {
|
||||||
// This is an impossible value; it should not be used at runtime.
|
// This is an impossible value; it should not be used at runtime.
|
||||||
// We just provide a dummy value here.
|
// We just provide a dummy value here.
|
||||||
return jsgraph()->Float32Constant(0.0f);
|
return jsgraph()->Float32Constant(0.0f);
|
||||||
@ -490,7 +490,7 @@ Node* RepresentationChanger::GetFloat64RepresentationFor(
|
|||||||
}
|
}
|
||||||
// Select the correct X -> Float64 operator.
|
// Select the correct X -> Float64 operator.
|
||||||
const Operator* op = nullptr;
|
const Operator* op = nullptr;
|
||||||
if (Type::Semantic(output_type, jsgraph()->zone())->Is(Type::None())) {
|
if (output_type->Is(Type::None())) {
|
||||||
// This is an impossible value; it should not be used at runtime.
|
// This is an impossible value; it should not be used at runtime.
|
||||||
// We just provide a dummy value here.
|
// We just provide a dummy value here.
|
||||||
return jsgraph()->Float64Constant(0.0);
|
return jsgraph()->Float64Constant(0.0);
|
||||||
@ -576,7 +576,7 @@ Node* RepresentationChanger::GetWord32RepresentationFor(
|
|||||||
|
|
||||||
// Select the correct X -> Word32 operator.
|
// Select the correct X -> Word32 operator.
|
||||||
const Operator* op = nullptr;
|
const Operator* op = nullptr;
|
||||||
if (Type::Semantic(output_type, jsgraph()->zone())->Is(Type::None())) {
|
if (output_type->Is(Type::None())) {
|
||||||
// This is an impossible value; it should not be used at runtime.
|
// This is an impossible value; it should not be used at runtime.
|
||||||
// We just provide a dummy value here.
|
// We just provide a dummy value here.
|
||||||
return jsgraph()->Int32Constant(0);
|
return jsgraph()->Int32Constant(0);
|
||||||
@ -698,7 +698,7 @@ Node* RepresentationChanger::GetBitRepresentationFor(
|
|||||||
}
|
}
|
||||||
// Select the correct X -> Bit operator.
|
// Select the correct X -> Bit operator.
|
||||||
const Operator* op;
|
const Operator* op;
|
||||||
if (Type::Semantic(output_type, jsgraph()->zone())->Is(Type::None())) {
|
if (output_type->Is(Type::None())) {
|
||||||
// This is an impossible value; it should not be used at runtime.
|
// This is an impossible value; it should not be used at runtime.
|
||||||
// We just provide a dummy value here.
|
// We just provide a dummy value here.
|
||||||
return jsgraph()->Int32Constant(0);
|
return jsgraph()->Int32Constant(0);
|
||||||
@ -737,7 +737,7 @@ Node* RepresentationChanger::GetBitRepresentationFor(
|
|||||||
|
|
||||||
Node* RepresentationChanger::GetWord64RepresentationFor(
|
Node* RepresentationChanger::GetWord64RepresentationFor(
|
||||||
Node* node, MachineRepresentation output_rep, Type* output_type) {
|
Node* node, MachineRepresentation output_rep, Type* output_type) {
|
||||||
if (Type::Semantic(output_type, jsgraph()->zone())->Is(Type::None())) {
|
if (output_type->Is(Type::None())) {
|
||||||
// This is an impossible value; it should not be used at runtime.
|
// This is an impossible value; it should not be used at runtime.
|
||||||
// We just provide a dummy value here.
|
// We just provide a dummy value here.
|
||||||
return jsgraph()->Int64Constant(0);
|
return jsgraph()->Int64Constant(0);
|
||||||
@ -958,7 +958,7 @@ Node* RepresentationChanger::TypeError(Node* node,
|
|||||||
if (!testing_type_errors_) {
|
if (!testing_type_errors_) {
|
||||||
std::ostringstream out_str;
|
std::ostringstream out_str;
|
||||||
out_str << output_rep << " (";
|
out_str << output_rep << " (";
|
||||||
output_type->PrintTo(out_str, Type::SEMANTIC_DIM);
|
output_type->PrintTo(out_str);
|
||||||
out_str << ")";
|
out_str << ")";
|
||||||
|
|
||||||
std::ostringstream use_str;
|
std::ostringstream use_str;
|
||||||
|
@ -72,7 +72,7 @@ bool Type::Contains(RangeType* range, i::Object* val) {
|
|||||||
// Min and Max computation.
|
// Min and Max computation.
|
||||||
|
|
||||||
double Type::Min() {
|
double Type::Min() {
|
||||||
DCHECK(this->SemanticIs(Number()));
|
DCHECK(this->Is(Number()));
|
||||||
if (this->IsBitset()) return BitsetType::Min(this->AsBitset());
|
if (this->IsBitset()) return BitsetType::Min(this->AsBitset());
|
||||||
if (this->IsUnion()) {
|
if (this->IsUnion()) {
|
||||||
double min = +V8_INFINITY;
|
double min = +V8_INFINITY;
|
||||||
@ -88,7 +88,7 @@ double Type::Min() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
double Type::Max() {
|
double Type::Max() {
|
||||||
DCHECK(this->SemanticIs(Number()));
|
DCHECK(this->Is(Number()));
|
||||||
if (this->IsBitset()) return BitsetType::Max(this->AsBitset());
|
if (this->IsBitset()) return BitsetType::Max(this->AsBitset());
|
||||||
if (this->IsUnion()) {
|
if (this->IsUnion()) {
|
||||||
double max = -V8_INFINITY;
|
double max = -V8_INFINITY;
|
||||||
@ -115,13 +115,13 @@ Type::bitset BitsetType::Glb(Type* type) {
|
|||||||
} else if (type->IsUnion()) {
|
} else if (type->IsUnion()) {
|
||||||
SLOW_DCHECK(type->AsUnion()->Wellformed());
|
SLOW_DCHECK(type->AsUnion()->Wellformed());
|
||||||
return type->AsUnion()->Get(0)->BitsetGlb() |
|
return type->AsUnion()->Get(0)->BitsetGlb() |
|
||||||
SEMANTIC(type->AsUnion()->Get(1)->BitsetGlb()); // Shortcut.
|
type->AsUnion()->Get(1)->BitsetGlb(); // Shortcut.
|
||||||
} else if (type->IsRange()) {
|
} else if (type->IsRange()) {
|
||||||
bitset glb = SEMANTIC(
|
bitset glb =
|
||||||
BitsetType::Glb(type->AsRange()->Min(), type->AsRange()->Max()));
|
BitsetType::Glb(type->AsRange()->Min(), type->AsRange()->Max());
|
||||||
return glb | REPRESENTATION(type->BitsetLub());
|
return glb;
|
||||||
} else {
|
} else {
|
||||||
return type->Representation();
|
return kNone;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,7 +135,7 @@ Type::bitset BitsetType::Lub(Type* type) {
|
|||||||
int bitset = type->AsUnion()->Get(0)->BitsetLub();
|
int bitset = type->AsUnion()->Get(0)->BitsetLub();
|
||||||
for (int i = 0, n = type->AsUnion()->Length(); i < n; ++i) {
|
for (int i = 0, n = type->AsUnion()->Length(); i < n; ++i) {
|
||||||
// Other elements only contribute their semantic part.
|
// Other elements only contribute their semantic part.
|
||||||
bitset |= SEMANTIC(type->AsUnion()->Get(i)->BitsetLub());
|
bitset |= type->AsUnion()->Get(i)->BitsetLub();
|
||||||
}
|
}
|
||||||
return bitset;
|
return bitset;
|
||||||
}
|
}
|
||||||
@ -185,10 +185,10 @@ Type::bitset BitsetType::Lub(i::Map* map) {
|
|||||||
map == heap->arguments_marker_map() ||
|
map == heap->arguments_marker_map() ||
|
||||||
map == heap->optimized_out_map() ||
|
map == heap->optimized_out_map() ||
|
||||||
map == heap->stale_register_map());
|
map == heap->stale_register_map());
|
||||||
return kOtherInternal & kTaggedPointer;
|
return kOtherInternal;
|
||||||
}
|
}
|
||||||
case HEAP_NUMBER_TYPE:
|
case HEAP_NUMBER_TYPE:
|
||||||
return kNumber & kTaggedPointer;
|
return kNumber;
|
||||||
case SIMD128_VALUE_TYPE:
|
case SIMD128_VALUE_TYPE:
|
||||||
return kSimd;
|
return kSimd;
|
||||||
case JS_OBJECT_TYPE:
|
case JS_OBJECT_TYPE:
|
||||||
@ -242,10 +242,10 @@ Type::bitset BitsetType::Lub(i::Map* map) {
|
|||||||
case CODE_TYPE:
|
case CODE_TYPE:
|
||||||
case PROPERTY_CELL_TYPE:
|
case PROPERTY_CELL_TYPE:
|
||||||
case MODULE_TYPE:
|
case MODULE_TYPE:
|
||||||
return kOtherInternal & kTaggedPointer;
|
return kOtherInternal;
|
||||||
|
|
||||||
// Remaining instance types are unsupported for now. If any of them do
|
// Remaining instance types are unsupported for now. If any of them do
|
||||||
// require bit set types, they should get kOtherInternal & kTaggedPointer.
|
// require bit set types, they should get kOtherInternal.
|
||||||
case MUTABLE_HEAP_NUMBER_TYPE:
|
case MUTABLE_HEAP_NUMBER_TYPE:
|
||||||
case FREE_SPACE_TYPE:
|
case FREE_SPACE_TYPE:
|
||||||
#define FIXED_TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
|
#define FIXED_TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
|
||||||
@ -282,8 +282,7 @@ Type::bitset BitsetType::Lub(i::Map* map) {
|
|||||||
Type::bitset BitsetType::Lub(i::Object* value) {
|
Type::bitset BitsetType::Lub(i::Object* value) {
|
||||||
DisallowHeapAllocation no_allocation;
|
DisallowHeapAllocation no_allocation;
|
||||||
if (value->IsNumber()) {
|
if (value->IsNumber()) {
|
||||||
return Lub(value->Number()) &
|
return Lub(value->Number());
|
||||||
(value->IsSmi() ? kTaggedSigned : kTaggedPointer);
|
|
||||||
}
|
}
|
||||||
return Lub(i::HeapObject::cast(value)->map());
|
return Lub(i::HeapObject::cast(value)->map());
|
||||||
}
|
}
|
||||||
@ -316,12 +315,11 @@ size_t BitsetType::BoundariesSize() {
|
|||||||
|
|
||||||
Type::bitset BitsetType::ExpandInternals(Type::bitset bits) {
|
Type::bitset BitsetType::ExpandInternals(Type::bitset bits) {
|
||||||
DisallowHeapAllocation no_allocation;
|
DisallowHeapAllocation no_allocation;
|
||||||
if (!(bits & SEMANTIC(kPlainNumber))) return bits; // Shortcut.
|
if (!(bits & kPlainNumber)) return bits; // Shortcut.
|
||||||
const Boundary* boundaries = Boundaries();
|
const Boundary* boundaries = Boundaries();
|
||||||
for (size_t i = 0; i < BoundariesSize(); ++i) {
|
for (size_t i = 0; i < BoundariesSize(); ++i) {
|
||||||
DCHECK(BitsetType::Is(boundaries[i].internal, boundaries[i].external));
|
DCHECK(BitsetType::Is(boundaries[i].internal, boundaries[i].external));
|
||||||
if (bits & SEMANTIC(boundaries[i].internal))
|
if (bits & boundaries[i].internal) bits |= boundaries[i].external;
|
||||||
bits |= SEMANTIC(boundaries[i].external);
|
|
||||||
}
|
}
|
||||||
return bits;
|
return bits;
|
||||||
}
|
}
|
||||||
@ -340,9 +338,7 @@ Type::bitset BitsetType::Lub(double min, double max) {
|
|||||||
return lub | mins[BoundariesSize() - 1].internal;
|
return lub | mins[BoundariesSize() - 1].internal;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::bitset BitsetType::NumberBits(bitset bits) {
|
Type::bitset BitsetType::NumberBits(bitset bits) { return bits & kPlainNumber; }
|
||||||
return SEMANTIC(bits & kPlainNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
Type::bitset BitsetType::Glb(double min, double max) {
|
Type::bitset BitsetType::Glb(double min, double max) {
|
||||||
DisallowHeapAllocation no_allocation;
|
DisallowHeapAllocation no_allocation;
|
||||||
@ -360,16 +356,16 @@ Type::bitset BitsetType::Glb(double min, double max) {
|
|||||||
}
|
}
|
||||||
// OtherNumber also contains float numbers, so it can never be
|
// OtherNumber also contains float numbers, so it can never be
|
||||||
// in the greatest lower bound.
|
// in the greatest lower bound.
|
||||||
return glb & ~(SEMANTIC(kOtherNumber));
|
return glb & ~(kOtherNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
double BitsetType::Min(bitset bits) {
|
double BitsetType::Min(bitset bits) {
|
||||||
DisallowHeapAllocation no_allocation;
|
DisallowHeapAllocation no_allocation;
|
||||||
DCHECK(Is(SEMANTIC(bits), kNumber));
|
DCHECK(Is(bits, kNumber));
|
||||||
const Boundary* mins = Boundaries();
|
const Boundary* mins = Boundaries();
|
||||||
bool mz = SEMANTIC(bits & kMinusZero);
|
bool mz = bits & kMinusZero;
|
||||||
for (size_t i = 0; i < BoundariesSize(); ++i) {
|
for (size_t i = 0; i < BoundariesSize(); ++i) {
|
||||||
if (Is(SEMANTIC(mins[i].internal), bits)) {
|
if (Is(mins[i].internal, bits)) {
|
||||||
return mz ? std::min(0.0, mins[i].min) : mins[i].min;
|
return mz ? std::min(0.0, mins[i].min) : mins[i].min;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -379,14 +375,14 @@ double BitsetType::Min(bitset bits) {
|
|||||||
|
|
||||||
double BitsetType::Max(bitset bits) {
|
double BitsetType::Max(bitset bits) {
|
||||||
DisallowHeapAllocation no_allocation;
|
DisallowHeapAllocation no_allocation;
|
||||||
DCHECK(Is(SEMANTIC(bits), kNumber));
|
DCHECK(Is(bits, kNumber));
|
||||||
const Boundary* mins = Boundaries();
|
const Boundary* mins = Boundaries();
|
||||||
bool mz = SEMANTIC(bits & kMinusZero);
|
bool mz = bits & kMinusZero;
|
||||||
if (BitsetType::Is(SEMANTIC(mins[BoundariesSize() - 1].internal), bits)) {
|
if (BitsetType::Is(mins[BoundariesSize() - 1].internal, bits)) {
|
||||||
return +V8_INFINITY;
|
return +V8_INFINITY;
|
||||||
}
|
}
|
||||||
for (size_t i = BoundariesSize() - 1; i-- > 0;) {
|
for (size_t i = BoundariesSize() - 1; i-- > 0;) {
|
||||||
if (Is(SEMANTIC(mins[i].internal), bits)) {
|
if (Is(mins[i].internal, bits)) {
|
||||||
return mz ? std::max(0.0, mins[i + 1].min - 1) : mins[i + 1].min - 1;
|
return mz ? std::max(0.0, mins[i + 1].min - 1) : mins[i + 1].min - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -419,10 +415,6 @@ bool Type::SimplyEquals(Type* that) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::bitset Type::Representation() {
|
|
||||||
return REPRESENTATION(this->BitsetLub());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if [this] <= [that].
|
// Check if [this] <= [that].
|
||||||
bool Type::SlowIs(Type* that) {
|
bool Type::SlowIs(Type* that) {
|
||||||
DisallowHeapAllocation no_allocation;
|
DisallowHeapAllocation no_allocation;
|
||||||
@ -436,33 +428,10 @@ bool Type::SlowIs(Type* that) {
|
|||||||
return BitsetType::Is(this->AsBitset(), that->BitsetGlb());
|
return BitsetType::Is(this->AsBitset(), that->BitsetGlb());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the representations.
|
|
||||||
if (!BitsetType::Is(Representation(), that->Representation())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the semantic part.
|
|
||||||
return SemanticIs(that);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if SEMANTIC([this]) <= SEMANTIC([that]). The result of the method
|
|
||||||
// should be independent of the representation axis of the types.
|
|
||||||
bool Type::SemanticIs(Type* that) {
|
|
||||||
DisallowHeapAllocation no_allocation;
|
|
||||||
|
|
||||||
if (this == that) return true;
|
|
||||||
|
|
||||||
if (that->IsBitset()) {
|
|
||||||
return BitsetType::Is(SEMANTIC(this->BitsetLub()), that->AsBitset());
|
|
||||||
}
|
|
||||||
if (this->IsBitset()) {
|
|
||||||
return BitsetType::Is(SEMANTIC(this->AsBitset()), that->BitsetGlb());
|
|
||||||
}
|
|
||||||
|
|
||||||
// (T1 \/ ... \/ Tn) <= T if (T1 <= T) /\ ... /\ (Tn <= T)
|
// (T1 \/ ... \/ Tn) <= T if (T1 <= T) /\ ... /\ (Tn <= T)
|
||||||
if (this->IsUnion()) {
|
if (this->IsUnion()) {
|
||||||
for (int i = 0, n = this->AsUnion()->Length(); i < n; ++i) {
|
for (int i = 0, n = this->AsUnion()->Length(); i < n; ++i) {
|
||||||
if (!this->AsUnion()->Get(i)->SemanticIs(that)) return false;
|
if (!this->AsUnion()->Get(i)->Is(that)) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -470,7 +439,7 @@ bool Type::SemanticIs(Type* that) {
|
|||||||
// T <= (T1 \/ ... \/ Tn) if (T <= T1) \/ ... \/ (T <= Tn)
|
// T <= (T1 \/ ... \/ Tn) if (T <= T1) \/ ... \/ (T <= Tn)
|
||||||
if (that->IsUnion()) {
|
if (that->IsUnion()) {
|
||||||
for (int i = 0, n = that->AsUnion()->Length(); i < n; ++i) {
|
for (int i = 0, n = that->AsUnion()->Length(); i < n; ++i) {
|
||||||
if (this->SemanticIs(that->AsUnion()->Get(i))) return true;
|
if (this->Is(that->AsUnion()->Get(i))) return true;
|
||||||
if (i > 1 && this->IsRange()) return false; // Shortcut.
|
if (i > 1 && this->IsRange()) return false; // Shortcut.
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -490,21 +459,13 @@ bool Type::SemanticIs(Type* that) {
|
|||||||
bool Type::Maybe(Type* that) {
|
bool Type::Maybe(Type* that) {
|
||||||
DisallowHeapAllocation no_allocation;
|
DisallowHeapAllocation no_allocation;
|
||||||
|
|
||||||
// Take care of the representation part (and also approximate
|
|
||||||
// the semantic part).
|
|
||||||
if (!BitsetType::IsInhabited(this->BitsetLub() & that->BitsetLub()))
|
if (!BitsetType::IsInhabited(this->BitsetLub() & that->BitsetLub()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return SemanticMaybe(that);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Type::SemanticMaybe(Type* that) {
|
|
||||||
DisallowHeapAllocation no_allocation;
|
|
||||||
|
|
||||||
// (T1 \/ ... \/ Tn) overlaps T if (T1 overlaps T) \/ ... \/ (Tn overlaps T)
|
// (T1 \/ ... \/ Tn) overlaps T if (T1 overlaps T) \/ ... \/ (Tn overlaps T)
|
||||||
if (this->IsUnion()) {
|
if (this->IsUnion()) {
|
||||||
for (int i = 0, n = this->AsUnion()->Length(); i < n; ++i) {
|
for (int i = 0, n = this->AsUnion()->Length(); i < n; ++i) {
|
||||||
if (this->AsUnion()->Get(i)->SemanticMaybe(that)) return true;
|
if (this->AsUnion()->Get(i)->Maybe(that)) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -512,14 +473,11 @@ bool Type::SemanticMaybe(Type* that) {
|
|||||||
// T overlaps (T1 \/ ... \/ Tn) if (T overlaps T1) \/ ... \/ (T overlaps Tn)
|
// T overlaps (T1 \/ ... \/ Tn) if (T overlaps T1) \/ ... \/ (T overlaps Tn)
|
||||||
if (that->IsUnion()) {
|
if (that->IsUnion()) {
|
||||||
for (int i = 0, n = that->AsUnion()->Length(); i < n; ++i) {
|
for (int i = 0, n = that->AsUnion()->Length(); i < n; ++i) {
|
||||||
if (this->SemanticMaybe(that->AsUnion()->Get(i))) return true;
|
if (this->Maybe(that->AsUnion()->Get(i))) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!BitsetType::SemanticIsInhabited(this->BitsetLub() & that->BitsetLub()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (this->IsBitset() && that->IsBitset()) return true;
|
if (this->IsBitset() && that->IsBitset()) return true;
|
||||||
|
|
||||||
if (this->IsRange()) {
|
if (this->IsRange()) {
|
||||||
@ -540,7 +498,7 @@ bool Type::SemanticMaybe(Type* that) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (that->IsRange()) {
|
if (that->IsRange()) {
|
||||||
return that->SemanticMaybe(this); // This case is handled above.
|
return that->Maybe(this); // This case is handled above.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->IsBitset() || that->IsBitset()) return true;
|
if (this->IsBitset() || that->IsBitset()) return true;
|
||||||
@ -588,8 +546,7 @@ bool UnionType::Wellformed() {
|
|||||||
if (i != 1) DCHECK(!this->Get(i)->IsRange()); // (3)
|
if (i != 1) DCHECK(!this->Get(i)->IsRange()); // (3)
|
||||||
DCHECK(!this->Get(i)->IsUnion()); // (4)
|
DCHECK(!this->Get(i)->IsUnion()); // (4)
|
||||||
for (int j = 0; j < this->Length(); ++j) {
|
for (int j = 0; j < this->Length(); ++j) {
|
||||||
if (i != j && i != 0)
|
if (i != j && i != 0) DCHECK(!this->Get(i)->Is(this->Get(j))); // (5)
|
||||||
DCHECK(!this->Get(i)->SemanticIs(this->Get(j))); // (5)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DCHECK(!this->Get(1)->IsRange() ||
|
DCHECK(!this->Get(1)->IsRange() ||
|
||||||
@ -622,25 +579,15 @@ Type* Type::Intersect(Type* type1, Type* type2, Zone* zone) {
|
|||||||
|
|
||||||
// Slow case: create union.
|
// Slow case: create union.
|
||||||
|
|
||||||
// Figure out the representation of the result first.
|
|
||||||
// The rest of the method should not change this representation and
|
|
||||||
// it should not make any decisions based on representations (i.e.,
|
|
||||||
// it should only use the semantic part of types).
|
|
||||||
const bitset representation =
|
|
||||||
type1->Representation() & type2->Representation();
|
|
||||||
|
|
||||||
// Semantic subtyping check - this is needed for consistency with the
|
// Semantic subtyping check - this is needed for consistency with the
|
||||||
// semi-fast case above - we should behave the same way regardless of
|
// semi-fast case above.
|
||||||
// representations. Intersection with a universal bitset should only update
|
if (type1->Is(type2)) {
|
||||||
// the representations.
|
|
||||||
if (type1->SemanticIs(type2)) {
|
|
||||||
type2 = Any();
|
type2 = Any();
|
||||||
} else if (type2->SemanticIs(type1)) {
|
} else if (type2->Is(type1)) {
|
||||||
type1 = Any();
|
type1 = Any();
|
||||||
}
|
}
|
||||||
|
|
||||||
bitset bits =
|
bitset bits = type1->BitsetGlb() & type2->BitsetGlb();
|
||||||
SEMANTIC(type1->BitsetGlb() & type2->BitsetGlb()) | representation;
|
|
||||||
int size1 = type1->IsUnion() ? type1->AsUnion()->Length() : 1;
|
int size1 = type1->IsUnion() ? type1->AsUnion()->Length() : 1;
|
||||||
int size2 = type2->IsUnion() ? type2->AsUnion()->Length() : 1;
|
int size2 = type2->IsUnion() ? type2->AsUnion()->Length() : 1;
|
||||||
if (!AddIsSafe(size1, size2)) return Any();
|
if (!AddIsSafe(size1, size2)) return Any();
|
||||||
@ -660,8 +607,7 @@ Type* Type::Intersect(Type* type1, Type* type2, Zone* zone) {
|
|||||||
// If the range is not empty, then insert it into the union and
|
// If the range is not empty, then insert it into the union and
|
||||||
// remove the number bits from the bitset.
|
// remove the number bits from the bitset.
|
||||||
if (!lims.IsEmpty()) {
|
if (!lims.IsEmpty()) {
|
||||||
size = UpdateRange(RangeType::New(lims, representation, zone), result, size,
|
size = UpdateRange(RangeType::New(lims, zone), result, size, zone);
|
||||||
zone);
|
|
||||||
|
|
||||||
// Remove the number bits.
|
// Remove the number bits.
|
||||||
bitset number_bits = BitsetType::NumberBits(bits);
|
bitset number_bits = BitsetType::NumberBits(bits);
|
||||||
@ -682,7 +628,7 @@ int Type::UpdateRange(Type* range, UnionType* result, int size, Zone* zone) {
|
|||||||
|
|
||||||
// Remove any components that just got subsumed.
|
// Remove any components that just got subsumed.
|
||||||
for (int i = 2; i < size;) {
|
for (int i = 2; i < size;) {
|
||||||
if (result->Get(i)->SemanticIs(range)) {
|
if (result->Get(i)->Is(range)) {
|
||||||
result->Set(i, result->Get(--size));
|
result->Set(i, result->Get(--size));
|
||||||
} else {
|
} else {
|
||||||
++i;
|
++i;
|
||||||
@ -726,7 +672,7 @@ int Type::IntersectAux(Type* lhs, Type* rhs, UnionType* result, int size,
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!BitsetType::SemanticIsInhabited(lhs->BitsetLub() & rhs->BitsetLub())) {
|
if (!BitsetType::IsInhabited(lhs->BitsetLub() & rhs->BitsetLub())) {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -778,7 +724,7 @@ Type* Type::NormalizeRangeAndBitset(Type* range, bitset* bits, Zone* zone) {
|
|||||||
|
|
||||||
// If the range is semantically contained within the bitset, return None and
|
// If the range is semantically contained within the bitset, return None and
|
||||||
// leave the bitset untouched.
|
// leave the bitset untouched.
|
||||||
bitset range_lub = SEMANTIC(range->BitsetLub());
|
bitset range_lub = range->BitsetLub();
|
||||||
if (BitsetType::Is(range_lub, *bits)) {
|
if (BitsetType::Is(range_lub, *bits)) {
|
||||||
return None();
|
return None();
|
||||||
}
|
}
|
||||||
@ -806,7 +752,7 @@ Type* Type::NormalizeRangeAndBitset(Type* range, bitset* bits, Zone* zone) {
|
|||||||
if (bitset_max > range_max) {
|
if (bitset_max > range_max) {
|
||||||
range_max = bitset_max;
|
range_max = bitset_max;
|
||||||
}
|
}
|
||||||
return RangeType::New(range_min, range_max, BitsetType::kNone, zone);
|
return RangeType::New(range_min, range_max, zone);
|
||||||
}
|
}
|
||||||
|
|
||||||
Type* Type::Union(Type* type1, Type* type2, Zone* zone) {
|
Type* Type::Union(Type* type1, Type* type2, Zone* zone) {
|
||||||
@ -823,13 +769,6 @@ Type* Type::Union(Type* type1, Type* type2, Zone* zone) {
|
|||||||
if (type1->Is(type2)) return type2;
|
if (type1->Is(type2)) return type2;
|
||||||
if (type2->Is(type1)) return type1;
|
if (type2->Is(type1)) return type1;
|
||||||
|
|
||||||
// Figure out the representation of the result.
|
|
||||||
// The rest of the method should not change this representation and
|
|
||||||
// it should not make any decisions based on representations (i.e.,
|
|
||||||
// it should only use the semantic part of types).
|
|
||||||
const bitset representation =
|
|
||||||
type1->Representation() | type2->Representation();
|
|
||||||
|
|
||||||
// Slow case: create union.
|
// Slow case: create union.
|
||||||
int size1 = type1->IsUnion() ? type1->AsUnion()->Length() : 1;
|
int size1 = type1->IsUnion() ? type1->AsUnion()->Length() : 1;
|
||||||
int size2 = type2->IsUnion() ? type2->AsUnion()->Length() : 1;
|
int size2 = type2->IsUnion() ? type2->AsUnion()->Length() : 1;
|
||||||
@ -842,7 +781,7 @@ Type* Type::Union(Type* type1, Type* type2, Zone* zone) {
|
|||||||
size = 0;
|
size = 0;
|
||||||
|
|
||||||
// Compute the new bitset.
|
// Compute the new bitset.
|
||||||
bitset new_bitset = SEMANTIC(type1->BitsetGlb() | type2->BitsetGlb());
|
bitset new_bitset = type1->BitsetGlb() | type2->BitsetGlb();
|
||||||
|
|
||||||
// Deal with ranges.
|
// Deal with ranges.
|
||||||
Type* range = None();
|
Type* range = None();
|
||||||
@ -852,14 +791,13 @@ Type* Type::Union(Type* type1, Type* type2, Zone* zone) {
|
|||||||
RangeType::Limits lims =
|
RangeType::Limits lims =
|
||||||
RangeType::Limits::Union(RangeType::Limits(range1->AsRange()),
|
RangeType::Limits::Union(RangeType::Limits(range1->AsRange()),
|
||||||
RangeType::Limits(range2->AsRange()));
|
RangeType::Limits(range2->AsRange()));
|
||||||
Type* union_range = RangeType::New(lims, representation, zone);
|
Type* union_range = RangeType::New(lims, zone);
|
||||||
range = NormalizeRangeAndBitset(union_range, &new_bitset, zone);
|
range = NormalizeRangeAndBitset(union_range, &new_bitset, zone);
|
||||||
} else if (range1 != NULL) {
|
} else if (range1 != NULL) {
|
||||||
range = NormalizeRangeAndBitset(range1, &new_bitset, zone);
|
range = NormalizeRangeAndBitset(range1, &new_bitset, zone);
|
||||||
} else if (range2 != NULL) {
|
} else if (range2 != NULL) {
|
||||||
range = NormalizeRangeAndBitset(range2, &new_bitset, zone);
|
range = NormalizeRangeAndBitset(range2, &new_bitset, zone);
|
||||||
}
|
}
|
||||||
new_bitset = SEMANTIC(new_bitset) | representation;
|
|
||||||
Type* bits = BitsetType::New(new_bitset);
|
Type* bits = BitsetType::New(new_bitset);
|
||||||
result->Set(size++, bits);
|
result->Set(size++, bits);
|
||||||
if (!range->IsNone()) result->Set(size++, range);
|
if (!range->IsNone()) result->Set(size++, range);
|
||||||
@ -880,7 +818,7 @@ int Type::AddToUnion(Type* type, UnionType* result, int size, Zone* zone) {
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < size; ++i) {
|
for (int i = 0; i < size; ++i) {
|
||||||
if (type->SemanticIs(result->Get(i))) return size;
|
if (type->Is(result->Get(i))) return size;
|
||||||
}
|
}
|
||||||
result->Set(size++, type);
|
result->Set(size++, type);
|
||||||
return size;
|
return size;
|
||||||
@ -896,15 +834,10 @@ Type* Type::NormalizeUnion(Type* union_type, int size, Zone* zone) {
|
|||||||
}
|
}
|
||||||
bitset bits = unioned->Get(0)->AsBitset();
|
bitset bits = unioned->Get(0)->AsBitset();
|
||||||
// If the union only consists of a range, we can get rid of the union.
|
// If the union only consists of a range, we can get rid of the union.
|
||||||
if (size == 2 && SEMANTIC(bits) == BitsetType::kNone) {
|
if (size == 2 && bits == BitsetType::kNone) {
|
||||||
bitset representation = REPRESENTATION(bits);
|
|
||||||
if (representation == unioned->Get(1)->Representation()) {
|
|
||||||
return unioned->Get(1);
|
|
||||||
}
|
|
||||||
if (unioned->Get(1)->IsRange()) {
|
if (unioned->Get(1)->IsRange()) {
|
||||||
return RangeType::New(unioned->Get(1)->AsRange()->Min(),
|
return RangeType::New(unioned->Get(1)->AsRange()->Min(),
|
||||||
unioned->Get(1)->AsRange()->Max(),
|
unioned->Get(1)->AsRange()->Max(), zone);
|
||||||
unioned->Get(0)->AsBitset(), zone);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unioned->Shrink(size);
|
unioned->Shrink(size);
|
||||||
@ -912,19 +845,6 @@ Type* Type::NormalizeUnion(Type* union_type, int size, Zone* zone) {
|
|||||||
return union_type;
|
return union_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// Component extraction
|
|
||||||
|
|
||||||
// static
|
|
||||||
Type* Type::Representation(Type* t, Zone* zone) {
|
|
||||||
return BitsetType::New(t->Representation());
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
|
||||||
Type* Type::Semantic(Type* t, Zone* zone) {
|
|
||||||
return Intersect(t, BitsetType::New(BitsetType::kSemantic), zone);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Iteration.
|
// Iteration.
|
||||||
|
|
||||||
@ -994,20 +914,12 @@ void Type::Iterator<T>::Advance() {
|
|||||||
|
|
||||||
const char* BitsetType::Name(bitset bits) {
|
const char* BitsetType::Name(bitset bits) {
|
||||||
switch (bits) {
|
switch (bits) {
|
||||||
case REPRESENTATION(kAny):
|
#define RETURN_NAMED_TYPE(type, value) \
|
||||||
return "Any";
|
case k##type: \
|
||||||
#define RETURN_NAMED_REPRESENTATION_TYPE(type, value) \
|
|
||||||
case REPRESENTATION(k##type): \
|
|
||||||
return #type;
|
return #type;
|
||||||
REPRESENTATION_BITSET_TYPE_LIST(RETURN_NAMED_REPRESENTATION_TYPE)
|
PROPER_BITSET_TYPE_LIST(RETURN_NAMED_TYPE)
|
||||||
#undef RETURN_NAMED_REPRESENTATION_TYPE
|
INTERNAL_BITSET_TYPE_LIST(RETURN_NAMED_TYPE)
|
||||||
|
#undef RETURN_NAMED_TYPE
|
||||||
#define RETURN_NAMED_SEMANTIC_TYPE(type, value) \
|
|
||||||
case SEMANTIC(k##type): \
|
|
||||||
return #type;
|
|
||||||
SEMANTIC_BITSET_TYPE_LIST(RETURN_NAMED_SEMANTIC_TYPE)
|
|
||||||
INTERNAL_BITSET_TYPE_LIST(RETURN_NAMED_SEMANTIC_TYPE)
|
|
||||||
#undef RETURN_NAMED_SEMANTIC_TYPE
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -1025,13 +937,9 @@ void BitsetType::Print(std::ostream& os, // NOLINT
|
|||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const bitset named_bitsets[] = {
|
static const bitset named_bitsets[] = {
|
||||||
#define BITSET_CONSTANT(type, value) REPRESENTATION(k##type),
|
#define BITSET_CONSTANT(type, value) k##type,
|
||||||
REPRESENTATION_BITSET_TYPE_LIST(BITSET_CONSTANT)
|
|
||||||
#undef BITSET_CONSTANT
|
|
||||||
|
|
||||||
#define BITSET_CONSTANT(type, value) SEMANTIC(k##type),
|
|
||||||
INTERNAL_BITSET_TYPE_LIST(BITSET_CONSTANT)
|
INTERNAL_BITSET_TYPE_LIST(BITSET_CONSTANT)
|
||||||
SEMANTIC_BITSET_TYPE_LIST(BITSET_CONSTANT)
|
PROPER_BITSET_TYPE_LIST(BITSET_CONSTANT)
|
||||||
#undef BITSET_CONSTANT
|
#undef BITSET_CONSTANT
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
@ -1051,43 +959,37 @@ void BitsetType::Print(std::ostream& os, // NOLINT
|
|||||||
os << ")";
|
os << ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
void Type::PrintTo(std::ostream& os, PrintDimension dim) {
|
void Type::PrintTo(std::ostream& os) {
|
||||||
DisallowHeapAllocation no_allocation;
|
DisallowHeapAllocation no_allocation;
|
||||||
if (dim != REPRESENTATION_DIM) {
|
if (this->IsBitset()) {
|
||||||
if (this->IsBitset()) {
|
BitsetType::Print(os, this->AsBitset());
|
||||||
BitsetType::Print(os, SEMANTIC(this->AsBitset()));
|
} else if (this->IsConstant()) {
|
||||||
} else if (this->IsConstant()) {
|
os << "Constant(" << Brief(*this->AsConstant()->Value()) << ")";
|
||||||
os << "Constant(" << Brief(*this->AsConstant()->Value()) << ")";
|
} else if (this->IsRange()) {
|
||||||
} else if (this->IsRange()) {
|
std::ostream::fmtflags saved_flags = os.setf(std::ios::fixed);
|
||||||
std::ostream::fmtflags saved_flags = os.setf(std::ios::fixed);
|
std::streamsize saved_precision = os.precision(0);
|
||||||
std::streamsize saved_precision = os.precision(0);
|
os << "Range(" << this->AsRange()->Min() << ", " << this->AsRange()->Max()
|
||||||
os << "Range(" << this->AsRange()->Min() << ", " << this->AsRange()->Max()
|
<< ")";
|
||||||
<< ")";
|
os.flags(saved_flags);
|
||||||
os.flags(saved_flags);
|
os.precision(saved_precision);
|
||||||
os.precision(saved_precision);
|
} else if (this->IsUnion()) {
|
||||||
} else if (this->IsUnion()) {
|
os << "(";
|
||||||
os << "(";
|
for (int i = 0, n = this->AsUnion()->Length(); i < n; ++i) {
|
||||||
for (int i = 0, n = this->AsUnion()->Length(); i < n; ++i) {
|
Type* type_i = this->AsUnion()->Get(i);
|
||||||
Type* type_i = this->AsUnion()->Get(i);
|
if (i > 0) os << " | ";
|
||||||
if (i > 0) os << " | ";
|
type_i->PrintTo(os);
|
||||||
type_i->PrintTo(os, dim);
|
|
||||||
}
|
|
||||||
os << ")";
|
|
||||||
} else if (this->IsTuple()) {
|
|
||||||
os << "<";
|
|
||||||
for (int i = 0, n = this->AsTuple()->Arity(); i < n; ++i) {
|
|
||||||
Type* type_i = this->AsTuple()->Element(i);
|
|
||||||
if (i > 0) os << ", ";
|
|
||||||
type_i->PrintTo(os, dim);
|
|
||||||
}
|
|
||||||
os << ">";
|
|
||||||
} else {
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
}
|
||||||
}
|
os << ")";
|
||||||
if (dim == BOTH_DIMS) os << "/";
|
} else if (this->IsTuple()) {
|
||||||
if (dim != SEMANTIC_DIM) {
|
os << "<";
|
||||||
BitsetType::Print(os, REPRESENTATION(this->BitsetLub()));
|
for (int i = 0, n = this->AsTuple()->Arity(); i < n; ++i) {
|
||||||
|
Type* type_i = this->AsTuple()->Element(i);
|
||||||
|
if (i > 0) os << ", ";
|
||||||
|
type_i->PrintTo(os);
|
||||||
|
}
|
||||||
|
os << ">";
|
||||||
|
} else {
|
||||||
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,13 +22,7 @@ namespace compiler {
|
|||||||
// can express class types (a.k.a. specific maps) and singleton types (i.e.,
|
// can express class types (a.k.a. specific maps) and singleton types (i.e.,
|
||||||
// concrete constants).
|
// concrete constants).
|
||||||
//
|
//
|
||||||
// Types consist of two dimensions: semantic (value range) and representation.
|
// The following equations and inequations hold:
|
||||||
// Both are related through subtyping.
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// SEMANTIC DIMENSION
|
|
||||||
//
|
|
||||||
// The following equations and inequations hold for the semantic axis:
|
|
||||||
//
|
//
|
||||||
// None <= T
|
// None <= T
|
||||||
// T <= Any
|
// T <= Any
|
||||||
@ -40,41 +34,12 @@ namespace compiler {
|
|||||||
// InternalizedString < String
|
// InternalizedString < String
|
||||||
//
|
//
|
||||||
// Receiver = Object \/ Proxy
|
// Receiver = Object \/ Proxy
|
||||||
// RegExp < Object
|
|
||||||
// OtherUndetectable < Object
|
// OtherUndetectable < Object
|
||||||
// DetectableReceiver = Receiver - OtherUndetectable
|
// DetectableReceiver = Receiver - OtherUndetectable
|
||||||
//
|
//
|
||||||
// Constant(x) < T iff instance_type(map(x)) < T
|
// Constant(x) < T iff instance_type(map(x)) < T
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// REPRESENTATIONAL DIMENSION
|
|
||||||
//
|
|
||||||
// For the representation axis, the following holds:
|
|
||||||
//
|
|
||||||
// None <= R
|
|
||||||
// R <= Any
|
|
||||||
//
|
|
||||||
// UntaggedInt = UntaggedInt1 \/ UntaggedInt8 \/
|
|
||||||
// UntaggedInt16 \/ UntaggedInt32
|
|
||||||
// UntaggedFloat = UntaggedFloat32 \/ UntaggedFloat64
|
|
||||||
// UntaggedNumber = UntaggedInt \/ UntaggedFloat
|
|
||||||
// Untagged = UntaggedNumber \/ UntaggedPtr
|
|
||||||
// Tagged = TaggedInt \/ TaggedPtr
|
|
||||||
//
|
|
||||||
// Subtyping relates the two dimensions, for example:
|
|
||||||
//
|
|
||||||
// Number <= Tagged \/ UntaggedNumber
|
|
||||||
// Object <= TaggedPtr \/ UntaggedPtr
|
|
||||||
//
|
|
||||||
// That holds because the semantic type constructors defined by the API create
|
|
||||||
// types that allow for all possible representations, and dually, the ones for
|
|
||||||
// representation types initially include all semantic ranges. Representations
|
|
||||||
// can then e.g. be narrowed for a given semantic type using intersection:
|
|
||||||
//
|
|
||||||
// SignedSmall /\ TaggedInt (a 'smi')
|
|
||||||
// Number /\ TaggedPtr (a heap number)
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// RANGE TYPES
|
// RANGE TYPES
|
||||||
//
|
//
|
||||||
// A range type represents a continuous integer interval by its minimum and
|
// A range type represents a continuous integer interval by its minimum and
|
||||||
@ -125,64 +90,37 @@ namespace compiler {
|
|||||||
// Internally, all 'primitive' types, and their unions, are represented as
|
// Internally, all 'primitive' types, and their unions, are represented as
|
||||||
// bitsets. Bit 0 is reserved for tagging. Only structured types require
|
// bitsets. Bit 0 is reserved for tagging. Only structured types require
|
||||||
// allocation.
|
// allocation.
|
||||||
// Note that the bitset representation is closed under both Union and Intersect.
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Values for bitset types
|
// Values for bitset types
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
|
||||||
#define MASK_BITSET_TYPE_LIST(V) \
|
|
||||||
V(Representation, 0xffc00000u) \
|
|
||||||
V(Semantic, 0x003ffffeu)
|
|
||||||
|
|
||||||
#define REPRESENTATION(k) ((k) & BitsetType::kRepresentation)
|
|
||||||
#define SEMANTIC(k) ((k) & BitsetType::kSemantic)
|
|
||||||
|
|
||||||
#define REPRESENTATION_BITSET_TYPE_LIST(V) \
|
|
||||||
V(None, 0) \
|
|
||||||
V(UntaggedBit, 1u << 22 | kSemantic) \
|
|
||||||
V(UntaggedIntegral8, 1u << 23 | kSemantic) \
|
|
||||||
V(UntaggedIntegral16, 1u << 24 | kSemantic) \
|
|
||||||
V(UntaggedIntegral32, 1u << 25 | kSemantic) \
|
|
||||||
V(UntaggedFloat32, 1u << 26 | kSemantic) \
|
|
||||||
V(UntaggedFloat64, 1u << 27 | kSemantic) \
|
|
||||||
V(UntaggedSimd128, 1u << 28 | kSemantic) \
|
|
||||||
V(UntaggedPointer, 1u << 29 | kSemantic) \
|
|
||||||
V(TaggedSigned, 1u << 30 | kSemantic) \
|
|
||||||
V(TaggedPointer, 1u << 31 | kSemantic) \
|
|
||||||
\
|
|
||||||
V(UntaggedIntegral, kUntaggedBit | kUntaggedIntegral8 | \
|
|
||||||
kUntaggedIntegral16 | kUntaggedIntegral32) \
|
|
||||||
V(UntaggedFloat, kUntaggedFloat32 | kUntaggedFloat64) \
|
|
||||||
V(UntaggedNumber, kUntaggedIntegral | kUntaggedFloat) \
|
|
||||||
V(Untagged, kUntaggedNumber | kUntaggedPointer) \
|
|
||||||
V(Tagged, kTaggedSigned | kTaggedPointer)
|
|
||||||
|
|
||||||
#define INTERNAL_BITSET_TYPE_LIST(V) \
|
#define INTERNAL_BITSET_TYPE_LIST(V) \
|
||||||
V(OtherUnsigned31, 1u << 1 | REPRESENTATION(kTagged | kUntaggedNumber)) \
|
V(OtherUnsigned31, 1u << 1) \
|
||||||
V(OtherUnsigned32, 1u << 2 | REPRESENTATION(kTagged | kUntaggedNumber)) \
|
V(OtherUnsigned32, 1u << 2) \
|
||||||
V(OtherSigned32, 1u << 3 | REPRESENTATION(kTagged | kUntaggedNumber)) \
|
V(OtherSigned32, 1u << 3) \
|
||||||
V(OtherNumber, 1u << 4 | REPRESENTATION(kTagged | kUntaggedNumber))
|
V(OtherNumber, 1u << 4) \
|
||||||
|
|
||||||
#define SEMANTIC_BITSET_TYPE_LIST(V) \
|
#define PROPER_BITSET_TYPE_LIST(V) \
|
||||||
V(Negative31, 1u << 5 | REPRESENTATION(kTagged | kUntaggedNumber)) \
|
V(None, 0u) \
|
||||||
V(Null, 1u << 6 | REPRESENTATION(kTaggedPointer)) \
|
V(Negative31, 1u << 5) \
|
||||||
V(Undefined, 1u << 7 | REPRESENTATION(kTaggedPointer)) \
|
V(Null, 1u << 6) \
|
||||||
V(Boolean, 1u << 8 | REPRESENTATION(kTaggedPointer)) \
|
V(Undefined, 1u << 7) \
|
||||||
V(Unsigned30, 1u << 9 | REPRESENTATION(kTagged | kUntaggedNumber)) \
|
V(Boolean, 1u << 8) \
|
||||||
V(MinusZero, 1u << 10 | REPRESENTATION(kTagged | kUntaggedNumber)) \
|
V(Unsigned30, 1u << 9) \
|
||||||
V(NaN, 1u << 11 | REPRESENTATION(kTagged | kUntaggedNumber)) \
|
V(MinusZero, 1u << 10) \
|
||||||
V(Symbol, 1u << 12 | REPRESENTATION(kTaggedPointer)) \
|
V(NaN, 1u << 11) \
|
||||||
V(InternalizedString, 1u << 13 | REPRESENTATION(kTaggedPointer)) \
|
V(Symbol, 1u << 12) \
|
||||||
V(OtherString, 1u << 14 | REPRESENTATION(kTaggedPointer)) \
|
V(InternalizedString, 1u << 13) \
|
||||||
V(Simd, 1u << 15 | REPRESENTATION(kTaggedPointer)) \
|
V(OtherString, 1u << 14) \
|
||||||
V(OtherObject, 1u << 17 | REPRESENTATION(kTaggedPointer)) \
|
V(Simd, 1u << 15) \
|
||||||
V(OtherUndetectable, 1u << 16 | REPRESENTATION(kTaggedPointer)) \
|
V(OtherObject, 1u << 17) \
|
||||||
V(Proxy, 1u << 18 | REPRESENTATION(kTaggedPointer)) \
|
V(OtherUndetectable, 1u << 16) \
|
||||||
V(Function, 1u << 19 | REPRESENTATION(kTaggedPointer)) \
|
V(Proxy, 1u << 18) \
|
||||||
V(Hole, 1u << 20 | REPRESENTATION(kTaggedPointer)) \
|
V(Function, 1u << 19) \
|
||||||
V(OtherInternal, 1u << 21 | REPRESENTATION(kTagged | kUntagged)) \
|
V(Hole, 1u << 20) \
|
||||||
|
V(OtherInternal, 1u << 21) \
|
||||||
\
|
\
|
||||||
V(Signed31, kUnsigned30 | kNegative31) \
|
V(Signed31, kUnsigned30 | kNegative31) \
|
||||||
V(Signed32, kSigned31 | kOtherUnsigned31 | kOtherSigned32) \
|
V(Signed32, kSigned31 | kOtherUnsigned31 | kOtherSigned32) \
|
||||||
@ -243,15 +181,9 @@ namespace compiler {
|
|||||||
* occur as part of PlainNumber.
|
* occur as part of PlainNumber.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PROPER_BITSET_TYPE_LIST(V) \
|
#define BITSET_TYPE_LIST(V) \
|
||||||
REPRESENTATION_BITSET_TYPE_LIST(V) \
|
INTERNAL_BITSET_TYPE_LIST(V) \
|
||||||
SEMANTIC_BITSET_TYPE_LIST(V)
|
PROPER_BITSET_TYPE_LIST(V)
|
||||||
|
|
||||||
#define BITSET_TYPE_LIST(V) \
|
|
||||||
MASK_BITSET_TYPE_LIST(V) \
|
|
||||||
REPRESENTATION_BITSET_TYPE_LIST(V) \
|
|
||||||
INTERNAL_BITSET_TYPE_LIST(V) \
|
|
||||||
SEMANTIC_BITSET_TYPE_LIST(V)
|
|
||||||
|
|
||||||
class Type;
|
class Type;
|
||||||
|
|
||||||
@ -276,13 +208,7 @@ class BitsetType {
|
|||||||
return static_cast<bitset>(reinterpret_cast<uintptr_t>(this) ^ 1u);
|
return static_cast<bitset>(reinterpret_cast<uintptr_t>(this) ^ 1u);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsInhabited(bitset bits) {
|
static bool IsInhabited(bitset bits) { return bits != kNone; }
|
||||||
return SEMANTIC(bits) != kNone && REPRESENTATION(bits) != kNone;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool SemanticIsInhabited(bitset bits) {
|
|
||||||
return SEMANTIC(bits) != kNone;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool Is(bitset bits1, bitset bits2) {
|
static bool Is(bitset bits1, bitset bits2) {
|
||||||
return (bits1 | bits2) == bits2;
|
return (bits1 | bits2) == bits2;
|
||||||
@ -389,7 +315,6 @@ class ConstantType : public TypeBase {
|
|||||||
Handle<i::Object> object_;
|
Handle<i::Object> object_;
|
||||||
};
|
};
|
||||||
// TODO(neis): Also cache value if numerical.
|
// TODO(neis): Also cache value if numerical.
|
||||||
// TODO(neis): Allow restricting the representation.
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Range types.
|
// Range types.
|
||||||
@ -415,21 +340,18 @@ class RangeType : public TypeBase {
|
|||||||
friend class BitsetType;
|
friend class BitsetType;
|
||||||
friend class UnionType;
|
friend class UnionType;
|
||||||
|
|
||||||
static Type* New(double min, double max, BitsetType::bitset representation,
|
static Type* New(double min, double max, Zone* zone) {
|
||||||
Zone* zone) {
|
return New(Limits(min, max), zone);
|
||||||
return New(Limits(min, max), representation, zone);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsInteger(double x) {
|
static bool IsInteger(double x) {
|
||||||
return nearbyint(x) == x && !i::IsMinusZero(x); // Allows for infinities.
|
return nearbyint(x) == x && !i::IsMinusZero(x); // Allows for infinities.
|
||||||
}
|
}
|
||||||
|
|
||||||
static Type* New(Limits lim, BitsetType::bitset representation, Zone* zone) {
|
static Type* New(Limits lim, Zone* zone) {
|
||||||
DCHECK(IsInteger(lim.min) && IsInteger(lim.max));
|
DCHECK(IsInteger(lim.min) && IsInteger(lim.max));
|
||||||
DCHECK(lim.min <= lim.max);
|
DCHECK(lim.min <= lim.max);
|
||||||
DCHECK(REPRESENTATION(representation) == representation);
|
BitsetType::bitset bits = BitsetType::Lub(lim.min, lim.max);
|
||||||
BitsetType::bitset bits =
|
|
||||||
SEMANTIC(BitsetType::Lub(lim.min, lim.max)) | representation;
|
|
||||||
|
|
||||||
return AsType(new (zone->New(sizeof(RangeType))) RangeType(bits, lim));
|
return AsType(new (zone->New(sizeof(RangeType))) RangeType(bits, lim));
|
||||||
}
|
}
|
||||||
@ -556,9 +478,7 @@ class Type {
|
|||||||
return ConstantType::New(value, zone);
|
return ConstantType::New(value, zone);
|
||||||
}
|
}
|
||||||
static Type* Range(double min, double max, Zone* zone) {
|
static Type* Range(double min, double max, Zone* zone) {
|
||||||
return RangeType::New(min, max, REPRESENTATION(BitsetType::kTagged |
|
return RangeType::New(min, max, zone);
|
||||||
BitsetType::kUntaggedNumber),
|
|
||||||
zone);
|
|
||||||
}
|
}
|
||||||
static Type* Tuple(Type* first, Type* second, Type* third, Zone* zone) {
|
static Type* Tuple(Type* first, Type* second, Type* third, Zone* zone) {
|
||||||
Type* tuple = TupleType::New(3, zone);
|
Type* tuple = TupleType::New(3, zone);
|
||||||
@ -586,10 +506,6 @@ class Type {
|
|||||||
}
|
}
|
||||||
static Type* For(i::Handle<i::Map> map) { return For(*map); }
|
static Type* For(i::Handle<i::Map> map) { return For(*map); }
|
||||||
|
|
||||||
// Extraction of components.
|
|
||||||
static Type* Representation(Type* t, Zone* zone);
|
|
||||||
static Type* Semantic(Type* t, Zone* zone);
|
|
||||||
|
|
||||||
// Predicates.
|
// Predicates.
|
||||||
bool IsInhabited() { return BitsetType::IsInhabited(this->BitsetLub()); }
|
bool IsInhabited() { return BitsetType::IsInhabited(this->BitsetLub()); }
|
||||||
|
|
||||||
@ -655,9 +571,7 @@ class Type {
|
|||||||
|
|
||||||
// Printing.
|
// Printing.
|
||||||
|
|
||||||
enum PrintDimension { BOTH_DIMS, SEMANTIC_DIM, REPRESENTATION_DIM };
|
void PrintTo(std::ostream& os);
|
||||||
|
|
||||||
void PrintTo(std::ostream& os, PrintDimension dim = BOTH_DIMS); // NOLINT
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
void Print();
|
void Print();
|
||||||
@ -690,16 +604,10 @@ class Type {
|
|||||||
}
|
}
|
||||||
UnionType* AsUnion() { return UnionType::cast(this); }
|
UnionType* AsUnion() { return UnionType::cast(this); }
|
||||||
|
|
||||||
bitset Representation();
|
|
||||||
|
|
||||||
// Auxiliary functions.
|
|
||||||
bool SemanticMaybe(Type* that);
|
|
||||||
|
|
||||||
bitset BitsetGlb() { return BitsetType::Glb(this); }
|
bitset BitsetGlb() { return BitsetType::Glb(this); }
|
||||||
bitset BitsetLub() { return BitsetType::Lub(this); }
|
bitset BitsetLub() { return BitsetType::Lub(this); }
|
||||||
|
|
||||||
bool SlowIs(Type* that);
|
bool SlowIs(Type* that);
|
||||||
bool SemanticIs(Type* that);
|
|
||||||
|
|
||||||
static bool Overlap(RangeType* lhs, RangeType* rhs);
|
static bool Overlap(RangeType* lhs, RangeType* rhs);
|
||||||
static bool Contains(RangeType* lhs, RangeType* rhs);
|
static bool Contains(RangeType* lhs, RangeType* rhs);
|
||||||
|
@ -187,72 +187,6 @@ struct Tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PointwiseRepresentation() {
|
|
||||||
// Check we can decompose type into semantics and representation and
|
|
||||||
// then compose it back to get an equivalent type.
|
|
||||||
int counter = 0;
|
|
||||||
for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
|
|
||||||
counter++;
|
|
||||||
Type* type1 = *it1;
|
|
||||||
Type* representation = T.Representation(type1);
|
|
||||||
Type* semantic = T.Semantic(type1);
|
|
||||||
Type* composed = T.Union(representation, semantic);
|
|
||||||
CHECK(type1->Equals(composed));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pointwiseness of Union.
|
|
||||||
for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
|
|
||||||
for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
|
|
||||||
Type* type1 = *it1;
|
|
||||||
Type* type2 = *it2;
|
|
||||||
Type* representation1 = T.Representation(type1);
|
|
||||||
Type* semantic1 = T.Semantic(type1);
|
|
||||||
Type* representation2 = T.Representation(type2);
|
|
||||||
Type* semantic2 = T.Semantic(type2);
|
|
||||||
Type* direct_union = T.Union(type1, type2);
|
|
||||||
Type* representation_union = T.Union(representation1, representation2);
|
|
||||||
Type* semantic_union = T.Union(semantic1, semantic2);
|
|
||||||
Type* composed_union = T.Union(representation_union, semantic_union);
|
|
||||||
CHECK(direct_union->Equals(composed_union));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pointwiseness of Intersect.
|
|
||||||
for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
|
|
||||||
for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
|
|
||||||
Type* type1 = *it1;
|
|
||||||
Type* type2 = *it2;
|
|
||||||
Type* representation1 = T.Representation(type1);
|
|
||||||
Type* semantic1 = T.Semantic(type1);
|
|
||||||
Type* representation2 = T.Representation(type2);
|
|
||||||
Type* semantic2 = T.Semantic(type2);
|
|
||||||
Type* direct_intersection = T.Intersect(type1, type2);
|
|
||||||
Type* representation_intersection =
|
|
||||||
T.Intersect(representation1, representation2);
|
|
||||||
Type* semantic_intersection = T.Intersect(semantic1, semantic2);
|
|
||||||
Type* composed_intersection =
|
|
||||||
T.Union(representation_intersection, semantic_intersection);
|
|
||||||
CHECK(direct_intersection->Equals(composed_intersection));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pointwiseness of Is.
|
|
||||||
for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
|
|
||||||
for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
|
|
||||||
Type* type1 = *it1;
|
|
||||||
Type* type2 = *it2;
|
|
||||||
Type* representation1 = T.Representation(type1);
|
|
||||||
Type* semantic1 = T.Semantic(type1);
|
|
||||||
Type* representation2 = T.Representation(type2);
|
|
||||||
Type* semantic2 = T.Semantic(type2);
|
|
||||||
bool representation_is = representation1->Is(representation2);
|
|
||||||
bool semantic_is = semantic1->Is(semantic2);
|
|
||||||
bool direct_is = type1->Is(type2);
|
|
||||||
CHECK(direct_is == (semantic_is && representation_is));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Constant() {
|
void Constant() {
|
||||||
// Constructor
|
// Constructor
|
||||||
for (ValueIterator vt = T.values.begin(); vt != T.values.end(); ++vt) {
|
for (ValueIterator vt = T.values.begin(); vt != T.values.end(); ++vt) {
|
||||||
@ -1153,8 +1087,6 @@ struct Tests {
|
|||||||
|
|
||||||
TEST(IsSomeType) { Tests().IsSomeType(); }
|
TEST(IsSomeType) { Tests().IsSomeType(); }
|
||||||
|
|
||||||
TEST(PointwiseRepresentation) { Tests().PointwiseRepresentation(); }
|
|
||||||
|
|
||||||
TEST(BitsetType) { Tests().Bitset(); }
|
TEST(BitsetType) { Tests().Bitset(); }
|
||||||
|
|
||||||
TEST(ConstantType) { Tests().Constant(); }
|
TEST(ConstantType) { Tests().Constant(); }
|
||||||
|
@ -108,9 +108,6 @@ class Types {
|
|||||||
PROPER_BITSET_TYPE_LIST(DECLARE_TYPE)
|
PROPER_BITSET_TYPE_LIST(DECLARE_TYPE)
|
||||||
#undef DECLARE_TYPE
|
#undef DECLARE_TYPE
|
||||||
|
|
||||||
#define DECLARE_TYPE(name, value) Type* Mask##name##ForTesting;
|
|
||||||
MASK_BITSET_TYPE_LIST(DECLARE_TYPE)
|
|
||||||
#undef DECLARE_TYPE
|
|
||||||
Type* SignedSmall;
|
Type* SignedSmall;
|
||||||
Type* UnsignedSmall;
|
Type* UnsignedSmall;
|
||||||
|
|
||||||
@ -142,10 +139,6 @@ class Types {
|
|||||||
|
|
||||||
Type* Intersect(Type* t1, Type* t2) { return Type::Intersect(t1, t2, zone_); }
|
Type* Intersect(Type* t1, Type* t2) { return Type::Intersect(t1, t2, zone_); }
|
||||||
|
|
||||||
Type* Representation(Type* t) { return Type::Representation(t, zone_); }
|
|
||||||
|
|
||||||
Type* Semantic(Type* t) { return Type::Semantic(t, zone_); }
|
|
||||||
|
|
||||||
Type* Random() {
|
Type* Random() {
|
||||||
return types[rng_->NextInt(static_cast<int>(types.size()))];
|
return types[rng_->NextInt(static_cast<int>(types.size()))];
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user