Loading EDG/src/main/java/edg/slicing/TabularAlgorithm.java +39 −25 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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()); Loading @@ -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() { Loading @@ -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)) { Loading @@ -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); } } } Loading @@ -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) { Loading @@ -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)); } } Loading Loading @@ -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(); } /** Loading @@ -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); } } } Loading
EDG/src/main/java/edg/slicing/TabularAlgorithm.java +39 −25 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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()); Loading @@ -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() { Loading @@ -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)) { Loading @@ -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); } } } Loading @@ -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) { Loading @@ -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)); } } Loading Loading @@ -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(); } /** Loading @@ -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); } } }