Commit 03832b39 authored by Carlos Galindo's avatar Carlos Galindo
Browse files

ICFG: debug session

- #getTopologicalNumber: Now uses LinkedStack instead of Stack to avoid modifications in different recursion levels to affect each other.
- buildISCRGraph: removed apparently unnecessary code? This change should be thoroughly tested.
- Noted a couple red flags that should be investigated and solved.
parent 4cc0eb7c
Loading
Loading
Loading
Loading
Loading
+15 −15
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@ import es.upv.mist.slicing.arcs.cfg.ControlFlowArc;
import es.upv.mist.slicing.graphs.Buildable;
import es.upv.mist.slicing.graphs.CallGraph;
import es.upv.mist.slicing.graphs.ClassGraph;
import es.upv.mist.slicing.util.LinkedStack;
import es.upv.mist.slicing.graphs.augmented.ACFG;
import es.upv.mist.slicing.graphs.cfg.CFG;
import es.upv.mist.slicing.graphs.scrs.CallSCR;
@@ -148,10 +149,10 @@ public class ICFG extends es.upv.mist.slicing.graphs.Graph implements Buildable<
                }
            }
            //callGetTopologicalNumber for exitNode (predecessors are visited inside)
            getTopologicalNumber(exitNode, new HashSet<>(), new Stack<>(), new HashMap<>());
            getTopologicalNumber(exitNode, new HashSet<>(), new LinkedStack<>(), new HashMap<>());
        }

        private void getTopologicalNumber(IntraSCR node, Set<IntraSCR> processedIntraSCRs, Stack<IntraSCR> callStack, Map<IntraSCR, Set<IntraSCR>> callNodeProcessMap) {
        private void getTopologicalNumber(IntraSCR node, Set<IntraSCR> processedIntraSCRs, LinkedStack<IntraSCR> callStack, Map<IntraSCR, Set<IntraSCR>> callNodeProcessMap) {
            if (processedIntraSCRs.contains(node)) {
                return;
            }
@@ -160,14 +161,18 @@ public class ICFG extends es.upv.mist.slicing.graphs.Graph implements Buildable<
                if (isCallSCR(predecessor)) {
                    if (callStack.isEmpty() || !predecessor.equals(callStack.peek()))
                        continue; // Non-matching call nodes are ignored
                    callStack.pop();
                    callStack = callStack.pop();
                    if (!callStack.isEmpty())
                        callNodeProcessMap.get(callStack.peek()).add(predecessor);
                    getTopologicalNumber(predecessor, processedIntraSCRs, callStack, callNodeProcessMap);
                } else if (isReturnSCR(predecessor)) {
                    if (!callStack.isEmpty())
                        callNodeProcessMap.get(callStack.peek()).add(predecessor);
                    IntraSCR callNode = returnToCorrespondentCallMap.get(predecessor);
                    callStack.push(callNode);
                    callStack = callStack.push(callNode);
                    callNodeProcessMap.computeIfAbsent(callNode, k -> new HashSet<>());
                    getTopologicalNumber(predecessor, processedIntraSCRs, callStack, callNodeProcessMap);
                    if (callNodeProcessMap.containsKey(callNode))
                    assert callNodeProcessMap.containsKey(callNode);
                    processedIntraSCRs.removeAll(callNodeProcessMap.get(callNode));
                } else {
                    if (!callStack.isEmpty())
@@ -345,6 +350,8 @@ public class ICFG extends es.upv.mist.slicing.graphs.Graph implements Buildable<
                    }
                }
            }
            // RED FLAG: why does not deleting call->return edges make function numbering miss (it gets numbered, but fewer times than correct).
            // To see this bug, delete the following for loop.
            for (DefaultEdge deletedEdge : toBeDeletedSet) {
                intraSCRs.removeEdge(deletedEdge);
            }
@@ -415,19 +422,12 @@ public class ICFG extends es.upv.mist.slicing.graphs.Graph implements Buildable<
                            @SuppressWarnings("unchecked")
                            GraphNode<CallableDeclaration<?>> enterNode = (GraphNode<CallableDeclaration<?>>) arc.getSecond();
                            IntraSCR enterIntraSCR = getEnterIntraSCR(enterNode);
                            if(processedIntraSCRs.contains(enterIntraSCR)) {
                                IntraSCR returnIntraSCR = callToCorrespondentReturnMap.get(intraSCR);
                                buildISCRGraph(returnIntraSCR, processedIntraSCRs);
                            } else {
                                buildISCRGraph(enterIntraSCR, processedIntraSCRs);
                            }

                        }
                    }
                } else if(graphNode instanceof CallNode.Return) {
                    if(!processedIntraSCRs.contains(returnToCorrespondentCallMap.get(intraSCR))) {
                        processedIntraSCRs.remove(intraSCR);
                        return;
                    }
                    // RED FLAG: unmarks nodes in this algorithm???
                }
            } else {
                throw new IllegalStateException("The intraSCRs is empty");
+57 −0
Original line number Diff line number Diff line
package es.upv.mist.slicing.util;

import java.util.Objects;

/** A stack implemented with a single linked list
 *  that does not modify its internals, but return
 *  pointers to new stacks (or states of the stack)
 *  to implement stack copying efficiently.
 * @param <E> The type of element contained in the stack
 */
public class LinkedStack<E> {
    private final E element;
    private final LinkedStack<E> next;

    /**
     * Creates a new, empty stack.
     */
    public LinkedStack() {
        this(null, null);
    }

    private LinkedStack(E element, LinkedStack<E> next) {
        this.element = element;
        this.next = next;
    }

    /**
     * Adds a new element to the stack. Should be used as: <code>stack = stack.push(element)</code>,
     * as it does not modify this object, but create a new one.
     * @param element The element to be added.
     * @return The new state of the stack. Should always be used, otherwise this method has no effect.
     */
    public LinkedStack<E> push(E element) {
        Objects.requireNonNull(element);
        return new LinkedStack<>(element, this);
    }

    /**
     * Removes the top element from this stack. Should be used as: <code>stack = stack.pop()</code>.
     * To see the element that has been popped, the user should run {@link #peek()} before this method.
     * @return The new state of the stack, with one fewer element. Should always be used,
     * otherwise this method has no effect.
     */
    public LinkedStack<E> pop() {
        return next;
    }

    /** Obtains the element at the top of the stack. */
    public E peek() {
        return element;
    }

    /** Whether this stack is empty. */
    public boolean isEmpty() {
        return element == null && next == null;
    }
}