From: jarin Date: Thu, 19 Feb 2015 10:56:18 +0000 (-0800) Subject: [turbofan] Fix typing of comparisons. X-Git-Tag: upstream/4.7.83~4297 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=9951e1e5f0a7259ca2c07fb616dc907f7e4a23f7;p=platform%2Fupstream%2Fv8.git [turbofan] Fix typing of comparisons. BUG=chromium:459955 LOG=n R=bmeurer@chromium.org Review URL: https://codereview.chromium.org/943483002 Cr-Commit-Position: refs/heads/master@{#26743} --- diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc index e9f3a35..f646d19 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 ComparisonOutcome; + + 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; } diff --git a/test/mjsunit/regress/regress-459955.js b/test/mjsunit/regress/regress-459955.js new file mode 100644 index 0000000..24eff6d --- /dev/null +++ b/test/mjsunit/regress/regress-459955.js @@ -0,0 +1,10 @@ +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +function f(x) { + var v; + if (x) v = 0; + return v <= 1; +} +assertFalse(f(false));