private final Iterator<IExplodedBasicBlock> getSuccs(IExplodedBasicBlock bb) { if (pdg.isIgnoreExceptions()) { return ecfg.getNormalSuccessors(bb).iterator(); } else { return ecfg.getSuccNodes(bb); } }
private Set<CGNode> findLoopingMethods(IProgressMonitor progress) throws CancelException { CallGraph cg = sdg.getCallGraph(); Set<CGNode> loops = HashSetFactory.make(); progress.subTask("Searching methods with potential endless loops"); for (CGNode node : cg) { IR ir = node.getIR(); if (ir != null) { ControlFlowGraph<SSAInstruction, ISSABasicBlock> cfg = ir.getControlFlowGraph(); final boolean ac = Acyclic.isAcyclic(cfg, cfg.entry()); if (!ac && !loopsAreSimple(ir)) { loops.add(node); } } else { // Conservatively assume that methods may not terminate, iff we dont // have their code loops.add(node); } progress.worked(1); } progress.done(); return loops; }
/** * Is there a path between src and dst using only non-exception controlflow * * @param src * @param dst * @return */ public boolean isInNormalSuccessors(CFGNode src, CFGNode dst) { if (pdg.isIgnoreExceptions()) { return true; } else { IExplodedBasicBlock bbSrc = node2bb.get(src); IExplodedBasicBlock bbDst = node2bb.get(dst); if (bbDst == bbSrc) { return true; } else { Collection<IExplodedBasicBlock> bbNormSucc = ecfg.getNormalSuccessors(bbSrc); return bbNormSucc.contains(bbDst); } } }
private void addPhiConstraints( CGNode node, ControlFlowGraph<SSAInstruction, ISSABasicBlock> cfg, ISSABasicBlock b) { // visit each phi instruction in each successor block for (Iterator<? extends IBasicBlock> sbs = cfg.getSuccNodes(b); sbs.hasNext(); ) { ISSABasicBlock sb = (ISSABasicBlock) sbs.next(); if (sb.isExitBlock()) { // an optimization based on invariant that exit blocks should have no // phis. continue; } int n = 0; // set n to be whichPred(this, sb); for (Iterator<? extends IBasicBlock> back = cfg.getPredNodes(sb); back.hasNext(); n++) { if (back.next() == b) { break; } } assert n < cfg.getPredNodeCount(sb); for (Iterator<SSAPhiInstruction> phis = sb.iteratePhis(); phis.hasNext(); ) { SSAPhiInstruction phi = phis.next(); if (phi == null) { continue; } PointerKey def = heapModel.getPointerKeyForLocal(node, phi.getDef()); if (phi.getUse(n) > 0) { PointerKey use = heapModel.getPointerKeyForLocal(node, phi.getUse(n)); addNode(def); addNode(use); addEdge(def, use); } // } // } } } }
private void createCFG() { for (IExplodedBasicBlock block : ecfg) { Set<CFGNode> last = lastNodesOfBB(block); Iterator<IExplodedBasicBlock> it = getSuccs(block); while (it.hasNext()) { IExplodedBasicBlock succ = it.next(); if (succ == null) { Log.warn("Basic block is null in " + Util.methodName(ecfg.getMethod())); continue; } Set<CFGNode> firstOfSucc = firstNodesOfBB(succ); for (CFGNode from : last) { for (CFGNode to : firstOfSucc) { cfg.addEdge(from, to); } } } } cfg.addEdge(entry, exit); }
public IMethod getMethod() { return ecfg.getMethod(); }
private void createFirstAndLastNodes(IExplodedBasicBlock block) { final SSAInstruction instr = block.getInstruction(); if (block == ecfg.entry()) { assert (entry == null); CFGNode cfgNode = createNode(block); Set<CFGNode> first = HashSetFactory.make(1); first.add(cfgNode); firstNodes.put(block, first); entry = cfgNode; Set<? extends AbstractParameterNode> after = getAllHeapLocatedFormIns(); CFGNode current = cfgNode; for (AbstractParameterNode p : after) { CFGNode param = findOrCreateNode(block, p); cfg.addEdge(current, param); current = param; numberOfParameterNodes++; } if (instr != null) { AbstractPDGNode node = pdg.getMainNodeForInstruction(instr); if (node != null) { CFGNode artificialNode = createArtificialNode(block, node); cfg.addEdge(current, artificialNode); current = artificialNode; } } Set<CFGNode> last = HashSetFactory.make(1); last.add(current); lastNodes.put(block, last); } else if (block == ecfg.exit()) { assert (exit == null); CFGNode cfgNode = createNode(block); Set<AbstractParameterNode> before = getAllHeapLocatedFormOuts(); if (!pdg.isIgnoreExceptions() && pdg.getExceptionalExit() != null) { before.add(pdg.getExceptionalExit()); } if (before.isEmpty()) { Set<CFGNode> first = HashSetFactory.make(1); first.add(cfgNode); firstNodes.put(block, first); } else { CFGNode current = null; for (AbstractParameterNode p : before) { CFGNode param = findOrCreateNode(block, p); if (current == null) { Set<CFGNode> first = HashSetFactory.make(1); first.add(param); firstNodes.put(block, first); } else { cfg.addEdge(current, param); } current = param; numberOfParameterNodes++; } cfg.addEdge(current, cfgNode); } exit = cfgNode; Set<CFGNode> last = HashSetFactory.make(1); last.add(cfgNode); lastNodes.put(block, last); } else if (block.isCatchBlock() && instr != null) { // special case where a single cfg node corresponds to 2 statements... CFGNode cfgNode = createNode(block); Set<CFGNode> first = HashSetFactory.make(1); first.add(cfgNode); firstNodes.put(block, first); AbstractPDGNode pdgNode = pdg.getMainNodeForInstruction(instr); CFGNode lastNode = createArtificialNode(block, pdgNode); Set<CFGNode> last = HashSetFactory.make(1); last.add(lastNode); lastNodes.put(block, last); cfg.addEdge(cfgNode, lastNode); List<AbstractPDGNode> nodes = pdg.getNodesForInstruction(instr); for (AbstractPDGNode node : nodes) { if (node instanceof ExpressionNode) { sdg2cfg.put((ExpressionNode) node, lastNode); } } } else if (instr instanceof SSAInvokeInstruction) { // method call found - add actual in nodes before and actual-out // nodes after the call Set<CFGNode> first = HashSetFactory.make(); Set<CFGNode> last = HashSetFactory.make(); Set<CallNode> calls = getCallsForInstruction((SSAInvokeInstruction) instr); CFGNode compoundCallNode = null; if (calls.size() > 1) { compoundCallNode = createNode(block); first.add(compoundCallNode); } for (CallNode call : calls) { CFGNode cfgNode = createNode(block, call); Set<? extends AbstractParameterNode> actIns = getAllHeapLocatedActualIns(call); numberOfParameterNodes += actIns.size(); if (actIns.size() == 0) { if (compoundCallNode == null) { first.add(cfgNode); } else { cfg.addEdge(compoundCallNode, cfgNode); } } else { CFGNode current = null; for (AbstractParameterNode p : actIns) { CFGNode param = findOrCreateNode(block, p); if (current == null) { if (compoundCallNode == null) { first.add(param); } else { cfg.addEdge(compoundCallNode, param); } } else { cfg.addEdge(current, param); } current = param; } cfg.addEdge(current, cfgNode); } Set<? extends AbstractParameterNode> actOuts = getAllHeapLocatedActualOuts(call); numberOfParameterNodes += actOuts.size(); CFGNode current = cfgNode; for (AbstractParameterNode p : actOuts) { CFGNode param = findOrCreateNode(block, p); cfg.addEdge(current, param); current = param; } last.add(current); } firstNodes.put(block, first); lastNodes.put(block, last); } else { CFGNode cfgNode = createNode(block); AbstractPDGNode node = null; if (instr != null) { node = pdg.getMainNodeForInstruction(instr); } if (node instanceof ExpressionNode) { ExpressionNode expr = (ExpressionNode) node; sdg2cfg.put((ExpressionNode) node, cfgNode); if (expr.isFieldAccess() || expr.isArrayAccess()) { Set<CFGNode> first = HashSetFactory.make(1); Set<CFGNode> last = HashSetFactory.make(1); last.add(cfgNode); CFGNode pred = null; if (!expr.isStaticFieldAccess()) { CFGNode baseCfg = createArtificialNode(block, expr.getBaseValue()); first.add(baseCfg); pred = baseCfg; } if (expr.isArrayAccess()) { CFGNode indexCfg = createArtificialNode(block, expr.getIndexValue()); if (pred != null) { cfg.addEdge(pred, indexCfg); } else { first.add(indexCfg); } pred = indexCfg; } if (expr.isGet()) { CFGNode fieldCfg = createArtificialNode(block, expr.getFieldValue()); if (pred != null) { cfg.addEdge(pred, fieldCfg); } else { first.add(fieldCfg); } pred = fieldCfg; } if (expr.isSet()) { CFGNode valCfg = createArtificialNode(block, expr.getSetValue()); if (pred != null) { cfg.addEdge(pred, valCfg); } else { first.add(valCfg); } pred = valCfg; } if (pred != null) { cfg.addEdge(pred, cfgNode); } else { first.add(cfgNode); } firstNodes.put(block, first); lastNodes.put(block, last); } else { Set<CFGNode> firstAndLast = HashSetFactory.make(1); firstAndLast.add(cfgNode); firstNodes.put(block, firstAndLast); lastNodes.put(block, firstAndLast); } } else { Set<CFGNode> firstAndLast = HashSetFactory.make(1); firstAndLast.add(cfgNode); firstNodes.put(block, firstAndLast); lastNodes.put(block, firstAndLast); } } }
@SuppressWarnings("unused") private boolean loopsAreSimple( ControlFlowGraph<SSAInstruction, ISSABasicBlock> cfg, Set<ISSABasicBlock> scc) throws CancelException { boolean isSimple = true; MutableIntSet sccInts = MutableSparseIntSet.createMutableSparseIntSet(scc.size()); for (ISSABasicBlock bb : scc) { sccInts.add(cfg.getNumber(bb)); } boolean noExit = true; for (ISSABasicBlock bb : scc) { if (cfg.getSuccNodeCount(bb) > 1 && !cfg.getSuccNodeNumbers(bb).isSubset(sccInts)) { noExit = false; // if preds are no subset of the scc block we have a jump to the outside of the scc SSAInstruction last = bb.getLastInstruction(); int[] uses = new int[last.getNumberOfUses()]; for (int i = 0; i < uses.length; i++) { uses[i] = last.getUse(i); } TransitiveDataDependence tdep = new TransitiveDataDependence(scc); tdep.solve(null); for (ISSABasicBlock bb2 : scc) { if (bb2 == bb) { continue; } for (SSAInstruction ii : bb2) { for (int use : uses) { isSimple &= !tdep.influences(ii, use); } // IntSet is = tdep.influences((SSAInstruction) ii); // System.err.println(ii + ": " + is); if (!isSimple) { break; } } if (!isSimple) { break; } } // TODO check if condition is simple... // if (isSimple) { // System.err.println("Simple: " + last + " -> " + // PrettyWalaNames.methodName(bb.getMethod())); // } else { // System.err.println("Not Simple: " + last + " -> " + // PrettyWalaNames.methodName(bb.getMethod())); // } if (!isSimple) { break; } } } return isSimple && !noExit; }