Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(117)

Side by Side Diff: src/compiler/typer.cc

Issue 943483002: [turbofan] Fix typing of comparisons. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Test Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | test/mjsunit/regress/regress-459955.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 the V8 project authors. All rights reserved. 1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/base/flags.h"
5 #include "src/bootstrapper.h" 6 #include "src/bootstrapper.h"
6 #include "src/compiler/graph-reducer.h" 7 #include "src/compiler/graph-reducer.h"
7 #include "src/compiler/js-operator.h" 8 #include "src/compiler/js-operator.h"
8 #include "src/compiler/node.h" 9 #include "src/compiler/node.h"
9 #include "src/compiler/node-properties.h" 10 #include "src/compiler/node-properties.h"
10 #include "src/compiler/simplified-operator.h" 11 #include "src/compiler/simplified-operator.h"
11 #include "src/compiler/typer.h" 12 #include "src/compiler/typer.h"
12 13
13 namespace v8 { 14 namespace v8 {
14 namespace internal { 15 namespace internal {
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after
318 Isolate* isolate() { return typer_->isolate(); } 319 Isolate* isolate() { return typer_->isolate(); }
319 Graph* graph() { return typer_->graph(); } 320 Graph* graph() { return typer_->graph(); }
320 MaybeHandle<Context> context() { return typer_->context(); } 321 MaybeHandle<Context> context() { return typer_->context(); }
321 322
322 typedef Type* (*UnaryTyperFun)(Type*, Typer* t); 323 typedef Type* (*UnaryTyperFun)(Type*, Typer* t);
323 typedef Type* (*BinaryTyperFun)(Type*, Type*, Typer* t); 324 typedef Type* (*BinaryTyperFun)(Type*, Type*, Typer* t);
324 325
325 Bounds TypeUnaryOp(Node* node, UnaryTyperFun); 326 Bounds TypeUnaryOp(Node* node, UnaryTyperFun);
326 Bounds TypeBinaryOp(Node* node, BinaryTyperFun); 327 Bounds TypeBinaryOp(Node* node, BinaryTyperFun);
327 328
329 enum ComparisonOutcomeFlags {
330 kComparisonTrue = 1,
331 kComparisonFalse = 2,
332 kComparisonUndefined = 4
333 };
334 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
335
336 static ComparisonOutcome Invert(ComparisonOutcome, Typer*);
328 static Type* Invert(Type*, Typer*); 337 static Type* Invert(Type*, Typer*);
329 static Type* FalsifyUndefined(Type*, Typer*); 338 static Type* FalsifyUndefined(ComparisonOutcome, Typer*);
330 static Type* Rangify(Type*, Typer*); 339 static Type* Rangify(Type*, Typer*);
331 340
332 static Type* ToPrimitive(Type*, Typer*); 341 static Type* ToPrimitive(Type*, Typer*);
333 static Type* ToBoolean(Type*, Typer*); 342 static Type* ToBoolean(Type*, Typer*);
334 static Type* ToNumber(Type*, Typer*); 343 static Type* ToNumber(Type*, Typer*);
335 static Type* ToString(Type*, Typer*); 344 static Type* ToString(Type*, Typer*);
336 static Type* NumberToInt32(Type*, Typer*); 345 static Type* NumberToInt32(Type*, Typer*);
337 static Type* NumberToUint32(Type*, Typer*); 346 static Type* NumberToUint32(Type*, Typer*);
338 347
339 static Type* JSAddRanger(Type::RangeType*, Type::RangeType*, Typer*); 348 static Type* JSAddRanger(Type::RangeType*, Type::RangeType*, Typer*);
340 static Type* JSSubtractRanger(Type::RangeType*, Type::RangeType*, Typer*); 349 static Type* JSSubtractRanger(Type::RangeType*, Type::RangeType*, Typer*);
341 static Type* JSMultiplyRanger(Type::RangeType*, Type::RangeType*, Typer*); 350 static Type* JSMultiplyRanger(Type::RangeType*, Type::RangeType*, Typer*);
342 static Type* JSDivideRanger(Type::RangeType*, Type::RangeType*, Typer*); 351 static Type* JSDivideRanger(Type::RangeType*, Type::RangeType*, Typer*);
343 static Type* JSModulusRanger(Type::RangeType*, Type::RangeType*, Typer*); 352 static Type* JSModulusRanger(Type::RangeType*, Type::RangeType*, Typer*);
344 353
345 static Type* JSCompareTyper(Type*, Type*, Typer*); 354 static ComparisonOutcome JSCompareTyper(Type*, Type*, Typer*);
346 355
347 #define DECLARE_METHOD(x) static Type* x##Typer(Type*, Type*, Typer*); 356 #define DECLARE_METHOD(x) static Type* x##Typer(Type*, Type*, Typer*);
348 JS_SIMPLE_BINOP_LIST(DECLARE_METHOD) 357 JS_SIMPLE_BINOP_LIST(DECLARE_METHOD)
349 #undef DECLARE_METHOD 358 #undef DECLARE_METHOD
350 359
351 static Type* JSUnaryNotTyper(Type*, Typer*); 360 static Type* JSUnaryNotTyper(Type*, Typer*);
352 static Type* JSLoadPropertyTyper(Type*, Type*, Typer*); 361 static Type* JSLoadPropertyTyper(Type*, Type*, Typer*);
353 static Type* JSCallFunctionTyper(Type*, Typer*); 362 static Type* JSCallFunctionTyper(Type*, Typer*);
354 363
355 Reduction UpdateBounds(Node* node, Bounds current) { 364 Reduction UpdateBounds(Node* node, Bounds current) {
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
461 upper->IsConstant()) 470 upper->IsConstant())
462 ? upper 471 ? upper
463 : f(left.lower, right.lower, typer_)) 472 : f(left.lower, right.lower, typer_))
464 : Type::None(); 473 : Type::None();
465 // TODO(neis): Figure out what to do with lower bound. 474 // TODO(neis): Figure out what to do with lower bound.
466 return Bounds(lower, upper); 475 return Bounds(lower, upper);
467 } 476 }
468 477
469 478
470 Type* Typer::Visitor::Invert(Type* type, Typer* t) { 479 Type* Typer::Visitor::Invert(Type* type, Typer* t) {
480 DCHECK(type->Is(Type::Boolean()));
481 DCHECK(type->IsInhabited());
471 if (type->Is(t->singleton_false)) return t->singleton_true; 482 if (type->Is(t->singleton_false)) return t->singleton_true;
472 if (type->Is(t->singleton_true)) return t->singleton_false; 483 if (type->Is(t->singleton_true)) return t->singleton_false;
473 return type; 484 return type;
474 } 485 }
475 486
476 487
477 Type* Typer::Visitor::FalsifyUndefined(Type* type, Typer* t) { 488 Typer::Visitor::ComparisonOutcome Typer::Visitor::Invert(
478 if (type->Is(Type::Undefined())) return t->singleton_false; 489 ComparisonOutcome outcome, Typer* t) {
479 return type; 490 ComparisonOutcome result(0);
491 if ((outcome & kComparisonUndefined) != 0) result |= kComparisonUndefined;
492 if ((outcome & kComparisonTrue) != 0) result |= kComparisonFalse;
493 if ((outcome & kComparisonFalse) != 0) result |= kComparisonTrue;
494 return result;
480 } 495 }
481 496
482 497
498 Type* Typer::Visitor::FalsifyUndefined(ComparisonOutcome outcome, Typer* t) {
499 if ((outcome & kComparisonFalse) != 0 ||
500 (outcome & kComparisonUndefined) != 0) {
501 return (outcome & kComparisonTrue) != 0 ? Type::Boolean()
502 : t->singleton_false;
503 }
504 // Type should be non empty, so we know it should be true.
505 DCHECK((outcome & kComparisonTrue) != 0);
506 return t->singleton_true;
507 }
508
509
483 Type* Typer::Visitor::Rangify(Type* type, Typer* t) { 510 Type* Typer::Visitor::Rangify(Type* type, Typer* t) {
484 if (type->IsRange()) return type; // Shortcut. 511 if (type->IsRange()) return type; // Shortcut.
485 if (!type->Is(t->integer) && !type->Is(Type::Integral32())) { 512 if (!type->Is(t->integer) && !type->Is(Type::Integral32())) {
486 return type; // Give up on non-integer types. 513 return type; // Give up on non-integer types.
487 } 514 }
488 double min = type->Min(); 515 double min = type->Min();
489 double max = type->Max(); 516 double max = type->Max();
490 // Handle the degenerate case of empty bitset types (such as 517 // Handle the degenerate case of empty bitset types (such as
491 // OtherUnsigned31 and OtherSigned32 on 64-bit architectures). 518 // OtherUnsigned31 and OtherSigned32 on 64-bit architectures).
492 if (std::isnan(min)) { 519 if (std::isnan(min)) {
(...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after
766 793
767 Type* Typer::Visitor::JSStrictNotEqualTyper(Type* lhs, Type* rhs, Typer* t) { 794 Type* Typer::Visitor::JSStrictNotEqualTyper(Type* lhs, Type* rhs, Typer* t) {
768 return Invert(JSStrictEqualTyper(lhs, rhs, t), t); 795 return Invert(JSStrictEqualTyper(lhs, rhs, t), t);
769 } 796 }
770 797
771 798
772 // The EcmaScript specification defines the four relational comparison operators 799 // The EcmaScript specification defines the four relational comparison operators
773 // (<, <=, >=, >) with the help of a single abstract one. It behaves like < 800 // (<, <=, >=, >) with the help of a single abstract one. It behaves like <
774 // but returns undefined when the inputs cannot be compared. 801 // but returns undefined when the inputs cannot be compared.
775 // We implement the typing analogously. 802 // We implement the typing analogously.
776 Type* Typer::Visitor::JSCompareTyper(Type* lhs, Type* rhs, Typer* t) { 803 Typer::Visitor::ComparisonOutcome Typer::Visitor::JSCompareTyper(Type* lhs,
804 Type* rhs,
805 Typer* t) {
777 lhs = ToPrimitive(lhs, t); 806 lhs = ToPrimitive(lhs, t);
778 rhs = ToPrimitive(rhs, t); 807 rhs = ToPrimitive(rhs, t);
779 if (lhs->Maybe(Type::String()) && rhs->Maybe(Type::String())) { 808 if (lhs->Maybe(Type::String()) && rhs->Maybe(Type::String())) {
780 return Type::Boolean(); 809 return ComparisonOutcome(kComparisonTrue) |
810 ComparisonOutcome(kComparisonFalse);
781 } 811 }
782 lhs = ToNumber(lhs, t); 812 lhs = ToNumber(lhs, t);
783 rhs = ToNumber(rhs, t); 813 rhs = ToNumber(rhs, t);
784 if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return Type::Undefined(); 814
815 // Shortcut for NaNs.
816 if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return kComparisonUndefined;
817
818 ComparisonOutcome result;
785 if (lhs->IsConstant() && rhs->Is(lhs)) { 819 if (lhs->IsConstant() && rhs->Is(lhs)) {
786 // Types are equal and are inhabited only by a single semantic value, 820 // Types are equal and are inhabited only by a single semantic value.
787 // which is not NaN due to the previous check. 821 result = kComparisonFalse;
788 return t->singleton_false; 822 } else if (lhs->Min() >= rhs->Max()) {
823 result = kComparisonFalse;
824 } else if (lhs->Max() < rhs->Min()) {
825 result = kComparisonTrue;
826 } else {
827 // We cannot figure out the result, return both true and false. (We do not
828 // have to return undefined because that cannot affect the result of
829 // FalsifyUndefined.)
830 return ComparisonOutcome(kComparisonTrue) |
831 ComparisonOutcome(kComparisonFalse);
789 } 832 }
790 if (lhs->Min() >= rhs->Max()) return t->singleton_false; 833 // Add the undefined if we could see NaN.
791 if (lhs->Max() < rhs->Min() && 834 if (lhs->Maybe(Type::NaN()) || rhs->Maybe(Type::NaN())) {
792 !lhs->Maybe(Type::NaN()) && !rhs->Maybe(Type::NaN())) { 835 result |= kComparisonUndefined;
793 return t->singleton_true;
794 } 836 }
795 return Type::Boolean(); 837 return result;
796 } 838 }
797 839
798 840
799 Type* Typer::Visitor::JSLessThanTyper(Type* lhs, Type* rhs, Typer* t) { 841 Type* Typer::Visitor::JSLessThanTyper(Type* lhs, Type* rhs, Typer* t) {
800 return FalsifyUndefined(JSCompareTyper(lhs, rhs, t), t); 842 return FalsifyUndefined(JSCompareTyper(lhs, rhs, t), t);
801 } 843 }
802 844
803 845
804 Type* Typer::Visitor::JSGreaterThanTyper(Type* lhs, Type* rhs, Typer* t) { 846 Type* Typer::Visitor::JSGreaterThanTyper(Type* lhs, Type* rhs, Typer* t) {
805 return FalsifyUndefined(JSCompareTyper(rhs, lhs, t), t); 847 return FalsifyUndefined(JSCompareTyper(rhs, lhs, t), t);
(...skipping 1331 matching lines...) Expand 10 before | Expand all | Expand 10 after
2137 TYPED_ARRAYS(TYPED_ARRAY_CASE) 2179 TYPED_ARRAYS(TYPED_ARRAY_CASE)
2138 #undef TYPED_ARRAY_CASE 2180 #undef TYPED_ARRAY_CASE
2139 } 2181 }
2140 } 2182 }
2141 return Type::Constant(value, zone()); 2183 return Type::Constant(value, zone());
2142 } 2184 }
2143 2185
2144 } // namespace compiler 2186 } // namespace compiler
2145 } // namespace internal 2187 } // namespace internal
2146 } // namespace v8 2188 } // namespace v8
OLDNEW
« no previous file with comments | « no previous file | test/mjsunit/regress/regress-459955.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698