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

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

Issue 872373003: Reapply "Add a shrinking reduction for dead continuation parameters." (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: The actual fix. 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 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
76 break; 76 break;
77 case _ReductionKind.DEAD_CONT: 77 case _ReductionKind.DEAD_CONT:
78 _reduceDeadCont(task); 78 _reduceDeadCont(task);
79 break; 79 break;
80 case _ReductionKind.BETA_CONT_LIN: 80 case _ReductionKind.BETA_CONT_LIN:
81 _reduceBetaContLin(task); 81 _reduceBetaContLin(task);
82 break; 82 break;
83 case _ReductionKind.ETA_CONT: 83 case _ReductionKind.ETA_CONT:
84 _reduceEtaCont(task); 84 _reduceEtaCont(task);
85 break; 85 break;
86 case _ReductionKind.DEAD_PARAMETER:
87 _reduceDeadParameter(task);
88 break;
86 default: 89 default:
87 assert(false); 90 assert(false);
88 } 91 }
89 } 92 }
90 93
91 /// Applies the dead-val reduction: 94 /// Applies the dead-val reduction:
92 /// letprim x = V in E -> E (x not free in E). 95 /// letprim x = V in E -> E (x not free in E).
93 void _reduceDeadVal(_ReductionTask task) { 96 void _reduceDeadVal(_ReductionTask task) {
94 assert(_isDeadVal(task.node)); 97 assert(_isDeadVal(task.node));
95 98
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 172
170 InvokeContinuation invoke = cont.body; 173 InvokeContinuation invoke = cont.body;
171 Continuation wrappedCont = invoke.continuation.definition; 174 Continuation wrappedCont = invoke.continuation.definition;
172 175
173 // Replace all occurrences with the wrapped continuation. 176 // Replace all occurrences with the wrapped continuation.
174 wrappedCont.substituteFor(cont); 177 wrappedCont.substituteFor(cont);
175 178
176 // Perform bookkeeping on removed body and scan for new redexes. 179 // Perform bookkeeping on removed body and scan for new redexes.
177 new _RemovalVisitor(_worklist).visit(cont); 180 new _RemovalVisitor(_worklist).visit(cont);
178 } 181 }
182
183 void _reduceDeadParameter(_ReductionTask task) {
184 // Continuation eta-reduction can destroy a dead parameter redex. For
185 // example, in the term:
186 //
187 // let cont k0(v0) = /* v0 is not used */ in
188 // let cont k1(v1) = k0(v1) in
189 // call foo () k1
190 //
191 // Continuation eta-reduction of k1 gives:
192 //
193 // let cont k0(v0) = /* v0 is not used */ in
194 // call foo () k0
195 //
196 // Where the dead parameter reduction is no longer valid because we do not
197 // allow removing the paramter of call continuations. We disallow such eta
198 // reductions in [_isEtaCont].
199 assert(_isDeadParameter(task.node));
200
201 Parameter parameter = task.node;
202 Continuation continuation = parameter.parent;
203 int index = parameter.parent_index;
204
205 // Remove the index'th argument from each invocation.
206 Reference<Continuation> current = continuation.firstRef;
207 while (current != null) {
208 InvokeContinuation invoke = current.parent;
209 Reference<Primitive> argument = invoke.arguments[index];
210 argument.unlink();
211 // Removing an argument can create a dead parameter or dead value redex.
212 if (argument.definition is Parameter) {
213 if (_isDeadParameter(argument.definition)) {
214 _worklist.add(new _ReductionTask(_ReductionKind.DEAD_PARAMETER,
215 argument.definition));
216 }
217 } else {
218 Node parent = argument.definition.parent;
219 if (parent is LetPrim) {
220 if (_isDeadVal(parent)) {
221 _worklist.add(new _ReductionTask(_ReductionKind.DEAD_VAL, parent));
222 }
223 }
224 }
225 invoke.arguments.removeAt(index);
226 current = current.next;
227 }
228 // Copy the parameters above index down.
229 List<Parameter> parameters = continuation.parameters;
230 for (int i = index; i < parameters.length - 1; ++i) {
231 Parameter p = parameters[i + 1];
232 parameters[i] = p;
233 p.parent_index = i;
234 }
235 parameters.removeLast();
236
237 // Removing an unused parameter can create an eta-redex.
238 if (_isEtaCont(continuation)) {
239 _worklist.add(new _ReductionTask(_ReductionKind.ETA_CONT, continuation));
240 }
241 }
179 } 242 }
180 243
181 /// Returns true iff the bound primitive is unused. 244 /// Returns true iff the bound primitive is unused.
182 bool _isDeadVal(LetPrim node) => !node.primitive.hasAtLeastOneUse; 245 bool _isDeadVal(LetPrim node) => !node.primitive.hasAtLeastOneUse;
183 246
184 /// Returns true iff the continuation is unused. 247 /// Returns true iff the continuation is unused.
185 bool _isDeadCont(Continuation cont) { 248 bool _isDeadCont(Continuation cont) {
186 assert(!cont.isReturnContinuation); 249 return !cont.isReturnContinuation && !cont.hasAtLeastOneUse;
187 return !cont.hasAtLeastOneUse;
188 } 250 }
189 251
190 /// Returns true iff the continuation is used exactly once, and that 252 /// Returns true iff the continuation has a body (i.e., it is not the return
191 /// use is as the continuation of a continuation invocation. 253 /// continuation), it is used exactly once, and that use is as the continuation
254 /// of a continuation invocation.
192 bool _isBetaContLin(Continuation cont) { 255 bool _isBetaContLin(Continuation cont) {
193 if (!cont.hasExactlyOneUse) { 256 // There is a restriction on continuation eta-redexes that the body is not an
257 // invocation of the return continuation, because that leads to worse code
258 // when translating back to direct style (it duplicates returns). There is no
259 // such restriction here because continuation beta-reduction is only performed
260 // for singly referenced continuations. Thus, there is no possibility of code
261 // duplication.
262 if (cont.isReturnContinuation || !cont.hasExactlyOneUse) {
194 return false; 263 return false;
195 } 264 }
196 265
197 if (cont.firstRef.parent is InvokeContinuation) { 266 if (cont.firstRef.parent is InvokeContinuation) {
198 InvokeContinuation invoke = cont.firstRef.parent; 267 InvokeContinuation invoke = cont.firstRef.parent;
199 return (cont == invoke.continuation.definition); 268 return (cont == invoke.continuation.definition);
200 } 269 }
201 270
202 return false; 271 return false;
203 } 272 }
204 273
205 /// Returns true iff the continuation consists of a continuation 274 /// Returns true iff the continuation consists of a continuation
206 /// invocation, passing on all parameters. Special cases exist (see below). 275 /// invocation, passing on all parameters. Special cases exist (see below).
207 bool _isEtaCont(Continuation cont) { 276 bool _isEtaCont(Continuation cont) {
208 if (cont.body is! InvokeContinuation) { 277 if (cont.isReturnContinuation || cont.body is! InvokeContinuation) {
209 return false; 278 return false;
210 } 279 }
211 280
212 InvokeContinuation invoke = cont.body; 281 InvokeContinuation invoke = cont.body;
213 Continuation invokedCont = invoke.continuation.definition; 282 Continuation invokedCont = invoke.continuation.definition;
214 283
215 // Do not eta-reduce return join-points since the resulting code is worse 284 // Do not eta-reduce return join-points since the direct-style code is worse
216 // in the common case (i.e. returns are moved inside `if` branches). 285 // in the common case (i.e. returns are moved inside `if` branches).
217 if (invokedCont.isReturnContinuation) { 286 if (invokedCont.isReturnContinuation) {
218 return false; 287 return false;
219 } 288 }
220 289
290 // Do not perform reductions replace a function call continuation with a
asgerf 2015/01/26 12:56:57 *that* replace or *replacing*
291 // non-call continuation. The invoked continuation is definitely not a call
292 // continuation, because it has a direct invocation in this continuation's
293 // body.
294 bool isCallContinuation(Continuation continuation) {
295 Reference<Continuation> current = cont.firstRef;
296 while (current != null) {
297 if (current.parent is InvokeContinuation) {
298 InvokeContinuation invoke = current.parent;
299 if (invoke.continuation.definition == continuation) return false;
300 }
301 current = current.next;
302 }
303 return true;
304 }
305 if (isCallContinuation(cont)) {
306 return false;
307 }
308
221 // Translation to direct style generates different statements for recursive 309 // Translation to direct style generates different statements for recursive
222 // and non-recursive invokes. It should be possible to apply eta-cont, but 310 // and non-recursive invokes. It should still be possible to apply eta-cont if
223 // higher order continuations require escape analysis, left as a possibility 311 // this is not a self-invocation.
224 // for future improvements. 312 //
313 // TODO(kmillikin): Remove this restriction if it makes sense to do so.
225 if (invoke.isRecursive) { 314 if (invoke.isRecursive) {
226 return false; 315 return false;
227 } 316 }
228 317
318 // If cont has more parameters than the invocation has arguments, the extra
319 // parameters will be dead and dead-parameter will eventually create the
320 // eta-redex if possible.
321 //
322 // If the invocation's arguments are simply a permutation of cont's
323 // parameters, then there is likewise a possible reduction that involves
324 // rewriting the invocations of cont. We are missing that reduction here.
325 //
326 // If cont has fewer parameters than the invocation has arguments then a
327 // reduction would still possible, since the extra invocation arguments must
328 // be in scope at all the invocations of cont. For example:
329 //
330 // let cont k1(x1) = k0(x0, x1) in E -eta-> E'
331 // where E' has k0(x0, v) substituted for each k1(v).
332 //
333 // HOWEVER, adding continuation parameters is unlikely to be an optimization
334 // since it duplicates assignments used in direct-style to implement parameter
335 // passing.
336 //
337 // TODO(kmillikin): find real occurrences of these patterns, and see if they
338 // can be optimized.
229 if (cont.parameters.length != invoke.arguments.length) { 339 if (cont.parameters.length != invoke.arguments.length) {
230 return false; 340 return false;
231 } 341 }
232 342
233 // TODO(jgruber): Linear in the parameter count. Can be improved to near 343 // TODO(jgruber): Linear in the parameter count. Can be improved to near
234 // constant time by using union-find data structure. 344 // constant time by using union-find data structure.
235 for (int i = 0; i < cont.parameters.length; i++) { 345 for (int i = 0; i < cont.parameters.length; i++) {
236 if (invoke.arguments[i].definition != cont.parameters[i]) { 346 if (invoke.arguments[i].definition != cont.parameters[i]) {
237 return false; 347 return false;
238 } 348 }
239 } 349 }
240 350
241 return true; 351 return true;
242 } 352 }
243 353
354 bool _isDeadParameter(Parameter parameter) {
355 // We cannot remove function parameters as an intraprocedural optimization.
356 if (parameter.parent is! Continuation || parameter.hasAtLeastOneUse) {
357 return false;
358 }
359
360 // We cannot remove the parameter to a call continuation, because the
361 // resulting expression will not be well-formed (call continuations have
362 // exactly one argument). The return continuation is a call continuation, so
363 // we cannot remove its dummy parameter.
364 Continuation continuation = parameter.parent;
365 if (continuation.isReturnContinuation) return false;
366 Reference<Continuation> current = continuation.firstRef;
367 while (current != null) {
368 if (current.parent is! InvokeContinuation) return false;
369 InvokeContinuation invoke = current.parent;
370 if (invoke.continuation.definition != continuation) return false;
371 current = current.next;
372 }
373 return true;
374 }
375
244 /// Traverses a term and adds any found redexes to the worklist. 376 /// Traverses a term and adds any found redexes to the worklist.
245 class _RedexVisitor extends RecursiveVisitor { 377 class _RedexVisitor extends RecursiveVisitor {
246 final Set<_ReductionTask> worklist; 378 final Set<_ReductionTask> worklist;
247 379
248 _RedexVisitor(this.worklist); 380 _RedexVisitor(this.worklist);
249 381
250 void processLetPrim(LetPrim node) { 382 void processLetPrim(LetPrim node) {
251 if (_isDeadVal(node)) { 383 if (_isDeadVal(node)) {
252 worklist.add(new _ReductionTask(_ReductionKind.DEAD_VAL, node)); 384 worklist.add(new _ReductionTask(_ReductionKind.DEAD_VAL, node));
253 } 385 }
254 } 386 }
255 387
256 void processContinuation(Continuation node) { 388 void processContinuation(Continuation node) {
389 // Continuation beta- and eta-redexes can overlap, namely when an eta-redex
390 // is invoked exactly once. We prioritize continuation beta-redexes over
391 // eta-redexes because some reductions (e.g., dead parameter elimination)
392 // can destroy a continuation eta-redex. If we prioritized eta- over
393 // beta-redexes, this would implicitly "create" the corresponding beta-redex
394 // (in the sense that it would still apply) and the algorithm would not
395 // detect it.
257 if (_isDeadCont(node)) { 396 if (_isDeadCont(node)) {
258 worklist.add(new _ReductionTask(_ReductionKind.DEAD_CONT, node)); 397 worklist.add(new _ReductionTask(_ReductionKind.DEAD_CONT, node));
398 } else if (_isBetaContLin(node)){
399 worklist.add(new _ReductionTask(_ReductionKind.BETA_CONT_LIN, node));
259 } else if (_isEtaCont(node)) { 400 } else if (_isEtaCont(node)) {
260 worklist.add(new _ReductionTask(_ReductionKind.ETA_CONT, node)); 401 worklist.add(new _ReductionTask(_ReductionKind.ETA_CONT, node));
261 } else if (_isBetaContLin(node)){ 402 }
262 worklist.add(new _ReductionTask(_ReductionKind.BETA_CONT_LIN, node)); 403 }
404
405 void processParameter(Parameter node) {
406 if (_isDeadParameter(node)) {
407 worklist.add(new _ReductionTask(_ReductionKind.DEAD_PARAMETER, node));
263 } 408 }
264 } 409 }
265 } 410 }
266 411
267 /// Traverses a deleted CPS term, marking nodes that might participate in a 412 /// Traverses a deleted CPS term, marking nodes that might participate in a
268 /// redex as deleted and adding newly created redexes to the worklist. 413 /// redex as deleted and adding newly created redexes to the worklist.
269 /// 414 ///
270 /// Deleted nodes that might participate in a reduction task are marked so that 415 /// Deleted nodes that might participate in a reduction task are marked so that
271 /// any corresponding tasks can be skipped. Nodes are marked so by setting 416 /// any corresponding tasks can be skipped. Nodes are marked so by setting
272 /// their parent to the deleted sentinel. 417 /// their parent to the deleted sentinel.
(...skipping 18 matching lines...) Expand all
291 Node parent = primitive.parent; 436 Node parent = primitive.parent;
292 // The parent might be the deleted sentinel, or it might be a 437 // The parent might be the deleted sentinel, or it might be a
293 // Continuation or FunctionDefinition if the primitive is an argument. 438 // Continuation or FunctionDefinition if the primitive is an argument.
294 if (parent is LetPrim && _isDeadVal(parent)) { 439 if (parent is LetPrim && _isDeadVal(parent)) {
295 worklist.add(new _ReductionTask(_ReductionKind.DEAD_VAL, parent)); 440 worklist.add(new _ReductionTask(_ReductionKind.DEAD_VAL, parent));
296 } 441 }
297 } else if (reference.definition is Continuation) { 442 } else if (reference.definition is Continuation) {
298 Continuation cont = reference.definition; 443 Continuation cont = reference.definition;
299 Node parent = cont.parent; 444 Node parent = cont.parent;
300 // The parent might be the deleted sentinel, or it might be a 445 // The parent might be the deleted sentinel, or it might be a
301 // FunctionDefinition if the continuation is the return continuation. 446 // RunnableBody if the continuation is the return continuation.
302 if (parent is LetCont) { 447 if (parent is LetCont) {
303 if (cont.isRecursive && cont.hasAtMostOneUse) { 448 if (cont.isRecursive && cont.hasAtMostOneUse) {
304 // Convert recursive to nonrecursive continuations. If the 449 // Convert recursive to nonrecursive continuations. If the
305 // continuation is still in use, it is either dead and will be 450 // continuation is still in use, it is either dead and will be
306 // removed, or it is called nonrecursively outside its body. 451 // removed, or it is called nonrecursively outside its body.
307 cont.isRecursive = false; 452 cont.isRecursive = false;
308 } 453 }
309 if (_isDeadCont(cont)) { 454 if (_isDeadCont(cont)) {
310 worklist.add(new _ReductionTask(_ReductionKind.DEAD_CONT, cont)); 455 worklist.add(new _ReductionTask(_ReductionKind.DEAD_CONT, cont));
456 } else if (_isBetaContLin(cont)) {
457 worklist.add(new _ReductionTask(_ReductionKind.BETA_CONT_LIN, cont));
311 } 458 }
312 } 459 }
313 } 460 }
314 } 461 }
315 } 462 }
316 463
317 /// Traverses the CPS term and sets node.parent for each visited node. 464 /// Traverses the CPS term and sets node.parent for each visited node.
318 class ParentVisitor extends RecursiveVisitor { 465 class ParentVisitor extends RecursiveVisitor {
319 processFunctionDefinition(FunctionDefinition node) { 466 processFunctionDefinition(FunctionDefinition node) {
320 node.body.parent = node; 467 node.body.parent = node;
321 node.parameters.forEach((Definition p) => p.parent = node); 468 int index = 0;
469 node.parameters.forEach((Definition parameter) {
470 parameter.parent = node;
471 if (parameter is Parameter) parameter.parent_index = index++;
472 });
322 } 473 }
323 474
324 processRunnableBody(RunnableBody node) { 475 processRunnableBody(RunnableBody node) {
476 node.returnContinuation.parent = node;
325 node.body.parent = node; 477 node.body.parent = node;
326 } 478 }
327 479
328 processConstructorDefinition(ConstructorDefinition node) { 480 processConstructorDefinition(ConstructorDefinition node) {
329 node.body.parent = node; 481 node.body.parent = node;
330 node.parameters.forEach((Definition p) => p.parent = node); 482 int index = 0;
483 node.parameters.forEach((Parameter parameter) {
484 parameter.parent = node;
485 parameter.parent_index = index++;
486 });
331 node.initializers.forEach((Initializer i) => i.parent = node); 487 node.initializers.forEach((Initializer i) => i.parent = node);
332 } 488 }
333 489
334 // Expressions. 490 // Expressions.
335 491
336 processFieldInitializer(FieldInitializer node) { 492 processFieldInitializer(FieldInitializer node) {
337 node.body.body.parent = node; 493 node.body.body.parent = node;
338 } 494 }
339 495
340 processSuperInitializer(SuperInitializer node) { 496 processSuperInitializer(SuperInitializer node) {
341 node.arguments.forEach( 497 node.arguments.forEach(
342 (RunnableBody argument) => argument.body.parent = node); 498 (RunnableBody argument) => argument.body.parent = node);
343 } 499 }
344 500
345 processLetPrim(LetPrim node) { 501 processLetPrim(LetPrim node) {
346 node.primitive.parent = node; 502 node.primitive.parent = node;
347 node.body.parent = node; 503 node.body.parent = node;
348 } 504 }
349 505
350 processLetCont(LetCont node) { 506 processLetCont(LetCont node) {
351 for (int i = 0; i < node.continuations.length; ++i) { 507 int index = 0;
352 Continuation cont = node.continuations[i]; 508 node.continuations.forEach((Continuation continuation) {
353 cont.parent = node; 509 continuation.parent = node;
354 cont.parent_index = i; 510 continuation.parent_index = index++;
355 } 511 });
356 node.body.parent = node; 512 node.body.parent = node;
357 } 513 }
358 514
359 processInvokeStatic(InvokeStatic node) { 515 processInvokeStatic(InvokeStatic node) {
360 node.arguments.forEach((Reference ref) => ref.parent = node); 516 node.arguments.forEach((Reference ref) => ref.parent = node);
361 node.continuation.parent = node; 517 node.continuation.parent = node;
362 } 518 }
363 519
364 processInvokeContinuation(InvokeContinuation node) { 520 processInvokeContinuation(InvokeContinuation node) {
365 node.continuation.parent = node; 521 node.continuation.parent = node;
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
420 entry.key.parent = node; 576 entry.key.parent = node;
421 entry.value.parent = node; 577 entry.value.parent = node;
422 }); 578 });
423 } 579 }
424 580
425 processCreateFunction(CreateFunction node) { 581 processCreateFunction(CreateFunction node) {
426 node.definition.parent = node; 582 node.definition.parent = node;
427 } 583 }
428 584
429 processContinuation(Continuation node) { 585 processContinuation(Continuation node) {
430 node.body.parent = node; 586 if (node.body != null) node.body.parent = node;
431 node.parameters.forEach((Parameter param) => param.parent = node); 587 int index = 0;
588 node.parameters.forEach((Parameter parameter) {
589 parameter.parent = node;
590 parameter.parent_index = index++;
591 });
432 } 592 }
433 593
434 // Conditions. 594 // Conditions.
435 595
436 processIsTrue(IsTrue node) { 596 processIsTrue(IsTrue node) {
437 node.value.parent = node; 597 node.value.parent = node;
438 } 598 }
439 599
440 // JavaScript specific nodes. 600 // JavaScript specific nodes.
441 601
(...skipping 28 matching lines...) Expand all
470 final String name; 630 final String name;
471 final int hashCode; 631 final int hashCode;
472 632
473 const _ReductionKind(this.name, this.hashCode); 633 const _ReductionKind(this.name, this.hashCode);
474 634
475 static const _ReductionKind DEAD_VAL = const _ReductionKind('dead-val', 0); 635 static const _ReductionKind DEAD_VAL = const _ReductionKind('dead-val', 0);
476 static const _ReductionKind DEAD_CONT = const _ReductionKind('dead-cont', 1); 636 static const _ReductionKind DEAD_CONT = const _ReductionKind('dead-cont', 1);
477 static const _ReductionKind BETA_CONT_LIN = 637 static const _ReductionKind BETA_CONT_LIN =
478 const _ReductionKind('beta-cont-lin', 2); 638 const _ReductionKind('beta-cont-lin', 2);
479 static const _ReductionKind ETA_CONT = const _ReductionKind('eta-cont', 3); 639 static const _ReductionKind ETA_CONT = const _ReductionKind('eta-cont', 3);
640 static const _ReductionKind DEAD_PARAMETER =
641 const _ReductionKind('dead-parameter', 4);
480 642
481 String toString() => name; 643 String toString() => name;
482 } 644 }
483 645
484 /// Represents a reduction task on the worklist. Implements both hashCode and 646 /// Represents a reduction task on the worklist. Implements both hashCode and
485 /// operator== since instantiations are used as Set elements. 647 /// operator== since instantiations are used as Set elements.
486 class _ReductionTask { 648 class _ReductionTask {
487 final _ReductionKind kind; 649 final _ReductionKind kind;
488 final Node node; 650 final Node node;
489 651
490 int get hashCode { 652 int get hashCode {
491 assert(kind.hashCode < (1 << 2)); 653 assert(kind.hashCode < (1 << 3));
492 return (node.hashCode << 2) | kind.hashCode; 654 return (node.hashCode << 3) | kind.hashCode;
493 } 655 }
494 656
495 _ReductionTask(this.kind, this.node) { 657 _ReductionTask(this.kind, this.node) {
496 assert(node is Continuation || node is LetPrim); 658 assert(node is Continuation || node is LetPrim || node is Parameter);
497 } 659 }
498 660
499 bool operator==(_ReductionTask that) { 661 bool operator==(_ReductionTask that) {
500 return (that.kind == this.kind && that.node == this.node); 662 return (that.kind == this.kind && that.node == this.node);
501 } 663 }
502 664
503 String toString() => "$kind: $node"; 665 String toString() => "$kind: $node";
504 } 666 }
505 667
506 /// A dummy class used solely to mark nodes as deleted once they are removed 668 /// A dummy class used solely to mark nodes as deleted once they are removed
507 /// from a term. 669 /// from a term.
508 class _DeletedNode extends Node { 670 class _DeletedNode extends Node {
509 accept(_) => null; 671 accept(_) => null;
510 } 672 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart ('k') | tests/compiler/dart2js/backend_dart/opt_constprop_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698