Loading sdg-cli/src/main/java/es/upv/mist/slicing/cli/Slicer.java +6 −4 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ import com.github.javaparser.symbolsolver.resolution.typesolvers.JavaParserTypeS import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver; import es.upv.mist.slicing.graphs.augmented.ASDG; import es.upv.mist.slicing.graphs.augmented.PSDG; import es.upv.mist.slicing.graphs.augmented.TapasSDG; import es.upv.mist.slicing.graphs.exceptionsensitive.ESSDG; import es.upv.mist.slicing.graphs.sdg.SDG; import es.upv.mist.slicing.slicing.FileLineSlicingCriterion; Loading Loading @@ -236,6 +237,7 @@ public class Slicer { case "ASDG": sdg = new ASDG(); break; case "PSDG": sdg = new PSDG(); break; case "ESSDG": sdg = new ESSDG(); break; case "TSDG": sdg = new TapasSDG(); break; default: throw new IllegalArgumentException("Unknown type of graph. Available graphs are SDG, ASDG, PSDG, ESSDG"); } Loading sdg-core/src/main/java/es/upv/mist/slicing/graphs/augmented/ACFGBuilder.java +4 −2 Original line number Diff line number Diff line Loading @@ -69,12 +69,13 @@ public class ACFGBuilder extends CFGBuilder { // Link previous statement to the switch's selector switchEntriesStack.push(new LinkedList<>()); breakStack.push(new LinkedList<>()); GraphNode<?> cond = connectTo(switchStmt, String.format("switch (%s)", switchStmt.getSelector())); GraphNode<SwitchStmt> cond = connectTo(switchStmt, String.format("switch (%s)", switchStmt.getSelector())); hangingNodes.remove(cond); switchStack.push(cond); switchStmt.getSelector().accept(this, arg); // expr --> each case (fallthrough by default, so case --> case too) for (SwitchEntryStmt entry : switchStmt.getEntries()) { entry.accept(this, arg); // expr && prev case --> case --> next case hangingNodes.add(cond); // expr --> next case } // The next statement will be linked to: // 1. All break statements that broke from the switch (done with break section) Loading @@ -84,6 +85,7 @@ public class ACFGBuilder extends CFGBuilder { if (ASTUtils.switchHasDefaultCase(switchStmt)) hangingNodes.remove(cond); List<GraphNode<SwitchEntryStmt>> entries = switchEntriesStack.pop(); switchStack.pop(); GraphNode<SwitchEntryStmt> def = null; for (GraphNode<SwitchEntryStmt> entry : entries) { if (entry.getAstNode().getLabel().isEmpty()) { Loading sdg-core/src/main/java/es/upv/mist/slicing/graphs/augmented/TapasPDG.java 0 → 100644 +70 −0 Original line number Diff line number Diff line package es.upv.mist.slicing.graphs.augmented; import es.upv.mist.slicing.arcs.Arc; import es.upv.mist.slicing.arcs.pdg.ControlDependencyArc; import es.upv.mist.slicing.nodes.GraphNode; import java.util.HashSet; import java.util.Set; import java.util.stream.Collectors; /** * An alternative program dependence graph to the {@link PPDG}, which * performs the same optimization without altering the slicing algorithm, * thus guaranteeing that it's kept ats its original linear time complexity. */ public class TapasPDG extends APDG { public TapasPDG() { super(); } public TapasPDG(ACFG acfg) { super(acfg); } @Override protected Builder createBuilder() { return new Builder(); } public class Builder extends APDG.Builder { @Override protected void buildControlDependency() { super.buildControlDependency(); algorithm1(); } /** Removes all incoming edges of a pseudo-predicate, when (1) there is a control * dependency between itself and another pseudo-predicate, and (2) both jump to * the same instruction. */ protected void algorithm1() { Set<ControlDependencyArc> Ac = edgeSet().stream() .filter(Arc::isControlDependencyArc) .map(ControlDependencyArc.class::cast) .collect(Collectors.toSet()); Set<Arc> arcsToRemove = new HashSet<>(); for (ControlDependencyArc arc : Ac) { GraphNode<?> ns = getEdgeSource(arc); GraphNode<?> ne = getEdgeTarget(arc); ACFG acfg = (ACFG) cfg; if (acfg.isPseudoPredicate(ns) && acfg.isPseudoPredicate(ne) && jumpDest(ns).equals(jumpDest(ne))) { edgeSet().stream() .filter(Arc::isControlDependencyArc) .filter(a -> getEdgeTarget(a).equals(ne)) .forEach(arcsToRemove::add); } } arcsToRemove.forEach(TapasPDG.this::removeEdge); } /** Obtain the target of a jump instruction. In the CFG, it should * have just one executable outgoing edge. */ protected GraphNode<?> jumpDest(GraphNode<?> jumpNode) { Set<Arc> outgoing = new HashSet<>(cfg.outgoingEdgesOf(jumpNode)); outgoing.removeIf(Arc::isNonExecutableControlFlowArc); if (outgoing.size() != 1) throw new IllegalArgumentException("Jump has 0 or multiple executable outgoing edges."); return cfg.getEdgeTarget(outgoing.iterator().next()); } } } sdg-core/src/main/java/es/upv/mist/slicing/graphs/augmented/TapasSDG.java 0 → 100644 +19 −0 Original line number Diff line number Diff line package es.upv.mist.slicing.graphs.augmented; import es.upv.mist.slicing.graphs.cfg.CFG; import es.upv.mist.slicing.graphs.pdg.PDG; public class TapasSDG extends ASDG { @Override protected Builder createBuilder() { return new Builder(); } public class Builder extends ASDG.Builder { @Override protected PDG createPDG(CFG cfg) { assert cfg instanceof ACFG; return new TapasPDG((ACFG) cfg); } } } sdg-core/src/main/java/es/upv/mist/slicing/graphs/cfg/CFGBuilder.java +11 −5 Original line number Diff line number Diff line Loading @@ -55,6 +55,8 @@ public class CFGBuilder extends VoidVisitorAdapter<Void> { protected final Map<SimpleName, List<GraphNode<ContinueStmt>>> continueMap = new HashMap<>(); /** Return statements that should be connected to the final node, if it is created at the end of the */ protected final List<GraphNode<ReturnStmt>> returnList = new LinkedList<>(); /** Stack of switch statements. */ protected final Deque<GraphNode<SwitchStmt>> switchStack = new LinkedList<>(); /** Stack of lists of hanging cases on switch statements */ protected final Deque<List<GraphNode<SwitchEntryStmt>>> switchEntriesStack = new LinkedList<>(); Loading Loading @@ -271,8 +273,10 @@ public class CFGBuilder extends VoidVisitorAdapter<Void> { @Override public void visit(SwitchEntryStmt entryStmt, Void arg) { // Case header (prev -> case EXPR) GraphNode<SwitchEntryStmt> node = connectTo(entryStmt, entryStmt.getLabel().isPresent() ? "case " + entryStmt.getLabel().get() : "default"); GraphNode<SwitchEntryStmt> node = graph.addVertex(entryStmt.getLabel().isPresent() ? "case " + entryStmt.getLabel().get() : "default", entryStmt); graph.addControlFlowArc(switchStack.element(), node); hangingNodes.add(node); switchEntriesStack.peek().add(node); // Case body (case EXPR --> body) entryStmt.getStatements().accept(this, arg); Loading @@ -284,12 +288,13 @@ public class CFGBuilder extends VoidVisitorAdapter<Void> { // Link previous statement to the switch's selector switchEntriesStack.push(new LinkedList<>()); breakStack.push(new LinkedList<>()); GraphNode<?> cond = connectTo(switchStmt, String.format("switch (%s)", switchStmt.getSelector())); GraphNode<SwitchStmt> cond = connectTo(switchStmt, String.format("switch (%s)", switchStmt.getSelector())); hangingNodes.remove(cond); switchStack.push(cond); switchStmt.getSelector().accept(this, arg); // expr --> each case (fallthrough by default, so case --> case too) for (SwitchEntryStmt entry : switchStmt.getEntries()) { entry.accept(this, arg); // expr && prev case --> case --> next case hangingNodes.add(cond); // expr --> next case } // The next statement will be linked to: // 1. All break statements that broke from the switch (done with break section) Loading @@ -298,7 +303,8 @@ public class CFGBuilder extends VoidVisitorAdapter<Void> { // If the last case is a default case, remove the selector node from the list of nodes (see 2) if (ASTUtils.switchHasDefaultCase(switchStmt)) hangingNodes.remove(cond); List<GraphNode<SwitchEntryStmt>> entries = switchEntriesStack.pop(); switchEntriesStack.pop(); switchStack.pop(); // End block and break section hangingNodes.addAll(breakStack.pop()); } Loading Loading
sdg-cli/src/main/java/es/upv/mist/slicing/cli/Slicer.java +6 −4 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ import com.github.javaparser.symbolsolver.resolution.typesolvers.JavaParserTypeS import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver; import es.upv.mist.slicing.graphs.augmented.ASDG; import es.upv.mist.slicing.graphs.augmented.PSDG; import es.upv.mist.slicing.graphs.augmented.TapasSDG; import es.upv.mist.slicing.graphs.exceptionsensitive.ESSDG; import es.upv.mist.slicing.graphs.sdg.SDG; import es.upv.mist.slicing.slicing.FileLineSlicingCriterion; Loading Loading @@ -236,6 +237,7 @@ public class Slicer { case "ASDG": sdg = new ASDG(); break; case "PSDG": sdg = new PSDG(); break; case "ESSDG": sdg = new ESSDG(); break; case "TSDG": sdg = new TapasSDG(); break; default: throw new IllegalArgumentException("Unknown type of graph. Available graphs are SDG, ASDG, PSDG, ESSDG"); } Loading
sdg-core/src/main/java/es/upv/mist/slicing/graphs/augmented/ACFGBuilder.java +4 −2 Original line number Diff line number Diff line Loading @@ -69,12 +69,13 @@ public class ACFGBuilder extends CFGBuilder { // Link previous statement to the switch's selector switchEntriesStack.push(new LinkedList<>()); breakStack.push(new LinkedList<>()); GraphNode<?> cond = connectTo(switchStmt, String.format("switch (%s)", switchStmt.getSelector())); GraphNode<SwitchStmt> cond = connectTo(switchStmt, String.format("switch (%s)", switchStmt.getSelector())); hangingNodes.remove(cond); switchStack.push(cond); switchStmt.getSelector().accept(this, arg); // expr --> each case (fallthrough by default, so case --> case too) for (SwitchEntryStmt entry : switchStmt.getEntries()) { entry.accept(this, arg); // expr && prev case --> case --> next case hangingNodes.add(cond); // expr --> next case } // The next statement will be linked to: // 1. All break statements that broke from the switch (done with break section) Loading @@ -84,6 +85,7 @@ public class ACFGBuilder extends CFGBuilder { if (ASTUtils.switchHasDefaultCase(switchStmt)) hangingNodes.remove(cond); List<GraphNode<SwitchEntryStmt>> entries = switchEntriesStack.pop(); switchStack.pop(); GraphNode<SwitchEntryStmt> def = null; for (GraphNode<SwitchEntryStmt> entry : entries) { if (entry.getAstNode().getLabel().isEmpty()) { Loading
sdg-core/src/main/java/es/upv/mist/slicing/graphs/augmented/TapasPDG.java 0 → 100644 +70 −0 Original line number Diff line number Diff line package es.upv.mist.slicing.graphs.augmented; import es.upv.mist.slicing.arcs.Arc; import es.upv.mist.slicing.arcs.pdg.ControlDependencyArc; import es.upv.mist.slicing.nodes.GraphNode; import java.util.HashSet; import java.util.Set; import java.util.stream.Collectors; /** * An alternative program dependence graph to the {@link PPDG}, which * performs the same optimization without altering the slicing algorithm, * thus guaranteeing that it's kept ats its original linear time complexity. */ public class TapasPDG extends APDG { public TapasPDG() { super(); } public TapasPDG(ACFG acfg) { super(acfg); } @Override protected Builder createBuilder() { return new Builder(); } public class Builder extends APDG.Builder { @Override protected void buildControlDependency() { super.buildControlDependency(); algorithm1(); } /** Removes all incoming edges of a pseudo-predicate, when (1) there is a control * dependency between itself and another pseudo-predicate, and (2) both jump to * the same instruction. */ protected void algorithm1() { Set<ControlDependencyArc> Ac = edgeSet().stream() .filter(Arc::isControlDependencyArc) .map(ControlDependencyArc.class::cast) .collect(Collectors.toSet()); Set<Arc> arcsToRemove = new HashSet<>(); for (ControlDependencyArc arc : Ac) { GraphNode<?> ns = getEdgeSource(arc); GraphNode<?> ne = getEdgeTarget(arc); ACFG acfg = (ACFG) cfg; if (acfg.isPseudoPredicate(ns) && acfg.isPseudoPredicate(ne) && jumpDest(ns).equals(jumpDest(ne))) { edgeSet().stream() .filter(Arc::isControlDependencyArc) .filter(a -> getEdgeTarget(a).equals(ne)) .forEach(arcsToRemove::add); } } arcsToRemove.forEach(TapasPDG.this::removeEdge); } /** Obtain the target of a jump instruction. In the CFG, it should * have just one executable outgoing edge. */ protected GraphNode<?> jumpDest(GraphNode<?> jumpNode) { Set<Arc> outgoing = new HashSet<>(cfg.outgoingEdgesOf(jumpNode)); outgoing.removeIf(Arc::isNonExecutableControlFlowArc); if (outgoing.size() != 1) throw new IllegalArgumentException("Jump has 0 or multiple executable outgoing edges."); return cfg.getEdgeTarget(outgoing.iterator().next()); } } }
sdg-core/src/main/java/es/upv/mist/slicing/graphs/augmented/TapasSDG.java 0 → 100644 +19 −0 Original line number Diff line number Diff line package es.upv.mist.slicing.graphs.augmented; import es.upv.mist.slicing.graphs.cfg.CFG; import es.upv.mist.slicing.graphs.pdg.PDG; public class TapasSDG extends ASDG { @Override protected Builder createBuilder() { return new Builder(); } public class Builder extends ASDG.Builder { @Override protected PDG createPDG(CFG cfg) { assert cfg instanceof ACFG; return new TapasPDG((ACFG) cfg); } } }
sdg-core/src/main/java/es/upv/mist/slicing/graphs/cfg/CFGBuilder.java +11 −5 Original line number Diff line number Diff line Loading @@ -55,6 +55,8 @@ public class CFGBuilder extends VoidVisitorAdapter<Void> { protected final Map<SimpleName, List<GraphNode<ContinueStmt>>> continueMap = new HashMap<>(); /** Return statements that should be connected to the final node, if it is created at the end of the */ protected final List<GraphNode<ReturnStmt>> returnList = new LinkedList<>(); /** Stack of switch statements. */ protected final Deque<GraphNode<SwitchStmt>> switchStack = new LinkedList<>(); /** Stack of lists of hanging cases on switch statements */ protected final Deque<List<GraphNode<SwitchEntryStmt>>> switchEntriesStack = new LinkedList<>(); Loading Loading @@ -271,8 +273,10 @@ public class CFGBuilder extends VoidVisitorAdapter<Void> { @Override public void visit(SwitchEntryStmt entryStmt, Void arg) { // Case header (prev -> case EXPR) GraphNode<SwitchEntryStmt> node = connectTo(entryStmt, entryStmt.getLabel().isPresent() ? "case " + entryStmt.getLabel().get() : "default"); GraphNode<SwitchEntryStmt> node = graph.addVertex(entryStmt.getLabel().isPresent() ? "case " + entryStmt.getLabel().get() : "default", entryStmt); graph.addControlFlowArc(switchStack.element(), node); hangingNodes.add(node); switchEntriesStack.peek().add(node); // Case body (case EXPR --> body) entryStmt.getStatements().accept(this, arg); Loading @@ -284,12 +288,13 @@ public class CFGBuilder extends VoidVisitorAdapter<Void> { // Link previous statement to the switch's selector switchEntriesStack.push(new LinkedList<>()); breakStack.push(new LinkedList<>()); GraphNode<?> cond = connectTo(switchStmt, String.format("switch (%s)", switchStmt.getSelector())); GraphNode<SwitchStmt> cond = connectTo(switchStmt, String.format("switch (%s)", switchStmt.getSelector())); hangingNodes.remove(cond); switchStack.push(cond); switchStmt.getSelector().accept(this, arg); // expr --> each case (fallthrough by default, so case --> case too) for (SwitchEntryStmt entry : switchStmt.getEntries()) { entry.accept(this, arg); // expr && prev case --> case --> next case hangingNodes.add(cond); // expr --> next case } // The next statement will be linked to: // 1. All break statements that broke from the switch (done with break section) Loading @@ -298,7 +303,8 @@ public class CFGBuilder extends VoidVisitorAdapter<Void> { // If the last case is a default case, remove the selector node from the list of nodes (see 2) if (ASTUtils.switchHasDefaultCase(switchStmt)) hangingNodes.remove(cond); List<GraphNode<SwitchEntryStmt>> entries = switchEntriesStack.pop(); switchEntriesStack.pop(); switchStack.pop(); // End block and break section hangingNodes.addAll(breakStack.pop()); } Loading