Finds the basic blocks that end a subroutine starting with the basic block corresponding to this label and, for each one of them, adds an outgoing edge to the basic block following the given subroutine call. In other words, completes the control flow graph by adding the edges corresponding to the re
(final Label subroutineCaller)
| 533 | * this label. This label is supposed to correspond to the start of a subroutine. |
| 534 | */ |
| 535 | final void addSubroutineRetSuccessors(final Label subroutineCaller) { |
| 536 | // Data flow algorithm: put this basic block in a list blocks to process (which are blocks |
| 537 | // belonging to a subroutine starting with this label) and, while there are blocks to process, |
| 538 | // remove one from the list, put it in a list of blocks that have been processed, add a return |
| 539 | // edge to the successor of subroutineCaller if applicable, and add its successor basic blocks |
| 540 | // in the control flow graph to the list of blocks to process (if not already done). |
| 541 | Label listOfProcessedBlocks = EMPTY_LIST; |
| 542 | Label listOfBlocksToProcess = this; |
| 543 | listOfBlocksToProcess.nextListElement = EMPTY_LIST; |
| 544 | while (listOfBlocksToProcess != EMPTY_LIST) { |
| 545 | // Move a basic block from the list of blocks to process to the list of processed blocks. |
| 546 | Label basicBlock = listOfBlocksToProcess; |
| 547 | listOfBlocksToProcess = basicBlock.nextListElement; |
| 548 | basicBlock.nextListElement = listOfProcessedBlocks; |
| 549 | listOfProcessedBlocks = basicBlock; |
| 550 | |
| 551 | // Add an edge from this block to the successor of the caller basic block, if this block is |
| 552 | // the end of a subroutine and if this block and subroutineCaller do not belong to the same |
| 553 | // subroutine. |
| 554 | if ((basicBlock.flags & FLAG_SUBROUTINE_END) != 0 |
| 555 | && basicBlock.subroutineId != subroutineCaller.subroutineId) { |
| 556 | basicBlock.outgoingEdges = |
| 557 | new Edge( |
| 558 | basicBlock.outputStackSize, |
| 559 | // By construction, the first outgoing edge of a basic block that ends with a jsr |
| 560 | // instruction leads to the jsr continuation block, i.e. where execution continues |
| 561 | // when ret is called (see {@link #FLAG_SUBROUTINE_CALLER}). |
| 562 | subroutineCaller.outgoingEdges.successor, |
| 563 | basicBlock.outgoingEdges); |
| 564 | } |
| 565 | // Add its successors to the list of blocks to process. Note that {@link #pushSuccessors} does |
| 566 | // not push basic blocks which are already in a list. Here this means either in the list of |
| 567 | // blocks to process, or in the list of already processed blocks. This second list is |
| 568 | // important to make sure we don't reprocess an already processed block. |
| 569 | listOfBlocksToProcess = basicBlock.pushSuccessors(listOfBlocksToProcess); |
| 570 | } |
| 571 | // Reset the {@link #nextListElement} of all the basic blocks that have been processed to null, |
| 572 | // so that this method can be called again with a different subroutine or subroutine caller. |
| 573 | while (listOfProcessedBlocks != EMPTY_LIST) { |
| 574 | Label newListOfProcessedBlocks = listOfProcessedBlocks.nextListElement; |
| 575 | listOfProcessedBlocks.nextListElement = null; |
| 576 | listOfProcessedBlocks = newListOfProcessedBlocks; |
| 577 | } |
| 578 | } |
| 579 | |
| 580 | /** |
| 581 | * Adds the successors of this label in the method's control flow graph (except those |
no test coverage detected