/** * Constructs the online graph for the analysis. Additionally an offline graph for HCD is * constructed to speed up the computation of the dynamic transitive closure with it. * * @param bConstr List of all {@link BaseConstraint}s that should be considered.<br> * A {@link BaseConstraint} leads to an entry in a nodes points-to set. * @param sConstr List of all {@link SimpleConstraint}s that should be considered.<br> * A {@link SimpleConstraint} represents an edge in the graph. * @param cConstr List of all {@link ComplexConstraint}s that should be considered.<br> * {@link ComplexConstraint}s are stored in nodes, so they can be accessed faster when * computing the dynamic transitive closure. * @param g The resulting graph. Should be empty. */ private static void buildGraph( Set<BaseConstraint> bConstr, Set<SimpleConstraint> sConstr, Set<ComplexConstraint> cConstr, DirectedGraph g) { // HCD offline - build offline graph List<List<String>> sccs = buildOfflineGraphAndFindSCCs(sConstr, cConstr); // build online graph for (BaseConstraint bc : bConstr) { DirectedGraph.Node n = g.getNode(bc.getSuperVar()); n.addPointerTarget(bc.getSubVar()); } for (SimpleConstraint sc : sConstr) { DirectedGraph.Node src = g.getNode(sc.getSubVar()); DirectedGraph.Node dest = g.getNode(sc.getSuperVar()); g.addEdge(src, dest); } for (ComplexConstraint cc : cConstr) { DirectedGraph.Node n; if (cc.isSubDerefed()) { n = g.getNode(cc.getSubVar()); n.complexConstrMeSub.add(cc.getSuperVar()); } else { n = g.getNode(cc.getSuperVar()); n.complexConstrMeSuper.add(cc.getSubVar()); } } // for HCD mergeOrMarkSCCs(g, sccs); // ... in online graph }
/** * Merges all non-ref nodes in an SCC. For every ref-node the last remaining non-ref Node is * stored. * * @param g The (online) points-to graph for the analysis. * @param sccs List of all found SCCs in the offline version of the graph. */ private static void mergeOrMarkSCCs(DirectedGraph g, List<List<String>> sccs) { for (List<String> scc : sccs) { LinkedList<DirectedGraph.Node> refNodes = new LinkedList<>(); LinkedList<DirectedGraph.Node> normNodes = new LinkedList<>(); for (String n : scc) { // translate to new node if (n.charAt(0) == '*') { refNodes.add(g.getNode(n.substring(1))); } else { normNodes.add(g.getNode(n)); } } DirectedGraph.Node merged = g.mergeNodes(normNodes.poll(), normNodes); for (DirectedGraph.Node n : refNodes) { n.mergePts = merged; } } }
/** * Recursive part of tarjans algorithm to find strongly connected components. Algorithm is e.g. * described in <a * href="http://en.wikipedia.org/wiki/Tarjan's_strongly_connected_components_algorithm">wikipedia</a> * * @param maxdfs The current value for maxdfs. * @param v The current Node to process. * @param workset Set of all unreached Nodes. * @param stack Temporary datastructure for algorithm. * @param nodeStrMap Because the sccs are returned as a list of variables (i.e. Strings), the * mapping from Node to String must be given. * @param sccs All found strongly connected components are added to this list. * @return an updated value for maxdfs. */ private static int tarjan( int maxdfs, DirectedGraph.Node v, Set<DirectedGraph.Node> workset, LinkedList<DirectedGraph.Node> stack, Map<DirectedGraph.Node, String> nodeStrMap, List<List<String>> sccs) { v.dfs = maxdfs; v.lowlink = maxdfs; maxdfs++; stack.push(v); workset.remove(v); for (DirectedGraph.Node succ : v.getSuccessors()) { if (workset.contains(succ)) { maxdfs = tarjan(maxdfs, succ, workset, stack, nodeStrMap, sccs); v.lowlink = Math.min(v.lowlink, succ.lowlink); } else if (succ.dfs > 0) { // <==> stack.contains(succ) v.lowlink = Math.min(v.lowlink, succ.dfs); } } if (v.lowlink == v.dfs) { DirectedGraph.Node succ; LinkedList<String> scc = new LinkedList<>(); do { succ = stack.pop(); succ.dfs = -succ.dfs; scc.add(nodeStrMap.get(succ)); } while (!succ.equals(v)); if (scc.size() > 1) { sccs.add(scc); } } return maxdfs; }
/** * Computes the dynamic transitive closure of the given constraint system and writes the resulting * points-to sets to the {@link Map} <code>ptSets</code>. * * @param bConstr {@link Set} of {@link BaseConstraint}s in the constraint system. * @param sConstr {@link Set} of {@link SimpleConstraint}s in the constraint system. * @param cConstr {@link Set} of {@link ComplexConstraint}s in the constraint system. * @param ptSets Writes all found points-to relations to this {@link Map}.<br> * <i>Note:</i> The map is cleared, before the results are written. */ private static void computeDynTransitiveClosure( Set<BaseConstraint> bConstr, Set<SimpleConstraint> sConstr, Set<ComplexConstraint> cConstr, Map<String, String[]> ptSets) { // build initial graph DirectedGraph g = new DirectedGraph(); buildGraph(bConstr, sConstr, cConstr, g); HashSet<DirectedGraph.Node> workset = new HashSet<>(); // add all nodes in graph to the initial workset for (Map.Entry<String, DirectedGraph.Node> entry : g.getNameMappings()) { workset.add(entry.getValue()); } HashSet<DirectedGraph.Edge> tested = new HashSet<>(); // dynamic transitive closure while (!workset.isEmpty()) { DirectedGraph.Node n = workset.iterator().next(); workset.remove(n); if (!n.isValid()) { // node is invalid, if it was merged into another one continue; } // two lines for HCD if (n.mergePts != null) { g.mergeNodes(n.mergePts, n.getPointsToNodesSet()); } for (DirectedGraph.Node v : n.getPointsToNodesSet()) { for (String aStr : n.complexConstrMeSub) { DirectedGraph.Node a = g.getNode(aStr); if (!v.isSuccessor(a)) { g.addEdge(v, a); workset.add(v); } } for (String bStr : n.complexConstrMeSuper) { DirectedGraph.Node b = g.getNode(bStr); if (!b.isSuccessor(v)) { g.addEdge(b, v); workset.add(b); } } } // for (String vStr : n.pointsToSet) for (DirectedGraph.Node z : n.getSuccessors()) { // LCD code DirectedGraph.Edge edge = new DirectedGraph.Edge(n, z); if (z.getPointsToSet().equals(n.getPointsToSet()) && !tested.contains(edge)) { tested.add(edge); DirectedGraph.Node merged = g.detectAndCollapseCycleContainingEdge(edge); if (merged != null) { workset.add(merged); break; } } else /* END LCD code */ if (n.propagatePointerTargetsTo(z)) { workset.add(z); } } } // while (!workset.isEmpty()) // clear result map ptSets.clear(); // write results to map for (Map.Entry<String, DirectedGraph.Node> e : g.getNameMappings()) { Collection<String> ptSetNode = e.getValue().getPointsToSet(); ptSets.put(e.getKey(), ptSetNode.toArray(new String[ptSetNode.size()])); } }