| Index: pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
|
| diff --git a/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart b/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
|
| index 1c96301711577753d98346431fcc4e8fb7d3cc06..80ffa43c9cf5d24f8718e494abefa67be34142b9 100644
|
| --- a/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
|
| +++ b/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
|
| @@ -752,16 +752,26 @@ class StatementRewriter extends Transformer implements Pass {
|
| return node;
|
| }
|
|
|
| - bool sameVariable(Expression e1, Expression e2) {
|
| - return e1 is VariableUse && e2 is VariableUse && e1.variable == e2.variable;
|
| - }
|
| -
|
| bool isCompoundableBuiltin(Expression e) {
|
| return e is ApplyBuiltinOperator &&
|
| - e.arguments.length == 2 &&
|
| + e.arguments.length >= 2 &&
|
| isCompoundableOperator(e.operator);
|
| }
|
|
|
| + /// Converts a compoundable operator application into the right-hand side for
|
| + /// use in a compound assignment, discarding the left-hand value.
|
| + ///
|
| + /// For example, for `x + y + z` it returns `y + z`.
|
| + Expression contractCompoundableBuiltin(ApplyBuiltinOperator e) {
|
| + assert(isCompoundableBuiltin(e));
|
| + if (e.arguments.length > 2) {
|
| + assert(e.operator == BuiltinOperator.StringConcatenate);
|
| + return new ApplyBuiltinOperator(e.operator, e.arguments.skip(1).toList());
|
| + } else {
|
| + return e.arguments[1];
|
| + }
|
| + }
|
| +
|
| void destroyVariableUse(VariableUse node) {
|
| --node.variable.readCount;
|
| }
|
| @@ -772,13 +782,12 @@ class StatementRewriter extends Transformer implements Pass {
|
| if (isCompoundableBuiltin(node.value)) {
|
| ApplyBuiltinOperator rhs = node.value;
|
| Expression left = rhs.arguments[0];
|
| - Expression right = rhs.arguments[1];
|
| if (left is GetField &&
|
| left.field == node.field &&
|
| - sameVariable(left.object, node.object)) {
|
| - destroyVariableUse(left.object);
|
| + samePrimary(left.object, node.object)) {
|
| + destroyPrimaryExpression(left.object);
|
| node.compound = rhs.operator;
|
| - node.value = right;
|
| + node.value = contractCompoundableBuiltin(rhs);
|
| }
|
| }
|
| node.object = visitExpression(node.object);
|
| @@ -798,6 +807,16 @@ class StatementRewriter extends Transformer implements Pass {
|
| Expression visitSetStatic(SetStatic node) {
|
| allowRhsPropagation.add(true);
|
| node.value = visitExpression(node.value);
|
| + if (isCompoundableBuiltin(node.value)) {
|
| + ApplyBuiltinOperator rhs = node.value;
|
| + Expression left = rhs.arguments[0];
|
| + if (left is GetStatic &&
|
| + left.element == node.element &&
|
| + !left.useLazyGetter) {
|
| + node.compound = rhs.operator;
|
| + node.value = contractCompoundableBuiltin(rhs);
|
| + }
|
| + }
|
| allowRhsPropagation.removeLast();
|
| return node;
|
| }
|
| @@ -857,14 +876,13 @@ class StatementRewriter extends Transformer implements Pass {
|
| if (isCompoundableBuiltin(node.value)) {
|
| ApplyBuiltinOperator rhs = node.value;
|
| Expression left = rhs.arguments[0];
|
| - Expression right = rhs.arguments[1];
|
| if (left is GetIndex &&
|
| - sameVariable(left.object, node.object) &&
|
| - sameVariable(left.index, node.index)) {
|
| - destroyVariableUse(left.object);
|
| - destroyVariableUse(left.index);
|
| + samePrimary(left.object, node.object) &&
|
| + samePrimary(left.index, node.index)) {
|
| + destroyPrimaryExpression(left.object);
|
| + destroyPrimaryExpression(left.index);
|
| node.compound = rhs.operator;
|
| - node.value = right;
|
| + node.value = contractCompoundableBuiltin(rhs);
|
| }
|
| }
|
| node.index = visitExpression(node.index);
|
| @@ -1356,3 +1374,22 @@ class VariableUseVisitor extends RecursiveVisitor {
|
| new VariableUseVisitor(callback).visitExpression(node);
|
| }
|
| }
|
| +
|
| +bool sameVariable(Expression e1, Expression e2) {
|
| + return e1 is VariableUse && e2 is VariableUse && e1.variable == e2.variable;
|
| +}
|
| +
|
| +/// True if [e1] and [e2] are primary expressions (expressions without
|
| +/// subexpressions) with the same value.
|
| +bool samePrimary(Expression e1, Expression e2) {
|
| + return sameVariable(e1, e2) || (e1 is This && e2 is This);
|
| +}
|
| +
|
| +/// Decrement the reference count for [e] if it is a variable use.
|
| +void destroyPrimaryExpression(Expression e) {
|
| + if (e is VariableUse) {
|
| + --e.variable.readCount;
|
| + } else {
|
| + assert(e is This);
|
| + }
|
| +}
|
|
|