public static void ReplaceVariables(ILNode node, Func <ILVariable, ILVariable> variableMapping) { ILExpression expr = node as ILExpression; if (expr != null) { ILVariable v = expr.Operand as ILVariable; if (v != null) { expr.Operand = variableMapping(v); } foreach (ILExpression child in expr.Arguments) { ReplaceVariables(child, variableMapping); } } else { var catchBlock = node as ILTryCatchBlock.CatchBlock; if (catchBlock != null && catchBlock.ExceptionVariable != null) { catchBlock.ExceptionVariable = variableMapping(catchBlock.ExceptionVariable); } foreach (ILNode child in node.GetChildren()) { ReplaceVariables(child, variableMapping); } } }
/// <summary> /// Converts call and callvirt instructions that read/write properties into CallGetter/CallSetter instructions. /// /// CallGetter/CallSetter is used to allow the ILAst to represent "while ((SomeProperty = value) != null)". /// /// Also simplifies 'newobj(SomeDelegate, target, ldvirtftn(F, target))' to 'newobj(SomeDelegate, target, ldvirtftn(F))' /// </summary> void IntroducePropertyAccessInstructions(ILNode node) { ILExpression parentExpr = node as ILExpression; if (parentExpr != null) { for (int i = 0; i < parentExpr.Arguments.Count; i++) { ILExpression expr = parentExpr.Arguments[i]; IntroducePropertyAccessInstructions(expr); IntroducePropertyAccessInstructions(expr, parentExpr, i); } } else { foreach (ILNode child in node.GetChildren()) { IntroducePropertyAccessInstructions(child); ILExpression expr = child as ILExpression; if (expr != null) { IntroducePropertyAccessInstructions(expr, null, -1); } } } }
/// <summary> /// Reduce the nesting of conditions. /// It should be done on flat data that already had most gotos removed /// </summary> void ReduceIfNesting(ILNode node) { ILBlock block = node as ILBlock; if (block != null) { for (int i = 0; i < block.Body.Count; i++) { ILCondition cond = block.Body[i] as ILCondition; if (cond != null) { bool trueExits = cond.TrueBlock.Body.LastOrDefault().IsUnconditionalControlFlow(); bool falseExits = cond.FalseBlock.Body.LastOrDefault().IsUnconditionalControlFlow(); if (trueExits) { // Move the false block after the condition block.Body.InsertRange(i + 1, cond.FalseBlock.GetChildren()); cond.FalseBlock = new ILBlock(); } else if (falseExits) { // Move the true block after the condition block.Body.InsertRange(i + 1, cond.TrueBlock.GetChildren()); cond.TrueBlock = new ILBlock(); } // Eliminate empty true block if (!cond.TrueBlock.GetChildren().Any() && cond.FalseBlock.GetChildren().Any()) { // Swap bodies ILBlock tmp = cond.TrueBlock; cond.TrueBlock = cond.FalseBlock; cond.FalseBlock = tmp; cond.Condition = new ILExpression(ILCode.LogicNot, null, cond.Condition); } } } } // We are changing the number of blocks so we use plain old recursion to get all blocks foreach (ILNode child in node.GetChildren()) { if (child != null && !(child is ILExpression)) { ReduceIfNesting(child); } } }
void AnalyzeNode(ILNode node) { ILExpression expr = node as ILExpression; if (expr != null) { ILVariable locVar = expr.Operand as ILVariable; if (locVar != null) { if (expr.Code == ILCode.Stloc) { numStloc[locVar] = numStloc.GetOrDefault(locVar) + 1; } else if (expr.Code == ILCode.Ldloc) { numLdloc[locVar] = numLdloc.GetOrDefault(locVar) + 1; } else if (expr.Code == ILCode.Ldloca) { numLdloca[locVar] = numLdloca.GetOrDefault(locVar) + 1; } else { throw new NotSupportedException(expr.Code.ToString()); } } foreach (ILExpression child in expr.Arguments) { AnalyzeNode(child); } } else { var catchBlock = node as ILTryCatchBlock.CatchBlock; if (catchBlock != null && catchBlock.ExceptionVariable != null) { numStloc[catchBlock.ExceptionVariable] = numStloc.GetOrDefault(catchBlock.ExceptionVariable) + 1; } foreach (ILNode child in node.GetChildren()) { AnalyzeNode(child); } } }
/// <summary> /// Flattens all nested basic blocks, except the the top level 'node' argument /// </summary> void FlattenBasicBlocks(ILNode node) { ILBlock block = node as ILBlock; if (block != null) { List <ILNode> flatBody = new List <ILNode>(); foreach (ILNode child in block.GetChildren()) { FlattenBasicBlocks(child); ILBasicBlock childAsBB = child as ILBasicBlock; if (childAsBB != null) { if (!(childAsBB.Body.FirstOrDefault() is ILLabel)) { throw new Exception("Basic block has to start with a label. \n" + childAsBB.ToString()); } if (childAsBB.Body.LastOrDefault() is ILExpression && !childAsBB.Body.LastOrDefault().IsUnconditionalControlFlow()) { throw new Exception("Basci block has to end with unconditional control flow. \n" + childAsBB.ToString()); } flatBody.AddRange(childAsBB.GetChildren()); } else { flatBody.Add(child); } } block.EntryGoto = null; block.Body = flatBody; } else if (node is ILExpression) { // Optimization - no need to check expressions } else if (node != null) { // Recursively find all ILBlocks foreach (ILNode child in node.GetChildren()) { FlattenBasicBlocks(child); } } }