예제 #1
0
        bool SimplifyLiftedOperators(List<ILNode> body, ILExpression expr, int pos)
        {
            if (!new PatternMatcher(typeSystem).SimplifyLiftedOperators(expr)) return false;

            var inlining = new ILInlining(method);
            while (--pos >= 0 && inlining.InlineIfPossible(body, ref pos)) ;

            return true;
        }
예제 #2
0
        bool SimplifyLiftedOperators(List <ILNode> body, ILExpression expr, int pos)
        {
            if (!new PatternMatcher(typeSystem).SimplifyLiftedOperators(expr))
            {
                return(false);
            }

            var inlining = new ILInlining(method);

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

            return(true);
        }
예제 #3
0
        bool MakeAssignmentExpression(List<ILNode> body, ILExpression expr, int pos)
        {
            // exprVar = ...
            // stloc(v, exprVar)
            // ->
            // exprVar = stloc(v, ...))
            ILVariable exprVar;
            ILExpression initializer;
            if (!(expr.Match(ILCode.Stloc, out exprVar, out initializer) && exprVar.IsGenerated))
                return false;
            ILExpression nextExpr = body.ElementAtOrDefault(pos + 1) as ILExpression;
            ILVariable v;
            ILExpression stLocArg;
            if (nextExpr.Match(ILCode.Stloc, out v, out stLocArg) && stLocArg.MatchLdloc(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;
            } else if ((nextExpr.Code == ILCode.Stsfld || nextExpr.Code == ILCode.CallSetter || nextExpr.Code == ILCode.CallvirtSetter) && nextExpr.Arguments.Count == 1) {
                // exprVar = ...
                // stsfld(fld, exprVar)
                // ->
                // exprVar = stsfld(fld, ...))
                if (nextExpr.Arguments[0].MatchLdloc(exprVar)) {
                    body.RemoveAt(pos + 1); // remove stsfld
                    nextExpr.Arguments[0] = initializer;
                    ((ILExpression)body[pos]).Arguments[0] = nextExpr;
                    return true;
                }
            }
            return false;
        }
예제 #4
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;
            TypeReference       newObjType;
            bool                isValueType;
            MethodReference     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);
                    ctorArgs.RemoveAt(0);
                    newObjExpr = new ILExpression(ILCode.Newobj, ctor, ctorArgs);
                }
                else
                {
                    return(false);
                }
            }
            else
            {
                return(false);
            }
            if (newObjType.IsValueType != 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), 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
            }
            ILInlining inlining = new ILInlining(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] = initializer;
            }
            else
            {
                Debug.Assert(expr.Code == ILCode.Call);
                expr.Code    = ILCode.Stloc;
                expr.Operand = v;
                expr.Arguments.Clear();
                expr.Arguments.Add(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);
        }
예제 #5
0
        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 (!Ast.Transforms.DelegateConstruction.IsAnonymousMethod(context, anonymousMethod))
                return;

            ILNode followingNode = block.Body.ElementAtOrDefault(i + 1);
            if (followingNode != null && followingNode.GetSelfAndChildrenRecursive<ILExpression>().Count(
                e => e.Code == ILCode.Ldloc && (ILVariable)e.Operand == v) == 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.GetSelfAndChildrenRecursive<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);
            }
        }