| Index: pkg/compiler/lib/src/ssa/optimize.dart
|
| diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
|
| index 9aa2d98dd339645993dc3367293532c7c205f48a..6ff4e783c2628f33e7a24e2fe26721b75945ba10 100644
|
| --- a/pkg/compiler/lib/src/ssa/optimize.dart
|
| +++ b/pkg/compiler/lib/src/ssa/optimize.dart
|
| @@ -2604,7 +2604,33 @@ class MemorySet {
|
| MemorySet intersectionFor(
|
| MemorySet other, HBasicBlock block, int predecessorIndex) {
|
| MemorySet result = new MemorySet(compiler);
|
| - if (other == null) return result;
|
| + if (other == null) {
|
| + // This is the first visit to a loop header ([other] is `null` because we
|
| + // have not visited the back edge). Copy the nonEscapingReceivers that are
|
| + // guaranteed to survive the loop because they are not escaped before
|
| + // method exit.
|
| + // TODO(sra): We should do a proper dataflow to find the maximal
|
| + // nonEscapingReceivers (a variant of Available-Expressions), which must
|
| + // converge before we edit the program in [findCommonInstruction].
|
| + for (HInstruction instruction in nonEscapingReceivers) {
|
| + bool isNonEscapingUse(HInstruction use) {
|
| + if (use is HReturn) return true; // Escapes, but so does control.
|
| + if (use is HFieldGet) return true;
|
| + if (use is HFieldSet &&
|
| + use.receiver.nonCheck() == instruction &&
|
| + use.value.nonCheck() != instruction) {
|
| + return true;
|
| + }
|
| + if (use is HTypeInfoReadVariable) return true;
|
| + return false;
|
| + }
|
| +
|
| + if (instruction.usedBy.every(isNonEscapingUse)) {
|
| + result.nonEscapingReceivers.add(instruction);
|
| + }
|
| + }
|
| + return result;
|
| + }
|
|
|
| fieldValues.forEach((element, values) {
|
| var otherValues = other.fieldValues[element];
|
|
|