Index: pkg/compiler/lib/src/cps_ir/type_propagation.dart |
diff --git a/pkg/compiler/lib/src/cps_ir/type_propagation.dart b/pkg/compiler/lib/src/cps_ir/type_propagation.dart |
index b090dec0a778c4934b1a6e071fead1c1f8f452ec..76eb580ead3f628f192064200b387874bd64d39d 100644 |
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart |
+++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart |
@@ -1150,7 +1150,13 @@ class TransformingVisitor extends LeafVisitor { |
} |
if (!isExtendable) return false; |
Primitive addedList = getDartArgument(node, 0); |
- if (addedList is! LiteralList) return false; |
+ // Rewrite addAll([x1, ..., xN]) to push(x1, ..., xN). |
+ // Ensure that the list is not mutated between creation and use. |
+ // We aim for the common case where this is the only use of the list, |
+ // which also guarantees that this list is not mutated before use. |
+ if (addedList is! LiteralList || !addedList.hasExactlyOneUse) { |
+ return false; |
+ } |
LiteralList addedLiteral = addedList; |
CpsFragment cps = new CpsFragment(sourceInfo); |
cps.invokeBuiltin(BuiltinMethod.Push, |
@@ -1720,7 +1726,7 @@ class TransformingVisitor extends LeafVisitor { |
} |
} |
- Primitive visitApplyBuiltinMethod(ApplyBuiltinMethod node) { |
+ void visitApplyBuiltinMethod(ApplyBuiltinMethod node) { |
if (node.method == BuiltinMethod.Push) { |
// Convert consecutive pushes into a single push. |
InteriorNode parent = getEffectiveParent(node.parent); |
@@ -1728,17 +1734,22 @@ class TransformingVisitor extends LeafVisitor { |
ApplyBuiltinMethod previous = parent.primitive; |
if (previous.method == BuiltinMethod.Push && |
previous.receiver.definition == node.receiver.definition) { |
- for (Reference ref in node.arguments) { |
- previous.arguments.add(ref); |
- ref.parent = previous; |
+ // We found two consecutive pushes. |
+ // Move all arguments from the first push onto the second one. |
+ List<Reference<Primitive>> arguments = previous.arguments; |
+ for (Reference ref in arguments) { |
+ ref.parent = node; |
} |
- node.arguments.clear(); // Avoid unlinking adopted references. |
- // Replace the old push by a dummy that will get removed. |
- return makeConstantPrimitive(new NullConstantValue()); |
+ arguments.addAll(node.arguments); |
+ node.arguments = arguments; |
+ // Elimnate the old push. |
+ previous.receiver.unlink(); |
+ assert(previous.hasNoUses); |
+ parent.parent.body = parent.body; |
+ parent.body.parent = parent.parent; |
} |
} |
} |
- return null; |
} |
Primitive visitTypeTest(TypeTest node) { |