Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 256 // There is a restriction on continuation eta-redexes that the body is not an | 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 | 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 | 258 // when translating back to direct style (it duplicates returns). There is no |
| 259 // such restriction here because continuation beta-reduction is only performed | 259 // such restriction here because continuation beta-reduction is only performed |
| 260 // for singly referenced continuations. Thus, there is no possibility of code | 260 // for singly referenced continuations. Thus, there is no possibility of code |
| 261 // duplication. | 261 // duplication. |
| 262 if (cont.isReturnContinuation || !cont.hasExactlyOneUse) { | 262 if (cont.isReturnContinuation || !cont.hasExactlyOneUse) { |
| 263 return false; | 263 return false; |
| 264 } | 264 } |
| 265 | 265 |
| 266 if (cont.firstRef.parent is InvokeContinuation) { | 266 if (cont.firstRef.parent is! InvokeContinuation) return false; |
| 267 InvokeContinuation invoke = cont.firstRef.parent; | 267 |
| 268 return (cont == invoke.continuation.definition); | 268 InvokeContinuation invoke = cont.firstRef.parent; |
| 269 if (cont != invoke.continuation.definition) return false; | |
| 270 | |
| 271 // Beta-reduction will move the continuation's body to its unique invocation | |
| 272 // site. This is not safe if the body is moved inside an exception handler | |
|
karlklose
2015/02/16 10:15:48
'inside' -> 'into'?
Kevin Millikin (Google)
2015/02/25 11:06:35
Thanks.
| |
| 273 // binding. | |
| 274 Node current = invoke.parent; | |
| 275 while (current != cont.parent) { | |
| 276 if (current is LetHandler) return false; | |
| 277 current = current.parent; | |
| 269 } | 278 } |
| 270 | 279 return true; |
| 271 return false; | |
| 272 } | 280 } |
| 273 | 281 |
| 274 /// Returns true iff the continuation consists of a continuation | 282 /// Returns true iff the continuation consists of a continuation |
| 275 /// invocation, passing on all parameters. Special cases exist (see below). | 283 /// invocation, passing on all parameters. Special cases exist (see below). |
| 276 bool _isEtaCont(Continuation cont) { | 284 bool _isEtaCont(Continuation cont) { |
| 277 if (cont.isReturnContinuation || cont.body is! InvokeContinuation) { | 285 if (cont.isReturnContinuation || cont.body is! InvokeContinuation) { |
| 278 return false; | 286 return false; |
| 279 } | 287 } |
| 280 | 288 |
| 281 InvokeContinuation invoke = cont.body; | 289 InvokeContinuation invoke = cont.body; |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 350 | 358 |
| 351 return true; | 359 return true; |
| 352 } | 360 } |
| 353 | 361 |
| 354 bool _isDeadParameter(Parameter parameter) { | 362 bool _isDeadParameter(Parameter parameter) { |
| 355 // We cannot remove function parameters as an intraprocedural optimization. | 363 // We cannot remove function parameters as an intraprocedural optimization. |
| 356 if (parameter.parent is! Continuation || parameter.hasAtLeastOneUse) { | 364 if (parameter.parent is! Continuation || parameter.hasAtLeastOneUse) { |
| 357 return false; | 365 return false; |
| 358 } | 366 } |
| 359 | 367 |
| 368 // We cannot remove exception handler parameters, they have a fixed arity | |
| 369 // of two (TODO(kmillikin): is that true?). | |
|
asgerf
2015/02/20 10:10:07
I agree that they should have two parameters. Plea
Kevin Millikin (Google)
2015/02/25 11:06:36
Done.
| |
| 370 if (parameter.parent.parent is LetHandler) { | |
| 371 return false; | |
| 372 } | |
| 373 | |
| 360 // We cannot remove the parameter to a call continuation, because the | 374 // We cannot remove the parameter to a call continuation, because the |
| 361 // resulting expression will not be well-formed (call continuations have | 375 // resulting expression will not be well-formed (call continuations have |
| 362 // exactly one argument). The return continuation is a call continuation, so | 376 // exactly one argument). The return continuation is a call continuation, so |
| 363 // we cannot remove its dummy parameter. | 377 // we cannot remove its dummy parameter. |
| 364 Continuation continuation = parameter.parent; | 378 Continuation continuation = parameter.parent; |
| 365 if (continuation.isReturnContinuation) return false; | 379 if (continuation.isReturnContinuation) return false; |
| 366 Reference<Continuation> current = continuation.firstRef; | 380 Reference<Continuation> current = continuation.firstRef; |
| 367 while (current != null) { | 381 while (current != null) { |
| 368 if (current.parent is! InvokeContinuation) return false; | 382 if (current.parent is! InvokeContinuation) return false; |
| 369 InvokeContinuation invoke = current.parent; | 383 InvokeContinuation invoke = current.parent; |
| 370 if (invoke.continuation.definition != continuation) return false; | 384 if (invoke.continuation.definition != continuation) return false; |
| 371 current = current.next; | 385 current = current.next; |
| 372 } | 386 } |
| 373 return true; | 387 return true; |
| 374 } | 388 } |
| 375 | 389 |
| 376 /// Traverses a term and adds any found redexes to the worklist. | 390 /// Traverses a term and adds any found redexes to the worklist. |
| 377 class _RedexVisitor extends RecursiveVisitor { | 391 class _RedexVisitor extends RecursiveVisitor { |
| 378 final Set<_ReductionTask> worklist; | 392 final Set<_ReductionTask> worklist; |
| 379 | 393 |
| 380 _RedexVisitor(this.worklist); | 394 _RedexVisitor(this.worklist); |
| 381 | 395 |
| 382 void processLetPrim(LetPrim node) { | 396 void processLetPrim(LetPrim node) { |
| 383 if (_isDeadVal(node)) { | 397 if (_isDeadVal(node)) { |
| 384 worklist.add(new _ReductionTask(_ReductionKind.DEAD_VAL, node)); | 398 worklist.add(new _ReductionTask(_ReductionKind.DEAD_VAL, node)); |
| 385 } | 399 } |
| 386 } | 400 } |
| 387 | 401 |
| 388 void processContinuation(Continuation node) { | 402 void processContinuation(Continuation node) { |
| 403 // While it would be nice to remove exception handlers that are provably | |
| 404 // unnecessary (e.g., the body cannot throw), that takes more sophisticated | |
| 405 // analysis than we do in this pass. | |
| 406 if (node.parent is LetHandler) return; | |
| 407 | |
| 389 // Continuation beta- and eta-redexes can overlap, namely when an eta-redex | 408 // Continuation beta- and eta-redexes can overlap, namely when an eta-redex |
| 390 // is invoked exactly once. We prioritize continuation beta-redexes over | 409 // is invoked exactly once. We prioritize continuation beta-redexes over |
| 391 // eta-redexes because some reductions (e.g., dead parameter elimination) | 410 // eta-redexes because some reductions (e.g., dead parameter elimination) |
| 392 // can destroy a continuation eta-redex. If we prioritized eta- over | 411 // can destroy a continuation eta-redex. If we prioritized eta- over |
| 393 // beta-redexes, this would implicitly "create" the corresponding beta-redex | 412 // beta-redexes, this would implicitly "create" the corresponding beta-redex |
| 394 // (in the sense that it would still apply) and the algorithm would not | 413 // (in the sense that it would still apply) and the algorithm would not |
| 395 // detect it. | 414 // detect it. |
| 396 if (_isDeadCont(node)) { | 415 if (_isDeadCont(node)) { |
| 397 worklist.add(new _ReductionTask(_ReductionKind.DEAD_CONT, node)); | 416 worklist.add(new _ReductionTask(_ReductionKind.DEAD_CONT, node)); |
| 398 } else if (_isBetaContLin(node)){ | 417 } else if (_isBetaContLin(node)){ |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 505 | 524 |
| 506 processLetCont(LetCont node) { | 525 processLetCont(LetCont node) { |
| 507 int index = 0; | 526 int index = 0; |
| 508 node.continuations.forEach((Continuation continuation) { | 527 node.continuations.forEach((Continuation continuation) { |
| 509 continuation.parent = node; | 528 continuation.parent = node; |
| 510 continuation.parent_index = index++; | 529 continuation.parent_index = index++; |
| 511 }); | 530 }); |
| 512 node.body.parent = node; | 531 node.body.parent = node; |
| 513 } | 532 } |
| 514 | 533 |
| 534 processLetHandler(LetHandler node) { | |
| 535 node.handler.parent = node; | |
| 536 node.body.parent = node; | |
| 537 } | |
| 538 | |
| 515 processLetMutable(LetMutable node) { | 539 processLetMutable(LetMutable node) { |
| 516 node.variable.parent = node; | 540 node.variable.parent = node; |
| 517 node.value.parent = node; | 541 node.value.parent = node; |
| 518 node.body.parent = node; | 542 node.body.parent = node; |
| 519 } | 543 } |
| 520 | 544 |
| 521 processInvokeStatic(InvokeStatic node) { | 545 processInvokeStatic(InvokeStatic node) { |
| 522 node.arguments.forEach((Reference ref) => ref.parent = node); | 546 node.arguments.forEach((Reference ref) => ref.parent = node); |
| 523 node.continuation.parent = node; | 547 node.continuation.parent = node; |
| 524 } | 548 } |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 675 } | 699 } |
| 676 | 700 |
| 677 String toString() => "$kind: $node"; | 701 String toString() => "$kind: $node"; |
| 678 } | 702 } |
| 679 | 703 |
| 680 /// A dummy class used solely to mark nodes as deleted once they are removed | 704 /// A dummy class used solely to mark nodes as deleted once they are removed |
| 681 /// from a term. | 705 /// from a term. |
| 682 class _DeletedNode extends Node { | 706 class _DeletedNode extends Node { |
| 683 accept(_) => null; | 707 accept(_) => null; |
| 684 } | 708 } |
| OLD | NEW |