/// <summary>
        /// Reduces the branch codes to just br and brtrue.
        /// Moves ILRanges to the branch argument
        /// </summary>
        void ReduceBranchInstructionSet(ILBlock block)
        {
            for (int i = 0; i < block.Body.Count; i++)
            {
                ILExpression expr = block.Body[i] as ILExpression;
                if (expr != null && expr.Prefixes == null)
                {
                    switch (expr.Code)
                    {
                    case ILCode.Switch:
                    case ILCode.Brtrue:
                        expr.Arguments.Single().ILRanges.AddRange(expr.ILRanges);
                        expr.ILRanges.Clear();
                        continue;

                    case ILCode.__Brfalse:  block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, expr.Arguments.Single())); break;

                    case ILCode.__Beq:      block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Ceq, null, expr.Arguments)); break;

                    case ILCode.__Bne_Un:   block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Ceq, null, expr.Arguments))); break;

                    case ILCode.__Bgt:      block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Cgt, null, expr.Arguments)); break;

                    case ILCode.__Bgt_Un:   block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Cgt_Un, null, expr.Arguments)); break;

                    case ILCode.__Ble:      block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Cgt, null, expr.Arguments))); break;

                    case ILCode.__Ble_Un:   block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Cgt_Un, null, expr.Arguments))); break;

                    case ILCode.__Blt:      block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Clt, null, expr.Arguments)); break;

                    case ILCode.__Blt_Un:   block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Clt_Un, null, expr.Arguments)); break;

                    case ILCode.__Bge:          block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Clt, null, expr.Arguments))); break;

                    case ILCode.__Bge_Un:   block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Clt_Un, null, expr.Arguments))); break;

                    default:
                        continue;
                    }
                    ((ILExpression)block.Body[i]).Arguments.Single().ILRanges.AddRange(expr.ILRanges);
                }
            }
        }
        /// <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. 3
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);
        }
        /// <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 YieldAnalysisFailedException();
            }
        }
        void ConstructExceptionTable()
        {
            disposeMethod = enumeratorType.Methods.FirstOrDefault(m => m.Name == "System.IDisposable.Dispose");
            ILBlock ilMethod = CreateILAst(disposeMethod);

            finallyMethodToStateInterval = new Dictionary <MethodDefinition, Interval>();

            InitStateRanges(ilMethod.Body[0]);
            AssignStateRanges(ilMethod.Body, ilMethod.Body.Count, forDispose: true);

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

                MethodDefinition mdef = GetMethodDefinition(call.Operand as MethodReference);
                if (mdef == null || finallyMethodToStateInterval.ContainsKey(mdef))
                {
                    throw new YieldAnalysisFailedException();
                }
                finallyMethodToStateInterval.Add(mdef, interval);
            }
            ranges = null;
        }
        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 (YieldAnalysisFailedException) {
                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();
        }
        /// <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 YieldAnalysisFailedException();
            }
        }
        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);
            });
        }
        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.EnumerateSelfAndChildrenRecursive().OfType <ILExpression>())
            {
                if (expr.Code == ILCode.Ret)
                {
                    expr.Code = ILCode.Endfinally;
                }
            }
            return(block);
        }
        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;
                        }
                    }
                }
            }
        }
        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);
        }
        /// <summary>
        /// Removes redundatant Br, Nop, Dup, Pop
        /// </summary>
        /// <param name="method"></param>
        void RemoveRedundantCode(ILBlock method)
        {
            Dictionary <ILLabel, int> labelRefCount = new Dictionary <ILLabel, int>();
            var targets =
                from e in method.GetSelfAndChildrenRecursive().OfType <ILExpression>()
                where e.IsBranch()
                from t in e.GetBranchTargets()
                select t;

            foreach (ILLabel target in targets)
            {
                labelRefCount[target] = labelRefCount.GetOrDefault(target) + 1;
            }

            foreach (ILBlock block in method.GetSelfAndChildrenRecursive().OfType <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
                    {
                        newBody.Add(body[i]);
                    }
                }
                block.Body = newBody;
            }

            // 'dup' removal
            foreach (ILExpression expr in method.GetSelfAndChildrenRecursive().OfType <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;
                    }
                }
            }
        }
        /// <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;
        }
        void DuplicateReturnStatements(ILBlock method)
        {
            Dictionary <ILLabel, ILNode> nextSibling = new Dictionary <ILLabel, ILNode>();

            // Build navigation data
            foreach (ILBlock block in method.GetSelfAndChildrenRecursive().OfType <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().OfType <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);
                            }
                        }
                    }
                }
            }
        }
        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().OfType <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);

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

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

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

            var controlFlow = new SimpleControlFlow(context, method);

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

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

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

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

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

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

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

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

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

                    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;
                    }
                    modified |= block.RunOptimization(MakeAssignmentExpression);
                    modified |= block.RunOptimization(MakeCompoundAssignments);

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

                    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().OfType <ILBlock>())
            {
                new LoopsAndConditions(context).FindLoops(block);
            }

            if (abortBeforeStep == ILAstOptimizationStep.FindConditions)
            {
                return;
            }
            foreach (ILBlock block in method.GetSelfAndChildrenRecursive().OfType <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;
            }
            foreach (ILBlock block in method.GetSelfAndChildrenRecursive().OfType <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);
        }
        void CachedDelegateInitializationWithLocal(ILBlock block, ref int i)
        {
            // if (logicnot(ldloc(v))) {
            //     stloc(v, newobj(Action::.ctor, ldloc(displayClass), ldftn(method)))
            // } else {
            // }
            // ...(..., ldloc(v), ...)

            ILCondition c = block.Body[i] as ILCondition;

            if (c == null || c.Condition == null && c.TrueBlock == null || c.FalseBlock == null)
            {
                return;
            }
            if (!(c.TrueBlock.Body.Count == 1 && c.FalseBlock.Body.Count == 0))
            {
                return;
            }
            if (!c.Condition.Match(ILCode.LogicNot))
            {
                return;
            }
            ILExpression condition = c.Condition.Arguments.Single() as ILExpression;

            if (condition == null || condition.Code != ILCode.Ldloc)
            {
                return;
            }
            ILVariable   v     = (ILVariable)condition.Operand;
            ILExpression stloc = c.TrueBlock.Body[0] as ILExpression;

            if (!(stloc != null && stloc.Code == ILCode.Stloc && (ILVariable)stloc.Operand == v))
            {
                return;
            }
            ILExpression newObj = stloc.Arguments[0];

            if (!(newObj.Code == ILCode.Newobj && newObj.Arguments.Count == 2))
            {
                return;
            }
            if (newObj.Arguments[0].Code != ILCode.Ldloc)
            {
                return;
            }
            if (newObj.Arguments[1].Code != ILCode.Ldftn)
            {
                return;
            }
            MethodDefinition anonymousMethod = ((MethodReference)newObj.Arguments[1].Operand).ResolveWithinSameModule();             // method is defined in current assembly

            if (!AstServices.Transforms.DelegateConstruction.IsAnonymousMethod(context, anonymousMethod))
            {
                return;
            }

            ILNode followingNode     = block.Body.ElementAtOrDefault(i + 1);
            int    ldlocOperandCount =
                followingNode
                .EnumerateSelfAndChildrenRecursive()
                .OfType <ILExpression>()
                .Count(
                    e =>
                    e.Code == ILCode.Ldloc &&
                    (ILVariable)e.Operand == v);

            if (followingNode != null && ldlocOperandCount == 1)
            {
                ILInlining inlining = new ILInlining(method);
                if (!(inlining.numLdloc.GetOrDefault(v) == 2 && inlining.numStloc.GetOrDefault(v) == 2 && inlining.numLdloca.GetOrDefault(v) == 0))
                {
                    return;
                }

                // Find the store instruction that initializes the local to null:
                foreach (ILBlock storeBlock in method.EnumerateSelfAndChildrenRecursive().OfType <ILBlock>())
                {
                    for (int j = 0; j < storeBlock.Body.Count; j++)
                    {
                        ILVariable   storedVar;
                        ILExpression storedExpr;
                        if (storeBlock.Body[j].Match(ILCode.Stloc, out storedVar, out storedExpr) && storedVar == v && storedExpr.Match(ILCode.Ldnull))
                        {
                            // Remove the instruction
                            storeBlock.Body.RemoveAt(j);
                            if (storeBlock == block && j < i)
                            {
                                i--;
                            }
                            break;
                        }
                    }
                }

                block.Body[i] = stloc;                 // remove the 'if (v==null)'
                inlining      = new ILInlining(method);
                inlining.InlineIfPossible(block.Body, ref i);
            }
        }
        /// <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. 18
0
 public ILInlining(ILBlock method)
 {
     this.method = method;
     AnalyzeMethod();
 }
        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);
        }
        public static void RemoveRedundantCode(ILBlock method)
        {
            // Remove dead lables and nops
            var liveLabels = new HashSet <ILLabel>(
                from e in method.EnumerateSelfAndChildrenRecursive().OfType <ILExpression>()
                where e.IsBranch()
                from t in e.GetBranchTargets()
                select t);

            foreach (ILBlock block in method.EnumerateSelfAndChildrenRecursive().OfType <ILBlock>())
            {
                var liveBlockNodes =
                    from n in block.Body
                    where !n.Match(ILCode.Nop) &&
                    !(n is ILLabel &&
                      !liveLabels.Contains((ILLabel)n))
                    select n;

                block.Body = liveBlockNodes.ToList();
            }

            // Remove redundant continue
            foreach (ILWhileLoop loop in method.EnumerateSelfAndChildrenRecursive().OfType <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.EnumerateSelfAndChildrenRecursive().OfType <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.EnumerateSelfAndChildrenRecursive().OfType <ILBlock>().ToList())
            {
                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);
            }
        }
        void CachedDelegateInitializationWithField(ILBlock block, ref int i)
        {
            // if (logicnot(ldsfld(field))) {
            //     stsfld(field, newobj(Action::.ctor, ldnull(), ldftn(method)))
            // } else {
            // }
            // ...(..., ldsfld(field), ...)

            ILCondition c = block.Body[i] as ILCondition;

            if (c == null || c.Condition == null && c.TrueBlock == null || c.FalseBlock == null)
            {
                return;
            }
            if (!(c.TrueBlock.Body.Count == 1 && c.FalseBlock.Body.Count == 0))
            {
                return;
            }
            if (!c.Condition.Match(ILCode.LogicNot))
            {
                return;
            }
            ILExpression condition = c.Condition.Arguments.Single() as ILExpression;

            if (condition == null || condition.Code != ILCode.Ldsfld)
            {
                return;
            }
            FieldDefinition field = ((FieldReference)condition.Operand).ResolveWithinSameModule();             // field is defined in current assembly

            if (field == null || !field.IsCompilerGeneratedOrIsInCompilerGeneratedClass())
            {
                return;
            }
            ILExpression stsfld = c.TrueBlock.Body[0] as ILExpression;

            if (!(stsfld != null && stsfld.Code == ILCode.Stsfld && ((FieldReference)stsfld.Operand).ResolveWithinSameModule() == field))
            {
                return;
            }
            ILExpression newObj = stsfld.Arguments[0];

            if (!(newObj.Code == ILCode.Newobj && newObj.Arguments.Count == 2))
            {
                return;
            }
            if (newObj.Arguments[0].Code != ILCode.Ldnull)
            {
                return;
            }
            if (newObj.Arguments[1].Code != ILCode.Ldftn)
            {
                return;
            }
            MethodDefinition anonymousMethod = ((MethodReference)newObj.Arguments[1].Operand).ResolveWithinSameModule();             // method is defined in current assembly

            if (!AstServices.Transforms.DelegateConstruction.IsAnonymousMethod(context, anonymousMethod))
            {
                return;
            }

            ILNode followingNode = block.Body.ElementAtOrDefault(i + 1);

            int ldfldResolvingWithinSameMethodCount =
                followingNode
                .EnumerateSelfAndChildrenRecursive()
                .OfType <ILExpression>()
                .Count(
                    e =>
                    e.Code == ILCode.Ldsfld &&
                    ((FieldReference)e.Operand).ResolveWithinSameModule() == field);

            if (followingNode != null && ldfldResolvingWithinSameMethodCount == 1)
            {
                foreach (ILExpression parent in followingNode.EnumerateSelfAndChildrenRecursive().OfType <ILExpression>())
                {
                    for (int j = 0; j < parent.Arguments.Count; j++)
                    {
                        if (parent.Arguments[j].Code == ILCode.Ldsfld && ((FieldReference)parent.Arguments[j].Operand).ResolveWithinSameModule() == field)
                        {
                            parent.Arguments[j] = newObj;
                            block.Body.RemoveAt(i);
                            i -= new ILInlining(method).InlineInto(block.Body, i, aggressive: false);
                            return;
                        }
                    }
                }
            }
        }