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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 import 'optimization.dart' show Pass;
6 import '../tree_ir_nodes.dart';
7
8 /// Pulls assignment expressions to the top of the function body so they can be
9 /// translated into declaration-site variable initializaters.
10 ///
11 /// This reverts the assignment expression propagation performed by
12 /// [StatementRewriter] in cases where it not beneficial.
13 ///
14 /// EXAMPLE:
15 ///
16 /// var x = foo(),
17 /// y = bar(x);
18 ///
19 /// ==> [StatementRewriter]
20 ///
21 /// var x,
22 /// y = bar(x = foo());
23 ///
24 /// ==> [PullIntoInitializers] restores the initializer for x
25 ///
26 /// var x = foo(),
27 /// y = bar(x);
28 ///
29 ///
30 /// Sometimes the assignment propagation will trigger another optimization
31 /// in the [StatementRewriter] which then prevents [PullIntoInitializers] from
32 /// restoring the initializer. This is acceptable, since most optimizations
33 /// at that level are better than restoring an initializer.
34 ///
35 /// EXAMPLE:
36 ///
37 /// var x = foo(),
38 /// y = bar();
39 /// baz(x, y, y);
40 ///
41 /// ==> [StatementRewriter]
42 ///
43 /// var y;
44 /// baz(foo(), y = bar(), y);
45 ///
46 /// [PullIntoInitializers] cannot pull `y` into an initializer because
47 /// the impure expressions `foo()` and `bar()` would then be swapped.
48 ///
49 class PullIntoInitializers implements Pass {
50 String get passName => 'Pull into initializers';
51
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>();
61
62 /// The fragment between [first] and [last] holds the statements
63 /// we pulled into the initializer block.
64 ///
65 /// 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
67 /// that code generation will convert them to variable initializers.
68 ///
69 /// The block is empty when both are `null`.
70 Statement first, last;
71
72 /// True if an impure expression has been returned by visitExpression.
73 ///
74 /// Expressions cannot be pulled into an initializer if this might reorder
75 /// impure expressions.
76 ///
77 /// A visit method may not be called while this flag is set, meaning all
78 /// visitor methods must check the flag between visiting subexpressions.
79 bool seenImpure;
80
81 /// Appends a statement to the initializer block.
82 void append(Statement node) {
83 if (first == null) {
84 first = last = node;
85 } else {
86 last.next = node;
87 last = node;
88 }
89 }
90
91 /// Pulls assignment expressions from [node] into the initializer block
92 /// by calling [append].
93 ///
94 /// Returns a transformed expression where the pulled assignments are
95 /// replaced by variable uses.
96 Expression rewriteExpression(Expression node) {
97 seenImpure = false;
98 return visitExpression(node);
99 }
100
101 Statement rewriteBody(List<Variable> parameters, Statement body) {
102 assignedVariables.addAll(parameters);
103
104 // [body] represents the first statement after the initializer block.
105 // Repeatedly pull assignment statements into the initializer block.
106 while (body is ExpressionStatement) {
107 ExpressionStatement stmt = body;
108 stmt.expression = rewriteExpression(stmt.expression);
109 if (stmt.expression is VariableUse) {
110 // The entire expression was pulled into an initializer.
111 // This can happen when the expression was an assignment that was
112 // pulled into the initializer block and replaced by a variable use.
113 // Discard the statement and try to pull in more initializers from
114 // the next statement.
115 destroyVariableUse(stmt.expression);
116 body = stmt.next;
117 } else {
118 // The whole expression could not be pulled into an initializer, so we
119 // have reached the end of the initializer block.
120 break;
121 }
122 }
123
124 // [If] and [Return] statements terminate the initializer block, but the
125 // initial expression they contain may be pulled up into an initializer.
126 // It's ok to pull an assignment across a label so look for the first
127 // non-labeled statement and try to pull its initial subexpression.
128 Statement entryNode = unfoldLabeledStatements(body);
129 if (entryNode is If) {
130 entryNode.condition = rewriteExpression(entryNode.condition);
131 } else if (entryNode is Return) {
132 entryNode.value = rewriteExpression(entryNode.value);
133 }
134
135 append(body);
136 assert(first != null); // Because we just appended the body.
137 return first;
138 }
139
140 void destroyVariableUse(VariableUse node) {
141 --node.variable.readCount;
142 }
143
144 Statement unfoldLabeledStatements(Statement node) {
145 while (node is LabeledStatement) {
146 node = (node as LabeledStatement).body;
147 }
148 return node;
149 }
150
151 Expression visitAssign(Assign node) {
152 assert(!seenImpure);
153 node.value = visitExpression(node.value);
154 if (!assignedVariables.add(node.variable)) {
155 // This is not the first assignment to the variable, so it cannot be
156 // pulled into an initializer.
157 // We have to leave the assignment here, and assignments are impure.
158 seenImpure = true;
159 return node;
160 } else {
161 // Pull the assignment into an initializer.
162 // We will leave behind a variable use, which is pure, so we can
163 // disregard any impure expressions seen in the right-hand side.
164 seenImpure = false;
165 append(new ExpressionStatement(node, null));
166 return new VariableUse(node.variable);
167 }
168 }
169
170 void rewriteList(List<Expression> list) {
171 for (int i = 0; i < list.length; i++) {
172 list[i] = visitExpression(list[i]);
173 if (seenImpure) return;
174 }
175 }
176
177 Expression visitInvokeStatic(InvokeStatic node) {
178 rewriteList(node.arguments);
179 seenImpure = true;
180 return node;
181 }
182
183 Expression visitInvokeMethod(InvokeMethod node) {
184 node.receiver = visitExpression(node.receiver);
185 if (seenImpure) return node;
186 rewriteList(node.arguments);
187 seenImpure = true;
188 return node;
189 }
190
191 Expression visitInvokeMethodDirectly(InvokeMethodDirectly node) {
192 node.receiver = visitExpression(node.receiver);
193 if (seenImpure) return node;
194 rewriteList(node.arguments);
195 seenImpure = true;
196 return node;
197 }
198
199 Expression visitInvokeConstructor(InvokeConstructor node) {
200 rewriteList(node.arguments);
201 seenImpure = true;
202 return node;
203 }
204
205 Expression visitConcatenateStrings(ConcatenateStrings node) {
206 rewriteList(node.arguments);
207 seenImpure = true;
208 return node;
209 }
210
211 Expression visitTypeExpression(TypeExpression node) {
212 rewriteList(node.arguments);
213 return node;
214 }
215
216 Expression visitConditional(Conditional node) {
217 node.condition = visitExpression(node.condition);
218 if (seenImpure) return node;
219 node.thenExpression = visitExpression(node.thenExpression);
220 if (seenImpure) return node;
221 node.elseExpression = visitExpression(node.elseExpression);
222 return node;
223 }
224
225 Expression visitLogicalOperator(LogicalOperator node) {
226 node.left = visitExpression(node.left);
227 if (seenImpure) return node;
228 node.right = visitExpression(node.right);
229 return node;
230 }
231
232 Expression visitLiteralList(LiteralList node) {
233 rewriteList(node.values);
234 if (node.type != null) seenImpure = true; // Type casts can throw.
235 return node;
236 }
237
238 Expression visitLiteralMap(LiteralMap node) {
239 for (LiteralMapEntry entry in node.entries) {
240 entry.key = visitExpression(entry.key);
241 if (seenImpure) return node;
242 entry.value = visitExpression(entry.value);
243 if (seenImpure) return node;
244 }
245 if (node.type != null) seenImpure = true; // Type casts can throw.
246 return node;
247 }
248
249 Expression visitTypeOperator(TypeOperator node) {
250 node.receiver = visitExpression(node.receiver);
251 if (!node.isTypeTest) seenImpure = true; // Type cast can throw.
252 return node;
253 }
254
255 void visitInnerFunction(FunctionDefinition node) {
256 node.body = new BodyRewriter().rewriteBody(node.parameters, node.body);
257 }
258
259 Expression visitFunctionExpression(FunctionExpression node) {
260 visitInnerFunction(node.definition);
261 return node;
262 }
263
264 Expression visitGetField(GetField node) {
265 node.object = visitExpression(node.object);
266 seenImpure = true;
267 return node;
268 }
269
270 Expression visitSetField(SetField node) {
271 node.object = visitExpression(node.object);
272 if (seenImpure) return node;
273 node.value = visitExpression(node.value);
274 seenImpure = true;
275 return node;
276 }
277
278 Expression visitCreateBox(CreateBox node) {
279 return node;
280 }
281
282 Expression visitCreateInstance(CreateInstance node) {
283 rewriteList(node.arguments);
284 return node;
285 }
286
287 Expression visitReifyRuntimeType(ReifyRuntimeType node) {
288 node.value = visitExpression(node.value);
289 return node;
290 }
291
292 Expression visitReadTypeVariable(ReadTypeVariable node) {
293 node.target = visitExpression(node.target);
294 return node;
295 }
296
297 Expression visitConstant(Constant node) {
298 return node;
299 }
300
301 Expression visitThis(This node) {
302 return node;
303 }
304
305 Expression visitReifyTypeVar(ReifyTypeVar node) {
306 return node;
307 }
308
309 Expression visitNot(Not node) {
310 node.operand = visitExpression(node.operand);
311 return node;
312 }
313
314 Expression visitVariableUse(VariableUse node) {
315 return node;
316 }
317 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698