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 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 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 227 bool get isSafeForElimination; | 227 bool get isSafeForElimination; |
| 228 | 228 |
| 229 /// True if time-of-evaluation is irrelevant for the given primitive, | 229 /// True if time-of-evaluation is irrelevant for the given primitive, |
| 230 /// assuming its inputs are the same values. | 230 /// assuming its inputs are the same values. |
| 231 bool get isSafeForReordering; | 231 bool get isSafeForReordering; |
| 232 | 232 |
| 233 /// The source information associated with this primitive. | 233 /// The source information associated with this primitive. |
| 234 // TODO(johnniwinther): Require source information for all primitives. | 234 // TODO(johnniwinther): Require source information for all primitives. |
| 235 SourceInformation get sourceInformation => null; | 235 SourceInformation get sourceInformation => null; |
| 236 | 236 |
| 237 /// If this is a [Refinement] node, returns the value being refined. | 237 /// If this is a [Refinement] or [BoundsCheck] returns the value being refined |
| 238 /// or the indexable object being checked. | |
| 239 /// | |
| 240 /// Those instructions all return the corresponding operand directly, and | |
| 241 /// this getter can be used to get (closer to) where the value came from. | |
| 242 // | |
| 243 // TODO(asgerf): Also do this for [TypeCast]? | |
| 238 Primitive get effectiveDefinition => this; | 244 Primitive get effectiveDefinition => this; |
| 239 | 245 |
| 240 /// True if the two primitives are (refinements of) the same value. | 246 /// True if the two primitives are (refinements of) the same value. |
| 241 bool sameValue(Primitive other) { | 247 bool sameValue(Primitive other) { |
| 242 return effectiveDefinition == other.effectiveDefinition; | 248 return effectiveDefinition == other.effectiveDefinition; |
| 243 } | 249 } |
| 244 | 250 |
| 245 /// Iterates all non-refinement uses of the primitive and all uses of | 251 /// Iterates all non-refinement uses of the primitive and all uses of |
| 246 /// a [Refinement] of this primitive (transitively). | 252 /// a [Refinement] of this primitive (transitively). |
| 247 /// | 253 /// |
| (...skipping 449 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 697 | 703 |
| 698 accept(Visitor visitor) => visitor.visitRefinement(this); | 704 accept(Visitor visitor) => visitor.visitRefinement(this); |
| 699 | 705 |
| 700 Primitive get effectiveDefinition => value.definition.effectiveDefinition; | 706 Primitive get effectiveDefinition => value.definition.effectiveDefinition; |
| 701 | 707 |
| 702 void setParentPointers() { | 708 void setParentPointers() { |
| 703 value.parent = this; | 709 value.parent = this; |
| 704 } | 710 } |
| 705 } | 711 } |
| 706 | 712 |
| 713 /// Checks that [index] is a valid index on a given indexable [object]. | |
| 714 /// | |
| 715 /// [index] must be an integer, and [object] must refer to null or an indexable | |
| 716 /// object, and [length] must be the length of [object] at the time of the | |
| 717 /// check. | |
| 718 /// | |
| 719 /// Returns [object] so the bounds check can be used to restrict code motion. | |
| 720 /// It is possible to have a bounds check node that performs no checks but | |
| 721 /// is retained to restrict code motion. | |
| 722 /// | |
| 723 /// The [index] reference may be null if there are no checks to perform, | |
| 724 /// and the [length] reference may be null if there is no upper bound or | |
| 725 /// emptiness check. | |
| 726 /// | |
| 727 /// If a separate code motion guard for the index is required, e.g. because it | |
| 728 /// must be known to be non-negative in an operator that does not involve | |
| 729 /// [object], a [Refinement] can be created for it with the non-negative integer | |
| 730 /// type. | |
| 731 class BoundsCheck extends Primitive { | |
| 732 final Reference<Primitive> object; | |
| 733 Reference<Primitive> index; | |
| 734 Reference<Primitive> length; // FIXME write docs for length | |
| 735 int checks; | |
| 736 final SourceInformation sourceInformation; | |
| 737 | |
| 738 /// If true, check that `index >= 0`. | |
| 739 bool get hasLowerBoundCheck => checks & LOWER_BOUND != 0; | |
| 740 | |
| 741 /// If true, check that `index < object.length`. | |
| 742 bool get hasUpperBoundCheck => checks & UPPER_BOUND != 0; | |
| 743 | |
| 744 /// If true, check that `object.length !== 0`. | |
| 745 /// | |
| 746 /// Equivalent to a lower bound check with `object.length - 1` as the index, | |
| 747 /// but this check is faster. | |
| 748 /// | |
| 749 /// Although [index] is not used in the condition, it is used to generate | |
| 750 /// the thrown error. Currently it is always `-1` for emptiness checks, | |
| 751 /// because that corresponds to `object.length - 1` in the error case. | |
| 752 bool get hasEmptinessCheck => checks & EMPTINESS != 0; | |
| 753 | |
| 754 /// True of the [length] is needed. | |
|
sra1
2015/12/10 19:09:40
... is needed to perform the check.
Maybe call it
asgerf
2015/12/11 12:16:31
Done.
| |
| 755 bool get checkNeedsLength => checks & (UPPER_BOUND | EMPTINESS) != 0; | |
| 756 | |
| 757 bool get hasNoChecks => checks == NONE; | |
| 758 | |
| 759 static const int UPPER_BOUND = 1 << 0; | |
| 760 static const int LOWER_BOUND = 1 << 1; | |
| 761 static const int EMPTINESS = 1 << 2; | |
|
sra1
2015/12/10 19:09:39
What is EMPTINESS?
asgerf
2015/12/11 12:16:31
I thought it would be clear from hasEmptinessCheck
| |
| 762 static const int BOTH_BOUNDS = UPPER_BOUND | LOWER_BOUND; | |
| 763 static const int NONE = 0; | |
| 764 | |
| 765 BoundsCheck(Primitive object, Primitive index, Primitive length, | |
| 766 [this.checks = BOTH_BOUNDS, this.sourceInformation]) | |
| 767 : this.object = new Reference<Primitive>(object), | |
| 768 this.index = new Reference<Primitive>(index), | |
| 769 this.length = new Reference<Primitive>(length); | |
| 770 | |
| 771 BoundsCheck.noCheck(Primitive object, [this.sourceInformation]) | |
| 772 : this.object = new Reference<Primitive>(object), | |
| 773 this.checks = NONE; | |
| 774 | |
| 775 accept(Visitor visitor) => visitor.visitBoundsCheck(this); | |
| 776 | |
| 777 void setParentPointers() { | |
| 778 object.parent = this; | |
| 779 if (index != null) { | |
| 780 index.parent = this; | |
| 781 } | |
| 782 if (length != null) { | |
| 783 length.parent = this; | |
| 784 } | |
| 785 } | |
| 786 | |
| 787 String get checkString { | |
| 788 if (hasUpperBoundCheck && hasLowerBoundCheck) { | |
| 789 return 'upper-lower-checks'; | |
| 790 } else if (hasUpperBoundCheck) { | |
| 791 return 'upper-check'; | |
| 792 } else if (hasLowerBoundCheck) { | |
| 793 return 'lower-check'; | |
| 794 } else if (hasEmptinessCheck) { | |
| 795 return 'emptiness-check'; | |
| 796 } else { | |
| 797 return 'no-check'; | |
| 798 } | |
| 799 } | |
| 800 | |
| 801 bool get isSafeForElimination => checks == NONE; | |
| 802 bool get isSafeForReordering => false; | |
| 803 bool get hasValue => true; // Can be referenced to restrict code motion. | |
| 804 | |
| 805 Primitive get effectiveDefinition => object.definition.effectiveDefinition; | |
| 806 } | |
| 807 | |
| 707 /// An "is" type test. | 808 /// An "is" type test. |
| 708 /// | 809 /// |
| 709 /// Returns `true` if [value] is an instance of [type]. | 810 /// Returns `true` if [value] is an instance of [type]. |
| 710 /// | 811 /// |
| 711 /// [type] must not be the [Object], `dynamic` or [Null] types (though it might | 812 /// [type] must not be the [Object], `dynamic` or [Null] types (though it might |
| 712 /// be a type variable containing one of these types). This design is chosen | 813 /// be a type variable containing one of these types). This design is chosen |
| 713 /// to simplify code generation for type tests. | 814 /// to simplify code generation for type tests. |
| 714 class TypeTest extends Primitive { | 815 class TypeTest extends Primitive { |
| 715 Reference<Primitive> value; | 816 Reference<Primitive> value; |
| 716 final DartType dartType; | 817 final DartType dartType; |
| (...skipping 369 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1086 bool get isSafeForElimination => objectIsNotNull; | 1187 bool get isSafeForElimination => objectIsNotNull; |
| 1087 bool get isSafeForReordering => false; | 1188 bool get isSafeForReordering => false; |
| 1088 | 1189 |
| 1089 accept(Visitor v) => v.visitGetLength(this); | 1190 accept(Visitor v) => v.visitGetLength(this); |
| 1090 | 1191 |
| 1091 void setParentPointers() { | 1192 void setParentPointers() { |
| 1092 object.parent = this; | 1193 object.parent = this; |
| 1093 } | 1194 } |
| 1094 } | 1195 } |
| 1095 | 1196 |
| 1096 /// Read an entry from a string or native list. | 1197 /// Read an entry from an indexable object. |
| 1097 /// | 1198 /// |
| 1098 /// [object] must be null or a native list or a string, and [index] must be | 1199 /// [object] must be null or an indexable object, and [index] must be |
| 1099 /// an integer. | 1200 /// an integer. |
| 1100 class GetIndex extends Primitive { | 1201 class GetIndex extends Primitive { |
| 1101 final Reference<Primitive> object; | 1202 final Reference<Primitive> object; |
| 1102 final Reference<Primitive> index; | 1203 final Reference<Primitive> index; |
| 1103 | 1204 |
| 1104 /// True if the object is known not to be null. | 1205 /// True if the object is known not to be null. |
| 1105 bool objectIsNotNull = false; | 1206 bool objectIsNotNull = false; |
| 1106 | 1207 |
| 1107 GetIndex(Primitive object, Primitive index) | 1208 GetIndex(Primitive object, Primitive index) |
| 1108 : this.object = new Reference<Primitive>(object), | 1209 : this.object = new Reference<Primitive>(object), |
| (...skipping 616 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1725 T visitTypeExpression(TypeExpression node); | 1826 T visitTypeExpression(TypeExpression node); |
| 1726 T visitCreateInvocationMirror(CreateInvocationMirror node); | 1827 T visitCreateInvocationMirror(CreateInvocationMirror node); |
| 1727 T visitTypeTest(TypeTest node); | 1828 T visitTypeTest(TypeTest node); |
| 1728 T visitTypeTestViaFlag(TypeTestViaFlag node); | 1829 T visitTypeTestViaFlag(TypeTestViaFlag node); |
| 1729 T visitApplyBuiltinOperator(ApplyBuiltinOperator node); | 1830 T visitApplyBuiltinOperator(ApplyBuiltinOperator node); |
| 1730 T visitApplyBuiltinMethod(ApplyBuiltinMethod node); | 1831 T visitApplyBuiltinMethod(ApplyBuiltinMethod node); |
| 1731 T visitGetLength(GetLength node); | 1832 T visitGetLength(GetLength node); |
| 1732 T visitGetIndex(GetIndex node); | 1833 T visitGetIndex(GetIndex node); |
| 1733 T visitSetIndex(SetIndex node); | 1834 T visitSetIndex(SetIndex node); |
| 1734 T visitRefinement(Refinement node); | 1835 T visitRefinement(Refinement node); |
| 1836 T visitBoundsCheck(BoundsCheck node); | |
| 1735 | 1837 |
| 1736 // Support for literal foreign code. | 1838 // Support for literal foreign code. |
| 1737 T visitForeignCode(ForeignCode node); | 1839 T visitForeignCode(ForeignCode node); |
| 1738 } | 1840 } |
| 1739 | 1841 |
| 1740 /// Recursively visits all children of a CPS term. | 1842 /// Recursively visits all children of a CPS term. |
| 1741 /// | 1843 /// |
| 1742 /// The user of the class is responsible for avoiding stack overflows from | 1844 /// The user of the class is responsible for avoiding stack overflows from |
| 1743 /// deep recursion, e.g. by overriding methods to cut off recursion at certain | 1845 /// deep recursion, e.g. by overriding methods to cut off recursion at certain |
| 1744 /// points. | 1846 /// points. |
| (...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2043 processReference(node.object); | 2145 processReference(node.object); |
| 2044 processReference(node.index); | 2146 processReference(node.index); |
| 2045 processReference(node.value); | 2147 processReference(node.value); |
| 2046 } | 2148 } |
| 2047 | 2149 |
| 2048 processRefinement(Refinement node) {} | 2150 processRefinement(Refinement node) {} |
| 2049 visitRefinement(Refinement node) { | 2151 visitRefinement(Refinement node) { |
| 2050 processRefinement(node); | 2152 processRefinement(node); |
| 2051 processReference(node.value); | 2153 processReference(node.value); |
| 2052 } | 2154 } |
| 2155 | |
| 2156 processBoundsCheck(BoundsCheck node) {} | |
| 2157 visitBoundsCheck(BoundsCheck node) { | |
| 2158 processBoundsCheck(node); | |
| 2159 processReference(node.object); | |
| 2160 if (node.index != null) { | |
| 2161 processReference(node.index); | |
| 2162 } | |
| 2163 if (node.length != null) { | |
| 2164 processReference(node.length); | |
| 2165 } | |
| 2166 } | |
| 2053 } | 2167 } |
| 2054 | 2168 |
| 2055 typedef void StackAction(); | 2169 typedef void StackAction(); |
| 2056 | 2170 |
| 2057 /// Calls `process*` for all nodes in a tree. | 2171 /// Calls `process*` for all nodes in a tree. |
| 2058 /// For simple usage, only override the `process*` methods. | 2172 /// For simple usage, only override the `process*` methods. |
| 2059 /// | 2173 /// |
| 2060 /// To avoid deep recursion, this class uses an "action stack" containing | 2174 /// To avoid deep recursion, this class uses an "action stack" containing |
| 2061 /// callbacks to be invoked after the processing of some term has finished. | 2175 /// callbacks to be invoked after the processing of some term has finished. |
| 2062 /// | 2176 /// |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2176 /// Visit a just-deleted subterm and unlink all [Reference]s in it. | 2290 /// Visit a just-deleted subterm and unlink all [Reference]s in it. |
| 2177 class RemovalVisitor extends TrampolineRecursiveVisitor { | 2291 class RemovalVisitor extends TrampolineRecursiveVisitor { |
| 2178 processReference(Reference reference) { | 2292 processReference(Reference reference) { |
| 2179 reference.unlink(); | 2293 reference.unlink(); |
| 2180 } | 2294 } |
| 2181 | 2295 |
| 2182 static void remove(Node node) { | 2296 static void remove(Node node) { |
| 2183 (new RemovalVisitor()).visit(node); | 2297 (new RemovalVisitor()).visit(node); |
| 2184 } | 2298 } |
| 2185 } | 2299 } |
| OLD | NEW |