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, new[] { 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, new[] { 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 int[] 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 = new ArrayType( arrayType.ElementType, from l in arrayLengths select new ArrayDimension(0, l)); 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; }
static bool AreSame (ArrayType a, ArrayType b) { if (a.Rank != b.Rank) return false; // TODO: dimensions return true; }