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

Side by Side Diff: pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart

Issue 848363002: Allow LetCont to bind multiple continuations. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 11 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
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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 part of dart2js.cps_ir.optimizers; 5 part of dart2js.cps_ir.optimizers;
6 6
7 /** 7 /**
8 * [ShrinkingReducer] applies shrinking reductions to CPS terms as described 8 * [ShrinkingReducer] applies shrinking reductions to CPS terms as described
9 * in 'Compiling with Continuations, Continued' by Andrew Kennedy. 9 * in 'Compiling with Continuations, Continued' by Andrew Kennedy.
10 */ 10 */
(...skipping 28 matching lines...) Expand all
39 void _removeNode(InteriorNode node) { 39 void _removeNode(InteriorNode node) {
40 Node body = node.body; 40 Node body = node.body;
41 InteriorNode parent = node.parent; 41 InteriorNode parent = node.parent;
42 assert(parent.body == node); 42 assert(parent.body == node);
43 43
44 body.parent = parent; 44 body.parent = parent;
45 parent.body = body; 45 parent.body = body;
46 node.parent = _DELETED; 46 node.parent = _DELETED;
47 } 47 }
48 48
49 /// Remove a given continuation from the CPS graph. The LetCont itself is
50 /// removed if the given continuation is the only binding.
51 void _removeContinuation(Continuation cont) {
52 LetCont parent = cont.parent;
53 if (parent.continuations.length == 1) {
54 assert(cont.parent_index == 0);
55 _removeNode(parent);
56 } else {
57 List<Continuation> continuations = parent.continuations;
58 for (int i = cont.parent_index; i < continuations.length - 1; ++i) {
59 Continuation current = continuations[i + 1];
60 continuations[i] = current;
61 current.parent_index = i;
62 }
63 continuations.removeLast();
64 }
65 cont.parent = _DELETED;
66 }
67
49 void _processTask(_ReductionTask task) { 68 void _processTask(_ReductionTask task) {
50 // Lazily skip tasks for deleted nodes. 69 // Skip tasks for deleted nodes.
51 if (task.node.parent == _DELETED) { 70 if (task.node.parent == _DELETED) {
52 return; 71 return;
53 } 72 }
54 73
55 switch (task.kind) { 74 switch (task.kind) {
56 case _ReductionKind.DEAD_VAL: 75 case _ReductionKind.DEAD_VAL:
57 _reduceDeadVal(task); 76 _reduceDeadVal(task);
58 break; 77 break;
59 case _ReductionKind.DEAD_CONT: 78 case _ReductionKind.DEAD_CONT:
60 _reduceDeadCont(task); 79 _reduceDeadCont(task);
(...skipping 21 matching lines...) Expand all
82 // Perform bookkeeping on removed body and scan for new redexes. 101 // Perform bookkeeping on removed body and scan for new redexes.
83 new _RemovalRedexVisitor(_worklist).visit(letPrim.primitive); 102 new _RemovalRedexVisitor(_worklist).visit(letPrim.primitive);
84 } 103 }
85 104
86 /// Applies the dead-cont reduction: 105 /// Applies the dead-cont reduction:
87 /// letcont k x = E0 in E1 -> E1 (k not free in E1). 106 /// letcont k x = E0 in E1 -> E1 (k not free in E1).
88 void _reduceDeadCont(_ReductionTask task) { 107 void _reduceDeadCont(_ReductionTask task) {
89 assert(_isDeadCont(task.node)); 108 assert(_isDeadCont(task.node));
90 109
91 // Remove dead continuation. 110 // Remove dead continuation.
92 LetCont letCont = task.node; 111 Continuation cont = task.node;
93 _removeNode(letCont); 112 _removeContinuation(cont);
94 113
95 // Perform bookkeeping on removed body and scan for new redexes. 114 // Perform bookkeeping on removed body and scan for new redexes.
96 new _RemovalRedexVisitor(_worklist).visit(letCont.continuation); 115 new _RemovalRedexVisitor(_worklist).visit(cont);
97 } 116 }
98 117
99 /// Applies the beta-cont-lin reduction: 118 /// Applies the beta-cont-lin reduction:
100 /// letcont k x = E0 in E1[k y] -> E1[E0[y/x]] (k not free in E1). 119 /// letcont k x = E0 in E1[k y] -> E1[E0[y/x]] (k not free in E1).
101 void _reduceBetaContLin(_ReductionTask task) { 120 void _reduceBetaContLin(_ReductionTask task) {
102 // Might have been mutated, recheck if reduction is still valid. 121 // Might have been mutated, recheck if reduction is still valid.
103 // In the following example, the beta-cont-lin reduction of k0 could have 122 // In the following example, the beta-cont-lin reduction of k0 could have
104 // been invalidated by removal of the dead continuation k1: 123 // been invalidated by removal of the dead continuation k1:
105 // 124 //
106 // letcont k0 x0 = E0 in 125 // letcont k0 x0 = E0 in
107 // letcont k1 x1 = k0 x1 in 126 // letcont k1 x1 = k0 x1 in
108 // return x2 127 // return x2
109 if (!_isBetaContLin(task.node)) { 128 if (!_isBetaContLin(task.node)) {
110 return; 129 return;
111 } 130 }
112 131
113 // Remove the continuation. 132 // Remove the continuation.
114 LetCont letCont = task.node; 133 Continuation cont = task.node;
115 Continuation cont = letCont.continuation; 134 _removeContinuation(cont);
116 _removeNode(letCont);
117 135
118 // Replace its invocation with the continuation body. 136 // Replace its invocation with the continuation body.
119 InvokeContinuation invoke = cont.firstRef.parent; 137 InvokeContinuation invoke = cont.firstRef.parent;
120 InteriorNode invokeParent = invoke.parent; 138 InteriorNode invokeParent = invoke.parent;
121 139
122 cont.body.parent = invokeParent; 140 cont.body.parent = invokeParent;
123 invokeParent.body = cont.body; 141 invokeParent.body = cont.body;
124 142
125 // Substitute the invocation argument for the continuation parameter. 143 // Substitute the invocation argument for the continuation parameter.
126 for (int i = 0; i < invoke.arguments.length; i++) { 144 for (int i = 0; i < invoke.arguments.length; i++) {
127 Reference argRef = invoke.arguments[i]; 145 Reference argRef = invoke.arguments[i];
128 argRef.definition.substituteFor(cont.parameters[i]); 146 argRef.definition.substituteFor(cont.parameters[i]);
129 } 147 }
130 148
131 // Perform bookkeeping on removed body and scan for new redexes. 149 // Perform bookkeeping on substituted body and scan for new redexes.
132 new _RemovalRedexVisitor(_worklist).visit(invoke); 150 new _RemovalRedexVisitor(_worklist).visit(invoke);
133 } 151 }
134 152
135 /// Applies the eta-cont reduction: 153 /// Applies the eta-cont reduction:
136 /// letcont k x = j x in E -> E[j/k]. 154 /// letcont k x = j x in E -> E[j/k].
137 /// If k is unused, degenerates to dead-cont. 155 /// If k is unused, degenerates to dead-cont.
138 void _reduceEtaCont(_ReductionTask task) { 156 void _reduceEtaCont(_ReductionTask task) {
139 // Might have been mutated, recheck if reduction is still valid. 157 // Might have been mutated, recheck if reduction is still valid.
140 // In the following example, the eta-cont reduction of k1 could have been 158 // In the following example, the eta-cont reduction of k1 could have been
141 // invalidated by an earlier beta-cont-lin reduction of k0. 159 // invalidated by an earlier beta-cont-lin reduction of k0.
142 // 160 //
143 // letcont k0 x0 = E0 in 161 // letcont k0 x0 = E0 in
144 // letcont k1 x1 = k0 x1 in E1 162 // letcont k1 x1 = k0 x1 in E1
145 if (!_isEtaCont(task.node)) { 163 if (!_isEtaCont(task.node)) {
146 return; 164 return;
147 } 165 }
148 166
149 // Remove the continuation. 167 // Remove the continuation.
150 LetCont letCont = task.node; 168 Continuation cont = task.node;
151 Continuation cont = letCont.continuation; 169 _removeContinuation(cont);
152 _removeNode(letCont);
153 170
154 InvokeContinuation invoke = cont.body; 171 InvokeContinuation invoke = cont.body;
155 Continuation wrappedCont = invoke.continuation.definition; 172 Continuation wrappedCont = invoke.continuation.definition;
156 173
157 // Replace all occurrences with the wrapped continuation. 174 // Replace all occurrences with the wrapped continuation.
158 wrappedCont.substituteFor(cont); 175 wrappedCont.substituteFor(cont);
159 176
160 // Perform bookkeeping on removed body and scan for new redexes. 177 // Perform bookkeeping on removed body and scan for new redexes.
161 new _RemovalRedexVisitor(_worklist).visit(cont); 178 new _RemovalRedexVisitor(_worklist).visit(cont);
162 } 179 }
163 } 180 }
164 181
165 /// Returns true iff the bound primitive is unused. 182 /// Returns true iff the bound primitive is unused.
166 bool _isDeadVal(LetPrim node) => !node.primitive.hasAtLeastOneUse; 183 bool _isDeadVal(LetPrim node) => !node.primitive.hasAtLeastOneUse;
167 184
168 /// Returns true iff the bound continuation is unused. 185 /// Returns true iff the continuation is unused.
169 bool _isDeadCont(LetCont node) => !node.continuation.hasAtLeastOneUse; 186 bool _isDeadCont(Continuation cont) {
187 return !cont.hasAtLeastOneUse && !cont.isReturnContinuation;
188 }
170 189
171 /// Returns true iff the bound continuation is used exactly once, and that 190 /// Returns true iff the continuation is used exactly once, and that
172 /// use is as the receiver of a continuation invocation. 191 /// use is as the continuation of a continuation invocation.
173 bool _isBetaContLin(LetCont node) { 192 bool _isBetaContLin(Continuation cont) {
174 Continuation cont = node.continuation;
175 if (!cont.hasExactlyOneUse) { 193 if (!cont.hasExactlyOneUse) {
176 return false; 194 return false;
177 } 195 }
178 196
179 if (cont.firstRef.parent is InvokeContinuation) { 197 if (cont.firstRef.parent is InvokeContinuation) {
180 InvokeContinuation invoke = cont.firstRef.parent; 198 InvokeContinuation invoke = cont.firstRef.parent;
181 return (cont == invoke.continuation.definition); 199 return (cont == invoke.continuation.definition);
182 } 200 }
183 201
184 return false; 202 return false;
185
186 } 203 }
187 204
188 /// Returns true iff the bound continuation consists of a continuation 205 /// Returns true iff the continuation consists of a continuation
189 /// invocation, passing on all parameters. Special cases exist (see below). 206 /// invocation, passing on all parameters. Special cases exist (see below).
190 bool _isEtaCont(LetCont node) { 207 bool _isEtaCont(Continuation cont) {
191 Continuation cont = node.continuation; 208 if (cont.body is! InvokeContinuation) {
192 if (!(cont.body is InvokeContinuation)) {
193 return false; 209 return false;
194 } 210 }
195 211
196 InvokeContinuation invoke = cont.body; 212 InvokeContinuation invoke = cont.body;
197 Continuation invokedCont = invoke.continuation.definition; 213 Continuation invokedCont = invoke.continuation.definition;
198 214
199 // Do not eta-reduce return join-points since the resulting code is worse 215 // Do not eta-reduce return join-points since the resulting code is worse
200 // in the common case (i.e. returns are moved inside `if` branches). 216 // in the common case (i.e. returns are moved inside `if` branches).
201 if (invokedCont.isReturnContinuation) { 217 if (invokedCont.isReturnContinuation) {
202 return false; 218 return false;
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
235 if (node.parent == ShrinkingReducer._DELETED) { 251 if (node.parent == ShrinkingReducer._DELETED) {
236 return; 252 return;
237 } else if (_isDeadVal(node)) { 253 } else if (_isDeadVal(node)) {
238 worklist.add(new _ReductionTask(_ReductionKind.DEAD_VAL, node)); 254 worklist.add(new _ReductionTask(_ReductionKind.DEAD_VAL, node));
239 } 255 }
240 } 256 }
241 257
242 void processLetCont(LetCont node) { 258 void processLetCont(LetCont node) {
243 if (node.parent == ShrinkingReducer._DELETED) { 259 if (node.parent == ShrinkingReducer._DELETED) {
244 return; 260 return;
245 } else if (_isDeadCont(node)) { 261 }
246 worklist.add(new _ReductionTask(_ReductionKind.DEAD_CONT, node)); 262 for (int i = 0; i < node.continuations.length; ++i) {
247 } else if (_isEtaCont(node)) { 263 Continuation cont = node.continuations[i];
248 worklist.add(new _ReductionTask(_ReductionKind.ETA_CONT, node)); 264 if (_isDeadCont(cont)) {
249 } else if (_isBetaContLin(node)){ 265 worklist.add(new _ReductionTask(_ReductionKind.DEAD_CONT, cont));
250 worklist.add(new _ReductionTask(_ReductionKind.BETA_CONT_LIN, node)); 266 } else if (_isEtaCont(cont)) {
267 worklist.add(new _ReductionTask(_ReductionKind.ETA_CONT, cont));
268 } else if (_isBetaContLin(cont)){
269 worklist.add(new _ReductionTask(_ReductionKind.BETA_CONT_LIN, cont));
270 }
251 } 271 }
252 } 272 }
253 } 273 }
254 274
255 /// Traverses a deleted CPS term, marking existing tasks associated with a node 275 /// Traverses a deleted CPS term, marking existing tasks associated with a node
256 /// within the term as deleted (which causes them to be skipped lazily when 276 /// within the term as deleted (which causes them to be skipped lazily when
257 /// popped from the worklist), and adding newly created redexes to the worklist. 277 /// popped from the worklist), and adding newly created redexes to the worklist.
258 class _RemovalRedexVisitor extends _RedexVisitor { 278 class _RemovalRedexVisitor extends _RedexVisitor {
259 _RemovalRedexVisitor(Set<_ReductionTask> worklist) : super(worklist); 279 _RemovalRedexVisitor(Set<_ReductionTask> worklist) : super(worklist);
260 280
261 void processLetPrim(LetPrim node) { 281 void processLetPrim(LetPrim node) {
262 node.parent = ShrinkingReducer._DELETED; 282 node.parent = ShrinkingReducer._DELETED;
263 } 283 }
264 284
265 void processLetCont(LetCont node) { 285 void processLetCont(LetCont node) {
266 node.parent = ShrinkingReducer._DELETED; 286 node.parent = ShrinkingReducer._DELETED;
267 } 287 }
268 288
289 void processContinuation(Continuation node) {
290 node.parent = ShrinkingReducer._DELETED;
291 }
292
269 void processReference(Reference reference) { 293 void processReference(Reference reference) {
270 reference.unlink(); 294 reference.unlink();
271 295
272 if (reference.definition is Primitive) { 296 if (reference.definition is Primitive) {
273 Primitive primitive = reference.definition; 297 Primitive primitive = reference.definition;
274 Node parent = primitive.parent; 298 Node parent = primitive.parent;
275 if (parent is LetPrim && _isDeadVal(parent)) { 299 if (parent is LetPrim && _isDeadVal(parent)) {
276 worklist.add(new _ReductionTask(_ReductionKind.DEAD_VAL, parent)); 300 worklist.add(new _ReductionTask(_ReductionKind.DEAD_VAL, parent));
277 } 301 }
278 } else if (reference.definition is Continuation) { 302 } else if (reference.definition is Continuation) {
279 Continuation cont = reference.definition; 303 Continuation cont = reference.definition;
280 if (cont.isRecursive && cont.hasAtMostOneUse) { 304 if (cont.isRecursive && cont.hasAtMostOneUse) {
281 // Convert recursive to nonrecursive continuations. 305 // Convert recursive to nonrecursive continuations.
282 // If the continuation is still in use, it is either dead and will be 306 // If the continuation is still in use, it is either dead and will be
283 // removed, or it is called nonrecursively outside its body. 307 // removed, or it is called nonrecursively outside its body.
284 cont.isRecursive = false; 308 cont.isRecursive = false;
285 } 309 }
286 Node parent = cont.parent; 310 if (_isDeadCont(cont)) {
287 if (parent is LetCont && _isDeadCont(parent)) { 311 worklist.add(new _ReductionTask(_ReductionKind.DEAD_CONT, cont));
288 worklist.add(new _ReductionTask(_ReductionKind.DEAD_CONT, parent));
289 } 312 }
290 } 313 }
291 } 314 }
292 } 315 }
293 316
294 /// Traverses the CPS term and sets node.parent for each visited node. 317 /// Traverses the CPS term and sets node.parent for each visited node.
295 class ParentVisitor extends RecursiveVisitor { 318 class ParentVisitor extends RecursiveVisitor {
296
297 processFunctionDefinition(FunctionDefinition node) { 319 processFunctionDefinition(FunctionDefinition node) {
298 node.body.parent = node; 320 node.body.parent = node;
299 node.parameters.forEach((Definition p) => p.parent = node); 321 node.parameters.forEach((Definition p) => p.parent = node);
300 } 322 }
301 323
302 processRunnableBody(RunnableBody node) { 324 processRunnableBody(RunnableBody node) {
303 node.body.parent = node; 325 node.body.parent = node;
304 } 326 }
305 327
306 processConstructorDefinition(ConstructorDefinition node) { 328 processConstructorDefinition(ConstructorDefinition node) {
(...skipping 12 matching lines...) Expand all
319 node.arguments.forEach( 341 node.arguments.forEach(
320 (RunnableBody argument) => argument.body.parent = node); 342 (RunnableBody argument) => argument.body.parent = node);
321 } 343 }
322 344
323 processLetPrim(LetPrim node) { 345 processLetPrim(LetPrim node) {
324 node.primitive.parent = node; 346 node.primitive.parent = node;
325 node.body.parent = node; 347 node.body.parent = node;
326 } 348 }
327 349
328 processLetCont(LetCont node) { 350 processLetCont(LetCont node) {
329 node.continuation.parent = node; 351 for (int i = 0; i < node.continuations.length; ++i) {
352 Continuation cont = node.continuations[i];
353 cont.parent = node;
354 cont.parent_index = i;
355 }
330 node.body.parent = node; 356 node.body.parent = node;
331 } 357 }
332 358
333 processInvokeStatic(InvokeStatic node) { 359 processInvokeStatic(InvokeStatic node) {
360 node.arguments.forEach((Reference ref) => ref.parent = node);
334 node.continuation.parent = node; 361 node.continuation.parent = node;
335 node.arguments.forEach((Reference ref) => ref.parent = node);
336 } 362 }
337 363
338 processInvokeContinuation(InvokeContinuation node) { 364 processInvokeContinuation(InvokeContinuation node) {
339 node.continuation.parent = node; 365 node.continuation.parent = node;
340 node.arguments.forEach((Reference ref) => ref.parent = node); 366 node.arguments.forEach((Reference ref) => ref.parent = node);
341 } 367 }
342 368
343 processInvokeMethod(InvokeMethod node) { 369 processInvokeMethod(InvokeMethod node) {
344 node.receiver.parent = node; 370 node.receiver.parent = node;
345 node.continuation.parent = node; 371 node.continuation.parent = node;
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
476 } 502 }
477 503
478 String toString() => "$kind: $node"; 504 String toString() => "$kind: $node";
479 } 505 }
480 506
481 /// A dummy class used solely to mark nodes as deleted once they are removed 507 /// A dummy class used solely to mark nodes as deleted once they are removed
482 /// from a term. 508 /// from a term.
483 class _DeletedNode extends Node { 509 class _DeletedNode extends Node {
484 accept(_) => null; 510 accept(_) => null;
485 } 511 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698