Newer
Older
package edg.slicing;
import edg.constraint.*;
import edg.graph.EDG;
import edg.graph.Edge;
import edg.graph.LAST.Direction;
import edg.graph.Node;
import edg.work.EdgeWork;
import edg.work.NodeWork;
import edg.work.Work;
import edg.work.WorkList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
public class OnePassConstrainedAlgorithm implements SlicingAlgorithm
{
protected final EDG edg;
public OnePassConstrainedAlgorithm(EDG edg) { this.edg = edg; }
public Set<Node> slice(Node node)
{
final Set<Node> slice = new HashSet<>();
if (node == null)
return slice;
final WorkList workList = new WorkList();
workList.pend(new NodeWork(node, node, new Constraints()));
this.traverse(Phase.OnePhase, workList);
slice.addAll(workList.getDoneNodes());
// Reset constraints to their original form after slicing the graph
// edg.edgeSet().stream()
// .filter(e -> e.getType() == Edge.Type.Flow || e.getType() == Edge.Type.Value)
// .forEach(Edge::resetVisibleConstraint);
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
return slice;
}
private void traverse(Phase phase, WorkList workList)
{
while (workList.hasMore())
{
final Work pendingWork = workList.next();
final List<Work> newWorks = this.processWork(phase, pendingWork);
workList.done(pendingWork);
workList.pendAll(newWorks);
}
}
public List<Work> processWork(Phase phase, Work work)
{
if (work instanceof NodeWork)
return this.processWork(phase, (NodeWork) work);
if (work instanceof EdgeWork)
return this.processWork(phase, (EdgeWork) work);
throw new RuntimeException("Work type not contemplated");
}
protected List<Work> processWork(Phase phase, NodeWork work)
{
final List<Work> newWorks = new LinkedList<>();
final Node initialNode = work.getInitialNode();
final Node currentNode = work.getCurrentNode();
final Constraints constraints = work.getConstraints();
final Set<NodeConstraint> nodeConstraints = constraints.getNodeConstraints();
final Set<Edge> edges = edg.getEdges(currentNode, sliceDirection);
edges.removeIf(Edge::isControlFlowEdge);
if(phase == Phase.SummaryGeneration) {
edges.removeIf(edge -> edge.getType() == Edge.Type.Exception);
edges.removeIf(edge -> edge.getType() == Edge.Type.Input ||
edge.getType() == Edge.Type.Output ||
edge.getType() == Edge.Type.Call);
}
// TRAVERSAL RESTRICTION TODO: Change this restriction to construction time removing structural arcs
// GENERATOR NODES CONTAIN VALUE EDGES THAT MUST BE TRAVERSED ONLY IF THE GENERATOR NODE IS INCLUDED BY CONTROL
if (currentNode.getType() == Node.Type.Generator && work.getPreviousEdgeType() != Edge.Type.Control)
edges.removeIf(edge -> edge.getType() == Edge.Type.Value);
if (work.getPreviousEdgeType() == Edge.Type.Structural)
edges.removeIf(edge -> edge.getType() != Edge.Type.Structural);
for (NodeConstraint nodeConstraint : nodeConstraints)
nodeConstraint.resolve(phase, edges);
final Constraints constraintsClone = (Constraints) constraints.clone();
constraintsClone.clearNodeConstraints();
for (Edge edge : edges){
newWorks.add(new EdgeWork(edg, initialNode, edge, work.getTraversedEdges(), constraintsClone));
}
return newWorks;
}
protected List<Work> processWork(Phase phase, EdgeWork work)
{
final List<Work> newWorks = new LinkedList<>();
final Node initialNode = work.getInitialNode();
final Edge currentEdge = work.getCurrentEdge();
final EdgeList traversedEdges = work.getTraversedEdges();
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
final Node nextNode = sliceDirection == Direction.Backwards ?
edg.getEdgeSource(currentEdge) : edg.getEdgeTarget(currentEdge);
// NECESSARY TO CONTROL THE OUTPUT EDGES WITH LET_THROUGH_CONSTRAINTS
final Edge.Type edgeType = currentEdge.getType();
if (phase == Phase.Input && edgeType == Edge.Type.Output)
return newWorks;
if (phase == Phase.Output && edgeType == Edge.Type.Input)
return newWorks;
if (phase == Phase.SummaryGeneration && (edgeType == Edge.Type.Input || edgeType == Edge.Type.Output))
return newWorks;
// Do not traverse non-traversable edges
if (!currentEdge.isTraversable())
return newWorks;
int idTo = edg.getEdgeTarget(currentEdge).getId();
int idFrom = edg.getEdgeSource(currentEdge).getId();
try
{
final Constraints constraints = work.getConstraints();
final Constraints constraintsClone = (Constraints) constraints.clone();
final EdgeConstraint constraint = currentEdge.getConstraint();
final EdgeConstraint topConstraint = constraintsClone.isEdgeConstraintsEmpty() ? null : constraintsClone.peekEdgeConstraint();
// THIS STATEMENT MAY LAUNCH A StackOverflowError EMPTYING THE STACK (k-limiting 20 elements => Config.MAX_STACK_SIZE = 20;)
final List<Constraints> newConstraintsList = constraint.resolve(phase, edg, currentEdge, constraintsClone, topConstraint, 0);
for (Constraints newConstraints : newConstraintsList) {
if (traversedEdges.contains(currentEdge)) { // IF WE TRAVERSE THE SAME EDGE TWICE WHILE TRAVERSING FLOW AND VALUE EDGES...
List<Edge> loopEdges = work.getTraversedLoop(currentEdge); // 1) WE EXTRACT THE EDGES OF THE LOOP
boolean isIncreasingLoop = PDA.isIncreasingLoop(loopEdges); // 2) WE CALL THE PDA TO EVALUATE THE LOOP
if (isIncreasingLoop) { // 3) IF THE LOOP IS INCREASING...
// REMOVE STACK (ASTERISK CONSTRAINT) AND CONTINUE TRAVERSAL ADDING THE EDGE TO traversedEdges
// ACTS AS AN ASTERISK BUT DOES NOT REPLACE THE CONSTRAINT IN THE ARC
// currentEdge.setVisibleConstraint(AsteriskConstraint.getConstraint());
newWorks.add(new NodeWork(initialNode, nextNode, new EdgeList(currentEdge), new Constraints(), edgeType));
// WE CAN OPTIONALLY MODIFY IT TO OPTIMISE FUTURE TRAVERSALS TOO
} // 4) IF THE LOOP WAS NOT INCREASING RESTART TRAVERSED EDGES (DO NOTHING)
} else {
final EdgeList traversedParam;
switch (currentEdge.getType()) {
case Flow: // SUMMARY EDGES MAY GENERATE IT TOO, BUT WE ARE INTRAPROCEDURAL NOW
case Value:
if ((constraint instanceof AccessConstraint || !traversedEdges.isEmpty())
&& !(constraint instanceof LiteralConstraint))
traversedParam = new EdgeList(traversedEdges, currentEdge);
else
traversedParam = EdgeList.emptyList();
if (!traversedEdges.isEmpty())
traversedParam = new EdgeList(traversedEdges, currentEdge);
else
traversedParam = EdgeList.emptyList();
break;
default:
traversedParam = EdgeList.emptyList();
break;
}
newWorks.add(new NodeWork(initialNode, nextNode, traversedParam, newConstraints, edgeType));
}
}
return newWorks;
}
catch (StackOverflowError e)
{
if (!phase.isInstanceof(Phase.Slicing))
throw new RuntimeException("Constraint situation not contemplated");
newWorks.add(new NodeWork(initialNode, nextNode, new Constraints(), edgeType));
}
return newWorks;
}
}