Esempio n. 1
0
        /// <summary>
        /// Flattens all nested basic blocks, except the the top level 'node' argument
        /// </summary>
        void FlattenBasicBlocks(ILNode node)
        {
            ILBlock block = node as ILBlock;

            if (block != null)
            {
                List <ILNode> flatBody = new List <ILNode>();
                foreach (ILNode child in block.GetChildren())
                {
                    FlattenBasicBlocks(child);
                    ILBasicBlock childAsBB = child as ILBasicBlock;
                    if (childAsBB != null)
                    {
                        if (!(childAsBB.Body.FirstOrDefault() is ILLabel))
                        {
                            throw new Exception("Basic block has to start with a label. \n" + childAsBB.ToString());
                        }
                        if (childAsBB.Body.LastOrDefault() is ILExpression && !childAsBB.Body.LastOrDefault().IsUnconditionalControlFlow())
                        {
                            throw new Exception("Basci block has to end with unconditional control flow. \n" + childAsBB.ToString());
                        }
                        flatBody.AddRange(childAsBB.GetChildren());
                    }
                    else
                    {
                        flatBody.Add(child);
                    }
                }
                block.EntryGoto = null;
                block.Body      = flatBody;
            }
            else if (node is ILExpression)
            {
                // Optimization - no need to check expressions
            }
            else if (node != null)
            {
                // Recursively find all ILBlocks
                foreach (ILNode child in node.GetChildren())
                {
                    FlattenBasicBlocks(child);
                }
            }
        }
Esempio n. 2
0
        public bool InlineAllInBlock(ILBlock block)
        {
            bool          modified = false;
            List <ILNode> body     = block.Body;

            if (block is ILTryCatchBlock.CatchBlock && body.Count > 1)
            {
                ILVariable v = ((ILTryCatchBlock.CatchBlock)block).ExceptionVariable;
                if (v != null && v.IsGenerated)
                {
                    if (numLdloca.GetOrDefault(v) == 0 && numStloc.GetOrDefault(v) == 1 && numLdloc.GetOrDefault(v) == 1)
                    {
                        ILVariable   v2;
                        ILExpression ldException;
                        if (body[0].Match(ILCode.Stloc, out v2, out ldException) && ldException.MatchLdloc(v))
                        {
                            body.RemoveAt(0);
                            ((ILTryCatchBlock.CatchBlock)block).ExceptionVariable = v2;
                            modified = true;
                        }
                    }
                }
            }
            for (int i = 0; i < body.Count - 1;)
            {
                ILVariable   locVar;
                ILExpression expr;
                if (body[i].Match(ILCode.Stloc, out locVar, out expr) && InlineOneIfPossible(block.Body, i, aggressive: false))
                {
                    modified = true;
                    i        = Math.Max(0, i - 1);              // Go back one step
                }
                else
                {
                    i++;
                }
            }
            foreach (ILBasicBlock bb in body.OfType <ILBasicBlock>())
            {
                modified |= InlineAllInBasicBlock(bb);
            }
            return(modified);
        }
Esempio n. 3
0
        /// <summary>
        /// Looks at the enumerator's get_Current method and figures out which of the fields holds the current value.
        /// </summary>
        void AnalyzeCurrentProperty()
        {
            MethodDefinition getCurrentMethod = enumeratorType.Methods.FirstOrDefault(
                m => m.Name.StartsWith("System.Collections.Generic.IEnumerator", StringComparison.Ordinal) &&
                m.Name.EndsWith(".get_Current", StringComparison.Ordinal));
            ILBlock method = CreateILAst(getCurrentMethod);

            if (method.Body.Count == 1)
            {
                // release builds directly return the current field
                ILExpression   retExpr;
                FieldReference field;
                ILExpression   ldFromObj;
                if (method.Body[0].Match(ILCode.Ret, out retExpr) &&
                    retExpr.Match(ILCode.Ldfld, out field, out ldFromObj) &&
                    ldFromObj.MatchThis())
                {
                    currentField = GetFieldDefinition(field);
                }
            }
            else if (method.Body.Count == 2)
            {
                ILVariable     v, v2;
                ILExpression   stExpr;
                FieldReference field;
                ILExpression   ldFromObj;
                ILExpression   retExpr;
                if (method.Body[0].Match(ILCode.Stloc, out v, out stExpr) &&
                    stExpr.Match(ILCode.Ldfld, out field, out ldFromObj) &&
                    ldFromObj.MatchThis() &&
                    method.Body[1].Match(ILCode.Ret, out retExpr) &&
                    retExpr.Match(ILCode.Ldloc, out v2) &&
                    v == v2)
                {
                    currentField = GetFieldDefinition(field);
                }
            }
            if (currentField == null)
            {
                throw new SymbolicAnalysisFailedException();
            }
        }
Esempio n. 4
0
        void ConstructExceptionTable()
        {
            disposeMethod = enumeratorType.Methods.FirstOrDefault(m => m.Name == "System.IDisposable.Dispose");
            ILBlock ilMethod = CreateILAst(disposeMethod);

            var rangeAnalysis = new StateRangeAnalysis(ilMethod.Body[0], StateRangeAnalysisMode.IteratorDispose, stateField);

            rangeAnalysis.AssignStateRanges(ilMethod.Body, ilMethod.Body.Count);
            finallyMethodToStateInterval = rangeAnalysis.finallyMethodToStateInterval;

            // Now look at the finally blocks:
            foreach (var tryFinally in ilMethod.GetSelfAndChildrenRecursive <ILTryCatchBlock>())
            {
                Interval interval    = rangeAnalysis.ranges[tryFinally.TryBlock.Body[0]].ToEnclosingInterval();
                var      finallyBody = tryFinally.FinallyBlock.Body;
                if (finallyBody.Count != 2)
                {
                    throw new SymbolicAnalysisFailedException();
                }
                ILExpression call = finallyBody[0] as ILExpression;
                if (call == null || call.Code != ILCode.Call || call.Arguments.Count != 1)
                {
                    throw new SymbolicAnalysisFailedException();
                }
                if (!call.Arguments[0].MatchThis())
                {
                    throw new SymbolicAnalysisFailedException();
                }
                if (!finallyBody[1].Match(ILCode.Endfinally))
                {
                    throw new SymbolicAnalysisFailedException();
                }

                MethodDefinition mdef = GetMethodDefinition(call.Operand as MethodReference);
                if (mdef == null || finallyMethodToStateInterval.ContainsKey(mdef))
                {
                    throw new SymbolicAnalysisFailedException();
                }
                finallyMethodToStateInterval.Add(mdef, interval);
            }
            rangeAnalysis = null;
        }
Esempio n. 5
0
        public static void Run(DecompilerContext context, ILBlock method)
        {
            if (!context.Settings.YieldReturn)
            {
                return;                 // abort if enumerator decompilation is disabled
            }
            var yrd = new YieldReturnDecompiler();

            yrd.context = context;
            if (!yrd.MatchEnumeratorCreationPattern(method))
            {
                return;
            }
            yrd.enumeratorType = yrd.enumeratorCtor.DeclaringType;
                        #if DEBUG
            if (Debugger.IsAttached)
            {
                yrd.Run();
            }
            else
            {
                                #endif
            try {
                yrd.Run();
            } catch (SymbolicAnalysisFailedException) {
                return;
            }
                                #if DEBUG
        }
                        #endif
            method.Body.Clear();
            method.EntryGoto = null;
            method.Body.AddRange(yrd.newBody);

            // Repeat the inlining/copy propagation optimization because the conversion of field access
            // to local variables can open up additional inlining possibilities.
            ILInlining inlining = new ILInlining(method);
            inlining.InlineAllVariables();
            inlining.CopyPropagation();
        }
Esempio n. 6
0
        public void RemoveGotos(ILBlock method)
        {
            // Build the navigation data
            parent[method] = null;
            foreach (ILNode node in method.GetSelfAndChildrenRecursive <ILNode>())
            {
                ILNode previousChild = null;
                foreach (ILNode child in node.GetChildren())
                {
                    if (parent.ContainsKey(child))
                    {
                        throw new Exception("The following expression is linked from several locations: " + child.ToString());
                    }
                    parent[child] = node;
                    if (previousChild != null)
                    {
                        nextSibling[previousChild] = child;
                    }
                    previousChild = child;
                }
                if (previousChild != null)
                {
                    nextSibling[previousChild] = null;
                }
            }

            // Simplify gotos
            bool modified;

            do
            {
                modified = false;
                foreach (ILExpression gotoExpr in method.GetSelfAndChildrenRecursive <ILExpression>(e => e.Code == ILCode.Br || e.Code == ILCode.Leave))
                {
                    modified |= TrySimplifyGoto(gotoExpr);
                }
            } while(modified);

            RemoveRedundantCode(method);
        }
Esempio n. 7
0
 /// <summary>
 /// Replace endfinally with jump to the end of the finally block
 /// </summary>
 void RemoveEndFinally(ILBlock method)
 {
     // Go thought the list in reverse so that we do the nested blocks first
     foreach (var tryCatch in method.GetSelfAndChildrenRecursive <ILTryCatchBlock>(tc => tc.FinallyBlock != null).Reverse())
     {
         ILLabel label = new ILLabel()
         {
             Name = "EndFinally_" + nextLabelIndex++
         };
         tryCatch.FinallyBlock.Body.Add(label);
         foreach (var block in tryCatch.FinallyBlock.GetSelfAndChildrenRecursive <ILBlock>())
         {
             for (int i = 0; i < block.Body.Count; i++)
             {
                 if (block.Body[i].Match(ILCode.Endfinally))
                 {
                     block.Body[i] = new ILExpression(ILCode.Br, label).WithILRanges(((ILExpression)block.Body[i]).ILRanges);
                 }
             }
         }
     }
 }
Esempio n. 8
0
        void RecombineVariables(ILBlock method)
        {
            // Recombine variables that were split when the ILAst was created
            // This ensures that a single IL variable is a single C# variable (gets assigned only one name)
            // The DeclareVariables transformation might then split up the C# variable again if it is used indendently in two separate scopes.
            Dictionary <VariableDefinition, ILVariable> dict = new Dictionary <VariableDefinition, ILVariable>();

            ReplaceVariables(
                method,
                delegate(ILVariable v) {
                if (v.OriginalVariable == null)
                {
                    return(v);
                }
                ILVariable combinedVariable;
                if (!dict.TryGetValue(v.OriginalVariable, out combinedVariable))
                {
                    dict.Add(v.OriginalVariable, v);
                    combinedVariable = v;
                }
                return(combinedVariable);
            });
        }
Esempio n. 9
0
        /// <summary>
        /// Looks at the enumerator's ctor and figures out which of the fields holds the state.
        /// </summary>
        void AnalyzeCtor()
        {
            ILBlock method = CreateILAst(enumeratorCtor);

            foreach (ILNode node in method.Body)
            {
                FieldReference field;
                ILExpression   instExpr;
                ILExpression   stExpr;
                ILVariable     arg;
                if (node.Match(ILCode.Stfld, out field, out instExpr, out stExpr) &&
                    instExpr.MatchThis() &&
                    stExpr.Match(ILCode.Ldloc, out arg) &&
                    arg.IsParameter && arg.OriginalParameter.Index == 0)
                {
                    stateField = GetFieldDefinition(field);
                }
            }
            if (stateField == null)
            {
                throw new SymbolicAnalysisFailedException();
            }
        }
Esempio n. 10
0
        public static void RunStep1(DecompilerContext context, ILBlock method)
        {
            if (!context.Settings.AsyncAwait)
            {
                return;                 // abort if async decompilation is disabled
            }
            var yrd = new AsyncDecompiler();

            yrd.context = context;
            if (!yrd.MatchTaskCreationPattern(method))
            {
                return;
            }
                        #if DEBUG
            if (Debugger.IsAttached)
            {
                yrd.Run();
            }
            else
            {
                                #endif
            try {
                yrd.Run();
            } catch (SymbolicAnalysisFailedException) {
                return;
            }
                                #if DEBUG
        }
                        #endif
            context.CurrentMethodIsAsync = true;

            method.Body.Clear();
            method.EntryGoto = null;
            method.Body.AddRange(yrd.newTopLevelBody);
            ILAstOptimizer.RemoveRedundantCode(method);
        }
Esempio n. 11
0
        void AnalyzeStateMachine(ILBlock block)
        {
            var body = block.Body;

            if (body.Count == 0)
            {
                throw new SymbolicAnalysisFailedException();
            }
            if (DetectDoFinallyBodies(body))
            {
                body.RemoveAt(0);
                if (body.Count == 0)
                {
                    throw new SymbolicAnalysisFailedException();
                }
            }
            StateRangeAnalysis rangeAnalysis = new StateRangeAnalysis(body[0], StateRangeAnalysisMode.AsyncMoveNext, stateField);
            int bodyLength = block.Body.Count;
            int pos        = rangeAnalysis.AssignStateRanges(body, bodyLength);

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

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

            newTopLevelBody = ConvertBody(body, pos, bodyLength, labelStateRangeMapping);
            newTopLevelBody.Insert(0, MakeGoTo(labelStateRangeMapping, initialState));
            newTopLevelBody.Add(setResultAndExitLabel);
            if (methodType == AsyncMethodType.TaskOfT)
            {
                newTopLevelBody.Add(new ILExpression(ILCode.Ret, null, resultExpr));
            }
            else
            {
                newTopLevelBody.Add(new ILExpression(ILCode.Ret, null));
            }
        }
Esempio n. 12
0
        ILBlock ConvertFinallyBlock(MethodDefinition finallyMethod)
        {
            ILBlock block = CreateILAst(finallyMethod);
            // Get rid of assignment to state
            FieldReference      stfld;
            List <ILExpression> args;

            if (block.Body.Count > 0 && block.Body[0].Match(ILCode.Stfld, out stfld, out args))
            {
                if (GetFieldDefinition(stfld) == stateField && args[0].MatchThis())
                {
                    block.Body.RemoveAt(0);
                }
            }
            // Convert ret to endfinally
            foreach (ILExpression expr in block.GetSelfAndChildrenRecursive <ILExpression>())
            {
                if (expr.Code == ILCode.Ret)
                {
                    expr.Code = ILCode.Endfinally;
                }
            }
            return(block);
        }
Esempio n. 13
0
        void ResolveIEnumerableIEnumeratorFieldMapping()
        {
            MethodDefinition getEnumeratorMethod = enumeratorType.Methods.FirstOrDefault(
                m => m.Name.StartsWith("System.Collections.Generic.IEnumerable", StringComparison.Ordinal) &&
                m.Name.EndsWith(".GetEnumerator", StringComparison.Ordinal));

            if (getEnumeratorMethod == null)
            {
                return;                 // no mappings (maybe it's just an IEnumerator implementation?)
            }
            ILBlock method = CreateILAst(getEnumeratorMethod);

            foreach (ILNode node in method.Body)
            {
                FieldReference stField;
                ILExpression   stToObj;
                ILExpression   stExpr;
                FieldReference ldField;
                ILExpression   ldFromObj;
                if (node.Match(ILCode.Stfld, out stField, out stToObj, out stExpr) &&
                    stExpr.Match(ILCode.Ldfld, out ldField, out ldFromObj) &&
                    ldFromObj.MatchThis())
                {
                    FieldDefinition storedField = GetFieldDefinition(stField);
                    FieldDefinition loadedField = GetFieldDefinition(ldField);
                    if (storedField != null && loadedField != null)
                    {
                        ILVariable mappedParameter;
                        if (fieldToParameterMap.TryGetValue(loadedField, out mappedParameter))
                        {
                            fieldToParameterMap[storedField] = mappedParameter;
                        }
                    }
                }
            }
        }
Esempio n. 14
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);
        }
Esempio n. 15
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;
                    }
                }
            }
        }
Esempio n. 16
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;
        }
Esempio n. 17
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);
                            }
                        }
                    }
                }
            }
        }
Esempio n. 18
0
        bool MatchEnumeratorCreationPattern(ILBlock method)
        {
            if (method.Body.Count == 0)
            {
                return(false);
            }
            ILExpression newObj;

            if (method.Body.Count == 1)
            {
                // ret(newobj(...))
                if (method.Body[0].Match(ILCode.Ret, out newObj))
                {
                    return(MatchEnumeratorCreationNewObj(newObj, out enumeratorCtor));
                }
                else
                {
                    return(false);
                }
            }
            // stloc(var_1, newobj(..)
            ILVariable var1;

            if (!method.Body[0].Match(ILCode.Stloc, out var1, out newObj))
            {
                return(false);
            }
            if (!MatchEnumeratorCreationNewObj(newObj, out enumeratorCtor))
            {
                return(false);
            }

            int i;

            for (i = 1; i < method.Body.Count; i++)
            {
                // stfld(..., ldloc(var_1), ldloc(parameter))
                FieldReference storedField;
                ILExpression   ldloc, loadParameter;
                if (!method.Body[i].Match(ILCode.Stfld, out storedField, out ldloc, out loadParameter))
                {
                    break;
                }
                ILVariable loadedVar, loadedArg;
                if (!ldloc.Match(ILCode.Ldloc, out loadedVar) || !loadParameter.Match(ILCode.Ldloc, out loadedArg))
                {
                    return(false);
                }
                storedField = GetFieldDefinition(storedField);
                if (loadedVar != var1 || storedField == null || !loadedArg.IsParameter)
                {
                    return(false);
                }
                fieldToParameterMap[(FieldDefinition)storedField] = loadedArg;
            }
            ILVariable   var2;
            ILExpression ldlocForStloc2;

            if (i < method.Body.Count && method.Body[i].Match(ILCode.Stloc, out var2, out ldlocForStloc2))
            {
                // stloc(var_2, ldloc(var_1))
                if (ldlocForStloc2.Code != ILCode.Ldloc || ldlocForStloc2.Operand != var1)
                {
                    return(false);
                }
                i++;
            }
            else
            {
                // the compiler might skip the above instruction in release builds; in that case, it directly returns stloc.Operand
                var2 = var1;
            }
            ILExpression retArg;

            if (i < method.Body.Count && method.Body[i].Match(ILCode.Ret, out retArg))
            {
                // ret(ldloc(var_2))
                if (retArg.Code == ILCode.Ldloc && retArg.Operand == var2)
                {
                    return(true);
                }
            }
            return(false);
        }
Esempio n. 19
0
        public static void RemoveRedundantCode(ILBlock method)
        {
            // Remove dead lables and nops
            HashSet <ILLabel> liveLabels = new HashSet <ILLabel>(method.GetSelfAndChildrenRecursive <ILExpression>(e => e.IsBranch()).SelectMany(e => e.GetBranchTargets()));

            foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>())
            {
                block.Body = block.Body.Where(n => !n.Match(ILCode.Nop) && !(n is ILLabel && !liveLabels.Contains((ILLabel)n))).ToList();
            }

            // Remove redundant continue
            foreach (ILWhileLoop loop in method.GetSelfAndChildrenRecursive <ILWhileLoop>())
            {
                var body = loop.BodyBlock.Body;
                if (body.Count > 0 && body.Last().Match(ILCode.LoopContinue))
                {
                    body.RemoveAt(body.Count - 1);
                }
            }

            // Remove redundant break at the end of case
            // Remove redundant case blocks altogether
            foreach (ILSwitch ilSwitch in method.GetSelfAndChildrenRecursive <ILSwitch>())
            {
                foreach (ILBlock ilCase in ilSwitch.CaseBlocks)
                {
                    Debug.Assert(ilCase.EntryGoto == null);

                    int count = ilCase.Body.Count;
                    if (count >= 2)
                    {
                        if (ilCase.Body[count - 2].IsUnconditionalControlFlow() &&
                            ilCase.Body[count - 1].Match(ILCode.LoopOrSwitchBreak))
                        {
                            ilCase.Body.RemoveAt(count - 1);
                        }
                    }
                }

                var defaultCase = ilSwitch.CaseBlocks.SingleOrDefault(cb => cb.Values == null);
                // If there is no default block, remove empty case blocks
                if (defaultCase == null || (defaultCase.Body.Count == 1 && defaultCase.Body.Single().Match(ILCode.LoopOrSwitchBreak)))
                {
                    ilSwitch.CaseBlocks.RemoveAll(b => b.Body.Count == 1 && b.Body.Single().Match(ILCode.LoopOrSwitchBreak));
                }
            }

            // Remove redundant return at the end of method
            if (method.Body.Count > 0 && method.Body.Last().Match(ILCode.Ret) && ((ILExpression)method.Body.Last()).Arguments.Count == 0)
            {
                method.Body.RemoveAt(method.Body.Count - 1);
            }

            // Remove unreachable return statements
            bool modified = false;

            foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>())
            {
                for (int i = 0; i < block.Body.Count - 1;)
                {
                    if (block.Body[i].IsUnconditionalControlFlow() && block.Body[i + 1].Match(ILCode.Ret))
                    {
                        modified = true;
                        block.Body.RemoveAt(i + 1);
                    }
                    else
                    {
                        i++;
                    }
                }
            }
            if (modified)
            {
                // More removals might be possible
                new GotoRemoval().RemoveGotos(method);
            }
        }
Esempio n. 20
0
        public void Optimize(DecompilerContext context, ILBlock method, ILAstOptimizationStep abortBeforeStep = ILAstOptimizationStep.None)
        {
            this.context    = context;
            this.typeSystem = context.CurrentMethod.Module.TypeSystem;
            this.method     = method;

            if (abortBeforeStep == ILAstOptimizationStep.RemoveRedundantCode)
            {
                return;
            }
            RemoveRedundantCode(method);

            if (abortBeforeStep == ILAstOptimizationStep.ReduceBranchInstructionSet)
            {
                return;
            }
            foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>())
            {
                ReduceBranchInstructionSet(block);
            }
            // ReduceBranchInstructionSet runs before inlining because the non-aggressive inlining heuristic
            // looks at which type of instruction consumes the inlined variable.

            if (abortBeforeStep == ILAstOptimizationStep.InlineVariables)
            {
                return;
            }
            // Works better after simple goto removal because of the following debug pattern: stloc X; br Next; Next:; ldloc X
            ILInlining inlining1 = new ILInlining(method);

            inlining1.InlineAllVariables();

            if (abortBeforeStep == ILAstOptimizationStep.CopyPropagation)
            {
                return;
            }
            inlining1.CopyPropagation();

            if (abortBeforeStep == ILAstOptimizationStep.YieldReturn)
            {
                return;
            }
            YieldReturnDecompiler.Run(context, method);
            AsyncDecompiler.RunStep1(context, method);

            if (abortBeforeStep == ILAstOptimizationStep.AsyncAwait)
            {
                return;
            }
            AsyncDecompiler.RunStep2(context, method);

            if (abortBeforeStep == ILAstOptimizationStep.PropertyAccessInstructions)
            {
                return;
            }
            IntroducePropertyAccessInstructions(method);

            if (abortBeforeStep == ILAstOptimizationStep.SplitToMovableBlocks)
            {
                return;
            }
            foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>())
            {
                SplitToBasicBlocks(block);
            }

            if (abortBeforeStep == ILAstOptimizationStep.TypeInference)
            {
                return;
            }
            // Types are needed for the ternary operator optimization
            TypeAnalysis.Run(context, method);

            foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>())
            {
                bool modified;
                do
                {
                    modified = false;

                    if (abortBeforeStep == ILAstOptimizationStep.SimplifyShortCircuit)
                    {
                        return;
                    }
                    modified |= block.RunOptimization(new SimpleControlFlow(context, method).SimplifyShortCircuit);

                    if (abortBeforeStep == ILAstOptimizationStep.SimplifyTernaryOperator)
                    {
                        return;
                    }
                    modified |= block.RunOptimization(new SimpleControlFlow(context, method).SimplifyTernaryOperator);

                    if (abortBeforeStep == ILAstOptimizationStep.SimplifyNullCoalescing)
                    {
                        return;
                    }
                    modified |= block.RunOptimization(new SimpleControlFlow(context, method).SimplifyNullCoalescing);

                    if (abortBeforeStep == ILAstOptimizationStep.JoinBasicBlocks)
                    {
                        return;
                    }
                    modified |= block.RunOptimization(new SimpleControlFlow(context, method).JoinBasicBlocks);

                    if (abortBeforeStep == ILAstOptimizationStep.SimplifyLogicNot)
                    {
                        return;
                    }
                    modified |= block.RunOptimization(SimplifyLogicNot);

                    if (abortBeforeStep == ILAstOptimizationStep.SimplifyShiftOperators)
                    {
                        return;
                    }
                    modified |= block.RunOptimization(SimplifyShiftOperators);

                    if (abortBeforeStep == ILAstOptimizationStep.TypeConversionSimplifications)
                    {
                        return;
                    }
                    modified |= block.RunOptimization(TypeConversionSimplifications);

                    if (abortBeforeStep == ILAstOptimizationStep.SimplifyLdObjAndStObj)
                    {
                        return;
                    }
                    modified |= block.RunOptimization(SimplifyLdObjAndStObj);

                    if (abortBeforeStep == ILAstOptimizationStep.SimplifyCustomShortCircuit)
                    {
                        return;
                    }
                    modified |= block.RunOptimization(new SimpleControlFlow(context, method).SimplifyCustomShortCircuit);

                    if (abortBeforeStep == ILAstOptimizationStep.SimplifyLiftedOperators)
                    {
                        return;
                    }
                    modified |= block.RunOptimization(SimplifyLiftedOperators);

                    if (abortBeforeStep == ILAstOptimizationStep.TransformArrayInitializers)
                    {
                        return;
                    }
                    modified |= block.RunOptimization(TransformArrayInitializers);

                    if (abortBeforeStep == ILAstOptimizationStep.TransformMultidimensionalArrayInitializers)
                    {
                        return;
                    }
                    modified |= block.RunOptimization(TransformMultidimensionalArrayInitializers);

                    if (abortBeforeStep == ILAstOptimizationStep.TransformObjectInitializers)
                    {
                        return;
                    }
                    modified |= block.RunOptimization(TransformObjectInitializers);

                    if (abortBeforeStep == ILAstOptimizationStep.MakeAssignmentExpression)
                    {
                        return;
                    }
                    if (context.Settings.MakeAssignmentExpressions)
                    {
                        modified |= block.RunOptimization(MakeAssignmentExpression);
                    }
                    modified |= block.RunOptimization(MakeCompoundAssignments);

                    if (abortBeforeStep == ILAstOptimizationStep.IntroducePostIncrement)
                    {
                        return;
                    }
                    if (context.Settings.IntroduceIncrementAndDecrement)
                    {
                        modified |= block.RunOptimization(IntroducePostIncrement);
                    }

                    if (abortBeforeStep == ILAstOptimizationStep.InlineExpressionTreeParameterDeclarations)
                    {
                        return;
                    }
                    if (context.Settings.ExpressionTrees)
                    {
                        modified |= block.RunOptimization(InlineExpressionTreeParameterDeclarations);
                    }

                    if (abortBeforeStep == ILAstOptimizationStep.InlineVariables2)
                    {
                        return;
                    }
                    modified |= new ILInlining(method).InlineAllInBlock(block);
                    new ILInlining(method).CopyPropagation();
                } while(modified);
            }

            if (abortBeforeStep == ILAstOptimizationStep.FindLoops)
            {
                return;
            }
            foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>())
            {
                new LoopsAndConditions(context).FindLoops(block);
            }

            if (abortBeforeStep == ILAstOptimizationStep.FindConditions)
            {
                return;
            }
            foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>())
            {
                new LoopsAndConditions(context).FindConditions(block);
            }

            if (abortBeforeStep == ILAstOptimizationStep.FlattenNestedMovableBlocks)
            {
                return;
            }
            FlattenBasicBlocks(method);

            if (abortBeforeStep == ILAstOptimizationStep.RemoveEndFinally)
            {
                return;
            }
            RemoveEndFinally(method);

            if (abortBeforeStep == ILAstOptimizationStep.RemoveRedundantCode2)
            {
                return;
            }
            RemoveRedundantCode(method);

            if (abortBeforeStep == ILAstOptimizationStep.GotoRemoval)
            {
                return;
            }
            new GotoRemoval().RemoveGotos(method);

            if (abortBeforeStep == ILAstOptimizationStep.DuplicateReturns)
            {
                return;
            }
            DuplicateReturnStatements(method);

            if (abortBeforeStep == ILAstOptimizationStep.GotoRemoval2)
            {
                return;
            }
            new GotoRemoval().RemoveGotos(method);

            if (abortBeforeStep == ILAstOptimizationStep.ReduceIfNesting)
            {
                return;
            }
            ReduceIfNesting(method);

            if (abortBeforeStep == ILAstOptimizationStep.InlineVariables3)
            {
                return;
            }
            // The 2nd inlining pass is necessary because DuplicateReturns and the introduction of ternary operators
            // open up additional inlining possibilities.
            new ILInlining(method).InlineAllVariables();

            if (abortBeforeStep == ILAstOptimizationStep.CachedDelegateInitialization)
            {
                return;
            }
            if (context.Settings.AnonymousMethods)
            {
                foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>())
                {
                    for (int i = 0; i < block.Body.Count; i++)
                    {
                        // TODO: Move before loops
                        CachedDelegateInitializationWithField(block, ref i);
                        CachedDelegateInitializationWithLocal(block, ref i);
                    }
                }
            }

            if (abortBeforeStep == ILAstOptimizationStep.IntroduceFixedStatements)
            {
                return;
            }
            // we need post-order traversal, not pre-order, for "fixed" to work correctly
            foreach (ILBlock block in TreeTraversal.PostOrder <ILNode>(method, n => n.GetChildren()).OfType <ILBlock>())
            {
                for (int i = block.Body.Count - 1; i >= 0; i--)
                {
                    // TODO: Move before loops
                    if (i < block.Body.Count)
                    {
                        IntroduceFixedStatements(block.Body, i);
                    }
                }
            }

            if (abortBeforeStep == ILAstOptimizationStep.RecombineVariables)
            {
                return;
            }
            RecombineVariables(method);

            if (abortBeforeStep == ILAstOptimizationStep.TypeInference2)
            {
                return;
            }
            TypeAnalysis.Reset(method);
            TypeAnalysis.Run(context, method);

            if (abortBeforeStep == ILAstOptimizationStep.RemoveRedundantCode3)
            {
                return;
            }
            GotoRemoval.RemoveRedundantCode(method);

            // ReportUnassignedILRanges(method);
        }
Esempio n. 21
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());
        }
Esempio n. 22
0
 public ILInlining(ILBlock method)
 {
     this.method = method;
     AnalyzeMethod();
 }
Esempio n. 23
0
        bool MatchTaskCreationPattern(ILBlock method)
        {
            if (method.Body.Count < 5)
            {
                return(false);
            }
            // Check the second-to-last instruction (the start call) first, as we can get the most information from that
            MethodReference startMethod;
            ILExpression    loadStartTarget, loadStartArgument;

            // call(AsyncTaskMethodBuilder::Start, ldloca(builder), ldloca(stateMachine))
            if (!method.Body[method.Body.Count - 2].Match(ILCode.Call, out startMethod, out loadStartTarget, out loadStartArgument))
            {
                return(false);
            }
            if (startMethod.Name != "Start" || startMethod.DeclaringType == null || startMethod.DeclaringType.Namespace != "System.Runtime.CompilerServices")
            {
                return(false);
            }
            switch (startMethod.DeclaringType.Name)
            {
            case "AsyncTaskMethodBuilder`1":
                methodType = AsyncMethodType.TaskOfT;
                break;

            case "AsyncTaskMethodBuilder":
                methodType = AsyncMethodType.Task;
                break;

            case "AsyncVoidMethodBuilder":
                methodType = AsyncMethodType.Void;
                break;

            default:
                return(false);
            }
            ILVariable stateMachineVar, builderVar;

            if (!loadStartTarget.Match(ILCode.Ldloca, out builderVar))
            {
                return(false);
            }
            if (!loadStartArgument.Match(ILCode.Ldloca, out stateMachineVar))
            {
                return(false);
            }

            stateMachineStruct = stateMachineVar.Type.ResolveWithinSameModule();
            if (stateMachineStruct == null || !stateMachineStruct.IsValueType)
            {
                return(false);
            }
            moveNextMethod = stateMachineStruct.Methods.FirstOrDefault(f => f.Name == "MoveNext");
            if (moveNextMethod == null)
            {
                return(false);
            }

            // Check third-to-last instruction (copy of builder):
            // stloc(builder, ldfld(StateMachine::<>t__builder, ldloca(stateMachine)))
            ILExpression loadBuilderExpr;

            if (!method.Body[method.Body.Count - 3].MatchStloc(builderVar, out loadBuilderExpr))
            {
                return(false);
            }
            FieldReference builderFieldRef;
            ILExpression   loadStateMachineForBuilderExpr;

            if (!loadBuilderExpr.Match(ILCode.Ldfld, out builderFieldRef, out loadStateMachineForBuilderExpr))
            {
                return(false);
            }
            if (!loadStateMachineForBuilderExpr.MatchLdloca(stateMachineVar))
            {
                return(false);
            }
            builderField = builderFieldRef.ResolveWithinSameModule();
            if (builderField == null)
            {
                return(false);
            }

            // Check the last instruction (ret)
            if (methodType == AsyncMethodType.Void)
            {
                if (!method.Body[method.Body.Count - 1].Match(ILCode.Ret))
                {
                    return(false);
                }
            }
            else
            {
                // ret(call(AsyncTaskMethodBuilder::get_Task, ldflda(StateMachine::<>t__builder, ldloca(stateMachine))))
                ILExpression returnValue;
                if (!method.Body[method.Body.Count - 1].Match(ILCode.Ret, out returnValue))
                {
                    return(false);
                }
                MethodReference getTaskMethod;
                ILExpression    builderExpr;
                if (!returnValue.Match(ILCode.Call, out getTaskMethod, out builderExpr))
                {
                    return(false);
                }
                ILExpression   loadStateMachineForBuilderExpr2;
                FieldReference builderField2;
                if (!builderExpr.Match(ILCode.Ldflda, out builderField2, out loadStateMachineForBuilderExpr2))
                {
                    return(false);
                }
                if (builderField2.ResolveWithinSameModule() != builderField || !loadStateMachineForBuilderExpr2.MatchLdloca(stateMachineVar))
                {
                    return(false);
                }
            }

            // Check the last field assignment - this should be the state field
            ILExpression initialStateExpr;

            if (!MatchStFld(method.Body[method.Body.Count - 4], stateMachineVar, out stateField, out initialStateExpr))
            {
                return(false);
            }
            if (!initialStateExpr.Match(ILCode.Ldc_I4, out initialState))
            {
                return(false);
            }
            if (initialState != -1)
            {
                return(false);
            }

            // Check the second-to-last field assignment - this should be the builder field
            FieldDefinition builderField3;
            ILExpression    builderInitialization;

            if (!MatchStFld(method.Body[method.Body.Count - 5], stateMachineVar, out builderField3, out builderInitialization))
            {
                return(false);
            }
            MethodReference createMethodRef;

            if (builderField3 != builderField || !builderInitialization.Match(ILCode.Call, out createMethodRef))
            {
                return(false);
            }
            if (createMethodRef.Name != "Create")
            {
                return(false);
            }

            for (int i = 0; i < method.Body.Count - 5; i++)
            {
                FieldDefinition field;
                ILExpression    fieldInit;
                if (!MatchStFld(method.Body[i], stateMachineVar, out field, out fieldInit))
                {
                    return(false);
                }
                ILVariable v;
                if (!fieldInit.Match(ILCode.Ldloc, out v))
                {
                    return(false);
                }
                if (!v.IsParameter)
                {
                    return(false);
                }
                fieldToParameterMap[field] = v;
            }

            return(true);
        }