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

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: 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 {
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.
Kevin Millikin (Google) 2015/04/14 08:41:00 Here and below 'initializer block' is non-standard
asgerf 2015/04/14 10:12:14 Done.
64 ///
65 /// It is empty when both are `null`.
66 Statement first, last;
67
68 /// Appends a statement to the initializer block.
69 void append(Statement node) {
70 if (first == null) {
71 first = last = node;
72 } else {
73 last.next = node;
74 last = node;
75 }
76 }
77
78 /// Pulls assignment expressions from [node] into the initializer block
79 /// by calling [append].
80 ///
81 /// Returns a transformed expression where the pulled assignments are
82 /// replaced by variable uses.
83 Expression rewriteExpression(Expression node) {
84 return new ExpressionToInitializerVisitor(this).visitExpression(node);
85 }
86
87 Statement rewriteBody(List<Variable> parameters, Statement node) {
88 assignedVariables.addAll(parameters);
89
90 // [node] represents the first statement after the initializer block.
91 // Repeatedly pull assignment statements into the initializer block.
92 while (node is ExpressionStatement) {
93 ExpressionStatement stmt = node;
94 stmt.expression = rewriteExpression(stmt.expression);
95 if (stmt.expression is VariableUse) {
96 // The entire expression was pulled into an initializer.
97 // This can happen when the expression was an assignment that was
98 // pulled into the initializer block and replaced by a variable use.
99 // Discard the statement and try to pull in more initializers from
100 // the next statement.
101 destroyVariableUse(stmt.expression);
102 node = stmt.next;
Kevin Millikin (Google) 2015/04/14 08:41:00 It's a bit clearer to introduce a Statement 'curre
asgerf 2015/04/14 10:12:14 I don't like stale variables that you are likely t
103 } else {
104 // The whole expression could not be pulled into an initializer, so we
105 // have reached the end of the initializer block.
106 break;
107 }
108 }
109
110 // [If] and [Return] statements terminate the initializer block, but the
111 // initial expression they contain may be pulled up into an initializer.
112 // It's ok to pull an assignment across a label so look for the first
113 // non-labeled statement and try to pull its initial subexpression.
114 Statement entryNode = unfoldLabeledStatements(node);
115 if (entryNode is If) {
116 entryNode.condition = rewriteExpression(entryNode.condition);
117 } else if (entryNode is Return) {
118 entryNode.value = rewriteExpression(entryNode.value);
119 }
120
121 // Join the initializer block with the rest of the body.
122 append(node);
Kevin Millikin (Google) 2015/04/14 08:41:00 The code is backwards from the comment, so I'd mak
asgerf 2015/04/14 10:12:14 Removed the comment. Even less necessary after the
123
124 assert(first != null); // Because we just appended node.
125 return first;
126 }
127
128 void destroyVariableUse(VariableUse node) {
129 --node.variable.readCount;
130 }
131
132 Statement unfoldLabeledStatements(Statement node) {
133 while (node is LabeledStatement) {
134 node = (node as LabeledStatement).body;
135 }
136 return node;
137 }
138 }
139
140
141 class ExpressionToInitializerVisitor extends ExpressionVisitor<Expression> {
Kevin Millikin (Google) 2015/04/14 08:41:00 On the one hand, this class only has one bit of st
asgerf 2015/04/14 10:12:14 I don't think it's simpler, but either way is fine
142 BodyRewriter parent;
143
144 /// True if an impure expression has been returned by visitExpression.
145 ///
146 /// Expressions cannot be pulled into an initializer if this might reorder
147 /// impure expressions.
148 ///
149 /// A visit method may not be called while this flag is set, meaning all
150 /// visitor methods must check the flag between visiting subexpressions.
151 bool seenImpure = false;
152
153 ExpressionToInitializerVisitor(this.parent);
154
155 Expression visitAssign(Assign node) {
156 assert(!seenImpure);
157 node.value = visitExpression(node.value);
158 if (!parent.assignedVariables.add(node.variable)) {
159 // This is not the first assignment to the variable, so it cannot be
160 // pulled into an initializer.
161 // We have to leave the assignment here, and assignments are impure.
162 seenImpure = true;
163 return node;
164 } else {
165 // Pull the assignment into an initializer.
166 // We will leave behind a variable use, which is pure, so we can
167 // disregard any impure expressions seen in the right-side.
Kevin Millikin (Google) 2015/04/14 08:41:00 'right-hand side' or 'right side' (no hyphen).
asgerf 2015/04/14 10:12:14 Done.
168 seenImpure = false;
169 parent.append(new ExpressionStatement(node, null));
170 return new VariableUse(node.variable);
171 }
172 }
173
174 void rewriteList(List<Expression> list) {
175 for (int i = 0; i < list.length; i++) {
176 list[i] = visitExpression(list[i]);
177 if (seenImpure) return;
178 }
179 }
180
181 Expression visitInvokeStatic(InvokeStatic node) {
182 rewriteList(node.arguments);
183 seenImpure = true;
184 return node;
185 }
186
187 Expression visitInvokeMethod(InvokeMethod node) {
188 node.receiver = visitExpression(node.receiver);
189 if (seenImpure) return node;
190 rewriteList(node.arguments);
191 seenImpure = true;
192 return node;
193 }
194
195 Expression visitInvokeMethodDirectly(InvokeMethodDirectly node) {
196 node.receiver = visitExpression(node.receiver);
197 if (seenImpure) return node;
198 rewriteList(node.arguments);
199 seenImpure = true;
200 return node;
201 }
202
203 Expression visitInvokeConstructor(InvokeConstructor node) {
204 rewriteList(node.arguments);
205 seenImpure = true;
206 return node;
207 }
208
209 Expression visitConcatenateStrings(ConcatenateStrings node) {
210 rewriteList(node.arguments);
211 seenImpure = true;
212 return node;
213 }
214
215 Expression visitTypeExpression(TypeExpression node) {
216 rewriteList(node.arguments);
217 return node;
218 }
219
220 Expression visitConditional(Conditional node) {
221 node.condition = visitExpression(node.condition);
222 if (seenImpure) return node;
223 node.thenExpression = visitExpression(node.thenExpression);
224 if (seenImpure) return node;
225 node.elseExpression = visitExpression(node.elseExpression);
226 return node;
227 }
228
229 Expression visitLogicalOperator(LogicalOperator node) {
230 node.left = visitExpression(node.left);
231 if (seenImpure) return node;
232 node.right = visitExpression(node.right);
233 return node;
234 }
235
236 Expression visitLiteralList(LiteralList node) {
237 rewriteList(node.values);
238 if (node.type != null) seenImpure = true; // Type casts can throw.
239 return node;
240 }
241
242 Expression visitLiteralMap(LiteralMap node) {
243 for (LiteralMapEntry entry in node.entries) {
244 entry.key = visitExpression(entry.key);
245 if (seenImpure) return node;
246 entry.value = visitExpression(entry.value);
247 if (seenImpure) return node;
248 }
249 if (node.type != null) seenImpure = true; // Type casts can throw.
250 return node;
251 }
252
253 Expression visitTypeOperator(TypeOperator node) {
254 node.receiver = visitExpression(node.receiver);
255 if (!node.isTypeTest) seenImpure = true; // Type cast can throw.
256 return node;
257 }
258
259 void visitInnerFunction(FunctionDefinition node) {
260 node.body = new BodyRewriter().rewriteBody(node.parameters, node.body);
261 }
262
263 Expression visitFunctionExpression(FunctionExpression node) {
264 visitInnerFunction(node.definition);
265 return node;
266 }
267
268 Expression visitGetField(GetField node) {
269 node.object = visitExpression(node.object);
270 seenImpure = true;
271 return node;
272 }
273
274 Expression visitSetField(SetField node) {
275 node.object = visitExpression(node.object);
276 if (seenImpure) return node;
277 node.value = visitExpression(node.value);
278 seenImpure = true;
279 return node;
280 }
281
282 Expression visitCreateBox(CreateBox node) {
283 return node;
284 }
285
286 Expression visitCreateInstance(CreateInstance node) {
287 rewriteList(node.arguments);
288 return node;
289 }
290
291 Expression visitReifyRuntimeType(ReifyRuntimeType node) {
292 node.value = visitExpression(node.value);
293 return node;
294 }
295
296 Expression visitReadTypeVariable(ReadTypeVariable node) {
297 node.target = visitExpression(node.target);
298 return node;
299 }
300
301 Expression visitConstant(Constant node) {
302 return node;
303 }
304
305 Expression visitThis(This node) {
306 return node;
307 }
308
309 Expression visitReifyTypeVar(ReifyTypeVar node) {
310 return node;
311 }
312
313 Expression visitNot(Not node) {
314 node.operand = visitExpression(node.operand);
315 return node;
316 }
317
318 Expression visitVariableUse(VariableUse node) {
319 return node;
320 }
321 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698