private void build(Subroutine subroutine) throws CFGBuilderException {
        // Prime the work list
        subroutine.addEdgeAndExplore(subroutine.getEntry(), subroutine.getStartInstruction(), START_EDGE);

        // Keep going until all basic blocks in the subroutine have been added
        while (subroutine.hasMoreWork()) {
            WorkListItem item = subroutine.nextItem();

            InstructionHandle handle = item.getStartInstruction();
            BasicBlock basicBlock = item.getBasicBlock();

            // Add exception handler block (ETB) for exception-throwing
            // instructions
            if (isPEI(handle)) {
                if (DEBUG) {
                    System.out.println("ETB block " + basicBlock.getLabel() + " for " + handle);
                }
                handleExceptions(subroutine, handle, basicBlock);
                BasicBlock body = subroutine.allocateBasicBlock();
                subroutine.addEdge(basicBlock, body, FALL_THROUGH_EDGE);
                basicBlock = body;
            }

            if (DEBUG) {
                System.out.println("BODY block " + basicBlock.getLabel() + " for " + handle);
            }

            if (!basicBlock.isEmpty()) {
                throw new IllegalStateException("Block isn't empty!");
            }

            // Add instructions until we get to the end of the block
            boolean endOfBasicBlock = false;
            do {
                Instruction ins = handle.getInstruction();

                // Add the instruction to the block
                if (DEBUG) {
                    System.out.println("BB " + basicBlock.getLabel() + ": adding" + handle);
                }
                basicBlock.addInstruction(handle);
                subroutine.addInstruction(handle);

                short opcode = ins.getOpcode();

                // TODO: should check instruction to ensure that in a JSR
                // subroutine
                // no assignments are made to the local containing the return
                // address.
                // if (ins instanceof ASTORE) ...

                if (opcode == Const.JSR || opcode == Const.JSR_W) {
                    // Find JSR subroutine, add it to subroutine work list if
                    // we haven't built a CFG for it yet
                    JsrInstruction jsr = (JsrInstruction) ins;
                    InstructionHandle jsrTarget = jsr.getTarget();
                    Subroutine jsrSubroutine = jsrSubroutineMap.get(jsrTarget);
                    if (jsrSubroutine == null) {
                        jsrSubroutine = new Subroutine(jsrTarget);
                        jsrSubroutineMap.put(jsrTarget, jsrSubroutine);
                        subroutineWorkList.add(jsrSubroutine);
                    }

                    // This ends the basic block.
                    // Add a JSR_EDGE to the successor.
                    // It will be replaced later by the inlined JSR subroutine.
                    subroutine.addEdgeAndExplore(basicBlock, handle.getNext(), JSR_EDGE);
                    endOfBasicBlock = true;
                } else if (opcode == Const.RET) {
                    // End of JSR subroutine
                    subroutine.addEdge(basicBlock, subroutine.getExit(), RET_EDGE);
                    endOfBasicBlock = true;
                } else {
                    TargetEnumeratingVisitor visitor = new TargetEnumeratingVisitor(handle, cpg);
                    if (visitor.isEndOfBasicBlock()) {
                        endOfBasicBlock = true;

                        // Add control edges as appropriate
                        if (visitor.instructionIsThrow()) {
                            handleExceptions(subroutine, handle, basicBlock);
                        } else if (visitor.instructionIsExit()) {
                            subroutine.setExitBlock(basicBlock);
                        } else if (visitor.instructionIsReturn()) {
                            subroutine.setReturnBlock(basicBlock);
                        } else {
                            Iterator<Target> i = visitor.targetIterator();
                            while (i.hasNext()) {
                                Target target = i.next();
                                subroutine.addEdgeAndExplore(basicBlock, target.getTargetInstruction(), target.getEdgeType());
                            }
                        }
                    }
                }

                if (!endOfBasicBlock) {
                    InstructionHandle next = handle.getNext();
                    if (next == null) {
                        throw new CFGBuilderException("Control falls off end of method: " + handle);
                    }

                    // Is the next instruction a control merge or a PEI?
                    if (isMerge(next) || isPEI(next)) {
                        subroutine.addEdgeAndExplore(basicBlock, next, FALL_THROUGH_EDGE);
                        endOfBasicBlock = true;
                    } else {
                        // Basic block continues
                        handle = next;
                    }
                }

            } while (!endOfBasicBlock);
        }
    }
private void build ( Subroutine subroutine ) throws CFGBuilderException { subroutine . addEdgeAndExplore ( subroutine . getEntry ( ) , subroutine . getStartInstruction ( ) , START_EDGE ) ; while ( subroutine . hasMoreWork ( ) ) { WorkListItem item = subroutine . nextItem ( ) ; InstructionHandle handle = item . getStartInstruction ( ) ; BasicBlock basicBlock = item . getBasicBlock ( ) ; if ( isPEI ( handle ) ) { if ( DEBUG ) { System . out . println ( "ETB block " + basicBlock . getLabel ( ) + " for " + handle ) ; } handleExceptions ( subroutine , handle , basicBlock ) ; BasicBlock body = subroutine . allocateBasicBlock ( ) ; subroutine . addEdge ( basicBlock , body , FALL_THROUGH_EDGE ) ; basicBlock = body ; } if ( DEBUG ) { System . out . println ( "BODY block " + basicBlock . getLabel ( ) + " for " + handle ) ; } if ( ! basicBlock . isEmpty ( ) ) { throw new IllegalStateException ( "Block isn't empty!" ) ; } boolean endOfBasicBlock = false ; do { Instruction ins = handle . getInstruction ( ) ; if ( DEBUG ) { System . out . println ( "BB " + basicBlock . getLabel ( ) + ": adding" + handle ) ; } basicBlock . addInstruction ( handle ) ; subroutine . addInstruction ( handle ) ; short opcode = ins . getOpcode ( ) ; if ( opcode == Const . JSR || opcode == Const . JSR_W ) { JsrInstruction jsr = ( JsrInstruction ) ins ; InstructionHandle jsrTarget = jsr . getTarget ( ) ; Subroutine jsrSubroutine = jsrSubroutineMap . get ( jsrTarget ) ; if ( jsrSubroutine == null ) { jsrSubroutine = new Subroutine ( jsrTarget ) ; jsrSubroutineMap . put ( jsrTarget , jsrSubroutine ) ; subroutineWorkList . add ( jsrSubroutine ) ; } subroutine . addEdgeAndExplore ( basicBlock , handle . getNext ( ) , JSR_EDGE ) ; endOfBasicBlock = true ; } else if ( opcode == Const . RET ) { subroutine . addEdge ( basicBlock , subroutine . getExit ( ) , RET_EDGE ) ; endOfBasicBlock = true ; } else { TargetEnumeratingVisitor visitor = new TargetEnumeratingVisitor ( handle , cpg ) ; if ( visitor . isEndOfBasicBlock ( ) ) { endOfBasicBlock = true ; if ( visitor . instructionIsThrow ( ) ) { handleExceptions ( subroutine , handle , basicBlock ) ; } else if ( visitor . instructionIsExit ( ) ) { subroutine . setExitBlock ( basicBlock ) ; } else if ( visitor . instructionIsReturn ( ) ) { subroutine . setReturnBlock ( basicBlock ) ; } else { Iterator < Target > i = visitor . targetIterator ( ) ; while ( i . hasNext ( ) ) { Target target = i . next ( ) ; subroutine . addEdgeAndExplore ( basicBlock , target . getTargetInstruction ( ) , target . getEdgeType ( ) ) ; } } } } if ( ! endOfBasicBlock ) { InstructionHandle next = handle . getNext ( ) ; if ( next == null ) { throw new CFGBuilderException ( "Control falls off end of method: " + handle ) ; } if ( isMerge ( next ) || isPEI ( next ) ) { subroutine . addEdgeAndExplore ( basicBlock , next , FALL_THROUGH_EDGE ) ; endOfBasicBlock = true ; } else { handle = next ; } } } while ( ! endOfBasicBlock ) ; } }
Build a subroutine. We iteratively add basic blocks to the subroutine
until there are no more blocks reachable from the calling context. As JSR
instructions are encountered, new Subroutines are added to the subroutine
work list.

@param subroutine
the subroutine