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

Unified Diff: pkg/compiler/lib/src/cps_ir/bounds_checker.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 | « no previous file | pkg/compiler/lib/src/cps_ir/cps_fragment.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/bounds_checker.dart
diff --git a/pkg/compiler/lib/src/cps_ir/bounds_checker.dart b/pkg/compiler/lib/src/cps_ir/bounds_checker.dart
index a22779413844f694518957080342a0c7d4a942b5..223c24a303c8f3b52a87fcabdfc83e228c1206f1 100644
--- a/pkg/compiler/lib/src/cps_ir/bounds_checker.dart
+++ b/pkg/compiler/lib/src/cps_ir/bounds_checker.dart
@@ -10,12 +10,11 @@ import 'octagon.dart';
import '../constants/values.dart';
import 'cps_fragment.dart';
import 'type_mask_system.dart';
+import '../types/types.dart';
import '../world.dart';
import '../elements/elements.dart';
import 'loop_effects.dart';
-
-
/// Eliminates bounds checks when they can be proven safe.
///
/// In general, this pass will try to eliminate any branch with arithmetic
@@ -114,17 +113,24 @@ class BoundsChecker extends TrampolineRecursiveVisitor implements Pass {
}
/// Get a constraint variable representing the length of [indexableObject] at
- /// program locations with the given [effectCounter].
- SignedVariable getLength(Primitive indexableObject, int effectCounter) {
+ /// program locations with the given [effectNumber].
+ SignedVariable getLength(Primitive indexableObject, int effectNumber) {
indexableObject = indexableObject.effectiveDefinition;
- if (indexableObject.type != null &&
- types.isDefinitelyFixedLengthIndexable(indexableObject.type)) {
- // Always use the same effect counter if the length is immutable.
- effectCounter = 0;
+ TypeMask type = indexableObject.type.nonNullable();
+ if (types.isDefinitelyFixedLengthIndexable(type)) {
+ // Always use the same effect number if the length is immutable.
+ effectNumber = 0;
}
return lengthOf
.putIfAbsent(indexableObject, () => <int, SignedVariable>{})
- .putIfAbsent(effectCounter, () => octagon.makeVariable(0, MAX_UINT32));
+ .putIfAbsent(effectNumber, () {
+ int length = types.getContainerLength(type);
+ if (length != null) {
+ return octagon.makeVariable(length, length);
+ } else {
+ return octagon.makeVariable(0, MAX_UINT32);
+ }
+ });
}
// ------------- CONSTRAINT HELPERS -----------------
@@ -238,6 +244,11 @@ class BoundsChecker extends TrampolineRecursiveVisitor implements Pass {
return testConstraint(v1, v2.negated, 0);
}
+ /// Return true if we can prove that `v1 < v2`.
+ bool isDefinitelyLessThan(SignedVariable v1, SignedVariable v2) {
+ return testConstraint(v1, v2.negated, -1);
+ }
+
/// Return true if we can prove that `v1 >= v2`.
bool isDefinitelyGreaterThanOrEqualTo(SignedVariable v1, SignedVariable v2) {
return testConstraint(v2, v1.negated, 0);
@@ -466,10 +477,58 @@ class BoundsChecker extends TrampolineRecursiveVisitor implements Pass {
}
@override
+ void visitRefinement(Refinement node) {
+ // In general we should get the container length of the refined type and
+ // add a constraint if we know the length after the refinement.
+ // However, our current type system removes container information when a
+ // type becomes part of a union, so this cannot happen.
+ }
+
+ @override
void visitGetLength(GetLength node) {
valueOf[node] = getLength(node.object.definition, currentEffectNumber);
}
+ @override
+ void visitBoundsCheck(BoundsCheck node) {
+ if (node.checks == BoundsCheck.NONE) return;
+ assert(node.index != null); // Because there is at least one check.
+ Primitive object = node.object.definition;
+ SignedVariable length = node.length == null
+ ? null
+ : getValue(node.length.definition);
+ SignedVariable index = getValue(node.index.definition);
+ if (node.hasUpperBoundCheck) {
+ if (isDefinitelyLessThan(index, length)) {
+ node.checks &= ~BoundsCheck.UPPER_BOUND;
+ } else {
+ makeLessThan(index, length);
+ }
+ }
+ if (node.hasLowerBoundCheck) {
+ if (isDefinitelyGreaterThanOrEqualToConstant(index, 0)) {
+ node.checks &= ~BoundsCheck.LOWER_BOUND;
+ } else {
+ makeGreaterThanOrEqualToConstant(index, 0);
+ }
+ }
+ if (node.hasEmptinessCheck) {
+ if (isDefinitelyGreaterThanOrEqualToConstant(length, 1)) {
+ node.checks &= ~BoundsCheck.EMPTINESS;
+ } else {
+ makeGreaterThanOrEqualToConstant(length, 1);
+ }
+ }
+ if (!node.lengthUsedInCheck && node.length != null) {
+ node..length.unlink()..length = null;
+ }
+ if (node.checks == BoundsCheck.NONE) {
+ // We can't remove the bounds check node because it may still be used to
+ // restrict code motion. But the index is no longer needed.
+ node..index.unlink()..index = null;
+ }
+ }
+
void analyzeLoopEntry(InvokeContinuation node) {
foundLoop = true;
Continuation cont = node.continuation.definition;
« no previous file with comments | « no previous file | pkg/compiler/lib/src/cps_ir/cps_fragment.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698