Unverified Commit f938e9ed authored by Javier Costa's avatar Javier Costa Committed by GitHub
Browse files

Merge pull request #28 from jacosro/revert-ctrl-dep

Revert "Reduce complexity of control dependency computation"
parents 5273de58 e2f02826
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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()));
    }
+1 −2
Original line number Diff line number Diff line
@@ -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");
    }
}
+0 −20
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@ import java.util.Set;
 */
public class CFG extends GraphWithRootNode<MethodDeclaration> {
    private boolean built = false;
    protected GraphNode<?> exitNode;

    public CFG() {
        super();
@@ -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;
    }

+1 −2
Original line number Diff line number Diff line
@@ -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");
    }
}
+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.
@@ -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