| Index: src/compiler/typer.cc
|
| diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc
|
| index 5417f66f27c94a7c89290149147b0df32f85d0fe..6e9a28ee3b0f7cb889e4606f7a759a7f8d110822 100644
|
| --- a/src/compiler/typer.cc
|
| +++ b/src/compiler/typer.cc
|
| @@ -26,6 +26,10 @@ namespace compiler {
|
| V(Float64)
|
|
|
| enum LazyCachedType {
|
| + kInteger,
|
| + kWeakint,
|
| + kWeakintFunc1,
|
| + kRandomFunc0,
|
| kAnyFunc0,
|
| kAnyFunc1,
|
| kAnyFunc2,
|
| @@ -53,9 +57,9 @@ class LazyTypeCache final : public ZoneObject {
|
| memset(cache_, 0, sizeof(cache_));
|
| }
|
|
|
| - inline Type* Get(LazyCachedType type) {
|
| - int index = static_cast<int>(type);
|
| - DCHECK(index < kNumLazyCachedTypes);
|
| + V8_INLINE Type* Get(LazyCachedType type) {
|
| + int const index = static_cast<int>(type);
|
| + DCHECK_LT(index, kNumLazyCachedTypes);
|
| if (cache_[index] == NULL) cache_[index] = Create(type);
|
| return cache_[index];
|
| }
|
| @@ -82,6 +86,14 @@ class LazyTypeCache final : public ZoneObject {
|
| return CreateNative(Type::Number(), Type::UntaggedFloat64());
|
| case kUint8Clamped:
|
| return Get(kUint8);
|
| + case kInteger:
|
| + return CreateRange(-V8_INFINITY, V8_INFINITY);
|
| + case kWeakint:
|
| + return Type::Union(Get(kInteger), Type::MinusZeroOrNaN(), zone());
|
| + case kWeakintFunc1:
|
| + return Type::Function(Get(kWeakint), Type::Number(), zone());
|
| + case kRandomFunc0:
|
| + return Type::Function(Type::OrderedNumber(), zone());
|
| case kAnyFunc0:
|
| return Type::Function(Type::Any(), zone());
|
| case kAnyFunc1:
|
| @@ -171,47 +183,30 @@ Typer::Typer(Isolate* isolate, Graph* graph, MaybeHandle<Context> context)
|
| decorator_(NULL),
|
| cache_(new (graph->zone()) LazyTypeCache(isolate, graph->zone())) {
|
| Zone* zone = this->zone();
|
| - Factory* f = isolate->factory();
|
| + Factory* const factory = isolate->factory();
|
|
|
| - Handle<Object> infinity = f->NewNumber(+V8_INFINITY);
|
| - Handle<Object> minusinfinity = f->NewNumber(-V8_INFINITY);
|
| -
|
| - Type* number = Type::Number();
|
| - Type* signed32 = Type::Signed32();
|
| - Type* unsigned32 = Type::Unsigned32();
|
| - Type* nan_or_minuszero = Type::Union(Type::NaN(), Type::MinusZero(), zone);
|
| + Type* infinity = Type::Constant(factory->infinity_value(), zone);
|
| + Type* minus_infinity = Type::Constant(factory->minus_infinity_value(), zone);
|
| Type* truncating_to_zero =
|
| - Type::Union(Type::Union(Type::Constant(infinity, zone),
|
| - Type::Constant(minusinfinity, zone), zone),
|
| - nan_or_minuszero, zone);
|
| -
|
| - boolean_or_number = Type::Union(Type::Boolean(), Type::Number(), zone);
|
| - undefined_or_null = Type::Union(Type::Undefined(), Type::Null(), zone);
|
| - 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(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);
|
| - unsigned32ish = Type::Union(unsigned32, truncating_to_zero, zone);
|
| - falsish = Type::Union(Type::Undetectable(),
|
| - Type::Union(Type::Union(singleton_false, zeroish, zone),
|
| - undefined_or_null, zone),
|
| - zone);
|
| - truish = Type::Union(
|
| - singleton_true,
|
| + Type::Union(Type::Union(infinity, minus_infinity, zone),
|
| + Type::MinusZeroOrNaN(), zone);
|
| +
|
| + singleton_false_ = Type::Constant(factory->false_value(), zone);
|
| + singleton_true_ = Type::Constant(factory->true_value(), zone);
|
| + singleton_zero_ = Type::Range(0.0, 0.0, zone);
|
| + singleton_one_ = Type::Range(1.0, 1.0, zone);
|
| + zero_or_one_ = Type::Range(0.0, 1.0, zone);
|
| + zeroish_ = Type::Union(singleton_zero_, Type::MinusZeroOrNaN(), zone);
|
| + signed32ish_ = Type::Union(Type::Signed32(), truncating_to_zero, zone);
|
| + unsigned32ish_ = Type::Union(Type::Unsigned32(), truncating_to_zero, zone);
|
| + falsish_ =
|
| + Type::Union(Type::Undetectable(),
|
| + Type::Union(Type::Union(singleton_false_, zeroish_, zone),
|
| + Type::NullOrUndefined(), zone),
|
| + zone);
|
| + truish_ = Type::Union(
|
| + singleton_true_,
|
| Type::Union(Type::DetectableReceiver(), Type::Symbol(), zone), zone);
|
| - integer = Type::Range(-V8_INFINITY, V8_INFINITY, zone);
|
| - weakint = Type::Union(integer, nan_or_minuszero, zone);
|
| -
|
| - number_fun0_ = Type::Function(number, zone);
|
| - number_fun1_ = Type::Function(number, number, zone);
|
| - number_fun2_ = Type::Function(number, number, number, zone);
|
| -
|
| - weakint_fun1_ = Type::Function(weakint, number, zone);
|
| - random_fun_ = Type::Function(Type::OrderedNumber(), zone);
|
|
|
| decorator_ = new (zone) Decorator(this);
|
| graph_->AddDecorator(decorator_);
|
| @@ -500,8 +495,8 @@ Bounds Typer::Visitor::TypeBinaryOp(Node* node, BinaryTyperFun f) {
|
| Type* Typer::Visitor::Invert(Type* type, Typer* t) {
|
| DCHECK(type->Is(Type::Boolean()));
|
| DCHECK(type->IsInhabited());
|
| - if (type->Is(t->singleton_false)) return t->singleton_true;
|
| - if (type->Is(t->singleton_true)) return t->singleton_false;
|
| + if (type->Is(t->singleton_false_)) return t->singleton_true_;
|
| + if (type->Is(t->singleton_true_)) return t->singleton_false_;
|
| return type;
|
| }
|
|
|
| @@ -520,17 +515,17 @@ Type* Typer::Visitor::FalsifyUndefined(ComparisonOutcome outcome, Typer* t) {
|
| if ((outcome & kComparisonFalse) != 0 ||
|
| (outcome & kComparisonUndefined) != 0) {
|
| return (outcome & kComparisonTrue) != 0 ? Type::Boolean()
|
| - : t->singleton_false;
|
| + : t->singleton_false_;
|
| }
|
| // Type should be non empty, so we know it should be true.
|
| DCHECK((outcome & kComparisonTrue) != 0);
|
| - return t->singleton_true;
|
| + return t->singleton_true_;
|
| }
|
|
|
|
|
| Type* Typer::Visitor::Rangify(Type* type, Typer* t) {
|
| if (type->IsRange()) return type; // Shortcut.
|
| - if (!type->Is(t->integer) && !type->Is(Type::Integral32())) {
|
| + if (!type->Is(t->cache_->Get(kInteger))) {
|
| return type; // Give up on non-integer types.
|
| }
|
| double min = type->Min();
|
| @@ -558,10 +553,10 @@ Type* Typer::Visitor::ToPrimitive(Type* type, Typer* t) {
|
|
|
| Type* Typer::Visitor::ToBoolean(Type* type, Typer* t) {
|
| if (type->Is(Type::Boolean())) return type;
|
| - if (type->Is(t->falsish)) return t->singleton_false;
|
| - if (type->Is(t->truish)) return t->singleton_true;
|
| + if (type->Is(t->falsish_)) return t->singleton_false_;
|
| + if (type->Is(t->truish_)) return t->singleton_true_;
|
| if (type->Is(Type::PlainNumber()) && (type->Max() < 0 || 0 < type->Min())) {
|
| - return t->singleton_true; // Ruled out nan, -0 and +0.
|
| + return t->singleton_true_; // Ruled out nan, -0 and +0.
|
| }
|
| return Type::Boolean();
|
| }
|
| @@ -569,21 +564,21 @@ Type* Typer::Visitor::ToBoolean(Type* type, Typer* t) {
|
|
|
| Type* Typer::Visitor::ToNumber(Type* type, Typer* t) {
|
| if (type->Is(Type::Number())) return type;
|
| - if (type->Is(Type::Null())) return t->singleton_zero;
|
| - if (type->Is(Type::Undefined())) return Type::NaN();
|
| - if (type->Is(t->undefined_or_null)) {
|
| - return Type::Union(Type::NaN(), t->singleton_zero, t->zone());
|
| + if (type->Is(Type::NullOrUndefined())) {
|
| + if (type->Is(Type::Null())) return t->singleton_zero_;
|
| + if (type->Is(Type::Undefined())) return Type::NaN();
|
| + return Type::Union(Type::NaN(), t->singleton_zero_, t->zone());
|
| }
|
| - if (type->Is(t->undefined_or_number)) {
|
| + if (type->Is(Type::NumberOrUndefined())) {
|
| return Type::Union(Type::Intersect(type, Type::Number(), t->zone()),
|
| Type::NaN(), t->zone());
|
| }
|
| - if (type->Is(t->singleton_false)) return t->singleton_zero;
|
| - if (type->Is(t->singleton_true)) return t->singleton_one;
|
| - if (type->Is(Type::Boolean())) return t->zero_or_one;
|
| - if (type->Is(t->boolean_or_number)) {
|
| + if (type->Is(t->singleton_false_)) return t->singleton_zero_;
|
| + if (type->Is(t->singleton_true_)) return t->singleton_one_;
|
| + if (type->Is(Type::Boolean())) return t->zero_or_one_;
|
| + if (type->Is(Type::BooleanOrNumber())) {
|
| return Type::Union(Type::Intersect(type, Type::Number(), t->zone()),
|
| - t->zero_or_one, t->zone());
|
| + t->zero_or_one_, t->zone());
|
| }
|
| return Type::Number();
|
| }
|
| @@ -598,9 +593,9 @@ Type* Typer::Visitor::ToString(Type* type, Typer* t) {
|
| Type* Typer::Visitor::NumberToInt32(Type* type, Typer* t) {
|
| // TODO(neis): DCHECK(type->Is(Type::Number()));
|
| if (type->Is(Type::Signed32())) return type;
|
| - if (type->Is(t->zeroish)) return t->singleton_zero;
|
| - if (type->Is(t->signed32ish)) {
|
| - return Type::Intersect(Type::Union(type, t->singleton_zero, t->zone()),
|
| + if (type->Is(t->zeroish_)) return t->singleton_zero_;
|
| + if (type->Is(t->signed32ish_)) {
|
| + return Type::Intersect(Type::Union(type, t->singleton_zero_, t->zone()),
|
| Type::Signed32(), t->zone());
|
| }
|
| return Type::Signed32();
|
| @@ -610,9 +605,9 @@ Type* Typer::Visitor::NumberToInt32(Type* type, Typer* t) {
|
| Type* Typer::Visitor::NumberToUint32(Type* type, Typer* t) {
|
| // TODO(neis): DCHECK(type->Is(Type::Number()));
|
| if (type->Is(Type::Unsigned32())) return type;
|
| - if (type->Is(t->zeroish)) return t->singleton_zero;
|
| - if (type->Is(t->unsigned32ish)) {
|
| - return Type::Intersect(Type::Union(type, t->singleton_zero, t->zone()),
|
| + if (type->Is(t->zeroish_)) return t->singleton_zero_;
|
| + if (type->Is(t->unsigned32ish_)) {
|
| + return Type::Intersect(Type::Union(type, t->singleton_zero_, t->zone()),
|
| Type::Unsigned32(), t->zone());
|
| }
|
| return Type::Unsigned32();
|
| @@ -776,19 +771,19 @@ Bounds Typer::Visitor::TypeDead(Node* node) {
|
|
|
|
|
| Type* Typer::Visitor::JSEqualTyper(Type* lhs, Type* rhs, Typer* t) {
|
| - if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return t->singleton_false;
|
| - if (lhs->Is(t->undefined_or_null) && rhs->Is(t->undefined_or_null)) {
|
| - return t->singleton_true;
|
| + if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return t->singleton_false_;
|
| + if (lhs->Is(Type::NullOrUndefined()) && rhs->Is(Type::NullOrUndefined())) {
|
| + return t->singleton_true_;
|
| }
|
| if (lhs->Is(Type::Number()) && rhs->Is(Type::Number()) &&
|
| (lhs->Max() < rhs->Min() || lhs->Min() > rhs->Max())) {
|
| - return t->singleton_false;
|
| + return t->singleton_false_;
|
| }
|
| if (lhs->IsConstant() && rhs->Is(lhs)) {
|
| // Types are equal and are inhabited only by a single semantic value,
|
| // which is not nan due to the earlier check.
|
| // TODO(neis): Extend this to Range(x,x), MinusZero, ...?
|
| - return t->singleton_true;
|
| + return t->singleton_true_;
|
| }
|
| return Type::Boolean();
|
| }
|
| @@ -812,16 +807,16 @@ static Type* JSType(Type* type) {
|
|
|
|
|
| Type* Typer::Visitor::JSStrictEqualTyper(Type* lhs, Type* rhs, Typer* t) {
|
| - if (!JSType(lhs)->Maybe(JSType(rhs))) return t->singleton_false;
|
| - if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return t->singleton_false;
|
| + if (!JSType(lhs)->Maybe(JSType(rhs))) return t->singleton_false_;
|
| + if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return t->singleton_false_;
|
| if (lhs->Is(Type::Number()) && rhs->Is(Type::Number()) &&
|
| (lhs->Max() < rhs->Min() || lhs->Min() > rhs->Max())) {
|
| - return t->singleton_false;
|
| + return t->singleton_false_;
|
| }
|
| if (lhs->IsConstant() && rhs->Is(lhs)) {
|
| // Types are equal and are inhabited only by a single semantic value,
|
| // which is not nan due to the earlier check.
|
| - return t->singleton_true;
|
| + return t->singleton_true_;
|
| }
|
| return Type::Boolean();
|
| }
|
| @@ -1162,13 +1157,13 @@ Type* Typer::Visitor::JSMultiplyRanger(Type::RangeType* lhs,
|
| // the discontinuity makes it too complicated. Note that even if none of the
|
| // "results" above is nan, the actual result may still be, so we have to do a
|
| // different check:
|
| - bool maybe_nan = (lhs->Maybe(t->singleton_zero) &&
|
| + bool maybe_nan = (lhs->Maybe(t->singleton_zero_) &&
|
| (rmin == -V8_INFINITY || rmax == +V8_INFINITY)) ||
|
| - (rhs->Maybe(t->singleton_zero) &&
|
| + (rhs->Maybe(t->singleton_zero_) &&
|
| (lmin == -V8_INFINITY || lmax == +V8_INFINITY));
|
| - 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);
|
| + if (maybe_nan) return t->cache_->Get(kWeakint); // Giving up.
|
| + bool maybe_minuszero = (lhs->Maybe(t->singleton_zero_) && rmin < 0) ||
|
| + (rhs->Maybe(t->singleton_zero_) && lmin < 0);
|
| Type* range =
|
| Type::Range(array_min(results, 4), array_max(results, 4), t->zone());
|
| return maybe_minuszero ? Type::Union(range, Type::MinusZero(), t->zone())
|
| @@ -1194,7 +1189,7 @@ Type* Typer::Visitor::JSDivideTyper(Type* lhs, Type* rhs, Typer* t) {
|
| // Division is tricky, so all we do is try ruling out nan.
|
| // TODO(neis): try ruling out -0 as well?
|
| bool maybe_nan =
|
| - lhs->Maybe(Type::NaN()) || rhs->Maybe(t->zeroish) ||
|
| + lhs->Maybe(Type::NaN()) || rhs->Maybe(t->zeroish_) ||
|
| ((lhs->Min() == -V8_INFINITY || lhs->Max() == +V8_INFINITY) &&
|
| (rhs->Min() == -V8_INFINITY || rhs->Max() == +V8_INFINITY));
|
| return maybe_nan ? Type::Number() : Type::OrderedNumber();
|
| @@ -1239,7 +1234,7 @@ Type* Typer::Visitor::JSModulusTyper(Type* lhs, Type* rhs, Typer* t) {
|
| rhs = ToNumber(rhs, t);
|
| if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return Type::NaN();
|
|
|
| - if (lhs->Maybe(Type::NaN()) || rhs->Maybe(t->zeroish) ||
|
| + if (lhs->Maybe(Type::NaN()) || rhs->Maybe(t->zeroish_) ||
|
| lhs->Min() == -V8_INFINITY || lhs->Max() == +V8_INFINITY) {
|
| // Result maybe NaN.
|
| return Type::Number();
|
| @@ -1367,15 +1362,14 @@ Type* Typer::Visitor::Weaken(Node* node, Type* current_type,
|
| STATIC_ASSERT(arraysize(kWeakenMinLimits) == arraysize(kWeakenMaxLimits));
|
|
|
| // If the types have nothing to do with integers, return the types.
|
| - if (!previous_type->Maybe(typer_->integer)) {
|
| + Type* const integer = typer_->cache_->Get(kInteger);
|
| + if (!previous_type->Maybe(integer)) {
|
| return current_type;
|
| }
|
| - DCHECK(current_type->Maybe(typer_->integer));
|
| + DCHECK(current_type->Maybe(integer));
|
|
|
| - Type* current_integer =
|
| - Type::Intersect(current_type, typer_->integer, zone());
|
| - Type* previous_integer =
|
| - Type::Intersect(previous_type, typer_->integer, zone());
|
| + Type* current_integer = Type::Intersect(current_type, integer, zone());
|
| + Type* previous_integer = Type::Intersect(previous_type, integer, zone());
|
|
|
| // Once we start weakening a node, we should always weaken.
|
| if (!IsWeakened(node->id())) {
|
| @@ -1396,7 +1390,7 @@ Type* Typer::Visitor::Weaken(Node* node, Type* current_type,
|
| // Find the closest lower entry in the list of allowed
|
| // minima (or negative infinity if there is no such entry).
|
| if (current_min != previous_integer->Min()) {
|
| - new_min = typer_->integer->AsRange()->Min();
|
| + new_min = -V8_INFINITY;
|
| for (double const min : kWeakenMinLimits) {
|
| if (min <= current_min) {
|
| new_min = min;
|
| @@ -1410,7 +1404,7 @@ Type* Typer::Visitor::Weaken(Node* node, Type* current_type,
|
| // Find the closest greater entry in the list of allowed
|
| // maxima (or infinity if there is no such entry).
|
| if (current_max != previous_integer->Max()) {
|
| - new_max = typer_->integer->AsRange()->Max();
|
| + new_max = V8_INFINITY;
|
| for (double const max : kWeakenMaxLimits) {
|
| if (max >= current_max) {
|
| new_max = max;
|
| @@ -2336,13 +2330,11 @@ Type* Typer::Visitor::TypeConstant(Handle<Object> value) {
|
| if (JSFunction::cast(*value)->shared()->HasBuiltinFunctionId()) {
|
| switch (JSFunction::cast(*value)->shared()->builtin_function_id()) {
|
| case kMathRandom:
|
| - return typer_->random_fun_;
|
| + return typer_->cache_->Get(kRandomFunc0);
|
| case kMathFloor:
|
| - return typer_->weakint_fun1_;
|
| case kMathRound:
|
| - return typer_->weakint_fun1_;
|
| case kMathCeil:
|
| - return typer_->weakint_fun1_;
|
| + return typer_->cache_->Get(kWeakintFunc1);
|
| // Unary math functions.
|
| case kMathAbs: // TODO(rossberg): can't express overloading
|
| case kMathLog:
|
|
|