/// <summary> /// Inlines instructions before pos into block.Body[pos]. /// </summary> /// <returns>The number of instructions that were inlined.</returns> public int InlineInto(ILBlockBase block, List <ILNode> body, int pos, bool aggressive) { if (pos >= body.Count) { return(0); } int count = 0; while (--pos >= 0) { ILExpression expr = body[pos] as ILExpression; if (expr == null || expr.Code != ILCode.Stloc) { break; } if (InlineOneIfPossible(block, body, pos, aggressive)) { count++; } else { break; } } return(count); }
public static void AddILRanges(ILBlockBase block, List <ILNode> body, int removedIndex, IEnumerable <ILRange> ilRanges) { var prev = removedIndex - 1 >= 0 ? body[removedIndex - 1] : null; var next = removedIndex + 1 < body.Count ? body[removedIndex + 1] : null; ILNode node = null; if (node == null && next is ILExpression) { node = next; } if (node == null && prev is ILExpression) { node = prev; } if (node == null && next is ILLabel) { node = next; } if (node == null && prev is ILLabel) { node = prev; } if (node == null) { node = next ?? prev; // Using next before prev should work better } AddILRangesToInstruction(node, prev, next, block, ilRanges); }
/// <summary> /// Adds the removed instruction's ILRanges to the next or previous instruction /// </summary> /// <param name="block">The owner block</param> /// <param name="body">Body</param> /// <param name="removedIndex">Index of removed instruction</param> /// <param name="numRemoved">Number of removed instructions</param> public static void AddILRanges(ILBlockBase block, List <ILNode> body, int removedIndex, int numRemoved) { var prev = removedIndex - 1 >= 0 ? body[removedIndex - 1] : null; var next = removedIndex + numRemoved < body.Count ? body[removedIndex + numRemoved] : null; ILNode node = null; if (node == null && next is ILExpression) { node = next; } if (node == null && prev is ILExpression) { node = prev; } if (node == null && next is ILLabel) { node = next; } if (node == null && prev is ILLabel) { node = prev; } if (node == null) { node = next ?? prev; // Using next before prev should work better } for (int i = 0; i < numRemoved; i++) { AddILRangesToInstruction(node, prev, next, block, body[removedIndex + i].GetSelfAndChildrenRecursiveILRanges()); } }
/// <summary> /// Aggressively inlines the stloc instruction at block.Body[pos] into the next instruction, if possible. /// If inlining was possible; we will continue to inline (non-aggressively) into the the combined instruction. /// </summary> /// <remarks> /// After the operation, pos will point to the new combined instruction. /// </remarks> public bool InlineIfPossible(ILBlockBase block, List <ILNode> body, ref int pos) { if (InlineOneIfPossible(block, body, pos, true)) { pos -= InlineInto(block, body, pos, false); 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)); if (context.CalculateILRanges) { body[pos].AddSelfAndChildrenRecursiveILRanges(newStloc.ILRanges); body[initArrayPos].AddSelfAndChildrenRecursiveILRanges(newStloc.ILRanges); } body[pos] = newStloc; body.RemoveAt(initArrayPos); return(true); } } return(false); }
public static void NopMergeILRanges(ILBlockBase block, List <ILNode> newBody, int instrIndexToRemove) { var body = block.Body; ILNode prevNode = null, nextNode = null; ILExpression prev = null, next = null; if (newBody.Count > 0) { prev = (prevNode = newBody[newBody.Count - 1]) as ILExpression; } if (instrIndexToRemove + 1 < body.Count) { next = (nextNode = body[instrIndexToRemove + 1]) as ILExpression; } ILNode node = null; if (prev != null && prev.Prefixes == null) { switch (prev.Code) { case ILCode.Call: case ILCode.CallGetter: case ILCode.Calli: case ILCode.CallSetter: case ILCode.Callvirt: case ILCode.CallvirtGetter: case ILCode.CallvirtSetter: node = prev; break; } } if (next != null && next.Prefixes == null) { if (next.Match(ILCode.Leave)) { node = next; } } if (node != null && node == prevNode) { AddILRangesTryPreviousFirst(body[instrIndexToRemove], prevNode, nextNode, block); } else { AddILRangesTryNextFirst(body[instrIndexToRemove], prevNode, nextNode, block); } }
bool SimplifyLiftedOperators(ILBlockBase block, List <ILNode> body, ILExpression expr, int pos) { if (!GetPatternMatcher(corLib).SimplifyLiftedOperators(expr)) { return(false); } var inlining = GetILInlining(method); while (--pos >= 0 && inlining.InlineIfPossible(block, body, ref pos)) { ; } return(true); }
public static void LabelMergeILRanges(ILBlockBase block, List <ILNode> newBody, int instrIndexToRemove) { var body = block.Body; ILNode prevNode = null, nextNode = null; if (newBody.Count > 0) { prevNode = newBody[newBody.Count - 1]; } if (instrIndexToRemove + 1 < body.Count) { nextNode = body[instrIndexToRemove + 1]; } AddILRangesTryNextFirst(body[instrIndexToRemove], prevNode, nextNode, block); }
/// <summary> /// Inlines the stloc instruction at block.Body[pos] into the next instruction, if possible. /// </summary> public bool InlineOneIfPossible(ILBlockBase block, List <ILNode> body, int pos, bool aggressive) { ILVariable v; ILExpression inlinedExpression; if (body[pos].Match(ILCode.Stloc, out v, out inlinedExpression) && !v.IsPinned) { if (InlineIfPossible(v, inlinedExpression, body.ElementAtOrDefault(pos + 1), aggressive)) { // Assign the ranges of the stloc instruction: if (context.CalculateILRanges) { inlinedExpression.ILRanges.AddRange(body[pos].ILRanges); } // Remove the stloc instruction: body.RemoveAt(pos); return(true); } else if (numLdloc.GetOrDefault(v) == 0 && numLdloca.GetOrDefault(v) == 0) { // The variable is never loaded if (inlinedExpression.HasNoSideEffects()) { // Remove completely AnalyzeNode(body[pos], -1); if (context.CalculateILRanges) { Utils.AddILRanges(block, body, pos); } body.RemoveAt(pos); return(true); } else if (inlinedExpression.CanBeExpressionStatement() && v.GeneratedByDecompiler) { // Assign the ranges of the stloc instruction: if (context.CalculateILRanges) { inlinedExpression.ILRanges.AddRange(body[pos].ILRanges); } // Remove the stloc, but keep the inner expression body[pos] = inlinedExpression; return(true); } } } return(false); }
public static void AddILRangesTryPreviousFirst(ILNode prev, ILNode next, ILBlockBase block, IEnumerable <ILRange> ilRanges) { if (prev != null && prev.SafeToAddToEndILRanges) { prev.EndILRanges.AddRange(ilRanges); } else if (next != null) { next.ILRanges.AddRange(ilRanges); } else if (prev != null) { block.EndILRanges.AddRange(ilRanges); } else { block.ILRanges.AddRange(ilRanges); } }
public static void AddILRangesTryPreviousFirst(ILNode prev, ILNode next, ILBlockBase block, ILNode removed) { if (prev != null && prev.SafeToAddToEndILRanges) { removed.AddSelfAndChildrenRecursiveILRanges(prev.EndILRanges); } else if (next != null) { removed.AddSelfAndChildrenRecursiveILRanges(next.ILRanges); } else if (prev != null) { removed.AddSelfAndChildrenRecursiveILRanges(block.EndILRanges); } else { removed.AddSelfAndChildrenRecursiveILRanges(block.ILRanges); } }
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); }
/// <summary> /// Handles both object and collection initializers. /// </summary> bool TransformObjectInitializers(ILBlockBase block, 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; ITypeDefOrRef newObjType; bool isValueType; IMethod 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); var old = ctorArgs[0]; ctorArgs.RemoveAt(0); newObjExpr = new ILExpression(ILCode.Newobj, ctor, ctorArgs); old.AddSelfAndChildrenRecursiveILRanges(newObjExpr.ILRanges); } else { return(false); } } else { return(false); } if (DnlibExtensions.IsValueType(newObjType) != 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.ToTypeSig()), 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 } var inlining = GetILInlining(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].AddSelfAndChildrenRecursiveILRanges(initializer.ILRanges); expr.Arguments[0] = initializer; } else { Debug.Assert(expr.Code == ILCode.Call); expr.Code = ILCode.Stloc; expr.Operand = v; foreach (var arg in expr.Arguments) { arg.AddSelfAndChildrenRecursiveILRanges(initializer.ILRanges); } expr.Arguments.Clear(); expr.Arguments.Add(initializer); } // remove all the instructions that were pulled into the initializer for (int i = originalPos + 1; i < pos; i++) { body[i].AddSelfAndChildrenRecursiveILRanges(initializer.ILRanges); } 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 = GetILInlining(method); inlining.InlineIfPossible(block, body, ref originalPos); return(true); }
public static void AddILRangesTryNextFirst(ILNode removed, ILNode prev, ILNode next, ILBlockBase block) { if (removed == null) { return; } AddILRangesTryNextFirst(prev, next, block, removed.GetSelfAndChildrenRecursiveILRanges()); }
public static void AddILRangesToInstruction(ILNode nodeToAddTo, ILNode prev, ILNode next, ILBlockBase block, IEnumerable <ILRange> ilRanges) { Debug.Assert(nodeToAddTo == prev || nodeToAddTo == next || nodeToAddTo == block); if (nodeToAddTo != null) { if (nodeToAddTo == prev && prev.SafeToAddToEndILRanges) { prev.EndILRanges.AddRange(ilRanges); return; } else if (nodeToAddTo != null && nodeToAddTo == next) { next.ILRanges.AddRange(ilRanges); return; } } AddILRangesTryNextFirst(prev, next, block, ilRanges); }
public static void AddILRangesToInstruction(ILNode nodeToAddTo, ILNode prev, ILNode next, ILBlockBase block, ILNode removed) { Debug.Assert(nodeToAddTo == prev || nodeToAddTo == next || nodeToAddTo == block); if (nodeToAddTo != null) { if (nodeToAddTo == prev && prev.SafeToAddToEndILRanges) { removed.AddSelfAndChildrenRecursiveILRanges(prev.EndILRanges); return; } else if (nodeToAddTo != null && nodeToAddTo == next) { removed.AddSelfAndChildrenRecursiveILRanges(next.ILRanges); return; } } AddILRangesTryNextFirst(prev, next, block, removed); }
/// <summary> /// Adds the removed instruction's ILRanges to the next or previous instruction /// </summary> /// <param name="block">The owner block</param> /// <param name="body">Body</param> /// <param name="removedIndex">Index of removed instruction</param> public static void AddILRanges(ILBlockBase block, List <ILNode> body, int removedIndex) { AddILRanges(block, body, removedIndex, 1); }
public static void AddILRangesTryNextFirst(List <ILNode> newBody, List <ILNode> body, int removedIndex, ILBlockBase block) { ILNode prev = newBody.Count > 0 ? newBody[newBody.Count - 1] : null; ILNode next = removedIndex + 1 < body.Count ? body[removedIndex + 1] : null; AddILRangesTryNextFirst(body[removedIndex], prev, next, block); }
public static void AddILRangesTryNextFirst(ILNode removed, ILNode prev, ILNode next, ILBlockBase block) { if (removed == null) { return; } AddILRangesTryNextFirst(prev, next, block, removed); }