| 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 |