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); }
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)); body[pos].AddSelfAndChildrenRecursiveILRanges(newStloc.ILRanges); body[initArrayPos].AddSelfAndChildrenRecursiveILRanges(newStloc.ILRanges); body[pos] = newStloc; body.RemoveAt(initArrayPos); return(true); } } return(false); }