Commit 10f9343d authored by Sergio Pérez's avatar Sergio Pérez
Browse files

* Improved CFG for List Comprehensions

* Traversal restriction of Generator value edge traversal
* CFG limitation for unreachable code
parent dedf0449
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -78,6 +78,11 @@ public class ConstrainedAlgorithm implements SlicingAlgorithm
									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);

		for (NodeConstraint nodeConstraint : nodeConstraints)
			nodeConstraint.resolve(phase, edges);

@@ -109,6 +114,10 @@ public class ConstrainedAlgorithm implements SlicingAlgorithm
		if (!currentEdge.isTraversable())
			return newWorks;

		int sourceId = edg.getEdgeSource(currentEdge).getId();
		int targetId = edg.getEdgeTarget(currentEdge).getId();


		try
		{
			final Constraints constraints = work.getConstraints();
+99 −54
Original line number Diff line number Diff line
@@ -18,15 +18,17 @@ public class ControlFlowGenerator extends VoidVisitor<Void> implements Generator
	protected final Deque<Set<Node>> switchSelectorStack = new LinkedList<>();
	protected final Deque<Boolean> switchHasDefaultStack = new LinkedList<>();

	protected boolean absorbentPattern = false;
	protected boolean absorbentCondition = false;
	protected boolean ifContext = false;
	protected boolean stopCaseCFG = false;
	// protected boolean ifContext = false;

	protected int ttl = INFINITY;
	protected boolean generating = false;
	protected boolean parametersContext = false;
	protected Deque<Node> routineHanging = new LinkedList<>();
	protected Deque<Node> anonymousRoutineHanging = new LinkedList<>();

	protected final Deque<Set<Node>> lcStack = new LinkedList<>();
	protected final Deque<Node> lcPrevRestriction = new LinkedList<>();
	protected final Deque<Set<Node>> prevCaseGuardHanging = new LinkedList<>();

	public ControlFlowGenerator(LAST graph)
@@ -74,7 +76,7 @@ public class ControlFlowGenerator extends VoidVisitor<Void> implements Generator
		routineHanging.push(n);
		super.visitRoutine(n, arg);
		routineHanging.pop();
		hangingNodes.clear();
		clearHanging();
		hangingNodes.addAll(clauseHangingStack.peek());
		connectTo(n);
		clauseHangingStack.pop();
@@ -88,11 +90,12 @@ public class ControlFlowGenerator extends VoidVisitor<Void> implements Generator
	{
		clauseHangingStack.push(new HashSet<>());
		guardHangingStack.push(new HashSet<>());
		routineHanging.push(n);
		anonymousRoutineHanging.push(n);
		connectTo(n);
		clearHanging();
		super.visitAnonymousRoutine(n, arg);
		routineHanging.pop();
		hangingNodes.clear();
		anonymousRoutineHanging.pop();
		clearHanging();
		hangingNodes.addAll(clauseHangingStack.peek());
		connectTo(n);
		guardHangingStack.pop();
@@ -102,9 +105,8 @@ public class ControlFlowGenerator extends VoidVisitor<Void> implements Generator
	@Override
	public void visitClause(Node n, Void arg)
	{
		if (graph.getParent(n).equals(routineHanging.peek()))
		{
			hangingNodes.clear();
		if (graph.getParent(n).equals(routineHanging.peek())) {
			clearHanging();
			hangingNodes.add(routineHanging.peek());
		}

@@ -115,17 +117,25 @@ public class ControlFlowGenerator extends VoidVisitor<Void> implements Generator
		returnSet.push(new HashSet<>());
		graph.getChild(n, Node.Type.ParameterIn).accept(this, arg);
		graph.getChild(n, Node.Type.Parameters).accept(this, arg);
		graph.getChild(n, Node.Type.Guard).accept(this, arg);
		Node guardNode = graph.getChild(n, Node.Type.Guard);
		guardNode.accept(this, arg);
		if (!graph.getChildren(guardNode).isEmpty())
			guardHangingStack.peek().addAll(hangingNodes);
		graph.getChild(n, Node.Type.Body).accept(this, arg);
		hangingNodes.addAll(returnSet.peek());
		returnSet.pop();
		hangingNodes.addAll(returnSet.pop());
		graph.getChild(n, Node.Type.ParameterOut).accept(this, arg);
		hangingNodes.addAll(guardHangingStack.peek());
		guardHangingStack.peek().clear();
		connectTo(n);
	}

	@Override
	public void visitBlock(Node n, Void arg) {
		returnSet.push(new HashSet<>());
		super.visitBlock(n, arg);
		hangingNodes.addAll(returnSet.pop());
	}

	@Override
	public void visitEnclosed(Node n, Void arg)
	{
@@ -153,6 +163,8 @@ public class ControlFlowGenerator extends VoidVisitor<Void> implements Generator
	{
		super.visitDataConstructor(n, arg);
		connectTo(n);
		if (graph.isPatternZone(n) && !this.isMatchExprPattern(n))
			guardHangingStack.peek().addAll(hangingNodes);
	}

	@Override
@@ -172,55 +184,67 @@ public class ControlFlowGenerator extends VoidVisitor<Void> implements Generator
	@Override
	public void visitSwitch(Node n, Void arg)
	{
		if (n.getInfo().getConstruction().equals("if"))
			ifContext = true;
		else
			ifContext = false;

		returnSet.push(new HashSet<>());
		switchStack.push(new HashSet<>());
		graph.getChild(n, Node.Type.Selector).accept(this, arg);
		graph.getChild(n, Node.Type.Cases).accept(this, arg);
		hangingNodes.clear();
		clearHanging();
		hangingNodes.addAll(returnSet.peek());
		connectTo(n);
		returnSet.pop();

		absorbentCondition = false;
		ifContext = false;
	}

	@Override
	public void visitCases(Node n, Void arg){
		absorbentPattern = false;
		absorbentCondition = false;
		stopCaseCFG = false;

		prevCaseGuardHanging.push(new HashSet<>());
		super.visitCases(n, arg);
		returnSet.peek().addAll(Set.copyOf(prevCaseGuardHanging.peek()));
		prevCaseGuardHanging.pop();

		stopCaseCFG = false;
	}

	@Override
	public void visitCase(Node n, Void arg)
	{
		if(!absorbentCondition) {
			hangingNodes.addAll(prevCaseGuardHanging.peekFirst());
		if(!stopCaseCFG) {
			hangingNodes.addAll(prevCaseGuardHanging.peek());
			prevCaseGuardHanging.peek().clear();
			graph.getChild(n, Node.Type.Selectable).accept(this, arg);
			graph.getChild(n, Node.Type.Guard).accept(this, arg);
			prevCaseGuardHanging.peek().addAll(Set.copyOf(hangingNodes));

			boolean prevIfContext = ifContext;
			// SAVE THE ABSORBENT CASE STATE AND RESTORE IT AFTER BODY
			boolean prevAbsorbentPattern = absorbentPattern;
			boolean prevAbsorbentCondition = absorbentCondition;
			graph.getChild(n, Node.Type.Body).accept(this, arg);
			absorbentCondition = prevAbsorbentCondition;
			ifContext = prevIfContext;
			absorbentPattern = prevAbsorbentPattern;
			stopCaseCFG = absorbentPattern && absorbentCondition;

			absorbentPattern = false;
			absorbentCondition = false;

			returnSet.peek().addAll(Set.copyOf(hangingNodes));
		}
	}

	@Override
	public void visitSelectable(Node n, Void arg) {
		if (graph.getChildren(n).isEmpty() || this.isAbsorbentPattern(graph.getChild(n, 0)))
			absorbentPattern = true;
		else
			absorbentPattern = false;
		super.visitSelectable(n, arg);
	}

	@Override
	public void visitGuard(Node n, Void arg){
		if (this.isIfTrueGuard(n))
		if (this.isAbsorbentCondition(n))
			absorbentCondition = true;
		super.visitGuard(n,arg);
	}
@@ -246,7 +270,7 @@ public class ControlFlowGenerator extends VoidVisitor<Void> implements Generator
	public void visitVariable(Node n, Void arg)
	{
		connectTo(n);
		if (parametersContext &&
		if (graph.isPatternZone(n) && !this.isMatchExprPattern(n) &&
				((Variable) n).getContext() == Variable.Context.Use)
				guardHangingStack.peek().addAll(hangingNodes);
	}
@@ -255,7 +279,7 @@ public class ControlFlowGenerator extends VoidVisitor<Void> implements Generator
	public void visitLiteral(Node n, Void arg)
	{
		connectTo(n);
		if (parametersContext)
		if (graph.isPatternZone(n) && !this.isMatchExprPattern(n))
			guardHangingStack.peek().addAll(hangingNodes);
	}

@@ -274,15 +298,6 @@ public class ControlFlowGenerator extends VoidVisitor<Void> implements Generator
		connectTo(n);
	}

	@Override
	public void visitParameters(Node n, Void arg)
	{
		parametersContext = true;
		super.visitParameters(n, arg);
		parametersContext = false;
		connectTo(n);
	}

	@Override
	public void visitParameterOut(Node n, Void arg)
	{
@@ -305,16 +320,17 @@ public class ControlFlowGenerator extends VoidVisitor<Void> implements Generator
	// LIST COMPREHENSIONS AND LISTS IN LIST COMPREHENSIONS
	@Override
	public void visitListComprehension(Node n, Void arg) {
		lcStack.push(new HashSet<>());
		lcPrevRestriction.push(null);
		graph.getChild(n, Node.Type.Restrictions).accept(this, arg);
		graph.getChild(n, Node.Type.Value).accept(this, arg);
		ttl = 1;
		hangingNodes.addAll(lcStack.peekFirst());
		connectTo(lcPrevRestriction.pop());

		Node restrictions = graph.getChild(n, Node.Type.Restrictions);
		Node generator = graph.getChild(restrictions, Node.Type.Generator); // ERROR: More than 1 generator?
		graph.getChild(generator, Node.Type.Iterator).accept(this, arg);
		ttl = INFINITY;
		lcStack.pop();
		Node firstGenerator = graph.getChild(restrictions, Node.Type.Generator);
		//connectTo(graph.getChild(firstGenerator, Node.Type.Iterator));

		clearHanging();
		hangingNodes.add(firstGenerator);
		connectTo(n);
	}
	@Override
@@ -329,36 +345,65 @@ public class ControlFlowGenerator extends VoidVisitor<Void> implements Generator
	@Override
	public void visitFilter(Node n, Void arg) {
		super.visitFilter(n,arg);
		lcStack.peekFirst().addAll(hangingNodes);
		connectTo(lcPrevRestriction.pop());
		clearHanging();
		Node filterExpression = graph.getChild(n, Node.Type.Value);
		hangingNodes.add(filterExpression);
		lcPrevRestriction.push(filterExpression);
	}

	@Override
	public void visitGenerator(Node n, Void arg)
	{
		boolean isFirstGenerator = lcPrevRestriction.peek() == null;

		new EDG(graph).getChild(n, Node.Type.Iterator).accept(this, arg);
		new EDG(graph).getChild(n, Node.Type.Variable).accept(this, arg);
		lcStack.peekFirst().addAll(hangingNodes);
		connectTo(n);

		if (!isFirstGenerator)
			connectTo(lcPrevRestriction.pop());
		clearHanging();
		hangingNodes.add(n);
		lcPrevRestriction.push(n);
	}
	@Override
	public void visitList(Node n, Void arg) {
		super.visitList(n, arg);
		connectTo(n);

		if (graph.isPatternZone(n) && !this.isMatchExprPattern(n)) {
			if ((graph.getParent(n).getType() != Node.Type.List) &&
				graph.getChildren(n).isEmpty());
			guardHangingStack.peek().addAll(hangingNodes);
		}
	}

	private boolean isAbsorbentPattern(Node n) {
		if (n.getType() == Node.Type.Variable &&
				((Variable) n).getContext() == Variable.Context.Definition)
			return true;

		return false;
	}

	private boolean isIfTrueGuard(Node n) {
	private boolean isAbsorbentCondition(Node n) {
		List<Node> guardChildren = graph.getChildren(n);
		if (guardChildren.isEmpty())
			return false;
			return true;

		Node exprNode = graph.getChildren(
							graph.getChildren(
									guardChildren.get(0)
							).get(0)
						).get(0);

		return exprNode.getType() == Node.Type.Literal &&
				exprNode.getName().equals("true") &&
				ifContext;
				exprNode.getName().equals("true");
	}


	private boolean isMatchExprPattern(Node n) {
		return graph.getAncestor(n, Node.Type.Equality) != null ||
				graph.getAncestor(n, Node.Type.Generator) != null;
	}
}
 No newline at end of file
+29 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
package eknife.erlang;

import java.util.List;
import java.util.Set;

import edg.constraint.*;
import edg.graph.Edge;
@@ -158,6 +159,14 @@ public class ValueEdgeGenerator {
			}
		}
	}

	private boolean isCFGReached(Node node) {
		Set<Edge> outgoingCFGEdges = this.last.getEdges(node, LAST.Direction.Forwards);
		outgoingCFGEdges.removeIf(e -> e.getType() != Edge.Type.ControlFlow);

		return outgoingCFGEdges.size() > 0;
	}

	private void generateListComprehensionEdges()
	{
		final List<Node> listComprehensionNodes = this.last.getNodes(Node.Type.ListComprehension);
@@ -178,10 +187,27 @@ public class ValueEdgeGenerator {
		{
			final Node pattern = this.last.getChild(generator, Node.Type.Variable);
			final Node expression = this.last.getChild(generator, Node.Type.Iterator);
			this.generatePatternStructureEdges(generator, pattern);
			this.last.addEdge(expression, generator, Edge.Type.Value, EmptyConstraint.getConstraint());
			this.last.addEdge(expression, pattern, Edge.Type.Value, positiveConstraint);
		}
	}

	private void generatePatternStructureEdges(Node generator, Node pattern){
		switch(pattern.getType()){
			case List:
			case DataConstructor:
			case Literal:
				this.last.addEdge(pattern, generator, Edge.Type.Value, EmptyConstraint.getConstraint());
				List<Node> children = last.getChildrenNonResult(pattern);
				for (Node child : children)
					this.generatePatternStructureEdges(generator, child);
				break;
			default:
				break;
		}
	}

	private void generateRoutineCallEdges()
	{
		final List<Node> calls = this.last.getNodes(Node.Type.Call);
@@ -212,6 +238,9 @@ public class ValueEdgeGenerator {
			if (this.last.getChildren(returnNode).isEmpty())
				continue;

			if (!isCFGReached(returnNode))
				continue;

			final Node returnExpr = this.last.getChild(returnNode, Node.Type.Value);
			final String returnText = returnNode.getName();
			final int dstId = Integer.parseInt(returnText.substring(returnText.lastIndexOf(" ") + 1));