summaryrefslogtreecommitdiff
path: root/deps/v8/src/compiler/operation-typer.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/compiler/operation-typer.cc')
-rw-r--r--deps/v8/src/compiler/operation-typer.cc130
1 files changed, 76 insertions, 54 deletions
diff --git a/deps/v8/src/compiler/operation-typer.cc b/deps/v8/src/compiler/operation-typer.cc
index 67a7b138a5..313a263ebb 100644
--- a/deps/v8/src/compiler/operation-typer.cc
+++ b/deps/v8/src/compiler/operation-typer.cc
@@ -16,14 +16,11 @@ namespace v8 {
namespace internal {
namespace compiler {
-OperationTyper::OperationTyper(Isolate* isolate, JSHeapBroker* js_heap_broker,
- Zone* zone)
+OperationTyper::OperationTyper(JSHeapBroker* js_heap_broker, Zone* zone)
: zone_(zone), cache_(TypeCache::Get()) {
- Factory* factory = isolate->factory();
- infinity_ =
- Type::NewConstant(js_heap_broker, factory->infinity_value(), zone);
- minus_infinity_ =
- Type::NewConstant(js_heap_broker, factory->minus_infinity_value(), zone);
+ Factory* factory = js_heap_broker->isolate()->factory();
+ infinity_ = Type::NewConstant(V8_INFINITY, zone);
+ minus_infinity_ = Type::NewConstant(-V8_INFINITY, zone);
Type truncating_to_zero = Type::MinusZeroOrNaN();
DCHECK(!truncating_to_zero.Maybe(Type::Integral32()));
@@ -265,59 +262,61 @@ Type OperationTyper::ConvertReceiver(Type type) {
return type;
}
-// Returns the result type of converting {type} to number, if the
-// result does not depend on conversion options.
-base::Optional<Type> OperationTyper::ToNumberCommon(Type type) {
+Type OperationTyper::ToNumber(Type type) {
if (type.Is(Type::Number())) return type;
- if (type.Is(Type::NullOrUndefined())) {
- if (type.Is(Type::Null())) return cache_.kSingletonZero;
- if (type.Is(Type::Undefined())) return Type::NaN();
- return Type::Union(Type::NaN(), cache_.kSingletonZero, zone());
- }
- if (type.Is(Type::Boolean())) {
- if (type.Is(singleton_false_)) return cache_.kSingletonZero;
- if (type.Is(singleton_true_)) return cache_.kSingletonOne;
- return cache_.kZeroOrOne;
+
+ // If {type} includes any receivers, we cannot tell what kind of
+ // Number their callbacks might produce. Similarly in the case
+ // where {type} includes String, it's not possible at this point
+ // to tell which exact numbers are going to be produced.
+ if (type.Maybe(Type::StringOrReceiver())) return Type::Number();
+
+ // Both Symbol and BigInt primitives will cause exceptions
+ // to be thrown from ToNumber conversions, so they don't
+ // contribute to the resulting type anyways.
+ type = Type::Intersect(type, Type::PlainPrimitive(), zone());
+
+ // This leaves us with Number\/Oddball, so deal with the individual
+ // Oddball primitives below.
+ DCHECK(type.Is(Type::NumberOrOddball()));
+ if (type.Maybe(Type::Null())) {
+ // ToNumber(null) => +0
+ type = Type::Union(type, cache_.kSingletonZero, zone());
}
- if (type.Is(Type::NumberOrOddball())) {
- if (type.Is(Type::NumberOrUndefined())) {
- type = Type::Union(type, Type::NaN(), zone());
- } else if (type.Is(Type::NullOrNumber())) {
- type = Type::Union(type, cache_.kSingletonZero, zone());
- } else if (type.Is(Type::BooleanOrNullOrNumber())) {
- type = Type::Union(type, cache_.kZeroOrOne, zone());
- } else {
- type = Type::Union(type, cache_.kZeroOrOneOrNaN, zone());
- }
- return Type::Intersect(type, Type::Number(), zone());
+ if (type.Maybe(Type::Undefined())) {
+ // ToNumber(undefined) => NaN
+ type = Type::Union(type, Type::NaN(), zone());
}
- return base::Optional<Type>();
-}
-
-Type OperationTyper::ToNumberOrNumeric(Object::Conversion mode, Type type) {
- if (base::Optional<Type> maybe_result_type = ToNumberCommon(type)) {
- return *maybe_result_type;
+ if (type.Maybe(singleton_false_)) {
+ // ToNumber(false) => +0
+ type = Type::Union(type, cache_.kSingletonZero, zone());
}
- if (type.Is(Type::BigInt())) {
- return mode == Object::Conversion::kToNumber ? Type::None() : type;
+ if (type.Maybe(singleton_true_)) {
+ // ToNumber(true) => +1
+ type = Type::Union(type, cache_.kSingletonOne, zone());
}
- return mode == Object::Conversion::kToNumber ? Type::Number()
- : Type::Numeric();
-}
-
-Type OperationTyper::ToNumber(Type type) {
- return ToNumberOrNumeric(Object::Conversion::kToNumber, type);
+ return Type::Intersect(type, Type::Number(), zone());
}
Type OperationTyper::ToNumberConvertBigInt(Type type) {
- if (base::Optional<Type> maybe_result_type = ToNumberCommon(type)) {
- return *maybe_result_type;
- }
- return Type::Number();
+ // If the {type} includes any receivers, then the callbacks
+ // might actually produce BigInt primitive values here.
+ bool maybe_bigint =
+ type.Maybe(Type::BigInt()) || type.Maybe(Type::Receiver());
+ type = ToNumber(Type::Intersect(type, Type::NonBigInt(), zone()));
+
+ // Any BigInt is rounded to an integer Number in the range [-inf, inf].
+ return maybe_bigint ? Type::Union(type, cache_.kInteger, zone()) : type;
}
Type OperationTyper::ToNumeric(Type type) {
- return ToNumberOrNumeric(Object::Conversion::kToNumeric, type);
+ // If the {type} includes any receivers, then the callbacks
+ // might actually produce BigInt primitive values here.
+ if (type.Maybe(Type::Receiver())) {
+ type = Type::Union(type, Type::BigInt(), zone());
+ }
+ return Type::Union(ToNumber(Type::Intersect(type, Type::NonBigInt(), zone())),
+ Type::Intersect(type, Type::BigInt(), zone()), zone());
}
Type OperationTyper::NumberAbs(Type type) {
@@ -415,7 +414,7 @@ Type OperationTyper::NumberExp(Type type) {
Type OperationTyper::NumberExpm1(Type type) {
DCHECK(type.Is(Type::Number()));
- return Type::Union(Type::PlainNumber(), Type::NaN(), zone());
+ return Type::Number();
}
Type OperationTyper::NumberFloor(Type type) {
@@ -999,7 +998,6 @@ Type OperationTyper::NumberMax(Type lhs, Type rhs) {
if (lhs.Is(Type::NaN()) || rhs.Is(Type::NaN())) return Type::NaN();
Type type = Type::None();
- // TODO(turbofan): Improve minus zero handling here.
if (lhs.Maybe(Type::NaN()) || rhs.Maybe(Type::NaN())) {
type = Type::Union(type, Type::NaN(), zone());
}
@@ -1007,10 +1005,17 @@ Type OperationTyper::NumberMax(Type lhs, Type rhs) {
DCHECK(!lhs.IsNone());
rhs = Type::Intersect(rhs, Type::OrderedNumber(), zone());
DCHECK(!rhs.IsNone());
- if (lhs.Is(cache_.kInteger) && rhs.Is(cache_.kInteger)) {
+ if (lhs.Is(cache_.kIntegerOrMinusZero) &&
+ rhs.Is(cache_.kIntegerOrMinusZero)) {
+ // TODO(turbofan): This could still be improved in ruling out -0 when
+ // one of the inputs' min is 0.
double max = std::max(lhs.Max(), rhs.Max());
double min = std::max(lhs.Min(), rhs.Min());
type = Type::Union(type, Type::Range(min, max, zone()), zone());
+ if (min <= 0.0 && 0.0 <= max &&
+ (lhs.Maybe(Type::MinusZero()) || rhs.Maybe(Type::MinusZero()))) {
+ type = Type::Union(type, Type::MinusZero(), zone());
+ }
} else {
type = Type::Union(type, Type::Union(lhs, rhs, zone()), zone());
}
@@ -1025,7 +1030,6 @@ Type OperationTyper::NumberMin(Type lhs, Type rhs) {
if (lhs.Is(Type::NaN()) || rhs.Is(Type::NaN())) return Type::NaN();
Type type = Type::None();
- // TODO(turbofan): Improve minus zero handling here.
if (lhs.Maybe(Type::NaN()) || rhs.Maybe(Type::NaN())) {
type = Type::Union(type, Type::NaN(), zone());
}
@@ -1033,10 +1037,15 @@ Type OperationTyper::NumberMin(Type lhs, Type rhs) {
DCHECK(!lhs.IsNone());
rhs = Type::Intersect(rhs, Type::OrderedNumber(), zone());
DCHECK(!rhs.IsNone());
- if (lhs.Is(cache_.kInteger) && rhs.Is(cache_.kInteger)) {
+ if (lhs.Is(cache_.kIntegerOrMinusZero) &&
+ rhs.Is(cache_.kIntegerOrMinusZero)) {
double max = std::min(lhs.Max(), rhs.Max());
double min = std::min(lhs.Min(), rhs.Min());
type = Type::Union(type, Type::Range(min, max, zone()), zone());
+ if (min <= 0.0 && 0.0 <= max &&
+ (lhs.Maybe(Type::MinusZero()) || rhs.Maybe(Type::MinusZero()))) {
+ type = Type::Union(type, Type::MinusZero(), zone());
+ }
} else {
type = Type::Union(type, Type::Union(lhs, rhs, zone()), zone());
}
@@ -1163,6 +1172,19 @@ Type OperationTyper::StrictEqual(Type lhs, Type rhs) {
return Type::Boolean();
}
+Type OperationTyper::CheckBounds(Type index, Type length) {
+ DCHECK(length.Is(Type::Unsigned31()));
+ if (index.Maybe(Type::MinusZero())) {
+ index = Type::Union(index, cache_.kSingletonZero, zone());
+ }
+ index = Type::Intersect(index, Type::Integral32(), zone());
+ if (index.IsNone() || length.IsNone()) return Type::None();
+ double min = std::max(index.Min(), 0.0);
+ double max = std::min(index.Max(), length.Max() - 1);
+ if (max < min) return Type::None();
+ return Type::Range(min, max, zone());
+}
+
Type OperationTyper::CheckFloat64Hole(Type type) {
if (type.Maybe(Type::Hole())) {
// Turn "the hole" into undefined.