/// <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;
		}
Ejemplo n.º 2
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);
        }
Ejemplo n.º 3
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);
        }
		/// <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;
		}