Loading src/main/java/tfm/graphs/Graph.java +2 −1 Original line number Diff line number Diff line Loading @@ -88,7 +88,8 @@ public abstract class Graph extends DirectedPseudograph<GraphNode<?>, Arc> { @Override public String toString() { return vertexSet().stream().sorted() return vertexSet().stream() .sorted(Comparator.comparingInt(GraphNode::getId)) .map(GraphNode::toString) .collect(Collectors.joining(System.lineSeparator())); } Loading src/main/java/tfm/graphs/augmented/ACFGBuilder.java +1 −2 Original line number Diff line number Diff line Loading @@ -243,7 +243,6 @@ public class ACFGBuilder extends CFGBuilder { methodDeclaration.getBody().get().accept(this, arg); returnList.stream().filter(node -> !hangingNodes.contains(node)).forEach(hangingNodes::add); nonExecHangingNodes.add(graph.getRootNode().get()); GraphNode<EmptyStmt> exitNode = connectTo(new EmptyStmt(), "Exit"); ((ACFG) graph).setExitNode(exitNode); connectTo(new EmptyStmt(), "Exit"); } } src/main/java/tfm/graphs/cfg/CFG.java +0 −20 Original line number Diff line number Diff line Loading @@ -20,7 +20,6 @@ import java.util.Set; */ public class CFG extends GraphWithRootNode<MethodDeclaration> { private boolean built = false; protected GraphNode<?> exitNode; public CFG() { super(); Loading Loading @@ -63,28 +62,9 @@ public class CFG extends GraphWithRootNode<MethodDeclaration> { return res; } @Override public boolean removeVertex(GraphNode<?> graphNode) { if (Objects.equals(graphNode, exitNode)) return false; return super.removeVertex(graphNode); } public GraphNode<?> getExitNode() { return exitNode; } protected void setExitNode(GraphNode<?> exitNode) { if (this.exitNode != null) throw new IllegalStateException("Exit node already set!"); this.exitNode = exitNode; } @Override public void build(MethodDeclaration method) { method.accept(newCFGBuilder(), null); if (exitNode == null) throw new IllegalStateException("Exit node missing!"); built = true; } Loading src/main/java/tfm/graphs/cfg/CFGBuilder.java +1 −2 Original line number Diff line number Diff line Loading @@ -275,7 +275,6 @@ public class CFGBuilder extends VoidVisitorAdapter<Void> { hangingNodes.add(graph.getRootNode().get()); methodDeclaration.getBody().get().accept(this, arg); returnList.stream().filter(node -> !hangingNodes.contains(node)).forEach(hangingNodes::add); GraphNode<EmptyStmt> exitNode = connectTo(new EmptyStmt(), "Exit"); graph.setExitNode(exitNode); connectTo(new EmptyStmt(), "Exit"); } } src/main/java/tfm/graphs/pdg/ControlDependencyBuilder.java +75 −10 Original line number Diff line number Diff line package tfm.graphs.pdg; import tfm.arcs.Arc; import tfm.graphs.augmented.PPDG; import tfm.graphs.cfg.CFG; import tfm.nodes.GraphNode; import tfm.nodes.NodeFactory; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; /** * A simple but slow finder of control dependencies. Loading Loading @@ -29,21 +38,77 @@ class ControlDependencyBuilder { } public void analyze() { Map<GraphNode<?>, GraphNode<?>> nodeMap = new HashMap<>(); assert cfg.getRootNode().isPresent(); assert pdg.getRootNode().isPresent(); nodeMap.put(cfg.getRootNode().get(), pdg.getRootNode().get()); Set<GraphNode<?>> roots = new HashSet<>(cfg.vertexSet()); roots.remove(cfg.getRootNode().get()); Set<GraphNode<?>> cfgNodes = new HashSet<>(cfg.vertexSet()); cfgNodes.removeIf(node -> node.getInstruction().equals("Exit")); for (GraphNode<?> node : cfgNodes) registerNode(node, nodeMap); for (GraphNode<?> src : cfgNodes) { for (GraphNode<?> dest : cfgNodes) { if (src == dest) continue; if (hasControlDependence(src, dest)) { pdg.addControlDependencyArc(nodeMap.get(src), nodeMap.get(dest)); roots.remove(dest); } } } // In the original definition, nodes were dependent by default on the Enter/Start node for (GraphNode<?> node : roots) if (!node.getInstruction().equals("Exit")) pdg.addControlDependencyArc(pdg.getRootNode().get(), nodeMap.get(node)); } boolean needsStartEndEdge = !cfg.containsEdge(cfg.getRootNode().get(), cfg.getExitNode()); if (needsStartEndEdge) cfg.addControlFlowEdge(cfg.getRootNode().get(), cfg.getExitNode()); public void registerNode(GraphNode<?> node, Map<GraphNode<?>, GraphNode<?>> nodeMap) { if (nodeMap.containsKey(node) || node.getInstruction().equals("Exit")) return; GraphNode<?> clone = NodeFactory.graphNode(node.getId(), node.getInstruction(), node.getAstNode()); nodeMap.put(node, clone); pdg.addVertex(clone); } PostdominatorTree tree = new PostdominatorTree(cfg); public boolean hasControlDependence(GraphNode<?> a, GraphNode<?> b) { int yes = 0; Set<Arc> list = cfg.outgoingEdgesOf(a); // Nodes with less than 1 outgoing arc cannot control another node. if (cfg.outDegreeOf(a) < 2) return false; for (Arc arc : cfg.outgoingEdgesOf(a)) { GraphNode<?> successor = cfg.getEdgeTarget(arc); if (postdominates(successor, b)) yes++; } int no = list.size() - yes; return yes > 0 && no > 0; } for (GraphNode<?> src : pdg.vertexSet()) for (GraphNode<?> dest : tree.controlDependenciesOf(cfg, src)) if (!src.equals(dest)) pdg.addControlDependencyArc(src, dest); public boolean postdominates(GraphNode<?> a, GraphNode<?> b) { return postdominates(a, b, new HashSet<>()); } if (needsStartEndEdge) cfg.removeEdge(cfg.getRootNode().get(), cfg.getExitNode()); private boolean postdominates(GraphNode<?> a, GraphNode<?> b, Set<GraphNode<?>> visited) { // Stop w/ success if a == b or a has already been visited if (a.equals(b) || visited.contains(a)) return true; Set<Arc> outgoing = cfg.outgoingEdgesOf(a); // Limit the traversal if it is a PPDG if (pdg instanceof PPDG) outgoing = outgoing.stream().filter(Arc::isExecutableControlFlowArc).collect(Collectors.toSet()); // Stop w/ failure if there are no edges to traverse from a if (outgoing.isEmpty()) return false; // Find all possible paths starting from a, if ALL find b, then true, else false visited.add(a); for (Arc out : outgoing) { if (!postdominates(cfg.getEdgeTarget(out), b, visited)) return false; } return true; } } Loading
src/main/java/tfm/graphs/Graph.java +2 −1 Original line number Diff line number Diff line Loading @@ -88,7 +88,8 @@ public abstract class Graph extends DirectedPseudograph<GraphNode<?>, Arc> { @Override public String toString() { return vertexSet().stream().sorted() return vertexSet().stream() .sorted(Comparator.comparingInt(GraphNode::getId)) .map(GraphNode::toString) .collect(Collectors.joining(System.lineSeparator())); } Loading
src/main/java/tfm/graphs/augmented/ACFGBuilder.java +1 −2 Original line number Diff line number Diff line Loading @@ -243,7 +243,6 @@ public class ACFGBuilder extends CFGBuilder { methodDeclaration.getBody().get().accept(this, arg); returnList.stream().filter(node -> !hangingNodes.contains(node)).forEach(hangingNodes::add); nonExecHangingNodes.add(graph.getRootNode().get()); GraphNode<EmptyStmt> exitNode = connectTo(new EmptyStmt(), "Exit"); ((ACFG) graph).setExitNode(exitNode); connectTo(new EmptyStmt(), "Exit"); } }
src/main/java/tfm/graphs/cfg/CFG.java +0 −20 Original line number Diff line number Diff line Loading @@ -20,7 +20,6 @@ import java.util.Set; */ public class CFG extends GraphWithRootNode<MethodDeclaration> { private boolean built = false; protected GraphNode<?> exitNode; public CFG() { super(); Loading Loading @@ -63,28 +62,9 @@ public class CFG extends GraphWithRootNode<MethodDeclaration> { return res; } @Override public boolean removeVertex(GraphNode<?> graphNode) { if (Objects.equals(graphNode, exitNode)) return false; return super.removeVertex(graphNode); } public GraphNode<?> getExitNode() { return exitNode; } protected void setExitNode(GraphNode<?> exitNode) { if (this.exitNode != null) throw new IllegalStateException("Exit node already set!"); this.exitNode = exitNode; } @Override public void build(MethodDeclaration method) { method.accept(newCFGBuilder(), null); if (exitNode == null) throw new IllegalStateException("Exit node missing!"); built = true; } Loading
src/main/java/tfm/graphs/cfg/CFGBuilder.java +1 −2 Original line number Diff line number Diff line Loading @@ -275,7 +275,6 @@ public class CFGBuilder extends VoidVisitorAdapter<Void> { hangingNodes.add(graph.getRootNode().get()); methodDeclaration.getBody().get().accept(this, arg); returnList.stream().filter(node -> !hangingNodes.contains(node)).forEach(hangingNodes::add); GraphNode<EmptyStmt> exitNode = connectTo(new EmptyStmt(), "Exit"); graph.setExitNode(exitNode); connectTo(new EmptyStmt(), "Exit"); } }
src/main/java/tfm/graphs/pdg/ControlDependencyBuilder.java +75 −10 Original line number Diff line number Diff line package tfm.graphs.pdg; import tfm.arcs.Arc; import tfm.graphs.augmented.PPDG; import tfm.graphs.cfg.CFG; import tfm.nodes.GraphNode; import tfm.nodes.NodeFactory; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; /** * A simple but slow finder of control dependencies. Loading Loading @@ -29,21 +38,77 @@ class ControlDependencyBuilder { } public void analyze() { Map<GraphNode<?>, GraphNode<?>> nodeMap = new HashMap<>(); assert cfg.getRootNode().isPresent(); assert pdg.getRootNode().isPresent(); nodeMap.put(cfg.getRootNode().get(), pdg.getRootNode().get()); Set<GraphNode<?>> roots = new HashSet<>(cfg.vertexSet()); roots.remove(cfg.getRootNode().get()); Set<GraphNode<?>> cfgNodes = new HashSet<>(cfg.vertexSet()); cfgNodes.removeIf(node -> node.getInstruction().equals("Exit")); for (GraphNode<?> node : cfgNodes) registerNode(node, nodeMap); for (GraphNode<?> src : cfgNodes) { for (GraphNode<?> dest : cfgNodes) { if (src == dest) continue; if (hasControlDependence(src, dest)) { pdg.addControlDependencyArc(nodeMap.get(src), nodeMap.get(dest)); roots.remove(dest); } } } // In the original definition, nodes were dependent by default on the Enter/Start node for (GraphNode<?> node : roots) if (!node.getInstruction().equals("Exit")) pdg.addControlDependencyArc(pdg.getRootNode().get(), nodeMap.get(node)); } boolean needsStartEndEdge = !cfg.containsEdge(cfg.getRootNode().get(), cfg.getExitNode()); if (needsStartEndEdge) cfg.addControlFlowEdge(cfg.getRootNode().get(), cfg.getExitNode()); public void registerNode(GraphNode<?> node, Map<GraphNode<?>, GraphNode<?>> nodeMap) { if (nodeMap.containsKey(node) || node.getInstruction().equals("Exit")) return; GraphNode<?> clone = NodeFactory.graphNode(node.getId(), node.getInstruction(), node.getAstNode()); nodeMap.put(node, clone); pdg.addVertex(clone); } PostdominatorTree tree = new PostdominatorTree(cfg); public boolean hasControlDependence(GraphNode<?> a, GraphNode<?> b) { int yes = 0; Set<Arc> list = cfg.outgoingEdgesOf(a); // Nodes with less than 1 outgoing arc cannot control another node. if (cfg.outDegreeOf(a) < 2) return false; for (Arc arc : cfg.outgoingEdgesOf(a)) { GraphNode<?> successor = cfg.getEdgeTarget(arc); if (postdominates(successor, b)) yes++; } int no = list.size() - yes; return yes > 0 && no > 0; } for (GraphNode<?> src : pdg.vertexSet()) for (GraphNode<?> dest : tree.controlDependenciesOf(cfg, src)) if (!src.equals(dest)) pdg.addControlDependencyArc(src, dest); public boolean postdominates(GraphNode<?> a, GraphNode<?> b) { return postdominates(a, b, new HashSet<>()); } if (needsStartEndEdge) cfg.removeEdge(cfg.getRootNode().get(), cfg.getExitNode()); private boolean postdominates(GraphNode<?> a, GraphNode<?> b, Set<GraphNode<?>> visited) { // Stop w/ success if a == b or a has already been visited if (a.equals(b) || visited.contains(a)) return true; Set<Arc> outgoing = cfg.outgoingEdgesOf(a); // Limit the traversal if it is a PPDG if (pdg instanceof PPDG) outgoing = outgoing.stream().filter(Arc::isExecutableControlFlowArc).collect(Collectors.toSet()); // Stop w/ failure if there are no edges to traverse from a if (outgoing.isEmpty()) return false; // Find all possible paths starting from a, if ALL find b, then true, else false visited.add(a); for (Arc out : outgoing) { if (!postdominates(cfg.getEdgeTarget(out), b, visited)) return false; } return true; } }