private boolean checkIds(CFANode node) { // This is the (original) recursive algorithm. // We keep this implementation as an assertion check // to check that the non-recursive algorithm assigns exactly(!) the same ids. // Even slight variations have been found to cause performance differences, // although we are not sure why. if (!visited.add(node)) { // already handled, do nothing return true; } for (CFANode successor : CFAUtils.successorsOf(node)) { checkIds(successor); } // node.setReversePostorderId(reversePostorderId2++); assert node.getReversePostorderId() == reversePostorderId2++ : "Node " + node + " got " + node.getReversePostorderId() + ", but should get " + (reversePostorderId2 - 1); return true; }
private void step4() { for (int i = 2; i < n; i++) { CFANode w = vertex.get(i); NodeInfo infow = map.get(w); CFANode d = dom.get(w); if (!(d.equals(vertex.get(infow.semi)))) { CFANode dd = dom.get(d); dom.put(d, dd); } } if (mode == 0) { dom.put(entry, null); } else { dom.put(exit, null); } }
private void dfs(CFANode pNode) { NodeInfo infov = map.get(pNode); n = n + 1; infov.semi = n; vertex.set(n, pNode); infov.label = pNode; infov.ancestor = null; int m; if (mode == 0) { m = pNode.getNumLeavingEdges(); } else { m = pNode.getNumEnteringEdges(); } FunctionSummaryEdge e; CFANode w; if (mode == 0) { e = pNode.getLeavingSummaryEdge(); } else { e = pNode.getEnteringSummaryEdge(); } if (e != null) { if (mode == 0) { w = e.getSuccessor(); } else { w = e.getPredecessor(); } NodeInfo infow = map.get(w); if (infow.semi == 0) { infow.parent = pNode; dfs(w); } infow.pred.add(pNode); } // else{ for (int i = 0; i < m; i++) { if (mode == 0) { w = pNode.getLeavingEdge(i).getSuccessor(); } else { w = pNode.getEnteringEdge(i).getPredecessor(); } NodeInfo infow = map.get(w); if (infow.semi == 0) { infow.parent = pNode; dfs(w); } infow.pred.add(pNode); } // } }
public void assignSorting(final CFANode start) { // This is an iterative version of the original algorithm that is now in checkIds(). // We store the state of the function in two stacks: // - the current node (variable "node" in checkIds()) // - the iterator over the current node's successors (this is state hidden in the for-each loop // in checkIds()) // Together, these two items form a "stack frame". final Set<CFANode> visited = new HashSet<>(); final Deque<CFANode> nodeStack = new ArrayDeque<>(); final Deque<Iterator<CFANode>> iteratorStack = new LinkedList<>(); // ArrayDeque doesn't work here because we store nulls nodeStack.push(start); iteratorStack.push(null); while (!nodeStack.isEmpty()) { assert nodeStack.size() == iteratorStack.size(); final CFANode node = nodeStack.peek(); Iterator<CFANode> successors = iteratorStack.peek(); if (successors == null) { // Entering this stack frame. // This part of the code corresponds to the code in checkIds() // before the for loop. if (!visited.add(node)) { // already handled, do nothing // Do a simulated "return". nodeStack.pop(); iteratorStack.pop(); continue; } // enter the for loop successors = CFAUtils.successorsOf(node).iterator(); iteratorStack.pop(); iteratorStack.push(successors); } if (successors.hasNext()) { // "recursive call" // This part of the code corresponds to the code in checkIds() // during the loop. CFANode successor = successors.next(); // Do a simulated "function call" by pushing something on the stacks, // creating a new stack frame. nodeStack.push(successor); iteratorStack.push(null); } else { // All children handled. // This part of the code corresponds to the code in checkIds() // after the loop. node.setReversePostorderId(reversePostorderId++); // Do a simulated "return". nodeStack.pop(); iteratorStack.pop(); } } assert checkIds(start); }
public void writeCoverageReport( final PrintStream pStatisticsOutput, final ReachedSet pReached, final CFA pCfa) { if (!enabled) { return; } Multiset<FunctionEntryNode> reachedLocations = getFunctionEntriesFromReached(pReached); Map<String, FileCoverageInformation> infosPerFile = new HashMap<>(); // Add information about existing functions for (FunctionEntryNode entryNode : pCfa.getAllFunctionHeads()) { final FileLocation loc = entryNode.getFileLocation(); if (loc.getStartingLineNumber() == 0) { // dummy location continue; } final String functionName = entryNode.getFunctionName(); final FileCoverageInformation infos = getFileInfoTarget(loc, infosPerFile); final int startingLine = loc.getStartingLineInOrigin(); final int endingLine = loc.getEndingLineInOrigin(); infos.addExistingFunction(functionName, startingLine, endingLine); if (reachedLocations.contains(entryNode)) { infos.addVisitedFunction(entryNode.getFunctionName(), reachedLocations.count(entryNode)); } } // Add information about existing locations for (CFANode node : pCfa.getAllNodes()) { for (int i = 0; i < node.getNumLeavingEdges(); i++) { handleExistedEdge(node.getLeavingEdge(i), infosPerFile); } } Set<CFANode> reachedNodes = from(pReached).transform(EXTRACT_LOCATION).filter(notNull()).toSet(); // Add information about visited locations for (AbstractState state : pReached) { ARGState argState = AbstractStates.extractStateByType(state, ARGState.class); if (argState != null) { for (ARGState child : argState.getChildren()) { if (!child.isCovered()) { List<CFAEdge> edges = argState.getEdgesToChild(child); if (edges.size() > 1) { for (CFAEdge innerEdge : edges) { handleCoveredEdge(innerEdge, infosPerFile); } // BAM produces paths with no edge connection thus the list will be empty } else if (!edges.isEmpty()) { handleCoveredEdge(Iterables.getOnlyElement(edges), infosPerFile); } } } } else { // Simple kind of analysis // Cover all edges from reached nodes // It is less precise, but without ARG it is impossible to know what path we chose CFANode node = AbstractStates.extractLocation(state); for (int i = 0; i < node.getNumLeavingEdges(); i++) { CFAEdge edge = node.getLeavingEdge(i); if (reachedNodes.contains(edge.getSuccessor())) { handleCoveredEdge(edge, infosPerFile); } } } } for (CoverageWriter w : reportWriters) { w.write(infosPerFile, pStatisticsOutput); } }