OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 | 4 |
5 library dart2js.cps_ir.bounds_checker; | 5 library dart2js.cps_ir.bounds_checker; |
6 | 6 |
7 import 'cps_ir_nodes.dart'; | 7 import 'cps_ir_nodes.dart'; |
8 import 'optimizers.dart' show Pass; | 8 import 'optimizers.dart' show Pass; |
9 import 'octagon.dart'; | 9 import 'octagon.dart'; |
10 import '../constants/values.dart'; | 10 import '../constants/values.dart'; |
11 import 'cps_fragment.dart'; | 11 import 'cps_fragment.dart'; |
12 import 'type_mask_system.dart'; | 12 import 'type_mask_system.dart'; |
13 import '../world.dart'; | 13 import '../world.dart'; |
14 import '../elements/elements.dart'; | 14 import '../elements/elements.dart'; |
| 15 import 'loop_effects.dart'; |
| 16 |
| 17 |
15 | 18 |
16 /// Eliminates bounds checks when they can be proven safe. | 19 /// Eliminates bounds checks when they can be proven safe. |
17 /// | 20 /// |
18 /// In general, this pass will try to eliminate any branch with arithmetic | 21 /// In general, this pass will try to eliminate any branch with arithmetic |
19 /// in the condition, i.e. `x < y`, `x <= y`, `x == y` etc. | 22 /// in the condition, i.e. `x < y`, `x <= y`, `x == y` etc. |
20 /// | 23 /// |
21 /// The analysis uses an [Octagon] abstract domain. Unlike traditional octagon | 24 /// The analysis uses an [Octagon] abstract domain. Unlike traditional octagon |
22 /// analyzers, we do not use a closed matrix representation, but just maintain | 25 /// analyzers, we do not use a closed matrix representation, but just maintain |
23 /// a bucket of constraints. Constraints can therefore be added and removed | 26 /// a bucket of constraints. Constraints can therefore be added and removed |
24 /// on-the-fly without significant overhead. | 27 /// on-the-fly without significant overhead. |
25 /// | 28 /// |
26 /// We never copy the constraint system. While traversing the IR, the | 29 /// We never copy the constraint system. While traversing the IR, the |
27 /// constraint system is mutated to take into account the knowledge that is | 30 /// constraint system is mutated to take into account the knowledge that is |
28 /// valid for the current location. Constraints are added when entering a | 31 /// valid for the current location. Constraints are added when entering a |
29 /// branch, for instance, and removed again after the branch has been processed. | 32 /// branch, for instance, and removed again after the branch has been processed. |
30 /// | 33 /// |
31 /// Loops are analyzed in two passes. The first pass establishes monotonicity | 34 /// Loops are analyzed in two passes. The first pass establishes monotonicity |
32 /// of loop variables, which the second pass uses to compute upper/lower bounds. | 35 /// of loop variables, which the second pass uses to compute upper/lower bounds. |
33 /// The first pass also records whether any side effects occurred in the loop. | |
34 /// | 36 /// |
35 /// The two-pass scheme is suboptimal compared to a least fixed-point | 37 /// The two-pass scheme is suboptimal compared to a least fixed-point |
36 /// computation, but does not require repeated iteration. Repeated iteration | 38 /// computation, but does not require repeated iteration. Repeated iteration |
37 /// would be expensive, since we cannot perform a sparse analysis with our | 39 /// would be expensive, since we cannot perform a sparse analysis with our |
38 /// mutable octagon representation. | 40 /// mutable octagon representation. |
39 class BoundsChecker extends TrampolineRecursiveVisitor implements Pass { | 41 class BoundsChecker extends TrampolineRecursiveVisitor implements Pass { |
40 String get passName => 'Bounds checker'; | 42 String get passName => 'Bounds checker'; |
41 | 43 |
42 static const int MAX_UINT32 = (1 << 32) - 1; | 44 static const int MAX_UINT32 = (1 << 32) - 1; |
43 | 45 |
44 /// All integers of this magnitude or less are representable as JS numbers. | 46 /// All integers of this magnitude or less are representable as JS numbers. |
45 static const int MAX_SAFE_INT = (1 << 53) - 1; | 47 static const int MAX_SAFE_INT = (1 << 53) - 1; |
46 | 48 |
47 /// Marker to indicate that a continuation should get a unique effect number. | 49 /// Marker to indicate that a continuation should get a unique effect number. |
48 static const int NEW_EFFECT = -1; | 50 static const int NEW_EFFECT = -1; |
49 | 51 |
50 final TypeMaskSystem types; | 52 final TypeMaskSystem types; |
51 final World world; | 53 final World world; |
52 | 54 |
53 /// Fields for the constraint system and its variables. | 55 /// Fields for the constraint system and its variables. |
54 final Octagon octagon = new Octagon(); | 56 final Octagon octagon = new Octagon(); |
55 final Map<Primitive, SignedVariable> valueOf = {}; | 57 final Map<Primitive, SignedVariable> valueOf = {}; |
56 final Map<Primitive, Map<int, SignedVariable>> lengthOf = {}; | 58 final Map<Primitive, Map<int, SignedVariable>> lengthOf = {}; |
57 | 59 |
58 /// Fields for the two-pass handling of loops. | 60 /// Fields for the two-pass handling of loops. |
59 final Set<Continuation> loopsWithSideEffects = new Set<Continuation>(); | |
60 final Map<Parameter, Monotonicity> monotonicity = <Parameter, Monotonicity>{}; | 61 final Map<Parameter, Monotonicity> monotonicity = <Parameter, Monotonicity>{}; |
61 bool isStrongLoopPass; | 62 bool isStrongLoopPass; |
62 bool foundLoop = false; | 63 bool foundLoop = false; |
63 | 64 |
64 /// Fields for tracking side effects. | 65 /// Fields for tracking side effects. |
65 /// | 66 /// |
66 /// The IR is divided into regions wherein the lengths of indexable objects | 67 /// The IR is divided into regions wherein the lengths of indexable objects |
67 /// are known not to change. Regions are identified by their "effect number". | 68 /// are known not to change. Regions are identified by their "effect number". |
| 69 LoopSideEffects loopEffects; |
68 final Map<Continuation, int> effectNumberAt = <Continuation, int>{}; | 70 final Map<Continuation, int> effectNumberAt = <Continuation, int>{}; |
69 int currentEffectNumber = 0; | 71 int currentEffectNumber = 0; |
70 int effectNumberCounter = 0; | 72 int effectNumberCounter = 0; |
71 | 73 |
72 BoundsChecker(this.types, this.world); | 74 BoundsChecker(this.types, this.world); |
73 | 75 |
74 void rewrite(FunctionDefinition node) { | 76 void rewrite(FunctionDefinition node) { |
| 77 loopEffects = new LoopSideEffects(node, world); |
75 isStrongLoopPass = false; | 78 isStrongLoopPass = false; |
76 visit(node); | 79 visit(node); |
77 if (foundLoop) { | 80 if (foundLoop) { |
78 isStrongLoopPass = true; | 81 isStrongLoopPass = true; |
79 effectNumberAt.clear(); | 82 effectNumberAt.clear(); |
80 visit(node); | 83 visit(node); |
81 } | 84 } |
82 } | 85 } |
83 | 86 |
84 // ------------- VARIABLES ----------------- | 87 // ------------- VARIABLES ----------------- |
(...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
395 Monotonicity mono = monotonicity[param]; | 398 Monotonicity mono = monotonicity[param]; |
396 if (mono == null) { | 399 if (mono == null) { |
397 // Value never changes. This is extremely uncommon. | 400 // Value never changes. This is extremely uncommon. |
398 initialValue.substituteFor(param); | 401 initialValue.substituteFor(param); |
399 } else if (mono == Monotonicity.Increasing) { | 402 } else if (mono == Monotonicity.Increasing) { |
400 makeGreaterThanOrEqual(getValue(param), initialVariable); | 403 makeGreaterThanOrEqual(getValue(param), initialVariable); |
401 } else if (mono == Monotonicity.Decreasing) { | 404 } else if (mono == Monotonicity.Decreasing) { |
402 makeLessThanOrEqual(getValue(param), initialVariable); | 405 makeLessThanOrEqual(getValue(param), initialVariable); |
403 } | 406 } |
404 } | 407 } |
405 if (loopsWithSideEffects.contains(cont)) { | 408 } |
406 currentEffectNumber = makeNewEffect(); | 409 if (loopEffects.loopChangesLength(cont)) { |
407 } | |
408 } else { | |
409 // During the weak pass, conservatively make a new effect number in the | |
410 // loop body. This may be strengthened during the strong pass. | |
411 currentEffectNumber = effectNumberAt[cont] = makeNewEffect(); | 410 currentEffectNumber = effectNumberAt[cont] = makeNewEffect(); |
412 } | 411 } |
413 push(cont); | 412 push(cont); |
414 } | 413 } |
415 | 414 |
416 void analyzeLoopContinue(InvokeContinuation node) { | 415 void analyzeLoopContinue(InvokeContinuation node) { |
417 Continuation cont = node.continuation.definition; | 416 Continuation cont = node.continuation.definition; |
418 | 417 |
419 // During the strong loop phase, there is no need to compute monotonicity, | 418 // During the strong loop phase, there is no need to compute monotonicity, |
420 // and we already put bounds on the loop variables when we went into the | 419 // and we already put bounds on the loop variables when we went into the |
(...skipping 12 matching lines...) Expand all Loading... |
433 // We couldn't prove that the value does not increase, so assume | 432 // We couldn't prove that the value does not increase, so assume |
434 // henceforth that it might be increasing. | 433 // henceforth that it might be increasing. |
435 markMonotonicity(cont.parameters[i], Monotonicity.Increasing); | 434 markMonotonicity(cont.parameters[i], Monotonicity.Increasing); |
436 } | 435 } |
437 if (!isDefinitelyGreaterThanOrEqualTo(arg, paramVar)) { | 436 if (!isDefinitelyGreaterThanOrEqualTo(arg, paramVar)) { |
438 // We couldn't prove that the value does not decrease, so assume | 437 // We couldn't prove that the value does not decrease, so assume |
439 // henceforth that it might be decreasing. | 438 // henceforth that it might be decreasing. |
440 markMonotonicity(cont.parameters[i], Monotonicity.Decreasing); | 439 markMonotonicity(cont.parameters[i], Monotonicity.Decreasing); |
441 } | 440 } |
442 } | 441 } |
443 | |
444 // If a side effect has occurred between the entry and continue, mark | |
445 // the loop as having side effects. | |
446 if (currentEffectNumber != effectNumberAt[cont]) { | |
447 loopsWithSideEffects.add(cont); | |
448 } | |
449 } | 442 } |
450 | 443 |
451 void markMonotonicity(Parameter param, Monotonicity mono) { | 444 void markMonotonicity(Parameter param, Monotonicity mono) { |
452 Monotonicity current = monotonicity[param]; | 445 Monotonicity current = monotonicity[param]; |
453 if (current == null) { | 446 if (current == null) { |
454 monotonicity[param] = mono; | 447 monotonicity[param] = mono; |
455 } else if (current != mono) { | 448 } else if (current != mono) { |
456 monotonicity[param] = Monotonicity.NotMonotone; | 449 monotonicity[param] = Monotonicity.NotMonotone; |
457 } | 450 } |
458 } | 451 } |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
607 } | 600 } |
608 return node.body; | 601 return node.body; |
609 } | 602 } |
610 } | 603 } |
611 | 604 |
612 /// Lattice representing the known (weak) monotonicity of a loop variable. | 605 /// Lattice representing the known (weak) monotonicity of a loop variable. |
613 /// | 606 /// |
614 /// The lattice bottom is represented by `null` and represents the case where | 607 /// The lattice bottom is represented by `null` and represents the case where |
615 /// the loop variable never changes value during the loop. | 608 /// the loop variable never changes value during the loop. |
616 enum Monotonicity { NotMonotone, Increasing, Decreasing, } | 609 enum Monotonicity { NotMonotone, Increasing, Decreasing, } |
OLD | NEW |