Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 ssa; | 5 part of ssa; |
| 6 | 6 |
| 7 class BailoutInfo { | 7 class BailoutInfo { |
| 8 int instructionId; | 8 int instructionId; |
| 9 int bailoutId; | 9 int bailoutId; |
| 10 BailoutInfo(this.instructionId, this.bailoutId); | 10 BailoutInfo(this.instructionId, this.bailoutId); |
| (...skipping 376 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 387 } | 387 } |
| 388 | 388 |
| 389 /** | 389 /** |
| 390 * Propagates bailout information to blocks that need it. This visitor | 390 * Propagates bailout information to blocks that need it. This visitor |
| 391 * is run before codegen, to know which blocks have to deal with | 391 * is run before codegen, to know which blocks have to deal with |
| 392 * bailouts. | 392 * bailouts. |
| 393 */ | 393 */ |
| 394 class SsaBailoutPropagator extends HBaseVisitor { | 394 class SsaBailoutPropagator extends HBaseVisitor { |
| 395 final Compiler compiler; | 395 final Compiler compiler; |
| 396 final List<HBasicBlock> blocks; | 396 final List<HBasicBlock> blocks; |
| 397 final List<HLabeledBlockInformation> labeledBlockInformations; | |
| 398 final Set<HInstruction> generateAtUseSite; | |
| 399 SubGraph subGraph; | 397 SubGraph subGraph; |
| 398 HBlockInformation currentBlockInformation; | |
| 399 | |
| 400 /** | 400 /** |
| 401 * Max number of arguments to the bailout (not counting the state). | 401 * Max number of arguments to the bailout (not counting the state). |
| 402 */ | 402 */ |
| 403 int bailoutArity; | 403 int bailoutArity; |
| 404 /** | 404 /** |
| 405 * A map from variables to their names. These are the names in the | 405 * A map from variables to their names. These are the names in the |
| 406 * unoptimized (bailout) version of the function. Their names could be | 406 * unoptimized (bailout) version of the function. Their names could be |
| 407 * different in the optimized version. | 407 * different in the optimized version. |
| 408 */ | 408 */ |
| 409 VariableNames variableNames; | 409 VariableNames variableNames; |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 427 * The first type guard in the graph. | 427 * The first type guard in the graph. |
| 428 */ | 428 */ |
| 429 HBailoutTarget firstBailoutTarget; | 429 HBailoutTarget firstBailoutTarget; |
| 430 | 430 |
| 431 /** | 431 /** |
| 432 * If set, it is the first block in the graph where we generate | 432 * If set, it is the first block in the graph where we generate |
| 433 * code. Blocks before this one are dead code in the bailout | 433 * code. Blocks before this one are dead code in the bailout |
| 434 * version. | 434 * version. |
| 435 */ | 435 */ |
| 436 | 436 |
| 437 SsaBailoutPropagator(this.compiler, | 437 SsaBailoutPropagator(this.compiler, this.variableNames) |
| 438 this.generateAtUseSite, | |
| 439 this.variableNames) | |
| 440 : blocks = <HBasicBlock>[], | 438 : blocks = <HBasicBlock>[], |
| 441 labeledBlockInformations = <HLabeledBlockInformation>[], | |
| 442 bailoutArity = 0, | 439 bailoutArity = 0, |
| 443 parameterNames = new Map<String, int>(); | 440 parameterNames = new Map<String, int>(); |
| 444 | 441 |
| 445 void visitGraph(HGraph graph) { | 442 void visitGraph(HGraph graph) { |
| 446 subGraph = new SubGraph(graph.entry, graph.exit); | 443 subGraph = new SubGraph(graph.entry, graph.exit); |
| 447 visitBasicBlock(graph.entry); | 444 visitBasicBlock(graph.entry); |
| 448 if (!blocks.isEmpty) { | 445 if (!blocks.isEmpty) { |
| 449 compiler.internalError('Bailout propagation', | 446 compiler.internalError('Bailout propagation', |
| 450 node: compiler.currentElement.parseNode(compiler)); | 447 node: compiler.currentElement.parseNode(compiler)); |
| 451 } | 448 } |
| 452 } | 449 } |
| 453 | 450 |
| 451 bool handleBlockFlow(HBlockFlow blockFlow) { | |
|
kasperl
2013/01/31 01:50:06
This method deserves a comment.
ngeoffray
2013/01/31 08:17:24
Done.
| |
| 452 HBlockInformation body = blockFlow.body; | |
| 453 | |
| 454 // We reach here again when starting to visit a subgraph. Just | |
| 455 // return to visiting the block. | |
| 456 if (currentBlockInformation == body) return false; | |
| 457 | |
| 458 HBlockInformation oldInformation = currentBlockInformation; | |
| 459 if (body is HLabeledBlockInformation) { | |
| 460 currentBlockInformation = body; | |
| 461 HLabeledBlockInformation info = body; | |
| 462 visitStatements(info.body, newFlow: true); | |
| 463 } else if (body is HLoopBlockInformation) { | |
| 464 currentBlockInformation = body; | |
| 465 HLoopBlockInformation info = body; | |
| 466 if (info.initializer != null) { | |
| 467 visitExpression(info.initializer); | |
| 468 } | |
| 469 blocks.addLast(info.loopHeader); | |
| 470 if (!info.isDoWhile()) { | |
| 471 visitExpression(info.condition); | |
| 472 } | |
| 473 visitStatements(info.body, newFlow: false); | |
| 474 if (info.isDoWhile()) { | |
| 475 visitExpression(info.condition); | |
| 476 } | |
| 477 if (info.updates != null) { | |
| 478 visitExpression(info.updates); | |
| 479 } | |
| 480 blocks.removeLast(); | |
| 481 } else { | |
| 482 assert(body is! HTryBlockInformation); | |
| 483 assert(body is! HSwitchBlockInformation); | |
| 484 // [HIfBlockInformation] is handled by visitIf. | |
| 485 return false; | |
| 486 } | |
| 487 | |
| 488 currentBlockInformation = oldInformation; | |
| 489 if (blockFlow.continuation != null) { | |
| 490 visitBasicBlock(blockFlow.continuation); | |
| 491 } | |
| 492 return true; | |
| 493 } | |
| 494 | |
| 454 void visitBasicBlock(HBasicBlock block) { | 495 void visitBasicBlock(HBasicBlock block) { |
| 455 // Abort traversal if we are leaving the currently active sub-graph. | 496 // Abort traversal if we are leaving the currently active sub-graph. |
| 456 if (!subGraph.contains(block)) return; | 497 if (!subGraph.contains(block)) return; |
| 457 | 498 |
| 458 if (block.isLoopHeader()) { | 499 HBlockFlow blockFlow = block.blockFlow; |
| 459 blocks.addLast(block); | 500 if (blockFlow != null && handleBlockFlow(blockFlow)) return; |
| 460 } else if (block.isLabeledBlock() | |
| 461 && (blocks.isEmpty || !identical(blocks.last, block))) { | |
| 462 HLabeledBlockInformation info = block.blockFlow.body; | |
| 463 visitStatements(info.body); | |
| 464 return; | |
| 465 } | |
| 466 | 501 |
| 467 HInstruction instruction = block.first; | 502 HInstruction instruction = block.first; |
| 468 while (instruction != null) { | 503 while (instruction != null) { |
| 469 instruction.accept(this); | 504 instruction.accept(this); |
| 470 instruction = instruction.next; | 505 instruction = instruction.next; |
| 471 } | 506 } |
| 472 } | 507 } |
| 473 | 508 |
| 474 void visitStatements(HStatementInformation info) { | 509 void visitExpression(HSubExpressionBlockInformation info) { |
| 475 assert(info is HSubGraphBlockInformation); | 510 visitSubGraph(info.subExpression); |
| 476 HSubGraphBlockInformation graph = info; | 511 } |
| 477 visitSubGraph(graph.subGraph); | 512 |
| 513 void visitStatements(HSubGraphBlockInformation info, {bool newFlow}) { | |
|
kasperl
2013/01/31 01:50:06
Add a comment that explains how this works and wha
ngeoffray
2013/01/31 08:17:24
Done.
| |
| 514 SubGraph graph = info.subGraph; | |
| 515 if (newFlow) blocks.addLast(graph.start); | |
| 516 visitSubGraph(graph); | |
| 517 if (newFlow) blocks.removeLast(); | |
| 478 } | 518 } |
| 479 | 519 |
| 480 void visitSubGraph(SubGraph graph) { | 520 void visitSubGraph(SubGraph graph) { |
| 481 SubGraph oldSubGraph = subGraph; | 521 SubGraph oldSubGraph = subGraph; |
| 482 subGraph = graph; | 522 subGraph = graph; |
| 483 HBasicBlock start = graph.start; | 523 visitBasicBlock(graph.start); |
| 484 blocks.addLast(start); | |
| 485 visitBasicBlock(start); | |
| 486 blocks.removeLast(); | |
| 487 subGraph = oldSubGraph; | 524 subGraph = oldSubGraph; |
| 488 | |
| 489 if (start.isLabeledBlock()) { | |
| 490 HBasicBlock continuation = start.blockFlow.continuation; | |
| 491 if (continuation != null) { | |
| 492 visitBasicBlock(continuation); | |
| 493 } | |
| 494 } | |
| 495 } | 525 } |
| 496 | 526 |
| 497 void visitIf(HIf instruction) { | 527 void visitIf(HIf instruction) { |
| 498 int preVisitedBlocks = 0; | 528 int preVisitedBlocks = 0; |
| 499 HIfBlockInformation info = instruction.blockInformation.body; | 529 HIfBlockInformation info = instruction.blockInformation.body; |
| 500 visitStatements(info.thenGraph); | 530 visitStatements(info.thenGraph, newFlow: true); |
| 501 preVisitedBlocks++; | 531 preVisitedBlocks++; |
| 502 visitStatements(info.elseGraph); | 532 visitStatements(info.elseGraph, newFlow: true); |
| 503 preVisitedBlocks++; | 533 preVisitedBlocks++; |
| 504 | 534 |
| 505 HBasicBlock joinBlock = instruction.joinBlock; | 535 HBasicBlock joinBlock = instruction.joinBlock; |
| 506 if (joinBlock != null | 536 if (joinBlock != null |
| 507 && !identical(joinBlock.dominator, instruction.block)) { | 537 && !identical(joinBlock.dominator, instruction.block)) { |
| 508 // The join block is dominated by a block in one of the branches. | 538 // The join block is dominated by a block in one of the branches. |
| 509 // The subgraph traversal never reached it, so we visit it here | 539 // The subgraph traversal never reached it, so we visit it here |
| 510 // instead. | 540 // instead. |
| 511 visitBasicBlock(joinBlock); | 541 visitBasicBlock(joinBlock); |
| 512 } | 542 } |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 525 | 555 |
| 526 void visitGoto(HGoto goto) { | 556 void visitGoto(HGoto goto) { |
| 527 HBasicBlock block = goto.block; | 557 HBasicBlock block = goto.block; |
| 528 HBasicBlock successor = block.successors[0]; | 558 HBasicBlock successor = block.successors[0]; |
| 529 if (identical(successor.dominator, block)) { | 559 if (identical(successor.dominator, block)) { |
| 530 visitBasicBlock(block.successors[0]); | 560 visitBasicBlock(block.successors[0]); |
| 531 } | 561 } |
| 532 } | 562 } |
| 533 | 563 |
| 534 void visitLoopBranch(HLoopBranch branch) { | 564 void visitLoopBranch(HLoopBranch branch) { |
| 535 HBasicBlock branchBlock = branch.block; | |
| 536 List<HBasicBlock> dominated = branchBlock.dominatedBlocks; | |
| 537 // For a do-while loop, the body has already been visited. | 565 // For a do-while loop, the body has already been visited. |
| 538 if (!branch.isDoWhile()) { | 566 if (!branch.isDoWhile()) { |
| 539 visitBasicBlock(dominated[0]); | 567 visitBasicBlock(branch.block.dominatedBlocks[0]); |
| 540 } | |
| 541 blocks.removeLast(); | |
| 542 | |
| 543 // If the branch does not dominate the code after the loop, the | |
| 544 // dominator will visit it. | |
| 545 if (!identical(branchBlock.successors[1].dominator, branchBlock)) return; | |
| 546 | |
| 547 visitBasicBlock(branchBlock.successors[1]); | |
| 548 // With labeled breaks we can have more dominated blocks. | |
| 549 if (dominated.length >= 3) { | |
| 550 for (int i = 2; i < dominated.length; i++) { | |
| 551 visitBasicBlock(dominated[i]); | |
| 552 } | |
| 553 } | 568 } |
| 554 } | 569 } |
| 555 | 570 |
| 556 visitBailoutTarget(HBailoutTarget target) { | 571 visitBailoutTarget(HBailoutTarget target) { |
| 557 int inputLength = target.inputs.length; | 572 int inputLength = target.inputs.length; |
| 558 for (HInstruction input in target.inputs) { | 573 for (HInstruction input in target.inputs) { |
| 559 String inputName = variableNames.getName(input); | 574 String inputName = variableNames.getName(input); |
| 560 int position = parameterNames[inputName]; | 575 int position = parameterNames[inputName]; |
| 561 if (position == null) { | 576 if (position == null) { |
| 562 position = parameterNames[inputName] = bailoutArity++; | 577 position = parameterNames[inputName] = bailoutArity++; |
| 563 } | 578 } |
| 564 } | 579 } |
| 565 | 580 |
| 566 if (blocks.isEmpty) { | 581 if (blocks.isEmpty) { |
| 567 if (firstBailoutTarget == null) { | 582 if (firstBailoutTarget == null) { |
| 568 firstBailoutTarget = target; | 583 firstBailoutTarget = target; |
| 569 } else { | 584 } else { |
| 570 hasComplexBailoutTargets = true; | 585 hasComplexBailoutTargets = true; |
| 571 } | 586 } |
| 572 } else { | 587 } else { |
| 573 hasComplexBailoutTargets = true; | 588 hasComplexBailoutTargets = true; |
| 574 blocks.forEach((HBasicBlock block) { | 589 blocks.forEach((HBasicBlock block) { |
| 575 block.bailoutTargets.add(target); | 590 block.bailoutTargets.add(target); |
| 576 }); | 591 }); |
| 577 } | 592 } |
| 578 } | 593 } |
| 579 } | 594 } |
| OLD | NEW |