Example #1
0
        /// <summary>
        /// Inlines instructions before pos into block.Body[pos].
        /// </summary>
        /// <returns>The number of instructions that were inlined.</returns>
        public int InlineInto(ILBlockBase block, List <ILNode> body, int pos, bool aggressive)
        {
            if (pos >= body.Count)
            {
                return(0);
            }
            int count = 0;

            while (--pos >= 0)
            {
                ILExpression expr = body[pos] as ILExpression;
                if (expr == null || expr.Code != ILCode.Stloc)
                {
                    break;
                }
                if (InlineOneIfPossible(block, body, pos, aggressive))
                {
                    count++;
                }
                else
                {
                    break;
                }
            }
            return(count);
        }
Example #2
0
        public static void AddILRanges(ILBlockBase block, List <ILNode> body, int removedIndex, IEnumerable <ILRange> ilRanges)
        {
            var prev = removedIndex - 1 >= 0 ? body[removedIndex - 1] : null;
            var next = removedIndex + 1 < body.Count ? body[removedIndex + 1] : null;

            ILNode node = null;

            if (node == null && next is ILExpression)
            {
                node = next;
            }
            if (node == null && prev is ILExpression)
            {
                node = prev;
            }
            if (node == null && next is ILLabel)
            {
                node = next;
            }
            if (node == null && prev is ILLabel)
            {
                node = prev;
            }
            if (node == null)
            {
                node = next ?? prev;                    // Using next before prev should work better
            }
            AddILRangesToInstruction(node, prev, next, block, ilRanges);
        }
Example #3
0
        /// <summary>
        /// Adds the removed instruction's ILRanges to the next or previous instruction
        /// </summary>
        /// <param name="block">The owner block</param>
        /// <param name="body">Body</param>
        /// <param name="removedIndex">Index of removed instruction</param>
        /// <param name="numRemoved">Number of removed instructions</param>
        public static void AddILRanges(ILBlockBase block, List <ILNode> body, int removedIndex, int numRemoved)
        {
            var prev = removedIndex - 1 >= 0 ? body[removedIndex - 1] : null;
            var next = removedIndex + numRemoved < body.Count ? body[removedIndex + numRemoved] : null;

            ILNode node = null;

            if (node == null && next is ILExpression)
            {
                node = next;
            }
            if (node == null && prev is ILExpression)
            {
                node = prev;
            }
            if (node == null && next is ILLabel)
            {
                node = next;
            }
            if (node == null && prev is ILLabel)
            {
                node = prev;
            }
            if (node == null)
            {
                node = next ?? prev;                    // Using next before prev should work better
            }
            for (int i = 0; i < numRemoved; i++)
            {
                AddILRangesToInstruction(node, prev, next, block, body[removedIndex + i].GetSelfAndChildrenRecursiveILRanges());
            }
        }
Example #4
0
 /// <summary>
 /// Aggressively inlines the stloc instruction at block.Body[pos] into the next instruction, if possible.
 /// If inlining was possible; we will continue to inline (non-aggressively) into the the combined instruction.
 /// </summary>
 /// <remarks>
 /// After the operation, pos will point to the new combined instruction.
 /// </remarks>
 public bool InlineIfPossible(ILBlockBase block, List <ILNode> body, ref int pos)
 {
     if (InlineOneIfPossible(block, body, pos, true))
     {
         pos -= InlineInto(block, body, pos, false);
         return(true);
     }
     return(false);
 }
Example #5
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);
        }
Example #6
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);
            }
        }
Example #7
0
        bool SimplifyLiftedOperators(ILBlockBase block, List <ILNode> body, ILExpression expr, int pos)
        {
            if (!GetPatternMatcher(corLib).SimplifyLiftedOperators(expr))
            {
                return(false);
            }

            var inlining = GetILInlining(method);

            while (--pos >= 0 && inlining.InlineIfPossible(block, body, ref pos))
            {
                ;
            }

            return(true);
        }
Example #8
0
        public static void LabelMergeILRanges(ILBlockBase block, List <ILNode> newBody, int instrIndexToRemove)
        {
            var    body = block.Body;
            ILNode prevNode = null, nextNode = null;

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

            AddILRangesTryNextFirst(body[instrIndexToRemove], prevNode, nextNode, block);
        }
Example #9
0
        /// <summary>
        /// Inlines the stloc instruction at block.Body[pos] into the next instruction, if possible.
        /// </summary>
        public bool InlineOneIfPossible(ILBlockBase block, List <ILNode> body, int pos, bool aggressive)
        {
            ILVariable   v;
            ILExpression inlinedExpression;

            if (body[pos].Match(ILCode.Stloc, out v, out inlinedExpression) && !v.IsPinned)
            {
                if (InlineIfPossible(v, inlinedExpression, body.ElementAtOrDefault(pos + 1), aggressive))
                {
                    // Assign the ranges of the stloc instruction:
                    if (context.CalculateILRanges)
                    {
                        inlinedExpression.ILRanges.AddRange(body[pos].ILRanges);
                    }
                    // Remove the stloc instruction:
                    body.RemoveAt(pos);
                    return(true);
                }
                else if (numLdloc.GetOrDefault(v) == 0 && numLdloca.GetOrDefault(v) == 0)
                {
                    // The variable is never loaded
                    if (inlinedExpression.HasNoSideEffects())
                    {
                        // Remove completely
                        AnalyzeNode(body[pos], -1);
                        if (context.CalculateILRanges)
                        {
                            Utils.AddILRanges(block, body, pos);
                        }
                        body.RemoveAt(pos);
                        return(true);
                    }
                    else if (inlinedExpression.CanBeExpressionStatement() && v.GeneratedByDecompiler)
                    {
                        // Assign the ranges of the stloc instruction:
                        if (context.CalculateILRanges)
                        {
                            inlinedExpression.ILRanges.AddRange(body[pos].ILRanges);
                        }
                        // Remove the stloc, but keep the inner expression
                        body[pos] = inlinedExpression;
                        return(true);
                    }
                }
            }
            return(false);
        }
Example #10
0
 public static void AddILRangesTryPreviousFirst(ILNode prev, ILNode next, ILBlockBase block, IEnumerable <ILRange> ilRanges)
 {
     if (prev != null && prev.SafeToAddToEndILRanges)
     {
         prev.EndILRanges.AddRange(ilRanges);
     }
     else if (next != null)
     {
         next.ILRanges.AddRange(ilRanges);
     }
     else if (prev != null)
     {
         block.EndILRanges.AddRange(ilRanges);
     }
     else
     {
         block.ILRanges.AddRange(ilRanges);
     }
 }
Example #11
0
 public static void AddILRangesTryPreviousFirst(ILNode prev, ILNode next, ILBlockBase block, ILNode removed)
 {
     if (prev != null && prev.SafeToAddToEndILRanges)
     {
         removed.AddSelfAndChildrenRecursiveILRanges(prev.EndILRanges);
     }
     else if (next != null)
     {
         removed.AddSelfAndChildrenRecursiveILRanges(next.ILRanges);
     }
     else if (prev != null)
     {
         removed.AddSelfAndChildrenRecursiveILRanges(block.EndILRanges);
     }
     else
     {
         removed.AddSelfAndChildrenRecursiveILRanges(block.ILRanges);
     }
 }
Example #12
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);
        }
Example #13
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);
        }
Example #14
0
 public static void AddILRangesTryNextFirst(ILNode removed, ILNode prev, ILNode next, ILBlockBase block)
 {
     if (removed == null)
     {
         return;
     }
     AddILRangesTryNextFirst(prev, next, block, removed.GetSelfAndChildrenRecursiveILRanges());
 }
Example #15
0
 public static void AddILRangesToInstruction(ILNode nodeToAddTo, ILNode prev, ILNode next, ILBlockBase block, IEnumerable <ILRange> ilRanges)
 {
     Debug.Assert(nodeToAddTo == prev || nodeToAddTo == next || nodeToAddTo == block);
     if (nodeToAddTo != null)
     {
         if (nodeToAddTo == prev && prev.SafeToAddToEndILRanges)
         {
             prev.EndILRanges.AddRange(ilRanges);
             return;
         }
         else if (nodeToAddTo != null && nodeToAddTo == next)
         {
             next.ILRanges.AddRange(ilRanges);
             return;
         }
     }
     AddILRangesTryNextFirst(prev, next, block, ilRanges);
 }
Example #16
0
 public static void AddILRangesToInstruction(ILNode nodeToAddTo, ILNode prev, ILNode next, ILBlockBase block, ILNode removed)
 {
     Debug.Assert(nodeToAddTo == prev || nodeToAddTo == next || nodeToAddTo == block);
     if (nodeToAddTo != null)
     {
         if (nodeToAddTo == prev && prev.SafeToAddToEndILRanges)
         {
             removed.AddSelfAndChildrenRecursiveILRanges(prev.EndILRanges);
             return;
         }
         else if (nodeToAddTo != null && nodeToAddTo == next)
         {
             removed.AddSelfAndChildrenRecursiveILRanges(next.ILRanges);
             return;
         }
     }
     AddILRangesTryNextFirst(prev, next, block, removed);
 }
Example #17
0
 /// <summary>
 /// Adds the removed instruction's ILRanges to the next or previous instruction
 /// </summary>
 /// <param name="block">The owner block</param>
 /// <param name="body">Body</param>
 /// <param name="removedIndex">Index of removed instruction</param>
 public static void AddILRanges(ILBlockBase block, List <ILNode> body, int removedIndex)
 {
     AddILRanges(block, body, removedIndex, 1);
 }
Example #18
0
        public static void AddILRangesTryNextFirst(List <ILNode> newBody, List <ILNode> body, int removedIndex, ILBlockBase block)
        {
            ILNode prev = newBody.Count > 0 ? newBody[newBody.Count - 1] : null;
            ILNode next = removedIndex + 1 < body.Count ? body[removedIndex + 1] : null;

            AddILRangesTryNextFirst(body[removedIndex], prev, next, block);
        }
Example #19
0
 public static void AddILRangesTryNextFirst(ILNode removed, ILNode prev, ILNode next, ILBlockBase block)
 {
     if (removed == null)
     {
         return;
     }
     AddILRangesTryNextFirst(prev, next, block, removed);
 }