Index: src/compiler/typer.cc |
diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc |
index e9f3a3564ffd8da3e93b35b4eb8c644fb7baad32..f646d19ba13d3ab03a318e328b93316639823c94 100644 |
--- a/src/compiler/typer.cc |
+++ b/src/compiler/typer.cc |
@@ -2,6 +2,7 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
+#include "src/base/flags.h" |
#include "src/bootstrapper.h" |
#include "src/compiler/graph-reducer.h" |
#include "src/compiler/js-operator.h" |
@@ -325,8 +326,16 @@ class Typer::Visitor : public Reducer { |
Bounds TypeUnaryOp(Node* node, UnaryTyperFun); |
Bounds TypeBinaryOp(Node* node, BinaryTyperFun); |
+ enum ComparisonOutcomeFlags { |
+ kComparisonTrue = 1, |
+ kComparisonFalse = 2, |
+ kComparisonUndefined = 4 |
+ }; |
+ typedef base::Flags<ComparisonOutcomeFlags> ComparisonOutcome; |
Benedikt Meurer
2015/02/19 10:32:57
You should also DEFINE_OPERATOR_FOR_FLAGS here.
Jarin
2015/02/19 10:50:21
Unfortunately, the macro does not work with privat
|
+ |
+ static ComparisonOutcome Invert(ComparisonOutcome, Typer*); |
static Type* Invert(Type*, Typer*); |
- static Type* FalsifyUndefined(Type*, Typer*); |
+ static Type* FalsifyUndefined(ComparisonOutcome, Typer*); |
static Type* Rangify(Type*, Typer*); |
static Type* ToPrimitive(Type*, Typer*); |
@@ -342,7 +351,7 @@ class Typer::Visitor : public Reducer { |
static Type* JSDivideRanger(Type::RangeType*, Type::RangeType*, Typer*); |
static Type* JSModulusRanger(Type::RangeType*, Type::RangeType*, Typer*); |
- static Type* JSCompareTyper(Type*, Type*, Typer*); |
+ static ComparisonOutcome JSCompareTyper(Type*, Type*, Typer*); |
#define DECLARE_METHOD(x) static Type* x##Typer(Type*, Type*, Typer*); |
JS_SIMPLE_BINOP_LIST(DECLARE_METHOD) |
@@ -468,15 +477,33 @@ 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; |
return type; |
} |
-Type* Typer::Visitor::FalsifyUndefined(Type* type, Typer* t) { |
- if (type->Is(Type::Undefined())) return t->singleton_false; |
- return type; |
+Typer::Visitor::ComparisonOutcome Typer::Visitor::Invert( |
+ ComparisonOutcome outcome, Typer* t) { |
+ ComparisonOutcome result(0); |
+ if ((outcome & kComparisonUndefined) != 0) result |= kComparisonUndefined; |
+ if ((outcome & kComparisonTrue) != 0) result |= kComparisonFalse; |
+ if ((outcome & kComparisonFalse) != 0) result |= kComparisonTrue; |
+ return result; |
+} |
+ |
+ |
+Type* Typer::Visitor::FalsifyUndefined(ComparisonOutcome outcome, Typer* t) { |
+ if ((outcome & kComparisonFalse) != 0 || |
+ (outcome & kComparisonUndefined) != 0) { |
+ return (outcome & kComparisonTrue) != 0 ? Type::Boolean() |
+ : t->singleton_false; |
+ } |
+ // Type should be non empty, so we know it should be true. |
+ DCHECK((outcome & kComparisonTrue) != 0); |
+ return t->singleton_true; |
} |
@@ -773,26 +800,41 @@ Type* Typer::Visitor::JSStrictNotEqualTyper(Type* lhs, Type* rhs, Typer* t) { |
// (<, <=, >=, >) with the help of a single abstract one. It behaves like < |
// but returns undefined when the inputs cannot be compared. |
// We implement the typing analogously. |
-Type* Typer::Visitor::JSCompareTyper(Type* lhs, Type* rhs, Typer* t) { |
+Typer::Visitor::ComparisonOutcome Typer::Visitor::JSCompareTyper(Type* lhs, |
+ Type* rhs, |
+ Typer* t) { |
lhs = ToPrimitive(lhs, t); |
rhs = ToPrimitive(rhs, t); |
if (lhs->Maybe(Type::String()) && rhs->Maybe(Type::String())) { |
- return Type::Boolean(); |
+ return ComparisonOutcome(kComparisonTrue) | |
+ ComparisonOutcome(kComparisonFalse); |
} |
lhs = ToNumber(lhs, t); |
rhs = ToNumber(rhs, t); |
- if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return Type::Undefined(); |
+ |
+ // Shortcut for NaNs. |
+ if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return kComparisonUndefined; |
+ |
+ ComparisonOutcome result; |
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 previous check. |
- return t->singleton_false; |
+ // Types are equal and are inhabited only by a single semantic value. |
+ result = kComparisonFalse; |
+ } else if (lhs->Min() >= rhs->Max()) { |
+ result = kComparisonFalse; |
+ } else if (lhs->Max() < rhs->Min()) { |
+ result = kComparisonTrue; |
+ } else { |
+ // We cannot figure out the result, return both true and false. (We do not |
+ // have to return undefined because that cannot affect the result of |
+ // FalsifyUndefined.) |
+ return ComparisonOutcome(kComparisonTrue) | |
+ ComparisonOutcome(kComparisonFalse); |
} |
- if (lhs->Min() >= rhs->Max()) return t->singleton_false; |
- if (lhs->Max() < rhs->Min() && |
- !lhs->Maybe(Type::NaN()) && !rhs->Maybe(Type::NaN())) { |
- return t->singleton_true; |
+ // Add the undefined if we could see NaN. |
+ if (lhs->Maybe(Type::NaN()) || rhs->Maybe(Type::NaN())) { |
+ result |= kComparisonUndefined; |
} |
- return Type::Boolean(); |
+ return result; |
} |