Index: src/compiler/typer.cc |
diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc |
index f684dd8fae93d068b62e6031e8302bc96634a10e..556efa553192a3b4771b028cab96f5b70f730f56 100644 |
--- a/src/compiler/typer.cc |
+++ b/src/compiler/typer.cc |
@@ -10,8 +10,9 @@ |
#include "src/compiler/common-operator.h" |
#include "src/compiler/graph-reducer.h" |
#include "src/compiler/js-operator.h" |
-#include "src/compiler/node.h" |
#include "src/compiler/node-properties.h" |
+#include "src/compiler/node.h" |
+#include "src/compiler/operation-typer.h" |
#include "src/compiler/simplified-operator.h" |
#include "src/objects-inl.h" |
#include "src/type-cache.h" |
@@ -37,7 +38,8 @@ Typer::Typer(Isolate* isolate, Graph* graph, Flags flags, |
dependencies_(dependencies), |
function_type_(function_type), |
decorator_(nullptr), |
- cache_(TypeCache::Get()) { |
+ cache_(TypeCache::Get()), |
+ operation_typer_(isolate, zone()) { |
Zone* zone = this->zone(); |
Factory* const factory = isolate->factory(); |
@@ -232,7 +234,6 @@ class Typer::Visitor : public Reducer { |
static ComparisonOutcome Invert(ComparisonOutcome, Typer*); |
static Type* Invert(Type*, Typer*); |
static Type* FalsifyUndefined(ComparisonOutcome, Typer*); |
- static Type* Rangify(Type*, Typer*); |
static Type* ToPrimitive(Type*, Typer*); |
static Type* ToBoolean(Type*, Typer*); |
@@ -256,12 +257,6 @@ class Typer::Visitor : public Reducer { |
static Type* ObjectIsString(Type*, Typer*); |
static Type* ObjectIsUndetectable(Type*, Typer*); |
- static Type* JSAddRanger(double lhs_min, double lhs_max, double rhs_min, |
- double rhs_max, Typer* t); |
- static Type* JSSubtractRanger(RangeType*, RangeType*, Typer*); |
- static Type* JSDivideRanger(RangeType*, RangeType*, Typer*); |
- static Type* JSModulusRanger(RangeType*, RangeType*, Typer*); |
- |
static ComparisonOutcome JSCompareTyper(Type*, Type*, Typer*); |
#define DECLARE_METHOD(x) static Type* x##Typer(Type*, Type*, Typer*); |
@@ -382,27 +377,8 @@ Type* Typer::Visitor::FalsifyUndefined(ComparisonOutcome outcome, Typer* t) { |
return t->singleton_true_; |
} |
- |
-Type* Typer::Visitor::Rangify(Type* type, Typer* t) { |
- if (type->IsRange()) return type; // Shortcut. |
- if (!type->Is(t->cache_.kInteger)) { |
- return type; // Give up on non-integer types. |
- } |
- double min = type->Min(); |
- double max = type->Max(); |
- // Handle the degenerate case of empty bitset types (such as |
- // OtherUnsigned31 and OtherSigned32 on 64-bit architectures). |
- if (std::isnan(min)) { |
- DCHECK(std::isnan(max)); |
- return type; |
- } |
- return Type::Range(min, max, t->zone()); |
-} |
- |
- |
// Type conversion. |
- |
Type* Typer::Visitor::ToPrimitive(Type* type, Typer* t) { |
if (type->Is(Type::Primitive()) && !type->Maybe(Type::Receiver())) { |
return type; |
@@ -1006,64 +982,6 @@ Type* Typer::Visitor::JSShiftRightLogicalTyper(Type* lhs, Type* rhs, Typer* t) { |
// JS arithmetic operators. |
- |
-// Returns the array's least element, ignoring NaN. |
-// There must be at least one non-NaN element. |
-// Any -0 is converted to 0. |
-static double array_min(double a[], size_t n) { |
- DCHECK(n != 0); |
- double x = +V8_INFINITY; |
- for (size_t i = 0; i < n; ++i) { |
- if (!std::isnan(a[i])) { |
- x = std::min(a[i], x); |
- } |
- } |
- DCHECK(!std::isnan(x)); |
- return x == 0 ? 0 : x; // -0 -> 0 |
-} |
- |
- |
-// Returns the array's greatest element, ignoring NaN. |
-// There must be at least one non-NaN element. |
-// Any -0 is converted to 0. |
-static double array_max(double a[], size_t n) { |
- DCHECK(n != 0); |
- double x = -V8_INFINITY; |
- for (size_t i = 0; i < n; ++i) { |
- if (!std::isnan(a[i])) { |
- x = std::max(a[i], x); |
- } |
- } |
- DCHECK(!std::isnan(x)); |
- return x == 0 ? 0 : x; // -0 -> 0 |
-} |
- |
-Type* Typer::Visitor::JSAddRanger(double lhs_min, double lhs_max, |
- double rhs_min, double rhs_max, Typer* t) { |
- double results[4]; |
- results[0] = lhs_min + rhs_min; |
- results[1] = lhs_min + rhs_max; |
- results[2] = lhs_max + rhs_min; |
- results[3] = lhs_max + rhs_max; |
- // The results 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 |
- // result cannot be nan either. |
- int nans = 0; |
- for (int i = 0; i < 4; ++i) { |
- if (std::isnan(results[i])) ++nans; |
- } |
- if (nans == 4) return Type::NaN(); // [-inf..-inf] + [inf..inf] or vice versa |
- 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 |
- // [-inf, -inf] + [n, +inf] = [-inf, -inf] \/ NaN |
- // [-inf, +inf] + [n, +inf] = [-inf, +inf] \/ NaN |
- // [-inf, m] + [n, +inf] = [-inf, +inf] \/ NaN |
-} |
- |
- |
Type* Typer::Visitor::JSAddTyper(Type* lhs, Type* rhs, Typer* t) { |
lhs = ToPrimitive(lhs, t); |
rhs = ToPrimitive(rhs, t); |
@@ -1075,102 +993,22 @@ Type* Typer::Visitor::JSAddTyper(Type* lhs, Type* rhs, Typer* t) { |
} |
} |
// The addition must be numeric. |
- lhs = ToNumber(lhs, t); |
- rhs = ToNumber(rhs, t); |
- // We can give more precise types for integers. |
- if (!lhs->Is(t->cache_.kIntegerOrMinusZeroOrNaN) || |
- !rhs->Is(t->cache_.kIntegerOrMinusZeroOrNaN)) { |
- return Type::Number(); |
- } |
- Type* int_lhs = Type::Intersect(lhs, t->cache_.kInteger, t->zone()); |
- Type* int_rhs = Type::Intersect(rhs, t->cache_.kInteger, t->zone()); |
- Type* result = JSAddRanger(int_lhs->Min(), int_lhs->Max(), int_rhs->Min(), |
- int_rhs->Max(), t); |
- if (lhs->Maybe(Type::NaN()) || rhs->Maybe(Type::NaN())) { |
- result = Type::Union(result, Type::NaN(), t->zone()); |
- } |
- if (lhs->Maybe(Type::MinusZero()) && rhs->Maybe(Type::MinusZero())) { |
- result = Type::Union(result, Type::MinusZero(), t->zone()); |
- } |
- return result; |
-} |
- |
-Type* Typer::Visitor::JSSubtractRanger(RangeType* lhs, RangeType* rhs, |
- Typer* t) { |
- double results[4]; |
- 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 |
- // result cannot be nan either. |
- int nans = 0; |
- for (int i = 0; i < 4; ++i) { |
- if (std::isnan(results[i])) ++nans; |
- } |
- if (nans == 4) return Type::NaN(); // [inf..inf] - [inf..inf] (all same sign) |
- 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 |
- // [-inf, -inf] - [-inf, -inf] = NaN |
- // [-inf, -inf] - [n, +inf] = [-inf, -inf] \/ NaN |
- // [m, +inf] - [-inf, n] = [-inf, +inf] \/ NaN |
+ return t->operation_typer()->NumericAdd(ToNumber(lhs, t), ToNumber(rhs, t)); |
} |
- |
Type* Typer::Visitor::JSSubtractTyper(Type* lhs, Type* rhs, Typer* t) { |
- lhs = Rangify(ToNumber(lhs, t), t); |
- rhs = Rangify(ToNumber(rhs, t), t); |
- if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return Type::NaN(); |
- if (lhs->IsRange() && rhs->IsRange()) { |
- return JSSubtractRanger(lhs->AsRange(), rhs->AsRange(), t); |
- } |
- return Type::Number(); |
+ return t->operation_typer()->NumericSubtract(ToNumber(lhs, t), |
+ ToNumber(rhs, t)); |
} |
- |
Type* Typer::Visitor::JSMultiplyTyper(Type* lhs, Type* rhs, Typer* t) { |
- lhs = Rangify(ToNumber(lhs, t), t); |
- rhs = Rangify(ToNumber(rhs, t), t); |
- if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return Type::NaN(); |
- if (lhs->IsRange() && rhs->IsRange()) { |
- double results[4]; |
- double lmin = lhs->AsRange()->Min(); |
- double lmax = lhs->AsRange()->Max(); |
- double rmin = rhs->AsRange()->Min(); |
- double rmax = rhs->AsRange()->Max(); |
- results[0] = lmin * rmin; |
- results[1] = lmin * rmax; |
- results[2] = lmax * rmin; |
- results[3] = lmax * rmax; |
- // If the result may be nan, we give up on calculating a precise type, |
- // because |
- // 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->cache_.kSingletonZero) && |
- (rmin == -V8_INFINITY || rmax == +V8_INFINITY)) || |
- (rhs->Maybe(t->cache_.kSingletonZero) && |
- (lmin == -V8_INFINITY || lmax == +V8_INFINITY)); |
- if (maybe_nan) return t->cache_.kIntegerOrMinusZeroOrNaN; // Giving up. |
- bool maybe_minuszero = (lhs->Maybe(t->cache_.kSingletonZero) && rmin < 0) || |
- (rhs->Maybe(t->cache_.kSingletonZero) && 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()) |
- : range; |
- } |
- return Type::Number(); |
+ return t->operation_typer()->NumericMultiply(ToNumber(lhs, t), |
+ ToNumber(rhs, t)); |
} |
- |
Type* Typer::Visitor::JSDivideTyper(Type* lhs, Type* rhs, Typer* t) { |
+ return t->operation_typer()->NumericDivide(ToNumber(lhs, t), |
+ ToNumber(rhs, t)); |
lhs = ToNumber(lhs, t); |
rhs = ToNumber(rhs, t); |
if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return Type::NaN(); |
@@ -1182,56 +1020,9 @@ Type* Typer::Visitor::JSDivideTyper(Type* lhs, Type* rhs, Typer* t) { |
return maybe_nan ? Type::Number() : Type::OrderedNumber(); |
} |
-Type* Typer::Visitor::JSModulusRanger(RangeType* lhs, RangeType* rhs, |
- Typer* t) { |
- 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; |
- double abs = std::min(labs, rabs); |
- bool maybe_minus_zero = false; |
- double omin = 0; |
- double omax = 0; |
- if (lmin >= 0) { // {lhs} positive. |
- omin = 0; |
- omax = abs; |
- } else if (lmax <= 0) { // {lhs} negative. |
- omin = 0 - abs; |
- omax = 0; |
- maybe_minus_zero = true; |
- } else { |
- omin = 0 - abs; |
- omax = abs; |
- maybe_minus_zero = true; |
- } |
- |
- Type* result = Type::Range(omin, omax, t->zone()); |
- if (maybe_minus_zero) |
- result = Type::Union(result, Type::MinusZero(), t->zone()); |
- return result; |
-} |
- |
- |
Type* Typer::Visitor::JSModulusTyper(Type* lhs, Type* rhs, Typer* t) { |
- lhs = ToNumber(lhs, 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->cache_.kZeroish) || |
- lhs->Min() == -V8_INFINITY || lhs->Max() == +V8_INFINITY) { |
- // Result maybe NaN. |
- return Type::Number(); |
- } |
- |
- lhs = Rangify(lhs, t); |
- rhs = Rangify(rhs, t); |
- if (lhs->IsRange() && rhs->IsRange()) { |
- return JSModulusRanger(lhs->AsRange(), rhs->AsRange(), t); |
- } |
- return Type::OrderedNumber(); |
+ return t->operation_typer()->NumericModulus(ToNumber(lhs, t), |
+ ToNumber(rhs, t)); |
} |