| 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 '../constants/values.dart' as values; | 7 import '../constants/values.dart' as values; |
| 8 import '../dart_types.dart' show DartType, InterfaceType, TypeVariableType; | 8 import '../dart_types.dart' show DartType, InterfaceType, TypeVariableType; |
| 9 import '../elements/elements.dart'; | 9 import '../elements/elements.dart'; |
| 10 import '../io/source_information.dart' show SourceInformation; | 10 import '../io/source_information.dart' show SourceInformation; |
| (...skipping 693 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 704 | 704 |
| 705 accept(Visitor visitor) => visitor.visitRefinement(this); | 705 accept(Visitor visitor) => visitor.visitRefinement(this); |
| 706 | 706 |
| 707 Primitive get effectiveDefinition => value.definition.effectiveDefinition; | 707 Primitive get effectiveDefinition => value.definition.effectiveDefinition; |
| 708 | 708 |
| 709 void setParentPointers() { | 709 void setParentPointers() { |
| 710 value.parent = this; | 710 value.parent = this; |
| 711 } | 711 } |
| 712 } | 712 } |
| 713 | 713 |
| 714 /// Checks that [index] is a valid index on a given indexable [object]. |
| 715 /// |
| 716 /// Compiles to the following, with a subset of the conditions in the `if`: |
| 717 /// |
| 718 /// if (index < 0 || index >= object.length || object.length === 0) |
| 719 /// ThrowIndexOutOfRangeException(object, index); |
| 720 /// |
| 721 /// [index] must be an integer, and [object] must refer to null or an indexable |
| 722 /// object, and [length] must be the length of [object] at the time of the |
| 723 /// check. |
| 724 /// |
| 725 /// Returns [object] so the bounds check can be used to restrict code motion. |
| 726 /// It is possible to have a bounds check node that performs no checks but |
| 727 /// is retained to restrict code motion. |
| 728 /// |
| 729 /// The [index] reference may be null if there are no checks to perform, |
| 730 /// and the [length] reference may be null if there is no upper bound or |
| 731 /// emptiness check. |
| 732 /// |
| 733 /// If a separate code motion guard for the index is required, e.g. because it |
| 734 /// must be known to be non-negative in an operator that does not involve |
| 735 /// [object], a [Refinement] can be created for it with the non-negative integer |
| 736 /// type. |
| 737 class BoundsCheck extends Primitive { |
| 738 final Reference<Primitive> object; |
| 739 Reference<Primitive> index; |
| 740 Reference<Primitive> length; // FIXME write docs for length |
| 741 int checks; |
| 742 final SourceInformation sourceInformation; |
| 743 |
| 744 /// If true, check that `index >= 0`. |
| 745 bool get hasLowerBoundCheck => checks & LOWER_BOUND != 0; |
| 746 |
| 747 /// If true, check that `index < object.length`. |
| 748 bool get hasUpperBoundCheck => checks & UPPER_BOUND != 0; |
| 749 |
| 750 /// If true, check that `object.length !== 0`. |
| 751 /// |
| 752 /// Equivalent to a lower bound check with `object.length - 1` as the index, |
| 753 /// but this check is faster. |
| 754 /// |
| 755 /// Although [index] is not used in the condition, it is used to generate |
| 756 /// the thrown error. Currently it is always `-1` for emptiness checks, |
| 757 /// because that corresponds to `object.length - 1` in the error case. |
| 758 bool get hasEmptinessCheck => checks & EMPTINESS != 0; |
| 759 |
| 760 /// True if the [length] is needed to perform the check. |
| 761 bool get lengthUsedInCheck => checks & (UPPER_BOUND | EMPTINESS) != 0; |
| 762 |
| 763 bool get hasNoChecks => checks == NONE; |
| 764 |
| 765 static const int UPPER_BOUND = 1 << 0; |
| 766 static const int LOWER_BOUND = 1 << 1; |
| 767 static const int EMPTINESS = 1 << 2; // See [hasEmptinessCheck]. |
| 768 static const int BOTH_BOUNDS = UPPER_BOUND | LOWER_BOUND; |
| 769 static const int NONE = 0; |
| 770 |
| 771 BoundsCheck(Primitive object, Primitive index, Primitive length, |
| 772 [this.checks = BOTH_BOUNDS, this.sourceInformation]) |
| 773 : this.object = new Reference<Primitive>(object), |
| 774 this.index = new Reference<Primitive>(index), |
| 775 this.length = new Reference<Primitive>(length); |
| 776 |
| 777 BoundsCheck.noCheck(Primitive object, [this.sourceInformation]) |
| 778 : this.object = new Reference<Primitive>(object), |
| 779 this.checks = NONE; |
| 780 |
| 781 accept(Visitor visitor) => visitor.visitBoundsCheck(this); |
| 782 |
| 783 void setParentPointers() { |
| 784 object.parent = this; |
| 785 if (index != null) { |
| 786 index.parent = this; |
| 787 } |
| 788 if (length != null) { |
| 789 length.parent = this; |
| 790 } |
| 791 } |
| 792 |
| 793 String get checkString { |
| 794 if (hasUpperBoundCheck && hasLowerBoundCheck) { |
| 795 return 'upper-lower-checks'; |
| 796 } else if (hasUpperBoundCheck) { |
| 797 return 'upper-check'; |
| 798 } else if (hasLowerBoundCheck) { |
| 799 return 'lower-check'; |
| 800 } else if (hasEmptinessCheck) { |
| 801 return 'emptiness-check'; |
| 802 } else { |
| 803 return 'no-check'; |
| 804 } |
| 805 } |
| 806 |
| 807 bool get isSafeForElimination => checks == NONE; |
| 808 bool get isSafeForReordering => false; |
| 809 bool get hasValue => true; // Can be referenced to restrict code motion. |
| 810 |
| 811 Primitive get effectiveDefinition => object.definition.effectiveDefinition; |
| 812 } |
| 813 |
| 714 /// Throw an exception if [value] is `null`. | 814 /// Throw an exception if [value] is `null`. |
| 715 /// | 815 /// |
| 716 /// Returns [value] so this can be used to restrict code motion. | 816 /// Returns [value] so this can be used to restrict code motion. |
| 717 /// | 817 /// |
| 718 /// In the simplest form this compiles to `value.toString;`. | 818 /// In the simplest form this compiles to `value.toString;`. |
| 719 /// | 819 /// |
| 720 /// If [selector] is set, `toString` is replaced with the (possibly minified) | 820 /// If [selector] is set, `toString` is replaced with the (possibly minified) |
| 721 /// invocation name of the selector. This can be shorter and generate a more | 821 /// invocation name of the selector. This can be shorter and generate a more |
| 722 /// meaningful error message, but is expensive if [value] is non-null and does | 822 /// meaningful error message, but is expensive if [value] is non-null and does |
| 723 /// not have that property at runtime. | 823 /// not have that property at runtime. |
| (...skipping 1056 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1780 T visitTypeExpression(TypeExpression node); | 1880 T visitTypeExpression(TypeExpression node); |
| 1781 T visitCreateInvocationMirror(CreateInvocationMirror node); | 1881 T visitCreateInvocationMirror(CreateInvocationMirror node); |
| 1782 T visitTypeTest(TypeTest node); | 1882 T visitTypeTest(TypeTest node); |
| 1783 T visitTypeTestViaFlag(TypeTestViaFlag node); | 1883 T visitTypeTestViaFlag(TypeTestViaFlag node); |
| 1784 T visitApplyBuiltinOperator(ApplyBuiltinOperator node); | 1884 T visitApplyBuiltinOperator(ApplyBuiltinOperator node); |
| 1785 T visitApplyBuiltinMethod(ApplyBuiltinMethod node); | 1885 T visitApplyBuiltinMethod(ApplyBuiltinMethod node); |
| 1786 T visitGetLength(GetLength node); | 1886 T visitGetLength(GetLength node); |
| 1787 T visitGetIndex(GetIndex node); | 1887 T visitGetIndex(GetIndex node); |
| 1788 T visitSetIndex(SetIndex node); | 1888 T visitSetIndex(SetIndex node); |
| 1789 T visitRefinement(Refinement node); | 1889 T visitRefinement(Refinement node); |
| 1890 T visitBoundsCheck(BoundsCheck node); |
| 1790 T visitNullCheck(NullCheck node); | 1891 T visitNullCheck(NullCheck node); |
| 1791 | 1892 |
| 1792 // Support for literal foreign code. | 1893 // Support for literal foreign code. |
| 1793 T visitForeignCode(ForeignCode node); | 1894 T visitForeignCode(ForeignCode node); |
| 1794 } | 1895 } |
| 1795 | 1896 |
| 1796 /// Recursively visits all children of a CPS term. | 1897 /// Recursively visits all children of a CPS term. |
| 1797 /// | 1898 /// |
| 1798 /// The user of the class is responsible for avoiding stack overflows from | 1899 /// The user of the class is responsible for avoiding stack overflows from |
| 1799 /// deep recursion, e.g. by overriding methods to cut off recursion at certain | 1900 /// deep recursion, e.g. by overriding methods to cut off recursion at certain |
| (...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2100 processReference(node.index); | 2201 processReference(node.index); |
| 2101 processReference(node.value); | 2202 processReference(node.value); |
| 2102 } | 2203 } |
| 2103 | 2204 |
| 2104 processRefinement(Refinement node) {} | 2205 processRefinement(Refinement node) {} |
| 2105 visitRefinement(Refinement node) { | 2206 visitRefinement(Refinement node) { |
| 2106 processRefinement(node); | 2207 processRefinement(node); |
| 2107 processReference(node.value); | 2208 processReference(node.value); |
| 2108 } | 2209 } |
| 2109 | 2210 |
| 2211 processBoundsCheck(BoundsCheck node) {} |
| 2212 visitBoundsCheck(BoundsCheck node) { |
| 2213 processBoundsCheck(node); |
| 2214 processReference(node.object); |
| 2215 if (node.index != null) { |
| 2216 processReference(node.index); |
| 2217 } |
| 2218 if (node.length != null) { |
| 2219 processReference(node.length); |
| 2220 } |
| 2221 } |
| 2222 |
| 2110 processNullCheck(NullCheck node) {} | 2223 processNullCheck(NullCheck node) {} |
| 2111 visitNullCheck(NullCheck node) { | 2224 visitNullCheck(NullCheck node) { |
| 2112 processNullCheck(node); | 2225 processNullCheck(node); |
| 2113 processReference(node.value); | 2226 processReference(node.value); |
| 2114 if (node.condition != null) { | 2227 if (node.condition != null) { |
| 2115 processReference(node.condition); | 2228 processReference(node.condition); |
| 2116 } | 2229 } |
| 2117 } | 2230 } |
| 2118 } | 2231 } |
| 2119 | 2232 |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2241 /// Visit a just-deleted subterm and unlink all [Reference]s in it. | 2354 /// Visit a just-deleted subterm and unlink all [Reference]s in it. |
| 2242 class RemovalVisitor extends TrampolineRecursiveVisitor { | 2355 class RemovalVisitor extends TrampolineRecursiveVisitor { |
| 2243 processReference(Reference reference) { | 2356 processReference(Reference reference) { |
| 2244 reference.unlink(); | 2357 reference.unlink(); |
| 2245 } | 2358 } |
| 2246 | 2359 |
| 2247 static void remove(Node node) { | 2360 static void remove(Node node) { |
| 2248 (new RemovalVisitor()).visit(node); | 2361 (new RemovalVisitor()).visit(node); |
| 2249 } | 2362 } |
| 2250 } | 2363 } |
| OLD | NEW |