internal ControlFlowGraph(ControlFlowNode[] nodes) { this.nodes = new ReadOnlyCollection<ControlFlowNode>(nodes); Debug.Assert(EntryPoint.NodeType == ControlFlowNodeType.EntryPoint); Debug.Assert(RegularExit.NodeType == ControlFlowNodeType.RegularExit); Debug.Assert(ExceptionalExit.NodeType == ControlFlowNodeType.ExceptionalExit); }
private ControlFlowGraphBuilder(MethodBody methodBody) { this.methodBody = methodBody; offsets = methodBody.Instructions.Select(i => i.Offset).ToArray(); hasIncomingJumps = new bool[methodBody.Instructions.Count]; entryPoint = new ControlFlowNode(0, 0, ControlFlowNodeType.EntryPoint); nodes.Add(entryPoint); regularExit = new ControlFlowNode(1, -1, ControlFlowNodeType.RegularExit); nodes.Add(regularExit); exceptionalExit = new ControlFlowNode(2, -1, ControlFlowNodeType.ExceptionalExit); nodes.Add(exceptionalExit); Debug.Assert(nodes.Count == 3); }
static HashSet<ControlFlowNode> FindDominatedNodes(HashSet<ControlFlowNode> scope, ControlFlowNode head) { HashSet<ControlFlowNode> agenda = new HashSet<ControlFlowNode>(); HashSet<ControlFlowNode> result = new HashSet<ControlFlowNode>(); agenda.Add(head); while(agenda.Count > 0) { ControlFlowNode addNode = agenda.First(); agenda.Remove(addNode); if (scope.Contains(addNode) && head.Dominates(addNode) && result.Add(addNode)) { foreach (var successor in addNode.Successors) { agenda.Add(successor); } } } return result; }
public ControlStructure(HashSet<ControlFlowNode> nodes, ControlFlowNode entryPoint, ControlStructureType type) { if (nodes == null) throw new ArgumentNullException("nodes"); this.Nodes = nodes; this.EntryPoint = entryPoint; this.Type = type; this.AllNodes = new HashSet<ControlFlowNode>(nodes); }
static void FindLoopContents(ControlStructure current, HashSet<ControlFlowNode> loopContents, ControlFlowNode loopHead, ControlFlowNode node) { if (current.AllNodes.Contains(node) && loopHead.Dominates(node) && loopContents.Add(node)) { foreach (var edge in node.Incoming) { FindLoopContents(current, loopContents, loopHead, edge.Source); } } }
public CopyFinallySubGraphLogic(ControlFlowGraphBuilder builder, ControlFlowNode start, ControlFlowNode end, ControlFlowNode newEnd) { this.builder = builder; this.start = start; this.end = end; this.newEnd = newEnd; }
void CreateRegularControlFlow() { CreateEdge(entryPoint, methodBody.Instructions[0], JumpType.Normal); foreach (ControlFlowNode node in nodes) { if (node.End != null) { // create normal edges from one instruction to the next if (!OpCodeInfo.IsUnconditionalBranch(node.End.OpCode)) { CreateEdge(node, node.End.Next, JumpType.Normal); } // create edges for branch instructions if (node.End.OpCode.OperandType == OperandType.InlineBrTarget || node.End.OpCode.OperandType == OperandType.ShortInlineBrTarget) { if (node.End.OpCode == OpCodes.Leave || node.End.OpCode == OpCodes.Leave_S) { var handlerBlock = FindInnermostHandlerBlock(node.End.Offset); if (handlerBlock.NodeType == ControlFlowNodeType.FinallyOrFaultHandler) { CreateEdge(node, (Instruction)node.End.Operand, JumpType.LeaveTry); } else { CreateEdge(node, (Instruction)node.End.Operand, JumpType.Normal); } } else { CreateEdge(node, (Instruction)node.End.Operand, JumpType.Normal); } } else if (node.End.OpCode.OperandType == OperandType.InlineSwitch) { foreach (Instruction i in (Instruction[])node.End.Operand) { CreateEdge(node, i, JumpType.Normal); } } // create edges for return instructions if (node.End.OpCode.FlowControl == FlowControl.Return) { switch (node.End.OpCode.Code) { case Code.Ret: CreateEdge(node, regularExit, JumpType.Normal); break; case Code.Endfinally: ControlFlowNode handlerBlock = FindInnermostHandlerBlock(node.End.Offset); if (handlerBlock.EndFinallyOrFaultNode == null) { throw new InvalidProgramException("Found endfinally in block " + handlerBlock); } CreateEdge(node, handlerBlock.EndFinallyOrFaultNode, JumpType.Normal); break; default: throw new NotSupportedException(node.End.OpCode.ToString()); } } } } }
ControlFlowNode GetNew(ControlFlowNode oldNode) { if (oldNode == end) return newEnd; ControlFlowNode newNode; if (oldToNew.TryGetValue(oldNode, out newNode)) return newNode; return oldNode; }
ControlFlowGraph BuildGraph(List<ILNode> nodes, ILLabel entryLabel) { int index = 0; List<ControlFlowNode> cfNodes = new List<ControlFlowNode>(); ControlFlowNode entryPoint = new ControlFlowNode(index++, 0, ControlFlowNodeType.EntryPoint); cfNodes.Add(entryPoint); ControlFlowNode regularExit = new ControlFlowNode(index++, -1, ControlFlowNodeType.RegularExit); cfNodes.Add(regularExit); ControlFlowNode exceptionalExit = new ControlFlowNode(index++, -1, ControlFlowNodeType.ExceptionalExit); cfNodes.Add(exceptionalExit); // Create graph nodes labelToCfNode = new Dictionary<ILLabel, ControlFlowNode>(); Dictionary<ILNode, ControlFlowNode> astNodeToCfNode = new Dictionary<ILNode, ControlFlowNode>(); foreach(ILBasicBlock node in nodes) { ControlFlowNode cfNode = new ControlFlowNode(index++, -1, ControlFlowNodeType.Normal); cfNodes.Add(cfNode); astNodeToCfNode[node] = cfNode; cfNode.UserData = node; // Find all contained labels foreach(ILLabel label in node.GetSelfAndChildrenRecursive<ILLabel>()) { labelToCfNode[label] = cfNode; } } // Entry endge ControlFlowNode entryNode = labelToCfNode[entryLabel]; ControlFlowEdge entryEdge = new ControlFlowEdge(entryPoint, entryNode, JumpType.Normal); entryPoint.Outgoing.Add(entryEdge); entryNode.Incoming.Add(entryEdge); // Create edges foreach(ILBasicBlock node in nodes) { ControlFlowNode source = astNodeToCfNode[node]; // Find all branches foreach(ILLabel target in node.GetSelfAndChildrenRecursive<ILExpression>(e => e.IsBranch()).SelectMany(e => e.GetBranchTargets())) { ControlFlowNode destination; // Labels which are out of out scope will not be in the collection // Insert self edge only if we are sure we are a loop if (labelToCfNode.TryGetValue(target, out destination) && (destination != source || target == node.Body.FirstOrDefault())) { ControlFlowEdge edge = new ControlFlowEdge(source, destination, JumpType.Normal); source.Outgoing.Add(edge); destination.Incoming.Add(edge); } } } return new ControlFlowGraph(cfNodes.ToArray()); }
static bool HasSingleEdgeEnteringBlock(ControlFlowNode node) { return node.Incoming.Count(edge => !node.Dominates(edge.Source)) == 1; }
/// <summary> /// Gets whether <c>this</c> dominates <paramref name="node"/>. /// </summary> public bool Dominates(ControlFlowNode node) { // TODO: this can be made O(1) by numbering the dominator tree ControlFlowNode tmp = node; while (tmp != null) { if (tmp == this) return true; tmp = tmp.ImmediateDominator; } return false; }
internal ControlFlowNode(int blockIndex, ExceptionHandler exceptionHandler, ControlFlowNode endFinallyOrFaultNode) { this.BlockIndex = blockIndex; this.NodeType = endFinallyOrFaultNode != null ? ControlFlowNodeType.FinallyOrFaultHandler : ControlFlowNodeType.CatchHandler; this.ExceptionHandler = exceptionHandler; this.EndFinallyOrFaultNode = endFinallyOrFaultNode; Debug.Assert((exceptionHandler.HandlerType == ExceptionHandlerType.Finally || exceptionHandler.HandlerType == ExceptionHandlerType.Fault) == (endFinallyOrFaultNode != null)); this.Offset = exceptionHandler.HandlerStart.Offset; }
static ControlFlowNode FindCommonDominator(ControlFlowNode b1, ControlFlowNode b2) { // Here we could use the postorder numbers to get rid of the hashset, see "A Simple, Fast Dominance Algorithm" HashSet<ControlFlowNode> path1 = new HashSet<ControlFlowNode>(); while (b1 != null && path1.Add(b1)) b1 = b1.ImmediateDominator; while (b2 != null) { if (path1.Contains(b2)) return b2; else b2 = b2.ImmediateDominator; } throw new Exception("No common dominator found!"); }
public ControlFlowEdge(ControlFlowNode source, ControlFlowNode target, JumpType type) { this.Source = source; this.Target = target; this.Type = type; }
ControlFlowNode FindParentExceptionHandlerNode(ControlFlowNode exceptionHandler) { Debug.Assert(exceptionHandler.NodeType == ControlFlowNodeType.CatchHandler || exceptionHandler.NodeType == ControlFlowNodeType.FinallyOrFaultHandler); int offset = exceptionHandler.ExceptionHandler.TryStart.Offset; for (int i = exceptionHandler.BlockIndex + 1; i < nodes.Count; i++) { ExceptionHandler h = nodes[i].ExceptionHandler; if (h != null && h.TryStart.Offset <= offset && offset < h.TryEnd.Offset) return nodes[i]; } return exceptionalExit; }
List<ILNode> FindConditions(HashSet<ControlFlowNode> scope, ControlFlowNode entryNode) { List<ILNode> result = new List<ILNode>(); // Do not modify entry data scope = new HashSet<ControlFlowNode>(scope); Stack<ControlFlowNode> agenda = new Stack<ControlFlowNode>(); agenda.Push(entryNode); while(agenda.Count > 0) { ControlFlowNode node = agenda.Pop(); // Find a block that represents a simple condition if (scope.Contains(node)) { ILBasicBlock block = (ILBasicBlock)node.UserData; { // Switch ILLabel[] caseLabels; ILExpression switchArg; ILLabel fallLabel; if (block.MatchLastAndBr(ILCode.Switch, out caseLabels, out switchArg, out fallLabel)) { // Replace the switch code with ILSwitch ILSwitch ilSwitch = new ILSwitch() { Condition = switchArg }; block.Body.RemoveTail(ILCode.Switch, ILCode.Br); block.Body.Add(ilSwitch); block.Body.Add(new ILExpression(ILCode.Br, fallLabel)); result.Add(block); // Remove the item so that it is not picked up as content scope.RemoveOrThrow(node); // Find the switch offset int addValue = 0; List<ILExpression> subArgs; if (ilSwitch.Condition.Match(ILCode.Sub, out subArgs) && subArgs[1].Match(ILCode.Ldc_I4, out addValue)) { ilSwitch.Condition = subArgs[0]; } // Pull in code of cases ControlFlowNode fallTarget = null; labelToCfNode.TryGetValue(fallLabel, out fallTarget); HashSet<ControlFlowNode> frontiers = new HashSet<ControlFlowNode>(); if (fallTarget != null) frontiers.UnionWith(fallTarget.DominanceFrontier.Except(new [] { fallTarget })); foreach(ILLabel condLabel in caseLabels) { ControlFlowNode condTarget = null; labelToCfNode.TryGetValue(condLabel, out condTarget); if (condTarget != null) frontiers.UnionWith(condTarget.DominanceFrontier.Except(new [] { condTarget })); } for (int i = 0; i < caseLabels.Length; i++) { ILLabel condLabel = caseLabels[i]; // Find or create new case block ILSwitch.CaseBlock caseBlock = ilSwitch.CaseBlocks.FirstOrDefault(b => b.EntryGoto.Operand == condLabel); if (caseBlock == null) { caseBlock = new ILSwitch.CaseBlock() { Values = new List<int>(), EntryGoto = new ILExpression(ILCode.Br, condLabel) }; ilSwitch.CaseBlocks.Add(caseBlock); ControlFlowNode condTarget = null; labelToCfNode.TryGetValue(condLabel, out condTarget); if (condTarget != null && !frontiers.Contains(condTarget)) { HashSet<ControlFlowNode> content = FindDominatedNodes(scope, condTarget); scope.ExceptWith(content); caseBlock.Body.AddRange(FindConditions(content, condTarget)); // Add explicit break which should not be used by default, but the goto removal might decide to use it caseBlock.Body.Add(new ILBasicBlock() { Body = { new ILLabel() { Name = "SwitchBreak_" + (nextLabelIndex++) }, new ILExpression(ILCode.LoopOrSwitchBreak, null) } }); } } caseBlock.Values.Add(i + addValue); } // Heuristis to determine if we want to use fallthough as default case if (fallTarget != null && !frontiers.Contains(fallTarget)) { HashSet<ControlFlowNode> content = FindDominatedNodes(scope, fallTarget); if (content.Any()) { var caseBlock = new ILSwitch.CaseBlock() { EntryGoto = new ILExpression(ILCode.Br, fallLabel) }; ilSwitch.CaseBlocks.Add(caseBlock); block.Body.RemoveTail(ILCode.Br); scope.ExceptWith(content); caseBlock.Body.AddRange(FindConditions(content, fallTarget)); // Add explicit break which should not be used by default, but the goto removal might decide to use it caseBlock.Body.Add(new ILBasicBlock() { Body = { new ILLabel() { Name = "SwitchBreak_" + (nextLabelIndex++) }, new ILExpression(ILCode.LoopOrSwitchBreak, null) } }); } } } // Two-way branch ILExpression condExpr; ILLabel trueLabel; ILLabel falseLabel; if(block.MatchLastAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel)) { // Swap bodies since that seems to be the usual C# order ILLabel temp = trueLabel; trueLabel = falseLabel; falseLabel = temp; condExpr = new ILExpression(ILCode.LogicNot, null, condExpr); // Convert the brtrue to ILCondition ILCondition ilCond = new ILCondition() { Condition = condExpr, TrueBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, trueLabel) }, FalseBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, falseLabel) } }; block.Body.RemoveTail(ILCode.Brtrue, ILCode.Br); block.Body.Add(ilCond); result.Add(block); // Remove the item immediately so that it is not picked up as content scope.RemoveOrThrow(node); ControlFlowNode trueTarget = null; labelToCfNode.TryGetValue(trueLabel, out trueTarget); ControlFlowNode falseTarget = null; labelToCfNode.TryGetValue(falseLabel, out falseTarget); // Pull in the conditional code if (trueTarget != null && HasSingleEdgeEnteringBlock(trueTarget)) { HashSet<ControlFlowNode> content = FindDominatedNodes(scope, trueTarget); scope.ExceptWith(content); ilCond.TrueBlock.Body.AddRange(FindConditions(content, trueTarget)); } if (falseTarget != null && HasSingleEdgeEnteringBlock(falseTarget)) { HashSet<ControlFlowNode> content = FindDominatedNodes(scope, falseTarget); scope.ExceptWith(content); ilCond.FalseBlock.Body.AddRange(FindConditions(content, falseTarget)); } } } // Add the node now so that we have good ordering if (scope.Contains(node)) { result.Add((ILNode)node.UserData); scope.Remove(node); } } // depth-first traversal of dominator tree for (int i = node.DominatorTreeChildren.Count - 1; i >= 0; i--) { agenda.Push(node.DominatorTreeChildren[i]); } } // Add whatever is left foreach(var node in scope) { result.Add((ILNode)node.UserData); } return result; }
void CollectNodes(ControlFlowNode node) { if (node == end || node == newEnd) throw new InvalidOperationException("unexpected cycle involving finally construct"); if (!oldToNew.ContainsKey(node)) { int newBlockIndex = builder.nodes.Count; ControlFlowNode copy; switch (node.NodeType) { case ControlFlowNodeType.Normal: copy = new ControlFlowNode(newBlockIndex, node.Start, node.End); break; case ControlFlowNodeType.FinallyOrFaultHandler: copy = new ControlFlowNode(newBlockIndex, node.ExceptionHandler, node.EndFinallyOrFaultNode); break; default: // other nodes shouldn't occur when copying finally blocks throw new NotSupportedException(node.NodeType.ToString()); } copy.CopyFrom = node; builder.nodes.Add(copy); oldToNew.Add(node, copy); if (node != start) { foreach (ControlFlowNode n in node.Predecessors) { CollectNodes(n); } } } }
List<ILNode> FindLoops(HashSet<ControlFlowNode> scope, ControlFlowNode entryPoint, bool excludeEntryPoint) { List<ILNode> result = new List<ILNode>(); // Do not modify entry data scope = new HashSet<ControlFlowNode>(scope); Queue<ControlFlowNode> agenda = new Queue<ControlFlowNode>(); agenda.Enqueue(entryPoint); while(agenda.Count > 0) { ControlFlowNode node = agenda.Dequeue(); // If the node is a loop header if (scope.Contains(node) && node.DominanceFrontier.Contains(node) && (node != entryPoint || !excludeEntryPoint)) { HashSet<ControlFlowNode> loopContents = FindLoopContent(scope, node); // If the first expression is a loop condition ILBasicBlock basicBlock = (ILBasicBlock)node.UserData; ILExpression condExpr; ILLabel trueLabel; ILLabel falseLabel; // It has to be just brtrue - any preceding code would introduce goto if(basicBlock.MatchSingleAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel)) { ControlFlowNode trueTarget; labelToCfNode.TryGetValue(trueLabel, out trueTarget); ControlFlowNode falseTarget; labelToCfNode.TryGetValue(falseLabel, out falseTarget); // If one point inside the loop and the other outside if ((!loopContents.Contains(trueTarget) && loopContents.Contains(falseTarget)) || (loopContents.Contains(trueTarget) && !loopContents.Contains(falseTarget)) ) { loopContents.RemoveOrThrow(node); scope.RemoveOrThrow(node); // If false means enter the loop if (loopContents.Contains(falseTarget) || falseTarget == node) { // Negate the condition condExpr = new ILExpression(ILCode.LogicNot, null, condExpr); ILLabel tmp = trueLabel; trueLabel = falseLabel; falseLabel = tmp; } ControlFlowNode postLoopTarget; labelToCfNode.TryGetValue(falseLabel, out postLoopTarget); if (postLoopTarget != null) { // Pull more nodes into the loop HashSet<ControlFlowNode> postLoopContents = FindDominatedNodes(scope, postLoopTarget); var pullIn = scope.Except(postLoopContents).Where(n => node.Dominates(n)); loopContents.UnionWith(pullIn); } // Use loop to implement the brtrue basicBlock.Body.RemoveTail(ILCode.Brtrue, ILCode.Br); basicBlock.Body.Add(new ILWhileLoop() { Condition = condExpr, BodyBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, trueLabel), Body = FindLoops(loopContents, node, false) } }); basicBlock.Body.Add(new ILExpression(ILCode.Br, falseLabel)); result.Add(basicBlock); scope.ExceptWith(loopContents); } } // Fallback method: while(true) if (scope.Contains(node)) { result.Add(new ILBasicBlock() { Body = new List<ILNode>() { new ILLabel() { Name = "Loop_" + (nextLabelIndex++) }, new ILWhileLoop() { BodyBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, (ILLabel)basicBlock.Body.First()), Body = FindLoops(loopContents, node, true) } }, }, }); scope.ExceptWith(loopContents); } } // Using the dominator tree should ensure we find the the widest loop first foreach(var child in node.DominatorTreeChildren) { agenda.Enqueue(child); } } // Add whatever is left foreach(var node in scope) { result.Add((ILNode)node.UserData); } scope.Clear(); return result; }
void ReconstructEdges(ControlFlowNode oldNode, ControlFlowNode newNode) { foreach (ControlFlowEdge oldEdge in oldNode.Outgoing) { builder.CreateEdge(newNode, GetNew(oldEdge.Target), oldEdge.Type); } }
static HashSet<ControlFlowNode> FindLoopContent(HashSet<ControlFlowNode> scope, ControlFlowNode head) { var viaBackEdges = head.Predecessors.Where(p => head.Dominates(p)); HashSet<ControlFlowNode> agenda = new HashSet<ControlFlowNode>(viaBackEdges); HashSet<ControlFlowNode> result = new HashSet<ControlFlowNode>(); while(agenda.Count > 0) { ControlFlowNode addNode = agenda.First(); agenda.Remove(addNode); if (scope.Contains(addNode) && head.Dominates(addNode) && result.Add(addNode)) { foreach (var predecessor in addNode.Predecessors) { agenda.Add(predecessor); } } } if (scope.Contains(head)) result.Add(head); return result; }
void CreateInstructions(int blockIndex) { ControlFlowNode cfgNode = cfg.Nodes[blockIndex]; SsaBlock block = blocks[blockIndex]; int stackSize = stackSizeAtBlockStart[blockIndex]; Debug.Assert(stackSize >= 0); List <Instruction> prefixes = new List <Instruction>(); foreach (Instruction inst in cfgNode.Instructions) { if (inst.OpCode.OpCodeType == OpCodeType.Prefix) { prefixes.Add(inst); continue; } int popCount = inst.GetPopDelta(method) ?? stackSize; stackSize -= popCount; if (stackSize < 0) { throw new InvalidProgramException("IL stack underflow"); } int pushCount = inst.GetPushDelta(); if (stackSize + pushCount > stackLocations.Length) { throw new InvalidProgramException("IL stack overflow"); } SsaVariable target; SsaVariable[] operands; DetermineOperands(stackSize, inst, popCount, pushCount, out target, out operands); Instruction[] prefixArray = prefixes.Count > 0 ? prefixes.ToArray() : null; prefixes.Clear(); // ignore NOP instructions if (!(inst.OpCode == OpCodes.Nop || inst.OpCode == OpCodes.Pop)) { block.Instructions.Add(new SsaInstruction(block, inst, target, operands, prefixArray)); } stackSize += pushCount; } foreach (ControlFlowEdge edge in cfgNode.Outgoing) { int newStackSize; switch (edge.Type) { case JumpType.Normal: newStackSize = stackSize; break; case JumpType.EndFinally: if (stackSize != 0) { throw new NotSupportedException("stacksize must be 0 in endfinally edge"); } newStackSize = 0; break; case JumpType.JumpToExceptionHandler: switch (edge.Target.NodeType) { case ControlFlowNodeType.FinallyOrFaultHandler: newStackSize = 0; break; case ControlFlowNodeType.ExceptionalExit: case ControlFlowNodeType.CatchHandler: newStackSize = 1; break; default: throw new NotSupportedException("unsupported target node type: " + edge.Target.NodeType); } break; default: throw new NotSupportedException("unsupported jump type: " + edge.Type); } int nextStackSize = stackSizeAtBlockStart[edge.Target.BlockIndex]; if (nextStackSize == -1) { stackSizeAtBlockStart[edge.Target.BlockIndex] = newStackSize; CreateInstructions(edge.Target.BlockIndex); } else if (nextStackSize != newStackSize) { throw new InvalidProgramException("Stack size doesn't match"); } } }
/// <summary> /// Creates a copy of all nodes pointing to 'end' and replaces those references with references to 'newEnd'. /// Nodes pointing to the copied node are copied recursively to update those references, too. /// This recursion stops at 'start'. The modified version of start is returned. /// </summary> ControlFlowNode CopyFinallySubGraph(ControlFlowNode start, ControlFlowNode end, ControlFlowNode newEnd) { return new CopyFinallySubGraphLogic(this, start, end, newEnd).CopyFinallySubGraph(); }
/// <summary> /// Creates a copy of all nodes pointing to 'end' and replaces those references with references to 'newEnd'. /// Nodes pointing to the copied node are copied recursively to update those references, too. /// This recursion stops at 'start'. The modified version of start is returned. /// </summary> ControlFlowNode CopyFinallySubGraph(ControlFlowNode start, ControlFlowNode end, ControlFlowNode newEnd) { return(new CopyFinallySubGraphLogic(this, start, end, newEnd).CopyFinallySubGraph()); }
void CreateEdge(ControlFlowNode fromNode, Instruction toInstruction, JumpType type) { CreateEdge(fromNode, nodes.Single(n => n.Start == toInstruction), type); }
void CreateEdge(ControlFlowNode fromNode, ControlFlowNode toNode, JumpType type) { ControlFlowEdge edge = new ControlFlowEdge(fromNode, toNode, type); fromNode.Outgoing.Add(edge); toNode.Incoming.Add(edge); }
static void FindLoops(ControlStructure current, ControlFlowNode node) { if (node.Visited) return; node.Visited = true; if (current.Nodes.Contains(node) && node.DominanceFrontier.Contains(node) && !(node == current.EntryPoint && current.Type == ControlStructureType.Loop)) { HashSet<ControlFlowNode> loopContents = new HashSet<ControlFlowNode>(); FindLoopContents(current, loopContents, node, node); List<ControlStructure> containedChildStructures = new List<ControlStructure>(); bool invalidNesting = false; foreach (ControlStructure childStructure in current.Children) { if (childStructure.AllNodes.IsSubsetOf(loopContents)) { containedChildStructures.Add(childStructure); } else if (childStructure.AllNodes.Intersect(loopContents).Any()) { invalidNesting = true; } } if (!invalidNesting) { current.Nodes.ExceptWith(loopContents); ControlStructure ctl = new ControlStructure(loopContents, node, ControlStructureType.Loop); foreach (ControlStructure childStructure in containedChildStructures) { ctl.Children.Add(childStructure); current.Children.Remove(childStructure); ctl.Nodes.ExceptWith(childStructure.AllNodes); } current.Children.Add(ctl); } } foreach (var edge in node.Outgoing) { FindLoops(current, edge.Target); } }
void CreateNodes() { // Step 2a: find basic blocks and create nodes for them for (int i = 0; i < methodBody.Instructions.Count; i++) { Instruction blockStart = methodBody.Instructions[i]; ExceptionHandler blockStartEH = FindInnermostExceptionHandler(blockStart.Offset); // try and see how big we can make that block: for (; i + 1 < methodBody.Instructions.Count; i++) { Instruction inst = methodBody.Instructions[i]; if (IsBranch(inst.OpCode) || CanThrowException(inst.OpCode)) break; if (hasIncomingJumps[i + 1]) break; if (inst.Next != null) { // ensure that blocks never contain instructions from different try blocks ExceptionHandler instEH = FindInnermostExceptionHandler(inst.Next.Offset); if (instEH != blockStartEH) break; } } nodes.Add(new ControlFlowNode(nodes.Count, blockStart, methodBody.Instructions[i])); } // Step 2b: Create special nodes for the exception handling constructs foreach (ExceptionHandler handler in methodBody.ExceptionHandlers) { if (handler.HandlerType == ExceptionHandlerType.Filter) throw new NotSupportedException(); ControlFlowNode endFinallyOrFaultNode = null; if (handler.HandlerType == ExceptionHandlerType.Finally || handler.HandlerType == ExceptionHandlerType.Fault) { endFinallyOrFaultNode = new ControlFlowNode(nodes.Count, handler.HandlerEnd.Offset, ControlFlowNodeType.EndFinallyOrFault); nodes.Add(endFinallyOrFaultNode); } nodes.Add(new ControlFlowNode(nodes.Count, handler, endFinallyOrFaultNode)); } }
static void FindLoopContents(ControlStructure current, HashSet <ControlFlowNode> loopContents, ControlFlowNode loopHead, ControlFlowNode node) { if (current.AllNodes.Contains(node) && loopHead.Dominates(node) && loopContents.Add(node)) { foreach (var edge in node.Incoming) { FindLoopContents(current, loopContents, loopHead, edge.Source); } } }
internal SsaBlock(ControlFlowNode node) { this.NodeType = node.NodeType; this.BlockIndex = node.BlockIndex; }