示例#1
0
        void AnalyzeMoveNext()
        {
            MethodDefinition moveNextMethod = enumeratorType.Methods.FirstOrDefault(m => m.Name == "MoveNext");
            ILBlock          ilMethod       = CreateILAst(moveNextMethod);

            if (ilMethod.Body.Count == 0)
            {
                throw new SymbolicAnalysisFailedException();
            }
            ILExpression lastReturnArg;

            if (!ilMethod.Body.Last().Match(ILCode.Ret, out lastReturnArg))
            {
                throw new SymbolicAnalysisFailedException();
            }

            // There are two possibilities:
            if (lastReturnArg.Code == ILCode.Ldloc)
            {
                // a) the compiler uses a variable for returns (in debug builds, or when there are try-finally blocks)
                returnVariable = (ILVariable)lastReturnArg.Operand;
                returnLabel    = ilMethod.Body.ElementAtOrDefault(ilMethod.Body.Count - 2) as ILLabel;
                if (returnLabel == null)
                {
                    throw new SymbolicAnalysisFailedException();
                }
            }
            else
            {
                // b) the compiler directly returns constants
                returnVariable = null;
                returnLabel    = null;
                // In this case, the last return must return false.
                if (lastReturnArg.Code != ILCode.Ldc_I4 || (int)lastReturnArg.Operand != 0)
                {
                    throw new SymbolicAnalysisFailedException();
                }
            }

            ILTryCatchBlock tryFaultBlock = ilMethod.Body[0] as ILTryCatchBlock;
            List <ILNode>   body;
            int             bodyLength;

            if (tryFaultBlock != null)
            {
                // there are try-finally blocks
                if (returnVariable == null)                 // in this case, we must use a return variable
                {
                    throw new SymbolicAnalysisFailedException();
                }
                // must be a try-fault block:
                if (tryFaultBlock.CatchBlocks.Count != 0 || tryFaultBlock.FinallyBlock != null || tryFaultBlock.FaultBlock == null)
                {
                    throw new SymbolicAnalysisFailedException();
                }

                ILBlock faultBlock = tryFaultBlock.FaultBlock;
                // Ensure the fault block contains the call to Dispose().
                if (faultBlock.Body.Count != 2)
                {
                    throw new SymbolicAnalysisFailedException();
                }
                MethodReference disposeMethodRef;
                ILExpression    disposeArg;
                if (!faultBlock.Body[0].Match(ILCode.Call, out disposeMethodRef, out disposeArg))
                {
                    throw new SymbolicAnalysisFailedException();
                }
                if (GetMethodDefinition(disposeMethodRef) != disposeMethod || !disposeArg.MatchThis())
                {
                    throw new SymbolicAnalysisFailedException();
                }
                if (!faultBlock.Body[1].Match(ILCode.Endfinally))
                {
                    throw new SymbolicAnalysisFailedException();
                }

                body       = tryFaultBlock.TryBlock.Body;
                bodyLength = body.Count;
            }
            else
            {
                // no try-finally blocks
                body = ilMethod.Body;
                if (returnVariable == null)
                {
                    bodyLength = body.Count - 1;                     // all except for the return statement
                }
                else
                {
                    bodyLength = body.Count - 2;                     // all except for the return label and statement
                }
            }

            // Now verify that the last instruction in the body is 'ret(false)'
            if (returnVariable != null)
            {
                // If we don't have a return variable, we already verified that above.
                // If we do have one, check for 'stloc(returnVariable, ldc.i4(0))'

                // Maybe might be a jump to the return label after the stloc:
                ILExpression leave = body.ElementAtOrDefault(bodyLength - 1) as ILExpression;
                if (leave != null && (leave.Code == ILCode.Br || leave.Code == ILCode.Leave) && leave.Operand == returnLabel)
                {
                    bodyLength--;
                }
                ILExpression store0 = body.ElementAtOrDefault(bodyLength - 1) as ILExpression;
                if (store0 == null || store0.Code != ILCode.Stloc || store0.Operand != returnVariable)
                {
                    throw new SymbolicAnalysisFailedException();
                }
                if (store0.Arguments[0].Code != ILCode.Ldc_I4 || (int)store0.Arguments[0].Operand != 0)
                {
                    throw new SymbolicAnalysisFailedException();
                }

                bodyLength--;                 // don't conside the stloc instruction to be part of the body
            }
            // verify that the last element in the body is a label pointing to the 'ret(false)'
            returnFalseLabel = body.ElementAtOrDefault(bodyLength - 1) as ILLabel;
            if (returnFalseLabel == null)
            {
                throw new SymbolicAnalysisFailedException();
            }

            var rangeAnalysis = new StateRangeAnalysis(body[0], StateRangeAnalysisMode.IteratorMoveNext, stateField);
            int pos           = rangeAnalysis.AssignStateRanges(body, bodyLength);

            rangeAnalysis.EnsureLabelAtPos(body, ref pos, ref bodyLength);

            var labels = rangeAnalysis.CreateLabelRangeMapping(body, pos, bodyLength);

            ConvertBody(body, pos, bodyLength, labels);
        }
示例#2
0
        void ConvertBody(List <ILNode> body, int startPos, int bodyLength, List <KeyValuePair <ILLabel, StateRange> > labels)
        {
            newBody = new List <ILNode>();
            newBody.Add(MakeGoTo(labels, 0));
            List <SetState> stateChanges = new List <SetState>();
            int             currentState = -1;

            // Copy all instructions from the old body to newBody.
            for (int pos = startPos; pos < bodyLength; pos++)
            {
                ILExpression expr = body[pos] as ILExpression;
                if (expr != null && expr.Code == ILCode.Stfld && expr.Arguments[0].MatchThis())
                {
                    // Handle stores to 'state' or 'current'
                    if (GetFieldDefinition(expr.Operand as FieldReference) == stateField)
                    {
                        if (expr.Arguments[1].Code != ILCode.Ldc_I4)
                        {
                            throw new SymbolicAnalysisFailedException();
                        }
                        currentState = (int)expr.Arguments[1].Operand;
                        stateChanges.Add(new SetState(newBody.Count, currentState));
                    }
                    else if (GetFieldDefinition(expr.Operand as FieldReference) == currentField)
                    {
                        newBody.Add(new ILExpression(ILCode.YieldReturn, null, expr.Arguments[1]));
                    }
                    else
                    {
                        newBody.Add(body[pos]);
                    }
                }
                else if (returnVariable != null && expr != null && expr.Code == ILCode.Stloc && expr.Operand == returnVariable)
                {
                    // handle store+branch to the returnVariable
                    ILExpression br = body.ElementAtOrDefault(++pos) as ILExpression;
                    if (br == null || !(br.Code == ILCode.Br || br.Code == ILCode.Leave) || br.Operand != returnLabel || expr.Arguments[0].Code != ILCode.Ldc_I4)
                    {
                        throw new SymbolicAnalysisFailedException();
                    }
                    int val = (int)expr.Arguments[0].Operand;
                    if (val == 0)
                    {
                        newBody.Add(MakeGoTo(returnFalseLabel));
                    }
                    else if (val == 1)
                    {
                        newBody.Add(MakeGoTo(labels, currentState));
                    }
                    else
                    {
                        throw new SymbolicAnalysisFailedException();
                    }
                }
                else if (expr != null && expr.Code == ILCode.Ret)
                {
                    if (expr.Arguments.Count != 1 || expr.Arguments[0].Code != ILCode.Ldc_I4)
                    {
                        throw new SymbolicAnalysisFailedException();
                    }
                    // handle direct return (e.g. in release builds)
                    int val = (int)expr.Arguments[0].Operand;
                    if (val == 0)
                    {
                        newBody.Add(MakeGoTo(returnFalseLabel));
                    }
                    else if (val == 1)
                    {
                        newBody.Add(MakeGoTo(labels, currentState));
                    }
                    else
                    {
                        throw new SymbolicAnalysisFailedException();
                    }
                }
                else if (expr != null && expr.Code == ILCode.Call && expr.Arguments.Count == 1 && expr.Arguments[0].MatchThis())
                {
                    MethodDefinition method = GetMethodDefinition(expr.Operand as MethodReference);
                    if (method == null)
                    {
                        throw new SymbolicAnalysisFailedException();
                    }
                    Interval interval;
                    if (method == disposeMethod)
                    {
                        // Explicit call to dispose is used for "yield break;" within the method.
                        ILExpression br = body.ElementAtOrDefault(++pos) as ILExpression;
                        if (br == null || !(br.Code == ILCode.Br || br.Code == ILCode.Leave) || br.Operand != returnFalseLabel)
                        {
                            throw new SymbolicAnalysisFailedException();
                        }
                        newBody.Add(MakeGoTo(returnFalseLabel));
                    }
                    else if (finallyMethodToStateInterval.TryGetValue(method, out interval))
                    {
                        // Call to Finally-method
                        int index = stateChanges.FindIndex(ss => ss.NewState >= interval.Start && ss.NewState <= interval.End);
                        if (index < 0)
                        {
                            throw new SymbolicAnalysisFailedException();
                        }

                        ILLabel label = new ILLabel();
                        label.Name = "JumpOutOfTryFinally" + interval.Start + "_" + interval.End;
                        newBody.Add(new ILExpression(ILCode.Leave, label));

                        SetState stateChange = stateChanges[index];
                        // Move all instructions from stateChange.Pos to newBody.Count into a try-block
                        stateChanges.RemoveRange(index, stateChanges.Count - index);                         // remove all state changes up to the one we found
                        ILTryCatchBlock tryFinally = new ILTryCatchBlock();
                        tryFinally.TryBlock = new ILBlock(newBody.GetRange(stateChange.NewBodyPos, newBody.Count - stateChange.NewBodyPos));
                        newBody.RemoveRange(stateChange.NewBodyPos, newBody.Count - stateChange.NewBodyPos);                         // remove all nodes that we just moved into the try block
                        tryFinally.CatchBlocks  = new List <ILTryCatchBlock.CatchBlock>();
                        tryFinally.FinallyBlock = ConvertFinallyBlock(method);
                        newBody.Add(tryFinally);
                        newBody.Add(label);
                    }
                }
                else
                {
                    newBody.Add(body[pos]);
                }
            }
            newBody.Add(new ILExpression(ILCode.YieldBreak, null));
        }
示例#3
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()));
        }
示例#4
0
        /// <summary>
        /// Get the first expression to be excecuted if the instruction pointer is at the start of the given node.
        /// Try blocks may not be entered in any way.  If possible, the try block is returned as the node to be executed.
        /// </summary>
        ILNode Enter(ILNode node, HashSet <ILNode> visitedNodes)
        {
            if (node == null)
            {
                throw new ArgumentNullException();
            }

            if (!visitedNodes.Add(node))
            {
                return(null);                 // Infinite loop
            }
            ILLabel label = node as ILLabel;

            if (label != null)
            {
                return(Exit(label, visitedNodes));
            }

            ILExpression expr = node as ILExpression;

            if (expr != null)
            {
                if (expr.Code == ILCode.Br || expr.Code == ILCode.Leave)
                {
                    ILLabel target = (ILLabel)expr.Operand;
                    // Early exit - same try-block
                    if (GetParents(expr).OfType <ILTryCatchBlock>().FirstOrDefault() == GetParents(target).OfType <ILTryCatchBlock>().FirstOrDefault())
                    {
                        return(Enter(target, visitedNodes));
                    }
                    // Make sure we are not entering any try-block
                    var srcTryBlocks = GetParents(expr).OfType <ILTryCatchBlock>().Reverse().ToList();
                    var dstTryBlocks = GetParents(target).OfType <ILTryCatchBlock>().Reverse().ToList();
                    // Skip blocks that we are already in
                    int i = 0;
                    while (i < srcTryBlocks.Count && i < dstTryBlocks.Count && srcTryBlocks[i] == dstTryBlocks[i])
                    {
                        i++;
                    }
                    if (i == dstTryBlocks.Count)
                    {
                        return(Enter(target, visitedNodes));
                    }
                    else
                    {
                        ILTryCatchBlock dstTryBlock = dstTryBlocks[i];
                        // Check that the goto points to the start
                        ILTryCatchBlock current = dstTryBlock;
                        while (current != null)
                        {
                            foreach (ILNode n in current.TryBlock.Body)
                            {
                                if (n is ILLabel)
                                {
                                    if (n == target)
                                    {
                                        return(dstTryBlock);
                                    }
                                }
                                else if (!n.Match(ILCode.Nop))
                                {
                                    current = n as ILTryCatchBlock;
                                    break;
                                }
                            }
                        }
                        return(null);
                    }
                }
                else if (expr.Code == ILCode.Nop)
                {
                    return(Exit(expr, visitedNodes));
                }
                else if (expr.Code == ILCode.LoopOrSwitchBreak)
                {
                    ILNode breakBlock = GetParents(expr).First(n => n is ILWhileLoop || n is ILSwitch);
                    return(Exit(breakBlock, new HashSet <ILNode>()
                    {
                        expr
                    }));
                }
                else if (expr.Code == ILCode.LoopContinue)
                {
                    ILNode continueBlock = GetParents(expr).First(n => n is ILWhileLoop);
                    return(Enter(continueBlock, new HashSet <ILNode>()
                    {
                        expr
                    }));
                }
                else
                {
                    return(expr);
                }
            }

            ILBlock block = node as ILBlock;

            if (block != null)
            {
                if (block.EntryGoto != null)
                {
                    return(Enter(block.EntryGoto, visitedNodes));
                }
                else if (block.Body.Count > 0)
                {
                    return(Enter(block.Body[0], visitedNodes));
                }
                else
                {
                    return(Exit(block, visitedNodes));
                }
            }

            ILCondition cond = node as ILCondition;

            if (cond != null)
            {
                return(cond.Condition);
            }

            ILWhileLoop loop = node as ILWhileLoop;

            if (loop != null)
            {
                if (loop.Condition != null)
                {
                    return(loop.Condition);
                }
                else
                {
                    return(Enter(loop.BodyBlock, visitedNodes));
                }
            }

            ILTryCatchBlock tryCatch = node as ILTryCatchBlock;

            if (tryCatch != null)
            {
                return(tryCatch);
            }

            ILSwitch ilSwitch = node as ILSwitch;

            if (ilSwitch != null)
            {
                return(ilSwitch.Condition);
            }

            throw new NotSupportedException(node.GetType().ToString());
        }
示例#5
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);
        }
示例#6
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);
        }
示例#7
0
        void DuplicateReturnStatements(ILBlock method)
        {
            Dictionary <ILLabel, ILNode> nextSibling = new Dictionary <ILLabel, ILNode>();

            // Build navigation data
            foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>())
            {
                for (int i = 0; i < block.Body.Count - 1; i++)
                {
                    ILLabel curr = block.Body[i] as ILLabel;
                    if (curr != null)
                    {
                        nextSibling[curr] = block.Body[i + 1];
                    }
                }
            }

            // Duplicate returns
            foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>())
            {
                for (int i = 0; i < block.Body.Count; i++)
                {
                    ILLabel targetLabel;
                    if (block.Body[i].Match(ILCode.Br, out targetLabel) || block.Body[i].Match(ILCode.Leave, out targetLabel))
                    {
                        // Skip extra labels
                        while (nextSibling.ContainsKey(targetLabel) && nextSibling[targetLabel] is ILLabel)
                        {
                            targetLabel = (ILLabel)nextSibling[targetLabel];
                        }

                        // Inline return statement
                        ILNode target;
                        List <ILExpression> retArgs;
                        if (nextSibling.TryGetValue(targetLabel, out target))
                        {
                            if (target.Match(ILCode.Ret, out retArgs))
                            {
                                ILVariable locVar;
                                object     constValue;
                                if (retArgs.Count == 0)
                                {
                                    block.Body[i] = new ILExpression(ILCode.Ret, null)
                                    {
                                        Original = new List <ILExpression> {
                                            (ILExpression)block.Body[i]
                                        }
                                    };
                                }
                                else if (retArgs.Single().Match(ILCode.Ldloc, out locVar))
                                {
                                    block.Body[i] = new ILExpression(ILCode.Ret, null, new ILExpression(ILCode.Ldloc, locVar))
                                    {
                                        Original = new List <ILExpression> {
                                            (ILExpression)block.Body[i]
                                        }
                                    };
                                }
                                else if (retArgs.Single().Match(ILCode.Ldc_I4, out constValue))
                                {
                                    block.Body[i] = new ILExpression(ILCode.Ret, null, new ILExpression(ILCode.Ldc_I4, constValue))
                                    {
                                        Original = new List <ILExpression> {
                                            (ILExpression)block.Body[i]
                                        }
                                    };
                                }
                            }
                        }
                        else
                        {
                            if (method.Body.Count > 0 && method.Body.Last() == targetLabel)
                            {
                                // It exits the main method - so it is same as return;
                                block.Body[i] = new ILExpression(ILCode.Ret, null);
                            }
                        }
                    }
                }
            }
        }
示例#8
0
        /// <summary>
        /// Group input into a set of blocks that can be later arbitraliby schufled.
        /// The method adds necessary branches to make control flow between blocks
        /// explicit and thus order independent.
        /// </summary>
        void SplitToBasicBlocks(ILBlock block)
        {
            List <ILNode> basicBlocks = new List <ILNode>();

            ILLabel entryLabel = block.Body.FirstOrDefault() as ILLabel ?? new ILLabel()
            {
                Name = "Block_" + (nextLabelIndex++)
            };
            ILBasicBlock basicBlock = new ILBasicBlock();

            basicBlocks.Add(basicBlock);
            basicBlock.Body.Add(entryLabel);
            block.EntryGoto = new ILExpression(ILCode.Br, entryLabel);

            if (block.Body.Count > 0)
            {
                if (block.Body[0] != entryLabel)
                {
                    basicBlock.Body.Add(block.Body[0]);
                }

                for (int i = 1; i < block.Body.Count; i++)
                {
                    ILNode lastNode = block.Body[i - 1];
                    ILNode currNode = block.Body[i];

                    // Start a new basic block if necessary
                    if (currNode is ILLabel ||
                        currNode is ILTryCatchBlock ||                     // Counts as label
                        lastNode.IsConditionalControlFlow() ||
                        lastNode.IsUnconditionalControlFlow())
                    {
                        // Try to reuse the label
                        ILLabel label = currNode as ILLabel ?? new ILLabel()
                        {
                            Name = "Block_" + (nextLabelIndex++).ToString()
                        };

                        // Terminate the last block
                        if (!lastNode.IsUnconditionalControlFlow())
                        {
                            // Explicit branch from one block to other
                            basicBlock.Body.Add(new ILExpression(ILCode.Br, label));
                        }

                        // Start the new block
                        basicBlock = new ILBasicBlock();
                        basicBlocks.Add(basicBlock);
                        basicBlock.Body.Add(label);

                        // Add the node to the basic block
                        if (currNode != label)
                        {
                            basicBlock.Body.Add(currNode);
                        }
                    }
                    else
                    {
                        basicBlock.Body.Add(currNode);
                    }
                }
            }

            block.Body = basicBlocks;
            return;
        }
示例#9
0
        /// <summary>
        /// Removes redundatant Br, Nop, Dup, Pop
        /// Ignore arguments of 'leave'
        /// </summary>
        /// <param name="method"></param>
        internal static void RemoveRedundantCode(ILBlock method)
        {
            Dictionary <ILLabel, int> labelRefCount = new Dictionary <ILLabel, int>();

            foreach (ILLabel target in method.GetSelfAndChildrenRecursive <ILExpression>(e => e.IsBranch()).SelectMany(e => e.GetBranchTargets()))
            {
                labelRefCount[target] = labelRefCount.GetOrDefault(target) + 1;
            }

            foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>())
            {
                List <ILNode> body    = block.Body;
                List <ILNode> newBody = new List <ILNode>(body.Count);
                for (int i = 0; i < body.Count; i++)
                {
                    ILLabel      target;
                    ILExpression popExpr;
                    if (body[i].Match(ILCode.Br, out target) && i + 1 < body.Count && body[i + 1] == target)
                    {
                        // Ignore the branch
                        if (labelRefCount[target] == 1)
                        {
                            i++;                              // Ignore the label as well
                        }
                    }
                    else if (body[i].Match(ILCode.Nop))
                    {
                        // Ignore nop
                    }
                    else if (body[i].Match(ILCode.Pop, out popExpr))
                    {
                        ILVariable v;
                        if (!popExpr.Match(ILCode.Ldloc, out v))
                        {
                            throw new Exception("Pop should have just ldloc at this stage");
                        }
                        // Best effort to move the ILRange to previous statement
                        ILVariable   prevVar;
                        ILExpression prevExpr;
                        if (i - 1 >= 0 && body[i - 1].Match(ILCode.Stloc, out prevVar, out prevExpr) && prevVar == v)
                        {
                            prevExpr.ILRanges.AddRange(((ILExpression)body[i]).ILRanges);
                        }
                        // Ignore pop
                    }
                    else
                    {
                        ILLabel label = body[i] as ILLabel;
                        if (label != null)
                        {
                            if (labelRefCount.GetOrDefault(label) > 0)
                            {
                                newBody.Add(label);
                            }
                        }
                        else
                        {
                            newBody.Add(body[i]);
                        }
                    }
                }
                block.Body = newBody;
            }

            // Ignore arguments of 'leave'
            foreach (ILExpression expr in method.GetSelfAndChildrenRecursive <ILExpression>(e => e.Code == ILCode.Leave))
            {
                if (expr.Arguments.Any(arg => !arg.Match(ILCode.Ldloc)))
                {
                    throw new Exception("Leave should have just ldloc at this stage");
                }
                expr.Arguments.Clear();
            }

            // 'dup' removal
            foreach (ILExpression expr in method.GetSelfAndChildrenRecursive <ILExpression>())
            {
                for (int i = 0; i < expr.Arguments.Count; i++)
                {
                    ILExpression child;
                    if (expr.Arguments[i].Match(ILCode.Dup, out child))
                    {
                        child.ILRanges.AddRange(expr.Arguments[i].ILRanges);
                        expr.Arguments[i] = child;
                    }
                }
            }
        }
示例#10
0
 public static bool MatchLastAndBr <T>(this ILBasicBlock bb, ILCode code, out T operand, out ILExpression arg, out ILLabel brLabel)
 {
     if (bb.Body.ElementAtOrDefault(bb.Body.Count - 2).Match(code, out operand, out arg) &&
         bb.Body.LastOrDefault().Match(ILCode.Br, out brLabel))
     {
         return(true);
     }
     operand = default(T);
     arg     = null;
     brLabel = null;
     return(false);
 }
示例#11
0
 public static bool MatchSingleAndBr <T>(this ILBasicBlock bb, ILCode code, out T operand, out ILExpression arg, out ILLabel brLabel)
 {
     if (bb.Body.Count == 3 &&
         bb.Body[0] is ILLabel &&
         bb.Body[1].Match(code, out operand, out arg) &&
         bb.Body[2].Match(ILCode.Br, out brLabel))
     {
         return(true);
     }
     operand = default(T);
     arg     = null;
     brLabel = null;
     return(false);
 }