}
-// The smallest bitset subsuming this type.
+// The smallest bitset subsuming this type, possibly not a proper one.
template<class Config>
typename TypeImpl<Config>::bitset
TypeImpl<Config>::BitsetType::Lub(TypeImpl* type) {
}
return bitset;
}
- if (type->IsClass()) {
- // 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();
- }
- if (type->IsConstant()) return type->AsConstant()->Bound()->AsBitset();
- if (type->IsRange()) return type->AsRange()->Bound();
+ if (type->IsClass()) return type->AsClass()->Lub();
+ if (type->IsConstant()) return type->AsConstant()->Lub();
+ if (type->IsRange()) return type->AsRange()->Lub();
if (type->IsContext()) return kInternal & kTaggedPointer;
if (type->IsArray()) return kOtherObject;
if (type->IsFunction()) return kOtherObject; // TODO(rossberg): kFunction
if (i::IsMinusZero(value)) return kMinusZero;
if (std::isnan(value)) return kNaN;
if (IsUint32Double(value) || IsInt32Double(value)) return Lub(value, value);
- return kPlainNumber;
+ return kOtherNumber;
}
-// Minimum values of regular numeric bitsets.
+// Minimum values of plain numeric bitsets.
template <class Config>
const typename TypeImpl<Config>::BitsetType::Boundary
- TypeImpl<Config>::BitsetType::BoundariesArray[] = {
- {kPlainNumber, -V8_INFINITY},
- {kNegative32, kMinInt},
- {kNegative31, -0x40000000},
- {kUnsigned30, 0},
- {kUnsigned31, 0x40000000},
- {kUnsigned32, 0x80000000},
- {kPlainNumber, static_cast<double>(kMaxUInt32) + 1}
-};
+TypeImpl<Config>::BitsetType::BoundariesArray[] = {
+ {kOtherNumber, kPlainNumber, -V8_INFINITY},
+ {kOtherSigned32, kNegative32, kMinInt},
+ {kNegative31, kNegative31, -0x40000000},
+ {kUnsigned30, kUnsigned30, 0},
+ {kOtherUnsigned31, kUnsigned31, 0x40000000},
+ {kOtherUnsigned32, kUnsigned32, 0x80000000},
+ {kOtherNumber, kPlainNumber, static_cast<double>(kMaxUInt32) + 1}};
template <class Config>
}
+template <class Config>
+typename TypeImpl<Config>::bitset TypeImpl<Config>::BitsetType::ExpandInternals(
+ typename TypeImpl<Config>::bitset bits) {
+ DisallowHeapAllocation no_allocation;
+ if (!(bits & SEMANTIC(kPlainNumber))) return bits; // Shortcut.
+ const Boundary* boundaries = Boundaries();
+ for (size_t i = 0; i < BoundariesSize(); ++i) {
+ DCHECK(BitsetType::Is(boundaries[i].internal, boundaries[i].external));
+ if (bits & SEMANTIC(boundaries[i].internal))
+ bits |= SEMANTIC(boundaries[i].external);
+ }
+ return bits;
+}
+
+
template<class Config>
typename TypeImpl<Config>::bitset
TypeImpl<Config>::BitsetType::Lub(double min, double max) {
int lub = kNone;
const Boundary* mins = Boundaries();
- // Make sure the min-max range touches 0, so we are guaranteed no holes
- // in unions of valid bitsets.
- if (max < -1) max = -1;
- if (min > 0) min = 0;
-
for (size_t i = 1; i < BoundariesSize(); ++i) {
if (min < mins[i].min) {
- lub |= mins[i-1].bits;
+ lub |= mins[i-1].internal;
if (max < mins[i].min) return lub;
}
}
- return lub |= mins[BoundariesSize() - 1].bits;
+ return lub | mins[BoundariesSize() - 1].internal;
}
template <class Config>
-void TypeImpl<Config>::BitsetType::CheckNumberBits(bitset bits) {
- // Check that the bitset does not contain any holes in number ranges.
- bitset number_bits = NumberBits(bits);
- if (number_bits != 0) {
- bitset lub = SEMANTIC(Lub(Min(number_bits), Max(number_bits)));
- CHECK(lub == number_bits);
- }
-}
-
-template <class Config>
typename TypeImpl<Config>::bitset TypeImpl<Config>::BitsetType::Glb(
double min, double max) {
DisallowHeapAllocation no_allocation;
for (size_t i = 1; i + 1 < BoundariesSize(); ++i) {
if (min <= mins[i].min) {
if (max + 1 < mins[i + 1].min) break;
- glb |= mins[i].bits;
+ glb |= mins[i].external;
}
}
// OtherNumber also contains float numbers, so it can never be
- // in the greatest lower bound. (There is also the small trouble
- // of kOtherNumber having a range hole, which we can conveniently
- // ignore here.)
+ // in the greatest lower bound.
return glb & ~(SEMANTIC(kOtherNumber));
}
const Boundary* mins = Boundaries();
bool mz = SEMANTIC(bits & kMinusZero);
for (size_t i = 0; i < BoundariesSize(); ++i) {
- if (Is(SEMANTIC(mins[i].bits), bits)) {
+ if (Is(SEMANTIC(mins[i].internal), bits)) {
return mz ? std::min(0.0, mins[i].min) : mins[i].min;
}
}
DCHECK(Is(SEMANTIC(bits), kNumber));
const Boundary* mins = Boundaries();
bool mz = SEMANTIC(bits & kMinusZero);
- if (BitsetType::Is(SEMANTIC(mins[BoundariesSize() - 1].bits), bits)) {
+ if (BitsetType::Is(SEMANTIC(mins[BoundariesSize() - 1].internal), bits)) {
return +V8_INFINITY;
}
for (size_t i = BoundariesSize() - 1; i-- > 0;) {
- if (Is(SEMANTIC(mins[i].bits), bits)) {
+ if (Is(SEMANTIC(mins[i].internal), bits)) {
return mz ?
std::max(0.0, mins[i+1].min - 1) : mins[i+1].min - 1;
}
// If the range is semantically contained within the bitset, return None and
// leave the bitset untouched.
bitset range_lub = SEMANTIC(range->BitsetLub());
- if (BitsetType::Is(BitsetType::NumberBits(range_lub), *bits)) {
+ if (BitsetType::Is(range_lub, *bits)) {
return None(region);
}
double range_max = range->Max();
// Remove the number bits from the bitset, they would just confuse us now.
+ // NOTE: bits contains OtherNumber iff bits contains PlainNumber, in which
+ // case we already returned after the subtype check above.
*bits &= ~number_bits;
if (range_min <= bitset_min && range_max >= bitset_max) {
* -2^31 -2^30 0 2^30 2^31 2^32
*
* E.g., OtherUnsigned32 (OU32) covers all integers from 2^31 to 2^32-1.
+ *
+ * Some of the atomic numerical bitsets are internal only (see
+ * INTERNAL_BITSET_TYPE_LIST). To a types user, they should only occur in
+ * union with certain other bitsets. For instance, OtherNumber should only
+ * occur as part of PlainNumber.
*/
#define PROPER_BITSET_TYPE_LIST(V) \
static TypeHandle Intersect(TypeHandle type1, TypeHandle type2, Region* reg);
static TypeHandle Of(double value, Region* region) {
- return Config::from_bitset(BitsetType::Lub(value), region);
+ return Config::from_bitset(BitsetType::ExpandInternals(
+ BitsetType::Lub(value)), region);
}
static TypeHandle Of(i::Object* value, Region* region) {
- return Config::from_bitset(BitsetType::Lub(value), region);
+ return Config::from_bitset(BitsetType::ExpandInternals(
+ BitsetType::Lub(value)), region);
}
static TypeHandle Of(i::Handle<i::Object> value, Region* region) {
return Of(*value, region);
bitset Bitset() { return Config::as_bitset(this); }
static TypeImpl* New(bitset bits) {
- if (FLAG_enable_slow_asserts) CheckNumberBits(bits);
return Config::from_bitset(bits);
}
static TypeHandle New(bitset bits, Region* region) {
- if (FLAG_enable_slow_asserts) CheckNumberBits(bits);
return Config::from_bitset(bits, region);
}
static bitset Lub(i::Object* value);
static bitset Lub(double value);
static bitset Lub(double min, double max);
+ static bitset ExpandInternals(bitset bits);
static const char* Name(bitset);
static void Print(std::ostream& os, bitset); // NOLINT
private:
struct Boundary {
- bitset bits;
+ bitset internal;
+ bitset external;
double min;
};
static const Boundary BoundariesArray[];
static inline const Boundary* Boundaries();
static inline size_t BoundariesSize();
-
- static void CheckNumberBits(bitset bits);
};
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);
DCHECK(type->IsClass());
return static_cast<ClassType*>(type);
}
+
+ private:
+ template<class> friend class TypeImpl;
+ bitset Lub() {
+ return Config::is_class(this) ?
+ BitsetType::Lub(*Config::as_class(this)) :
+ this->Get(0)->AsBitset();
+ }
};
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, Region* region) {
DCHECK(type->IsConstant());
return static_cast<ConstantType*>(type);
}
+
+ private:
+ template<class> friend class TypeImpl;
+ bitset Lub() { return this->Get(0)->AsBitset(); }
};
// TODO(neis): Also cache value if numerical.
// TODO(neis): Allow restricting the representation.
template <class Config>
class TypeImpl<Config>::RangeType : public TypeImpl<Config> {
public:
- bitset Bound() { return Config::range_get_bitset(Config::as_range(this)); }
double Min() { return Config::range_get_double(Config::as_range(this), 0); }
double Max() { return Config::range_get_double(Config::as_range(this), 1); }
DCHECK(type->IsRange());
return static_cast<RangeType*>(type);
}
+
+ private:
+ template<class> friend class TypeImpl;
+ bitset Lub() {
+ return Config::range_get_bitset(Config::as_range(this));
+ }
};
-// TODO(neis): Also cache min and max values.
// -----------------------------------------------------------------------------