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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
index 53a1a98b7f5c118b732ee793c3eb30e338ef2594..1c60c5a66ecd8128b5018b460478cf8a8c81b54c 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
@@ -234,7 +234,13 @@ abstract class Primitive extends Variable<Primitive> {
// TODO(johnniwinther): Require source information for all primitives.
SourceInformation get sourceInformation => null;
- /// If this is a [Refinement] node, returns the value being refined.
+ /// If this is a [Refinement] or [BoundsCheck] returns the value being refined
+ /// or the indexable object being checked.
+ ///
+ /// Those instructions all return the corresponding operand directly, and
+ /// this getter can be used to get (closer to) where the value came from.
+ //
+ // TODO(asgerf): Also do this for [TypeCast]?
Primitive get effectiveDefinition => this;
/// True if the two primitives are (refinements of) the same value.
@@ -704,6 +710,101 @@ class Refinement extends Primitive {
}
}
+/// Checks that [index] is a valid index on a given indexable [object].
+///
+/// [index] must be an integer, and [object] must refer to null or an indexable
+/// object, and [length] must be the length of [object] at the time of the
+/// check.
+///
+/// Returns [object] so the bounds check can be used to restrict code motion.
+/// It is possible to have a bounds check node that performs no checks but
+/// is retained to restrict code motion.
+///
+/// The [index] reference may be null if there are no checks to perform,
+/// and the [length] reference may be null if there is no upper bound or
+/// emptiness check.
+///
+/// If a separate code motion guard for the index is required, e.g. because it
+/// must be known to be non-negative in an operator that does not involve
+/// [object], a [Refinement] can be created for it with the non-negative integer
+/// type.
+class BoundsCheck extends Primitive {
+ final Reference<Primitive> object;
+ Reference<Primitive> index;
+ Reference<Primitive> length; // FIXME write docs for length
+ int checks;
+ final SourceInformation sourceInformation;
+
+ /// If true, check that `index >= 0`.
+ bool get hasLowerBoundCheck => checks & LOWER_BOUND != 0;
+
+ /// If true, check that `index < object.length`.
+ bool get hasUpperBoundCheck => checks & UPPER_BOUND != 0;
+
+ /// If true, check that `object.length !== 0`.
+ ///
+ /// Equivalent to a lower bound check with `object.length - 1` as the index,
+ /// but this check is faster.
+ ///
+ /// Although [index] is not used in the condition, it is used to generate
+ /// the thrown error. Currently it is always `-1` for emptiness checks,
+ /// because that corresponds to `object.length - 1` in the error case.
+ bool get hasEmptinessCheck => checks & EMPTINESS != 0;
+
+ /// 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.
+ bool get checkNeedsLength => checks & (UPPER_BOUND | EMPTINESS) != 0;
+
+ bool get hasNoChecks => checks == NONE;
+
+ static const int UPPER_BOUND = 1 << 0;
+ static const int LOWER_BOUND = 1 << 1;
+ 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
+ static const int BOTH_BOUNDS = UPPER_BOUND | LOWER_BOUND;
+ static const int NONE = 0;
+
+ BoundsCheck(Primitive object, Primitive index, Primitive length,
+ [this.checks = BOTH_BOUNDS, this.sourceInformation])
+ : this.object = new Reference<Primitive>(object),
+ this.index = new Reference<Primitive>(index),
+ this.length = new Reference<Primitive>(length);
+
+ BoundsCheck.noCheck(Primitive object, [this.sourceInformation])
+ : this.object = new Reference<Primitive>(object),
+ this.checks = NONE;
+
+ accept(Visitor visitor) => visitor.visitBoundsCheck(this);
+
+ void setParentPointers() {
+ object.parent = this;
+ if (index != null) {
+ index.parent = this;
+ }
+ if (length != null) {
+ length.parent = this;
+ }
+ }
+
+ String get checkString {
+ if (hasUpperBoundCheck && hasLowerBoundCheck) {
+ return 'upper-lower-checks';
+ } else if (hasUpperBoundCheck) {
+ return 'upper-check';
+ } else if (hasLowerBoundCheck) {
+ return 'lower-check';
+ } else if (hasEmptinessCheck) {
+ return 'emptiness-check';
+ } else {
+ return 'no-check';
+ }
+ }
+
+ bool get isSafeForElimination => checks == NONE;
+ bool get isSafeForReordering => false;
+ bool get hasValue => true; // Can be referenced to restrict code motion.
+
+ Primitive get effectiveDefinition => object.definition.effectiveDefinition;
+}
+
/// An "is" type test.
///
/// Returns `true` if [value] is an instance of [type].
@@ -1093,9 +1194,9 @@ class GetLength extends Primitive {
}
}
-/// Read an entry from a string or native list.
+/// Read an entry from an indexable object.
///
-/// [object] must be null or a native list or a string, and [index] must be
+/// [object] must be null or an indexable object, and [index] must be
/// an integer.
class GetIndex extends Primitive {
final Reference<Primitive> object;
@@ -1732,6 +1833,7 @@ abstract class Visitor<T> {
T visitGetIndex(GetIndex node);
T visitSetIndex(SetIndex node);
T visitRefinement(Refinement node);
+ T visitBoundsCheck(BoundsCheck node);
// Support for literal foreign code.
T visitForeignCode(ForeignCode node);
@@ -2050,6 +2152,18 @@ class DeepRecursiveVisitor implements Visitor {
processRefinement(node);
processReference(node.value);
}
+
+ processBoundsCheck(BoundsCheck node) {}
+ visitBoundsCheck(BoundsCheck node) {
+ processBoundsCheck(node);
+ processReference(node.object);
+ if (node.index != null) {
+ processReference(node.index);
+ }
+ if (node.length != null) {
+ processReference(node.length);
+ }
+ }
}
typedef void StackAction();

Powered by Google App Engine
This is Rietveld 408576698