예제 #1
0
 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);
 }
예제 #2
0
        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);
        }
예제 #3
0
        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;
        }
예제 #4
0
 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);
 }
예제 #5
0
 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);
         }
     }
 }
예제 #6
0
 public CopyFinallySubGraphLogic(ControlFlowGraphBuilder builder, ControlFlowNode start, ControlFlowNode end, ControlFlowNode newEnd)
 {
     this.builder = builder;
     this.start   = start;
     this.end     = end;
     this.newEnd  = newEnd;
 }
예제 #7
0
        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());
                        }
                    }
                }
            }
        }
예제 #8
0
 ControlFlowNode GetNew(ControlFlowNode oldNode)
 {
     if (oldNode == end)
         return newEnd;
     ControlFlowNode newNode;
     if (oldToNew.TryGetValue(oldNode, out newNode))
         return newNode;
     return oldNode;
 }
예제 #9
0
 public CopyFinallySubGraphLogic(ControlFlowGraphBuilder builder, ControlFlowNode start, ControlFlowNode end, ControlFlowNode newEnd)
 {
     this.builder = builder;
     this.start = start;
     this.end = end;
     this.newEnd = newEnd;
 }
예제 #10
0
        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());
        }
예제 #11
0
 static bool HasSingleEdgeEnteringBlock(ControlFlowNode node)
 {
     return node.Incoming.Count(edge => !node.Dominates(edge.Source)) == 1;
 }
예제 #12
0
 /// <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;
 }
예제 #13
0
 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;
 }
예제 #14
0
 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!");
 }
예제 #15
0
 public ControlFlowEdge(ControlFlowNode source, ControlFlowNode target, JumpType type)
 {
     this.Source = source;
     this.Target = target;
     this.Type = type;
 }
예제 #16
0
 public ControlFlowEdge(ControlFlowNode source, ControlFlowNode target, JumpType type)
 {
     this.Source = source;
     this.Target = target;
     this.Type   = type;
 }
예제 #17
0
 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;
 }
예제 #18
0
        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;
        }
예제 #19
0
            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);
                        }
                    }
                }
            }
예제 #20
0
        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;
        }
예제 #21
0
 void ReconstructEdges(ControlFlowNode oldNode, ControlFlowNode newNode)
 {
     foreach (ControlFlowEdge oldEdge in oldNode.Outgoing) {
         builder.CreateEdge(newNode, GetNew(oldEdge.Target), oldEdge.Type);
     }
 }
예제 #22
0
        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;
        }
예제 #23
0
        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");
                }
            }
        }
예제 #24
0
 /// <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();
 }
예제 #25
0
 /// <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());
 }
예제 #26
0
 void CreateEdge(ControlFlowNode fromNode, Instruction toInstruction, JumpType type)
 {
     CreateEdge(fromNode, nodes.Single(n => n.Start == toInstruction), type);
 }
예제 #27
0
 void CreateEdge(ControlFlowNode fromNode, Instruction toInstruction, JumpType type)
 {
     CreateEdge(fromNode, nodes.Single(n => n.Start == toInstruction), type);
 }
예제 #28
0
 void CreateEdge(ControlFlowNode fromNode, ControlFlowNode toNode, JumpType type)
 {
     ControlFlowEdge edge = new ControlFlowEdge(fromNode, toNode, type);
     fromNode.Outgoing.Add(edge);
     toNode.Incoming.Add(edge);
 }
예제 #29
0
 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);
     }
 }
예제 #30
0
        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));
            }
        }
예제 #31
0
 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);
         }
     }
 }
예제 #32
0
파일: SsaBlock.cs 프로젝트: ropean/Usable
 internal SsaBlock(ControlFlowNode node)
 {
     this.NodeType = node.NodeType;
     this.BlockIndex = node.BlockIndex;
 }