private void GenerateTryFinallyHandler(YieldExceptionHandlerInfo handlerInfo) { this.finallyBlocks = new HashSet <ILogicalConstruct>(); this.entryOfTry = this.GetStateBeginBlockConstruct(handlerInfo.get_TryStates()); this.BuildTryBody(handlerInfo); if (handlerInfo.get_HandlerType() != YieldExceptionHandlerType.Method) { V_0 = this.GenerateFinallyBlock(); } else { if (this.newFinallyBody == null) { throw new Exception("Could not determine the end ot the try block"); } this.RemoveExcessNodesFromTheTryBlock(); this.ProcessFinallyNodes(); stackVariable31 = this.newFinallyBody; stackVariable33 = new ILogicalConstruct[1]; stackVariable33[0] = this.newFinallyBody; V_0 = new BlockLogicalConstruct(stackVariable31, stackVariable33); } V_1 = new TryFinallyLogicalConstruct(new BlockLogicalConstruct(this.entryOfTry, this.newTryBody), V_0); this.createdConstructsToIntervalMap.set_Item(V_1, handlerInfo); this.CleanUpOrderedNodes(V_1); return; }
private bool CanBeLoopCondition(ILogicalConstruct node, HashSet <ILogicalConstruct> loopBody) { if (!loopBody.Contains(node)) { return(false); } if (node as ConditionLogicalConstruct == null) { return(false); } V_0 = 0; V_1 = node.get_SameParentSuccessors().GetEnumerator(); try { while (V_1.MoveNext()) { V_2 = (ILogicalConstruct)V_1.get_Current(); if (!loopBody.Contains(V_2)) { continue; } V_0 = V_0 + 1; } } finally { ((IDisposable)V_1).Dispose(); } return(V_0 == 1); }
private void ProcessGotoFlowConstructs(BlockLogicalConstruct theConstruct) { ILogicalConstruct[] sortedChildren = new ILogicalConstruct[theConstruct.Children.Count]; int index = 0; foreach (ILogicalConstruct child in theConstruct.Children) { sortedChildren[index++] = child; } Array.Sort <ISingleEntrySubGraph>(sortedChildren); HashSet <ILogicalConstruct> usedAsFollow = new HashSet <ILogicalConstruct>(); foreach (ILogicalConstruct currentChild in sortedChildren) { if (visitedConstructs.Add(currentChild)) { if (visitedConstructs.Contains(currentChild.FollowNode) || !usedAsFollow.Add(currentChild.FollowNode)) { currentChild.CFGFollowNode = null; } ProcessLogicalConstruct(currentChild); } } }
/// <summary> /// Removes the inner nodes of the try that are reachable by the finally node. /// </summary> /// <remarks> /// Do not traverse the entry of the try since there can be an actual loop. /// </remarks> private void RemoveExcessNodesFromTheTryBlock() { HashSet <ILogicalConstruct> markedForTraversal = new HashSet <ILogicalConstruct>(finallyBlocks); Queue <ILogicalConstruct> bfsQueue = new Queue <ILogicalConstruct>(finallyBlocks); while (bfsQueue.Count > 0) { ILogicalConstruct current = bfsQueue.Dequeue(); foreach (ILogicalConstruct successor in current.SameParentSuccessors) { if (!markedForTraversal.Contains(successor) && successor != entryOfTry) { markedForTraversal.Add(successor); bfsQueue.Enqueue(successor); } } } foreach (ILogicalConstruct node in markedForTraversal) { if (node != entryOfTry) { newTryBody.Remove(node); } } }
private void DetermineLoopBodyBlock(ILogicalConstruct entry, HashSet <ILogicalConstruct> loopBodyNodes) { this.set_LoopBodyBlock(null); if (loopBodyNodes.get_Count() > 0) { if (this.get_LoopType() != 1) { if (!loopBodyNodes.Contains(entry)) { throw new Exception("Invalid entry of loop body."); } this.set_LoopBodyBlock(new BlockLogicalConstruct(entry, loopBodyNodes)); return; } V_0 = this.get_LoopCondition().get_TrueSuccessor(); if (V_0 == null || !loopBodyNodes.Contains(V_0)) { V_0 = this.get_LoopCondition().get_FalseSuccessor(); } if (V_0 == null || !loopBodyNodes.Contains(V_0)) { throw new Exception("Invalid entry of loop body."); } this.set_LoopBodyBlock(new BlockLogicalConstruct(V_0, loopBodyNodes)); } return; }
/// <summary> /// Builds the try body of the specified exception handler starting from the given entry node. /// </summary> /// <remarks> /// We assume that all nodes before reaching the finally block are in the try construct. /// </remarks> /// <param name="handlerInfo"></param> /// <param name="entryOfTry"></param> private void BuildTryBody(YieldExceptionHandlerInfo handlerInfo) { newTryBody = new HashSet <ILogicalConstruct>(); newTryBody.Add(entryOfTry); newFinallyBody = null; HashSet <ILogicalConstruct> traversedNodes = new HashSet <ILogicalConstruct>(); Queue <ILogicalConstruct> bfsQueue = new Queue <ILogicalConstruct>(); foreach (ILogicalConstruct successor in entryOfTry.SameParentSuccessors) { bfsQueue.Enqueue(successor); } while (bfsQueue.Count > 0) { ILogicalConstruct currentNode = bfsQueue.Dequeue(); if (!traversedNodes.Add(currentNode) || finallyBlocks.Contains(currentNode)) { continue; } ProcessCurrentNode(handlerInfo, bfsQueue, currentNode); } }
private void DetermineFollowNodesInSubGraph(ILogicalConstruct theGraph) { this.GetVerticesAndAdjacencyMatrix(theGraph); V_0 = MaxWeightDisjointPathsFinder.GetOptimalEdgesInDAG(this.adjacencyMatrix).GetEnumerator(); try { while (V_0.MoveNext()) { V_1 = V_0.get_Current(); this.orderedVertexArray[V_1.get_Key()].set_CFGFollowNode(this.orderedVertexArray[V_1.get_Value()].get_FirstBlock()); if (this.orderedVertexArray[V_1.get_Key()] as ConditionLogicalConstruct == null) { continue; } V_2 = this.orderedVertexArray[V_1.get_Key()] as ConditionLogicalConstruct; if (V_2.get_CFGFollowNode() != V_2.get_TrueCFGSuccessor()) { continue; } V_2.Negate(this.typeSystem); } } finally { ((IDisposable)V_0).Dispose(); } return; }
/// <summary> /// Gets a collection of all possible latching nodes for a loop. Builds the body of the loop in the process. /// </summary> /// <param name="tree">The tree in which the loop was found.</param> /// <param name="loopBody">On exit contains the resulted loop body.</param> /// <returns>Returns collection of all possible latching nodes.</returns> private HashSet <ILogicalConstruct> BuildLoop(DFSTree tree, out HashSet <ILogicalConstruct> loopBody) { loopBody = new HashSet <ILogicalConstruct>(); HashSet <ILogicalConstruct> possibleLatchingNodes = new HashSet <ILogicalConstruct>(); /// Loops are defined by their backedges. foreach (DFSTEdge edge in tree.BackEdges) { ILogicalConstruct header = edge.End.Construct as ILogicalConstruct; ILogicalConstruct latchingNode = edge.Start.Construct as ILogicalConstruct; /// The edge between the header and the latching node was marked as goto-edge on an earlier step. if (removedEdges.ContainsKey(latchingNode) && removedEdges[latchingNode].Contains(header)) { continue; } ICollection <DFSTNode> shortLoopBody = tree.GetPath(edge.End, edge.Start); ICollection <DFSTNode> fullLoopBody = ExpandLoopBodyWithCrossEdges(shortLoopBody); ICollection <ILogicalConstruct> fullLoopBodyConstructs = GetConstructsCollection(fullLoopBody); if (CanBeLoop(header, latchingNode, fullLoopBody)) { possibleLatchingNodes.Add(latchingNode); foreach (ILogicalConstruct construct in fullLoopBodyConstructs) { loopBody.Add(construct); } } } return(possibleLatchingNodes); }
private void RemoveBackEdgesFromSwitchConstructs(ILogicalConstruct theConstruct) { V_0 = DFSTBuilder.BuildTree(theConstruct).get_BackEdges().GetEnumerator(); try { while (V_0.MoveNext()) { V_1 = V_0.get_Current(); V_2 = V_1.get_Start().get_Construct() as ILogicalConstruct; if (V_2 as ConditionLogicalConstruct != null) { continue; } V_3 = V_2 as CFGBlockLogicalConstruct; if (V_3 == null || V_3.get_TheBlock().get_Last().get_OpCode().get_Code() != 68) { continue; } this.MarkAsGotoEdge(V_2, V_1.get_End().get_Construct() as ILogicalConstruct); } } finally { ((IDisposable)V_0).Dispose(); } return; }
private static void AddSuccessorsToCount(ILogicalConstruct construct, Dictionary <CFGBlockLogicalConstruct, uint> numberOfHandlersLeavingToBlock) { V_0 = construct.get_CFGSuccessors().GetEnumerator(); try { while (V_0.MoveNext()) { V_1 = V_0.get_Current(); if (numberOfHandlersLeavingToBlock.ContainsKey(V_1)) { stackVariable10 = numberOfHandlersLeavingToBlock; V_2 = V_1; stackVariable10.set_Item(V_2, stackVariable10.get_Item(V_2) + 1); } else { numberOfHandlersLeavingToBlock.Add(V_1, 1); } } } finally { ((IDisposable)V_0).Dispose(); } return; }
private void AddNewHeaders(ILogicalConstruct currentHeader, IntervalConstruct currentInterval) { V_0 = new Stack <ILogicalConstruct>(); V_1 = new HashSet <ILogicalConstruct>(); V_0.Push(currentHeader); while (V_0.get_Count() > 0) { V_2 = V_0.Pop(); if (V_1.Contains(V_2)) { continue; } dummyVar0 = V_1.Add(V_2); V_3 = this.GetNodeSuccessors(V_2).GetEnumerator(); try { while (V_3.MoveNext()) { V_4 = V_3.get_Current(); this.CheckAndAddPossibleHeader(V_4, currentInterval, V_0); } } finally { if (V_3 != null) { V_3.Dispose(); } } } return; }
/// <summary> /// Creates a new case logical construct that is not yet attached to the logical tree. /// </summary> /// <param name="entry"></param> public CaseLogicalConstruct(ILogicalConstruct entry) { this.Entry = entry; this.body = new HashSet<ILogicalConstruct>(); body.Add(entry); CaseNumbers = new List<int>(); }
protected ILogicalConstruct[] GetSortedArrayFromCollection <T>(ICollection <T> collection) where T : ISingleEntrySubGraph { V_0 = new ILogicalConstruct[collection.get_Count()]; V_1 = 0; V_2 = collection.GetEnumerator(); try { while (V_2.MoveNext()) { V_3 = (ILogicalConstruct)(object)V_2.get_Current(); stackVariable13 = V_1; V_1 = stackVariable13 + 1; V_0[stackVariable13] = V_3; } } finally { if (V_2 != null) { V_2.Dispose(); } } Array.Sort <ISingleEntrySubGraph>(V_0); return(V_0); }
/// <summary> /// Gets the successors (direct or indirect) of the given <paramref name="startNode"/>, /// that are in the specified <paramref name="interval"/>. /// </summary> /// <remarks> /// If the start node is not in the interval, then it will not be traversed. This is a corner case for entwined loops. /// The start node will not be included in the result, even if it is its own successor. /// </remarks> /// <returns></returns> private HashSet <ILogicalConstruct> GetIntervalSuccessors(IntervalConstruct interval, ILogicalConstruct startNode) { HashSet <ILogicalConstruct> intervalSuccessors = new HashSet <ILogicalConstruct>(); if (!interval.Children.Contains(startNode)) { return(intervalSuccessors); } Queue <ILogicalConstruct> traversalQueue = new Queue <ILogicalConstruct>(); traversalQueue.Enqueue(startNode); HashSet <ILogicalConstruct> traversedNodes = new HashSet <ILogicalConstruct>(); traversedNodes.Add(startNode); while (traversalQueue.Count > 0) { ILogicalConstruct currentNode = traversalQueue.Dequeue(); foreach (ILogicalConstruct successor in currentNode.SameParentSuccessors) { if (!traversedNodes.Contains(successor) && interval.Children.Contains(successor) && intervalSuccessors.Add(successor)) { traversedNodes.Add(successor); traversalQueue.Enqueue(successor); } } } return(intervalSuccessors); }
private bool CanBeLoop(ILogicalConstruct header, ILogicalConstruct latchingNode, ICollection <DFSTNode> nodesInLoop) { if (header == null || latchingNode == null) { return(false); } V_0 = this.GetConstructsCollection(nodesInLoop); V_1 = V_0.GetEnumerator(); try { while (V_1.MoveNext()) { V_2 = V_1.get_Current(); if (this.CanBeInLoop(V_2, V_0, header)) { continue; } V_3 = false; goto Label1; } goto Label0; } finally { if (V_1 != null) { V_1.Dispose(); } } Label1: return(V_3); Label0: return(true); }
/// <summary> /// Determines whether the specified <paramref name="node"/> can be a condition to the loop with body - <paramref name="loopBody"/>. /// </summary> /// <param name="node">The possible condition node.</param> /// <param name="loopBody">The body of the loop.</param> /// <returns>Returns true, if <paramref name="node"/> can be the condition of the loop.</returns> private bool CanBeLoopCondition(ILogicalConstruct node, HashSet <ILogicalConstruct> loopBody) { if (!loopBody.Contains(node)) { //The node should be inside the loop. return(false); } if (node is ConditionLogicalConstruct) { HashSet <ISingleEntrySubGraph> nodeSuccessors = node.SameParentSuccessors; int insideBody = 0; foreach (ILogicalConstruct successor in nodeSuccessors) { if (loopBody.Contains(successor)) { insideBody++; } } //There should be exactly one successor that is inside the body of the loop. return(insideBody == 1); } return(false); }
/// <summary> /// Checks if single node can be in a loop. The loop is determined by <paramref name="loopHeader"/> and has <paramref name="nodesInLoop"/> for its body. /// </summary> /// <param name="node">The node in question.</param> /// <param name="nodesInLoop">The other nodes in the body of the loop.</param> /// <param name="loopHeader">The header of the loop.</param> /// <returns>Returns true, if <paramref name="node"/> can be in the loop.</returns> private bool CanBeInLoop(ILogicalConstruct node, ICollection <ILogicalConstruct> nodesInLoop, ILogicalConstruct loopHeader) { if (node == null) { return(false); } if (node == loopHeader) { /// The header is always part of the loop. return(true); } foreach (ISingleEntrySubGraph predecessor in node.SameParentPredecessors) { ILogicalConstruct predecessorLogicalConstruct = predecessor as ILogicalConstruct; if (predecessorLogicalConstruct == null) { return(false); } HashSet <ILogicalConstruct> removedEdgesEnds; if (!nodesInLoop.Contains(predecessorLogicalConstruct) || (removedEdges.TryGetValue(predecessorLogicalConstruct, out removedEdgesEnds) && removedEdgesEnds.Contains(node))) { /// The predecessor is not part of the loop. /// Or it was marked for goto on earlier stage. /// Either way this is multy-entry loop, which is not allowed return(false); } } return(true); }
/// <summary> /// The entry point of the builder. /// </summary> /// <param name="block">The logical construct, that is searched for loops.</param> public void BuildLoops(ILogicalConstruct block) { if (block.Children.Count == 0) { return; } foreach (ISingleEntrySubGraph child in block.Children) { //all children should be logical constructs ILogicalConstruct childConstruct = child as ILogicalConstruct; if (childConstruct == null) { throw new ArgumentException("Child is not a logical construct."); } if (childConstruct is ConditionLogicalConstruct) { //no loops should be found inside logical constructs //this covers the rare case in which a single block is condition and body of the loop at the same time continue; } /// Build the inner-most loops first. BuildLoops(childConstruct); } ProcessLogicalConstruct(block); }
public void ProcessConstruct(ILogicalConstruct theConstruct) { if (theConstruct as CFGBlockLogicalConstruct != null || theConstruct as ConditionLogicalConstruct != null) { return; } if (theConstruct as BlockLogicalConstruct != null) { this.DetermineFollowNodesInSubGraph(theConstruct); } V_0 = theConstruct.get_Children().GetEnumerator(); try { while (V_0.MoveNext()) { V_1 = (ILogicalConstruct)V_0.get_Current(); this.ProcessConstruct(V_1); } } finally { ((IDisposable)V_0).Dispose(); } return; }
private bool ArePredecessorsLegal(ILogicalConstruct node, HashSet <ILogicalConstruct> allowedPredecessors) { V_0 = node.get_SameParentPredecessors().GetEnumerator(); try { while (V_0.MoveNext()) { V_1 = (ILogicalConstruct)V_0.get_Current(); if (allowedPredecessors.Contains(V_1)) { continue; } V_2 = false; goto Label1; } goto Label0; } finally { ((IDisposable)V_0).Dispose(); } Label1: return(V_2); Label0: return(true); }
/// <summary> /// Creates a new case logical construct that is not yet attached to the logical tree. /// </summary> /// <param name="entry"></param> public CaseLogicalConstruct(ILogicalConstruct entry) { this.Entry = entry; this.body = new HashSet <ILogicalConstruct>(); body.Add(entry); CaseNumbers = new List <int>(); }
/// <summary> /// Creates the loop body block. /// </summary> /// <param name="entry"></param> /// <param name="loopBodyNodes"></param> private void DetermineLoopBodyBlock(ILogicalConstruct entry, HashSet <ILogicalConstruct> loopBodyNodes) { this.LoopBodyBlock = null; if (loopBodyNodes.Count > 0) { if (this.LoopType != LoopType.PreTestedLoop) { //If the loop is not pretested then the entry should be the entry of the loop body if (!loopBodyNodes.Contains(entry)) { //sanity check throw new Exception("Invalid entry of loop body."); } this.LoopBodyBlock = new BlockLogicalConstruct(entry, loopBodyNodes); } else { //Otherwise the entry should be the successor of the condition that is in the collection. ILogicalConstruct loopBodyEntry = LoopCondition.TrueSuccessor; if (loopBodyEntry == null || !loopBodyNodes.Contains(loopBodyEntry)) { loopBodyEntry = LoopCondition.FalseSuccessor; } if (loopBodyEntry == null || !loopBodyNodes.Contains(loopBodyEntry)) { //sanity check throw new Exception("Invalid entry of loop body."); } this.LoopBodyBlock = new BlockLogicalConstruct(loopBodyEntry, loopBodyNodes); } } }
public void BuildLoops(ILogicalConstruct block) { if (block.get_Children().get_Count() == 0) { return; } V_0 = block.get_Children().GetEnumerator(); try { while (V_0.MoveNext()) { V_1 = V_0.get_Current() as ILogicalConstruct; if (V_1 == null) { throw new ArgumentException("Child is not a logical construct."); } if (V_1 as ConditionLogicalConstruct != null) { continue; } this.BuildLoops(V_1); } } finally { ((IDisposable)V_0).Dispose(); } this.ProcessLogicalConstruct(block); return; }
private bool CanBePartOfComplexCondition(ILogicalConstruct node, HashSet <ILogicalConstruct> nodesInCondition, CFGBlockLogicalConstruct commonSuccessor) { if (node == null || node as ConditionLogicalConstruct == null || !this.ArePredecessorsLegal(node, nodesInCondition) || !node.get_CFGSuccessors().Contains(commonSuccessor)) { return(false); } return(!nodesInCondition.Contains(node)); }
/// <summary> /// Determines whether the specified node can be added in a complex condition. /// </summary> /// <param name="node">The node that we want to add to the condition.</param> /// <param name="nodesInCondition">The nodes that are in the complex condition.</param> /// <param name="commonSuccessor">The supposed common successor.</param> /// <returns></returns> private bool CanBePartOfComplexCondition(ILogicalConstruct node, HashSet <ILogicalConstruct> nodesInCondition, CFGBlockLogicalConstruct commonSuccessor) { //In order to add the node to the condition it has to be a condition node. All of it's predecessors should be in the complex condition. //The node should have for successor the supposed common successor (the check is optimized). And the node should not be part of the complex //condition. return(node != null && node is ConditionLogicalConstruct && ArePredecessorsLegal(node, nodesInCondition) && node.CFGSuccessors.Contains(commonSuccessor) && !nodesInCondition.Contains(node)); }
private ILogicalConstruct CheckSuccessor(ILogicalConstruct condition, ILogicalConstruct conditionSuccessor, HashSet <ISingleEntrySubGraph> otherSuccessorFrontier, DFSTree dfsTree) { if (otherSuccessorFrontier.Contains(conditionSuccessor) && !dfsTree.get_ConstructToNodeMap().TryGetValue(conditionSuccessor, out V_0) || dfsTree.get_ConstructToNodeMap().get_Item(condition).CompareTo(V_0) < 0) { return(conditionSuccessor); } return(null); }
/// <summary> /// Fills <paramref name="interval"/> with the nodes, that belong to it. /// </summary> /// <param name="intervalHeader">The header node of <paramref name="interval"/>.</param> /// <param name="interval">The interval to be filled with nodes.</param> private void FillInterval(ILogicalConstruct intervalHeader, IntervalConstruct interval) { /// For more clarifications on the algorithm, see "6.3.3 Interval Theory" of <see cref="Reverse Compilation Techniques.pdf"/>. nodeToInterval.Add(intervalHeader, interval); Queue <ILogicalConstruct> possibleNodes = new Queue <ILogicalConstruct>(); IEnumerable <ILogicalConstruct> currentNodeSuccessors = GetNodeSuccessors(intervalHeader); foreach (ILogicalConstruct successor in currentNodeSuccessors) { /// Check if the successor is from the graph that is being analysed /// This check is needed, because GetNodeSuccessors returns all successors, even the one that have been marked only as goto reachable. if (availableNodes.Contains(successor)) { possibleNodes.Enqueue(successor); } } while (possibleNodes.Count > 0) { ILogicalConstruct currentNode = possibleNodes.Dequeue(); //check if the node is in any interval if (nodeToInterval.ContainsKey(currentNode)) { continue; } bool addInInterval = true; IEnumerable <ILogicalConstruct> currentNodePredecessorsCollection = GetNodePredecessors(currentNode); foreach (ILogicalConstruct predecessor in currentNodePredecessorsCollection) { if (!nodeToInterval.ContainsKey(predecessor) || nodeToInterval[predecessor] != interval) { /// The construct has a predecessor, that is not from the current interval. /// Thus, the construct is not dominated by the interval header, and isnt part of the interval addInInterval = false; break; } } if (addInInterval) { /// Add the node to the interval and update the corresponding collections. interval.Children.Add(currentNode); nodeToInterval.Add(currentNode, interval); currentNodeSuccessors = GetNodeSuccessors(currentNode); /// Update the possible nodes collection with all the successors of the current node. foreach (ILogicalConstruct successor in currentNodeSuccessors) { if (availableNodes.Contains(successor)) { possibleNodes.Enqueue(successor); } } } } }
/// <param name="graph">The graph to be analyzed by the interval builder.</param> /// <param name="removedEdges">The edges in the Control flow graph, that have been marked as goto-edges.</param> public IntervalAnalyzer(ISingleEntrySubGraph graph, Dictionary<ILogicalConstruct, HashSet<ILogicalConstruct>> removedEdges) { this.availableNodes = graph.Children; this.entryPoint = graph.Entry as ILogicalConstruct; this.headers = new Queue<ILogicalConstruct>(); this.intervals = new List<IntervalConstruct>(); this.nodeToInterval = new Dictionary<ISingleEntrySubGraph, IntervalConstruct>(); this.removedEdges = removedEdges; }
/// <summary> /// Fills <paramref name="interval"/> with the nodes, that belong to it. /// </summary> /// <param name="intervalHeader">The header node of <paramref name="interval"/>.</param> /// <param name="interval">The interval to be filled with nodes.</param> private void FillInterval(ILogicalConstruct intervalHeader, IntervalConstruct interval) { /// For more clarifications on the algorithm, see "6.3.3 Interval Theory" of <see cref="Reverse Compilation Techniques.pdf"/>. nodeToInterval.Add(intervalHeader, interval); Queue<ILogicalConstruct> possibleNodes = new Queue<ILogicalConstruct>(); IEnumerable<ILogicalConstruct> currentNodeSuccessors = GetNodeSuccessors(intervalHeader); foreach (ILogicalConstruct successor in currentNodeSuccessors) { /// Check if the successor is from the graph that is being analysed /// This check is needed, because GetNodeSuccessors returns all successors, even the one that have been marked only as goto reachable. if (availableNodes.Contains(successor)) { possibleNodes.Enqueue(successor); } } while (possibleNodes.Count > 0) { ILogicalConstruct currentNode = possibleNodes.Dequeue(); //check if the node is in any interval if (nodeToInterval.ContainsKey(currentNode)) { continue; } bool addInInterval = true; IEnumerable<ILogicalConstruct> currentNodePredecessorsCollection = GetNodePredecessors(currentNode); foreach (ILogicalConstruct predecessor in currentNodePredecessorsCollection) { if (!nodeToInterval.ContainsKey(predecessor) || nodeToInterval[predecessor] != interval) { /// The construct has a predecessor, that is not from the current interval. /// Thus, the construct is not dominated by the interval header, and isnt part of the interval addInInterval = false; break; } } if (addInInterval) { /// Add the node to the interval and update the corresponding collections. interval.Children.Add(currentNode); nodeToInterval.Add(currentNode, interval); currentNodeSuccessors = GetNodeSuccessors(currentNode); /// Update the possible nodes collection with all the successors of the current node. foreach (ILogicalConstruct successor in currentNodeSuccessors) { if (availableNodes.Contains(successor)) { possibleNodes.Enqueue(successor); } } } } }
protected DominatorTree GetDominatorTreeFromContext(ILogicalConstruct construct) { if (!this.logicalContext.get_LogicalConstructToDominatorTreeMap().TryGetValue(construct, out V_0)) { V_0 = FastDominatorTreeBuilder.BuildTree(construct); this.logicalContext.get_LogicalConstructToDominatorTreeMap().Add(construct, V_0); } return(V_0); }
public CaseLogicalConstruct(ILogicalConstruct entry) { base(); this.set_Entry(entry); this.body = new HashSet <ILogicalConstruct>(); dummyVar0 = this.body.Add(entry); this.set_CaseNumbers(new List <int>()); return; }
/// <summary> /// Builds if constructs in the specified construct. /// </summary> /// <param name="construct"></param> private void BuildIfConstructs(ILogicalConstruct construct) { DominatorTree dominatorTree = GetDominatorTreeFromContext(construct); DFSTree dfsTree = DFSTBuilder.BuildTree(construct); foreach (ConditionLogicalConstruct condition in GetPostOrderedIfConditionCandidates(dfsTree)) { TryBuildIfConstruct(condition, dominatorTree, dfsTree); } }
/// <summary> /// Returns the closest guarded block (try/catch/filter/fault/finally) that encloses the given construct. /// </summary> /// <param name="start">The construct for which the guarded block parent should be found</param> /// <returns></returns> public static BlockLogicalConstruct GetNearestGuardedBlock(ILogicalConstruct start) { ILogicalConstruct nearestGuardedBlockCandidate = start; while (nearestGuardedBlockCandidate != null && !(nearestGuardedBlockCandidate is ExceptionHandlingLogicalConstruct)) { nearestGuardedBlockCandidate = (ILogicalConstruct)nearestGuardedBlockCandidate.Parent; } if (nearestGuardedBlockCandidate == null) { return(null); } if ((nearestGuardedBlockCandidate as ExceptionHandlingLogicalConstruct).Try.CFGBlocks.Contains(start.FirstBlock)) { return((nearestGuardedBlockCandidate as ExceptionHandlingLogicalConstruct).Try); } if (nearestGuardedBlockCandidate is TryCatchFilterLogicalConstruct) { TryCatchFilterLogicalConstruct tcf = nearestGuardedBlockCandidate as TryCatchFilterLogicalConstruct; foreach (IFilteringExceptionHandler handler in tcf.Handlers) { if (handler.HandlerType == FilteringExceptionHandlerType.Filter) { if ((handler as ExceptionHandlingBlockFilter).Filter.CFGBlocks.Contains(start.FirstBlock)) { return((handler as ExceptionHandlingBlockFilter).Filter); } else { return((handler as ExceptionHandlingBlockFilter).Handler); } } else if (handler.HandlerType == FilteringExceptionHandlerType.Catch) { return(handler as ExceptionHandlingBlockCatch); } } } else if (nearestGuardedBlockCandidate is TryFinallyLogicalConstruct) { return((nearestGuardedBlockCandidate as TryFinallyLogicalConstruct).Finally); } else if (nearestGuardedBlockCandidate is TryFaultLogicalConstruct) { return((nearestGuardedBlockCandidate as TryFaultLogicalConstruct).Fault); } else { throw new Exception("Unknown type of exception handling logical construct encountered."); } return(null); }
/// <param name="graph">The graph to be analyzed by the interval builder.</param> /// <param name="removedEdges">The edges in the Control flow graph, that have been marked as goto-edges.</param> public IntervalAnalyzer(ISingleEntrySubGraph graph, Dictionary <ILogicalConstruct, HashSet <ILogicalConstruct> > removedEdges) { this.availableNodes = graph.Children; this.entryPoint = graph.Entry as ILogicalConstruct; this.headers = new Queue <ILogicalConstruct>(); this.intervals = new List <IntervalConstruct>(); this.nodeToInterval = new Dictionary <ISingleEntrySubGraph, IntervalConstruct>(); this.removedEdges = removedEdges; }
/// <summary> /// Returns the closest guarded block (try/catch/filter/fault/finally) that encloses the given construct. /// </summary> /// <param name="start">The construct for which the guarded block parent should be found</param> /// <returns></returns> public static BlockLogicalConstruct GetNearestGuardedBlock(ILogicalConstruct start) { ILogicalConstruct nearestGuardedBlockCandidate = start; while (nearestGuardedBlockCandidate != null && !(nearestGuardedBlockCandidate is ExceptionHandlingLogicalConstruct)) { nearestGuardedBlockCandidate = (ILogicalConstruct)nearestGuardedBlockCandidate.Parent; } if (nearestGuardedBlockCandidate == null) { return null; } if ((nearestGuardedBlockCandidate as ExceptionHandlingLogicalConstruct).Try.CFGBlocks.Contains(start.FirstBlock)) { return (nearestGuardedBlockCandidate as ExceptionHandlingLogicalConstruct).Try; } if (nearestGuardedBlockCandidate is TryCatchFilterLogicalConstruct) { TryCatchFilterLogicalConstruct tcf = nearestGuardedBlockCandidate as TryCatchFilterLogicalConstruct; foreach(IFilteringExceptionHandler handler in tcf.Handlers) { if (handler.HandlerType == FilteringExceptionHandlerType.Filter) { if ((handler as ExceptionHandlingBlockFilter).Filter.CFGBlocks.Contains(start.FirstBlock)) { return (handler as ExceptionHandlingBlockFilter).Filter; } else { return (handler as ExceptionHandlingBlockFilter).Handler; } } else if (handler.HandlerType == FilteringExceptionHandlerType.Catch) { return handler as ExceptionHandlingBlockCatch; } } } else if (nearestGuardedBlockCandidate is TryFinallyLogicalConstruct) { return (nearestGuardedBlockCandidate as TryFinallyLogicalConstruct).Finally; } else if (nearestGuardedBlockCandidate is TryFaultLogicalConstruct) { return (nearestGuardedBlockCandidate as TryFaultLogicalConstruct).Fault; } else { throw new Exception("Unknown type of exception handling logical construct encountered."); } return null; }
private void ProcessSwitchConstructs(ILogicalConstruct parent, List<CFGBlockLogicalConstruct> switchBlocks) { DominatorTree dominatorTree = GetDominatorTreeFromContext(parent); DFSTree dfsTree = DFSTBuilder.BuildTree(parent); switchBlocks.Sort((x, y) => dfsTree.ConstructToNodeMap[y].ReversePostOrderIndex.CompareTo(dfsTree.ConstructToNodeMap[x].ReversePostOrderIndex)); foreach (CFGBlockLogicalConstruct switchBlock in switchBlocks) { CreateSwitchConstruct(switchBlock, parent, this.logicalContext.CFG.SwitchBlocksInformation[switchBlock.TheBlock], dominatorTree); } }
protected DominatorTree GetDominatorTreeFromContext(ILogicalConstruct construct) { DominatorTree result; if (!logicalContext.LogicalConstructToDominatorTreeMap.TryGetValue(construct, out result)) { result = FastDominatorTreeBuilder.BuildTree(construct); logicalContext.LogicalConstructToDominatorTreeMap.Add(construct, result); } return result; }
/// <summary> /// Creates a collection holding all the children (to be) of the construct. /// </summary> /// <returns></returns> private ICollection<ILogicalConstruct> GetBodyCollection() { int additionalNodes = this.DefaultCase != null ? 2 : 1; ILogicalConstruct[] switchBody = new ILogicalConstruct[this.ConditionCases.Length + additionalNodes]; Array.Copy(this.ConditionCases, switchBody, this.ConditionCases.Length); switchBody[switchBody.Length - additionalNodes] = this.Entry as ILogicalConstruct; if (additionalNodes == 2) { switchBody[switchBody.Length - 1] = this.DefaultCase; } return switchBody; }
/// <summary> /// Builds if constructs in the specified construct and all of it's children. /// </summary> /// <param name="construct"></param> public void BuildConstructs(ILogicalConstruct construct) { if(construct is CFGBlockLogicalConstruct || construct is ConditionLogicalConstruct) { return; } foreach (ILogicalConstruct child in construct.Children) { BuildConstructs(child); } BuildIfConstructs(construct); }
/// <summary> /// Traverses the graph and tries to merge conditions into complex condition constructs. /// </summary> /// <param name="theConstruct"></param> /// <returns>Returns true if there was a successful merge.</returns> private bool TryTraverseAndMerge(ILogicalConstruct theConstruct) { //The algorithm is split into iterations, because once it merges a complex condition this condition can be used with one of //its predecessors to create another complex condition. This means that special modifications are needed to the traversal, //which may lead to bugs and is overall more hard to maintain. //We use BFS to traverse the subgraph HashSet<ILogicalConstruct> traversedNodes = new HashSet<ILogicalConstruct>(); Queue<ILogicalConstruct> traverseQueue = new Queue<ILogicalConstruct>(); traverseQueue.Enqueue(theConstruct.Entry as ILogicalConstruct); bool changed = false; while (traverseQueue.Count > 0) { ILogicalConstruct currentNode = traverseQueue.Dequeue(); //For each node that is a condition construct we try to create a complex condition starting from it ConditionLogicalConstruct currentConditionNode = currentNode as ConditionLogicalConstruct; if(currentConditionNode != null) { ConditionLogicalConstruct newNode = CreateComplexCondition(currentConditionNode); //If we succeed we mark that there was a change in the subgraph; changed |= newNode != currentNode; //We change the currentNode to the newNode since if there was a merge then the currentNode will be a successor of the newNode currentNode = newNode; } //We mark the current node as traversed traversedNodes.Add(currentNode); //Normal bfs continues foreach (ILogicalConstruct successor in currentNode.SameParentSuccessors) { if(!traversedNodes.Contains(successor)) { traverseQueue.Enqueue(successor); } } while(traverseQueue.Count > 0 && traversedNodes.Contains(traverseQueue.Peek())) { traverseQueue.Dequeue(); } } return changed; }
/// <summary> /// Generates the loops in the graph with entry point <paramref name="construct"/>. /// </summary> /// <param name="construct">The entry point of the graph.</param> private void ProcessLogicalConstruct(ILogicalConstruct construct) { DominatorTree dominatorTree = GetDominatorTreeFromContext(construct); int lastIterationIntervalsCount = int.MaxValue; RemoveBackEdgesFromSwitchConstructs(construct); while (lastIterationIntervalsCount > 1) { IntervalAnalyzer ia = new IntervalAnalyzer(construct, removedEdges); List<IntervalConstruct> intervals = ia.ReduceCfg(); List<IntervalConstruct> reverseIntervals = new List<IntervalConstruct>(intervals); reverseIntervals.Reverse(); /// Make only one loop at a time, since the newly made loop can be the header node of a bigger loop (if they are nested so). bool madeLoop = false; foreach (IntervalConstruct interval in reverseIntervals) { if (TryMakeLoop(interval, dominatorTree)) { madeLoop = true; break; } } if(madeLoop) { lastIterationIntervalsCount = intervals.Count; continue; } /// No loop was made in the last iteration and the interval count wasn't reduced. Then, an edge must be deleted from the graph, /// to ensure the reducibility. if (intervals.Count == lastIterationIntervalsCount) { RemoveBlockingEdges(intervals); } /// This is sanity check. Intervals are supposed to decrease in count, or stay the same with each iteration if (intervals.Count > lastIterationIntervalsCount) { throw new Exception("Intervails are more than in the last iteration."); } lastIterationIntervalsCount = intervals.Count; } }
/// <summary> /// Recursively determines the follow nodes of all logical constructs in the given construct. /// </summary> /// <remarks> /// We need to determine only the follow nodes of the constructs that are children of block logical constructs. In every other construct /// the order is determined by the type of the construct. /// </remarks> /// <param name="theConstruct"></param> public void ProcessConstruct(ILogicalConstruct theConstruct) { if(theConstruct is CFGBlockLogicalConstruct || theConstruct is ConditionLogicalConstruct) { return; } if (theConstruct is BlockLogicalConstruct) { DetermineFollowNodesInSubGraph(theConstruct); } foreach (ILogicalConstruct child in theConstruct.Children) { ProcessConstruct(child); } }
private void CreateSwitchConstruct(CFGBlockLogicalConstruct switchBlock, ILogicalConstruct parentConstruct, SwitchData switchData, DominatorTree dominatorTree) { List<KeyValuePair<CFGBlockLogicalConstruct, List<int>>> cfgSuccessorToLabelsMap = GetOrderedCFGSuccessorToLabelsMap(switchData); Dictionary<ILogicalConstruct, HashSet<ISingleEntrySubGraph>> validCaseEntryToDominatedNodesMap = GetValidCases(dominatorTree, switchBlock); List<CaseLogicalConstruct> orderedCaseConstructs = new List<CaseLogicalConstruct>(); PairList<List<int>, CFGBlockLogicalConstruct> labelsToCFGSuccessorsList = new PairList<List<int>, CFGBlockLogicalConstruct>(); foreach (KeyValuePair<CFGBlockLogicalConstruct, List<int>> cfgSuccessorToLabelsPair in cfgSuccessorToLabelsMap) { ILogicalConstruct successor; HashSet<ISingleEntrySubGraph> dominatedNodes; if (LogicalFlowUtilities.TryGetParentConstructWithGivenParent(cfgSuccessorToLabelsPair.Key, parentConstruct, out successor) && validCaseEntryToDominatedNodesMap.TryGetValue(successor, out dominatedNodes)) { CaseLogicalConstruct newCaseConstruct = new CaseLogicalConstruct(successor); newCaseConstruct.CaseNumbers.AddRange(cfgSuccessorToLabelsPair.Value); newCaseConstruct.Body.UnionWith(dominatedNodes.Cast<ILogicalConstruct>()); newCaseConstruct.AttachCaseConstructToGraph(); orderedCaseConstructs.Add(newCaseConstruct); } else { labelsToCFGSuccessorsList.Add(cfgSuccessorToLabelsPair.Value, cfgSuccessorToLabelsPair.Key); } } CaseLogicalConstruct defaultCase = null; CFGBlockLogicalConstruct defaultCFGSuccessor = GetCFGLogicalConstructFromBlock(switchData.DefaultCase); ILogicalConstruct defaultSuccessor; HashSet<ISingleEntrySubGraph> defaultCaseNodes; if (LogicalFlowUtilities.TryGetParentConstructWithGivenParent(defaultCFGSuccessor, parentConstruct, out defaultSuccessor) && validCaseEntryToDominatedNodesMap.TryGetValue(defaultSuccessor, out defaultCaseNodes)) { defaultCase = new CaseLogicalConstruct(defaultSuccessor); if (HasSuccessors(defaultCaseNodes)) { defaultCase.Body.UnionWith(defaultCaseNodes.Cast<ILogicalConstruct>()); } defaultCase.AttachCaseConstructToGraph(); } SwitchLogicalConstruct theSwitch = SwitchLogicalConstruct.GroupInSwitchConstruct(switchBlock, orderedCaseConstructs, labelsToCFGSuccessorsList, defaultCase, defaultCFGSuccessor); UpdateDominatorTree(dominatorTree, theSwitch); }
/// <summary> /// Merges the simple condition constructs into complex condition constructs representing a short-circuit boolean expression. /// </summary> /// <param name="theConstruct"></param> private void CreateComplexConditions(ILogicalConstruct theConstruct) { //If the construct is ConditionLC then there is no need to traverse it. if(theConstruct is ConditionLogicalConstruct || theConstruct is CFGBlockLogicalConstruct) { return; } foreach (ILogicalConstruct child in theConstruct.Children) { CreateComplexConditions(child); } //Each iteration tries to find and merge new condition constructs together. bool mergedCondition; do { mergedCondition = TryTraverseAndMerge(theConstruct); } while (mergedCondition); }
/// <summary> /// Determines the follow nodes in the given subgraph. /// </summary> /// <remarks> /// Every node can follow only one node. /// Everey node can be followed by only one node. /// The follow node relation cannot form a back edge. (i.e. B can be the follow node of A <=> (A, B) is not a backedge) /// Let G = (V, E) be the original graph. /// Let G' = (V, E') be the subgraph of G, where E' = E \ { e | e is from E && e is backedge in the DFS traversal }. /// /// The solution is to find a cover of vertex-disjoint paths of G' that will yield the minimum number of gotos. /// The gotos will be the edges that are not in the cover. So we want the edges that will yeild the greatest number of gotos to /// be in the cover. If we find a good weight function for the edges in the graph (i.e. correctly determines how much gotos there will be between /// two nodes), then all we have to do is find a cover of vertex-disjoint paths of G' with maximum total weight. /// </remarks> /// <param name="theGraph"></param> private void DetermineFollowNodesInSubGraph(ILogicalConstruct theGraph) { //Creates the adjacency matrix for the mentioned subgraph - G'. GetVerticesAndAdjacencyMatrix(theGraph); //Since no back edge is left in G', then G' is a DAG. List<KeyValuePair<int, int>> followEdges = MaxWeightDisjointPathsFinder.GetOptimalEdgesInDAG(adjacencyMatrix); foreach (KeyValuePair<int, int> followEdge in followEdges) { orderedVertexArray[followEdge.Key].CFGFollowNode = orderedVertexArray[followEdge.Value].FirstBlock; if(orderedVertexArray[followEdge.Key] is ConditionLogicalConstruct) { ConditionLogicalConstruct theCondition = orderedVertexArray[followEdge.Key] as ConditionLogicalConstruct; if(theCondition.CFGFollowNode == theCondition.TrueCFGSuccessor) { //If the follow node of a condition construct is the true successor, then we need to negate the condition construct. theCondition.Negate(typeSystem); } } } }
/// <summary> /// Creates a new loop construct and attaches it to the logical tree. /// </summary> /// <param name="entry">The entry to the loop construct.</param> /// <param name="loopBody">Collection containing all of the constructs in the loop body.</param> /// <param name="loopType">The type of the loop.</param> /// <param name="loopCondition">The condition of the loop.</param> public LoopLogicalConstruct(ILogicalConstruct entry, HashSet<ILogicalConstruct> loopBody, LoopType loopType, ConditionLogicalConstruct loopCondition, TypeSystem typeSystem) { if (loopCondition != null) { loopCondition.LogicalContainer = this; } LoopType = loopType; LoopCondition = loopCondition; if(this.LoopType != LoopType.InfiniteLoop) { loopBody.Remove(LoopCondition); } DetermineLoopBodyBlock(entry, loopBody); RedirectChildrenToNewParent(GetLoopChildrenCollection()); FixLoopCondition(typeSystem); }
private void ProcessGotoFlowConstructs(BlockLogicalConstruct theConstruct) { ILogicalConstruct[] sortedChildren = new ILogicalConstruct[theConstruct.Children.Count]; int index = 0; foreach (ILogicalConstruct child in theConstruct.Children) { sortedChildren[index++] = child; } Array.Sort<ISingleEntrySubGraph>(sortedChildren); HashSet<ILogicalConstruct> usedAsFollow = new HashSet<ILogicalConstruct>(); foreach (ILogicalConstruct currentChild in sortedChildren) { if(visitedConstructs.Add(currentChild)) { if (visitedConstructs.Contains(currentChild.FollowNode) || !usedAsFollow.Add(currentChild.FollowNode)) { currentChild.CFGFollowNode = null; } ProcessLogicalConstruct(currentChild); } } }
private void ProcessLogicalConstruct(ILogicalConstruct theConstruct) { if (theConstruct is BlockLogicalConstruct) { ILogicalConstruct current = (ILogicalConstruct)theConstruct.Entry; while (current != null) { ProcessLogicalConstruct(current); if(visitedConstructs.Contains(current.FollowNode)) { current.CFGFollowNode = null; } current = current.FollowNode; } ProcessGotoFlowConstructs(theConstruct as BlockLogicalConstruct); } else if (theConstruct is ExceptionHandlingLogicalConstruct) { ProcessLogicalConstruct((theConstruct as ExceptionHandlingLogicalConstruct).Try); if (theConstruct is TryCatchFilterLogicalConstruct) { foreach (IFilteringExceptionHandler handler in (theConstruct as TryCatchFilterLogicalConstruct).Handlers) { if (handler.HandlerType == FilteringExceptionHandlerType.Filter) { ProcessLogicalConstruct((handler as ExceptionHandlingBlockFilter).Filter); ProcessLogicalConstruct((handler as ExceptionHandlingBlockFilter).Handler); } else if (handler.HandlerType == FilteringExceptionHandlerType.Catch) { ProcessLogicalConstruct((handler as ExceptionHandlingBlockCatch)); } } } else if (theConstruct is TryFaultLogicalConstruct) { ProcessLogicalConstruct((theConstruct as TryFaultLogicalConstruct).Fault); } else if (theConstruct is TryFinallyLogicalConstruct) { ProcessLogicalConstruct((theConstruct as TryFinallyLogicalConstruct).Finally); } } else if (theConstruct is IfLogicalConstruct) { IfLogicalConstruct theIf = theConstruct as IfLogicalConstruct; ProcessLogicalConstruct(theIf.Then); if (theIf.Else != null) { ProcessLogicalConstruct(theIf.Else); } } else if (theConstruct is LoopLogicalConstruct) { LoopLogicalConstruct theLogicalLoop = theConstruct as LoopLogicalConstruct; ProcessLogicalConstruct(theLogicalLoop.LoopBodyBlock); ProcessLogicalConstruct(theLogicalLoop.LoopCondition); } else if (theConstruct is SwitchLogicalConstruct) { SwitchLogicalConstruct theLogicalSwitch = theConstruct as SwitchLogicalConstruct; foreach(CaseLogicalConstruct @case in theLogicalSwitch.ConditionCases) { ProcessLogicalConstruct(@case); } ProcessLogicalConstruct(theLogicalSwitch.DefaultCase); } else if (theConstruct is ConditionLogicalConstruct) { ConditionLogicalConstruct clc = theConstruct as ConditionLogicalConstruct; ProcessLogicalConstruct(clc.FirstBlock); } visitedConstructs.Add(theConstruct); }
/// <summary> /// Removes back edges from switch blocks. Switch cases can not form a loop. If the control flow forms a loop, it should be represented by goto-label contructs. /// </summary> /// <param name="theConstruct">The construct, that might contain switches.</param> private void RemoveBackEdgesFromSwitchConstructs(ILogicalConstruct theConstruct) { DFSTree dfsTree = DFSTBuilder.BuildTree(theConstruct); foreach (DFSTEdge edge in dfsTree.BackEdges) { ILogicalConstruct startConstruct = edge.Start.Construct as ILogicalConstruct; if (startConstruct is ConditionLogicalConstruct) { continue; } CFGBlockLogicalConstruct startCfgConstruct = startConstruct as CFGBlockLogicalConstruct; if((startCfgConstruct != null && startCfgConstruct.TheBlock.Last.OpCode.Code == Mono.Cecil.Cil.Code.Switch)) { MarkAsGotoEdge(startConstruct, edge.End.Construct as ILogicalConstruct); } } }
/// <summary> /// Checks if single node can be in a loop. The loop is determined by <paramref name="loopHeader"/> and has <paramref name="nodesInLoop"/> for its body. /// </summary> /// <param name="node">The node in question.</param> /// <param name="nodesInLoop">The other nodes in the body of the loop.</param> /// <param name="loopHeader">The header of the loop.</param> /// <returns>Returns true, if <paramref name="node"/> can be in the loop.</returns> private bool CanBeInLoop(ILogicalConstruct node, ICollection<ILogicalConstruct> nodesInLoop, ILogicalConstruct loopHeader) { if (node == null) { return false; } if (node == loopHeader) { /// The header is always part of the loop. return true; } foreach (ISingleEntrySubGraph predecessor in node.SameParentPredecessors) { ILogicalConstruct predecessorLogicalConstruct = predecessor as ILogicalConstruct; if (predecessorLogicalConstruct == null) { return false; } HashSet<ILogicalConstruct> removedEdgesEnds; if (!nodesInLoop.Contains(predecessorLogicalConstruct) || (removedEdges.TryGetValue(predecessorLogicalConstruct, out removedEdgesEnds) && removedEdgesEnds.Contains(node))) { /// The predecessor is not part of the loop. /// Or it was marked for goto on earlier stage. /// Either way this is multy-entry loop, which is not allowed return false; } } return true; }
ILogicalConstruct FindChildBlockBelongsTo(ILogicalConstruct parent, CFGBlockLogicalConstruct block) { ILogicalConstruct result = null, current = block; do { if (current.Parent == parent) { result = current; break; } current = (ILogicalConstruct)current.Parent; } while (current.Parent != null); return result; }
private HashSet<ILogicalConstruct> GetLogicalConstructsInRange(BlockRange blockRange, out ILogicalConstruct theCommonParent) { HashSet<ILogicalConstruct> children = new HashSet<ILogicalConstruct>(); HashSet<ISingleEntrySubGraph> blocksParents = new HashSet<ISingleEntrySubGraph>(); int rangeBegin = blockRange.Start.First.Offset; int rangeEnd = blockRange.End.First.Offset; for (int i = 0; i < context.CFG.Blocks.Length; i++) { InstructionBlock currentBlock = context.CFG.Blocks[i]; if(currentBlock.First.Offset >= rangeBegin && currentBlock.First.Offset <= rangeEnd) { CFGBlockLogicalConstruct[] cfgConstructs = context.CFGBlockToLogicalConstructMap[currentBlock]; for (int j = 0; j < cfgConstructs.Length; j++) { blocksParents.Add((ILogicalConstruct)cfgConstructs[j].Parent); children.Add(cfgConstructs[j]); } } } if (blocksParents.Count == 1) { theCommonParent = (ILogicalConstruct)blocksParents.ToArray<ISingleEntrySubGraph>()[0]; return children; } //TODO: CCheck whether the parent logical construct of of each CFGBlockLogicalConstruct that belongs to the exception handling block, //(i.e. each member of blocksParents) contains as children ONLY blocks that belong to the exception handling block (i.e. blocks that are in blockRange). theCommonParent = (ILogicalConstruct)LogicalFlowUtilities.FindFirstCommonParent(blocksParents); HashSet<ILogicalConstruct> result = new HashSet<ILogicalConstruct>(); foreach (ILogicalConstruct child in children) { ILogicalConstruct desiredNode; LogicalFlowUtilities.TryGetParentConstructWithGivenParent(child, theCommonParent, out desiredNode); result.Add(desiredNode); } if (theCommonParent is ExceptionHandlingLogicalConstruct) { result.Clear(); result.Add(theCommonParent); theCommonParent = theCommonParent.Parent as ILogicalConstruct; } return result; }
/// <summary> /// Gets the successors (direct or indirect) of the given <paramref name="startNode"/>, /// that are in the specified <paramref name="interval"/>. /// </summary> /// <remarks> /// If the start node is not in the interval, then it will not be traversed. This is a corner case for entwined loops. /// The start node will not be included in the result, even if it is its own successor. /// </remarks> /// <returns></returns> private HashSet<ILogicalConstruct> GetIntervalSuccessors(IntervalConstruct interval, ILogicalConstruct startNode) { HashSet<ILogicalConstruct> intervalSuccessors = new HashSet<ILogicalConstruct>(); if (!interval.Children.Contains(startNode)) { return intervalSuccessors; } Queue<ILogicalConstruct> traversalQueue = new Queue<ILogicalConstruct>(); traversalQueue.Enqueue(startNode); HashSet<ILogicalConstruct> traversedNodes = new HashSet<ILogicalConstruct>(); traversedNodes.Add(startNode); while(traversalQueue.Count > 0) { ILogicalConstruct currentNode = traversalQueue.Dequeue(); foreach (ILogicalConstruct successor in currentNode.SameParentSuccessors) { if(!traversedNodes.Contains(successor) && interval.Children.Contains(successor) && intervalSuccessors.Add(successor)) { traversedNodes.Add(successor); traversalQueue.Enqueue(successor); } } } return intervalSuccessors; }
/// <summary> /// Marks the edge between <paramref name="start"/> and <paramref name="end"/> as goto. /// </summary> /// <param name="start">The starting construct of the edge.</param> /// <param name="end">The ending construct of the edge.</param> private void MarkAsGotoEdge(ILogicalConstruct start, ILogicalConstruct end) { /// We assume, that all edges that will be marked as Goto are between CFGBlockLogicalConstruct nodes. /// If at some later stage it's evident that this case may arrise between constructs, different from CFGBlocks, then the implementation /// must be changed in a way, that ensures that the goto-links are transfered down the logical tree to the CfgBlocks. if (start == null || end == null) { throw new System.ArgumentOutOfRangeException("GoTo edge's ends must implement ILogicalConstruct."); } HashSet<ILogicalConstruct> removedSuccessors; if(!removedEdges.TryGetValue(start, out removedSuccessors)) { removedSuccessors = new HashSet<ILogicalConstruct>(); removedEdges[start] = removedSuccessors; } removedSuccessors.Add(end); }
/// <summary> /// Adds all of the nodes from the <paramref name="interval"/>, that are not preceded by the <paramref name="loopSuccessor"/>, /// to the <paramref name="loopBody"/>. /// </summary> /// <remarks> /// Does not add the <paramref name="loopSuccessor"/>. /// </remarks> private void ExpandLoopBody(IntervalConstruct interval, HashSet<ILogicalConstruct> loopBody, ILogicalConstruct loopSuccessor) { HashSet<ILogicalConstruct> nodesToSkip = GetIntervalSuccessors(interval, loopSuccessor); nodesToSkip.Add(loopSuccessor); foreach (LogicalConstructBase node in interval.Children) { if (!nodesToSkip.Contains(node)) { loopBody.Add(node); } } }
/// <summary> /// Determines whether the specified <paramref name="node"/> can be a condition to the loop with body - <paramref name="loopBody"/>. /// </summary> /// <param name="node">The possible condition node.</param> /// <param name="loopBody">The body of the loop.</param> /// <returns>Returns true, if <paramref name="node"/> can be the condition of the loop.</returns> private bool CanBeLoopCondition(ILogicalConstruct node, HashSet<ILogicalConstruct> loopBody) { if(!loopBody.Contains(node)) { //The node should be inside the loop. return false; } if(node is ConditionLogicalConstruct) { HashSet<ISingleEntrySubGraph> nodeSuccessors = node.SameParentSuccessors; int insideBody = 0; foreach (ILogicalConstruct successor in nodeSuccessors) { if (loopBody.Contains(successor)) { insideBody++; } } //There should be exactly one successor that is inside the body of the loop. return insideBody == 1; } return false; }
/// <summary> /// Returns the condition loop exit with the greatest post order index, that has the <paramref name="loopSuccessor"/> as successor. /// </summary> /// <param name="dfsTree"></param> /// <param name="loopBody"></param> /// <param name="loopExits"></param> /// <param name="loopSuccessor"></param> /// <returns></returns> private ConditionLogicalConstruct GetLoopConditionWithMaxIndex(DFSTree dfsTree, HashSet<ILogicalConstruct> loopBody, HashSet<ILogicalConstruct> loopExits, ILogicalConstruct loopSuccessor) { int maxOrderIndexOfExit = -1; foreach (ILogicalConstruct loopExit in loopExits) { int currentOrderIndex = dfsTree.ConstructToNodeMap[loopExit].ReversePostOrderIndex; if (loopExit.SameParentSuccessors.Contains(loopSuccessor) && currentOrderIndex > maxOrderIndexOfExit && CanBeLoopCondition(loopExit, loopBody)) { maxOrderIndexOfExit = currentOrderIndex; } } if(maxOrderIndexOfExit > -1) { return dfsTree.ReversePostOrder[maxOrderIndexOfExit].Construct as ConditionLogicalConstruct; } return null; }
public BlockLogicalConstruct(ILogicalConstruct Entry, IEnumerable<ILogicalConstruct> body) { this.Entry = Entry; RedirectChildrenToNewParent(body); }
/// <summary> /// Determines if <paramref name="header"/>, <paramref name="latchingNode"/> and <paramref name="nodesInLoop"/> can form a loop. /// </summary> /// <param name="header">The header of the loop.</param> /// <param name="latchingNode">The latching node of the loop.</param> /// <param name="nodesInLoop">The body of the loop.</param> /// <returns>Returns true, if correct loop can be formed.</returns> private bool CanBeLoop(ILogicalConstruct header, ILogicalConstruct latchingNode, ICollection<DFSTNode> nodesInLoop) { if (header == null || latchingNode == null) { return false; } ICollection<ILogicalConstruct> constructsInLoop = GetConstructsCollection(nodesInLoop); foreach (ILogicalConstruct node in constructsInLoop) { if (!CanBeInLoop(node, constructsInLoop, header)) { return false; } } return true; }