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; }
static bool TypeConversionSimplifications(ILBlockBase block, List<ILNode> body, ILExpression expr, int pos) { bool modified = false; modified |= TransformDecimalCtorToConstant(expr); modified |= SimplifyLdcI4ConvI8(expr); modified |= RemoveConvIFromArrayCreation(expr); foreach(ILExpression arg in expr.Arguments) { modified |= TypeConversionSimplifications(block, null, arg, -1); } return modified; }
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); }
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 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); }
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]); }
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); }
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); }
/// <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); }
static bool SimplifyLogicNot(ILBlockBase block, List<ILNode> body, ILExpression expr, int pos) { bool modified = false; expr = SimplifyLogicNot(expr, ref modified); Debug.Assert(expr == null); return modified; }
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); }
/// <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; }
public static void AddILRangesTryNextFirst(ILNode removed, ILNode prev, ILNode next, ILBlockBase block) { if (removed == null) return; AddILRangesTryNextFirst(prev, next, block, removed.GetSelfAndChildrenRecursiveILRanges()); }
static bool SimplifyLdObjAndStObj(ILBlockBase block, List<ILNode> body, ILExpression expr, int pos) { bool modified = false; expr = SimplifyLdObjAndStObj(expr, ref modified); if (modified && body != null) body[pos] = expr; for (int i = 0; i < expr.Arguments.Count; i++) { expr.Arguments[i] = SimplifyLdObjAndStObj(expr.Arguments[i], ref modified); modified |= SimplifyLdObjAndStObj(block, null, expr.Arguments[i], -1); } return modified; }
bool InlineExpressionTreeParameterDeclarations(ILBlockBase block, List<ILNode> body, ILExpression expr, int pos) { // When there is a Expression.Lambda() call, and the parameters are declared in the // IL statement immediately prior to the one containing the Lambda() call, // using this code for the3 declaration: // stloc(v, call(Expression::Parameter, call(Type::GetTypeFromHandle, ldtoken(...)), ldstr(...))) // and the variables v are assigned only once (in that statements), and read only in a Expression::Lambda // call that immediately follows the assignment statements, then we will inline those assignments // into the Lambda call using ILCode.ExpressionTreeParameterDeclarations. // This is sufficient to allow inlining over the expression tree construction. The remaining translation // of expression trees into C# will be performed by a C# AST transformer. for (int i = expr.Arguments.Count - 1; i >= 0; i--) { if (InlineExpressionTreeParameterDeclarations(block, body, expr.Arguments[i], pos)) return true; } IMethod mr; ILExpression lambdaBodyExpr, parameterArray; if (!(expr.Match(ILCode.Call, out mr, out lambdaBodyExpr, out parameterArray) && mr.Name == "Lambda")) return false; if (!(parameterArray.Code == ILCode.InitArray && mr.DeclaringType != null && mr.DeclaringType.FullName == "System.Linq.Expressions.Expression")) return false; int firstParameterPos = pos - parameterArray.Arguments.Count; if (firstParameterPos < 0) return false; ILExpression[] parameterInitExpressions = new ILExpression[parameterArray.Arguments.Count + 1]; for (int i = 0; i < parameterArray.Arguments.Count; i++) { parameterInitExpressions[i] = body[firstParameterPos + i] as ILExpression; if (!MatchParameterVariableAssignment(parameterInitExpressions[i])) return false; ILVariable v = (ILVariable)parameterInitExpressions[i].Operand; if (!parameterArray.Arguments[i].MatchLdloc(v)) return false; // TODO: validate that the variable is only used here and within 'body' } parameterInitExpressions[parameterInitExpressions.Length - 1] = lambdaBodyExpr; Debug.Assert(expr.Arguments[0] == lambdaBodyExpr); expr.Arguments[0] = new ILExpression(ILCode.ExpressionTreeParameterDeclarations, null, parameterInitExpressions); body.RemoveRange(firstParameterPos, parameterArray.Arguments.Count); return true; }
static bool SimplifyShiftOperators(ILBlockBase block, List<ILNode> body, ILExpression expr, int pos) { // C# compiles "a << b" to "a << (b & 31)", so we will remove the "& 31" if possible. bool modified = false; SimplifyShiftOperators(expr, ref modified); return modified; }
bool MakeAssignmentExpression(ILBlockBase block, List<ILNode> body, ILExpression expr, int pos) { // exprVar = ... // stloc(v, exprVar) // -> // exprVar = stloc(v, ...)) ILVariable exprVar; ILExpression initializer; if (!(expr.Match(ILCode.Stloc, out exprVar, out initializer) && exprVar.GeneratedByDecompiler)) return false; ILExpression nextExpr = body.ElementAtOrDefault(pos + 1) as ILExpression; if (nextExpr == null) return false; ILVariable v; ILExpression stLocArg; if (nextExpr.Match(ILCode.Stloc, out v, out stLocArg) && stLocArg.MatchLdloc(exprVar)) { ILExpression store2 = body.ElementAtOrDefault(pos + 2) as ILExpression; if (StoreCanBeConvertedToAssignment(store2, exprVar)) { // expr_44 = ... // stloc(v1, expr_44) // anystore(v2, expr_44) // -> // stloc(v1, anystore(v2, ...)) ILInlining inlining = new ILInlining(method); if (inlining.numLdloc.GetOrDefault(exprVar) == 2 && inlining.numStloc.GetOrDefault(exprVar) == 1) { body.RemoveAt(pos + 2); // remove store2 body.RemoveAt(pos); // remove expr = ... nextExpr.ILRanges.AddRange(nextExpr.Arguments[0].GetSelfAndChildrenRecursiveILRanges()); nextExpr.Arguments[0] = store2; store2.ILRanges.AddRange(expr.GetSelfAndChildrenRecursiveILRanges()); store2.ILRanges.AddRange(store2.Arguments[store2.Arguments.Count - 1].GetSelfAndChildrenRecursiveILRanges()); store2.Arguments[store2.Arguments.Count - 1] = initializer; inlining.InlineIfPossible(block, body, ref pos); return true; } } body.RemoveAt(pos + 1); // remove stloc nextExpr.ILRanges.AddRange(nextExpr.Arguments[0].GetSelfAndChildrenRecursiveILRanges()); nextExpr.Arguments[0] = initializer; nextExpr.ILRanges.AddRange(expr.Arguments[0].GetSelfAndChildrenRecursiveILRanges()); expr.Arguments[0] = nextExpr; return true; } else if ((nextExpr.Code == ILCode.Stsfld || nextExpr.Code == ILCode.CallSetter || nextExpr.Code == ILCode.CallvirtSetter) && nextExpr.Arguments.Count == 1) { // exprVar = ... // stsfld(fld, exprVar) // -> // exprVar = stsfld(fld, ...)) if (nextExpr.Arguments[0].MatchLdloc(exprVar)) { body.RemoveAt(pos + 1); // remove stsfld nextExpr.ILRanges.AddRange(nextExpr.Arguments[0].GetSelfAndChildrenRecursiveILRanges()); nextExpr.Arguments[0] = initializer; expr.ILRanges.AddRange(expr.Arguments[0].GetSelfAndChildrenRecursiveILRanges()); expr.Arguments[0] = nextExpr; return true; } } return false; }
bool MakeCompoundAssignments(ILBlockBase block, List<ILNode> body, ILExpression expr, int pos) { bool modified = false; modified |= MakeCompoundAssignment(expr); // Static fields and local variables are not handled here - those are expressions without side effects // and get handled by ReplaceMethodCallsWithOperators // (which does a reversible transform to the short operator form, as the introduction of checked/unchecked might have to revert to the long form). foreach (ILExpression arg in expr.Arguments) { modified |= MakeCompoundAssignments(block, null, arg, -1); } if (modified && body != null) new ILInlining(method).InlineInto(block, body, pos, aggressive: false); return modified; }
public static void AddILRangesTryPreviousFirst(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; AddILRangesTryPreviousFirst(body[removedIndex], prev, next, block); }
bool IntroducePostIncrement(ILBlockBase block, List<ILNode> body, ILExpression expr, int pos) { bool modified = IntroducePostIncrementForVariables(body, expr, pos); Debug.Assert(body[pos] == expr); // IntroducePostIncrementForVariables shouldn't change the expression reference ILExpression newExpr = IntroducePostIncrementForInstanceFields(expr); if (newExpr != null) { modified = true; body[pos] = newExpr; new ILInlining(method).InlineIfPossible(block, body, ref pos); } return modified; }
/// <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; }
bool IntroduceFixedStatements(ILBlockBase block, List<ILNode> body, int i) { ILExpression initValue; ILVariable pinnedVar; int initEndPos; if (!MatchFixedInitializer(body, i, out pinnedVar, out initValue, out initEndPos)) return false; ILFixedStatement fixedStmt = body.ElementAtOrDefault(initEndPos) as ILFixedStatement; if (fixedStmt != null) { ILExpression expr = fixedStmt.BodyBlock.Body.LastOrDefault() as ILExpression; if (expr != null && expr.Code == ILCode.Stloc && expr.Operand == pinnedVar && IsNullOrZero(expr.Arguments[0])) { // we found a second initializer for the existing fixed statement fixedStmt.Initializers.Insert(0, initValue); for (int k = i; k < initEndPos; k++) initValue.ILRanges.AddRange(body[k].GetSelfAndChildrenRecursiveILRanges().ToArray()); body.RemoveRange(i, initEndPos - i); Utils.AddILRanges(fixedStmt.BodyBlock, fixedStmt.BodyBlock.Body, fixedStmt.BodyBlock.Body.Count - 1); fixedStmt.BodyBlock.Body.RemoveAt(fixedStmt.BodyBlock.Body.Count - 1); if (pinnedVar.Type is ByRefSig) pinnedVar.Type = new PtrSig(((ByRefSig)pinnedVar.Type).Next); return true; } } // find where pinnedVar is reset to 0: int j; for (j = initEndPos; j < body.Count; j++) { ILVariable v2; ILExpression storedVal; // stloc(pinned_Var, conv.u(ldc.i4(0))) if (body[j].Match(ILCode.Stloc, out v2, out storedVal) && v2 == pinnedVar) { if (IsNullOrZero(storedVal)) { break; } } } // Create fixed statement from i to j fixedStmt = new ILFixedStatement(); fixedStmt.Initializers.Add(initValue); fixedStmt.BodyBlock = new ILBlock(body.GetRange(initEndPos, j - initEndPos)); // from initEndPos to j-1 (inclusive) for (int k = i; k < initEndPos; k++) initValue.ILRanges.AddRange(body[k].GetSelfAndChildrenRecursiveILRanges().ToArray()); body.RemoveRange(i + 1, Math.Min(j, body.Count - 1) - i); // from i+1 to j (inclusive) body[i] = fixedStmt; if (pinnedVar.Type is ByRefSig) pinnedVar.Type = new PtrSig(((ByRefSig)pinnedVar.Type).Next); return true; }
/// <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 removed, ILNode prev, ILNode next, ILBlockBase block) { if (removed == null) return; AddILRangesTryPreviousFirst(prev, next, block, removed); }