Exemplo n.º 1
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;
                    }
                }
            }
        }
Exemplo n.º 2
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;
        }
Exemplo n.º 3
0
        void AnalyzeMoveNext()
        {
            ILBlock ilMethod = CreateILAst(moveNextMethod);

            int startIndex;

            if (ilMethod.Body.Count == 6)
            {
                startIndex = 0;
            }
            else if (ilMethod.Body.Count == 7)
            {
                // stloc(cachedState, ldfld(valuetype StateMachineStruct::<>1__state, ldloc(this)))
                ILExpression cachedStateInit;
                if (!ilMethod.Body[0].Match(ILCode.Stloc, out cachedStateVar, out cachedStateInit))
                {
                    throw new SymbolicAnalysisFailedException();
                }
                ILExpression instanceExpr;
                IField       loadedField;
                if (!cachedStateInit.Match(ILCode.Ldfld, out loadedField, out instanceExpr) || loadedField.ResolveFieldWithinSameModule() != stateField || !instanceExpr.MatchThis())
                {
                    throw new SymbolicAnalysisFailedException();
                }
                startIndex = 1;
            }
            else
            {
                throw new SymbolicAnalysisFailedException();
            }

            mainTryCatch = ilMethod.Body[startIndex + 0] as ILTryCatchBlock;
            if (mainTryCatch == null || mainTryCatch.CatchBlocks.Count != 1)
            {
                throw new SymbolicAnalysisFailedException();
            }
            if (mainTryCatch.FaultBlock != null || mainTryCatch.FinallyBlock != null)
            {
                throw new SymbolicAnalysisFailedException();
            }

            setResultAndExitLabel = ilMethod.Body[startIndex + 1] as ILLabel;
            if (setResultAndExitLabel == null)
            {
                throw new SymbolicAnalysisFailedException();
            }

            if (!MatchStateAssignment(ilMethod.Body[startIndex + 2], out finalState))
            {
                throw new SymbolicAnalysisFailedException();
            }

            // call(AsyncTaskMethodBuilder`1::SetResult, ldflda(StateMachine::<>t__builder, ldloc(this)), ldloc(<>t__result))
            IMethod      setResultMethod;
            ILExpression builderExpr;

            if (methodType == AsyncMethodType.TaskOfT)
            {
                if (!ilMethod.Body[startIndex + 3].Match(ILCode.Call, out setResultMethod, out builderExpr, out resultExpr))
                {
                    throw new SymbolicAnalysisFailedException();
                }
            }
            else
            {
                if (!ilMethod.Body[startIndex + 3].Match(ILCode.Call, out setResultMethod, out builderExpr))
                {
                    throw new SymbolicAnalysisFailedException();
                }
            }
            if (!(setResultMethod.Name == "SetResult" && IsBuilderFieldOnThis(builderExpr)))
            {
                throw new SymbolicAnalysisFailedException();
            }

            exitLabel = ilMethod.Body[startIndex + 4] as ILLabel;
            if (exitLabel == null)
            {
                throw new SymbolicAnalysisFailedException();
            }
        }
Exemplo n.º 4
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);
 }
Exemplo n.º 5
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());
        }
Exemplo n.º 6
0
        public bool SimplifyShortCircuit(List <ILNode> body, ILBasicBlock head, int pos)
        {
            Debug.Assert(body.Contains(head));

            ILExpression condExpr;
            ILLabel      trueLabel;
            ILLabel      falseLabel;

            if (head.MatchLastAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel))
            {
                for (int pass = 0; pass < 2; pass++)
                {
                    // On the second pass, swap labels and negate expression of the first branch
                    // It is slightly ugly, but much better then copy-pasting this whole block
                    ILLabel nextLabel   = (pass == 0) ? trueLabel  : falseLabel;
                    ILLabel otherLablel = (pass == 0) ? falseLabel : trueLabel;
                    bool    negate      = (pass == 1);

                    ILBasicBlock nextBasicBlock = labelToBasicBlock[nextLabel];
                    ILExpression nextCondExpr;
                    ILLabel      nextTrueLablel;
                    ILLabel      nextFalseLabel;
                    if (body.Contains(nextBasicBlock) &&
                        nextBasicBlock != head &&
                        labelGlobalRefCount[(ILLabel)nextBasicBlock.Body.First()] == 1 &&
                        nextBasicBlock.MatchSingleAndBr(ILCode.Brtrue, out nextTrueLablel, out nextCondExpr, out nextFalseLabel) &&
                        (otherLablel == nextFalseLabel || otherLablel == nextTrueLablel))
                    {
                        // Create short cicuit branch
                        ILExpression logicExpr;
                        if (otherLablel == nextFalseLabel)
                        {
                            logicExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, negate ? new ILExpression(ILCode.LogicNot, null, condExpr) : condExpr, nextCondExpr);
                        }
                        else
                        {
                            logicExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, negate ? condExpr : new ILExpression(ILCode.LogicNot, null, condExpr), nextCondExpr);
                        }
                        var tail = head.Body.RemoveTail(ILCode.Brtrue, ILCode.Br);
                        if (context.CalculateILRanges)
                        {
                            nextCondExpr.ILRanges.AddRange(tail[0].ILRanges);                                  // brtrue
                            nextCondExpr.ILRanges.AddRange(nextBasicBlock.ILRanges);
                            nextBasicBlock.Body[0].AddSelfAndChildrenRecursiveILRanges(nextCondExpr.ILRanges); // label
                            nextCondExpr.ILRanges.AddRange(nextBasicBlock.Body[1].ILRanges);                   // brtrue
                        }

                        head.Body.Add(new ILExpression(ILCode.Brtrue, nextTrueLablel, logicExpr));
                        ILExpression brFalseLbl;
                        head.Body.Add(brFalseLbl = new ILExpression(ILCode.Br, nextFalseLabel));
                        if (context.CalculateILRanges)
                        {
                            nextBasicBlock.Body[2].AddSelfAndChildrenRecursiveILRanges(brFalseLbl.ILRanges);              // br
                            brFalseLbl.ILRanges.AddRange(nextBasicBlock.EndILRanges);
                            tail[1].AddSelfAndChildrenRecursiveILRanges(brFalseLbl.ILRanges);                             // br
                        }

                        // Remove the inlined branch from scope
                        body.RemoveOrThrow(nextBasicBlock);

                        return(true);
                    }
                }
            }
            return(false);
        }
        void AnalyzeMoveNext()
        {
            MethodDef 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();
                }
                IMethod      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);
        }
Exemplo n.º 8
0
        int AssignStateRanges(List <ILNode> body, int bodyLength, bool forDispose)
        {
            if (bodyLength == 0)
            {
                return(0);
            }
            for (int i = 0; i < bodyLength; i++)
            {
                StateRange nodeRange = ranges[body[i]];
                nodeRange.Simplify();

                ILLabel label = body[i] as ILLabel;
                if (label != null)
                {
                    ranges[body[i + 1]].UnionWith(nodeRange);
                    continue;
                }

                ILTryCatchBlock tryFinally = body[i] as ILTryCatchBlock;
                if (tryFinally != null)
                {
                    if (!forDispose || tryFinally.CatchBlocks.Count != 0 || tryFinally.FaultBlock != null || tryFinally.FinallyBlock == null)
                    {
                        throw new YieldAnalysisFailedException();
                    }
                    ranges[tryFinally.TryBlock].UnionWith(nodeRange);
                    if (tryFinally.TryBlock.Body.Count != 0)
                    {
                        ranges[tryFinally.TryBlock.Body[0]].UnionWith(nodeRange);
                        AssignStateRanges(tryFinally.TryBlock.Body, tryFinally.TryBlock.Body.Count, forDispose);
                    }
                    continue;
                }

                ILExpression expr = body[i] as ILExpression;
                if (expr == null)
                {
                    throw new YieldAnalysisFailedException();
                }
                switch (expr.Code)
                {
                case ILCode.Switch:
                {
                    SymbolicValue val = Eval(expr.Arguments[0]);
                    if (val.Type != SymbolicValueType.State)
                    {
                        throw new YieldAnalysisFailedException();
                    }
                    ILLabel[] targetLabels = (ILLabel[])expr.Operand;
                    for (int j = 0; j < targetLabels.Length; j++)
                    {
                        int state = j - val.Constant;
                        ranges[targetLabels[j]].UnionWith(nodeRange, state, state);
                    }
                    StateRange nextRange = ranges[body[i + 1]];
                    nextRange.UnionWith(nodeRange, int.MinValue, -1 - val.Constant);
                    nextRange.UnionWith(nodeRange, targetLabels.Length - val.Constant, int.MaxValue);
                    break;
                }

                case ILCode.Br:
                case ILCode.Leave:
                    ranges[(ILLabel)expr.Operand].UnionWith(nodeRange);
                    break;

                case ILCode.Brtrue:
                {
                    SymbolicValue val = Eval(expr.Arguments[0]);
                    if (val.Type == SymbolicValueType.StateEquals)
                    {
                        ranges[(ILLabel)expr.Operand].UnionWith(nodeRange, val.Constant, val.Constant);
                        StateRange nextRange = ranges[body[i + 1]];
                        nextRange.UnionWith(nodeRange, int.MinValue, val.Constant - 1);
                        nextRange.UnionWith(nodeRange, val.Constant + 1, int.MaxValue);
                    }
                    else if (val.Type == SymbolicValueType.StateInEquals)
                    {
                        ranges[body[i + 1]].UnionWith(nodeRange, val.Constant, val.Constant);
                        StateRange targetRange = ranges[(ILLabel)expr.Operand];
                        targetRange.UnionWith(nodeRange, int.MinValue, val.Constant - 1);
                        targetRange.UnionWith(nodeRange, val.Constant + 1, int.MaxValue);
                    }
                    else
                    {
                        throw new YieldAnalysisFailedException();
                    }
                    break;
                }

                case ILCode.Nop:
                    ranges[body[i + 1]].UnionWith(nodeRange);
                    break;

                case ILCode.Ret:
                    break;

                case ILCode.Stloc:
                {
                    SymbolicValue val = Eval(expr.Arguments[0]);
                    if (val.Type == SymbolicValueType.State && val.Constant == 0 && rangeAnalysisStateVariable == null)
                    {
                        rangeAnalysisStateVariable = (ILVariable)expr.Operand;
                    }
                    else
                    {
                        throw new YieldAnalysisFailedException();
                    }
                    goto case ILCode.Nop;
                }

                case ILCode.Call:
                    // in some cases (e.g. foreach over array) the C# compiler produces a finally method outside of try-finally blocks
                    if (forDispose)
                    {
                        MethodDefinition mdef = GetMethodDefinition(expr.Operand as MethodReference);
                        if (mdef == null || finallyMethodToStateInterval.ContainsKey(mdef))
                        {
                            throw new YieldAnalysisFailedException();
                        }
                        finallyMethodToStateInterval.Add(mdef, nodeRange.ToEnclosingInterval());
                    }
                    else
                    {
                        throw new YieldAnalysisFailedException();
                    }
                    break;

                default:
                    if (forDispose)
                    {
                        throw new YieldAnalysisFailedException();
                    }
                    else
                    {
                        return(i);
                    }
                }
            }
            return(bodyLength);
        }
Exemplo n.º 9
0
        ControlFlowGraph BuildGraph(List <ILNode> nodes, ILLabel entryLabel)
        {
            cached_ControlFlowGraph.Nodes.Clear();
            int             index      = 0;
            var             cfNodes    = cached_ControlFlowGraph.Nodes;
            ControlFlowNode entryPoint = new ControlFlowNode(index++, 0, ControlFlowNodeType.EntryPoint);

            cfNodes.Add(entryPoint);
            ControlFlowNode regularExit = new ControlFlowNode(index++, null, ControlFlowNodeType.RegularExit);

            cfNodes.Add(regularExit);
            ControlFlowNode exceptionalExit = new ControlFlowNode(index++, null, ControlFlowNodeType.ExceptionalExit);

            cfNodes.Add(exceptionalExit);

            // Create graph nodes
            labelToCfNode.Clear();
            Dictionary <ILNode, ControlFlowNode> astNodeToCfNode = new Dictionary <ILNode, ControlFlowNode>();
            List <ILLabel> listLabels = null;

            foreach (ILBasicBlock node in nodes)
            {
                ControlFlowNode cfNode = new ControlFlowNode(index++, null, ControlFlowNodeType.Normal);
                cfNodes.Add(cfNode);
                astNodeToCfNode[node] = cfNode;
                cfNode.UserData       = node;

                // Find all contained labels
                foreach (ILLabel label in node.GetSelfAndChildrenRecursive <ILLabel>(listLabels ?? (listLabels = new List <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
            List <ILExpression> listExpressions = null;

            foreach (ILBasicBlock node in nodes)
            {
                ControlFlowNode source = astNodeToCfNode[node];

                // Find all branches
                foreach (ILLabel target in node.GetSelfAndChildrenRecursive <ILExpression>(listExpressions ?? (listExpressions = new List <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(cached_ControlFlowGraph);
        }
Exemplo n.º 10
0
        public int AssignStateRanges(List <ILNode> body, int bodyLength)
        {
            if (bodyLength == 0)
            {
                return(0);
            }
            for (int i = 0; i < bodyLength; i++)
            {
                StateRange nodeRange = ranges[body[i]];
                nodeRange.Simplify();

                ILLabel label = body[i] as ILLabel;
                if (label != null)
                {
                    ranges[body[i + 1]].UnionWith(nodeRange);
                    continue;
                }

                ILTryCatchBlock tryFinally = body[i] as ILTryCatchBlock;
                if (tryFinally != null)
                {
                    if (mode == StateRangeAnalysisMode.IteratorDispose)
                    {
                        if (tryFinally.CatchBlocks.Count != 0 || tryFinally.FaultBlock != null || tryFinally.FinallyBlock == null)
                        {
                            throw new SymbolicAnalysisFailedException();
                        }
                        ranges[tryFinally.TryBlock].UnionWith(nodeRange);
                        if (tryFinally.TryBlock.Body.Count != 0)
                        {
                            ranges[tryFinally.TryBlock.Body[0]].UnionWith(nodeRange);
                            AssignStateRanges(tryFinally.TryBlock.Body, tryFinally.TryBlock.Body.Count);
                        }
                        continue;
                    }
                    else if (mode == StateRangeAnalysisMode.AsyncMoveNext)
                    {
                        return(i);
                    }
                    else
                    {
                        throw new SymbolicAnalysisFailedException();
                    }
                }

                ILExpression expr = body[i] as ILExpression;
                if (expr == null)
                {
                    throw new SymbolicAnalysisFailedException();
                }
                switch (expr.Code)
                {
                case ILCode.Switch:
                {
                    SymbolicValue val = evalContext.Eval(expr.Arguments[0]);
                    if (val.Type != SymbolicValueType.State)
                    {
                        goto default;
                    }
                    ILLabel[] targetLabels = (ILLabel[])expr.Operand;
                    for (int j = 0; j < targetLabels.Length; j++)
                    {
                        int state = j - val.Constant;
                        ranges[targetLabels[j]].UnionWith(nodeRange, state, state);
                    }
                    StateRange nextRange = ranges[body[i + 1]];
                    nextRange.UnionWith(nodeRange, int.MinValue, -1 - val.Constant);
                    nextRange.UnionWith(nodeRange, targetLabels.Length - val.Constant, int.MaxValue);
                    break;
                }

                case ILCode.Br:
                case ILCode.Leave:
                    ranges[(ILLabel)expr.Operand].UnionWith(nodeRange);
                    break;

                case ILCode.Brtrue:
                {
                    SymbolicValue val = evalContext.Eval(expr.Arguments[0]).AsBool();
                    if (val.Type == SymbolicValueType.StateEquals)
                    {
                        ranges[(ILLabel)expr.Operand].UnionWith(nodeRange, val.Constant, val.Constant);
                        StateRange nextRange = ranges[body[i + 1]];
                        nextRange.UnionWith(nodeRange, int.MinValue, val.Constant - 1);
                        nextRange.UnionWith(nodeRange, val.Constant + 1, int.MaxValue);
                        break;
                    }
                    else if (val.Type == SymbolicValueType.StateInEquals)
                    {
                        ranges[body[i + 1]].UnionWith(nodeRange, val.Constant, val.Constant);
                        StateRange targetRange = ranges[(ILLabel)expr.Operand];
                        targetRange.UnionWith(nodeRange, int.MinValue, val.Constant - 1);
                        targetRange.UnionWith(nodeRange, val.Constant + 1, int.MaxValue);
                        break;
                    }
                    else
                    {
                        goto default;
                    }
                }

                case ILCode.Nop:
                    ranges[body[i + 1]].UnionWith(nodeRange);
                    break;

                case ILCode.Ret:
                    break;

                case ILCode.Stloc:
                {
                    SymbolicValue val = evalContext.Eval(expr.Arguments[0]);
                    if (val.Type == SymbolicValueType.State && val.Constant == 0)
                    {
                        evalContext.AddStateVariable((ILVariable)expr.Operand);
                        goto case ILCode.Nop;
                    }
                    else
                    {
                        goto default;
                    }
                }

                case ILCode.Call:
                    // in some cases (e.g. foreach over array) the C# compiler produces a finally method outside of try-finally blocks
                    if (mode == StateRangeAnalysisMode.IteratorDispose)
                    {
                        MethodDefinition mdef = (expr.Operand as MethodReference).ResolveWithinSameModule();
                        if (mdef == null || finallyMethodToStateRange.ContainsKey(mdef))
                        {
                            throw new SymbolicAnalysisFailedException();
                        }
                        finallyMethodToStateRange.Add(mdef, nodeRange);
                        break;
                    }
                    else
                    {
                        goto default;
                    }

                case ILCode.Stfld:
//					IL_0000: ldarg.0
//					IL_0001: ldc.i4.m1
//					IL_0002: stfld int32 CodeCleaner.Program/'<TestX>c__Iterator0'::$PC
//					IL_0007: ret
                    if (expr.Arguments [0].MatchThis() && (expr.Operand as FieldReference).Name == "$PC")
                    {
                        break;
                    }
                    else
                    {
                        if (mode == StateRangeAnalysisMode.IteratorDispose)
                        {
                            throw new SymbolicAnalysisFailedException();
                        }
                        else
                        {
                            return(i);
                        }
                    }
                    break;

                default:
                    if (mode == StateRangeAnalysisMode.IteratorDispose)
                    {
                        throw new SymbolicAnalysisFailedException();
                    }
                    else
                    {
                        return(i);
                    }
                }
            }
            return(bodyLength);
        }
Exemplo n.º 11
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
                            };
                            var tail = block.Body.RemoveTail(ILCode.Switch, ILCode.Br);
                            if (context.CalculateILRanges)
                            {
                                ilSwitch.ILRanges.AddRange(tail[0].ILRanges);                                   // no recursive add
                                tail[1].AddSelfAndChildrenRecursiveILRanges(ilSwitch.ILRanges);
                            }
                            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))
                            {
                                var old = ilSwitch.Condition;
                                ilSwitch.Condition = subArgs[0];
                                if (context.CalculateILRanges)
                                {
                                    ilSwitch.Condition.ILRanges.AddRange(old.ILRanges);                                     // no recursive add
                                    for (int i = 1; i < subArgs.Count; i++)
                                    {
                                        subArgs[i].AddSelfAndChildrenRecursiveILRanges(ilSwitch.Condition.ILRanges);
                                    }
                                }
                            }

                            // 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++).ToString()
                                                },
                                                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);
                                    tail = block.Body.RemoveTail(ILCode.Br);
                                    if (context.CalculateILRanges)
                                    {
                                        tail[0].AddSelfAndChildrenRecursiveILRanges(caseBlock.ILRanges);
                                    }

                                    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++).ToString()
                                            },
                                            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)
                                }
                            };
                            var tail = block.Body.RemoveTail(ILCode.Brtrue, ILCode.Br);
                            if (context.CalculateILRanges)
                            {
                                condExpr.ILRanges.AddRange(tail[0].ILRanges);                                   // no recursive add
                                tail[1].AddSelfAndChildrenRecursiveILRanges(ilCond.FalseBlock.ILRanges);
                            }
                            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);
        }
Exemplo n.º 12
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
                            var         tail = basicBlock.Body.RemoveTail(ILCode.Brtrue, ILCode.Br);
                            ILWhileLoop whileLoop;
                            basicBlock.Body.Add(whileLoop = new ILWhileLoop()
                            {
                                Condition = condExpr,
                                BodyBlock = new ILBlock()
                                {
                                    EntryGoto = new ILExpression(ILCode.Br, trueLabel),
                                    Body      = FindLoops(loopContents, node, false)
                                }
                            });
                            if (context.CalculateILRanges)
                            {
                                whileLoop.ILRanges.AddRange(tail[0].ILRanges);                                  // no recursive add
                                tail[1].AddSelfAndChildrenRecursiveILRanges(whileLoop.ILRanges);
                            }
                            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++).ToString()
                                },
                                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);
        }
Exemplo n.º 13
0
        void AnalyzeMoveNext()
        {
            MethodDefinition moveNextMethod = enumeratorType.Methods.FirstOrDefault(m => m.Name == "MoveNext");
            ILBlock          ilMethod       = CreateILAst(moveNextMethod);

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

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

            // 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 YieldAnalysisFailedException();
                }
            }
            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 YieldAnalysisFailedException();
                }
            }

            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 YieldAnalysisFailedException();
                }
                // must be a try-fault block:
                if (tryFaultBlock.CatchBlocks.Count != 0 || tryFaultBlock.FinallyBlock != null || tryFaultBlock.FaultBlock == null)
                {
                    throw new YieldAnalysisFailedException();
                }

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

                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 YieldAnalysisFailedException();
                }
                if (store0.Arguments[0].Code != ILCode.Ldc_I4 || (int)store0.Arguments[0].Operand != 0)
                {
                    throw new YieldAnalysisFailedException();
                }

                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 YieldAnalysisFailedException();
            }

            InitStateRanges(body[0]);
            int pos = AssignStateRanges(body, bodyLength, forDispose: false);

            if (pos > 0 && body[pos - 1] is ILLabel)
            {
                pos--;
            }
            else
            {
                // ensure that the first element at body[pos] is a label:
                ILLabel newLabel = new ILLabel();
                newLabel.Name    = "YieldReturnEntryPoint";
                ranges[newLabel] = ranges[body[pos]];                 // give the label the range of the instruction at body[pos]

                body.Insert(pos, newLabel);
                bodyLength++;
            }

            List <KeyValuePair <ILLabel, StateRange> > labels = new List <KeyValuePair <ILLabel, StateRange> >();

            for (int i = pos; i < bodyLength; i++)
            {
                ILLabel label = body[i] as ILLabel;
                if (label != null)
                {
                    labels.Add(new KeyValuePair <ILLabel, StateRange>(label, ranges[label]));
                }
            }

            ConvertBody(body, pos, bodyLength, labels);
        }
Exemplo n.º 14
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);
                                }
                                else if (retArgs.Single().Match(ILCode.Ldloc, out locVar))
                                {
                                    block.Body[i] = new ILExpression(ILCode.Ret, null, new ILExpression(ILCode.Ldloc, locVar));
                                }
                                else if (retArgs.Single().Match(ILCode.Ldc_I4, out constValue))
                                {
                                    block.Body[i] = new ILExpression(ILCode.Ret, null, new ILExpression(ILCode.Ldc_I4, constValue));
                                }
                            }
                        }
                        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);
                            }
                        }
                    }
                }
            }
        }
        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 IField) == 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 IField) == 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())
                {
                    MethodDef method = GetMethodDefinition(expr.Operand as IMethod);
                    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));
        }
Exemplo n.º 16
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);
 }
Exemplo n.º 17
0
		public int AssignStateRanges(List<ILNode> body, int bodyLength)
		{
			if (bodyLength == 0)
				return 0;
			for (int i = 0; i < bodyLength; i++) {
				StateRange nodeRange = ranges[body[i]];
				nodeRange.Simplify();
				
				ILLabel label = body[i] as ILLabel;
				if (label != null) {
					ranges[body[i + 1]].UnionWith(nodeRange);
					continue;
				}
				
				ILTryCatchBlock tryFinally = body[i] as ILTryCatchBlock;
				if (tryFinally != null) {
					if (mode == StateRangeAnalysisMode.IteratorDispose) {
						if (tryFinally.CatchBlocks.Count != 0 || tryFinally.FaultBlock != null || tryFinally.FinallyBlock == null)
							throw new SymbolicAnalysisFailedException();
						ranges[tryFinally.TryBlock].UnionWith(nodeRange);
						if (tryFinally.TryBlock.Body.Count != 0) {
							ranges[tryFinally.TryBlock.Body[0]].UnionWith(nodeRange);
							AssignStateRanges(tryFinally.TryBlock.Body, tryFinally.TryBlock.Body.Count);
						}
						continue;
					} else if (mode == StateRangeAnalysisMode.AsyncMoveNext) {
						return i;
					} else {
						throw new SymbolicAnalysisFailedException();
					}
				}
				
				ILExpression expr = body[i] as ILExpression;
				if (expr == null)
					throw new SymbolicAnalysisFailedException();
				switch (expr.Code) {
					case ILCode.Switch:
						{
							SymbolicValue val = evalContext.Eval(expr.Arguments[0]);
							if (val.Type != SymbolicValueType.State)
								goto default;
							ILLabel[] targetLabels = (ILLabel[])expr.Operand;
							for (int j = 0; j < targetLabels.Length; j++) {
								int state = j - val.Constant;
								ranges[targetLabels[j]].UnionWith(nodeRange, state, state);
							}
							StateRange nextRange = ranges[body[i + 1]];
							nextRange.UnionWith(nodeRange, int.MinValue, -1 - val.Constant);
							nextRange.UnionWith(nodeRange, targetLabels.Length - val.Constant, int.MaxValue);
							break;
						}
					case ILCode.Br:
					case ILCode.Leave:
						ranges[(ILLabel)expr.Operand].UnionWith(nodeRange);
						break;
					case ILCode.Brtrue:
						{
							SymbolicValue val = evalContext.Eval(expr.Arguments[0]);
							if (val.Type == SymbolicValueType.StateEquals) {
								ranges[(ILLabel)expr.Operand].UnionWith(nodeRange, val.Constant, val.Constant);
								StateRange nextRange = ranges[body[i + 1]];
								nextRange.UnionWith(nodeRange, int.MinValue, val.Constant - 1);
								nextRange.UnionWith(nodeRange, val.Constant + 1, int.MaxValue);
								break;
							} else if (val.Type == SymbolicValueType.StateInEquals) {
								ranges[body[i + 1]].UnionWith(nodeRange, val.Constant, val.Constant);
								StateRange targetRange = ranges[(ILLabel)expr.Operand];
								targetRange.UnionWith(nodeRange, int.MinValue, val.Constant - 1);
								targetRange.UnionWith(nodeRange, val.Constant + 1, int.MaxValue);
								break;
							} else {
								goto default;
							}
						}
					case ILCode.Nop:
						ranges[body[i + 1]].UnionWith(nodeRange);
						break;
					case ILCode.Ret:
						break;
					case ILCode.Stloc:
						{
							SymbolicValue val = evalContext.Eval(expr.Arguments[0]);
							if (val.Type == SymbolicValueType.State && val.Constant == 0) {
								evalContext.AddStateVariable((ILVariable)expr.Operand);
								goto case ILCode.Nop;
							} else {
								goto default;
							}
						}
					case ILCode.Call:
						// in some cases (e.g. foreach over array) the C# compiler produces a finally method outside of try-finally blocks
						if (mode == StateRangeAnalysisMode.IteratorDispose) {
							MethodDef mdef = (expr.Operand as IMethod).ResolveMethodWithinSameModule();
							if (mdef == null || finallyMethodToStateInterval.ContainsKey(mdef))
								throw new SymbolicAnalysisFailedException();
							finallyMethodToStateInterval.Add(mdef, nodeRange.ToEnclosingInterval());
							break;
						} else {
							goto default;
						}
					default:
						if (mode == StateRangeAnalysisMode.IteratorDispose) {
							throw new SymbolicAnalysisFailedException();
						} else {
							return i;
						}
				}
			}
			return bodyLength;
		}