Commit 2fb5c84f authored by Carlos Galindo's avatar Carlos Galindo
Browse files

Merge branch 'JSS_rainbow' into 'master'

Stop condition change for slicing

See merge request program-slicing/e-knife-erlang!1
parents 3f239493 04d23705
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ public abstract class EdgeConstraint extends Constraint
	}
	protected Constraints push(Phase phase, Constraints constraints)
	{
		// STACK IS FULL AND EXCEPTION IS RAISED
		if (phase.isInstanceof(Phase.Slicing) && constraints.sizeEdgeConstraints() == Config.MAX_STACK_SIZE)
			throw new StackOverflowError();
//if (phase.isInstanceof(Phase.SummaryGeneration) && constraints.sizeEdgeConstraints() == this.config.maxStackSize)
+6 −1
Original line number Diff line number Diff line
package edg.graph;

import edg.constraint.AsteriskConstraint;
import edg.constraint.Constraint;
import edg.constraint.EdgeConstraint;
import edg.constraint.EmptyConstraint;

@@ -22,6 +23,7 @@ public class Edge
	private boolean mark;
	private final Type type;
	private final EdgeConstraint constraint;
	private EdgeConstraint visibleConstraint;
	protected boolean traversable = true;
	private final int hash;

@@ -36,6 +38,7 @@ public class Edge
		Objects.requireNonNull(constraint, "Constraint can't be null, use 'EmptyConstraint#getConstraint()'");
		this.type = type;
		this.constraint = constraint;
		this.visibleConstraint = constraint;
		this.hash = new Random().nextInt();
	}

@@ -54,10 +57,12 @@ public class Edge
		return type;
	}

	public void resetVisibleConstraint() { this.visibleConstraint = this.constraint; }
	public EdgeConstraint getConstraint()
	{
		return constraint;
		return visibleConstraint;
	}
	public void setVisibleConstraint(EdgeConstraint constraint) { visibleConstraint = constraint;}

	public boolean isStructuralEdge()
	{
+112 −0
Original line number Diff line number Diff line
package edg.slicing;

import edg.graph.EDG;
import edg.graph.Edge;
import edg.graph.LAST;
import edg.graph.Node;

import java.util.*;

public class AdaptedTwoPassStandardAlgorithm extends StandardAlgorithm{

    public AdaptedTwoPassStandardAlgorithm(EDG edg) {
        super(edg);
    }

    public Set<Node> slice(Node slicingCriterion)
    {
        final Set<Node> slice = new HashSet<>();
        if (slicingCriterion == null)
            return slice;

        slice.add(slicingCriterion);
        this.traverse(slicingCriterion, slice, Edge.Type.Output);
        this.traverse(slicingCriterion, slice, Edge.Type.Input);

        return slice;
    }

    protected void traverse(Node slicingCriterion, Set<Node> slice, Edge.Type... ignoreEdgeTypes) {
        final Deque<SliceState> pendingNodes = new LinkedList<>();

        for (Node n : slice)
            pendingNodes.add(new SliceState(n,null));

        final Set<Edge.Type> ignoreEdgeTypesSet = new HashSet<>(Arrays.asList(ignoreEdgeTypes));

        while (!pendingNodes.isEmpty())
        {
            final SliceState pendingNode = pendingNodes.removeFirst();
            final Set<Edge> nextEdges = edg.getEdges(pendingNode.getNode(), sliceDirection);

            nextEdges.removeIf(e -> ignoreEdgeTypesSet.contains(e.getType()));
            nextEdges.removeIf(Edge::isControlFlowEdge);
            nextEdges.removeIf(e -> !e.isTraversable());

            if (pendingNode.getLastEdgeType() != null && pendingNode.getLastEdgeType() == Edge.Type.Structural)
                nextEdges.removeIf(e -> e.getType() != Edge.Type.Structural);

            for (Edge nextEdge : nextEdges)
            {
                final Node nextNode = sliceDirection == LAST.Direction.Backwards ?
                        edg.getEdgeSource(nextEdge): edg.getEdgeTarget(nextEdge);
                if (!slice.contains(nextNode))
                {
                    Node outerStructureNode = this.getOuterCompositeNode(nextNode);
                    if (outerStructureNode != null) {
                        List<Node> nextNodes = edg.getDescendants(outerStructureNode);
                        nextNodes.add(outerStructureNode);

                        if (nextNodes.contains(slicingCriterion))
                            nextNodes.removeIf(n -> n.getType() == Node.Type.Result);
                        nextNodes.add(edg.getResFromNode(nextNode));

                        for (Node next : nextNodes) {
                            pendingNodes.addLast(new SliceState(next,nextEdge.getType()));
                            slice.add(next);
                        }
                    }
                    else {
                        pendingNodes.addLast(new SliceState(nextNode,nextEdge.getType()));
                        slice.add(nextNode);
                    }
                }
            }
        }
    }
    public Node getOuterCompositeNode(Node node) {
        Node lastDataContainerParent = null;
        Node nextParent = edg.getParent(node);
        while (nextParent != null && isPossibleDataContainer(nextParent)){
            if (nextParent.getType() == Node.Type.List || nextParent.getType() == Node.Type.DataConstructor)
                lastDataContainerParent = nextParent;
            nextParent = edg.getParent(nextParent);
        }
        return lastDataContainerParent;
    }

    public boolean isPossibleDataContainer(Node parent) {
        switch (parent.getType()){
            case Equality:
            case Arguments:
            case Call:
            case Operation:
            case List:
            case DataConstructor:
                return true;
            default:
                return false;
        }
    }

    private class SliceState{
        private Node node;
        private Edge.Type lastEdgeType;
        public SliceState(Node n, Edge.Type type){
            node = n;
            lastEdgeType = type;
        }
        public Node getNode() { return node; }
        public Edge.Type getLastEdgeType() { return lastEdgeType; }
    }
}
+180 −0
Original line number Diff line number Diff line
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);

		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 List<Edge> traversedEdges = work.getTraversedEdges();
		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, traversedEdges, constraintsClone));
		}

		return newWorks;
	}

	private List<Work> processWork(Phase phase, EdgeWork work)
	{
		final List<Work> newWorks = new LinkedList<>();
		final Node initialNode = work.getInitialNode();
		final Edge currentEdge = work.getCurrentEdge();
		final List<Edge> traversedEdges = work.getTraversedEdges();
		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){
				List<Edge> traversedParam = new LinkedList<>();
				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 = true; // 2) TODO: WE CALL THE PDA TO EVALUATE THE LOOP
					// 2.B WE CAN OPTIONALLY SAVE THE LOOP OR MODIFY IT TO OPTIMISE FUTURE TRAVERSALS
					if (isIncreasingLoop) { // 3) IF THE LOOP IS INCREASING...
						// ALTERNATIVE 1: REMOVE STACK (ASTERISK CONSTRAINT) AND CONTINUE TRAVERSAL ADDING THE EDGE TO traversedEdges
						currentEdge.setVisibleConstraint(AsteriskConstraint.getConstraint());
						traversedParam.add(currentEdge);
						newWorks.add(new NodeWork(initialNode, nextNode, traversedParam, new Constraints(), edgeType));
					} else { // 4) IF THE LOOP IS NOT INCREASING

					}
				}
				else {
					switch (currentEdge.getType()) {
						case Flow: // SUMMARY EDGES MAY GENERATE IT TOO, BUT WE ARE INTRAPROCEDURAL NOW
						case Value:
							if (constraint instanceof AccessConstraint || !traversedEdges.isEmpty()) {
								traversedParam.addAll(traversedEdges);
								traversedParam.add(currentEdge);
							}
							break;
						default:
							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");
			// STACK FULL => EMPTY CONSTRAINT LIST (*)
			newWorks.add(new NodeWork(initialNode, nextNode, new Constraints(), edgeType));
		}

		return newWorks;
	}
}
+10 −2
Original line number Diff line number Diff line
@@ -23,18 +23,26 @@ import edg.graph.EDG;
import edg.graph.Edge;
import edg.graph.Node;

import java.util.LinkedList;
import java.util.List;

public class EdgeWork extends Work
{
	private final Edge currentEdge;

	public EdgeWork(EDG edg, Node initialNode, Edge currentEdge, Constraints constraints)
	public EdgeWork(EDG edg, Node initialNode, Edge currentEdge, List<Edge> traversed, Constraints constraints)
	{
		super(initialNode, constraints);
		super(initialNode, constraints, traversed);

		this.id = edg.getEdgeSource(currentEdge).getId() + "->" + edg.getEdgeTarget(currentEdge).getId();
		this.currentEdge = currentEdge;
	}

	public EdgeWork(EDG edg, Node initialNode, Edge currentEdge, Constraints constraints)
	{
		this(edg, initialNode, currentEdge, new LinkedList<>(), constraints);
	}

	public Edge getCurrentEdge()
	{
		return this.currentEdge;
Loading