void CachedDelegateInitializationWithLocal(ILBlock block, ref int i) { // if (logicnot(ldloc(v))) { // stloc(v, newobj(Action::.ctor, ldloc(displayClass), ldftn(method))) // } else { // } // ...(..., ldloc(v), ...) ILCondition c = block.Body[i] as ILCondition; if (c == null || c.Condition == null && c.TrueBlock == null || c.FalseBlock == null) { return; } if (!(c.TrueBlock.Body.Count == 1 && c.FalseBlock.Body.Count == 0)) { return; } if (!c.Condition.Match(ILCode.LogicNot)) { return; } ILExpression condition = c.Condition.Arguments.Single() as ILExpression; if (condition == null || condition.Code != ILCode.Ldloc) { return; } ILVariable v = (ILVariable)condition.Operand; ILExpression stloc = c.TrueBlock.Body[0] as ILExpression; if (!(stloc != null && stloc.Code == ILCode.Stloc && (ILVariable)stloc.Operand == v)) { return; } ILExpression newObj = stloc.Arguments[0]; if (!(newObj.Code == ILCode.Newobj && newObj.Arguments.Count == 2)) { return; } if (newObj.Arguments[0].Code != ILCode.Ldloc) { return; } if (newObj.Arguments[1].Code != ILCode.Ldftn) { return; } MethodDefinition anonymousMethod = ((MethodReference)newObj.Arguments[1].Operand).ResolveWithinSameModule(); // method is defined in current assembly if (!AstServices.Transforms.DelegateConstruction.IsAnonymousMethod(context, anonymousMethod)) { return; } ILNode followingNode = block.Body.ElementAtOrDefault(i + 1); int ldlocOperandCount = followingNode .EnumerateSelfAndChildrenRecursive() .OfType <ILExpression>() .Count( e => e.Code == ILCode.Ldloc && (ILVariable)e.Operand == v); if (followingNode != null && ldlocOperandCount == 1) { ILInlining inlining = new ILInlining(method); if (!(inlining.numLdloc.GetOrDefault(v) == 2 && inlining.numStloc.GetOrDefault(v) == 2 && inlining.numLdloca.GetOrDefault(v) == 0)) { return; } // Find the store instruction that initializes the local to null: foreach (ILBlock storeBlock in method.EnumerateSelfAndChildrenRecursive().OfType <ILBlock>()) { for (int j = 0; j < storeBlock.Body.Count; j++) { ILVariable storedVar; ILExpression storedExpr; if (storeBlock.Body[j].Match(ILCode.Stloc, out storedVar, out storedExpr) && storedVar == v && storedExpr.Match(ILCode.Ldnull)) { // Remove the instruction storeBlock.Body.RemoveAt(j); if (storeBlock == block && j < i) { i--; } break; } } } block.Body[i] = stloc; // remove the 'if (v==null)' inlining = new ILInlining(method); inlining.InlineIfPossible(block.Body, ref i); } }
bool IntroducePostIncrementForVariables(List <ILNode> body, ILExpression expr, int pos) { // Works for variables and static fields/properties // expr = ldloc(i) // stloc(i, add(expr, ldc.i4(1))) // -> // expr = postincrement(1, ldloca(i)) ILVariable exprVar; ILExpression exprInit; if (!(expr.Match(ILCode.Stloc, out exprVar, out exprInit) && exprVar.IsGenerated)) { return(false); } //The next expression ILExpression nextExpr = body.ElementAtOrDefault(pos + 1) as ILExpression; if (nextExpr == null) { return(false); } ILCode loadInstruction = exprInit.Code; ILCode storeInstruction = nextExpr.Code; bool recombineVariable = false; // We only recognise local variables, static fields, and static getters with no arguments switch (loadInstruction) { case ILCode.Ldloc: //Must be a matching store type if (storeInstruction != ILCode.Stloc) { return(false); } ILVariable loadVar = (ILVariable)exprInit.Operand; ILVariable storeVar = (ILVariable)nextExpr.Operand; if (loadVar != storeVar) { if (loadVar.OriginalVariable != null && loadVar.OriginalVariable == storeVar.OriginalVariable) { recombineVariable = true; } else { return(false); } } break; case ILCode.Ldsfld: if (storeInstruction != ILCode.Stsfld) { return(false); } if (exprInit.Operand != nextExpr.Operand) { return(false); } break; case ILCode.CallGetter: // non-static getters would have the 'this' argument if (exprInit.Arguments.Count != 0) { return(false); } if (storeInstruction != ILCode.CallSetter) { return(false); } if (!IsGetterSetterPair(exprInit.Operand, nextExpr.Operand)) { return(false); } break; default: return(false); } ILExpression addExpr = nextExpr.Arguments[0]; int incrementAmount; ILCode incrementCode = GetIncrementCode(addExpr, out incrementAmount); if (!(incrementAmount != 0 && addExpr.Arguments[0].MatchLdloc(exprVar))) { return(false); } if (recombineVariable) { // Split local variable, unsplit these two instances // replace nextExpr.Operand with exprInit.Operand ReplaceVariables(method, oldVar => oldVar == nextExpr.Operand ? (ILVariable)exprInit.Operand : oldVar); } switch (loadInstruction) { case ILCode.Ldloc: exprInit.Code = ILCode.Ldloca; break; case ILCode.Ldsfld: exprInit.Code = ILCode.Ldsflda; break; case ILCode.CallGetter: exprInit = new ILExpression(ILCode.AddressOf, null, exprInit); break; } expr.Arguments[0] = new ILExpression(incrementCode, incrementAmount, exprInit); body.RemoveAt(pos + 1); // TODO ILRanges return(true); }
bool HandleStringFixing(ILVariable pinnedVar, List <ILNode> body, ref int pos, ref ILExpression fixedStmtInitializer) { // fixed (stloc(pinnedVar, ldloc(text))) { // var1 = var2 = conv.i(ldloc(pinnedVar)) // if (logicnot(logicnot(var1))) { // var2 = add(var1, call(RuntimeHelpers::get_OffsetToStringData)) // } // stloc(ptrVar, var2) // ... if (pos >= body.Count) { return(false); } ILVariable var1, var2; ILExpression varAssignment, ptrInitialization; if (!(body[pos].Match(ILCode.Stloc, out var1, out varAssignment) && varAssignment.Match(ILCode.Stloc, out var2, out ptrInitialization))) { return(false); } if (!(var1.IsGenerated && var2.IsGenerated)) { return(false); } if (ptrInitialization.Code == ILCode.Conv_I || ptrInitialization.Code == ILCode.Conv_U) { ptrInitialization = ptrInitialization.Arguments[0]; } if (!ptrInitialization.MatchLdloc(pinnedVar)) { return(false); } ILCondition ifStmt = body[pos + 1] as ILCondition; if (!(ifStmt != null && ifStmt.TrueBlock != null && ifStmt.TrueBlock.Body.Count == 1 && (ifStmt.FalseBlock == null || ifStmt.FalseBlock.Body.Count == 0))) { return(false); } if (!UnpackDoubleNegation(ifStmt.Condition).MatchLdloc(var1)) { return(false); } ILVariable assignedVar; ILExpression assignedExpr; if (!(ifStmt.TrueBlock.Body[0].Match(ILCode.Stloc, out assignedVar, out assignedExpr) && assignedVar == var2 && assignedExpr.Code == ILCode.Add)) { return(false); } MethodReference calledMethod; if (!(assignedExpr.Arguments[0].MatchLdloc(var1))) { return(false); } if (!(assignedExpr.Arguments[1].Match(ILCode.Call, out calledMethod) || assignedExpr.Arguments[1].Match(ILCode.CallGetter, out calledMethod))) { return(false); } if (!(calledMethod.Name == "get_OffsetToStringData" && calledMethod.DeclaringType.FullName == "System.Runtime.CompilerServices.RuntimeHelpers")) { return(false); } ILVariable pointerVar; if (body[pos + 2].Match(ILCode.Stloc, out pointerVar, out assignedExpr) && assignedExpr.MatchLdloc(var2)) { pos += 3; fixedStmtInitializer.Operand = pointerVar; return(true); } return(false); }