[turbofan] Use unboxed doubles in range types.
BUG= R=bmeurer@chromium.org Review URL: https://codereview.chromium.org/882063002 Cr-Commit-Position: refs/heads/master@{#26307}
This commit is contained in:
parent
b3de173d16
commit
3c9f98516c
@ -30,26 +30,23 @@ static void RelaxEffects(Node* node) {
|
||||
|
||||
JSTypedLowering::JSTypedLowering(JSGraph* jsgraph, Zone* zone)
|
||||
: jsgraph_(jsgraph), simplified_(graph()->zone()), conversions_(zone) {
|
||||
Handle<Object> zero = factory()->NewNumber(0.0);
|
||||
Handle<Object> one = factory()->NewNumber(1.0);
|
||||
zero_range_ = Type::Range(zero, zero, graph()->zone());
|
||||
one_range_ = Type::Range(one, one, graph()->zone());
|
||||
Handle<Object> thirtyone = factory()->NewNumber(31.0);
|
||||
zero_thirtyone_range_ = Type::Range(zero, thirtyone, graph()->zone());
|
||||
zero_range_ = Type::Range(0.0, 1.0, graph()->zone());
|
||||
one_range_ = Type::Range(1.0, 1.0, graph()->zone());
|
||||
zero_thirtyone_range_ = Type::Range(0.0, 31.0, graph()->zone());
|
||||
// TODO(jarin): Can we have a correctification of the stupid type system?
|
||||
// These stupid work-arounds are just stupid!
|
||||
shifted_int32_ranges_[0] = Type::Signed32();
|
||||
if (SmiValuesAre31Bits()) {
|
||||
shifted_int32_ranges_[1] = Type::SignedSmall();
|
||||
for (size_t k = 2; k < arraysize(shifted_int32_ranges_); ++k) {
|
||||
Handle<Object> min = factory()->NewNumber(kMinInt / (1 << k));
|
||||
Handle<Object> max = factory()->NewNumber(kMaxInt / (1 << k));
|
||||
double min = kMinInt / (1 << k);
|
||||
double max = kMaxInt / (1 << k);
|
||||
shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone());
|
||||
}
|
||||
} else {
|
||||
for (size_t k = 1; k < arraysize(shifted_int32_ranges_); ++k) {
|
||||
Handle<Object> min = factory()->NewNumber(kMinInt / (1 << k));
|
||||
Handle<Object> max = factory()->NewNumber(kMaxInt / (1 << k));
|
||||
double min = kMinInt / (1 << k);
|
||||
double max = kMaxInt / (1 << k);
|
||||
shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone());
|
||||
}
|
||||
}
|
||||
|
@ -75,10 +75,8 @@ class RepresentationSelector {
|
||||
queue_(zone) {
|
||||
memset(info_, 0, sizeof(NodeInfo) * count_);
|
||||
|
||||
Factory* f = jsgraph->isolate()->factory();
|
||||
safe_int_additive_range_ =
|
||||
Type::Range(f->NewNumber(-std::pow(2.0, 52.0)),
|
||||
f->NewNumber(std::pow(2.0, 52.0)), zone);
|
||||
Type::Range(-std::pow(2.0, 52.0), std::pow(2.0, 52.0), zone);
|
||||
}
|
||||
|
||||
void Run(SimplifiedLowering* lowering) {
|
||||
|
@ -129,8 +129,7 @@ class LazyTypeCache FINAL : public ZoneObject {
|
||||
}
|
||||
|
||||
Type* CreateRange(double min, double max) const {
|
||||
return Type::Range(factory()->NewNumber(min), factory()->NewNumber(max),
|
||||
zone());
|
||||
return Type::Range(min, max, zone());
|
||||
}
|
||||
|
||||
Factory* factory() const { return isolate()->factory(); }
|
||||
@ -164,8 +163,6 @@ Typer::Typer(Isolate* isolate, Graph* graph, MaybeHandle<Context> context)
|
||||
Zone* zone = this->zone();
|
||||
Factory* f = isolate->factory();
|
||||
|
||||
Handle<Object> zero = f->NewNumber(0);
|
||||
Handle<Object> one = f->NewNumber(1);
|
||||
Handle<Object> infinity = f->NewNumber(+V8_INFINITY);
|
||||
Handle<Object> minusinfinity = f->NewNumber(-V8_INFINITY);
|
||||
|
||||
@ -183,8 +180,8 @@ Typer::Typer(Isolate* isolate, Graph* graph, MaybeHandle<Context> context)
|
||||
undefined_or_number = Type::Union(Type::Undefined(), Type::Number(), zone);
|
||||
singleton_false = Type::Constant(f->false_value(), zone);
|
||||
singleton_true = Type::Constant(f->true_value(), zone);
|
||||
singleton_zero = Type::Range(zero, zero, zone);
|
||||
singleton_one = Type::Range(one, one, zone);
|
||||
singleton_zero = Type::Range(0.0, 0.0, zone);
|
||||
singleton_one = Type::Range(1.0, 1.0, zone);
|
||||
zero_or_one = Type::Union(singleton_zero, singleton_one, zone);
|
||||
zeroish = Type::Union(singleton_zero, nan_or_minuszero, zone);
|
||||
signed32ish = Type::Union(signed32, truncating_to_zero, zone);
|
||||
@ -196,7 +193,7 @@ Typer::Typer(Isolate* isolate, Graph* graph, MaybeHandle<Context> context)
|
||||
truish = Type::Union(
|
||||
singleton_true,
|
||||
Type::Union(Type::DetectableReceiver(), Type::Symbol(), zone), zone);
|
||||
integer = Type::Range(minusinfinity, infinity, zone);
|
||||
integer = Type::Range(-V8_INFINITY, V8_INFINITY, zone);
|
||||
weakint = Type::Union(integer, nan_or_minuszero, zone);
|
||||
|
||||
number_fun0_ = Type::Function(number, zone);
|
||||
@ -212,11 +209,11 @@ Typer::Typer(Isolate* isolate, Graph* graph, MaybeHandle<Context> context)
|
||||
weaken_max_limits_.reserve(limits_count + 1);
|
||||
|
||||
double limit = 1 << 30;
|
||||
weaken_min_limits_.push_back(f->NewNumber(0));
|
||||
weaken_max_limits_.push_back(f->NewNumber(0));
|
||||
weaken_min_limits_.push_back(0);
|
||||
weaken_max_limits_.push_back(0);
|
||||
for (int i = 0; i < limits_count; i++) {
|
||||
weaken_min_limits_.push_back(f->NewNumber(-limit));
|
||||
weaken_max_limits_.push_back(f->NewNumber(limit - 1));
|
||||
weaken_min_limits_.push_back(-limit);
|
||||
weaken_max_limits_.push_back(limit - 1);
|
||||
limit *= 2;
|
||||
}
|
||||
|
||||
@ -496,8 +493,7 @@ Type* Typer::Visitor::Rangify(Type* type, Typer* t) {
|
||||
DCHECK(std::isnan(max));
|
||||
return type;
|
||||
}
|
||||
Factory* f = t->isolate()->factory();
|
||||
return Type::Range(f->NewNumber(min), f->NewNumber(max), t->zone());
|
||||
return Type::Range(min, max, t->zone());
|
||||
}
|
||||
|
||||
|
||||
@ -610,8 +606,7 @@ Bounds Typer::Visitor::TypeOsrValue(Node* node) {
|
||||
|
||||
|
||||
Bounds Typer::Visitor::TypeInt32Constant(Node* node) {
|
||||
Factory* f = isolate()->factory();
|
||||
Handle<Object> number = f->NewNumber(OpParameter<int32_t>(node));
|
||||
double number = OpParameter<int32_t>(node);
|
||||
return Bounds(Type::Intersect(
|
||||
Type::Range(number, number, zone()), Type::UntaggedSigned32(), zone()));
|
||||
}
|
||||
@ -826,7 +821,6 @@ Type* Typer::Visitor::JSGreaterThanOrEqualTyper(
|
||||
|
||||
|
||||
Type* Typer::Visitor::JSBitwiseOrTyper(Type* lhs, Type* rhs, Typer* t) {
|
||||
Factory* f = t->isolate()->factory();
|
||||
lhs = NumberToInt32(ToNumber(lhs, t), t);
|
||||
rhs = NumberToInt32(ToNumber(rhs, t), t);
|
||||
double lmin = lhs->Min();
|
||||
@ -854,13 +848,12 @@ Type* Typer::Visitor::JSBitwiseOrTyper(Type* lhs, Type* rhs, Typer* t) {
|
||||
// value.
|
||||
max = std::min(max, -1.0);
|
||||
}
|
||||
return Type::Range(f->NewNumber(min), f->NewNumber(max), t->zone());
|
||||
return Type::Range(min, max, t->zone());
|
||||
// TODO(neis): Be precise for singleton inputs, here and elsewhere.
|
||||
}
|
||||
|
||||
|
||||
Type* Typer::Visitor::JSBitwiseAndTyper(Type* lhs, Type* rhs, Typer* t) {
|
||||
Factory* f = t->isolate()->factory();
|
||||
lhs = NumberToInt32(ToNumber(lhs, t), t);
|
||||
rhs = NumberToInt32(ToNumber(rhs, t), t);
|
||||
double lmin = lhs->Min();
|
||||
@ -882,7 +875,7 @@ Type* Typer::Visitor::JSBitwiseAndTyper(Type* lhs, Type* rhs, Typer* t) {
|
||||
min = 0;
|
||||
max = std::min(max, rmax);
|
||||
}
|
||||
return Type::Range(f->NewNumber(min), f->NewNumber(max), t->zone());
|
||||
return Type::Range(min, max, t->zone());
|
||||
}
|
||||
|
||||
|
||||
@ -942,8 +935,7 @@ Type* Typer::Visitor::JSShiftRightTyper(Type* lhs, Type* rhs, Typer* t) {
|
||||
// TODO(jarin) Ideally, the following micro-optimization should be performed
|
||||
// by the type constructor.
|
||||
if (max != Type::Signed32()->Max() || min != Type::Signed32()->Min()) {
|
||||
Factory* f = t->isolate()->factory();
|
||||
return Type::Range(f->NewNumber(min), f->NewNumber(max), t->zone());
|
||||
return Type::Range(min, max, t->zone());
|
||||
}
|
||||
return Type::Signed32();
|
||||
}
|
||||
@ -951,11 +943,8 @@ Type* Typer::Visitor::JSShiftRightTyper(Type* lhs, Type* rhs, Typer* t) {
|
||||
|
||||
Type* Typer::Visitor::JSShiftRightLogicalTyper(Type* lhs, Type* rhs, Typer* t) {
|
||||
lhs = NumberToUint32(ToNumber(lhs, t), t);
|
||||
Factory* f = t->isolate()->factory();
|
||||
// Logical right-shifting any value cannot make it larger.
|
||||
Handle<Object> min = f->NewNumber(0);
|
||||
Handle<Object> max = f->NewNumber(lhs->Max());
|
||||
return Type::Range(min, max, t->zone());
|
||||
return Type::Range(0.0, lhs->Max(), t->zone());
|
||||
}
|
||||
|
||||
|
||||
@ -997,10 +986,10 @@ static double array_max(double a[], size_t n) {
|
||||
Type* Typer::Visitor::JSAddRanger(Type::RangeType* lhs, Type::RangeType* rhs,
|
||||
Typer* t) {
|
||||
double results[4];
|
||||
results[0] = lhs->Min()->Number() + rhs->Min()->Number();
|
||||
results[1] = lhs->Min()->Number() + rhs->Max()->Number();
|
||||
results[2] = lhs->Max()->Number() + rhs->Min()->Number();
|
||||
results[3] = lhs->Max()->Number() + rhs->Max()->Number();
|
||||
results[0] = lhs->Min() + rhs->Min();
|
||||
results[1] = lhs->Min() + rhs->Max();
|
||||
results[2] = lhs->Max() + rhs->Min();
|
||||
results[3] = lhs->Max() + rhs->Max();
|
||||
// Since none of the inputs can be -0, the result cannot be -0 either.
|
||||
// However, it can be nan (the sum of two infinities of opposite sign).
|
||||
// On the other hand, if none of the "results" above is nan, then the actual
|
||||
@ -1010,9 +999,8 @@ Type* Typer::Visitor::JSAddRanger(Type::RangeType* lhs, Type::RangeType* rhs,
|
||||
if (std::isnan(results[i])) ++nans;
|
||||
}
|
||||
if (nans == 4) return Type::NaN(); // [-inf..-inf] + [inf..inf] or vice versa
|
||||
Factory* f = t->isolate()->factory();
|
||||
Type* range = Type::Range(f->NewNumber(array_min(results, 4)),
|
||||
f->NewNumber(array_max(results, 4)), t->zone());
|
||||
Type* range =
|
||||
Type::Range(array_min(results, 4), array_max(results, 4), t->zone());
|
||||
return nans == 0 ? range : Type::Union(range, Type::NaN(), t->zone());
|
||||
// Examples:
|
||||
// [-inf, -inf] + [+inf, +inf] = NaN
|
||||
@ -1046,10 +1034,10 @@ Type* Typer::Visitor::JSAddTyper(Type* lhs, Type* rhs, Typer* t) {
|
||||
Type* Typer::Visitor::JSSubtractRanger(Type::RangeType* lhs,
|
||||
Type::RangeType* rhs, Typer* t) {
|
||||
double results[4];
|
||||
results[0] = lhs->Min()->Number() - rhs->Min()->Number();
|
||||
results[1] = lhs->Min()->Number() - rhs->Max()->Number();
|
||||
results[2] = lhs->Max()->Number() - rhs->Min()->Number();
|
||||
results[3] = lhs->Max()->Number() - rhs->Max()->Number();
|
||||
results[0] = lhs->Min() - rhs->Min();
|
||||
results[1] = lhs->Min() - rhs->Max();
|
||||
results[2] = lhs->Max() - rhs->Min();
|
||||
results[3] = lhs->Max() - rhs->Max();
|
||||
// Since none of the inputs can be -0, the result cannot be -0.
|
||||
// However, it can be nan (the subtraction of two infinities of same sign).
|
||||
// On the other hand, if none of the "results" above is nan, then the actual
|
||||
@ -1059,9 +1047,8 @@ Type* Typer::Visitor::JSSubtractRanger(Type::RangeType* lhs,
|
||||
if (std::isnan(results[i])) ++nans;
|
||||
}
|
||||
if (nans == 4) return Type::NaN(); // [inf..inf] - [inf..inf] (all same sign)
|
||||
Factory* f = t->isolate()->factory();
|
||||
Type* range = Type::Range(f->NewNumber(array_min(results, 4)),
|
||||
f->NewNumber(array_max(results, 4)), t->zone());
|
||||
Type* range =
|
||||
Type::Range(array_min(results, 4), array_max(results, 4), t->zone());
|
||||
return nans == 0 ? range : Type::Union(range, Type::NaN(), t->zone());
|
||||
// Examples:
|
||||
// [-inf, +inf] - [-inf, +inf] = [-inf, +inf] \/ NaN
|
||||
@ -1085,10 +1072,10 @@ Type* Typer::Visitor::JSSubtractTyper(Type* lhs, Type* rhs, Typer* t) {
|
||||
Type* Typer::Visitor::JSMultiplyRanger(Type::RangeType* lhs,
|
||||
Type::RangeType* rhs, Typer* t) {
|
||||
double results[4];
|
||||
double lmin = lhs->Min()->Number();
|
||||
double lmax = lhs->Max()->Number();
|
||||
double rmin = rhs->Min()->Number();
|
||||
double rmax = rhs->Max()->Number();
|
||||
double lmin = lhs->Min();
|
||||
double lmax = lhs->Max();
|
||||
double rmin = rhs->Min();
|
||||
double rmax = rhs->Max();
|
||||
results[0] = lmin * rmin;
|
||||
results[1] = lmin * rmax;
|
||||
results[2] = lmax * rmin;
|
||||
@ -1104,9 +1091,8 @@ Type* Typer::Visitor::JSMultiplyRanger(Type::RangeType* lhs,
|
||||
if (maybe_nan) return t->weakint; // Giving up.
|
||||
bool maybe_minuszero = (lhs->Maybe(t->singleton_zero) && rmin < 0) ||
|
||||
(rhs->Maybe(t->singleton_zero) && lmin < 0);
|
||||
Factory* f = t->isolate()->factory();
|
||||
Type* range = Type::Range(f->NewNumber(array_min(results, 4)),
|
||||
f->NewNumber(array_max(results, 4)), t->zone());
|
||||
Type* range =
|
||||
Type::Range(array_min(results, 4), array_max(results, 4), t->zone());
|
||||
return maybe_minuszero ? Type::Union(range, Type::MinusZero(), t->zone())
|
||||
: range;
|
||||
}
|
||||
@ -1139,10 +1125,10 @@ Type* Typer::Visitor::JSDivideTyper(Type* lhs, Type* rhs, Typer* t) {
|
||||
|
||||
Type* Typer::Visitor::JSModulusRanger(Type::RangeType* lhs,
|
||||
Type::RangeType* rhs, Typer* t) {
|
||||
double lmin = lhs->Min()->Number();
|
||||
double lmax = lhs->Max()->Number();
|
||||
double rmin = rhs->Min()->Number();
|
||||
double rmax = rhs->Max()->Number();
|
||||
double lmin = lhs->Min();
|
||||
double lmax = lhs->Max();
|
||||
double rmin = rhs->Min();
|
||||
double rmax = rhs->Max();
|
||||
|
||||
double labs = std::max(std::abs(lmin), std::abs(lmax));
|
||||
double rabs = std::max(std::abs(rmin), std::abs(rmax)) - 1;
|
||||
@ -1163,8 +1149,7 @@ Type* Typer::Visitor::JSModulusRanger(Type::RangeType* lhs,
|
||||
maybe_minus_zero = true;
|
||||
}
|
||||
|
||||
Factory* f = t->isolate()->factory();
|
||||
Type* result = Type::Range(f->NewNumber(omin), f->NewNumber(omax), t->zone());
|
||||
Type* result = Type::Range(omin, omax, t->zone());
|
||||
if (maybe_minus_zero)
|
||||
result = Type::Union(result, Type::MinusZero(), t->zone());
|
||||
return result;
|
||||
@ -1287,29 +1272,28 @@ Type* Typer::Visitor::Weaken(Type* current_type, Type* previous_type) {
|
||||
Type::RangeType* previous = previous_number->AsRange();
|
||||
Type::RangeType* current = current_number->AsRange();
|
||||
|
||||
double current_min = current->Min()->Number();
|
||||
Handle<Object> new_min = current->Min();
|
||||
|
||||
double current_min = current->Min();
|
||||
double new_min = current_min;
|
||||
// Find the closest lower entry in the list of allowed
|
||||
// minima (or negative infinity if there is no such entry).
|
||||
if (current_min != previous->Min()->Number()) {
|
||||
if (current_min != previous->Min()) {
|
||||
new_min = typer_->integer->AsRange()->Min();
|
||||
for (const auto val : typer_->weaken_min_limits_) {
|
||||
if (val->Number() <= current_min) {
|
||||
if (val <= current_min) {
|
||||
new_min = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double current_max = current->Max()->Number();
|
||||
Handle<Object> new_max = current->Max();
|
||||
double current_max = current->Max();
|
||||
double new_max = current_max;
|
||||
// Find the closest greater entry in the list of allowed
|
||||
// maxima (or infinity if there is no such entry).
|
||||
if (current_max != previous->Max()->Number()) {
|
||||
if (current_max != previous->Max()) {
|
||||
new_max = typer_->integer->AsRange()->Max();
|
||||
for (const auto val : typer_->weaken_max_limits_) {
|
||||
if (val->Number() >= current_max) {
|
||||
if (val >= current_max) {
|
||||
new_max = val;
|
||||
break;
|
||||
}
|
||||
|
@ -65,8 +65,8 @@ class Typer {
|
||||
Type* random_fun_;
|
||||
LazyTypeCache* cache_;
|
||||
|
||||
ZoneVector<Handle<Object> > weaken_min_limits_;
|
||||
ZoneVector<Handle<Object> > weaken_max_limits_;
|
||||
ZoneVector<double> weaken_min_limits_;
|
||||
ZoneVector<double> weaken_max_limits_;
|
||||
DISALLOW_COPY_AND_ASSIGN(Typer);
|
||||
};
|
||||
|
||||
|
126
src/types-inl.h
126
src/types-inl.h
@ -96,7 +96,18 @@ bool ZoneTypeConfig::is_bitset(Type* type) {
|
||||
|
||||
// static
|
||||
bool ZoneTypeConfig::is_struct(Type* type, int tag) {
|
||||
return !is_bitset(type) && struct_tag(as_struct(type)) == tag;
|
||||
DCHECK(tag != kRangeStructTag);
|
||||
if (is_bitset(type)) return false;
|
||||
int type_tag = struct_tag(as_struct(type));
|
||||
return type_tag == tag;
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
bool ZoneTypeConfig::is_range(Type* type) {
|
||||
if (is_bitset(type)) return false;
|
||||
int type_tag = struct_tag(as_struct(type));
|
||||
return type_tag == kRangeStructTag;
|
||||
}
|
||||
|
||||
|
||||
@ -120,6 +131,13 @@ ZoneTypeConfig::Struct* ZoneTypeConfig::as_struct(Type* type) {
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
ZoneTypeConfig::Range* ZoneTypeConfig::as_range(Type* type) {
|
||||
DCHECK(!is_bitset(type));
|
||||
return reinterpret_cast<Range*>(type);
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
i::Handle<i::Map> ZoneTypeConfig::as_class(Type* type) {
|
||||
UNREACHABLE();
|
||||
@ -146,6 +164,12 @@ ZoneTypeConfig::Type* ZoneTypeConfig::from_struct(Struct* structure) {
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
ZoneTypeConfig::Type* ZoneTypeConfig::from_range(Range* range) {
|
||||
return reinterpret_cast<Type*>(range);
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
ZoneTypeConfig::Type* ZoneTypeConfig::from_class(
|
||||
i::Handle<i::Map> map, Zone* zone) {
|
||||
@ -156,6 +180,7 @@ ZoneTypeConfig::Type* ZoneTypeConfig::from_class(
|
||||
// static
|
||||
ZoneTypeConfig::Struct* ZoneTypeConfig::struct_create(
|
||||
int tag, int length, Zone* zone) {
|
||||
DCHECK(tag != kRangeStructTag);
|
||||
Struct* structure = reinterpret_cast<Struct*>(
|
||||
zone->New(sizeof(void*) * (length + 2))); // NOLINT
|
||||
structure[0] = reinterpret_cast<void*>(tag);
|
||||
@ -214,6 +239,45 @@ void ZoneTypeConfig::struct_set_value(
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
ZoneTypeConfig::Range* ZoneTypeConfig::range_create(Zone* zone) {
|
||||
Range* range = reinterpret_cast<Range*>(zone->New(sizeof(Range))); // NOLINT
|
||||
range->tag = reinterpret_cast<void*>(kRangeStructTag);
|
||||
range->bitset = 0;
|
||||
range->limits[0] = 1;
|
||||
range->limits[1] = 0;
|
||||
return range;
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
int ZoneTypeConfig::range_get_bitset(ZoneTypeConfig::Range* range) {
|
||||
return range->bitset;
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
void ZoneTypeConfig::range_set_bitset(ZoneTypeConfig::Range* range, int value) {
|
||||
range->bitset = value;
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
double ZoneTypeConfig::range_get_double(ZoneTypeConfig::Range* range,
|
||||
int index) {
|
||||
DCHECK(index >= 0 && index < 2);
|
||||
return range->limits[index];
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
void ZoneTypeConfig::range_set_double(ZoneTypeConfig::Range* range, int index,
|
||||
double value, Zone*) {
|
||||
DCHECK(index >= 0 && index < 2);
|
||||
range->limits[index] = value;
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// HeapTypeConfig
|
||||
|
||||
@ -252,10 +316,17 @@ bool HeapTypeConfig::is_class(Type* type) {
|
||||
|
||||
// static
|
||||
bool HeapTypeConfig::is_struct(Type* type, int tag) {
|
||||
DCHECK(tag != kRangeStructTag);
|
||||
return type->IsFixedArray() && struct_tag(as_struct(type)) == tag;
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
bool HeapTypeConfig::is_range(Type* type) {
|
||||
return type->IsFixedArray() && struct_tag(as_struct(type)) == kRangeStructTag;
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
HeapTypeConfig::Type::bitset HeapTypeConfig::as_bitset(Type* type) {
|
||||
// TODO(rossberg): Breaks the Smi abstraction. Fix once there is a better way.
|
||||
@ -275,6 +346,12 @@ i::Handle<HeapTypeConfig::Struct> HeapTypeConfig::as_struct(Type* type) {
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
i::Handle<HeapTypeConfig::Range> HeapTypeConfig::as_range(Type* type) {
|
||||
return i::handle(Range::cast(type));
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
HeapTypeConfig::Type* HeapTypeConfig::from_bitset(Type::bitset bitset) {
|
||||
// TODO(rossberg): Breaks the Smi abstraction. Fix once there is a better way.
|
||||
@ -303,6 +380,13 @@ i::Handle<HeapTypeConfig::Type> HeapTypeConfig::from_struct(
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
i::Handle<HeapTypeConfig::Type> HeapTypeConfig::from_range(
|
||||
i::Handle<Range> range) {
|
||||
return i::Handle<Type>::cast(i::Handle<Object>::cast(range));
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
i::Handle<HeapTypeConfig::Struct> HeapTypeConfig::struct_create(
|
||||
int tag, int length, Isolate* isolate) {
|
||||
@ -361,6 +445,46 @@ void HeapTypeConfig::struct_set_value(
|
||||
structure->set(i + 1, *x);
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
i::Handle<HeapTypeConfig::Range> HeapTypeConfig::range_create(
|
||||
Isolate* isolate) {
|
||||
i::Handle<Range> range = isolate->factory()->NewFixedArray(4);
|
||||
range->set(0, i::Smi::FromInt(kRangeStructTag));
|
||||
return range;
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
int HeapTypeConfig::range_get_bitset(i::Handle<HeapTypeConfig::Range> range) {
|
||||
Type* v = static_cast<Type*>(range->get(1));
|
||||
return as_bitset(v);
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
void HeapTypeConfig::range_set_bitset(i::Handle<HeapTypeConfig::Range> range,
|
||||
int value) {
|
||||
range->set(1, from_bitset(value));
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
double HeapTypeConfig::range_get_double(i::Handle<HeapTypeConfig::Range> range,
|
||||
int index) {
|
||||
DCHECK(index >= 0 && index < 2);
|
||||
return range->get(index + 2)->Number();
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
void HeapTypeConfig::range_set_double(i::Handle<HeapTypeConfig::Range> range,
|
||||
int index, double value,
|
||||
Isolate* isolate) {
|
||||
DCHECK(index >= 0 && index < 2);
|
||||
i::Handle<Object> number = isolate->factory()->NewNumber(value);
|
||||
range->set(index + 2, *number);
|
||||
}
|
||||
} } // namespace v8::internal
|
||||
|
||||
#endif // V8_TYPES_INL_H_
|
||||
|
65
src/types.cc
65
src/types.cc
@ -26,8 +26,8 @@ typename TypeImpl<Config>::Limits TypeImpl<Config>::Intersect(
|
||||
Limits lhs, Limits rhs) {
|
||||
DisallowHeapAllocation no_allocation;
|
||||
Limits result(lhs);
|
||||
if (lhs.min->Number() < rhs.min->Number()) result.min = rhs.min;
|
||||
if (lhs.max->Number() > rhs.max->Number()) result.max = rhs.max;
|
||||
if (lhs.min < rhs.min) result.min = rhs.min;
|
||||
if (lhs.max > rhs.max) result.max = rhs.max;
|
||||
result.representation = lhs.representation & rhs.representation;
|
||||
return result;
|
||||
}
|
||||
@ -35,7 +35,7 @@ typename TypeImpl<Config>::Limits TypeImpl<Config>::Intersect(
|
||||
|
||||
template <class Config>
|
||||
bool TypeImpl<Config>::IsEmpty(Limits lim) {
|
||||
return lim.min->Number() > lim.max->Number();
|
||||
return lim.min > lim.max;
|
||||
}
|
||||
|
||||
|
||||
@ -44,8 +44,8 @@ typename TypeImpl<Config>::Limits TypeImpl<Config>::Union(Limits lhs,
|
||||
Limits rhs) {
|
||||
DisallowHeapAllocation no_allocation;
|
||||
Limits result(lhs);
|
||||
if (lhs.min->Number() > rhs.min->Number()) result.min = rhs.min;
|
||||
if (lhs.max->Number() < rhs.max->Number()) result.max = rhs.max;
|
||||
if (lhs.min > rhs.min) result.min = rhs.min;
|
||||
if (lhs.max < rhs.max) result.max = rhs.max;
|
||||
result.representation = lhs.representation | rhs.representation;
|
||||
return result;
|
||||
}
|
||||
@ -57,7 +57,7 @@ bool TypeImpl<Config>::Overlap(
|
||||
typename TypeImpl<Config>::RangeType* rhs) {
|
||||
DisallowHeapAllocation no_allocation;
|
||||
typename TypeImpl<Config>::Limits lim = Intersect(Limits(lhs), Limits(rhs));
|
||||
return lim.min->Number() <= lim.max->Number();
|
||||
return lim.min <= lim.max;
|
||||
}
|
||||
|
||||
|
||||
@ -66,9 +66,8 @@ bool TypeImpl<Config>::Contains(
|
||||
typename TypeImpl<Config>::RangeType* lhs,
|
||||
typename TypeImpl<Config>::RangeType* rhs) {
|
||||
DisallowHeapAllocation no_allocation;
|
||||
return rhs->Bound()->Is(lhs->Bound()) &&
|
||||
lhs->Min()->Number() <= rhs->Min()->Number() &&
|
||||
rhs->Max()->Number() <= lhs->Max()->Number();
|
||||
return BitsetType::Is(rhs->Bound(), lhs->Bound()) &&
|
||||
lhs->Min() <= rhs->Min() && rhs->Max() <= lhs->Max();
|
||||
}
|
||||
|
||||
|
||||
@ -76,9 +75,10 @@ template <class Config>
|
||||
bool TypeImpl<Config>::Contains(typename TypeImpl<Config>::RangeType* lhs,
|
||||
typename TypeImpl<Config>::ConstantType* rhs) {
|
||||
DisallowHeapAllocation no_allocation;
|
||||
return IsInteger(*rhs->Value()) && rhs->Bound()->Is(lhs->Bound()) &&
|
||||
lhs->Min()->Number() <= rhs->Value()->Number() &&
|
||||
rhs->Value()->Number() <= lhs->Max()->Number();
|
||||
return IsInteger(*rhs->Value()) &&
|
||||
BitsetType::Is(rhs->Bound()->AsBitset(), lhs->Bound()) &&
|
||||
lhs->Min() <= rhs->Value()->Number() &&
|
||||
rhs->Value()->Number() <= lhs->Max();
|
||||
}
|
||||
|
||||
|
||||
@ -87,9 +87,8 @@ bool TypeImpl<Config>::Contains(
|
||||
typename TypeImpl<Config>::RangeType* range, i::Object* val) {
|
||||
DisallowHeapAllocation no_allocation;
|
||||
return IsInteger(val) &&
|
||||
BitsetType::Is(BitsetType::Lub(val), range->Bound()->AsBitset()) &&
|
||||
range->Min()->Number() <= val->Number() &&
|
||||
val->Number() <= range->Max()->Number();
|
||||
BitsetType::Is(BitsetType::Lub(val), range->Bound()) &&
|
||||
range->Min() <= val->Number() && val->Number() <= range->Max();
|
||||
}
|
||||
|
||||
|
||||
@ -107,7 +106,7 @@ double TypeImpl<Config>::Min() {
|
||||
}
|
||||
return min;
|
||||
}
|
||||
if (this->IsRange()) return this->AsRange()->Min()->Number();
|
||||
if (this->IsRange()) return this->AsRange()->Min();
|
||||
if (this->IsConstant()) return this->AsConstant()->Value()->Number();
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
@ -125,7 +124,7 @@ double TypeImpl<Config>::Max() {
|
||||
}
|
||||
return max;
|
||||
}
|
||||
if (this->IsRange()) return this->AsRange()->Max()->Number();
|
||||
if (this->IsRange()) return this->AsRange()->Max();
|
||||
if (this->IsConstant()) return this->AsConstant()->Value()->Number();
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
@ -148,8 +147,8 @@ TypeImpl<Config>::BitsetType::Glb(TypeImpl* type) {
|
||||
return type->AsUnion()->Get(0)->BitsetGlb() |
|
||||
type->AsUnion()->Get(1)->BitsetGlb(); // Shortcut.
|
||||
} else if (type->IsRange()) {
|
||||
bitset glb = SEMANTIC(BitsetType::Glb(type->AsRange()->Min()->Number(),
|
||||
type->AsRange()->Max()->Number()));
|
||||
bitset glb = SEMANTIC(
|
||||
BitsetType::Glb(type->AsRange()->Min(), type->AsRange()->Max()));
|
||||
if (glb == 0) {
|
||||
return kNone;
|
||||
} else {
|
||||
@ -181,7 +180,7 @@ TypeImpl<Config>::BitsetType::Lub(TypeImpl* type) {
|
||||
type->AsClass()->Bound(NULL)->AsBitset();
|
||||
}
|
||||
if (type->IsConstant()) return type->AsConstant()->Bound()->AsBitset();
|
||||
if (type->IsRange()) return type->AsRange()->Bound()->AsBitset();
|
||||
if (type->IsRange()) return type->AsRange()->Bound();
|
||||
if (type->IsContext()) return kInternal & kTaggedPointer;
|
||||
if (type->IsArray()) return kArray;
|
||||
if (type->IsFunction()) return kOtherObject; // TODO(rossberg): kFunction
|
||||
@ -765,13 +764,7 @@ typename TypeImpl<Config>::Limits TypeImpl<Config>::ToLimits(bitset bits,
|
||||
return Limits::Empty(region);
|
||||
}
|
||||
|
||||
double bitset_min = BitsetType::Min(number_bits);
|
||||
double bitset_max = BitsetType::Max(number_bits);
|
||||
|
||||
// TODO(jarin) Get rid of the heap numbers.
|
||||
i::Factory* f = i::Isolate::Current()->factory();
|
||||
|
||||
return Limits(f->NewNumber(bitset_min), f->NewNumber(bitset_max),
|
||||
return Limits(BitsetType::Min(number_bits), BitsetType::Max(number_bits),
|
||||
representation);
|
||||
}
|
||||
|
||||
@ -874,10 +867,8 @@ typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::NormalizeRangeAndBitset(
|
||||
double bitset_min = BitsetType::Min(number_bits);
|
||||
double bitset_max = BitsetType::Max(number_bits);
|
||||
|
||||
i::Handle<i::Object> range_min_obj = range->Min();
|
||||
i::Handle<i::Object> range_max_obj = range->Max();
|
||||
double range_min = range_min_obj->Number();
|
||||
double range_max = range_max_obj->Number();
|
||||
double range_min = range->Min();
|
||||
double range_max = range->Max();
|
||||
|
||||
bitset range_representation = REPRESENTATION(range->BitsetLub());
|
||||
bitset bits_representation = REPRESENTATION(*bits);
|
||||
@ -897,14 +888,12 @@ typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::NormalizeRangeAndBitset(
|
||||
}
|
||||
|
||||
if (bitset_min < range_min) {
|
||||
// TODO(jarin) Get rid of the heap numbers.
|
||||
range_min_obj = i::Isolate::Current()->factory()->NewNumber(bitset_min);
|
||||
range_min = bitset_min;
|
||||
}
|
||||
if (bitset_max > range_max) {
|
||||
// TODO(jarin) Get rid of the heap numbers.
|
||||
range_max_obj = i::Isolate::Current()->factory()->NewNumber(bitset_max);
|
||||
range_max = bitset_max;
|
||||
}
|
||||
return RangeType::New(range_min_obj, range_max_obj,
|
||||
return RangeType::New(range_min, range_max,
|
||||
BitsetType::New(representation, region), region);
|
||||
}
|
||||
|
||||
@ -1227,8 +1216,8 @@ void TypeImpl<Config>::PrintTo(std::ostream& os, PrintDimension dim) {
|
||||
} else if (this->IsRange()) {
|
||||
std::ostream::fmtflags saved_flags = os.setf(std::ios::fixed);
|
||||
std::streamsize saved_precision = os.precision(0);
|
||||
os << "Range(" << this->AsRange()->Min()->Number() << ", "
|
||||
<< this->AsRange()->Max()->Number() << ")";
|
||||
os << "Range(" << this->AsRange()->Min() << ", " << this->AsRange()->Max()
|
||||
<< ")";
|
||||
os.flags(saved_flags);
|
||||
os.precision(saved_precision);
|
||||
} else if (this->IsContext()) {
|
||||
|
104
src/types.h
104
src/types.h
@ -270,21 +270,29 @@ namespace internal {
|
||||
// typedef TypeImpl<Config> Type;
|
||||
// typedef Base;
|
||||
// typedef Struct;
|
||||
// typedef Range;
|
||||
// typedef Region;
|
||||
// template<class> struct Handle { typedef type; } // No template typedefs...
|
||||
// template<class T> static Handle<T>::type null_handle();
|
||||
// template<class T> static Handle<T>::type handle(T* t); // !is_bitset(t)
|
||||
// template<class T> static Handle<T>::type cast(Handle<Type>::type);
|
||||
//
|
||||
// static bool is_bitset(Type*);
|
||||
// static bool is_class(Type*);
|
||||
// static bool is_struct(Type*, int tag);
|
||||
// static bool is_range(Type*);
|
||||
//
|
||||
// static bitset as_bitset(Type*);
|
||||
// static i::Handle<i::Map> as_class(Type*);
|
||||
// static Handle<Struct>::type as_struct(Type*);
|
||||
// static Handle<Range>::type as_range(Type*);
|
||||
//
|
||||
// static Type* from_bitset(bitset);
|
||||
// static Handle<Type>::type from_bitset(bitset, Region*);
|
||||
// static Handle<Type>::type from_class(i::Handle<Map>, Region*);
|
||||
// static Handle<Type>::type from_struct(Handle<Struct>::type, int tag);
|
||||
// static Handle<Type>::type from_range(Handle<Range>::type);
|
||||
//
|
||||
// static Handle<Struct>::type struct_create(int tag, int length, Region*);
|
||||
// static void struct_shrink(Handle<Struct>::type, int length);
|
||||
// static int struct_tag(Handle<Struct>::type);
|
||||
@ -295,6 +303,12 @@ namespace internal {
|
||||
// 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>);
|
||||
//
|
||||
// static Handle<Range>::type range_create(Region*);
|
||||
// static int range_get_bitset(Handle<Range>::type);
|
||||
// static void range_set_bitset(Handle<Range>::type, int);
|
||||
// static double range_get_double(Handle<Range>::type, int);
|
||||
// static void range_set_double(Handle<Range>::type, int, double, Region*);
|
||||
// }
|
||||
template<class Config>
|
||||
class TypeImpl : public Config::Base {
|
||||
@ -354,8 +368,7 @@ class TypeImpl : public Config::Base {
|
||||
static TypeHandle Constant(i::Handle<i::Object> value, Region* region) {
|
||||
return ConstantType::New(value, region);
|
||||
}
|
||||
static TypeHandle Range(
|
||||
i::Handle<i::Object> min, i::Handle<i::Object> max, Region* region) {
|
||||
static TypeHandle Range(double min, double max, Region* region) {
|
||||
return RangeType::New(
|
||||
min, max, BitsetType::New(REPRESENTATION(BitsetType::kTagged |
|
||||
BitsetType::kUntaggedNumber),
|
||||
@ -453,6 +466,7 @@ class TypeImpl : public Config::Base {
|
||||
|
||||
// Inspection.
|
||||
|
||||
bool IsRange() { return Config::is_range(this); }
|
||||
bool IsClass() {
|
||||
return Config::is_class(this)
|
||||
|| Config::is_struct(this, StructuralType::kClassTag);
|
||||
@ -460,9 +474,6 @@ class TypeImpl : public Config::Base {
|
||||
bool IsConstant() {
|
||||
return Config::is_struct(this, StructuralType::kConstantTag);
|
||||
}
|
||||
bool IsRange() {
|
||||
return Config::is_struct(this, StructuralType::kRangeTag);
|
||||
}
|
||||
bool IsContext() {
|
||||
return Config::is_struct(this, StructuralType::kContextTag);
|
||||
}
|
||||
@ -523,6 +534,8 @@ class TypeImpl : public Config::Base {
|
||||
void Print();
|
||||
#endif
|
||||
|
||||
bool IsUnionForTesting() { return IsUnion(); }
|
||||
|
||||
protected:
|
||||
// Friends.
|
||||
|
||||
@ -565,22 +578,17 @@ class TypeImpl : public Config::Base {
|
||||
}
|
||||
|
||||
struct Limits {
|
||||
i::Handle<i::Object> min;
|
||||
i::Handle<i::Object> max;
|
||||
double min;
|
||||
double max;
|
||||
bitset representation;
|
||||
Limits(i::Handle<i::Object> min, i::Handle<i::Object> max,
|
||||
bitset representation)
|
||||
Limits(double min, double max, bitset representation)
|
||||
: min(min), max(max), representation(representation) {}
|
||||
explicit Limits(RangeType* range)
|
||||
: min(range->Min()),
|
||||
max(range->Max()),
|
||||
representation(REPRESENTATION(range->Bound()->AsBitset())) {}
|
||||
representation(REPRESENTATION(range->Bound())) {}
|
||||
static Limits Empty(Region* region) {
|
||||
// TODO(jarin) Get rid of the heap numbers.
|
||||
i::Factory* f = i::Isolate::Current()->factory();
|
||||
i::Handle<i::Object> min = f->NewNumber(1);
|
||||
i::Handle<i::Object> max = f->NewNumber(0);
|
||||
return Limits(min, max, BitsetType::kNone);
|
||||
return Limits(1, 0, BitsetType::kNone);
|
||||
}
|
||||
};
|
||||
|
||||
@ -698,7 +706,6 @@ class TypeImpl<Config>::StructuralType : public TypeImpl<Config> {
|
||||
enum Tag {
|
||||
kClassTag,
|
||||
kConstantTag,
|
||||
kRangeTag,
|
||||
kContextTag,
|
||||
kArrayTag,
|
||||
kFunctionTag,
|
||||
@ -824,29 +831,28 @@ class TypeImpl<Config>::ConstantType : public StructuralType {
|
||||
// -----------------------------------------------------------------------------
|
||||
// Range types.
|
||||
|
||||
template<class Config>
|
||||
class TypeImpl<Config>::RangeType : public StructuralType {
|
||||
template <class Config>
|
||||
class TypeImpl<Config>::RangeType : public TypeImpl<Config> {
|
||||
public:
|
||||
TypeHandle Bound() { return this->Get(0); }
|
||||
i::Handle<i::Object> Min() { return this->template GetValue<i::Object>(1); }
|
||||
i::Handle<i::Object> Max() { return this->template GetValue<i::Object>(2); }
|
||||
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); }
|
||||
|
||||
static RangeHandle New(i::Handle<i::Object> min, i::Handle<i::Object> max,
|
||||
TypeHandle representation, Region* region) {
|
||||
DCHECK(IsInteger(min->Number()) && IsInteger(max->Number()));
|
||||
DCHECK(min->Number() <= max->Number());
|
||||
static RangeHandle New(double min, double max, TypeHandle representation,
|
||||
Region* region) {
|
||||
DCHECK(IsInteger(min) && IsInteger(max));
|
||||
DCHECK(min <= max);
|
||||
bitset representation_bits = representation->AsBitset();
|
||||
DCHECK(REPRESENTATION(representation_bits) == representation_bits);
|
||||
|
||||
RangeHandle type = Config::template cast<RangeType>(
|
||||
StructuralType::New(StructuralType::kRangeTag, 3, region));
|
||||
typename Config::template Handle<typename Config::Range>::type range =
|
||||
Config::range_create(region);
|
||||
|
||||
bitset bits = SEMANTIC(BitsetType::Lub(min->Number(), max->Number())) |
|
||||
representation_bits;
|
||||
type->Set(0, BitsetType::New(bits, region));
|
||||
type->SetValue(1, min);
|
||||
type->SetValue(2, max);
|
||||
return type;
|
||||
bitset bits = SEMANTIC(BitsetType::Lub(min, max)) | representation_bits;
|
||||
Config::range_set_bitset(range, bits);
|
||||
Config::range_set_double(range, 0, min, region);
|
||||
Config::range_set_double(range, 1, max, region);
|
||||
return Config::template cast<RangeType>(Config::from_range(range));
|
||||
}
|
||||
|
||||
static RangeHandle New(Limits lim, Region* region) {
|
||||
@ -970,9 +976,19 @@ struct ZoneTypeConfig {
|
||||
typedef TypeImpl<ZoneTypeConfig> Type;
|
||||
class Base {};
|
||||
typedef void* Struct;
|
||||
// Hack: the Struct and Range types can be aliased in memory, the first
|
||||
// pointer word of each both must be the tag (kRangeStructTag for Range,
|
||||
// anything else for Struct) so that we can differentiate them.
|
||||
struct Range {
|
||||
void* tag;
|
||||
int bitset;
|
||||
double limits[2];
|
||||
};
|
||||
typedef i::Zone Region;
|
||||
template<class T> struct Handle { typedef T* type; };
|
||||
|
||||
static const int kRangeStructTag = 0x1000;
|
||||
|
||||
template<class T> static inline T* null_handle();
|
||||
template<class T> static inline T* handle(T* type);
|
||||
template<class T> static inline T* cast(Type* type);
|
||||
@ -980,15 +996,18 @@ struct ZoneTypeConfig {
|
||||
static inline bool is_bitset(Type* type);
|
||||
static inline bool is_class(Type* type);
|
||||
static inline bool is_struct(Type* type, int tag);
|
||||
static inline bool is_range(Type* type);
|
||||
|
||||
static inline Type::bitset as_bitset(Type* type);
|
||||
static inline i::Handle<i::Map> as_class(Type* type);
|
||||
static inline Struct* as_struct(Type* type);
|
||||
static inline Range* as_range(Type* type);
|
||||
|
||||
static inline Type* from_bitset(Type::bitset);
|
||||
static inline Type* from_bitset(Type::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_range(Range* range);
|
||||
|
||||
static inline Struct* struct_create(int tag, int length, Zone* zone);
|
||||
static inline void struct_shrink(Struct* structure, int length);
|
||||
@ -1000,6 +1019,12 @@ struct ZoneTypeConfig {
|
||||
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);
|
||||
|
||||
static inline Range* range_create(Zone* zone);
|
||||
static inline int range_get_bitset(Range* range);
|
||||
static inline void range_set_bitset(Range* range, int);
|
||||
static inline double range_get_double(Range*, int index);
|
||||
static inline void range_set_double(Range*, int index, double value, Zone*);
|
||||
};
|
||||
|
||||
typedef TypeImpl<ZoneTypeConfig> Type;
|
||||
@ -1013,9 +1038,12 @@ struct HeapTypeConfig {
|
||||
typedef TypeImpl<HeapTypeConfig> Type;
|
||||
typedef i::Object Base;
|
||||
typedef i::FixedArray Struct;
|
||||
typedef i::FixedArray Range;
|
||||
typedef i::Isolate Region;
|
||||
template<class T> struct Handle { typedef i::Handle<T> type; };
|
||||
|
||||
static const int kRangeStructTag = 0xffff;
|
||||
|
||||
template<class T> static inline i::Handle<T> null_handle();
|
||||
template<class T> static inline i::Handle<T> handle(T* type);
|
||||
template<class T> static inline i::Handle<T> cast(i::Handle<Type> type);
|
||||
@ -1023,16 +1051,19 @@ struct HeapTypeConfig {
|
||||
static inline bool is_bitset(Type* type);
|
||||
static inline bool is_class(Type* type);
|
||||
static inline bool is_struct(Type* type, int tag);
|
||||
static inline bool is_range(Type* type);
|
||||
|
||||
static inline Type::bitset as_bitset(Type* type);
|
||||
static inline i::Handle<i::Map> as_class(Type* type);
|
||||
static inline i::Handle<Struct> as_struct(Type* type);
|
||||
static inline i::Handle<Range> as_range(Type* type);
|
||||
|
||||
static inline Type* from_bitset(Type::bitset);
|
||||
static inline i::Handle<Type> from_bitset(Type::bitset, Isolate* isolate);
|
||||
static inline i::Handle<Type> from_class(
|
||||
i::Handle<i::Map> map, Isolate* isolate);
|
||||
static inline i::Handle<Type> from_struct(i::Handle<Struct> structure);
|
||||
static inline i::Handle<Type> from_range(i::Handle<Range> range);
|
||||
|
||||
static inline i::Handle<Struct> struct_create(
|
||||
int tag, int length, Isolate* isolate);
|
||||
@ -1048,6 +1079,13 @@ struct HeapTypeConfig {
|
||||
template<class V>
|
||||
static inline void struct_set_value(
|
||||
i::Handle<Struct> structure, int i, i::Handle<V> x);
|
||||
|
||||
static inline i::Handle<Range> range_create(Isolate* isolate);
|
||||
static inline int range_get_bitset(i::Handle<Range> range);
|
||||
static inline void range_set_bitset(i::Handle<Range> range, int value);
|
||||
static inline double range_get_double(i::Handle<Range> range, int index);
|
||||
static inline void range_set_double(i::Handle<Range> range, int index,
|
||||
double value, Isolate* isolate);
|
||||
};
|
||||
|
||||
typedef TypeImpl<HeapTypeConfig> HeapType;
|
||||
|
@ -972,11 +972,8 @@ TEST(LowerNumberCmp_to_float64) {
|
||||
|
||||
TEST(LowerNumberAddSub_to_int32) {
|
||||
HandleAndZoneScope scope;
|
||||
Factory* f = scope.main_isolate()->factory();
|
||||
Type* small_range =
|
||||
Type::Range(f->NewNumber(1), f->NewNumber(10), scope.main_zone());
|
||||
Type* large_range =
|
||||
Type::Range(f->NewNumber(-1e+13), f->NewNumber(1e+14), scope.main_zone());
|
||||
Type* small_range = Type::Range(1, 10, scope.main_zone());
|
||||
Type* large_range = Type::Range(-1e+13, 1e+14, scope.main_zone());
|
||||
static Type* types[] = {Type::Signed32(), Type::Integral32(), small_range,
|
||||
large_range};
|
||||
|
||||
@ -996,11 +993,8 @@ TEST(LowerNumberAddSub_to_int32) {
|
||||
|
||||
TEST(LowerNumberAddSub_to_uint32) {
|
||||
HandleAndZoneScope scope;
|
||||
Factory* f = scope.main_isolate()->factory();
|
||||
Type* small_range =
|
||||
Type::Range(f->NewNumber(1), f->NewNumber(10), scope.main_zone());
|
||||
Type* large_range =
|
||||
Type::Range(f->NewNumber(-1e+13), f->NewNumber(1e+14), scope.main_zone());
|
||||
Type* small_range = Type::Range(1, 10, scope.main_zone());
|
||||
Type* large_range = Type::Range(-1e+13, 1e+14, scope.main_zone());
|
||||
static Type* types[] = {Type::Signed32(), Type::Integral32(), small_range,
|
||||
large_range};
|
||||
|
||||
|
@ -87,11 +87,8 @@ class TyperTester : public HandleAndZoneScope, public GraphAndBuilders {
|
||||
}
|
||||
|
||||
Type* NewRange(double i, double j) {
|
||||
Factory* f = isolate()->factory();
|
||||
i::Handle<i::Object> min = f->NewNumber(i);
|
||||
i::Handle<i::Object> max = f->NewNumber(j);
|
||||
if (min->Number() > max->Number()) std::swap(min, max);
|
||||
return Type::Range(min, max, main_zone());
|
||||
if (i > j) std::swap(i, j);
|
||||
return Type::Range(i, j, main_zone());
|
||||
}
|
||||
|
||||
double RandomInt(double min, double max) {
|
||||
@ -113,7 +110,7 @@ class TyperTester : public HandleAndZoneScope, public GraphAndBuilders {
|
||||
}
|
||||
|
||||
double RandomInt(Type::RangeType* range) {
|
||||
return RandomInt(range->Min()->Number(), range->Max()->Number());
|
||||
return RandomInt(range->Min(), range->Max());
|
||||
}
|
||||
|
||||
// Careful, this function runs O(max_width^5) trials.
|
||||
|
@ -36,7 +36,8 @@ struct ZoneRep {
|
||||
return !IsBitset(t) && reinterpret_cast<intptr_t>(AsStruct(t)[0]) == tag;
|
||||
}
|
||||
static bool IsBitset(Type* t) { return reinterpret_cast<uintptr_t>(t) & 1; }
|
||||
static bool IsUnion(Type* t) { return IsStruct(t, 6); }
|
||||
// HACK: the number 5 below is the value of StructuralType::kUnionTag.
|
||||
static bool IsUnion(Type* t) { return t->IsUnionForTesting(); }
|
||||
|
||||
static Struct* AsStruct(Type* t) {
|
||||
return reinterpret_cast<Struct*>(t);
|
||||
@ -69,7 +70,8 @@ struct HeapRep {
|
||||
return t->IsFixedArray() && Smi::cast(AsStruct(t)->get(0))->value() == tag;
|
||||
}
|
||||
static bool IsBitset(Handle<HeapType> t) { return t->IsSmi(); }
|
||||
static bool IsUnion(Handle<HeapType> t) { return IsStruct(t, 6); }
|
||||
// HACK: the number 5 below is the value of StructuralType::kUnionTag.
|
||||
static bool IsUnion(Handle<HeapType> t) { return t->IsUnionForTesting(); }
|
||||
|
||||
static Struct* AsStruct(Handle<HeapType> t) { return FixedArray::cast(*t); }
|
||||
static bitset AsBitset(Handle<HeapType> t) {
|
||||
@ -351,9 +353,9 @@ struct Tests : Rep {
|
||||
// Constructor
|
||||
for (ValueIterator i = T.integers.begin(); i != T.integers.end(); ++i) {
|
||||
for (ValueIterator j = T.integers.begin(); j != T.integers.end(); ++j) {
|
||||
i::Handle<i::Object> min = *i;
|
||||
i::Handle<i::Object> max = *j;
|
||||
if (min->Number() > max->Number()) std::swap(min, max);
|
||||
double min = (*i)->Number();
|
||||
double max = (*j)->Number();
|
||||
if (min > max) std::swap(min, max);
|
||||
TypeHandle type = T.Range(min, max);
|
||||
CHECK(type->IsRange());
|
||||
}
|
||||
@ -362,12 +364,12 @@ struct Tests : Rep {
|
||||
// Range attributes
|
||||
for (ValueIterator i = T.integers.begin(); i != T.integers.end(); ++i) {
|
||||
for (ValueIterator j = T.integers.begin(); j != T.integers.end(); ++j) {
|
||||
i::Handle<i::Object> min = *i;
|
||||
i::Handle<i::Object> max = *j;
|
||||
if (min->Number() > max->Number()) std::swap(min, max);
|
||||
double min = (*i)->Number();
|
||||
double max = (*j)->Number();
|
||||
if (min > max) std::swap(min, max);
|
||||
TypeHandle type = T.Range(min, max);
|
||||
CHECK(*min == *type->AsRange()->Min());
|
||||
CHECK(*max == *type->AsRange()->Max());
|
||||
CHECK(min == type->AsRange()->Min());
|
||||
CHECK(max == type->AsRange()->Max());
|
||||
}
|
||||
}
|
||||
|
||||
@ -381,15 +383,15 @@ struct Tests : Rep {
|
||||
i2 != T.integers.end(); ++i2) {
|
||||
for (ValueIterator j2 = i2;
|
||||
j2 != T.integers.end(); ++j2) {
|
||||
i::Handle<i::Object> min1 = *i1;
|
||||
i::Handle<i::Object> max1 = *j1;
|
||||
i::Handle<i::Object> min2 = *i2;
|
||||
i::Handle<i::Object> max2 = *j2;
|
||||
if (min1->Number() > max1->Number()) std::swap(min1, max1);
|
||||
if (min2->Number() > max2->Number()) std::swap(min2, max2);
|
||||
double min1 = (*i1)->Number();
|
||||
double max1 = (*j1)->Number();
|
||||
double min2 = (*i2)->Number();
|
||||
double max2 = (*j2)->Number();
|
||||
if (min1 > max1) std::swap(min1, max1);
|
||||
if (min2 > max2) std::swap(min2, max2);
|
||||
TypeHandle type1 = T.Range(min1, max1);
|
||||
TypeHandle type2 = T.Range(min2, max2);
|
||||
CHECK(Equal(type1, type2) == (*min1 == *min2 && *max1 == *max2));
|
||||
CHECK(Equal(type1, type2) == (min1 == min2 && max1 == max2));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -608,8 +610,6 @@ struct Tests : Rep {
|
||||
}
|
||||
|
||||
void MinMax() {
|
||||
Factory* fac = isolate->factory();
|
||||
|
||||
// If b is regular numeric bitset, then Range(b->Min(), b->Max())->Is(b).
|
||||
// TODO(neis): Need to ignore representation for this to be true.
|
||||
/*
|
||||
@ -662,8 +662,7 @@ struct Tests : Rep {
|
||||
for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
|
||||
TypeHandle type = *it;
|
||||
CHECK(!(type->Is(T.Integer) && !type->Is(T.None)) ||
|
||||
type->Is(T.Range(fac->NewNumber(type->Min()),
|
||||
fac->NewNumber(type->Max()))));
|
||||
type->Is(T.Range(type->Min(), type->Max())));
|
||||
}
|
||||
}
|
||||
|
||||
@ -828,17 +827,15 @@ struct Tests : Rep {
|
||||
i2 != T.integers.end(); ++i2) {
|
||||
for (ValueIterator j2 = i2;
|
||||
j2 != T.integers.end(); ++j2) {
|
||||
i::Handle<i::Object> min1 = *i1;
|
||||
i::Handle<i::Object> max1 = *j1;
|
||||
i::Handle<i::Object> min2 = *i2;
|
||||
i::Handle<i::Object> max2 = *j2;
|
||||
if (min1->Number() > max1->Number()) std::swap(min1, max1);
|
||||
if (min2->Number() > max2->Number()) std::swap(min2, max2);
|
||||
double min1 = (*i1)->Number();
|
||||
double max1 = (*j1)->Number();
|
||||
double min2 = (*i2)->Number();
|
||||
double max2 = (*j2)->Number();
|
||||
if (min1 > max1) std::swap(min1, max1);
|
||||
if (min2 > max2) std::swap(min2, max2);
|
||||
TypeHandle type1 = T.Range(min1, max1);
|
||||
TypeHandle type2 = T.Range(min2, max2);
|
||||
CHECK(type1->Is(type2) ==
|
||||
(min1->Number() >= min2->Number() &&
|
||||
max1->Number() <= max2->Number()));
|
||||
CHECK(type1->Is(type2) == (min1 >= min2 && max1 <= max2));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -898,8 +895,8 @@ struct Tests : Rep {
|
||||
for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
|
||||
TypeHandle type = *it;
|
||||
if (type->IsConstant() && IsInteger(*type->AsConstant()->Value())) {
|
||||
CHECK(type->Is(
|
||||
T.Range(type->AsConstant()->Value(), type->AsConstant()->Value())));
|
||||
CHECK(type->Is(T.Range(type->AsConstant()->Value()->Number(),
|
||||
type->AsConstant()->Value()->Number())));
|
||||
}
|
||||
}
|
||||
|
||||
@ -910,8 +907,8 @@ struct Tests : Rep {
|
||||
TypeHandle type2 = *it2;
|
||||
if (type1->IsConstant() && type2->IsRange() && type1->Is(type2)) {
|
||||
double x = type1->AsConstant()->Value()->Number();
|
||||
double min = type2->AsRange()->Min()->Number();
|
||||
double max = type2->AsRange()->Max()->Number();
|
||||
double min = type2->AsRange()->Min();
|
||||
double max = type2->AsRange()->Max();
|
||||
CHECK(IsInteger(x) && min <= x && x <= max);
|
||||
}
|
||||
}
|
||||
@ -1848,8 +1845,8 @@ struct Tests : Rep {
|
||||
TypeHandle type1 = *it1;
|
||||
if (type1->IsRange()) {
|
||||
typename Type::RangeType* range = type1->GetRange();
|
||||
CHECK(type1->Min() == range->Min()->Number());
|
||||
CHECK(type1->Max() == range->Max()->Number());
|
||||
CHECK(type1->Min() == range->Min());
|
||||
CHECK(type1->Max() == range->Max());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1861,8 +1858,8 @@ struct Tests : Rep {
|
||||
if (type1->IsConstant() && type2->IsRange()) {
|
||||
TypeHandle u = T.Union(type1, type2);
|
||||
|
||||
CHECK(type2->Min() == u->GetRange()->Min()->Number());
|
||||
CHECK(type2->Max() == u->GetRange()->Max()->Number());
|
||||
CHECK(type2->Min() == u->GetRange()->Min());
|
||||
CHECK(type2->Max() == u->GetRange()->Max());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -101,8 +101,7 @@ class Types {
|
||||
if (!IsMinusZero(x)) integers.push_back(isolate->factory()->NewNumber(x));
|
||||
}
|
||||
|
||||
Integer = Type::Range(isolate->factory()->NewNumber(-V8_INFINITY),
|
||||
isolate->factory()->NewNumber(+V8_INFINITY), region);
|
||||
Integer = Type::Range(-V8_INFINITY, +V8_INFINITY, region);
|
||||
|
||||
NumberArray = Type::Array(Number, region);
|
||||
StringArray = Type::Array(String, region);
|
||||
@ -184,7 +183,7 @@ class Types {
|
||||
return Type::Constant(value, region_);
|
||||
}
|
||||
|
||||
TypeHandle Range(Handle<i::Object> min, Handle<i::Object> max) {
|
||||
TypeHandle Range(double min, double max) {
|
||||
return Type::Range(min, max, region_);
|
||||
}
|
||||
|
||||
@ -263,9 +262,9 @@ class Types {
|
||||
case 3: { // range
|
||||
int i = rng_->NextInt(static_cast<int>(integers.size()));
|
||||
int j = rng_->NextInt(static_cast<int>(integers.size()));
|
||||
i::Handle<i::Object> min = integers[i];
|
||||
i::Handle<i::Object> max = integers[j];
|
||||
if (min->Number() > max->Number()) std::swap(min, max);
|
||||
double min = integers[i]->Number();
|
||||
double max = integers[j]->Number();
|
||||
if (min > max) std::swap(min, max);
|
||||
return Type::Range(min, max, region_);
|
||||
}
|
||||
case 4: { // context
|
||||
|
@ -119,7 +119,6 @@ TEST_F(JSTypedLoweringTest, JSUnaryNotWithBoolean) {
|
||||
|
||||
|
||||
TEST_F(JSTypedLoweringTest, JSUnaryNotWithFalsish) {
|
||||
Handle<Object> zero = factory()->NewNumber(0);
|
||||
Node* input = Parameter(
|
||||
Type::Union(
|
||||
Type::MinusZero(),
|
||||
@ -133,7 +132,7 @@ TEST_F(JSTypedLoweringTest, JSUnaryNotWithFalsish) {
|
||||
Type::Undetectable(),
|
||||
Type::Union(
|
||||
Type::Constant(factory()->false_value(), zone()),
|
||||
Type::Range(zero, zero, zone()), zone()),
|
||||
Type::Range(0.0, 0.0, zone()), zone()),
|
||||
zone()),
|
||||
zone()),
|
||||
zone()),
|
||||
@ -164,9 +163,7 @@ TEST_F(JSTypedLoweringTest, JSUnaryNotWithTruish) {
|
||||
|
||||
|
||||
TEST_F(JSTypedLoweringTest, JSUnaryNotWithNonZeroPlainNumber) {
|
||||
Node* input = Parameter(
|
||||
Type::Range(factory()->NewNumber(1), factory()->NewNumber(42), zone()),
|
||||
0);
|
||||
Node* input = Parameter(Type::Range(1.0, 42.0, zone()), 0);
|
||||
Node* context = Parameter(Type::Any(), 1);
|
||||
Reduction r =
|
||||
Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
|
||||
@ -259,8 +256,7 @@ TEST_F(JSTypedLoweringTest, ParameterWithPlainNumber) {
|
||||
EXPECT_THAT(r.replacement(), IsNumberConstant(value));
|
||||
}
|
||||
TRACED_FOREACH(double, value, kIntegerValues) {
|
||||
Handle<Object> constant = factory()->NewNumber(value);
|
||||
Reduction r = Reduce(Parameter(Type::Range(constant, constant, zone())));
|
||||
Reduction r = Reduce(Parameter(Type::Range(value, value, zone())));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsNumberConstant(value));
|
||||
}
|
||||
@ -299,7 +295,6 @@ TEST_F(JSTypedLoweringTest, JSToBooleanWithBoolean) {
|
||||
|
||||
|
||||
TEST_F(JSTypedLoweringTest, JSToBooleanWithFalsish) {
|
||||
Handle<Object> zero = factory()->NewNumber(0);
|
||||
Node* input = Parameter(
|
||||
Type::Union(
|
||||
Type::MinusZero(),
|
||||
@ -313,7 +308,7 @@ TEST_F(JSTypedLoweringTest, JSToBooleanWithFalsish) {
|
||||
Type::Undetectable(),
|
||||
Type::Union(
|
||||
Type::Constant(factory()->false_value(), zone()),
|
||||
Type::Range(zero, zero, zone()), zone()),
|
||||
Type::Range(0.0, 0.0, zone()), zone()),
|
||||
zone()),
|
||||
zone()),
|
||||
zone()),
|
||||
@ -344,10 +339,7 @@ TEST_F(JSTypedLoweringTest, JSToBooleanWithTruish) {
|
||||
|
||||
|
||||
TEST_F(JSTypedLoweringTest, JSToBooleanWithNonZeroPlainNumber) {
|
||||
Node* input =
|
||||
Parameter(Type::Range(factory()->NewNumber(1),
|
||||
factory()->NewNumber(V8_INFINITY), zone()),
|
||||
0);
|
||||
Node* input = Parameter(Type::Range(1, V8_INFINITY, zone()), 0);
|
||||
Node* context = Parameter(Type::Any(), 1);
|
||||
Reduction r =
|
||||
Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
|
||||
@ -593,8 +585,7 @@ TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArray) {
|
||||
int const element_size = static_cast<int>(array->element_size());
|
||||
|
||||
Node* key = Parameter(
|
||||
Type::Range(factory()->NewNumber(kMinInt / element_size),
|
||||
factory()->NewNumber(kMaxInt / element_size), zone()));
|
||||
Type::Range(kMinInt / element_size, kMaxInt / element_size, zone()));
|
||||
Node* base = HeapConstant(array);
|
||||
Node* context = UndefinedConstant();
|
||||
Node* effect = graph()->start();
|
||||
@ -640,8 +631,7 @@ TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArrayWithSafeKey) {
|
||||
int min = random_number_generator()->NextInt(static_cast<int>(kLength));
|
||||
int max = random_number_generator()->NextInt(static_cast<int>(kLength));
|
||||
if (min > max) std::swap(min, max);
|
||||
Node* key = Parameter(Type::Range(factory()->NewNumber(min),
|
||||
factory()->NewNumber(max), zone()));
|
||||
Node* key = Parameter(Type::Range(min, max, zone()));
|
||||
Node* base = HeapConstant(array);
|
||||
Node* context = UndefinedConstant();
|
||||
Node* effect = graph()->start();
|
||||
@ -681,8 +671,7 @@ TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArray) {
|
||||
int const element_size = static_cast<int>(array->element_size());
|
||||
|
||||
Node* key = Parameter(
|
||||
Type::Range(factory()->NewNumber(kMinInt / element_size),
|
||||
factory()->NewNumber(kMaxInt / element_size), zone()));
|
||||
Type::Range(kMinInt / element_size, kMaxInt / element_size, zone()));
|
||||
Node* base = HeapConstant(array);
|
||||
Node* value =
|
||||
Parameter(AccessBuilder::ForTypedArrayElement(type, true).type);
|
||||
@ -728,8 +717,7 @@ TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArrayWithConversion) {
|
||||
int const element_size = static_cast<int>(array->element_size());
|
||||
|
||||
Node* key = Parameter(
|
||||
Type::Range(factory()->NewNumber(kMinInt / element_size),
|
||||
factory()->NewNumber(kMaxInt / element_size), zone()));
|
||||
Type::Range(kMinInt / element_size, kMaxInt / element_size, zone()));
|
||||
Node* base = HeapConstant(array);
|
||||
Node* value = Parameter(Type::Any());
|
||||
Node* context = UndefinedConstant();
|
||||
@ -787,8 +775,7 @@ TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArrayWithSafeKey) {
|
||||
int min = random_number_generator()->NextInt(static_cast<int>(kLength));
|
||||
int max = random_number_generator()->NextInt(static_cast<int>(kLength));
|
||||
if (min > max) std::swap(min, max);
|
||||
Node* key = Parameter(Type::Range(factory()->NewNumber(min),
|
||||
factory()->NewNumber(max), zone()));
|
||||
Node* key = Parameter(Type::Range(min, max, zone()));
|
||||
Node* base = HeapConstant(array);
|
||||
Node* value = Parameter(access.type);
|
||||
Node* context = UndefinedConstant();
|
||||
|
Loading…
Reference in New Issue
Block a user