Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/intermediate_language.h" | 5 #include "vm/intermediate_language.h" |
| 6 | 6 |
| 7 #include "vm/bigint_operations.h" | 7 #include "vm/bigint_operations.h" |
| 8 #include "vm/bit_vector.h" | 8 #include "vm/bit_vector.h" |
| 9 #include "vm/cpu.h" | 9 #include "vm/cpu.h" |
| 10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| (...skipping 2445 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2456 | 2456 |
| 2457 | 2457 |
| 2458 RangeBoundary RangeBoundary::FromDefinition(Definition* defn, intptr_t offs) { | 2458 RangeBoundary RangeBoundary::FromDefinition(Definition* defn, intptr_t offs) { |
| 2459 if (defn->IsConstant() && defn->AsConstant()->value().IsSmi()) { | 2459 if (defn->IsConstant() && defn->AsConstant()->value().IsSmi()) { |
| 2460 return FromConstant(Smi::Cast(defn->AsConstant()->value()).Value() + offs); | 2460 return FromConstant(Smi::Cast(defn->AsConstant()->value()).Value() + offs); |
| 2461 } | 2461 } |
| 2462 return RangeBoundary(kSymbol, reinterpret_cast<intptr_t>(defn), offs); | 2462 return RangeBoundary(kSymbol, reinterpret_cast<intptr_t>(defn), offs); |
| 2463 } | 2463 } |
| 2464 | 2464 |
| 2465 | 2465 |
| 2466 RangeBoundary RangeBoundary::LowerBound() const { | 2466 RangeBoundary RangeBoundary::LowerBound() const { |
|
Vyacheslav Egorov (Google)
2014/06/11 17:36:37
I don't think having PositiveInfinity.LowerBound()
| |
| 2467 if (IsNegativeInfinity()) return *this; | 2467 if (IsConstantOrInfinity()) return *this; |
| 2468 if (IsConstant()) return *this; | |
| 2469 return Add(Range::ConstantMin(symbol()->range()), | 2468 return Add(Range::ConstantMin(symbol()->range()), |
| 2470 RangeBoundary::FromConstant(offset_), | 2469 RangeBoundary::FromConstant(offset_), |
| 2471 NegativeInfinity()); | 2470 NegativeInfinity()); |
| 2472 } | 2471 } |
| 2473 | 2472 |
| 2474 | 2473 |
| 2475 RangeBoundary RangeBoundary::UpperBound() const { | 2474 RangeBoundary RangeBoundary::UpperBound() const { |
| 2476 if (IsPositiveInfinity()) return *this; | 2475 if (IsConstantOrInfinity()) return *this; |
|
Vyacheslav Egorov (Google)
2014/06/11 17:36:37
Ditto.
| |
| 2477 if (IsConstant()) return *this; | |
| 2478 return Add(Range::ConstantMax(symbol()->range()), | 2476 return Add(Range::ConstantMax(symbol()->range()), |
| 2479 RangeBoundary::FromConstant(offset_), | 2477 RangeBoundary::FromConstant(offset_), |
| 2480 PositiveInfinity()); | 2478 PositiveInfinity()); |
| 2481 } | 2479 } |
| 2482 | 2480 |
| 2483 | 2481 |
| 2482 RangeBoundary RangeBoundary::Add(const RangeBoundary& a, | |
| 2483 const RangeBoundary& b, | |
| 2484 const RangeBoundary& overflow) { | |
| 2485 ASSERT(a.IsConstantOrInfinity() && b.IsConstantOrInfinity()); | |
| 2486 | |
| 2487 intptr_t result = a.Value() + b.Value(); | |
| 2488 if (!Smi::IsValid(result)) { | |
| 2489 return overflow; | |
| 2490 } | |
| 2491 return RangeBoundary::FromConstant(result); | |
| 2492 } | |
| 2493 | |
| 2494 | |
| 2495 RangeBoundary RangeBoundary::Sub(const RangeBoundary& a, | |
| 2496 const RangeBoundary& b, | |
| 2497 const RangeBoundary& overflow) { | |
| 2498 ASSERT(a.IsConstantOrInfinity() && b.IsConstantOrInfinity()); | |
| 2499 | |
| 2500 intptr_t result = a.Value() - b.Value(); | |
| 2501 if (!Smi::IsValid(result)) { | |
| 2502 return overflow; | |
| 2503 } | |
| 2504 return RangeBoundary::FromConstant(result); | |
| 2505 } | |
| 2506 | |
| 2507 | |
| 2484 static Definition* UnwrapConstraint(Definition* defn) { | 2508 static Definition* UnwrapConstraint(Definition* defn) { |
| 2485 while (defn->IsConstraint()) { | 2509 while (defn->IsConstraint()) { |
| 2486 defn = defn->AsConstraint()->value()->definition(); | 2510 defn = defn->AsConstraint()->value()->definition(); |
| 2487 } | 2511 } |
| 2488 return defn; | 2512 return defn; |
| 2489 } | 2513 } |
| 2490 | 2514 |
| 2491 | 2515 |
| 2492 static bool AreEqualDefinitions(Definition* a, Definition* b) { | 2516 static bool AreEqualDefinitions(Definition* a, Definition* b) { |
| 2493 a = UnwrapConstraint(a); | 2517 a = UnwrapConstraint(a); |
| 2494 b = UnwrapConstraint(b); | 2518 b = UnwrapConstraint(b); |
| 2495 return (a == b) || | 2519 return (a == b) || |
| 2496 (a->AllowsCSE() && | 2520 (a->AllowsCSE() && |
| 2497 a->Dependencies().IsNone() && | 2521 a->Dependencies().IsNone() && |
| 2498 b->AllowsCSE() && | 2522 b->AllowsCSE() && |
| 2499 b->Dependencies().IsNone() && | 2523 b->Dependencies().IsNone() && |
| 2500 a->Equals(b)); | 2524 a->Equals(b)); |
| 2501 } | 2525 } |
| 2502 | 2526 |
| 2503 | 2527 |
| 2504 // Returns true if two range boundaries refer to the same symbol. | 2528 // Returns true if two range boundaries refer to the same symbol. |
| 2505 static bool DependOnSameSymbol(const RangeBoundary& a, const RangeBoundary& b) { | 2529 static bool DependOnSameSymbol(const RangeBoundary& a, const RangeBoundary& b) { |
| 2506 return a.IsSymbol() && b.IsSymbol() && | 2530 return a.IsSymbol() && b.IsSymbol() && |
| 2507 AreEqualDefinitions(a.symbol(), b.symbol()); | 2531 AreEqualDefinitions(a.symbol(), b.symbol()); |
| 2508 } | 2532 } |
| 2509 | 2533 |
| 2510 | 2534 |
| 2511 // Returns true if range has a least specific minimum value. | 2535 bool RangeBoundary::Equals(const RangeBoundary& other) const { |
| 2512 static bool IsMinSmi(Range* range) { | 2536 if (IsConstant() && other.IsConstant()) { |
| 2513 return (range == NULL) || | 2537 return Value() == other.Value(); |
| 2514 (range->min().IsConstant() && | 2538 } else if (IsInfinity() && other.IsInfinity()) { |
| 2515 (range->min().value() <= Smi::kMinValue)); | 2539 return Value() == other.Value(); |
| 2516 } | 2540 } else if (IsSymbol() && other.IsSymbol()) { |
| 2517 | 2541 return (offset() == other.offset()) && DependOnSameSymbol(*this, other); |
| 2518 | |
| 2519 // Returns true if range has a least specific maximium value. | |
| 2520 static bool IsMaxSmi(Range* range) { | |
| 2521 return (range == NULL) || | |
| 2522 (range->max().IsConstant() && | |
| 2523 (range->max().value() >= Smi::kMaxValue)); | |
| 2524 } | |
| 2525 | |
| 2526 | |
| 2527 // Returns true if two range boundaries can be proven to be equal. | |
| 2528 static bool IsEqual(const RangeBoundary& a, const RangeBoundary& b) { | |
| 2529 if (a.IsConstant() && b.IsConstant()) { | |
| 2530 return a.value() == b.value(); | |
| 2531 } else if (a.IsSymbol() && b.IsSymbol()) { | |
| 2532 return (a.offset() == b.offset()) && DependOnSameSymbol(a, b); | |
| 2533 } else { | |
| 2534 return false; | |
| 2535 } | 2542 } |
| 2543 return false; | |
| 2536 } | 2544 } |
| 2537 | 2545 |
| 2538 | 2546 |
| 2539 static RangeBoundary CanonicalizeBoundary(const RangeBoundary& a, | 2547 static RangeBoundary CanonicalizeBoundary(const RangeBoundary& a, |
| 2540 const RangeBoundary& overflow) { | 2548 const RangeBoundary& overflow) { |
| 2541 if (a.IsConstant() || a.IsNegativeInfinity() || a.IsPositiveInfinity()) { | 2549 if (a.IsConstant() || a.IsInfinity()) { |
| 2542 return a; | 2550 return a; |
| 2543 } | 2551 } |
| 2544 | 2552 |
| 2545 intptr_t offset = a.offset(); | 2553 intptr_t offset = a.offset(); |
| 2546 Definition* symbol = a.symbol(); | 2554 Definition* symbol = a.symbol(); |
| 2547 | 2555 |
| 2548 bool changed; | 2556 bool changed; |
| 2549 do { | 2557 do { |
| 2550 changed = false; | 2558 changed = false; |
| 2551 if (symbol->IsConstraint()) { | 2559 if (symbol->IsConstraint()) { |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2627 | 2635 |
| 2628 return true; | 2636 return true; |
| 2629 } | 2637 } |
| 2630 | 2638 |
| 2631 | 2639 |
| 2632 RangeBoundary RangeBoundary::Min(RangeBoundary a, RangeBoundary b) { | 2640 RangeBoundary RangeBoundary::Min(RangeBoundary a, RangeBoundary b) { |
| 2633 if (DependOnSameSymbol(a, b)) { | 2641 if (DependOnSameSymbol(a, b)) { |
| 2634 return (a.offset() <= b.offset()) ? a : b; | 2642 return (a.offset() <= b.offset()) ? a : b; |
| 2635 } | 2643 } |
| 2636 | 2644 |
| 2637 const intptr_t min_a = a.LowerBound().Clamp().value(); | 2645 const intptr_t min_a = a.LowerBound().Clamp().Value(); |
| 2638 const intptr_t min_b = b.LowerBound().Clamp().value(); | 2646 const intptr_t min_b = b.LowerBound().Clamp().Value(); |
| 2639 | 2647 |
| 2640 return RangeBoundary::FromConstant(Utils::Minimum(min_a, min_b)); | 2648 return RangeBoundary::FromConstant(Utils::Minimum(min_a, min_b)); |
| 2641 } | 2649 } |
| 2642 | 2650 |
| 2643 | 2651 |
| 2644 RangeBoundary RangeBoundary::Max(RangeBoundary a, RangeBoundary b) { | 2652 RangeBoundary RangeBoundary::Max(RangeBoundary a, RangeBoundary b) { |
| 2645 if (DependOnSameSymbol(a, b)) { | 2653 if (DependOnSameSymbol(a, b)) { |
| 2646 return (a.offset() >= b.offset()) ? a : b; | 2654 return (a.offset() >= b.offset()) ? a : b; |
| 2647 } | 2655 } |
| 2648 | 2656 |
| 2649 const intptr_t max_a = a.UpperBound().Clamp().value(); | 2657 const intptr_t max_a = a.UpperBound().Clamp().Value(); |
| 2650 const intptr_t max_b = b.UpperBound().Clamp().value(); | 2658 const intptr_t max_b = b.UpperBound().Clamp().Value(); |
| 2651 | 2659 |
| 2652 return RangeBoundary::FromConstant(Utils::Maximum(max_a, max_b)); | 2660 return RangeBoundary::FromConstant(Utils::Maximum(max_a, max_b)); |
| 2653 } | 2661 } |
| 2654 | 2662 |
| 2655 | 2663 |
| 2664 intptr_t RangeBoundary::Value() const { | |
|
Florian Schneider
2014/06/11 10:41:00
maybe add ASSERT(kind_ == kConstant);
Cutch
2014/06/13 04:24:25
Done.
| |
| 2665 if (IsNegativeInfinity()) { | |
| 2666 return kMin; | |
|
Florian Schneider
2014/06/11 10:41:00
I'm not sure this is ideal to return kMin/kMax. A
Vyacheslav Egorov (Google)
2014/06/11 17:36:37
I second Florian here. Let's prohibit asking a val
Cutch
2014/06/13 04:24:26
Done.
| |
| 2667 } | |
| 2668 if (IsPositiveInfinity()) { | |
| 2669 return kMax; | |
|
Florian Schneider
2014/06/11 10:41:00
UNREACHABLE()?
Cutch
2014/06/13 04:24:25
Done.
| |
| 2670 } | |
| 2671 ASSERT(IsConstant()); | |
| 2672 return value_; | |
| 2673 } | |
| 2674 | |
| 2675 | |
| 2656 void Definition::InferRange() { | 2676 void Definition::InferRange() { |
| 2657 ASSERT(Type()->ToCid() == kSmiCid); // Has meaning only for smis. | 2677 ASSERT(Type()->ToCid() == kSmiCid); // Has meaning only for smis. |
| 2658 if (range_ == NULL) { | 2678 if (range_ == NULL) { |
| 2659 range_ = Range::Unknown(); | 2679 range_ = Range::Unknown(); |
| 2660 } | 2680 } |
| 2661 } | 2681 } |
| 2662 | 2682 |
| 2663 | 2683 |
| 2664 void ConstantInstr::InferRange() { | 2684 void ConstantInstr::InferRange() { |
| 2665 ASSERT(value_.IsSmi()); | 2685 ASSERT(value_.IsSmi()); |
| 2666 if (range_ == NULL) { | 2686 if (range_ == NULL) { |
| 2667 intptr_t value = Smi::Cast(value_).Value(); | 2687 intptr_t value = Smi::Cast(value_).Value(); |
| 2668 range_ = new Range(RangeBoundary::FromConstant(value), | 2688 range_ = new Range(RangeBoundary::FromConstant(value), |
| 2669 RangeBoundary::FromConstant(value)); | 2689 RangeBoundary::FromConstant(value)); |
| 2670 } | 2690 } |
| 2671 } | 2691 } |
| 2672 | 2692 |
| 2673 | 2693 |
| 2674 void ConstraintInstr::InferRange() { | 2694 void ConstraintInstr::InferRange() { |
| 2675 Range* value_range = value()->definition()->range(); | 2695 Range* value_range = value()->definition()->range(); |
| 2676 | 2696 |
| 2677 RangeBoundary min; | 2697 RangeBoundary min; |
| 2678 RangeBoundary max; | 2698 RangeBoundary max; |
| 2679 | 2699 |
| 2680 if (IsMinSmi(value_range) && !IsMinSmi(constraint())) { | 2700 if (Range::IsSmiMinimumOrUnderflow(value_range) && |
|
Vyacheslav Egorov (Google)
2014/06/11 17:36:37
for simplicity I suggest we make this code differe
Vyacheslav Egorov (Google)
2014/06/11 20:06:37
I wonder if this code will become better if we int
Cutch
2014/06/13 04:24:25
I've extended Min and Max to handle infinities but
Cutch
2014/06/13 04:24:25
Done.
| |
| 2701 !Range::IsSmiMinimumOrUnderflow(constraint())) { | |
| 2681 min = constraint()->min(); | 2702 min = constraint()->min(); |
| 2682 } else if (IsMinSmi(constraint()) && !IsMinSmi(value_range)) { | 2703 } else if (Range::IsSmiMinimumOrUnderflow(constraint()) && |
| 2704 !Range::IsSmiMinimumOrUnderflow(value_range)) { | |
| 2683 min = value_range->min(); | 2705 min = value_range->min(); |
| 2684 } else if ((value_range != NULL) && | 2706 } else if ((value_range != NULL) && |
| 2685 IsEqual(constraint()->min(), value_range->min())) { | 2707 constraint()->min().Equals(value_range->min())) { |
| 2686 min = constraint()->min(); | 2708 min = constraint()->min(); |
| 2687 } else { | 2709 } else { |
| 2688 if (value_range != NULL) { | 2710 if (value_range != NULL) { |
| 2689 RangeBoundary canonical_a = | 2711 RangeBoundary canonical_a = |
| 2690 CanonicalizeBoundary(constraint()->min(), | 2712 CanonicalizeBoundary(constraint()->min(), |
| 2691 RangeBoundary::NegativeInfinity()); | 2713 RangeBoundary::NegativeInfinity()); |
| 2692 RangeBoundary canonical_b = | 2714 RangeBoundary canonical_b = |
| 2693 CanonicalizeBoundary(value_range->min(), | 2715 CanonicalizeBoundary(value_range->min(), |
| 2694 RangeBoundary::NegativeInfinity()); | 2716 RangeBoundary::NegativeInfinity()); |
| 2695 | 2717 |
| 2696 do { | 2718 do { |
| 2697 if (DependOnSameSymbol(canonical_a, canonical_b)) { | 2719 if (DependOnSameSymbol(canonical_a, canonical_b)) { |
| 2698 min = (canonical_a.offset() <= canonical_b.offset()) ? canonical_b | 2720 min = (canonical_a.offset() <= canonical_b.offset()) ? canonical_b |
| 2699 : canonical_a; | 2721 : canonical_a; |
| 2700 } | 2722 } |
| 2701 } while (CanonicalizeMinBoundary(&canonical_a) || | 2723 } while (CanonicalizeMinBoundary(&canonical_a) || |
| 2702 CanonicalizeMinBoundary(&canonical_b)); | 2724 CanonicalizeMinBoundary(&canonical_b)); |
| 2703 } | 2725 } |
| 2704 | 2726 |
| 2705 if (min.IsUnknown()) { | 2727 if (min.IsUnknown()) { |
| 2706 min = RangeBoundary::Max(Range::ConstantMin(value_range), | 2728 min = RangeBoundary::Max(Range::ConstantMin(value_range), |
| 2707 Range::ConstantMin(constraint())); | 2729 Range::ConstantMin(constraint())); |
| 2708 } | 2730 } |
| 2709 } | 2731 } |
| 2710 | 2732 |
| 2711 if (IsMaxSmi(value_range) && !IsMaxSmi(constraint())) { | 2733 if (Range::IsSmiMaximumOrOverflow(value_range) && |
| 2734 !Range::IsSmiMaximumOrOverflow(constraint())) { | |
| 2712 max = constraint()->max(); | 2735 max = constraint()->max(); |
| 2713 } else if (IsMaxSmi(constraint()) && !IsMaxSmi(value_range)) { | 2736 } else if (Range::IsSmiMaximumOrOverflow(constraint()) && |
| 2737 !Range::IsSmiMaximumOrOverflow(value_range)) { | |
| 2714 max = value_range->max(); | 2738 max = value_range->max(); |
| 2715 } else if ((value_range != NULL) && | 2739 } else if ((value_range != NULL) && |
| 2716 IsEqual(constraint()->max(), value_range->max())) { | 2740 constraint()->max().Equals(value_range->max())) { |
| 2717 max = constraint()->max(); | 2741 max = constraint()->max(); |
| 2718 } else { | 2742 } else { |
| 2719 if (value_range != NULL) { | 2743 if (value_range != NULL) { |
| 2720 RangeBoundary canonical_b = | 2744 RangeBoundary canonical_b = |
| 2721 CanonicalizeBoundary(value_range->max(), | 2745 CanonicalizeBoundary(value_range->max(), |
| 2722 RangeBoundary::PositiveInfinity()); | 2746 RangeBoundary::PositiveInfinity()); |
| 2723 RangeBoundary canonical_a = | 2747 RangeBoundary canonical_a = |
| 2724 CanonicalizeBoundary(constraint()->max(), | 2748 CanonicalizeBoundary(constraint()->max(), |
| 2725 RangeBoundary::PositiveInfinity()); | 2749 RangeBoundary::PositiveInfinity()); |
| 2726 | 2750 |
| (...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2963 ASSERT(InputCount() > 1); | 2987 ASSERT(InputCount() > 1); |
| 2964 Definition* first = InputAt(0)->definition(); | 2988 Definition* first = InputAt(0)->definition(); |
| 2965 for (intptr_t i = 1; i < InputCount(); ++i) { | 2989 for (intptr_t i = 1; i < InputCount(); ++i) { |
| 2966 Definition* def = InputAt(i)->definition(); | 2990 Definition* def = InputAt(i)->definition(); |
| 2967 if (def != first) return false; | 2991 if (def != first) return false; |
| 2968 } | 2992 } |
| 2969 return true; | 2993 return true; |
| 2970 } | 2994 } |
| 2971 | 2995 |
| 2972 | 2996 |
| 2973 static bool SymbolicSub(const RangeBoundary& a, | 2997 static bool SymbolicSub(const RangeBoundary& a, |
|
Vyacheslav Egorov (Google)
2014/06/11 20:06:36
This funciton should be moved to RangeBoundary?
Cutch
2014/06/13 04:24:25
Done.
| |
| 2974 const RangeBoundary& b, | 2998 const RangeBoundary& b, |
| 2975 RangeBoundary* result) { | 2999 RangeBoundary* result) { |
| 2976 if (a.IsSymbol() && b.IsConstant() && !b.Overflowed()) { | 3000 if (a.IsSymbol() && b.IsConstant() && !b.Overflowed()) { |
| 2977 const intptr_t offset = a.offset() - b.value(); | 3001 const intptr_t offset = a.offset() - b.Value(); |
| 2978 if (!Smi::IsValid(offset)) return false; | 3002 if (!Smi::IsValid(offset)) return false; |
| 2979 | 3003 |
| 2980 *result = RangeBoundary::FromDefinition(a.symbol(), offset); | 3004 *result = RangeBoundary::FromDefinition(a.symbol(), offset); |
| 2981 return true; | 3005 return true; |
| 2982 } | 3006 } |
| 2983 return false; | 3007 return false; |
| 2984 } | 3008 } |
| 2985 | 3009 |
| 2986 | 3010 |
| 2987 static bool SymbolicAdd(const RangeBoundary& a, | 3011 static bool SymbolicAdd(const RangeBoundary& a, |
| 2988 const RangeBoundary& b, | 3012 const RangeBoundary& b, |
| 2989 RangeBoundary* result) { | 3013 RangeBoundary* result) { |
| 2990 if (a.IsSymbol() && b.IsConstant() && !b.Overflowed()) { | 3014 if (a.IsSymbol() && b.IsConstant() && !b.Overflowed()) { |
| 2991 const intptr_t offset = a.offset() + b.value(); | 3015 const intptr_t offset = a.offset() + b.Value(); |
| 2992 if (!Smi::IsValid(offset)) return false; | 3016 if (!Smi::IsValid(offset)) return false; |
| 2993 | 3017 |
| 2994 *result = RangeBoundary::FromDefinition(a.symbol(), offset); | 3018 *result = RangeBoundary::FromDefinition(a.symbol(), offset); |
| 2995 return true; | 3019 return true; |
| 2996 } else if (b.IsSymbol() && a.IsConstant() && !a.Overflowed()) { | 3020 } else if (b.IsSymbol() && a.IsConstant() && !a.Overflowed()) { |
| 2997 const intptr_t offset = b.offset() + a.value(); | 3021 const intptr_t offset = b.offset() + a.Value(); |
| 2998 if (!Smi::IsValid(offset)) return false; | 3022 if (!Smi::IsValid(offset)) return false; |
| 2999 | 3023 |
| 3000 *result = RangeBoundary::FromDefinition(b.symbol(), offset); | 3024 *result = RangeBoundary::FromDefinition(b.symbol(), offset); |
| 3001 return true; | 3025 return true; |
| 3002 } | 3026 } |
| 3003 return false; | 3027 return false; |
| 3004 } | 3028 } |
| 3005 | 3029 |
| 3006 | 3030 |
| 3007 static bool IsArrayLength(Definition* defn) { | 3031 static bool IsArrayLength(Definition* defn) { |
| 3008 LoadFieldInstr* load = defn->AsLoadField(); | 3032 LoadFieldInstr* load = defn->AsLoadField(); |
| 3009 return (load != NULL) && load->IsImmutableLengthLoad(); | 3033 return (load != NULL) && load->IsImmutableLengthLoad(); |
| 3010 } | 3034 } |
| 3011 | 3035 |
| 3012 | 3036 |
| 3013 static int64_t ConstantAbsMax(const Range* range) { | |
| 3014 if (range == NULL) return Smi::kMaxValue; | |
| 3015 const int64_t abs_min = Utils::Abs(Range::ConstantMin(range).value()); | |
| 3016 const int64_t abs_max = Utils::Abs(Range::ConstantMax(range).value()); | |
| 3017 return abs_min > abs_max ? abs_min : abs_max; | |
| 3018 } | |
| 3019 | |
| 3020 | |
| 3021 static bool OnlyPositiveOrZero(const Range* a, const Range* b) { | |
| 3022 if ((a == NULL) || (b == NULL)) return false; | |
| 3023 if (Range::ConstantMin(a).value() < 0) return false; | |
| 3024 if (Range::ConstantMin(b).value() < 0) return false; | |
| 3025 return true; | |
| 3026 } | |
| 3027 | |
| 3028 | |
| 3029 static bool OnlyNegativeOrZero(const Range* a, const Range* b) { | |
| 3030 if ((a == NULL) || (b == NULL)) return false; | |
| 3031 if (Range::ConstantMax(a).value() > 0) return false; | |
| 3032 if (Range::ConstantMax(b).value() > 0) return false; | |
| 3033 return true; | |
| 3034 } | |
| 3035 | |
| 3036 | |
| 3037 void BinarySmiOpInstr::InferRange() { | 3037 void BinarySmiOpInstr::InferRange() { |
| 3038 // TODO(vegorov): canonicalize BinarySmiOp to always have constant on the | 3038 // TODO(vegorov): canonicalize BinarySmiOp to always have constant on the |
| 3039 // right and a non-constant on the left. | 3039 // right and a non-constant on the left. |
| 3040 Definition* left_defn = left()->definition(); | 3040 Definition* left_defn = left()->definition(); |
| 3041 | 3041 |
| 3042 Range* left_range = left_defn->range(); | 3042 Range* left_range = left_defn->range(); |
| 3043 Range* right_range = right()->definition()->range(); | 3043 Range* right_range = right()->definition()->range(); |
| 3044 | 3044 |
| 3045 if ((left_range == NULL) || (right_range == NULL)) { | 3045 if ((left_range == NULL) || (right_range == NULL)) { |
| 3046 range_ = new Range(RangeBoundary::MinSmi(), RangeBoundary::MaxSmi()); | 3046 range_ = new Range(RangeBoundary::MinSmi(), RangeBoundary::MaxSmi()); |
| 3047 return; | 3047 return; |
| 3048 } | 3048 } |
| 3049 | 3049 |
| 3050 RangeBoundary left_min = | 3050 RangeBoundary left_min = |
| 3051 IsArrayLength(left_defn) ? | 3051 IsArrayLength(left_defn) ? |
| 3052 RangeBoundary::FromDefinition(left_defn) : left_range->min(); | 3052 RangeBoundary::FromDefinition(left_defn) : left_range->min(); |
| 3053 | 3053 |
| 3054 RangeBoundary left_max = | 3054 RangeBoundary left_max = |
| 3055 IsArrayLength(left_defn) ? | 3055 IsArrayLength(left_defn) ? |
| 3056 RangeBoundary::FromDefinition(left_defn) : left_range->max(); | 3056 RangeBoundary::FromDefinition(left_defn) : left_range->max(); |
| 3057 | 3057 |
| 3058 RangeBoundary min; | 3058 // If we had no range information before, we do not update the overflow state. |
| 3059 RangeBoundary max; | 3059 bool should_update_overflow = range_ != NULL; |
|
Vyacheslav Egorov (Google)
2014/06/11 20:06:37
I don't understand the reasoning behind this lack
Cutch
2014/06/13 04:24:26
I've updated the predicate to include the + and -
| |
| 3060 switch (op_kind()) { | |
| 3061 case Token::kADD: | |
| 3062 if (!SymbolicAdd(left_min, right_range->min(), &min)) { | |
| 3063 min = | |
| 3064 RangeBoundary::Add(Range::ConstantMin(left_range), | |
| 3065 Range::ConstantMin(right_range), | |
| 3066 RangeBoundary::NegativeInfinity()); | |
| 3067 } | |
| 3068 | 3060 |
| 3069 if (!SymbolicAdd(left_max, right_range->max(), &max)) { | 3061 range_ = Range::BinaryOp(op_kind(), |
| 3070 max = | 3062 left_min, |
| 3071 RangeBoundary::Add(Range::ConstantMax(right_range), | 3063 left_max, |
| 3072 Range::ConstantMax(left_range), | 3064 left_range, |
| 3073 RangeBoundary::PositiveInfinity()); | 3065 right_range, |
| 3074 } | 3066 range_); |
| 3075 break; | 3067 if (range_ == NULL) { |
| 3076 | 3068 // No range information. |
| 3077 case Token::kSUB: | 3069 return; |
| 3078 if (!SymbolicSub(left_min, right_range->max(), &min)) { | |
| 3079 min = | |
| 3080 RangeBoundary::Sub(Range::ConstantMin(left_range), | |
| 3081 Range::ConstantMax(right_range), | |
| 3082 RangeBoundary::NegativeInfinity()); | |
| 3083 } | |
| 3084 | |
| 3085 if (!SymbolicSub(left_max, right_range->min(), &max)) { | |
| 3086 max = | |
| 3087 RangeBoundary::Sub(Range::ConstantMax(left_range), | |
| 3088 Range::ConstantMin(right_range), | |
| 3089 RangeBoundary::PositiveInfinity()); | |
| 3090 } | |
| 3091 break; | |
| 3092 | |
| 3093 case Token::kMUL: { | |
| 3094 const int64_t left_max = ConstantAbsMax(left_range); | |
| 3095 const int64_t right_max = ConstantAbsMax(right_range); | |
| 3096 if ((left_max < 0x7FFFFFFF) && (right_max < 0x7FFFFFFF)) { | |
| 3097 // Product of left and right max values stays in 64 bit range. | |
| 3098 const int64_t result_max = left_max * right_max; | |
| 3099 if (Smi::IsValid64(result_max) && Smi::IsValid64(-result_max)) { | |
| 3100 const intptr_t r_min = | |
| 3101 OnlyPositiveOrZero(left_range, right_range) ? 0 : -result_max; | |
| 3102 min = RangeBoundary::FromConstant(r_min); | |
| 3103 const intptr_t r_max = | |
| 3104 OnlyNegativeOrZero(left_range, right_range) ? 0 : result_max; | |
| 3105 max = RangeBoundary::FromConstant(r_max); | |
| 3106 break; | |
| 3107 } | |
| 3108 } | |
| 3109 if (range_ == NULL) { | |
| 3110 range_ = Range::Unknown(); | |
| 3111 } | |
| 3112 return; | |
| 3113 } | |
| 3114 case Token::kBIT_AND: | |
| 3115 if (Range::ConstantMin(right_range).value() >= 0) { | |
| 3116 min = RangeBoundary::FromConstant(0); | |
| 3117 max = Range::ConstantMax(right_range); | |
| 3118 break; | |
| 3119 } | |
| 3120 if (Range::ConstantMin(left_range).value() >= 0) { | |
| 3121 min = RangeBoundary::FromConstant(0); | |
| 3122 max = Range::ConstantMax(left_range); | |
| 3123 break; | |
| 3124 } | |
| 3125 | |
| 3126 if (range_ == NULL) { | |
| 3127 range_ = Range::Unknown(); | |
| 3128 } | |
| 3129 return; | |
| 3130 | |
| 3131 default: | |
| 3132 if (range_ == NULL) { | |
| 3133 range_ = Range::Unknown(); | |
| 3134 } | |
| 3135 return; | |
| 3136 } | 3070 } |
| 3137 | 3071 |
| 3138 ASSERT(!min.IsUnknown() && !max.IsUnknown()); | 3072 if (!should_update_overflow) { |
| 3139 set_overflow(min.LowerBound().Overflowed() || max.UpperBound().Overflowed()); | 3073 return; |
| 3074 } | |
| 3140 | 3075 |
| 3141 if (min.IsConstant()) min.Clamp(); | 3076 ASSERT(!range_->min().IsUnknown() && !range_->max().IsUnknown()); |
| 3142 if (max.IsConstant()) max.Clamp(); | 3077 const bool overflowed = range_->min().LowerBound().Overflowed() || |
| 3143 | 3078 range_->max().UpperBound().Overflowed(); |
| 3144 range_ = new Range(min, max); | 3079 set_overflow(overflowed); |
| 3145 } | 3080 } |
| 3146 | 3081 |
| 3147 | 3082 |
| 3148 bool Range::IsPositive() const { | 3083 bool Range::IsPositive() const { |
| 3149 if (min().IsNegativeInfinity()) { | 3084 if (min().IsNegativeInfinity()) { |
| 3150 return false; | 3085 return false; |
| 3151 } | 3086 } |
| 3152 if (min().LowerBound().value() < 0) { | 3087 if (min().LowerBound().Value() < 0) { |
| 3153 return false; | 3088 return false; |
| 3154 } | 3089 } |
| 3155 if (max().IsPositiveInfinity()) { | 3090 if (max().IsPositiveInfinity()) { |
| 3156 return true; | 3091 return true; |
| 3157 } | 3092 } |
| 3158 return max().UpperBound().value() >= 0; | 3093 return max().UpperBound().Value() >= 0; |
| 3159 } | 3094 } |
| 3160 | 3095 |
| 3161 | 3096 |
| 3162 bool Range::IsNegative() const { | 3097 bool Range::IsNegative() const { |
| 3163 if (max().IsPositiveInfinity()) { | 3098 if (max().IsPositiveInfinity()) { |
| 3164 return false; | 3099 return false; |
| 3165 } | 3100 } |
| 3166 if (max().UpperBound().value() >= 0) { | 3101 if (max().UpperBound().Value() >= 0) { |
| 3167 return false; | 3102 return false; |
| 3168 } | 3103 } |
| 3169 if (min().IsNegativeInfinity()) { | 3104 if (min().IsNegativeInfinity()) { |
| 3170 return true; | 3105 return true; |
| 3171 } | 3106 } |
| 3172 return min().LowerBound().value() < 0; | 3107 return min().LowerBound().Value() < 0; |
| 3173 } | 3108 } |
| 3174 | 3109 |
| 3175 | 3110 |
| 3176 bool Range::OnlyLessThanOrEqualTo(intptr_t val) const { | 3111 bool Range::OnlyLessThanOrEqualTo(intptr_t val) const { |
| 3177 if (max().IsPositiveInfinity()) { | 3112 if (max().IsPositiveInfinity()) { |
| 3178 // Cannot be true. | 3113 // Cannot be true. |
| 3179 return false; | 3114 return false; |
| 3180 } | 3115 } |
| 3181 if (max().UpperBound().value() > val) { | 3116 if (max().UpperBound().Value() > val) { |
| 3182 // Not true. | 3117 // Not true. |
| 3183 return false; | 3118 return false; |
| 3184 } | 3119 } |
| 3185 if (!min().IsNegativeInfinity()) { | 3120 if (!min().IsNegativeInfinity()) { |
| 3186 if (min().LowerBound().value() > val) { | 3121 if (min().LowerBound().Value() > val) { |
| 3187 // Lower bound is > value. | 3122 // Lower bound is > value. |
| 3188 return false; | 3123 return false; |
| 3189 } | 3124 } |
| 3190 } | 3125 } |
| 3191 return true; | 3126 return true; |
| 3192 } | 3127 } |
| 3193 | 3128 |
| 3194 | 3129 |
| 3195 // Inclusive. | 3130 // Inclusive. |
| 3196 bool Range::IsWithin(intptr_t min_int, intptr_t max_int) const { | 3131 bool Range::IsWithin(intptr_t min_int, intptr_t max_int) const { |
| 3197 RangeBoundary lower_min = min().LowerBound(); | 3132 RangeBoundary lower_min = min().LowerBound(); |
| 3198 if (lower_min.IsNegativeInfinity() || (lower_min.value() < min_int)) { | 3133 if (lower_min.IsNegativeInfinity() || (lower_min.Value() < min_int)) { |
| 3199 return false; | 3134 return false; |
| 3200 } | 3135 } |
| 3201 RangeBoundary upper_max = max().UpperBound(); | 3136 RangeBoundary upper_max = max().UpperBound(); |
| 3202 if (upper_max.IsPositiveInfinity() || (upper_max.value() > max_int)) { | 3137 if (upper_max.IsPositiveInfinity() || (upper_max.Value() > max_int)) { |
| 3203 return false; | 3138 return false; |
| 3204 } | 3139 } |
| 3205 return true; | 3140 return true; |
| 3206 } | 3141 } |
| 3207 | 3142 |
| 3208 | 3143 |
| 3209 bool Range::Overlaps(intptr_t min_int, intptr_t max_int) const { | 3144 bool Range::Overlaps(intptr_t min_int, intptr_t max_int) const { |
| 3210 const intptr_t this_min = min().IsNegativeInfinity() ? | 3145 const intptr_t this_min = min().LowerBound().Value(); |
| 3211 kIntptrMin : min().LowerBound().value(); | 3146 const intptr_t this_max = max().UpperBound().Value(); |
| 3212 const intptr_t this_max = max().IsPositiveInfinity() ? | |
| 3213 kIntptrMax : max().UpperBound().value(); | |
| 3214 if ((this_min <= min_int) && (min_int <= this_max)) return true; | 3147 if ((this_min <= min_int) && (min_int <= this_max)) return true; |
| 3215 if ((this_min <= max_int) && (max_int <= this_max)) return true; | 3148 if ((this_min <= max_int) && (max_int <= this_max)) return true; |
| 3216 if ((min_int < this_min) && (max_int > this_max)) return true; | 3149 if ((min_int < this_min) && (max_int > this_max)) return true; |
| 3217 return false; | 3150 return false; |
| 3218 } | 3151 } |
| 3219 | 3152 |
| 3220 | 3153 |
| 3221 bool Range::IsUnsatisfiable() const { | 3154 bool Range::IsUnsatisfiable() const { |
| 3222 // Infinity case: [+inf, ...] || [..., -inf] | 3155 // Infinity case: [+inf, ...] || [..., -inf] |
| 3223 if (min().IsPositiveInfinity() || max().IsNegativeInfinity()) { | 3156 if (min().IsPositiveInfinity() || max().IsNegativeInfinity()) { |
| 3224 return true; | 3157 return true; |
| 3225 } | 3158 } |
| 3226 // Constant case: For example [0, -1]. | 3159 // Constant case: For example [0, -1]. |
| 3227 if (Range::ConstantMin(this).value() > Range::ConstantMax(this).value()) { | 3160 if (Range::ConstantMin(this).Value() > Range::ConstantMax(this).Value()) { |
| 3228 return true; | 3161 return true; |
| 3229 } | 3162 } |
| 3230 // Symbol case: For example [v+1, v]. | 3163 // Symbol case: For example [v+1, v]. |
| 3231 if (DependOnSameSymbol(min(), max()) && min().offset() > max().offset()) { | 3164 if (DependOnSameSymbol(min(), max()) && min().offset() > max().offset()) { |
| 3232 return true; | 3165 return true; |
| 3233 } | 3166 } |
| 3234 return false; | 3167 return false; |
| 3235 } | 3168 } |
| 3236 | 3169 |
| 3237 | 3170 |
| 3171 // Returns true if range is at or below the minimum smi value. | |
| 3172 bool Range::IsSmiMinimumOrUnderflow(const Range* range) { | |
| 3173 return (range == NULL) || | |
| 3174 ((range->min().IsConstant() || range->min().IsInfinity()) && | |
|
Florian Schneider
2014/06/11 10:41:00
IsNegativeInfinity()?
| |
| 3175 (range->min().Value() <= Smi::kMinValue)); | |
|
Florian Schneider
2014/06/11 10:41:00
Same comment as below.
| |
| 3176 } | |
| 3177 | |
| 3178 // Returns true if range is at or above the maximum smi value. | |
| 3179 bool Range::IsSmiMaximumOrOverflow(const Range* range) { | |
| 3180 return (range == NULL) || | |
| 3181 ((range->max().IsConstant() || range->max().IsInfinity()) && | |
|
Florian Schneider
2014/06/11 10:41:00
IsPositiveInfinity?
| |
| 3182 (range->max().Value() >= Smi::kMaxValue)); | |
|
Florian Schneider
2014/06/11 10:41:00
This is a piece of code that gets hard to read bec
| |
| 3183 } | |
| 3184 | |
| 3185 | |
| 3186 // Both the a and b ranges are >= 0. | |
| 3187 bool Range::OnlyPositiveOrZero(const Range& a, const Range& b) { | |
|
Vyacheslav Egorov (Google)
2014/06/11 20:06:36
It feels like we have some kind of duplication her
Cutch
2014/06/13 04:24:25
Done.
| |
| 3188 if (Range::ConstantMin(&a).Value() < 0) { | |
| 3189 return false; | |
| 3190 } | |
| 3191 if (Range::ConstantMin(&b).Value() < 0) { | |
| 3192 return false; | |
| 3193 } | |
| 3194 return true; | |
| 3195 } | |
| 3196 | |
| 3197 | |
| 3198 // Both the a and b ranges are <= 0. | |
| 3199 bool Range::OnlyNegativeOrZero(const Range& a, const Range& b) { | |
| 3200 if (Range::ConstantMax(&a).Value() > 0) { | |
| 3201 return false; | |
| 3202 } | |
| 3203 if (Range::ConstantMax(&b).Value() > 0) { | |
| 3204 return false; | |
| 3205 } | |
| 3206 return true; | |
| 3207 } | |
| 3208 | |
| 3209 | |
| 3210 // Return the maximum absolute value included in range. | |
| 3211 int64_t Range::ConstantAbsMax(const Range* range) { | |
| 3212 if (range == NULL) { | |
| 3213 return RangeBoundary::kMax; | |
| 3214 } | |
| 3215 const int64_t abs_min = Utils::Abs(Range::ConstantMin(range).Value()); | |
| 3216 const int64_t abs_max = Utils::Abs(Range::ConstantMax(range).Value()); | |
| 3217 return Utils::Maximum(abs_min, abs_max); | |
| 3218 } | |
| 3219 | |
| 3220 | |
| 3221 Range* Range::BinaryOp(const Token::Kind op, | |
| 3222 const RangeBoundary& left_min, | |
| 3223 const RangeBoundary& left_max, | |
| 3224 const Range* left_range, | |
| 3225 const Range* right_range, | |
| 3226 const Range* original_range) { | |
| 3227 ASSERT(left_range != NULL); | |
| 3228 ASSERT(right_range != NULL); | |
| 3229 RangeBoundary min; | |
| 3230 RangeBoundary max; | |
| 3231 switch (op) { | |
| 3232 case Token::kADD: | |
| 3233 if (!SymbolicAdd(left_min, right_range->min(), &min)) { | |
| 3234 min = RangeBoundary::Add(Range::ConstantMin(left_range), | |
| 3235 Range::ConstantMin(right_range), | |
| 3236 RangeBoundary::NegativeInfinity()); | |
| 3237 } | |
| 3238 if (!SymbolicAdd(left_max, right_range->max(), &max)) { | |
| 3239 max = RangeBoundary::Add(Range::ConstantMax(right_range), | |
| 3240 Range::ConstantMax(left_range), | |
| 3241 RangeBoundary::PositiveInfinity()); | |
| 3242 } | |
| 3243 break; | |
| 3244 case Token::kSUB: | |
| 3245 if (!SymbolicSub(left_min, right_range->max(), &min)) { | |
| 3246 min = RangeBoundary::Sub(Range::ConstantMin(left_range), | |
| 3247 Range::ConstantMax(right_range), | |
| 3248 RangeBoundary::NegativeInfinity()); | |
| 3249 } | |
| 3250 if (!SymbolicSub(left_max, right_range->min(), &max)) { | |
| 3251 max = RangeBoundary::Sub(Range::ConstantMax(left_range), | |
| 3252 Range::ConstantMin(right_range), | |
| 3253 RangeBoundary::PositiveInfinity()); | |
| 3254 } | |
| 3255 break; | |
| 3256 case Token::kMUL: { | |
| 3257 const int64_t left_max = ConstantAbsMax(left_range); | |
| 3258 const int64_t right_max = ConstantAbsMax(right_range); | |
| 3259 if ((left_max < 0x7FFFFFFF) && (right_max < 0x7FFFFFFF)) { | |
| 3260 // Product of left and right max values stays in 64 bit range. | |
| 3261 const int64_t result_max = left_max * right_max; | |
| 3262 if (Smi::IsValid64(result_max) && Smi::IsValid64(-result_max)) { | |
| 3263 const intptr_t r_min = | |
| 3264 OnlyPositiveOrZero(*left_range, *right_range) ? 0 : -result_max; | |
| 3265 min = RangeBoundary::FromConstant(r_min); | |
| 3266 const intptr_t r_max = | |
| 3267 OnlyNegativeOrZero(*left_range, *right_range) ? 0 : result_max; | |
| 3268 max = RangeBoundary::FromConstant(r_max); | |
| 3269 break; | |
| 3270 } | |
| 3271 } | |
| 3272 if (original_range == NULL) { | |
| 3273 return Range::Unknown(); | |
| 3274 } | |
| 3275 break; | |
| 3276 } | |
| 3277 case Token::kBIT_AND: | |
| 3278 if (Range::ConstantMin(right_range).Value() >= 0) { | |
| 3279 min = RangeBoundary::FromConstant(0); | |
| 3280 max = Range::ConstantMax(right_range); | |
| 3281 break; | |
| 3282 } | |
| 3283 if (Range::ConstantMin(left_range).Value() >= 0) { | |
| 3284 min = RangeBoundary::FromConstant(0); | |
| 3285 max = Range::ConstantMax(left_range); | |
| 3286 break; | |
| 3287 } | |
| 3288 if (original_range == NULL) { | |
| 3289 return Range::Unknown(); | |
| 3290 } | |
| 3291 break; | |
| 3292 default: | |
| 3293 if (original_range == NULL) { | |
| 3294 return Range::Unknown(); | |
| 3295 } | |
| 3296 return const_cast<Range*>(original_range); | |
| 3297 } | |
| 3298 | |
| 3299 ASSERT(!min.IsUnknown() && !max.IsUnknown()); | |
| 3300 | |
| 3301 return new Range(min, max); | |
| 3302 } | |
| 3303 | |
| 3304 | |
| 3238 bool CheckArrayBoundInstr::IsFixedLengthArrayType(intptr_t cid) { | 3305 bool CheckArrayBoundInstr::IsFixedLengthArrayType(intptr_t cid) { |
| 3239 return LoadFieldInstr::IsFixedLengthArrayCid(cid); | 3306 return LoadFieldInstr::IsFixedLengthArrayCid(cid); |
| 3240 } | 3307 } |
| 3241 | 3308 |
| 3242 | 3309 |
| 3243 bool CheckArrayBoundInstr::IsRedundant(RangeBoundary length) { | 3310 bool CheckArrayBoundInstr::IsRedundant(RangeBoundary length) { |
| 3244 Range* index_range = index()->definition()->range(); | 3311 Range* index_range = index()->definition()->range(); |
| 3245 | 3312 |
| 3246 // Range of the index is unknown can't decide if the check is redundant. | 3313 // Range of the index is unknown can't decide if the check is redundant. |
| 3247 if (index_range == NULL) { | 3314 if (index_range == NULL) { |
| 3248 return false; | 3315 return false; |
| 3249 } | 3316 } |
| 3250 | 3317 |
| 3251 // Range of the index is not positive. Check can't be redundant. | 3318 // Range of the index is not positive. Check can't be redundant. |
| 3252 if (Range::ConstantMin(index_range).value() < 0) { | 3319 if (Range::ConstantMin(index_range).Value() < 0) { |
| 3253 return false; | 3320 return false; |
| 3254 } | 3321 } |
| 3255 | 3322 |
| 3256 RangeBoundary max = CanonicalizeBoundary(index_range->max(), | 3323 RangeBoundary max = CanonicalizeBoundary(index_range->max(), |
| 3257 RangeBoundary::PositiveInfinity()); | 3324 RangeBoundary::PositiveInfinity()); |
| 3258 | 3325 |
| 3259 if (max.Overflowed()) { | 3326 if (max.Overflowed()) { |
| 3260 return false; | 3327 return false; |
| 3261 } | 3328 } |
| 3262 | 3329 |
| 3263 | 3330 |
| 3264 RangeBoundary max_upper = max.UpperBound(); | 3331 RangeBoundary max_upper = max.UpperBound(); |
| 3265 RangeBoundary length_lower = length.LowerBound(); | 3332 RangeBoundary length_lower = length.LowerBound(); |
| 3266 | 3333 |
| 3267 if (max_upper.Overflowed() || length_lower.Overflowed()) { | 3334 if (max_upper.Overflowed() || length_lower.Overflowed()) { |
| 3268 return false; | 3335 return false; |
| 3269 } | 3336 } |
| 3270 | 3337 |
| 3271 // Try to compare constant boundaries. | 3338 // Try to compare constant boundaries. |
| 3272 if (max_upper.value() < length_lower.value()) { | 3339 if (max_upper.Value() < length_lower.Value()) { |
| 3273 return true; | 3340 return true; |
| 3274 } | 3341 } |
| 3275 | 3342 |
| 3276 length = CanonicalizeBoundary(length, RangeBoundary::PositiveInfinity()); | 3343 length = CanonicalizeBoundary(length, RangeBoundary::PositiveInfinity()); |
| 3277 if (length.Overflowed()) { | 3344 if (length.Overflowed()) { |
| 3278 return false; | 3345 return false; |
| 3279 } | 3346 } |
| 3280 | 3347 |
| 3281 // Try symbolic comparison. | 3348 // Try symbolic comparison. |
| 3282 do { | 3349 do { |
| (...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3560 case Token::kTRUNCDIV: return 0; | 3627 case Token::kTRUNCDIV: return 0; |
| 3561 case Token::kMOD: return 1; | 3628 case Token::kMOD: return 1; |
| 3562 default: UNIMPLEMENTED(); return -1; | 3629 default: UNIMPLEMENTED(); return -1; |
| 3563 } | 3630 } |
| 3564 } | 3631 } |
| 3565 | 3632 |
| 3566 | 3633 |
| 3567 #undef __ | 3634 #undef __ |
| 3568 | 3635 |
| 3569 } // namespace dart | 3636 } // namespace dart |
| OLD | NEW |