| 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..cb0318362417e0d38d9acea196e443eadf794362 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 of that elsewhere so
|
| + // 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);
|
|
|