MCPcopy Index your code
hub / github.com/clojure/clojure / addSubroutineRetSuccessors

Method addSubroutineRetSuccessors

src/jvm/clojure/asm/Label.java:535–578  ·  view source on GitHub ↗

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)

Source from the content-addressed store, hash-verified

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

Callers 1

Calls 1

pushSuccessorsMethod · 0.95

Tested by

no test coverage detected