| 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 library dart2js.ir_nodes; | 4 library dart2js.ir_nodes; |
| 5 | 5 |
| 6 import 'dart:collection'; | 6 import 'dart:collection'; |
| 7 import 'cps_fragment.dart' show CpsFragment; | 7 import 'cps_fragment.dart' show CpsFragment; |
| 8 import 'cps_ir_nodes_sexpr.dart'; | 8 import 'cps_ir_nodes_sexpr.dart'; |
| 9 import '../constants/values.dart' as values; | 9 import '../constants/values.dart' as values; |
| 10 import '../dart_types.dart' show DartType, InterfaceType, TypeVariableType; | 10 import '../dart_types.dart' show DartType, InterfaceType, TypeVariableType; |
| (...skipping 763 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 774 | 774 |
| 775 Primitive get unrefined => value.definition.unrefined; | 775 Primitive get unrefined => value.definition.unrefined; |
| 776 | 776 |
| 777 void setParentPointers() { | 777 void setParentPointers() { |
| 778 value.parent = this; | 778 value.parent = this; |
| 779 } | 779 } |
| 780 } | 780 } |
| 781 | 781 |
| 782 /// Checks that [index] is a valid index on a given indexable [object]. | 782 /// Checks that [index] is a valid index on a given indexable [object]. |
| 783 /// | 783 /// |
| 784 /// Compiles to the following, with a subset of the conditions in the `if`: | 784 /// In the simplest form, compiles to the following: |
| 785 /// | 785 /// |
| 786 /// if (index < 0 || index >= object.length || object.length === 0) | 786 /// if (index < 0 || index >= object.length) |
| 787 /// ThrowIndexOutOfRangeException(object, index); | 787 /// ThrowIndexOutOfRangeException(object, index); |
| 788 /// | 788 /// |
| 789 /// [index] must be an integer, and [object] must refer to null or an indexable | 789 /// In the general form, any of the following conditions can be checked: |
| 790 /// object, and [length] must be the length of [object] at the time of the | 790 /// |
| 791 /// check. | 791 /// Lower bound: `index >= 0` |
| 792 /// Upper bound: `index < object.length` |
| 793 /// Emptiness: `object.length !== 0` |
| 794 /// Integerness: `index >>> 0 === index` |
| 795 /// |
| 796 /// [index] must be an integer unless integerness is checked, and [object] must |
| 797 /// refer to null or an indexable object, and [length] must be the length of |
| 798 /// [object] at the time of the check. |
| 792 /// | 799 /// |
| 793 /// Returns [object] so the bounds check can be used to restrict code motion. | 800 /// Returns [object] so the bounds check can be used to restrict code motion. |
| 794 /// It is possible to have a bounds check node that performs no checks but | 801 /// It is possible to have a bounds check node that performs no checks but |
| 795 /// is retained to restrict code motion. | 802 /// is retained to restrict code motion. |
| 796 /// | 803 /// |
| 797 /// The [index] reference may be null if there are no checks to perform, | 804 /// The [index] reference may be null if there are no checks to perform, |
| 798 /// and the [length] reference may be null if there is no upper bound or | 805 /// and the [length] reference may be null if there is no upper bound or |
| 799 /// emptiness check. | 806 /// emptiness check. |
| 800 /// | 807 /// |
| 801 /// If a separate code motion guard for the index is required, e.g. because it | 808 /// If a separate code motion guard for the index is required, e.g. because it |
| (...skipping 16 matching lines...) Expand all Loading... |
| 818 /// If true, check that `object.length !== 0`. | 825 /// If true, check that `object.length !== 0`. |
| 819 /// | 826 /// |
| 820 /// Equivalent to a lower bound check with `object.length - 1` as the index, | 827 /// Equivalent to a lower bound check with `object.length - 1` as the index, |
| 821 /// but this check is faster. | 828 /// but this check is faster. |
| 822 /// | 829 /// |
| 823 /// Although [index] is not used in the condition, it is used to generate | 830 /// Although [index] is not used in the condition, it is used to generate |
| 824 /// the thrown error. Currently it is always `-1` for emptiness checks, | 831 /// the thrown error. Currently it is always `-1` for emptiness checks, |
| 825 /// because that corresponds to `object.length - 1` in the error case. | 832 /// because that corresponds to `object.length - 1` in the error case. |
| 826 bool get hasEmptinessCheck => checks & EMPTINESS != 0; | 833 bool get hasEmptinessCheck => checks & EMPTINESS != 0; |
| 827 | 834 |
| 835 /// If true, check that `index` is an integer. |
| 836 bool get hasIntegerCheck => checks & INTEGER != 0; |
| 837 |
| 828 /// True if the [length] is needed to perform the check. | 838 /// True if the [length] is needed to perform the check. |
| 829 bool get lengthUsedInCheck => checks & (UPPER_BOUND | EMPTINESS) != 0; | 839 bool get lengthUsedInCheck => checks & (UPPER_BOUND | EMPTINESS) != 0; |
| 830 | 840 |
| 831 bool get hasNoChecks => checks == NONE; | 841 bool get hasNoChecks => checks == NONE; |
| 832 | 842 |
| 833 static const int UPPER_BOUND = 1 << 0; | 843 static const int UPPER_BOUND = 1 << 0; |
| 834 static const int LOWER_BOUND = 1 << 1; | 844 static const int LOWER_BOUND = 1 << 1; |
| 835 static const int EMPTINESS = 1 << 2; // See [hasEmptinessCheck]. | 845 static const int EMPTINESS = 1 << 2; // See [hasEmptinessCheck]. |
| 846 static const int INTEGER = 1 << 3; // Check if index is an int. |
| 836 static const int BOTH_BOUNDS = UPPER_BOUND | LOWER_BOUND; | 847 static const int BOTH_BOUNDS = UPPER_BOUND | LOWER_BOUND; |
| 837 static const int NONE = 0; | 848 static const int NONE = 0; |
| 838 | 849 |
| 839 BoundsCheck(Primitive object, Primitive index, Primitive length, | 850 BoundsCheck(Primitive object, Primitive index, Primitive length, |
| 840 [this.checks = BOTH_BOUNDS, this.sourceInformation]) | 851 [this.checks = BOTH_BOUNDS, this.sourceInformation]) |
| 841 : this.object = new Reference<Primitive>(object), | 852 : this.object = new Reference<Primitive>(object), |
| 842 this.index = new Reference<Primitive>(index), | 853 this.index = new Reference<Primitive>(index), |
| 843 this.length = length == null ? null : new Reference<Primitive>(length); | 854 this.length = length == null ? null : new Reference<Primitive>(length); |
| 844 | 855 |
| 845 BoundsCheck.noCheck(Primitive object, [this.sourceInformation]) | 856 BoundsCheck.noCheck(Primitive object, [this.sourceInformation]) |
| 846 : this.object = new Reference<Primitive>(object), | 857 : this.object = new Reference<Primitive>(object), |
| 847 this.checks = NONE; | 858 this.checks = NONE; |
| 848 | 859 |
| 849 accept(Visitor visitor) => visitor.visitBoundsCheck(this); | 860 accept(Visitor visitor) => visitor.visitBoundsCheck(this); |
| 850 | 861 |
| 851 void setParentPointers() { | 862 void setParentPointers() { |
| 852 object.parent = this; | 863 object.parent = this; |
| 853 if (index != null) { | 864 if (index != null) { |
| 854 index.parent = this; | 865 index.parent = this; |
| 855 } | 866 } |
| 856 if (length != null) { | 867 if (length != null) { |
| 857 length.parent = this; | 868 length.parent = this; |
| 858 } | 869 } |
| 859 } | 870 } |
| 860 | 871 |
| 861 String get checkString { | 872 String get checkString { |
| 862 if (hasUpperBoundCheck && hasLowerBoundCheck) { | 873 if (hasNoChecks) return 'no-check'; |
| 863 return 'upper-lower-checks'; | 874 return [hasUpperBoundCheck ? 'upper' : null, |
| 864 } else if (hasUpperBoundCheck) { | 875 hasLowerBoundCheck ? 'lower' : null, |
| 865 return 'upper-check'; | 876 hasEmptinessCheck ? 'emptiness' : null, |
| 866 } else if (hasLowerBoundCheck) { | 877 hasIntegerCheck ? 'integer' : null, |
| 867 return 'lower-check'; | 878 'check'] |
| 868 } else if (hasEmptinessCheck) { | 879 .where((x) => x != null).join('-'); |
| 869 return 'emptiness-check'; | |
| 870 } else { | |
| 871 return 'no-check'; | |
| 872 } | |
| 873 } | 880 } |
| 874 | 881 |
| 875 bool get isSafeForElimination => checks == NONE; | 882 bool get isSafeForElimination => checks == NONE; |
| 876 bool get isSafeForReordering => false; | 883 bool get isSafeForReordering => false; |
| 877 bool get hasValue => true; // Can be referenced to restrict code motion. | 884 bool get hasValue => true; // Can be referenced to restrict code motion. |
| 878 | 885 |
| 879 Primitive get effectiveDefinition => object.definition.effectiveDefinition; | 886 Primitive get effectiveDefinition => object.definition.effectiveDefinition; |
| 880 } | 887 } |
| 881 | 888 |
| 882 /// Throw a [NoSuchMethodError] if [value] cannot respond to [selector]. | 889 /// Throw a [NoSuchMethodError] if [value] cannot respond to [selector]. |
| (...skipping 2090 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2973 plug(new Branch.loose(_definitions.getCopy(node.condition), | 2980 plug(new Branch.loose(_definitions.getCopy(node.condition), |
| 2974 _copies[node.trueContinuation.definition], | 2981 _copies[node.trueContinuation.definition], |
| 2975 _copies[node.falseContinuation.definition]) | 2982 _copies[node.falseContinuation.definition]) |
| 2976 ..isStrictCheck = node.isStrictCheck); | 2983 ..isStrictCheck = node.isStrictCheck); |
| 2977 } | 2984 } |
| 2978 | 2985 |
| 2979 visitUnreachable(Unreachable node) { | 2986 visitUnreachable(Unreachable node) { |
| 2980 plug(new Unreachable()); | 2987 plug(new Unreachable()); |
| 2981 } | 2988 } |
| 2982 } | 2989 } |
| OLD | NEW |