| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 library dart2js.cps_ir.bounds_checker; | 5 library dart2js.cps_ir.bounds_checker; |
| 6 | 6 |
| 7 import 'cps_ir_nodes.dart'; | 7 import 'cps_ir_nodes.dart'; |
| 8 import 'optimizers.dart' show Pass; | 8 import 'optimizers.dart' show Pass; |
| 9 import 'octagon.dart'; | 9 import 'octagon.dart'; |
| 10 import '../constants/values.dart'; | 10 import '../constants/values.dart'; |
| 11 import 'cps_fragment.dart'; | 11 import 'cps_fragment.dart'; |
| 12 import 'type_mask_system.dart'; | 12 import 'type_mask_system.dart'; |
| 13 import '../types/types.dart'; | 13 import '../types/types.dart'; |
| 14 import '../world.dart'; | 14 import '../world.dart'; |
| 15 import '../elements/elements.dart'; | 15 import '../elements/elements.dart'; |
| 16 import 'loop_effects.dart'; | 16 import 'loop_effects.dart'; |
| 17 import 'effects.dart'; |
| 17 | 18 |
| 18 /// Eliminates bounds checks when they can be proven safe. | 19 /// Eliminates bounds checks when they can be proven safe. |
| 19 /// | 20 /// |
| 20 /// In general, this pass will try to eliminate any branch with arithmetic | 21 /// In general, this pass will try to eliminate any branch with arithmetic |
| 21 /// in the condition, i.e. `x < y`, `x <= y`, `x == y` etc. | 22 /// in the condition, i.e. `x < y`, `x <= y`, `x == y` etc. |
| 22 /// | 23 /// |
| 23 /// The analysis uses an [Octagon] abstract domain. Unlike traditional octagon | 24 /// The analysis uses an [Octagon] abstract domain. Unlike traditional octagon |
| 24 /// analyzers, we do not use a closed matrix representation, but just maintain | 25 /// analyzers, we do not use a closed matrix representation, but just maintain |
| 25 /// a bucket of constraints. Constraints can therefore be added and removed | 26 /// a bucket of constraints. Constraints can therefore be added and removed |
| 26 /// on-the-fly without significant overhead. | 27 /// on-the-fly without significant overhead. |
| (...skipping 514 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 541 if (mono == null) { | 542 if (mono == null) { |
| 542 // Value never changes. This is extremely uncommon. | 543 // Value never changes. This is extremely uncommon. |
| 543 param.replaceUsesWith(initialValue); | 544 param.replaceUsesWith(initialValue); |
| 544 } else if (mono == Monotonicity.Increasing) { | 545 } else if (mono == Monotonicity.Increasing) { |
| 545 makeGreaterThanOrEqual(getValue(param), initialVariable); | 546 makeGreaterThanOrEqual(getValue(param), initialVariable); |
| 546 } else if (mono == Monotonicity.Decreasing) { | 547 } else if (mono == Monotonicity.Decreasing) { |
| 547 makeLessThanOrEqual(getValue(param), initialVariable); | 548 makeLessThanOrEqual(getValue(param), initialVariable); |
| 548 } | 549 } |
| 549 } | 550 } |
| 550 } | 551 } |
| 551 if (loopEffects.loopChangesLength(cont)) { | 552 if (loopEffects.changesIndexableLength(cont)) { |
| 552 currentEffectNumber = effectNumberAt[cont] = makeNewEffect(); | 553 currentEffectNumber = effectNumberAt[cont] = makeNewEffect(); |
| 553 } | 554 } |
| 554 push(cont); | 555 push(cont); |
| 555 } | 556 } |
| 556 | 557 |
| 557 void analyzeLoopContinue(InvokeContinuation node) { | 558 void analyzeLoopContinue(InvokeContinuation node) { |
| 558 Continuation cont = node.continuation.definition; | 559 Continuation cont = node.continuation.definition; |
| 559 | 560 |
| 560 // During the strong loop phase, there is no need to compute monotonicity, | 561 // During the strong loop phase, there is no need to compute monotonicity, |
| 561 // and we already put bounds on the loop variables when we went into the | 562 // and we already put bounds on the loop variables when we went into the |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 606 } else if (effect != currentEffectNumber && effect != NEW_EFFECT) { | 607 } else if (effect != currentEffectNumber && effect != NEW_EFFECT) { |
| 607 effectNumberAt[cont] = NEW_EFFECT; | 608 effectNumberAt[cont] = NEW_EFFECT; |
| 608 } | 609 } |
| 609 // TODO(asgerf): Compute join for parameters to increase precision? | 610 // TODO(asgerf): Compute join for parameters to increase precision? |
| 610 } | 611 } |
| 611 } | 612 } |
| 612 | 613 |
| 613 // ---------------- PRIMITIVES -------------------- | 614 // ---------------- PRIMITIVES -------------------- |
| 614 | 615 |
| 615 @override | 616 @override |
| 617 Expression traverseLetPrim(LetPrim node) { |
| 618 visit(node.primitive); |
| 619 // visitApplyBuiltinMethod updates the effect number. |
| 620 if (node.primitive is! ApplyBuiltinMethod) { |
| 621 if (node.primitive.effectFlags & Effects.changesIndexableLength != 0) { |
| 622 currentEffectNumber = makeNewEffect(); |
| 623 } |
| 624 } |
| 625 return node.body; |
| 626 } |
| 627 |
| 628 @override |
| 616 void visitInvokeMethod(InvokeMethod node) { | 629 void visitInvokeMethod(InvokeMethod node) { |
| 617 if (node.selector.isGetter && node.selector.name == 'length') { | 630 if (node.selector.isGetter && node.selector.name == 'length') { |
| 618 // If the receiver type is not known to be indexable, the length call | 631 // If the receiver type is not known to be indexable, the length call |
| 619 // was not rewritten to GetLength. But if we can prove that the call only | 632 // was not rewritten to GetLength. But if we can prove that the call only |
| 620 // succeeds for indexables, we can trust that it returns the length. | 633 // succeeds for indexables, we can trust that it returns the length. |
| 621 TypeMask successType = | 634 TypeMask successType = |
| 622 types.receiverTypeFor(node.selector, node.dartReceiver.type); | 635 types.receiverTypeFor(node.selector, node.dartReceiver.type); |
| 623 if (types.isDefinitelyIndexable(successType)) { | 636 if (types.isDefinitelyIndexable(successType)) { |
| 624 valueOf[node] = getLength(node.dartReceiver, currentEffectNumber); | 637 valueOf[node] = getLength(node.dartReceiver, currentEffectNumber); |
| 625 } | 638 } |
| 626 } | 639 } |
| 627 // TODO(asgerf): What we really need is a "changes length" side effect flag. | |
| 628 if (world | |
| 629 .getSideEffectsOfSelector(node.selector, node.mask) | |
| 630 .changesIndex()) { | |
| 631 currentEffectNumber = makeNewEffect(); | |
| 632 } | |
| 633 } | 640 } |
| 634 | 641 |
| 635 @override | 642 @override |
| 636 void visitInvokeStatic(InvokeStatic node) { | |
| 637 if (world.getSideEffectsOfElement(node.target).changesIndex()) { | |
| 638 currentEffectNumber = makeNewEffect(); | |
| 639 } | |
| 640 } | |
| 641 | |
| 642 @override | |
| 643 void visitInvokeMethodDirectly(InvokeMethodDirectly node) { | |
| 644 FunctionElement target = node.target; | |
| 645 if (target is ConstructorBodyElement) { | |
| 646 ConstructorBodyElement body = target; | |
| 647 target = body.constructor; | |
| 648 } | |
| 649 if (world.getSideEffectsOfElement(target).changesIndex()) { | |
| 650 currentEffectNumber = makeNewEffect(); | |
| 651 } | |
| 652 } | |
| 653 | |
| 654 @override | |
| 655 void visitInvokeConstructor(InvokeConstructor node) { | |
| 656 if (world.getSideEffectsOfElement(node.target).changesIndex()) { | |
| 657 currentEffectNumber = makeNewEffect(); | |
| 658 } | |
| 659 } | |
| 660 | |
| 661 @override | |
| 662 void visitTypeCast(TypeCast node) { | |
| 663 } | |
| 664 | |
| 665 @override | |
| 666 void visitGetLazyStatic(GetLazyStatic node) { | |
| 667 // TODO(asgerf): How do we get the side effects of a lazy field initializer? | |
| 668 currentEffectNumber = makeNewEffect(); | |
| 669 } | |
| 670 | |
| 671 @override | |
| 672 void visitForeignCode(ForeignCode node) { | |
| 673 if (node.nativeBehavior.sideEffects.changesIndex()) { | |
| 674 currentEffectNumber = makeNewEffect(); | |
| 675 } | |
| 676 } | |
| 677 | |
| 678 @override | |
| 679 void visitAwait(Await node) { | |
| 680 currentEffectNumber = makeNewEffect(); | |
| 681 } | |
| 682 | |
| 683 @override | |
| 684 void visitYield(Yield node) { | |
| 685 currentEffectNumber = makeNewEffect(); | |
| 686 } | |
| 687 | |
| 688 @override | |
| 689 void visitApplyBuiltinMethod(ApplyBuiltinMethod node) { | 643 void visitApplyBuiltinMethod(ApplyBuiltinMethod node) { |
| 690 Primitive receiver = node.receiver.definition; | 644 Primitive receiver = node.receiver.definition; |
| 691 int effectBefore = currentEffectNumber; | 645 int effectBefore = currentEffectNumber; |
| 692 currentEffectNumber = makeNewEffect(); | 646 currentEffectNumber = makeNewEffect(); |
| 693 int effectAfter = currentEffectNumber; | 647 int effectAfter = currentEffectNumber; |
| 694 SignedVariable lengthBefore = getLength(receiver, effectBefore); | 648 SignedVariable lengthBefore = getLength(receiver, effectBefore); |
| 695 SignedVariable lengthAfter = getLength(receiver, effectAfter); | 649 SignedVariable lengthAfter = getLength(receiver, effectAfter); |
| 696 switch (node.method) { | 650 switch (node.method) { |
| 697 case BuiltinMethod.Push: | 651 case BuiltinMethod.Push: |
| 698 // after = before + count | 652 // after = before + count |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 741 } | 695 } |
| 742 return node.body; | 696 return node.body; |
| 743 } | 697 } |
| 744 } | 698 } |
| 745 | 699 |
| 746 /// Lattice representing the known (weak) monotonicity of a loop variable. | 700 /// Lattice representing the known (weak) monotonicity of a loop variable. |
| 747 /// | 701 /// |
| 748 /// The lattice bottom is represented by `null` and represents the case where | 702 /// The lattice bottom is represented by `null` and represents the case where |
| 749 /// the loop variable never changes value during the loop. | 703 /// the loop variable never changes value during the loop. |
| 750 enum Monotonicity { NotMonotone, Increasing, Decreasing, } | 704 enum Monotonicity { NotMonotone, Increasing, Decreasing, } |
| OLD | NEW |