Chromium Code Reviews| 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 eeb12c5e0ad154d4b5c420457318d9b917424894..4c0454e41ddd1163cbfcd657ee190ea09cae4036 100644 |
| --- a/pkg/compiler/lib/src/ssa/optimize.dart |
| +++ b/pkg/compiler/lib/src/ssa/optimize.dart |
| @@ -1961,17 +1961,57 @@ class SsaLoadElimination extends HBaseVisitor implements OptimizationPhase { |
| void visitForeignNew(HForeignNew instruction) { |
| memorySet.registerAllocation(instruction); |
| - int argumentIndex = 0; |
| - instruction.element.forEachInstanceField((_, Element member) { |
| - if (compiler.elementHasCompileTimeError(member)) return; |
| - memorySet.registerFieldValue( |
| - member, instruction, instruction.inputs[argumentIndex++]); |
| - }, includeSuperAndInjectedMembers: true); |
| + if (shouldTrackInitialValues(instruction)) { |
| + int argumentIndex = 0; |
| + instruction.element.forEachInstanceField((_, Element member) { |
| + if (compiler.elementHasCompileTimeError(member)) return; |
| + memorySet.registerFieldValue( |
| + member, instruction, instruction.inputs[argumentIndex++]); |
| + }, includeSuperAndInjectedMembers: true); |
| + } |
| // In case this instruction has as input non-escaping objects, we |
| // need to mark these objects as escaping. |
| memorySet.killAffectedBy(instruction); |
| } |
| + bool shouldTrackInitialValues(HForeignNew instruction) { |
| + // Don't track initial field values of an allocation that are |
| + // unprofitable. We search the chain of single uses in allocations for a |
| + // limited depth. |
| + |
| + const MAX_HEAP_DEPTH = 5; |
| + |
| + bool interestingUse(HInstruction instruction, int heapDepth) { |
| + // Heuristic: if the allocation is too deep in heap it is unlikely we will |
| + // recover a field by load-elimination. |
| + // TODO(sra): We can measure this depth by looking at load chains. |
| + if (heapDepth == MAX_HEAP_DEPTH) return false; |
| + // There are multiple uses so do the full store analysis. |
| + if (instruction.usedBy.length != 1) return true; |
| + HInstruction use = instruction.usedBy.single; |
| + // When the only use is an allocation, the allocation becomes the only |
| + // heap alias for the current instruction. |
| + if (use is HForeignNew) return interestingUse(use, heapDepth + 1); |
| + if (use is HLiteralList) return interestingUse(use, heapDepth + 1); |
| + if (use is HInvokeStatic) { |
| + // Assume the argument escapes. All we do with our initial allocation is |
| + // have it escape or store it into an object that escapes. |
| + return false; |
| + // TODO(sra): Handle more functions. `setRuntimeTypeInfo` does not |
| + // actually kill it's input, but we don't make use that elsewhere so |
|
floitsch
2015/09/14 16:08:19
of that
sra1
2015/09/14 23:09:45
Done.
|
| + // there is not point in checking here. |
| + } |
| + if (use is HPhi) { |
| + // The initial allocation (it's only alias) gets merged out of the model |
| + // of the heap before load. |
| + return false; |
| + } |
| + return true; |
| + } |
| + |
| + return interestingUse(instruction, 0); |
| + } |
| + |
| void visitInstruction(HInstruction instruction) { |
| if (instruction.isAllocation) { |
| memorySet.registerAllocation(instruction); |