/** * Create the edges in the control flow graph with the basic blocks. * * @param insts the instructions * @param numBlocks an array containing the number of basic block for each instruction. * @param bbs the basic blocks */ private void findCFGEdges(Instruction[] insts, short[] numBlocks, BasicBlock[] bbs) { for (int i = 0; i < bbs.length; ++i) { BasicBlock bb = bbs[i]; Instruction lastInst = insts[bb.getEnd()]; if (lastInst.canComplete() && i != bbs.length - 1) { // the next block is accessible bb.addDefaultNextBlock(bbs[i + 1]); } if (lastInst instanceof JumpInstruction) { // goto, jsr are distincts than other jump instructions. Edge edge; JumpInstruction jumpInst = (JumpInstruction) lastInst; if (lastInst.getOpcode() == ClassfileConstants2.opc_goto) { edge = bb.addDefaultNextBlock( bbs[numBlocks[getInstructionLine(insts, jumpInst.getTarget())]]); jumpInst.setTarget(new EdgeLabel(edge)); } else if (lastInst.getOpcode() == ClassfileConstants2.opc_jsr) { // do nothing here // see method findSubRoutines } else { edge = bb.addConditionNextBlock( bbs[numBlocks[getInstructionLine(insts, jumpInst.getTarget())]]); jumpInst.setTarget(new EdgeLabel(edge)); } } if (lastInst instanceof SwitchInstruction) { SwitchInstruction si = (SwitchInstruction) lastInst; for (int k = -1; k < si.getSwitchCount(); k++) { Edge edge = bb.addSwitchNextBlock(bbs[numBlocks[getInstructionLine(insts, si.getTarget(k))]]); si.setTarget(k, new EdgeLabel(edge)); } } } }
/** * Find subroutines in the method. Create an object SubRoutine for each one. Add the edges. * * @param numBlocks an array containing the number of basic block for each instruction. * @param insts the instructions * @param bbs the basic blocks */ public void findSubRoutines(short[] numBlocks, final Instruction[] insts, BasicBlock[] bbs) { for (int i = 0; i < bbs.length; ++i) { Instruction lastInst = insts[bbs[i].getEnd()]; if (lastInst.getOpcode() == ClassfileConstants2.opc_jsr) { JumpInstruction jumpInst = (JumpInstruction) lastInst; BasicBlock subroutineCall = bbs[i]; BasicBlock subroutineReturn = bbs[i + 1]; final BasicBlock startSubroutine = bbs[numBlocks[getInstructionLine(insts, jumpInst.getTarget())]]; SubRoutine sub = (SubRoutine) subroutines.get(startSubroutine); if (sub == null) { startSubroutine.setFirstBlockSubroutine(true); // we have to create the SubRoutine object // so we research the end block of the subroutine // we follow a path from start block until we find the ret final Map subs = subroutines; final BasicBlock currentBB = startSubroutine; // the search will not enter into nested subroutine // because there is an edge after a block with // a jsr and its next block. graph.visitGraphFromNode( currentBB, new NodeVisitor() { public boolean visit(Node n) { BasicBlock bb = (BasicBlock) n; Instruction last = insts[bb.getEnd()]; if (last.getOpcode() == ClassfileConstants2.opc_ret) { // we found the end of the subroutine SubRoutine s = new SubRoutine(startSubroutine, currentBB); subs.put(startSubroutine, s); return false; } return true; } }); if ((sub = (SubRoutine) subroutines.get(startSubroutine)) == null) { // error throw new RuntimeException("NO RETURN TO SUBROUTINE"); } } // add edges Edge edgeCall = subroutineCall.addSubRoutineCallNextBlock(startSubroutine); jumpInst.setTarget(new EdgeLabel(edgeCall)); Edge edgeReturn = sub.getEnd().addSubRoutineReturnNextBlock(subroutineReturn); sub.addCall(edgeCall, edgeReturn); } } // remove all edges from basic blocks which end by jsr with // its next block. for (int i = 0; i < bbs.length; ++i) { Instruction lastInst = insts[bbs[i].getEnd()]; if (lastInst.getOpcode() == ClassfileConstants2.opc_jsr) { BasicBlock subroutineCall = bbs[i]; BasicBlock subroutineReturn = bbs[i + 1]; subroutineCall.removeSuccessor(subroutineReturn); } } }