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

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: Update gvn_test output 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
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/cps_fragment.dart ('k') | pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 8fb49d605e77b41ab7449b2ba217c80f94e2450a..4620f4f1c8770910797586588cf5f92c19a86c88 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
@@ -711,6 +711,106 @@ class Refinement extends Primitive {
}
}
+/// Checks that [index] is a valid index on a given indexable [object].
+///
+/// Compiles to the following, with a subset of the conditions in the `if`:
+///
+/// if (index < 0 || index >= object.length || object.length === 0)
+/// ThrowIndexOutOfRangeException(object, index);
+///
+/// [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 if the [length] is needed to perform the check.
+ bool get lengthUsedInCheck => 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; // See [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;
+}
+
/// Throw an exception if [value] is `null`.
///
/// Returns [value] so this can be used to restrict code motion.
@@ -1787,6 +1887,7 @@ abstract class Visitor<T> {
T visitGetIndex(GetIndex node);
T visitSetIndex(SetIndex node);
T visitRefinement(Refinement node);
+ T visitBoundsCheck(BoundsCheck node);
T visitNullCheck(NullCheck node);
// Support for literal foreign code.
@@ -2107,6 +2208,18 @@ class DeepRecursiveVisitor implements Visitor {
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);
+ }
+ }
+
processNullCheck(NullCheck node) {}
visitNullCheck(NullCheck node) {
processNullCheck(node);
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/cps_fragment.dart ('k') | pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698