Commit d0104cb8 authored by Carlos Galindo's avatar Carlos Galindo
Browse files

TabularAlgorithm: update with everything learned on ConstrainedTabularAlgorithm.

parent 25377390
Loading
Loading
Loading
Loading
+39 −25
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ public class TabularAlgorithm implements SlicingAlgorithm {
    protected Set<Work> workList = new HashSet<>();
    /** Contains processed and unprocessed works that have been reached. */
    protected Set<Work> pathEdge = new HashSet<>();
    protected Map<Node, Set<Work>> current2worksMap;

    public TabularAlgorithm(EDG edg) {
        this.edg = edg;
@@ -31,6 +32,7 @@ public class TabularAlgorithm implements SlicingAlgorithm {
    public Set<Node> slice(Node sc) {
        workList = new HashSet<>();
        pathEdge = new HashSet<>();
        current2worksMap = new HashMap<>();
        propagate(new Work(sc));
        workTheList();
        return pathEdge.stream().map(w -> w.current).collect(Collectors.toSet());
@@ -38,8 +40,10 @@ public class TabularAlgorithm implements SlicingAlgorithm {

    /** Adds a work to {@link #pathEdge} and {@link #workList} if it does not appear in the former. */
    protected void propagate(Work work) {
        if (pathEdge.add(work))
        if (pathEdge.add(work)) {
            workList.add(work);
            current2worksMap.computeIfAbsent(work.current, k -> new HashSet<>()).add(work);
        }
    }
    
    protected void workTheList() {
@@ -48,12 +52,15 @@ public class TabularAlgorithm implements SlicingAlgorithm {
            workList.remove(w);
            if (isEnter(w.current)) {
                if (w.context == null) {
                    traverseEdges(w, Predicate.not(this::edgeIsIntraprocedural));
                    traverseEdges(w, e -> true);
                } else {
                    traverseEdges(w, this::edgeIsIntraprocedural);
                }
            } else if (isFormalIn(w.current)) {
                if (w.context == null) {
                    traverseEdges(w, Predicate.not(this::edgeIsIntraprocedural));
                    traverseEdges(w, e -> true);
                } else {
                    traverseEdges(w, this::edgeIsIntraprocedural);
                    createSummaryEdges(w.current, w.context);
                }
            } else if (isActualOut(w.current)) {
@@ -61,7 +68,7 @@ public class TabularAlgorithm implements SlicingAlgorithm {
                traverseSummaries(w);
                contextSwitch(w.current);
            } else {
                traverseEdges(w, e -> true); // traverse all edges!
                traverseEdges(w, this::edgeIsIntraprocedural);
            }
        }
    }
@@ -74,9 +81,18 @@ public class TabularAlgorithm implements SlicingAlgorithm {
     */
    protected void traverseEdges(Work work, Predicate<Edge> filter) {
        for (Edge e : edg.getEdges(work.current, LAST.Direction.Backwards))
            if (!e.isControlFlowEdge() && e.isTraversable() && filter.test(e))
            if (!e.isControlFlowEdge()
                    && e.getType() != Edge.Type.Summary
                    && e.isTraversable()
                    && filter.test(e)
                    && !(work.current.getType() == Node.Type.Generator && work.lastEdge != Edge.Type.Control && e.getType() == Edge.Type.Value)
                    && !(work.lastEdge == Edge.Type.Structural && e.getType() != Edge.Type.Structural)) {
                if (e.getType() == Edge.Type.Structural || e.getType() == Edge.Type.Control)
                    propagate(new Work(work, edg.getEdgeSource(e), e.getType()));
                else
                    propagate(new Work(work, edg.getEdgeSource(e)));
            }
    }

    /** Filter for intra-procedural edges */
    protected boolean edgeIsIntraprocedural(Edge e) {
@@ -93,22 +109,16 @@ public class TabularAlgorithm implements SlicingAlgorithm {
    protected void createSummaryEdges(Node formalIn, Node formalOut) {
        List<Node> actualOutNodes = edg.getNodes(formalOut, LAST.Direction.Forwards, Edge.Type.Output);
        for (Node actualIn : edg.getNodes(formalIn, LAST.Direction.Backwards, Edge.Type.Input)) {
            Node call = edg.getNodeFromRes(actualIn).getType() == Node.Type.Call ?
                    edg.getNodeFromRes(actualIn) : edg.getAncestor(actualIn, Node.Type.Call);
            Node call = edg.getParent(actualIn).getType() == Node.Type.Arguments ?
                    edg.getAncestor(actualIn, Node.Type.Call) : edg.getNodeFromRes(actualIn);
            int toBeRemoved = -1;
            for (int i = 0; i < actualOutNodes.size(); i++) { // TODO: inefficient, optimize
                Node actualOut = actualOutNodes.get(i);
                if (call.equals(edg.getNodeFromRes(actualOut))) {
                    toBeRemoved = i;
                    if (!summaryEdges.containsKey(actualOut) || !summaryEdges.get(actualOut).contains(actualIn)) {
                        if (!summaryEdges.containsKey(actualOut))
                            summaryEdges.put(actualOut, new HashSet<>());
                        summaryEdges.get(actualOut).add(actualIn);
                        Set<Work> reached = new HashSet<>();
                        for (Work w : pathEdge)
                            if (w.current.equals(actualOut))
                                reached.add(w);
                        for (Work w : reached)
                        summaryEdges.computeIfAbsent(actualOut, k -> new HashSet<>()).add(actualIn);
                        for (Work w : current2worksMap.getOrDefault(actualOut, new HashSet<>()))
                            propagate(new Work(w, actualIn));
                    }
                }
@@ -142,16 +152,12 @@ public class TabularAlgorithm implements SlicingAlgorithm {

    /** Checks whether a given node is a formal-in node in a function. */
    protected boolean isFormalIn(Node node) {
        Node parent = edg.getParent(node);
        return parent != null && parent.getType() == Node.Type.Parameters;
        return edg.getAncestor(node, Node.Type.Parameters) != null;
    }

    /** Checks whether a given node is an actual-out node in a call. */
    protected boolean isActualOut(Node node) {
        Node call = edg.getNodeFromRes(node);
        if (node.getType() == Node.Type.Result && call.getType() == Node.Type.Call)
            return edg.getNodes(node, LAST.Direction.Backwards, Edge.Type.Value).contains(call);
        return false;
        return !edg.getEdges(node, LAST.Direction.Backwards, Edge.Type.Output).isEmpty();
    }

    /**
@@ -162,13 +168,21 @@ public class TabularAlgorithm implements SlicingAlgorithm {
     * <br>
     * Given a collection of works, the set of current nodes represents the slice.
     */
    protected record Work(Node context, Node current) {
    protected record Work(Node context, Node current, Edge.Type lastEdge) {
        public Work(Node current) {
            this((Node) null, current);
            this((Node) null, current, null);
        }

        public Work(Node context, Node current) {
            this(context, current, null);
        }

        public Work(Work w, Node current) {
            this(w.context, current);
            this(w, current, null);
        }

        public Work(Work w, Node current, Edge.Type lastEdge) {
            this(w.context, current, lastEdge);
        }
    }
}