mirror of https://github.com/icsharpcode/ILSpy.git
				
				
			
			You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							543 lines
						
					
					
						
							21 KiB
						
					
					
				
			
		
		
	
	
							543 lines
						
					
					
						
							21 KiB
						
					
					
				// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team | 
						|
//  | 
						|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this | 
						|
// software and associated documentation files (the "Software"), to deal in the Software | 
						|
// without restriction, including without limitation the rights to use, copy, modify, merge, | 
						|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons | 
						|
// to whom the Software is furnished to do so, subject to the following conditions: | 
						|
//  | 
						|
// The above copyright notice and this permission notice shall be included in all copies or | 
						|
// substantial portions of the Software. | 
						|
//  | 
						|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, | 
						|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR | 
						|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE | 
						|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | 
						|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | 
						|
// DEALINGS IN THE SOFTWARE. | 
						|
 | 
						|
using System; | 
						|
using System.Collections.Generic; | 
						|
using System.Diagnostics; | 
						|
using System.Linq; | 
						|
using Mono.Cecil; | 
						|
 | 
						|
namespace ICSharpCode.Decompiler.ILAst | 
						|
{ | 
						|
	/// <summary> | 
						|
	/// IL AST transformation that introduces array, object and collection initializers. | 
						|
	/// </summary> | 
						|
	partial class ILAstOptimizer | 
						|
	{ | 
						|
		#region Array Initializers | 
						|
		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 && | 
						|
					    !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 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; | 
						|
		} | 
						|
 | 
						|
		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)) { | 
						|
					body[pos] = new ILExpression(ILCode.Stloc, v, new ILExpression(ILCode.InitArray, arrayType, newArr)); | 
						|
					body.RemoveAt(initArrayPos); | 
						|
					return true; | 
						|
				} | 
						|
			} | 
						|
			return false; | 
						|
		} | 
						|
 | 
						|
		bool ForwardScanInitializeArrayRuntimeHelper(List<ILNode> body, int pos, ILVariable array, TypeReference arrayType, int arrayLength, out ILExpression[] values, out int foundPos) | 
						|
		{ | 
						|
			ILVariable v2; | 
						|
			MethodReference methodRef; | 
						|
			ILExpression methodArg1; | 
						|
			ILExpression methodArg2; | 
						|
			FieldReference fieldRef; | 
						|
			if (body.ElementAtOrDefault(pos).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) && | 
						|
			    array == v2 && | 
						|
			    methodArg2.Match(ILCode.Ldtoken, out fieldRef)) | 
						|
			{ | 
						|
				FieldDefinition fieldDef = fieldRef.ResolveWithinSameModule(); | 
						|
				if (fieldDef != null && fieldDef.InitialValue != null) { | 
						|
					ILExpression[] newArr = new ILExpression[arrayLength]; | 
						|
					if (DecodeArrayInitializer(arrayType.GetElementType(), fieldDef.InitialValue, newArr)) | 
						|
					{ | 
						|
						values = newArr; | 
						|
						foundPos = pos; | 
						|
						return true; | 
						|
					} | 
						|
				} | 
						|
			} | 
						|
			values = null; | 
						|
			foundPos = -1; | 
						|
			return false; | 
						|
		} | 
						|
 | 
						|
		static bool DecodeArrayInitializer(TypeReference elementTypeRef, byte[] initialValue, ILExpression[] output) | 
						|
		{ | 
						|
			TypeCode elementType = TypeAnalysis.GetTypeCode(elementTypeRef); | 
						|
			switch (elementType) { | 
						|
				case TypeCode.Boolean: | 
						|
				case TypeCode.Byte: | 
						|
					return DecodeArrayInitializer(initialValue, output, elementType, (d, i) => (int)d[i]); | 
						|
				case TypeCode.SByte: | 
						|
					return DecodeArrayInitializer(initialValue, output, elementType, (d, i) => (int)unchecked((sbyte)d[i])); | 
						|
				case TypeCode.Int16: | 
						|
					return DecodeArrayInitializer(initialValue, output, elementType, (d, i) => (int)BitConverter.ToInt16(d, i)); | 
						|
				case TypeCode.Char: | 
						|
				case TypeCode.UInt16: | 
						|
					return DecodeArrayInitializer(initialValue, output, elementType, (d, i) => (int)BitConverter.ToUInt16(d, i)); | 
						|
				case TypeCode.Int32: | 
						|
				case TypeCode.UInt32: | 
						|
					return DecodeArrayInitializer(initialValue, output, elementType, BitConverter.ToInt32); | 
						|
				case TypeCode.Int64: | 
						|
				case TypeCode.UInt64: | 
						|
					return DecodeArrayInitializer(initialValue, output, elementType, BitConverter.ToInt64); | 
						|
				case TypeCode.Single: | 
						|
					return DecodeArrayInitializer(initialValue, output, elementType, BitConverter.ToSingle); | 
						|
				case TypeCode.Double: | 
						|
					return DecodeArrayInitializer(initialValue, output, elementType, BitConverter.ToDouble); | 
						|
				case TypeCode.Object: | 
						|
					var typeDef = elementTypeRef.ResolveWithinSameModule(); | 
						|
					if (typeDef != null && typeDef.IsEnum) | 
						|
						return DecodeArrayInitializer(typeDef.GetEnumUnderlyingType(), initialValue, output); | 
						|
 | 
						|
					return false; | 
						|
				default: | 
						|
					return false; | 
						|
			} | 
						|
		} | 
						|
 | 
						|
		static bool DecodeArrayInitializer<T>(byte[] initialValue, ILExpression[] output, TypeCode elementType, Func<byte[], int, T> decoder) | 
						|
		{ | 
						|
			int elementSize = ElementSizeOf(elementType); | 
						|
			if (initialValue.Length < (output.Length * elementSize)) | 
						|
				return false; | 
						|
 | 
						|
			ILCode code = LoadCodeFor(elementType); | 
						|
			for (int i = 0; i < output.Length; i++) | 
						|
				output[i] = new ILExpression(code, decoder(initialValue, i * elementSize)); | 
						|
 | 
						|
			return true; | 
						|
		} | 
						|
 | 
						|
		private static ILCode LoadCodeFor(TypeCode elementType) | 
						|
		{ | 
						|
			switch (elementType) { | 
						|
				case TypeCode.Boolean: | 
						|
				case TypeCode.Byte: | 
						|
				case TypeCode.SByte: | 
						|
				case TypeCode.Char: | 
						|
				case TypeCode.Int16: | 
						|
				case TypeCode.UInt16: | 
						|
				case TypeCode.Int32: | 
						|
				case TypeCode.UInt32: | 
						|
					return ILCode.Ldc_I4; | 
						|
				case TypeCode.Int64: | 
						|
				case TypeCode.UInt64: | 
						|
					return ILCode.Ldc_I8; | 
						|
				case TypeCode.Single: | 
						|
					return ILCode.Ldc_R4; | 
						|
				case TypeCode.Double: | 
						|
					return ILCode.Ldc_R8; | 
						|
				default: | 
						|
					throw new ArgumentOutOfRangeException("elementType");					 | 
						|
			} | 
						|
		} | 
						|
 | 
						|
		private static int ElementSizeOf(TypeCode elementType) | 
						|
		{ | 
						|
			switch (elementType) { | 
						|
				case TypeCode.Boolean: | 
						|
				case TypeCode.Byte: | 
						|
				case TypeCode.SByte: | 
						|
					return 1; | 
						|
				case TypeCode.Char: | 
						|
				case TypeCode.Int16: | 
						|
				case TypeCode.UInt16: | 
						|
					return 2; | 
						|
				case TypeCode.Int32: | 
						|
				case TypeCode.UInt32: | 
						|
				case TypeCode.Single: | 
						|
					return 4; | 
						|
				case TypeCode.Int64: | 
						|
				case TypeCode.UInt64: | 
						|
				case TypeCode.Double: | 
						|
					return 8; | 
						|
				default: | 
						|
					throw new ArgumentOutOfRangeException("elementType"); | 
						|
			} | 
						|
		} | 
						|
		#endregion | 
						|
 | 
						|
		/// <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> | 
						|
		/// Gets whether the type supports collection initializers. | 
						|
		/// </summary> | 
						|
		static bool IsCollectionType(TypeReference tr) | 
						|
		{ | 
						|
			if (tr == null) | 
						|
				return false; | 
						|
			TypeDefinition td = tr.Resolve(); | 
						|
			while (td != null) { | 
						|
				if (td.Interfaces.Any(intf => intf.Name == "IEnumerable" && intf.Namespace == "System.Collections")) | 
						|
					return true; | 
						|
				td = td.BaseType != null ? td.BaseType.Resolve() : null; | 
						|
			} | 
						|
			return false; | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Gets whether 'expr' represents a setter in an object initializer. | 
						|
		/// ('CallvirtSetter(Property, v, value)') | 
						|
		/// </summary> | 
						|
		static bool IsSetterInObjectInitializer(ILExpression expr) | 
						|
		{ | 
						|
			if (expr == null) | 
						|
				return false; | 
						|
			if (expr.Code == ILCode.CallvirtSetter || expr.Code == ILCode.CallSetter || expr.Code == ILCode.Stfld) { | 
						|
				return expr.Arguments.Count == 2; | 
						|
			} | 
						|
			return false; | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Gets whether 'expr' represents the invocation of an 'Add' method in a collection initializer. | 
						|
		/// </summary> | 
						|
		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; | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Parses an object initializer. | 
						|
		/// </summary> | 
						|
		/// <param name="body">ILAst block</param> | 
						|
		/// <param name="pos"> | 
						|
		/// Input: position of the instruction assigning to 'v'. | 
						|
		/// Output: first position after the object initializer | 
						|
		/// </param> | 
						|
		/// <param name="v">The variable that holds the object being initialized</param> | 
						|
		/// <param name="newObjExpr">The newobj instruction</param> | 
						|
		/// <returns>InitObject instruction</returns> | 
						|
		ILExpression ParseObjectInitializer(List<ILNode> body, ref int pos, ILVariable v, ILExpression newObjExpr, bool isCollection, bool isValueType) | 
						|
		{ | 
						|
			// Take care not to modify any existing ILExpressions in here. | 
						|
			// We just construct new ones around the old ones, any modifications must wait until the whole | 
						|
			// object/collection initializer was analyzed. | 
						|
			ILExpression objectInitializer = new ILExpression(isCollection ? ILCode.InitCollection : ILCode.InitObject, null, newObjExpr); | 
						|
			List<ILExpression> initializerStack = new List<ILExpression>(); | 
						|
			initializerStack.Add(objectInitializer); | 
						|
			while (++pos < body.Count) { | 
						|
				ILExpression nextExpr = body[pos] as ILExpression; | 
						|
				if (IsSetterInObjectInitializer(nextExpr)) { | 
						|
					if (!AdjustInitializerStack(initializerStack, nextExpr.Arguments[0], v, false, isValueType)) { | 
						|
						CleanupInitializerStackAfterFailedAdjustment(initializerStack); | 
						|
						break; | 
						|
					} | 
						|
					initializerStack[initializerStack.Count - 1].Arguments.Add(nextExpr); | 
						|
				} else if (IsAddMethodCall(nextExpr)) { | 
						|
					if (!AdjustInitializerStack(initializerStack, nextExpr.Arguments[0], v, true, isValueType)) { | 
						|
						CleanupInitializerStackAfterFailedAdjustment(initializerStack); | 
						|
						break; | 
						|
					} | 
						|
					initializerStack[initializerStack.Count - 1].Arguments.Add(nextExpr); | 
						|
				} else { | 
						|
					// can't match any more initializers: end of object initializer | 
						|
					break; | 
						|
				} | 
						|
			} | 
						|
			return objectInitializer; | 
						|
		} | 
						|
 | 
						|
		static bool AdjustInitializerStack(List<ILExpression> initializerStack, ILExpression argument, ILVariable v, bool isCollection, bool isValueType) | 
						|
		{ | 
						|
			// Argument is of the form 'getter(getter(...(v)))' | 
						|
			// Unpack it into a list of getters: | 
						|
			List<ILExpression> getters = new List<ILExpression>(); | 
						|
			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]; | 
						|
				MemberReference mr = (MemberReference)g.Operand; | 
						|
				TypeReference returnType; | 
						|
				if (mr is FieldReference) | 
						|
					returnType = TypeAnalysis.GetFieldType((FieldReference)mr); | 
						|
				else | 
						|
					returnType = TypeAnalysis.SubstituteTypeArgs(((MethodReference)mr).ReturnType, 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; | 
						|
				} | 
						|
			} | 
						|
		} | 
						|
 | 
						|
		static void CleanupInitializerStackAfterFailedAdjustment(List<ILExpression> initializerStack) | 
						|
		{ | 
						|
			// There might be empty nested initializers left over; so we'll remove those: | 
						|
			while (initializerStack.Count > 1 && initializerStack[initializerStack.Count - 1].Arguments.Count == 1) { | 
						|
				ILExpression parent = initializerStack[initializerStack.Count - 2]; | 
						|
				Debug.Assert(parent.Arguments.Last() == initializerStack[initializerStack.Count - 1]); | 
						|
				parent.Arguments.RemoveAt(parent.Arguments.Count - 1); | 
						|
				initializerStack.RemoveAt(initializerStack.Count - 1); | 
						|
			} | 
						|
		} | 
						|
 | 
						|
		static void ChangeFirstArgumentToInitializedObject(ILExpression initializer) | 
						|
		{ | 
						|
			// Go through all elements in the initializer (so skip the newobj-instr. at the start) | 
						|
			for (int i = 1; i < initializer.Arguments.Count; i++) { | 
						|
				ILExpression element = initializer.Arguments[i]; | 
						|
				if (element.Code == ILCode.InitCollection || element.Code == ILCode.InitObject) { | 
						|
					// nested collection/object initializer | 
						|
					ILExpression getCollection = element.Arguments[0]; | 
						|
					getCollection.Arguments[0] = new ILExpression(ILCode.InitializedObject, null); | 
						|
					ChangeFirstArgumentToInitializedObject(element); // handle the collection elements | 
						|
				} else { | 
						|
					element.Arguments[0] = new ILExpression(ILCode.InitializedObject, null); | 
						|
				} | 
						|
			} | 
						|
		} | 
						|
	} | 
						|
}
 | 
						|
 |