Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(337)

Side by Side Diff: pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart

Issue 1512303002: dart2js cps: Add instruction for bounds checks. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698