static ILExpression SimplifyLdObjAndStObj(ILExpression expr, ref bool modified)
        {
            if (expr.Code == ILCode.Initobj)
            {
                expr.Code = ILCode.Stobj;
                expr.Arguments.Add(new ILExpression(ILCode.DefaultValue, expr.Operand));
                modified = true;
            }
            ILExpression  arg, arg2;
            TypeReference type;
            ILCode?       newCode = null;

            if (expr.Match(ILCode.Stobj, out type, out arg, out arg2))
            {
                switch (arg.Code)
                {
                case ILCode.Ldelema: newCode = ILCode.Stelem_Any; break;

                case ILCode.Ldloca:  newCode = ILCode.Stloc; break;

                case ILCode.Ldflda:  newCode = ILCode.Stfld; break;

                case ILCode.Ldsflda: newCode = ILCode.Stsfld; break;
                }
            }
            else if (expr.Match(ILCode.Ldobj, out type, out arg))
            {
                switch (arg.Code)
                {
                case ILCode.Ldelema: newCode = ILCode.Ldelem_Any; break;

                case ILCode.Ldloca:  newCode = ILCode.Ldloc; break;

                case ILCode.Ldflda:  newCode = ILCode.Ldfld; break;

                case ILCode.Ldsflda: newCode = ILCode.Ldsfld; break;
                }
            }
            if (newCode != null)
            {
                arg.Code = newCode.Value;
                if (expr.Code == ILCode.Stobj)
                {
                    arg.InferredType = expr.InferredType;
                    arg.ExpectedType = expr.ExpectedType;
                    arg.Arguments.Add(arg2);
                }
                arg.ILRanges.AddRange(expr.ILRanges);
                modified = true;
                return(arg);
            }
            else
            {
                return(expr);
            }
        }
Beispiel #2
0
		bool MatchLogicNot(ILExpression expr, out ILExpression arg)
		{
			ILExpression loadZero;
			object unused;
			if (expr.Match(ILCode.Ceq, out unused, out arg, out loadZero)) {
				int num;
				return loadZero.Match(ILCode.Ldc_I4, out num) && num == 0;
			}
			return expr.Match(ILCode.LogicNot, out arg);
		}
Beispiel #3
0
        static bool SimplifyLdObjAndStObj(List <ILNode> body, ILExpression expr, int pos)
        {
            bool modified = false;

            if (expr.Code == ILCode.Initobj)
            {
                expr.Code = ILCode.Stobj;
                expr.Arguments.Add(new ILExpression(ILCode.DefaultValue, expr.Operand));
                modified = true;
            }
            ILExpression  arg, arg2;
            TypeReference type;
            ILCode?       newCode = null;

            if (expr.Match(ILCode.Stobj, out type, out arg, out arg2))
            {
                switch (arg.Code)
                {
                case ILCode.Ldelema: newCode = ILCode.Stelem_Any; break;

                case ILCode.Ldloca:  newCode = ILCode.Stloc; break;

                case ILCode.Ldflda:  newCode = ILCode.Stfld; break;

                case ILCode.Ldsflda: newCode = ILCode.Stsfld; break;
                }
            }
            else if (expr.Match(ILCode.Ldobj, out type, out arg))
            {
                switch (arg.Code)
                {
                case ILCode.Ldelema: newCode = ILCode.Ldelem_Any; break;

                case ILCode.Ldloca:  newCode = ILCode.Ldloc; break;

                case ILCode.Ldflda:  newCode = ILCode.Ldfld; break;

                case ILCode.Ldsflda: newCode = ILCode.Ldsfld; break;
                }
            }
            if (newCode != null)
            {
                arg.Code = newCode.Value;
                if (expr.Code == ILCode.Stobj)
                {
                    arg.Arguments.Add(arg2);
                }
                arg.ILRanges.AddRange(expr.ILRanges);
                body[pos] = arg;
                modified  = true;
            }
            return(modified);
        }
        /// <summary>
        /// Gets whether 'expr' represents the invocation of an 'Add' method in a collection initializer.
        /// </summary>
        private static bool IsAddMethodCall(ILExpression expr)
        {
            MethodReference     addMethod;
            List <ILExpression> args;

            if (expr.Match(ILCode.Callvirt, out addMethod, out args) || expr.Match(ILCode.Call, out addMethod, out args))
            {
                if (addMethod.Name == "Add" && addMethod.HasThis)
                {
                    return(args.Count >= 2);
                }
            }
            return(false);
        }
Beispiel #5
0
        /// <summary>
        /// Gets whether 'expr' represents the invocation of an 'Add' method in a collection initializer.
        /// </summary>
        static bool IsAddMethodCall(ILExpression expr)
        {
            IMethod             addMethod;
            List <ILExpression> args;

            if (expr.Match(ILCode.Callvirt, out addMethod, out args) || expr.Match(ILCode.Call, out addMethod, out args))
            {
                if (addMethod.Name == "Add" && addMethod.MethodSig != null && addMethod.MethodSig.HasThis)
                {
                    return(args.Count >= 2);
                }
            }
            return(false);
        }
 private ILExpression MakeLeftAssociativeShortCircuit(ILCode code, ILExpression left, ILExpression right)
 {
     // Assuming that the inputs are already left associative
     if (right.Match(code))
     {
         // Find the leftmost logical expression
         ILExpression current = right;
         while (current.Arguments[0].Match(code))
         {
             current = current.Arguments[0];
         }
         current.Arguments[0] = new ILExpression(code, null, left, current.Arguments[0])
         {
             InferredType = typeSystem.Boolean
         };
         return(right);
     }
     else
     {
         return(new ILExpression(code, null, left, right)
         {
             InferredType = typeSystem.Boolean
         });
     }
 }
Beispiel #7
0
 ILExpression MakeLeftAssociativeShortCircuit(ILCode code, ILExpression left, ILExpression right)
 {
     // Assuming that the inputs are already left associative
     if (right.Match(code))
     {
         // Find the leftmost logical expression
         ILExpression current = right;
         while (current.Arguments[0].Match(code))
         {
             current = current.Arguments[0];
         }
         current.Arguments[0].AddSelfAndChildrenRecursiveILRanges(current.ILRanges);
         current.Arguments[0] = new ILExpression(code, null, left, current.Arguments[0])
         {
             InferredType = corLib.Boolean
         };
         return(right);
     }
     else
     {
         return(new ILExpression(code, null, left, right)
         {
             InferredType = corLib.Boolean
         });
     }
 }
Beispiel #8
0
		bool IsBuilderFieldOnThis(ILExpression builderExpr)
		{
			// ldflda(StateMachine::<>t__builder, ldloc(this))
			IField fieldRef;
			ILExpression target;
			return builderExpr.Match(ILCode.Ldflda, out fieldRef, out target)
				&& fieldRef.ResolveFieldWithinSameModule() == builderField
				&& target.MatchThis();
		}
Beispiel #9
0
        ILExpression UnpackDoubleNegation(ILExpression expr)
        {
            ILExpression negated;

            if (expr.Match(ILCode.LogicNot, out negated) && negated.Match(ILCode.LogicNot, out negated))
            {
                return(negated);
            }
            else
            {
                return(expr);
            }
        }
        public static bool TransformCollectionInitializers(List <ILNode> body, ILExpression expr, int pos)
        {
            ILVariable          v, v2;
            ILExpression        newObjExpr;
            MethodReference     ctor;
            List <ILExpression> ctorArgs;

            if (expr.Match(ILCode.Stloc, out v, out newObjExpr) &&
                newObjExpr.Match(ILCode.Newobj, out ctor, out ctorArgs))
            {
                TypeDefinition td = ctor.DeclaringType.Resolve();
                if (td == null || !td.Interfaces.Any(intf => intf.Name == "IEnumerable" && intf.Namespace == "System.Collections"))
                {
                    return(false);
                }

                // This is a collection: we can convert Add() calls into a collection initializer
                ILExpression collectionInitializer = new ILExpression(ILCode.InitCollection, null, newObjExpr);
                bool         anyAdded = false;
                while (pos + 1 < body.Count)
                {
                    ILExpression        nextExpr = body[pos + 1] as ILExpression;
                    MethodReference     addMethod;
                    List <ILExpression> args;
                    if (nextExpr.Match(ILCode.Callvirt, out addMethod, out args) &&
                        addMethod.Name == "Add" &&
                        addMethod.HasThis &&
                        args.Count >= 2 &&
                        args[0].Match(ILCode.Ldloc, out v2) &&
                        v == v2)
                    {
                        nextExpr.Code = ILCode.InitCollectionAddMethod;
                        nextExpr.Arguments.RemoveAt(0);
                        collectionInitializer.Arguments.Add(nextExpr);
                        body.RemoveAt(pos + 1);
                        anyAdded = true;
                    }
                    else
                    {
                        break;
                    }
                }
                // ensure we added at least one additional arg to the collection initializer:
                if (anyAdded)
                {
                    expr.Arguments[0] = collectionInitializer;
                    return(true);
                }
            }
            return(false);
        }
        bool MatchFixedArrayInitializerCondition(ILExpression condition, out ILExpression initValue)
        {
            ILExpression logicAnd;
            ILVariable   arrayVar;

            if (condition.Match(ILCode.LogicNot, out logicAnd) && logicAnd.Code == ILCode.LogicAnd)
            {
                initValue = UnpackDoubleNegation(logicAnd.Arguments[0]);
                ILExpression arrayVarInitializer;
                if (initValue.Match(ILCode.Ldloc, out arrayVar) ||
                    initValue.Match(ILCode.Stloc, out arrayVar, out arrayVarInitializer))
                {
                    ILExpression arrayLength = logicAnd.Arguments[1];
                    if (arrayLength.Code == ILCode.Conv_I4)
                    {
                        arrayLength = arrayLength.Arguments[0];
                    }
                    return(arrayLength.Code == ILCode.Ldlen && arrayLength.Arguments[0].MatchLdloc(arrayVar));
                }
            }
            initValue = null;
            return(false);
        }
Beispiel #12
0
        public static void NopMergeILRanges(ILBlockBase block, List <ILNode> newBody, int instrIndexToRemove)
        {
            var          body = block.Body;
            ILNode       prevNode = null, nextNode = null;
            ILExpression prev = null, next = null;

            if (newBody.Count > 0)
            {
                prev = (prevNode = newBody[newBody.Count - 1]) as ILExpression;
            }
            if (instrIndexToRemove + 1 < body.Count)
            {
                next = (nextNode = body[instrIndexToRemove + 1]) as ILExpression;
            }

            ILNode node = null;

            if (prev != null && prev.Prefixes == null)
            {
                switch (prev.Code)
                {
                case ILCode.Call:
                case ILCode.CallGetter:
                case ILCode.Calli:
                case ILCode.CallSetter:
                case ILCode.Callvirt:
                case ILCode.CallvirtGetter:
                case ILCode.CallvirtSetter:
                    node = prev;
                    break;
                }
            }

            if (next != null && next.Prefixes == null)
            {
                if (next.Match(ILCode.Leave))
                {
                    node = next;
                }
            }

            if (node != null && node == prevNode)
            {
                AddILRangesTryPreviousFirst(body[instrIndexToRemove], prevNode, nextNode, block);
            }
            else
            {
                AddILRangesTryNextFirst(body[instrIndexToRemove], prevNode, nextNode, block);
            }
        }
Beispiel #13
0
        bool TransformMultidimensionalArrayInitializers(ILBlockBase block, List <ILNode> body, ILExpression expr, int pos)
        {
            ILVariable          v;
            ILExpression        newarrExpr;
            IMethod             ctor;
            List <ILExpression> ctorArgs;
            TypeSpec            arySpec;
            ArraySigBase        arrayType;

            if (expr.Match(ILCode.Stloc, out v, out newarrExpr) &&
                newarrExpr.Match(ILCode.Newobj, out ctor, out ctorArgs) &&
                (arySpec = (ctor.DeclaringType as TypeSpec)) != null &&
                (arrayType = arySpec.TypeSig.RemovePinnedAndModifiers() as ArraySigBase) != null &&
                arrayType.Rank == ctorArgs.Count)
            {
                // Clone the type, so we can muck about with the Dimensions
                var multAry      = new ArraySig(arrayType.Next, arrayType.Rank, new uint[arrayType.Rank], new int[arrayType.Rank]);
                var arrayLengths = new int[multAry.Rank];
                for (int i = 0; i < multAry.Rank; i++)
                {
                    if (!ctorArgs[i].Match(ILCode.Ldc_I4, out arrayLengths[i]))
                    {
                        return(false);
                    }
                    if (arrayLengths[i] <= 0)
                    {
                        return(false);
                    }
                    multAry.Sizes[i]       = (uint)(arrayLengths[i] + 1);
                    multAry.LowerBounds[i] = 0;
                }

                var            totalElements = arrayLengths.Aggregate(1, (t, l) => t * l);
                ILExpression[] newArr;
                int            initArrayPos;
                if (ForwardScanInitializeArrayRuntimeHelper(body, pos + 1, v, multAry, totalElements, out newArr, out initArrayPos))
                {
                    var newStloc = new ILExpression(ILCode.Stloc, v, new ILExpression(ILCode.InitArray, multAry.ToTypeDefOrRef(), newArr));
                    if (context.CalculateILRanges)
                    {
                        body[pos].AddSelfAndChildrenRecursiveILRanges(newStloc.ILRanges);
                        body[initArrayPos].AddSelfAndChildrenRecursiveILRanges(newStloc.ILRanges);
                    }
                    body[pos] = newStloc;
                    body.RemoveAt(initArrayPos);
                    return(true);
                }
            }
            return(false);
        }
Beispiel #14
0
        bool MakeAssignmentExpression(List <ILNode> body, ILExpression expr, int pos)
        {
            // exprVar = ...
            // stloc(v, exprVar)
            // ->
            // exprVar = stloc(v, ...))
            ILExpression nextExpr = body.ElementAtOrDefault(pos + 1) as ILExpression;
            ILVariable   exprVar;
            ILExpression initializer;
            ILVariable   v;
            ILExpression stLocArg;

            if (expr.Match(ILCode.Stloc, out exprVar, out initializer) &&
                exprVar.IsGenerated &&
                nextExpr.Match(ILCode.Stloc, out v, out stLocArg) &&
                stLocArg.Match(ILCode.Ldloc, exprVar))
            {
                ILExpression store2 = body.ElementAtOrDefault(pos + 2) as ILExpression;
                if (StoreCanBeConvertedToAssignment(store2, exprVar))
                {
                    // expr_44 = ...
                    // stloc(v1, expr_44)
                    // anystore(v2, expr_44)
                    // ->
                    // stloc(v1, anystore(v2, ...))
                    ILInlining inlining = new ILInlining(method);
                    if (inlining.numLdloc.GetOrDefault(exprVar) == 2 && inlining.numStloc.GetOrDefault(exprVar) == 1)
                    {
                        body.RemoveAt(pos + 2);                     // remove store2
                        body.RemoveAt(pos);                         // remove expr = ...
                        nextExpr.Arguments[0] = store2;
                        store2.Arguments[store2.Arguments.Count - 1] = initializer;

                        inlining.InlineIfPossible(body, ref pos);

                        return(true);
                    }
                }

                body.RemoveAt(pos + 1);                 // remove stloc
                nextExpr.Arguments[0] = initializer;
                ((ILExpression)body[pos]).Arguments[0] = nextExpr;
                return(true);
            }
            return(false);
        }
Beispiel #15
0
        static bool TransformDecimalCtorToConstant(List <ILNode> body, ILExpression expr, int pos)
        {
            MethodReference     r;
            List <ILExpression> args;

            if (expr.Match(ILCode.Newobj, out r, out args) &&
                r.DeclaringType.Namespace == "System" &&
                r.DeclaringType.Name == "Decimal")
            {
                if (args.Count == 1)
                {
                    int val;
                    if (args[0].Match(ILCode.Ldc_I4, out val))
                    {
                        expr.Code         = ILCode.Ldc_Decimal;
                        expr.Operand      = new decimal(val);
                        expr.InferredType = r.DeclaringType;
                        expr.Arguments.Clear();
                        return(true);
                    }
                }
                else if (args.Count == 5)
                {
                    int lo, mid, hi, isNegative, scale;
                    if (expr.Arguments[0].Match(ILCode.Ldc_I4, out lo) &&
                        expr.Arguments[1].Match(ILCode.Ldc_I4, out mid) &&
                        expr.Arguments[2].Match(ILCode.Ldc_I4, out hi) &&
                        expr.Arguments[3].Match(ILCode.Ldc_I4, out isNegative) &&
                        expr.Arguments[4].Match(ILCode.Ldc_I4, out scale))
                    {
                        expr.Code         = ILCode.Ldc_Decimal;
                        expr.Operand      = new decimal(lo, mid, hi, isNegative != 0, (byte)scale);
                        expr.InferredType = r.DeclaringType;
                        expr.Arguments.Clear();
                        return(true);
                    }
                }
            }
            bool modified = false;

            foreach (ILExpression arg in expr.Arguments)
            {
                modified |= TransformDecimalCtorToConstant(null, arg, -1);
            }
            return(modified);
        }
        bool TransformMultidimensionalArrayInitializers(List <ILNode> body, ILExpression expr, int pos)
        {
            ILVariable          v;
            ILExpression        newarrExpr;
            IMethod             ctor;
            List <ILExpression> ctorArgs;
            ArraySig            arrayType;

            if (expr.Match(ILCode.Stloc, out v, out newarrExpr) &&
                newarrExpr.Match(ILCode.Newobj, out ctor, out ctorArgs) &&
                (arrayType = ctor.DeclaringType.TryGetArraySig()) != null &&
                arrayType.Rank == ctorArgs.Count)
            {
                // Clone the type, so we can muck about with the Dimensions
                arrayType = new ArraySig(arrayType.Next, arrayType.Rank);
                var arrayLengths = new int[arrayType.Rank];
                for (int i = 0; i < arrayType.Rank; i++)
                {
                    if (!ctorArgs[i].Match(ILCode.Ldc_I4, out arrayLengths[i]))
                    {
                        return(false);
                    }
                    if (arrayLengths[i] <= 0)
                    {
                        return(false);
                    }
                    arrayType.LowerBounds.Add(0);
                    arrayType.Sizes.Add((uint)arrayLengths[i]);
                }

                var            totalElements = arrayLengths.Aggregate(1, (t, l) => t * l);
                ILExpression[] newArr;
                int            initArrayPos;
                if (ForwardScanInitializeArrayRuntimeHelper(body, pos + 1, v, arrayType, totalElements, out newArr, out initArrayPos))
                {
                    body[pos] = new ILExpression(ILCode.Stloc, v, new ILExpression(ILCode.InitArray, arrayType, newArr));
                    body.RemoveAt(initArrayPos);
                    return(true);
                }
            }
            return(false);
        }
Beispiel #17
0
        bool TransformMultidimensionalArrayInitializers(List <ILNode> body, ILExpression expr, int pos)
        {
            ILVariable          v;
            ILExpression        newarrExpr;
            MethodReference     ctor;
            List <ILExpression> ctorArgs;
            ArrayType           arrayType;

            if (expr.Match(ILCode.Stloc, out v, out newarrExpr) &&
                newarrExpr.Match(ILCode.Newobj, out ctor, out ctorArgs) &&
                (arrayType = (ctor.DeclaringType as ArrayType)) != null &&
                arrayType.Rank == ctorArgs.Count)
            {
                // Clone the type, so we can muck about with the Dimensions
                arrayType = new ArrayType(arrayType.ElementType, arrayType.Rank);
                var arrayLengths = new int[arrayType.Rank];
                for (int i = 0; i < arrayType.Rank; i++)
                {
                    if (!ctorArgs[i].Match(ILCode.Ldc_I4, out arrayLengths[i]))
                    {
                        return(false);
                    }
                    if (arrayLengths[i] <= 0)
                    {
                        return(false);
                    }
                    arrayType.Dimensions[i] = new ArrayDimension(0, arrayLengths[i]);
                }

                var            totalElements = arrayLengths.Aggregate(1, (t, l) => t * l);
                ILExpression[] newArr;
                int            initArrayPos;
                if (ForwardScanInitializeArrayRuntimeHelper(body, pos + 1, v, arrayType, totalElements, out newArr, out initArrayPos))
                {
                    var mdArr = Array.CreateInstance(typeof(ILExpression), arrayLengths);
                    body[pos] = new ILExpression(ILCode.Stloc, v, new ILExpression(ILCode.InitArray, arrayType, newArr));
                    body.RemoveAt(initArrayPos);
                    return(true);
                }
            }
            return(false);
        }
Beispiel #18
0
        static bool SimplifyLdcI4ConvI8(List <ILNode> body, ILExpression expr, int pos)
        {
            ILExpression ldc;
            int          val;

            if (expr.Match(ILCode.Conv_I8, out ldc) && ldc.Match(ILCode.Ldc_I4, out val))
            {
                expr.Code    = ILCode.Ldc_I8;
                expr.Operand = (long)val;
                expr.Arguments.Clear();
                return(true);
            }
            bool modified = false;

            foreach (ILExpression arg in expr.Arguments)
            {
                modified |= SimplifyLdcI4ConvI8(null, arg, -1);
            }
            return(modified);
        }
Beispiel #19
0
        bool IntroducePostIncrementForVariables(List <ILNode> body, ILExpression expr, int pos)
        {
            // Works for variables and static fields/properties

            // expr = ldloc(i)
            // stloc(i, add(expr, ldc.i4(1)))
            // ->
            // expr = postincrement(1, ldloca(i))
            ILVariable   exprVar;
            ILExpression exprInit;

            if (!(expr.Match(ILCode.Stloc, out exprVar, out exprInit) && exprVar.IsGenerated))
            {
                return(false);
            }

            //The next expression
            ILExpression nextExpr = body.ElementAtOrDefault(pos + 1) as ILExpression;

            if (nextExpr == null)
            {
                return(false);
            }

            ILCode loadInstruction   = exprInit.Code;
            ILCode storeInstruction  = nextExpr.Code;
            bool   recombineVariable = false;

            // We only recognise local variables, static fields, and static getters with no arguments
            switch (loadInstruction)
            {
            case ILCode.Ldloc:
                //Must be a matching store type
                if (storeInstruction != ILCode.Stloc)
                {
                    return(false);
                }
                ILVariable loadVar  = (ILVariable)exprInit.Operand;
                ILVariable storeVar = (ILVariable)nextExpr.Operand;
                if (loadVar != storeVar)
                {
                    if (loadVar.OriginalVariable != null && loadVar.OriginalVariable == storeVar.OriginalVariable)
                    {
                        recombineVariable = true;
                    }
                    else
                    {
                        return(false);
                    }
                }
                break;

            case ILCode.Ldsfld:
                if (storeInstruction != ILCode.Stsfld)
                {
                    return(false);
                }
                if (exprInit.Operand != nextExpr.Operand)
                {
                    return(false);
                }
                break;

            case ILCode.CallGetter:
                // non-static getters would have the 'this' argument
                if (exprInit.Arguments.Count != 0)
                {
                    return(false);
                }
                if (storeInstruction != ILCode.CallSetter)
                {
                    return(false);
                }
                if (!IsGetterSetterPair(exprInit.Operand, nextExpr.Operand))
                {
                    return(false);
                }
                break;

            default:
                return(false);
            }

            ILExpression addExpr = nextExpr.Arguments[0];

            int    incrementAmount;
            ILCode incrementCode = GetIncrementCode(addExpr, out incrementAmount);

            if (!(incrementAmount != 0 && addExpr.Arguments[0].MatchLdloc(exprVar)))
            {
                return(false);
            }

            if (recombineVariable)
            {
                // Split local variable, unsplit these two instances
                // replace nextExpr.Operand with exprInit.Operand
                ReplaceVariables(method, oldVar => oldVar == nextExpr.Operand ? (ILVariable)exprInit.Operand : oldVar);
            }

            switch (loadInstruction)
            {
            case ILCode.Ldloc:
                exprInit.Code = ILCode.Ldloca;
                break;

            case ILCode.Ldsfld:
                exprInit.Code = ILCode.Ldsflda;
                break;

            case ILCode.CallGetter:
                exprInit = new ILExpression(ILCode.AddressOf, null, exprInit);
                break;
            }
            expr.Arguments[0] = new ILExpression(incrementCode, incrementAmount, exprInit);
            body.RemoveAt(pos + 1);             // TODO ILRanges
            return(true);
        }
Beispiel #20
0
        bool TransformArrayInitializers(ILBlockBase block, List <ILNode> body, ILExpression expr, int pos)
        {
            ILVariable    v, v3;
            ILExpression  newarrExpr;
            ITypeDefOrRef elementType;
            ILExpression  lengthExpr;
            int           arrayLength;

            if (expr.Match(ILCode.Stloc, out v, out newarrExpr) &&
                newarrExpr.Match(ILCode.Newarr, out elementType, out lengthExpr) &&
                lengthExpr.Match(ILCode.Ldc_I4, out arrayLength) &&
                arrayLength > 0)
            {
                ILExpression[] newArr;
                int            initArrayPos;
                if (ForwardScanInitializeArrayRuntimeHelper(body, pos + 1, v, new SZArraySig(elementType.ToTypeSig()), arrayLength, out newArr, out initArrayPos))
                {
                    var arrayType = new ArraySig(elementType.ToTypeSig(), 1, new uint[1], new int[1]);
                    arrayType.Sizes[0] = (uint)(arrayLength + 1);
                    var newStloc = new ILExpression(ILCode.Stloc, v, new ILExpression(ILCode.InitArray, arrayType.ToTypeDefOrRef(), newArr));
                    body[pos].AddSelfAndChildrenRecursiveILRanges(newStloc.ILRanges);
                    body[initArrayPos].AddSelfAndChildrenRecursiveILRanges(newStloc.ILRanges);
                    body[pos] = newStloc;
                    body.RemoveAt(initArrayPos);
                }
                // Put in a limit so that we don't consume too much memory if the code allocates a huge array
                // and populates it extremely sparsly. However, 255 "null" elements in a row actually occur in the Mono C# compiler!
                const int           maxConsecutiveDefaultValueExpressions = 300;
                List <ILExpression> operands     = new List <ILExpression>();
                int numberOfInstructionsToRemove = 0;
                for (int j = pos + 1; j < body.Count; j++)
                {
                    ILExpression nextExpr = body[j] as ILExpression;
                    int          arrayPos;
                    if (nextExpr != null &&
                        nextExpr.Code.IsStoreToArray() &&
                        nextExpr.Arguments[0].Match(ILCode.Ldloc, out v3) &&
                        v == v3 &&
                        nextExpr.Arguments[1].Match(ILCode.Ldc_I4, out arrayPos) &&
                        arrayPos >= operands.Count &&
                        arrayPos <= operands.Count + maxConsecutiveDefaultValueExpressions &&
                        !nextExpr.Arguments[2].ContainsReferenceTo(v3))
                    {
                        while (operands.Count < arrayPos)
                        {
                            operands.Add(new ILExpression(ILCode.DefaultValue, elementType));
                        }
                        operands.Add(nextExpr.Arguments[2]);
                        numberOfInstructionsToRemove++;
                    }
                    else
                    {
                        break;
                    }
                }
                if (operands.Count == arrayLength)
                {
                    var arrayType = new ArraySig(elementType.ToTypeSig(), 1, new uint[1], new int[1]);
                    arrayType.Sizes[0] = (uint)(arrayLength + 1);
                    expr.Arguments[0]  = new ILExpression(ILCode.InitArray, arrayType.ToTypeDefOrRef(), operands);
                    newarrExpr.AddSelfAndChildrenRecursiveILRanges(expr.ILRanges);
                    for (int i = 0; i < numberOfInstructionsToRemove; i++)
                    {
                        body[pos + 1 + i].AddSelfAndChildrenRecursiveILRanges(expr.ILRanges);
                    }
                    body.RemoveRange(pos + 1, numberOfInstructionsToRemove);

                    GetILInlining(method).InlineIfPossible(block, body, ref pos);
                    return(true);
                }
            }
            return(false);
        }
Beispiel #21
0
        /// <summary>
        /// Handles both object and collection initializers.
        /// </summary>
        bool TransformObjectInitializers(ILBlockBase block, List <ILNode> body, ILExpression expr, int pos)
        {
            if (!context.Settings.ObjectOrCollectionInitializers)
            {
                return(false);
            }

            Debug.Assert(body[pos] == expr);             // should be called for top-level expressions only
            ILVariable          v;
            ILExpression        newObjExpr;
            ITypeDefOrRef       newObjType;
            bool                isValueType;
            IMethod             ctor;
            List <ILExpression> ctorArgs;

            if (expr.Match(ILCode.Stloc, out v, out newObjExpr))
            {
                if (newObjExpr.Match(ILCode.Newobj, out ctor, out ctorArgs))
                {
                    // v = newObj(ctor, ctorArgs)
                    newObjType  = ctor.DeclaringType;
                    isValueType = false;
                }
                else if (newObjExpr.Match(ILCode.DefaultValue, out newObjType))
                {
                    // v = defaultvalue(type)
                    isValueType = true;
                }
                else
                {
                    return(false);
                }
            }
            else if (expr.Match(ILCode.Call, out ctor, out ctorArgs))
            {
                // call(SomeStruct::.ctor, ldloca(v), remainingArgs)
                if (ctorArgs.Count > 0 && ctorArgs[0].Match(ILCode.Ldloca, out v))
                {
                    isValueType = true;
                    newObjType  = ctor.DeclaringType;
                    ctorArgs    = new List <ILExpression>(ctorArgs);
                    var old = ctorArgs[0];
                    ctorArgs.RemoveAt(0);
                    newObjExpr = new ILExpression(ILCode.Newobj, ctor, ctorArgs);
                    old.AddSelfAndChildrenRecursiveILRanges(newObjExpr.ILRanges);
                }
                else
                {
                    return(false);
                }
            }
            else
            {
                return(false);
            }
            if (DnlibExtensions.IsValueType(newObjType) != isValueType)
            {
                return(false);
            }

            int originalPos = pos;

            // don't use object initializer syntax for closures
            if (Ast.Transforms.DelegateConstruction.IsPotentialClosure(context, newObjType.ResolveWithinSameModule()))
            {
                return(false);
            }

            ILExpression initializer = ParseObjectInitializer(body, ref pos, v, newObjExpr, IsCollectionType(newObjType.ToTypeSig()), isValueType);

            if (initializer.Arguments.Count == 1)             // only newobj argument, no initializer elements
            {
                return(false);
            }
            int totalElementCount = pos - originalPos - 1;             // totalElementCount: includes elements from nested collections

            Debug.Assert(totalElementCount >= initializer.Arguments.Count - 1);

            // Verify that we can inline 'v' into the next instruction:

            if (pos >= body.Count)
            {
                return(false);                // reached end of block, but there should be another instruction which consumes the initialized object
            }
            var inlining = GetILInlining(method);

            if (isValueType)
            {
                // one ldloc for the use of the initialized object
                if (inlining.numLdloc.GetOrDefault(v) != 1)
                {
                    return(false);
                }
                // one ldloca for each initializer argument, and also for the ctor call (if it exists)
                if (inlining.numLdloca.GetOrDefault(v) != totalElementCount + (expr.Code == ILCode.Call ? 1 : 0))
                {
                    return(false);
                }
                // one stloc for the initial store (if no ctor call was used)
                if (inlining.numStloc.GetOrDefault(v) != (expr.Code == ILCode.Call ? 0 : 1))
                {
                    return(false);
                }
            }
            else
            {
                // one ldloc for each initializer argument, and another ldloc for the use of the initialized object
                if (inlining.numLdloc.GetOrDefault(v) != totalElementCount + 1)
                {
                    return(false);
                }
                if (!(inlining.numStloc.GetOrDefault(v) == 1 && inlining.numLdloca.GetOrDefault(v) == 0))
                {
                    return(false);
                }
            }
            ILExpression nextExpr = body[pos] as ILExpression;

            if (!inlining.CanInlineInto(nextExpr, v, initializer))
            {
                return(false);
            }

            if (expr.Code == ILCode.Stloc)
            {
                expr.Arguments[0].AddSelfAndChildrenRecursiveILRanges(initializer.ILRanges);
                expr.Arguments[0] = initializer;
            }
            else
            {
                Debug.Assert(expr.Code == ILCode.Call);
                expr.Code    = ILCode.Stloc;
                expr.Operand = v;
                foreach (var arg in expr.Arguments)
                {
                    arg.AddSelfAndChildrenRecursiveILRanges(initializer.ILRanges);
                }
                expr.Arguments.Clear();
                expr.Arguments.Add(initializer);
            }
            // remove all the instructions that were pulled into the initializer
            for (int i = originalPos + 1; i < pos; i++)
            {
                body[i].AddSelfAndChildrenRecursiveILRanges(initializer.ILRanges);
            }
            body.RemoveRange(originalPos + 1, pos - originalPos - 1);

            // now that we know that it's an object initializer, change all the first arguments to 'InitializedObject'
            ChangeFirstArgumentToInitializedObject(initializer);

            inlining = GetILInlining(method);
            inlining.InlineIfPossible(block, body, ref originalPos);

            return(true);
        }
Beispiel #22
0
        bool TransformArrayInitializers(List <ILNode> body, ILExpression expr, int pos)
        {
            ILVariable    v, v3;
            ILExpression  newarrExpr;
            TypeReference elementType;
            ILExpression  lengthExpr;
            int           arrayLength;

            if (expr.Match(ILCode.Stloc, out v, out newarrExpr) &&
                newarrExpr.Match(ILCode.Newarr, out elementType, out lengthExpr) &&
                lengthExpr.Match(ILCode.Ldc_I4, out arrayLength) &&
                arrayLength > 0)
            {
                ILExpression[] newArr;
                int            initArrayPos;
                if (ForwardScanInitializeArrayRuntimeHelper(body, pos + 1, v, elementType, arrayLength, out newArr, out initArrayPos))
                {
                    var arrayType = new ArrayType(elementType, 1);
                    arrayType.Dimensions[0] = new ArrayDimension(0, arrayLength);
                    body[pos] = new ILExpression(ILCode.Stloc, v, new ILExpression(ILCode.InitArray, arrayType, newArr));
                    body.RemoveAt(initArrayPos);
                }
                // Put in a limit so that we don't consume too much memory if the code allocates a huge array
                // and populates it extremely sparsly. However, 255 "null" elements in a row actually occur in the Mono C# compiler!
                const int           maxConsecutiveDefaultValueExpressions = 300;
                List <ILExpression> operands     = new List <ILExpression>();
                int numberOfInstructionsToRemove = 0;
                for (int j = pos + 1; j < body.Count; j++)
                {
                    ILExpression nextExpr = body[j] as ILExpression;
                    int          arrayPos;
                    if (nextExpr != null &&
                        nextExpr.Code.IsStoreToArray() &&
                        nextExpr.Arguments[0].Match(ILCode.Ldloc, out v3) &&
                        v == v3 &&
                        nextExpr.Arguments[1].Match(ILCode.Ldc_I4, out arrayPos) &&
                        arrayPos >= operands.Count &&
                        arrayPos <= operands.Count + maxConsecutiveDefaultValueExpressions)
                    {
                        while (operands.Count < arrayPos)
                        {
                            operands.Add(new ILExpression(ILCode.DefaultValue, elementType));
                        }
                        operands.Add(nextExpr.Arguments[2]);
                        numberOfInstructionsToRemove++;
                    }
                    else
                    {
                        break;
                    }
                }
                if (operands.Count == arrayLength)
                {
                    var arrayType = new ArrayType(elementType, 1);
                    arrayType.Dimensions[0] = new ArrayDimension(0, arrayLength);
                    expr.Arguments[0]       = new ILExpression(ILCode.InitArray, arrayType, operands);
                    body.RemoveRange(pos + 1, numberOfInstructionsToRemove);

                    new ILInlining(method).InlineIfPossible(body, ref pos);
                    return(true);
                }
            }
            return(false);
        }
Beispiel #23
0
        /// <summary>
        /// Handles both object and collection initializers.
        /// </summary>
        bool TransformObjectInitializers(List <ILNode> body, ILExpression expr, int pos)
        {
            if (!context.Settings.ObjectOrCollectionInitializers)
            {
                return(false);
            }

            Debug.Assert(body[pos] == expr);             // should be called for top-level expressions only
            ILVariable          v;
            ILExpression        newObjExpr;
            MethodReference     ctor;
            List <ILExpression> ctorArgs;

            // v = newObj(ctor, ctorArgs)
            if (!(expr.Match(ILCode.Stloc, out v, out newObjExpr) && newObjExpr.Match(ILCode.Newobj, out ctor, out ctorArgs)))
            {
                return(false);
            }
            int originalPos = pos;

            // don't use object initializer syntax for closures
            if (Ast.Transforms.DelegateConstruction.IsPotentialClosure(context, ctor.DeclaringType.ResolveWithinSameModule()))
            {
                return(false);
            }

            ILExpression initializer = ParseObjectInitializer(body, ref pos, v, newObjExpr, IsCollectionType(ctor.DeclaringType));

            if (initializer.Arguments.Count == 1)             // only newobj argument, no initializer elements
            {
                return(false);
            }
            int totalElementCount = pos - originalPos - 1;             // totalElementCount: includes elements from nested collections

            Debug.Assert(totalElementCount >= initializer.Arguments.Count - 1);

            // Verify that we can inline 'v' into the next instruction:

            if (pos >= body.Count)
            {
                return(false);                // reached end of block, but there should be another instruction which consumes the initialized object
            }
            ILInlining inlining = new ILInlining(method);

            // one ldloc for each initializer argument, and another ldloc for the use of the initialized object
            if (inlining.numLdloc.GetOrDefault(v) != totalElementCount + 1)
            {
                return(false);
            }
            if (!(inlining.numStloc.GetOrDefault(v) == 1 && inlining.numLdloca.GetOrDefault(v) == 0))
            {
                return(false);
            }
            ILExpression nextExpr = body[pos] as ILExpression;

            if (!inlining.CanInlineInto(nextExpr, v, initializer))
            {
                return(false);
            }

            expr.Arguments[0] = initializer;
            // remove all the instructions that were pulled into the initializer
            body.RemoveRange(originalPos + 1, pos - originalPos - 1);

            // now that we know that it's an object initializer, change all the first arguments to 'InitializedObject'
            ChangeFirstArgumentToInitializedObject(initializer);

            inlining = new ILInlining(method);
            inlining.InlineIfPossible(body, ref originalPos);

            return(true);
        }
Beispiel #24
0
        bool AdjustInitializerStack(List <ILExpression> initializerStack, List <ILExpression> getters, ILExpression argument, ILVariable v, bool isCollection, bool isValueType)
        {
            // Argument is of the form 'getter(getter(...(v)))'
            // Unpack it into a list of getters:
            getters.Clear();
            while (argument.Code == ILCode.CallvirtGetter || argument.Code == ILCode.CallGetter || argument.Code == ILCode.Ldfld)
            {
                getters.Add(argument);
                if (argument.Arguments.Count != 1)
                {
                    return(false);
                }
                argument = argument.Arguments[0];
            }
            // Ensure that the final argument is 'v'
            if (isValueType)
            {
                ILVariable loadedVar;
                if (!(argument.Match(ILCode.Ldloca, out loadedVar) && loadedVar == v))
                {
                    return(false);
                }
            }
            else
            {
                if (!argument.MatchLdloc(v))
                {
                    return(false);
                }
            }
            // Now compare the getters with those that are currently active on the initializer stack:
            int i;

            for (i = 1; i <= Math.Min(getters.Count, initializerStack.Count - 1); i++)
            {
                ILExpression g1 = initializerStack[i].Arguments[0];           // getter stored in initializer
                ILExpression g2 = getters[getters.Count - i];                 // matching getter from argument
                if (g1.Operand != g2.Operand)
                {
                    // operands differ, so we abort the comparison
                    break;
                }
            }
            // Remove all initializers from the stack that were not matched with one from the argument:
            initializerStack.RemoveRange(i, initializerStack.Count - i);
            // Now create new initializers for the remaining arguments:
            for (; i <= getters.Count; i++)
            {
                ILExpression g  = getters[getters.Count - i];
                IMemberRef   mr = g.Operand as IMemberRef;
                TypeSig      returnType;
                if (mr == null || mr.IsField)
                {
                    returnType = TypeAnalysis.GetFieldType((IField)mr);
                }
                else
                {
                    returnType = TypeAnalysis.SubstituteTypeArgs(((IMethod)mr).MethodSig.GetRetType(), method: (IMethod)mr);
                }

                ILExpression nestedInitializer = new ILExpression(
                    IsCollectionType(returnType) ? ILCode.InitCollection : ILCode.InitObject,
                    null, g);
                // add new initializer to its parent:
                ILExpression parentInitializer = initializerStack[initializerStack.Count - 1];
                if (parentInitializer.Code == ILCode.InitCollection)
                {
                    // can't add children to collection initializer
                    if (parentInitializer.Arguments.Count == 1)
                    {
                        // convert empty collection initializer to object initializer
                        parentInitializer.Code = ILCode.InitObject;
                    }
                    else
                    {
                        return(false);
                    }
                }
                parentInitializer.Arguments.Add(nestedInitializer);
                initializerStack.Add(nestedInitializer);
            }
            ILExpression lastInitializer = initializerStack[initializerStack.Count - 1];

            if (isCollection)
            {
                return(lastInitializer.Code == ILCode.InitCollection);
            }
            else
            {
                if (lastInitializer.Code == ILCode.InitCollection)
                {
                    if (lastInitializer.Arguments.Count == 1)
                    {
                        // convert empty collection initializer to object initializer
                        lastInitializer.Code = ILCode.InitObject;
                        return(true);
                    }
                    else
                    {
                        return(false);
                    }
                }
                else
                {
                    return(true);
                }
            }
        }
        public static bool TransformArrayInitializers(List <ILNode> body, ILExpression expr, int pos)
        {
            ILVariable    v, v2, v3;
            ILExpression  newarrExpr;
            TypeReference arrayType;
            ILExpression  lengthExpr;
            int           arrayLength;

            if (expr.Match(ILCode.Stloc, out v, out newarrExpr) &&
                newarrExpr.Match(ILCode.Newarr, out arrayType, out lengthExpr) &&
                lengthExpr.Match(ILCode.Ldc_I4, out arrayLength) &&
                arrayLength > 0)
            {
                MethodReference methodRef;
                ILExpression    methodArg1;
                ILExpression    methodArg2;
                FieldDefinition field;
                if (body.ElementAtOrDefault(pos + 1).Match(ILCode.Call, out methodRef, out methodArg1, out methodArg2) &&
                    methodRef.DeclaringType.FullName == "System.Runtime.CompilerServices.RuntimeHelpers" &&
                    methodRef.Name == "InitializeArray" &&
                    methodArg1.Match(ILCode.Ldloc, out v2) &&
                    v == v2 &&
                    methodArg2.Match(ILCode.Ldtoken, out field) &&
                    field != null && field.InitialValue != null)
                {
                    ILExpression[] newArr = new ILExpression[arrayLength];
                    if (DecodeArrayInitializer(TypeAnalysis.GetTypeCode(arrayType), field.InitialValue, newArr))
                    {
                        body[pos] = new ILExpression(ILCode.Stloc, v, new ILExpression(ILCode.InitArray, arrayType, newArr));
                        body.RemoveAt(pos + 1);
                        return(true);
                    }
                }

                const int           maxConsecutiveDefaultValueExpressions = 10;
                List <ILExpression> operands     = new List <ILExpression>();
                int numberOfInstructionsToRemove = 0;
                for (int j = pos + 1; j < body.Count; j++)
                {
                    ILExpression nextExpr = body[j] as ILExpression;
                    int          arrayPos;
                    if (nextExpr != null &&
                        nextExpr.Code.IsStoreToArray() &&
                        nextExpr.Arguments[0].Match(ILCode.Ldloc, out v3) &&
                        v == v3 &&
                        nextExpr.Arguments[1].Match(ILCode.Ldc_I4, out arrayPos) &&
                        arrayPos >= operands.Count &&
                        arrayPos <= operands.Count + maxConsecutiveDefaultValueExpressions)
                    {
                        while (operands.Count < arrayPos)
                        {
                            operands.Add(new ILExpression(ILCode.DefaultValue, arrayType));
                        }
                        operands.Add(nextExpr.Arguments[2]);
                        numberOfInstructionsToRemove++;
                    }
                    else
                    {
                        break;
                    }
                }
                if (operands.Count == arrayLength)
                {
                    expr.Arguments[0] = new ILExpression(ILCode.InitArray, arrayType, operands);
                    body.RemoveRange(pos + 1, numberOfInstructionsToRemove);
                    return(true);
                }
            }
            return(false);
        }
        static bool Step2(List <ILNode> body, ref int pos)
        {
            // stloc(CS$0$0001, callvirt(class System.Threading.Tasks.Task`1<bool>::GetAwaiter, awaiterExpr)
            // brtrue(IL_7C, call(valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter`1<bool>::get_IsCompleted, ldloca(CS$0$0001)))
            // await(ldloca(CS$0$0001))
            // ...
            // IL_7C:
            // arg_8B_0 = call(valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter`1<bool>::GetResult, ldloca(CS$0$0001))
            // initobj(valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter`1<bool>, ldloca(CS$0$0001))

            ILExpression loadAwaiter;
            ILVariable   awaiterVar;

            if (!body[pos].Match(ILCode.Await, out loadAwaiter))
            {
                return(false);
            }
            if (!loadAwaiter.Match(ILCode.Ldloca, out awaiterVar))
            {
                return(false);
            }

            ILVariable   stackVar;
            ILExpression stackExpr;

            while (pos >= 1 && body[pos - 1].Match(ILCode.Stloc, out stackVar, out stackExpr))
            {
                pos--;
            }

            // stloc(CS$0$0001, callvirt(class System.Threading.Tasks.Task`1<bool>::GetAwaiter, awaiterExpr)
            ILExpression getAwaiterCall;

            if (!(pos >= 2 && body[pos - 2].MatchStloc(awaiterVar, out getAwaiterCall)))
            {
                return(false);
            }
            MethodReference getAwaiterMethod;
            ILExpression    awaitedExpr;

            if (!(getAwaiterCall.Match(ILCode.Call, out getAwaiterMethod, out awaitedExpr) || getAwaiterCall.Match(ILCode.Callvirt, out getAwaiterMethod, out awaitedExpr)))
            {
                return(false);
            }

            if (awaitedExpr.Code == ILCode.AddressOf)
            {
                // remove 'AddressOf()' when calling GetAwaiter() on a value type
                awaitedExpr = awaitedExpr.Arguments[0];
            }

            // brtrue(IL_7C, call(valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter`1<bool>::get_IsCompleted, ldloca(CS$0$0001)))
            ILLabel      label;
            ILExpression getIsCompletedCall;

            if (!(pos >= 1 && body[pos - 1].Match(ILCode.Brtrue, out label, out getIsCompletedCall)))
            {
                return(false);
            }

            int labelPos = body.IndexOf(label);

            if (labelPos < pos)
            {
                return(false);
            }
            for (int i = pos + 1; i < labelPos; i++)
            {
                // validate that we aren't deleting any unexpected instructions -
                // between the await and the label, there should only be the stack, awaiter and state logic
                ILExpression expr = body[i] as ILExpression;
                if (expr == null)
                {
                    return(false);
                }
                switch (expr.Code)
                {
                case ILCode.Stloc:
                case ILCode.Initobj:
                case ILCode.Stfld:
                case ILCode.Await:
                    // e.g.
                    // stloc(CS$0$0001, ldfld(StateMachine::<>u__$awaitere, ldloc(this)))
                    // initobj(valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter`1<bool>, ldloca(CS$0$0002_66))
                    // stfld('<AwaitInLoopCondition>d__d'::<>u__$awaitere, ldloc(this), ldloc(CS$0$0002_66))
                    // stfld('<AwaitInLoopCondition>d__d'::<>1__state, ldloc(this), ldc.i4(-1))
                    break;

                default:
                    return(false);
                }
            }
            if (labelPos + 1 >= body.Count)
            {
                return(false);
            }
            ILExpression resultAssignment = body[labelPos + 1] as ILExpression;
            ILVariable   resultVar;
            ILExpression getResultCall;
            bool         isResultAssignment = resultAssignment.Match(ILCode.Stloc, out resultVar, out getResultCall);

            if (!isResultAssignment)
            {
                getResultCall = resultAssignment;
            }
            if (!(getResultCall.Operand is MethodReference && ((MethodReference)getResultCall.Operand).Name == "GetResult"))
            {
                return(false);
            }

            pos -= 2;             // also delete 'stloc', 'brtrue' and 'await'
            body.RemoveRange(pos, labelPos - pos);
            Debug.Assert(body[pos] == label);

            pos++;
            if (isResultAssignment)
            {
                Debug.Assert(body[pos] == resultAssignment);
                resultAssignment.Arguments[0] = new ILExpression(ILCode.Await, null, awaitedExpr);
            }
            else
            {
                body[pos] = new ILExpression(ILCode.Await, null, awaitedExpr);
            }

            // if the awaiter variable is cleared out in the next instruction, remove that instruction
            if (IsVariableReset(body.ElementAtOrDefault(pos + 1), awaiterVar))
            {
                body.RemoveAt(pos + 1);
            }

            return(true);
        }
        bool IntroducePostIncrementForVariables(List <ILNode> body, ILExpression expr, int pos)
        {
            // Works for variables and static fields/properties

            // expr = ldloc(i)
            // stloc(i, add(expr, ldc.i4(1)))
            // ->
            // expr = postincrement(1, ldloca(i))
            ILVariable   exprVar;
            ILExpression exprInit;

            if (!(expr.Match(ILCode.Stloc, out exprVar, out exprInit) && exprVar.IsGenerated))
            {
                return(false);
            }
            if (!(exprInit.Code == ILCode.Ldloc || exprInit.Code == ILCode.Ldsfld || (exprInit.Code == ILCode.CallGetter && exprInit.Arguments.Count == 0)))
            {
                return(false);
            }

            ILExpression nextExpr = body.ElementAtOrDefault(pos + 1) as ILExpression;

            if (nextExpr == null)
            {
                return(false);
            }
            if (exprInit.Code == ILCode.CallGetter)
            {
                if (!(nextExpr.Code == ILCode.CallSetter && IsGetterSetterPair(exprInit.Operand, nextExpr.Operand)))
                {
                    return(false);
                }
            }
            else
            {
                if (!(nextExpr.Code == (exprInit.Code == ILCode.Ldloc ? ILCode.Stloc : ILCode.Stsfld) && nextExpr.Operand == exprInit.Operand))
                {
                    return(false);
                }
            }
            ILExpression addExpr = nextExpr.Arguments[0];

            int    incrementAmount;
            ILCode incrementCode = GetIncrementCode(addExpr, out incrementAmount);

            if (!(incrementAmount != 0 && addExpr.Arguments[0].MatchLdloc(exprVar)))
            {
                return(false);
            }

            if (exprInit.Code == ILCode.Ldloc)
            {
                exprInit.Code = ILCode.Ldloca;
            }
            else if (exprInit.Code == ILCode.CallGetter)
            {
                exprInit = new ILExpression(ILCode.AddressOf, null, exprInit);
            }
            else
            {
                exprInit.Code = ILCode.Ldsflda;
            }
            expr.Arguments[0] = new ILExpression(incrementCode, incrementAmount, exprInit);
            body.RemoveAt(pos + 1);             // TODO ILRanges
            return(true);
        }