final void addSubroutineRetSuccessors ( final Label subroutineCaller ) { // Data flow algorithm: put this basic block in a list blocks to process (which are blocks // belonging to a subroutine starting with this label) and, while there are blocks to process, // remove one from the list, put it in a list of blocks that have been processed, add a return // edge to the successor of subroutineCaller if applicable, and add its successor basic blocks // in the control flow graph to the list of blocks to process (if not already done). Label listOfProcessedBlocks = EMPTY_LIST ; Label listOfBlocksToProcess = this ; listOfBlocksToProcess . nextListElement = EMPTY_LIST ; while ( listOfBlocksToProcess != EMPTY_LIST ) { // Move a basic block from the list of blocks to process to the list of processed blocks. Label basicBlock = listOfBlocksToProcess ; listOfBlocksToProcess = basicBlock . nextListElement ; basicBlock . nextListElement = listOfProcessedBlocks ; listOfProcessedBlocks = basicBlock ; // Add an edge from this block to the successor of the caller basic block, if this block is // the end of a subroutine and if this block and subroutineCaller do not belong to the same // subroutine. if ( ( basicBlock . flags & FLAG_SUBROUTINE_END ) != 0 && basicBlock . subroutineId != subroutineCaller . subroutineId ) { basicBlock . outgoingEdges = new Edge ( basicBlock . outputStackSize , // By construction, the first outgoing edge of a basic block that ends with a jsr // instruction leads to the jsr continuation block, i.e. where execution continues // when ret is called (see {@link #FLAG_SUBROUTINE_CALLER}). subroutineCaller . outgoingEdges . successor , basicBlock . outgoingEdges ) ; } // Add its successors to the list of blocks to process. Note that {@link #pushSuccessors} does // not push basic blocks which are already in a list. Here this means either in the list of // blocks to process, or in the list of already processed blocks. This second list is // important to make sure we don't reprocess an already processed block. listOfBlocksToProcess = basicBlock . pushSuccessors ( listOfBlocksToProcess ) ; } // Reset the {@link #nextListElement} of all the basic blocks that have been processed to null, // so that this method can be called again with a different subroutine or subroutine caller. while ( listOfProcessedBlocks != EMPTY_LIST ) { Label newListOfProcessedBlocks = listOfProcessedBlocks . nextListElement ; listOfProcessedBlocks . nextListElement = null ; listOfProcessedBlocks = newListOfProcessedBlocks ; } }
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 return from this subroutine when called from the given caller basic block .