| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library tree_ir.optimization.pull_into_initializers; |
| 6 |
| 5 import 'optimization.dart' show Pass; | 7 import 'optimization.dart' show Pass; |
| 6 import '../tree_ir_nodes.dart'; | 8 import '../tree_ir_nodes.dart'; |
| 7 | 9 |
| 8 /// Pulls assignment expressions to the top of the function body so they can be | 10 /// Pulls assignment expressions to the top of the function body so they can be |
| 9 /// translated into declaration-site variable initializaters. | 11 /// translated into declaration-site variable initializaters. |
| 10 /// | 12 /// |
| 11 /// This reverts the assignment expression propagation performed by | 13 /// This reverts the assignment expression propagation performed by |
| 12 /// [StatementRewriter] in cases where it not beneficial. | 14 /// [StatementRewriter] in cases where it not beneficial. |
| 13 /// | 15 /// |
| 14 /// EXAMPLE: | 16 /// EXAMPLE: |
| (...skipping 24 matching lines...) Expand all Loading... |
| 39 /// baz(x, y, y); | 41 /// baz(x, y, y); |
| 40 /// | 42 /// |
| 41 /// ==> [StatementRewriter] | 43 /// ==> [StatementRewriter] |
| 42 /// | 44 /// |
| 43 /// var y; | 45 /// var y; |
| 44 /// baz(foo(), y = bar(), y); | 46 /// baz(foo(), y = bar(), y); |
| 45 /// | 47 /// |
| 46 /// [PullIntoInitializers] cannot pull `y` into an initializer because | 48 /// [PullIntoInitializers] cannot pull `y` into an initializer because |
| 47 /// the impure expressions `foo()` and `bar()` would then be swapped. | 49 /// the impure expressions `foo()` and `bar()` would then be swapped. |
| 48 /// | 50 /// |
| 49 class PullIntoInitializers implements Pass { | 51 class PullIntoInitializers extends ExpressionVisitor<Expression> |
| 52 implements Pass { |
| 50 String get passName => 'Pull into initializers'; | 53 String get passName => 'Pull into initializers'; |
| 51 | 54 |
| 52 void rewrite(RootNode node) { | |
| 53 node.replaceEachBody((Statement body) { | |
| 54 return new BodyRewriter().rewriteBody(node.parameters, body); | |
| 55 }); | |
| 56 } | |
| 57 } | |
| 58 | |
| 59 class BodyRewriter extends ExpressionVisitor<Expression> { | |
| 60 Set<Variable> assignedVariables = new Set<Variable>(); | 55 Set<Variable> assignedVariables = new Set<Variable>(); |
| 61 | 56 |
| 62 /// The fragment between [first] and [last] holds the statements | 57 /// The fragment between [first] and [last] holds the statements |
| 63 /// we pulled into the initializer block. | 58 /// we pulled into the initializer block. |
| 64 /// | 59 /// |
| 65 /// The *initializer block* is a sequence of [ExpressionStatement]s with | 60 /// The *initializer block* is a sequence of [ExpressionStatement]s with |
| 66 /// [Assign]s that we create in the beginning of the body, with the intent | 61 /// [Assign]s that we create in the beginning of the body, with the intent |
| 67 /// that code generation will convert them to variable initializers. | 62 /// that code generation will convert them to variable initializers. |
| 68 /// | 63 /// |
| 69 /// The block is empty when both are `null`. | 64 /// The block is empty when both are `null`. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 91 /// Pulls assignment expressions from [node] into the initializer block | 86 /// Pulls assignment expressions from [node] into the initializer block |
| 92 /// by calling [append]. | 87 /// by calling [append]. |
| 93 /// | 88 /// |
| 94 /// Returns a transformed expression where the pulled assignments are | 89 /// Returns a transformed expression where the pulled assignments are |
| 95 /// replaced by variable uses. | 90 /// replaced by variable uses. |
| 96 Expression rewriteExpression(Expression node) { | 91 Expression rewriteExpression(Expression node) { |
| 97 seenImpure = false; | 92 seenImpure = false; |
| 98 return visitExpression(node); | 93 return visitExpression(node); |
| 99 } | 94 } |
| 100 | 95 |
| 101 Statement rewriteBody(List<Variable> parameters, Statement body) { | 96 void rewrite(FunctionDefinition node) { |
| 102 assignedVariables.addAll(parameters); | 97 Statement body = node.body; |
| 98 assignedVariables.addAll(node.parameters); |
| 103 | 99 |
| 104 // [body] represents the first statement after the initializer block. | 100 // [body] represents the first statement after the initializer block. |
| 105 // Repeatedly pull assignment statements into the initializer block. | 101 // Repeatedly pull assignment statements into the initializer block. |
| 106 while (body is ExpressionStatement) { | 102 while (body is ExpressionStatement) { |
| 107 ExpressionStatement stmt = body; | 103 ExpressionStatement stmt = body; |
| 108 stmt.expression = rewriteExpression(stmt.expression); | 104 stmt.expression = rewriteExpression(stmt.expression); |
| 109 if (stmt.expression is VariableUse) { | 105 if (stmt.expression is VariableUse) { |
| 110 // The entire expression was pulled into an initializer. | 106 // The entire expression was pulled into an initializer. |
| 111 // This can happen when the expression was an assignment that was | 107 // This can happen when the expression was an assignment that was |
| 112 // pulled into the initializer block and replaced by a variable use. | 108 // pulled into the initializer block and replaced by a variable use. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 127 // non-labeled statement and try to pull its initial subexpression. | 123 // non-labeled statement and try to pull its initial subexpression. |
| 128 Statement entryNode = unfoldLabeledStatements(body); | 124 Statement entryNode = unfoldLabeledStatements(body); |
| 129 if (entryNode is If) { | 125 if (entryNode is If) { |
| 130 entryNode.condition = rewriteExpression(entryNode.condition); | 126 entryNode.condition = rewriteExpression(entryNode.condition); |
| 131 } else if (entryNode is Return) { | 127 } else if (entryNode is Return) { |
| 132 entryNode.value = rewriteExpression(entryNode.value); | 128 entryNode.value = rewriteExpression(entryNode.value); |
| 133 } | 129 } |
| 134 | 130 |
| 135 append(body); | 131 append(body); |
| 136 assert(first != null); // Because we just appended the body. | 132 assert(first != null); // Because we just appended the body. |
| 137 return first; | 133 |
| 134 node.body = first; |
| 138 } | 135 } |
| 139 | 136 |
| 140 void destroyVariableUse(VariableUse node) { | 137 void destroyVariableUse(VariableUse node) { |
| 141 --node.variable.readCount; | 138 --node.variable.readCount; |
| 142 } | 139 } |
| 143 | 140 |
| 144 Statement unfoldLabeledStatements(Statement node) { | 141 Statement unfoldLabeledStatements(Statement node) { |
| 145 while (node is LabeledStatement) { | 142 while (node is LabeledStatement) { |
| 146 node = (node as LabeledStatement).body; | 143 node = (node as LabeledStatement).body; |
| 147 } | 144 } |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 248 | 245 |
| 249 Expression visitTypeOperator(TypeOperator node) { | 246 Expression visitTypeOperator(TypeOperator node) { |
| 250 node.value = visitExpression(node.value); | 247 node.value = visitExpression(node.value); |
| 251 if (seenImpure) return node; | 248 if (seenImpure) return node; |
| 252 rewriteList(node.typeArguments); | 249 rewriteList(node.typeArguments); |
| 253 if (!node.isTypeTest) seenImpure = true; // Type cast can throw. | 250 if (!node.isTypeTest) seenImpure = true; // Type cast can throw. |
| 254 return node; | 251 return node; |
| 255 } | 252 } |
| 256 | 253 |
| 257 void visitInnerFunction(FunctionDefinition node) { | 254 void visitInnerFunction(FunctionDefinition node) { |
| 258 node.body = new BodyRewriter().rewriteBody(node.parameters, node.body); | 255 new PullIntoInitializers().rewrite(node); |
| 259 } | 256 } |
| 260 | 257 |
| 261 Expression visitFunctionExpression(FunctionExpression node) { | 258 Expression visitFunctionExpression(FunctionExpression node) { |
| 262 visitInnerFunction(node.definition); | 259 visitInnerFunction(node.definition); |
| 263 return node; | 260 return node; |
| 264 } | 261 } |
| 265 | 262 |
| 266 Expression visitGetField(GetField node) { | 263 Expression visitGetField(GetField node) { |
| 267 node.object = visitExpression(node.object); | 264 node.object = visitExpression(node.object); |
| 268 seenImpure = true; | 265 seenImpure = true; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 308 } | 305 } |
| 309 | 306 |
| 310 Expression visitConstant(Constant node) { | 307 Expression visitConstant(Constant node) { |
| 311 return node; | 308 return node; |
| 312 } | 309 } |
| 313 | 310 |
| 314 Expression visitThis(This node) { | 311 Expression visitThis(This node) { |
| 315 return node; | 312 return node; |
| 316 } | 313 } |
| 317 | 314 |
| 318 Expression visitReifyTypeVar(ReifyTypeVar node) { | |
| 319 return node; | |
| 320 } | |
| 321 | |
| 322 Expression visitNot(Not node) { | 315 Expression visitNot(Not node) { |
| 323 node.operand = visitExpression(node.operand); | 316 node.operand = visitExpression(node.operand); |
| 324 return node; | 317 return node; |
| 325 } | 318 } |
| 326 | 319 |
| 327 Expression visitVariableUse(VariableUse node) { | 320 Expression visitVariableUse(VariableUse node) { |
| 328 return node; | 321 return node; |
| 329 } | 322 } |
| 330 | 323 |
| 331 Expression visitCreateInvocationMirror(CreateInvocationMirror node) { | 324 Expression visitCreateInvocationMirror(CreateInvocationMirror node) { |
| 332 rewriteList(node.arguments); | 325 rewriteList(node.arguments); |
| 333 return node; | 326 return node; |
| 334 } | 327 } |
| 335 } | 328 } |
| OLD | NEW |