| 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 375 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 386 } | 386 } |
| 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 /** |
| 397 * A list to propagate bailout information to blocks that start a |
| 398 * guarded or labeled list of statements. Currently, these blocks |
| 399 * are: |
| 400 * - first block of a then branch, |
| 401 * - first block of an else branch, |
| 402 * - a loop header, |
| 403 * - labeled block. |
| 404 */ |
| 396 final List<HBasicBlock> blocks; | 405 final List<HBasicBlock> blocks; |
| 397 final List<HLabeledBlockInformation> labeledBlockInformations; | 406 |
| 398 final Set<HInstruction> generateAtUseSite; | 407 /** |
| 408 * The current subgraph we are visiting. |
| 409 */ |
| 399 SubGraph subGraph; | 410 SubGraph subGraph; |
| 411 |
| 412 /** |
| 413 * The current block information we are visiting. |
| 414 */ |
| 415 HBlockInformation currentBlockInformation; |
| 416 |
| 400 /** | 417 /** |
| 401 * Max number of arguments to the bailout (not counting the state). | 418 * Max number of arguments to the bailout (not counting the state). |
| 402 */ | 419 */ |
| 403 int bailoutArity; | 420 int bailoutArity; |
| 404 /** | 421 /** |
| 405 * A map from variables to their names. These are the names in the | 422 * A map from variables to their names. These are the names in the |
| 406 * unoptimized (bailout) version of the function. Their names could be | 423 * unoptimized (bailout) version of the function. Their names could be |
| 407 * different in the optimized version. | 424 * different in the optimized version. |
| 408 */ | 425 */ |
| 409 VariableNames variableNames; | 426 VariableNames variableNames; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 427 * The first type guard in the graph. | 444 * The first type guard in the graph. |
| 428 */ | 445 */ |
| 429 HBailoutTarget firstBailoutTarget; | 446 HBailoutTarget firstBailoutTarget; |
| 430 | 447 |
| 431 /** | 448 /** |
| 432 * If set, it is the first block in the graph where we generate | 449 * 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 | 450 * code. Blocks before this one are dead code in the bailout |
| 434 * version. | 451 * version. |
| 435 */ | 452 */ |
| 436 | 453 |
| 437 SsaBailoutPropagator(this.compiler, | 454 SsaBailoutPropagator(this.compiler, this.variableNames) |
| 438 this.generateAtUseSite, | |
| 439 this.variableNames) | |
| 440 : blocks = <HBasicBlock>[], | 455 : blocks = <HBasicBlock>[], |
| 441 labeledBlockInformations = <HLabeledBlockInformation>[], | |
| 442 bailoutArity = 0, | 456 bailoutArity = 0, |
| 443 parameterNames = new Map<String, int>(); | 457 parameterNames = new Map<String, int>(); |
| 444 | 458 |
| 445 void visitGraph(HGraph graph) { | 459 void visitGraph(HGraph graph) { |
| 446 subGraph = new SubGraph(graph.entry, graph.exit); | 460 subGraph = new SubGraph(graph.entry, graph.exit); |
| 447 visitBasicBlock(graph.entry); | 461 visitBasicBlock(graph.entry); |
| 448 if (!blocks.isEmpty) { | 462 if (!blocks.isEmpty) { |
| 449 compiler.internalError('Bailout propagation', | 463 compiler.internalError('Bailout propagation', |
| 450 node: compiler.currentElement.parseNode(compiler)); | 464 node: compiler.currentElement.parseNode(compiler)); |
| 451 } | 465 } |
| 452 } | 466 } |
| 453 | 467 |
| 468 /** |
| 469 * Returns true if we can visit the given [blockFlow]. False |
| 470 * otherwise. Currently, try/catch and switch are not in bailout |
| 471 * methods, so this method only deals with loops and labeled blocks. |
| 472 * If [blockFlow] is a labeled block or a loop, we also visit the |
| 473 * continuation of the block flow. |
| 474 */ |
| 475 bool handleBlockFlow(HBlockFlow blockFlow) { |
| 476 HBlockInformation body = blockFlow.body; |
| 477 |
| 478 // We reach here again when starting to visit a subgraph. Just |
| 479 // return to visiting the block. |
| 480 if (currentBlockInformation == body) return false; |
| 481 |
| 482 HBlockInformation oldInformation = currentBlockInformation; |
| 483 if (body is HLabeledBlockInformation) { |
| 484 currentBlockInformation = body; |
| 485 HLabeledBlockInformation info = body; |
| 486 visitStatements(info.body, newFlow: true); |
| 487 } else if (body is HLoopBlockInformation) { |
| 488 currentBlockInformation = body; |
| 489 HLoopBlockInformation info = body; |
| 490 if (info.initializer != null) { |
| 491 visitExpression(info.initializer); |
| 492 } |
| 493 blocks.addLast(info.loopHeader); |
| 494 if (!info.isDoWhile()) { |
| 495 visitExpression(info.condition); |
| 496 } |
| 497 visitStatements(info.body, newFlow: false); |
| 498 if (info.isDoWhile()) { |
| 499 visitExpression(info.condition); |
| 500 } |
| 501 if (info.updates != null) { |
| 502 visitExpression(info.updates); |
| 503 } |
| 504 blocks.removeLast(); |
| 505 } else { |
| 506 assert(body is! HTryBlockInformation); |
| 507 assert(body is! HSwitchBlockInformation); |
| 508 // [HIfBlockInformation] is handled by visitIf. |
| 509 return false; |
| 510 } |
| 511 |
| 512 currentBlockInformation = oldInformation; |
| 513 if (blockFlow.continuation != null) { |
| 514 visitBasicBlock(blockFlow.continuation); |
| 515 } |
| 516 return true; |
| 517 } |
| 518 |
| 454 void visitBasicBlock(HBasicBlock block) { | 519 void visitBasicBlock(HBasicBlock block) { |
| 455 // Abort traversal if we are leaving the currently active sub-graph. | 520 // Abort traversal if we are leaving the currently active sub-graph. |
| 456 if (!subGraph.contains(block)) return; | 521 if (!subGraph.contains(block)) return; |
| 457 | 522 |
| 458 if (block.isLoopHeader()) { | 523 HBlockFlow blockFlow = block.blockFlow; |
| 459 blocks.addLast(block); | 524 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 | 525 |
| 467 HInstruction instruction = block.first; | 526 HInstruction instruction = block.first; |
| 468 while (instruction != null) { | 527 while (instruction != null) { |
| 469 instruction.accept(this); | 528 instruction.accept(this); |
| 470 instruction = instruction.next; | 529 instruction = instruction.next; |
| 471 } | 530 } |
| 472 } | 531 } |
| 473 | 532 |
| 474 void visitStatements(HStatementInformation info) { | 533 void visitExpression(HSubExpressionBlockInformation info) { |
| 475 assert(info is HSubGraphBlockInformation); | 534 visitSubGraph(info.subExpression); |
| 476 HSubGraphBlockInformation graph = info; | 535 } |
| 477 visitSubGraph(graph.subGraph); | 536 |
| 537 /** |
| 538 * Visit the statements in [info]. If [newFlow] is true, we add the |
| 539 * first block of [statements] to the list of [blocks]. |
| 540 */ |
| 541 void visitStatements(HSubGraphBlockInformation info, {bool newFlow}) { |
| 542 SubGraph graph = info.subGraph; |
| 543 if (newFlow) blocks.addLast(graph.start); |
| 544 visitSubGraph(graph); |
| 545 if (newFlow) blocks.removeLast(); |
| 478 } | 546 } |
| 479 | 547 |
| 480 void visitSubGraph(SubGraph graph) { | 548 void visitSubGraph(SubGraph graph) { |
| 481 SubGraph oldSubGraph = subGraph; | 549 SubGraph oldSubGraph = subGraph; |
| 482 subGraph = graph; | 550 subGraph = graph; |
| 483 HBasicBlock start = graph.start; | 551 visitBasicBlock(graph.start); |
| 484 blocks.addLast(start); | |
| 485 visitBasicBlock(start); | |
| 486 blocks.removeLast(); | |
| 487 subGraph = oldSubGraph; | 552 subGraph = oldSubGraph; |
| 488 | |
| 489 if (start.isLabeledBlock()) { | |
| 490 HBasicBlock continuation = start.blockFlow.continuation; | |
| 491 if (continuation != null) { | |
| 492 visitBasicBlock(continuation); | |
| 493 } | |
| 494 } | |
| 495 } | 553 } |
| 496 | 554 |
| 497 void visitIf(HIf instruction) { | 555 void visitIf(HIf instruction) { |
| 498 int preVisitedBlocks = 0; | 556 int preVisitedBlocks = 0; |
| 499 HIfBlockInformation info = instruction.blockInformation.body; | 557 HIfBlockInformation info = instruction.blockInformation.body; |
| 500 visitStatements(info.thenGraph); | 558 visitStatements(info.thenGraph, newFlow: true); |
| 501 preVisitedBlocks++; | 559 preVisitedBlocks++; |
| 502 visitStatements(info.elseGraph); | 560 visitStatements(info.elseGraph, newFlow: true); |
| 503 preVisitedBlocks++; | 561 preVisitedBlocks++; |
| 504 | 562 |
| 505 HBasicBlock joinBlock = instruction.joinBlock; | 563 HBasicBlock joinBlock = instruction.joinBlock; |
| 506 if (joinBlock != null | 564 if (joinBlock != null |
| 507 && !identical(joinBlock.dominator, instruction.block)) { | 565 && !identical(joinBlock.dominator, instruction.block)) { |
| 508 // The join block is dominated by a block in one of the branches. | 566 // 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 | 567 // The subgraph traversal never reached it, so we visit it here |
| 510 // instead. | 568 // instead. |
| 511 visitBasicBlock(joinBlock); | 569 visitBasicBlock(joinBlock); |
| 512 } | 570 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 525 | 583 |
| 526 void visitGoto(HGoto goto) { | 584 void visitGoto(HGoto goto) { |
| 527 HBasicBlock block = goto.block; | 585 HBasicBlock block = goto.block; |
| 528 HBasicBlock successor = block.successors[0]; | 586 HBasicBlock successor = block.successors[0]; |
| 529 if (identical(successor.dominator, block)) { | 587 if (identical(successor.dominator, block)) { |
| 530 visitBasicBlock(block.successors[0]); | 588 visitBasicBlock(block.successors[0]); |
| 531 } | 589 } |
| 532 } | 590 } |
| 533 | 591 |
| 534 void visitLoopBranch(HLoopBranch branch) { | 592 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. | 593 // For a do-while loop, the body has already been visited. |
| 538 if (!branch.isDoWhile()) { | 594 if (!branch.isDoWhile()) { |
| 539 visitBasicBlock(dominated[0]); | 595 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 } | 596 } |
| 554 } | 597 } |
| 555 | 598 |
| 556 visitBailoutTarget(HBailoutTarget target) { | 599 visitBailoutTarget(HBailoutTarget target) { |
| 557 int inputLength = target.inputs.length; | 600 int inputLength = target.inputs.length; |
| 558 for (HInstruction input in target.inputs) { | 601 for (HInstruction input in target.inputs) { |
| 559 String inputName = variableNames.getName(input); | 602 String inputName = variableNames.getName(input); |
| 560 int position = parameterNames[inputName]; | 603 int position = parameterNames[inputName]; |
| 561 if (position == null) { | 604 if (position == null) { |
| 562 position = parameterNames[inputName] = bailoutArity++; | 605 position = parameterNames[inputName] = bailoutArity++; |
| 563 } | 606 } |
| 564 } | 607 } |
| 565 | 608 |
| 566 if (blocks.isEmpty) { | 609 if (blocks.isEmpty) { |
| 567 if (firstBailoutTarget == null) { | 610 if (firstBailoutTarget == null) { |
| 568 firstBailoutTarget = target; | 611 firstBailoutTarget = target; |
| 569 } else { | 612 } else { |
| 570 hasComplexBailoutTargets = true; | 613 hasComplexBailoutTargets = true; |
| 571 } | 614 } |
| 572 } else { | 615 } else { |
| 573 hasComplexBailoutTargets = true; | 616 hasComplexBailoutTargets = true; |
| 574 blocks.forEach((HBasicBlock block) { | 617 blocks.forEach((HBasicBlock block) { |
| 575 block.bailoutTargets.add(target); | 618 block.bailoutTargets.add(target); |
| 576 }); | 619 }); |
| 577 } | 620 } |
| 578 } | 621 } |
| 579 } | 622 } |
| OLD | NEW |