Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(394)

Unified Diff: pkg/compiler/lib/src/tree_ir/optimization/pull_into_initializers.dart

Issue 1088493002: Assignment expressions in tree IR. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Comments Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/compiler/lib/src/tree_ir/optimization/pull_into_initializers.dart
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/pull_into_initializers.dart b/pkg/compiler/lib/src/tree_ir/optimization/pull_into_initializers.dart
new file mode 100644
index 0000000000000000000000000000000000000000..a45b9f244a1fd5c1e530c4006a4c405c7253066b
--- /dev/null
+++ b/pkg/compiler/lib/src/tree_ir/optimization/pull_into_initializers.dart
@@ -0,0 +1,317 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'optimization.dart' show Pass;
+import '../tree_ir_nodes.dart';
+
+/// Pulls assignment expressions to the top of the function body so they can be
+/// translated into declaration-site variable initializaters.
+///
+/// This reverts the assignment expression propagation performed by
+/// [StatementRewriter] in cases where it not beneficial.
+///
+/// EXAMPLE:
+///
+/// var x = foo(),
+/// y = bar(x);
+///
+/// ==> [StatementRewriter]
+///
+/// var x,
+/// y = bar(x = foo());
+///
+/// ==> [PullIntoInitializers] restores the initializer for x
+///
+/// var x = foo(),
+/// y = bar(x);
+///
+///
+/// Sometimes the assignment propagation will trigger another optimization
+/// in the [StatementRewriter] which then prevents [PullIntoInitializers] from
+/// restoring the initializer. This is acceptable, since most optimizations
+/// at that level are better than restoring an initializer.
+///
+/// EXAMPLE:
+///
+/// var x = foo(),
+/// y = bar();
+/// baz(x, y, y);
+///
+/// ==> [StatementRewriter]
+///
+/// var y;
+/// baz(foo(), y = bar(), y);
+///
+/// [PullIntoInitializers] cannot pull `y` into an initializer because
+/// the impure expressions `foo()` and `bar()` would then be swapped.
+///
+class PullIntoInitializers implements Pass {
+ String get passName => 'Pull into initializers';
+
+ void rewrite(RootNode node) {
+ node.replaceEachBody((Statement body) {
+ return new BodyRewriter().rewriteBody(node.parameters, body);
+ });
+ }
+}
+
+class BodyRewriter extends ExpressionVisitor<Expression> {
+ Set<Variable> assignedVariables = new Set<Variable>();
+
+ /// The fragment between [first] and [last] holds the statements
+ /// we pulled into the initializer block.
+ ///
+ /// The *initializer block* is a sequence of [ExpressionStatement]s with
+ /// [Assign]s that we create in the beginning of the body, with the intent
+ /// that code generation will convert them to variable initializers.
+ ///
+ /// The block is empty when both are `null`.
+ Statement first, last;
+
+ /// True if an impure expression has been returned by visitExpression.
+ ///
+ /// Expressions cannot be pulled into an initializer if this might reorder
+ /// impure expressions.
+ ///
+ /// A visit method may not be called while this flag is set, meaning all
+ /// visitor methods must check the flag between visiting subexpressions.
+ bool seenImpure;
+
+ /// Appends a statement to the initializer block.
+ void append(Statement node) {
+ if (first == null) {
+ first = last = node;
+ } else {
+ last.next = node;
+ last = node;
+ }
+ }
+
+ /// Pulls assignment expressions from [node] into the initializer block
+ /// by calling [append].
+ ///
+ /// Returns a transformed expression where the pulled assignments are
+ /// replaced by variable uses.
+ Expression rewriteExpression(Expression node) {
+ seenImpure = false;
+ return visitExpression(node);
+ }
+
+ Statement rewriteBody(List<Variable> parameters, Statement body) {
+ assignedVariables.addAll(parameters);
+
+ // [body] represents the first statement after the initializer block.
+ // Repeatedly pull assignment statements into the initializer block.
+ while (body is ExpressionStatement) {
+ ExpressionStatement stmt = body;
+ stmt.expression = rewriteExpression(stmt.expression);
+ if (stmt.expression is VariableUse) {
+ // The entire expression was pulled into an initializer.
+ // This can happen when the expression was an assignment that was
+ // pulled into the initializer block and replaced by a variable use.
+ // Discard the statement and try to pull in more initializers from
+ // the next statement.
+ destroyVariableUse(stmt.expression);
+ body = stmt.next;
+ } else {
+ // The whole expression could not be pulled into an initializer, so we
+ // have reached the end of the initializer block.
+ break;
+ }
+ }
+
+ // [If] and [Return] statements terminate the initializer block, but the
+ // initial expression they contain may be pulled up into an initializer.
+ // It's ok to pull an assignment across a label so look for the first
+ // non-labeled statement and try to pull its initial subexpression.
+ Statement entryNode = unfoldLabeledStatements(body);
+ if (entryNode is If) {
+ entryNode.condition = rewriteExpression(entryNode.condition);
+ } else if (entryNode is Return) {
+ entryNode.value = rewriteExpression(entryNode.value);
+ }
+
+ append(body);
+ assert(first != null); // Because we just appended the body.
+ return first;
+ }
+
+ void destroyVariableUse(VariableUse node) {
+ --node.variable.readCount;
+ }
+
+ Statement unfoldLabeledStatements(Statement node) {
+ while (node is LabeledStatement) {
+ node = (node as LabeledStatement).body;
+ }
+ return node;
+ }
+
+ Expression visitAssign(Assign node) {
+ assert(!seenImpure);
+ node.value = visitExpression(node.value);
+ if (!assignedVariables.add(node.variable)) {
+ // This is not the first assignment to the variable, so it cannot be
+ // pulled into an initializer.
+ // We have to leave the assignment here, and assignments are impure.
+ seenImpure = true;
+ return node;
+ } else {
+ // Pull the assignment into an initializer.
+ // We will leave behind a variable use, which is pure, so we can
+ // disregard any impure expressions seen in the right-hand side.
+ seenImpure = false;
+ append(new ExpressionStatement(node, null));
+ return new VariableUse(node.variable);
+ }
+ }
+
+ void rewriteList(List<Expression> list) {
+ for (int i = 0; i < list.length; i++) {
+ list[i] = visitExpression(list[i]);
+ if (seenImpure) return;
+ }
+ }
+
+ Expression visitInvokeStatic(InvokeStatic node) {
+ rewriteList(node.arguments);
+ seenImpure = true;
+ return node;
+ }
+
+ Expression visitInvokeMethod(InvokeMethod node) {
+ node.receiver = visitExpression(node.receiver);
+ if (seenImpure) return node;
+ rewriteList(node.arguments);
+ seenImpure = true;
+ return node;
+ }
+
+ Expression visitInvokeMethodDirectly(InvokeMethodDirectly node) {
+ node.receiver = visitExpression(node.receiver);
+ if (seenImpure) return node;
+ rewriteList(node.arguments);
+ seenImpure = true;
+ return node;
+ }
+
+ Expression visitInvokeConstructor(InvokeConstructor node) {
+ rewriteList(node.arguments);
+ seenImpure = true;
+ return node;
+ }
+
+ Expression visitConcatenateStrings(ConcatenateStrings node) {
+ rewriteList(node.arguments);
+ seenImpure = true;
+ return node;
+ }
+
+ Expression visitTypeExpression(TypeExpression node) {
+ rewriteList(node.arguments);
+ return node;
+ }
+
+ Expression visitConditional(Conditional node) {
+ node.condition = visitExpression(node.condition);
+ if (seenImpure) return node;
+ node.thenExpression = visitExpression(node.thenExpression);
+ if (seenImpure) return node;
+ node.elseExpression = visitExpression(node.elseExpression);
+ return node;
+ }
+
+ Expression visitLogicalOperator(LogicalOperator node) {
+ node.left = visitExpression(node.left);
+ if (seenImpure) return node;
+ node.right = visitExpression(node.right);
+ return node;
+ }
+
+ Expression visitLiteralList(LiteralList node) {
+ rewriteList(node.values);
+ if (node.type != null) seenImpure = true; // Type casts can throw.
+ return node;
+ }
+
+ Expression visitLiteralMap(LiteralMap node) {
+ for (LiteralMapEntry entry in node.entries) {
+ entry.key = visitExpression(entry.key);
+ if (seenImpure) return node;
+ entry.value = visitExpression(entry.value);
+ if (seenImpure) return node;
+ }
+ if (node.type != null) seenImpure = true; // Type casts can throw.
+ return node;
+ }
+
+ Expression visitTypeOperator(TypeOperator node) {
+ node.receiver = visitExpression(node.receiver);
+ if (!node.isTypeTest) seenImpure = true; // Type cast can throw.
+ return node;
+ }
+
+ void visitInnerFunction(FunctionDefinition node) {
+ node.body = new BodyRewriter().rewriteBody(node.parameters, node.body);
+ }
+
+ Expression visitFunctionExpression(FunctionExpression node) {
+ visitInnerFunction(node.definition);
+ return node;
+ }
+
+ Expression visitGetField(GetField node) {
+ node.object = visitExpression(node.object);
+ seenImpure = true;
+ return node;
+ }
+
+ Expression visitSetField(SetField node) {
+ node.object = visitExpression(node.object);
+ if (seenImpure) return node;
+ node.value = visitExpression(node.value);
+ seenImpure = true;
+ return node;
+ }
+
+ Expression visitCreateBox(CreateBox node) {
+ return node;
+ }
+
+ Expression visitCreateInstance(CreateInstance node) {
+ rewriteList(node.arguments);
+ return node;
+ }
+
+ Expression visitReifyRuntimeType(ReifyRuntimeType node) {
+ node.value = visitExpression(node.value);
+ return node;
+ }
+
+ Expression visitReadTypeVariable(ReadTypeVariable node) {
+ node.target = visitExpression(node.target);
+ return node;
+ }
+
+ Expression visitConstant(Constant node) {
+ return node;
+ }
+
+ Expression visitThis(This node) {
+ return node;
+ }
+
+ Expression visitReifyTypeVar(ReifyTypeVar node) {
+ return node;
+ }
+
+ Expression visitNot(Not node) {
+ node.operand = visitExpression(node.operand);
+ return node;
+ }
+
+ Expression visitVariableUse(VariableUse node) {
+ return node;
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698