public void RemoveGotos(ILBlock method) { // Build the navigation data parent[method] = null; foreach (ILNode node in method.EnumerateSelfAndChildrenRecursive()) { ILNode previousChild = null; foreach (ILNode child in node.GetChildren()) { if (parent.ContainsKey(child)) throw new Exception("The following expression is linked from several locations: " + child.ToString()); parent[child] = node; if (previousChild != null) nextSibling[previousChild] = child; previousChild = child; } if (previousChild != null) nextSibling[previousChild] = null; } // Simplify gotos bool modified; do { modified = false; var gotos = from e in method.EnumerateSelfAndChildrenRecursive().OfType<ILExpression>() where e.Code == ILCode.Br || e.Code == ILCode.Leave select e; foreach (ILExpression gotoExpr in gotos) { modified |= TrySimplifyGoto(gotoExpr); } } while(modified); RemoveRedundantCode(method); }
public SimpleControlFlow(DecompilerContext context, ILBlock method) { this.context = context; this.typeSystem = context.CurrentMethod.Module.TypeSystem; var labelTargets = from e in method.EnumerateSelfAndChildrenRecursive().OfType<ILExpression>() where e.IsBranch() from t in e.GetBranchTargets() select t; foreach(ILLabel target in labelTargets) { labelGlobalRefCount[target] = labelGlobalRefCount.GetOrDefault(target) + 1; } var basicBlocks = method.EnumerateSelfAndChildrenRecursive().OfType<ILBasicBlock>(); foreach(ILBasicBlock bb in basicBlocks) { foreach(ILLabel label in bb.GetChildren().OfType<ILLabel>()) { labelToBasicBlock[label] = bb; } } }
string GenerateNameForVariable(ILVariable variable, ILBlock methodBody) { string proposedName = null; if (variable.Type == context.CurrentType.Module.TypeSystem.Int32) { // test whether the variable might be a loop counter bool isLoopCounter = false; foreach (ILWhileLoop loop in methodBody.EnumerateSelfAndChildrenRecursive().OfType<ILWhileLoop>()) { ILExpression expr = loop.Condition; while (expr != null && expr.Code == ILCode.LogicNot) expr = expr.Arguments[0]; if (expr != null) { switch (expr.Code) { case ILCode.Clt: case ILCode.Clt_Un: case ILCode.Cgt: case ILCode.Cgt_Un: ILVariable loadVar; if (expr.Arguments[0].Match(ILCode.Ldloc, out loadVar) && loadVar == variable) { isLoopCounter = true; } break; } } } if (isLoopCounter) { // For loop variables, use i,j,k,l,m,n for (char c = 'i'; c <= maxLoopVariableName; c++) { if (!typeNames.ContainsKey(c.ToString())) { proposedName = c.ToString(); break; } } } } if (string.IsNullOrEmpty(proposedName)) { var proposedNameForStores = (from expr in methodBody.EnumerateSelfAndChildrenRecursive().OfType<ILExpression>() where expr.Code == ILCode.Stloc && expr.Operand == variable select GetNameFromExpression(expr.Arguments.Single()) ).Except(fieldNamesInCurrentType).ToList(); if (proposedNameForStores.Count == 1) { proposedName = proposedNameForStores[0]; } } if (string.IsNullOrEmpty(proposedName)) { var proposedNameForLoads = (from expr in methodBody.EnumerateSelfAndChildrenRecursive().OfType<ILExpression>() from i in Enumerable.Range(0, expr.Arguments.Count) let arg = expr.Arguments[i] where arg.Code == ILCode.Ldloc && arg.Operand == variable select GetNameForArgument(expr, i) ).Except(fieldNamesInCurrentType).ToList(); if (proposedNameForLoads.Count == 1) { proposedName = proposedNameForLoads[0]; } } if (string.IsNullOrEmpty(proposedName)) { proposedName = GetNameByType(variable.Type); } // remove any numbers from the proposed name int number; proposedName = SplitName(proposedName, out number); if (!typeNames.ContainsKey(proposedName)) { typeNames.Add(proposedName, 0); } int count = ++typeNames[proposedName]; if (count > 1) { return proposedName + count.ToString(); } else { return proposedName; } }
string GenerateNameForVariable(ILVariable variable, ILBlock methodBody) { string proposedName = null; if (variable.Type == context.CurrentType.Module.TypeSystem.Int32) { // test whether the variable might be a loop counter bool isLoopCounter = false; foreach (ILWhileLoop loop in methodBody.EnumerateSelfAndChildrenRecursive().OfType <ILWhileLoop>()) { ILExpression expr = loop.Condition; while (expr != null && expr.Code == ILCode.LogicNot) { expr = expr.Arguments[0]; } if (expr != null) { switch (expr.Code) { case ILCode.Clt: case ILCode.Clt_Un: case ILCode.Cgt: case ILCode.Cgt_Un: ILVariable loadVar; if (expr.Arguments[0].Match(ILCode.Ldloc, out loadVar) && loadVar == variable) { isLoopCounter = true; } break; } } } if (isLoopCounter) { // For loop variables, use i,j,k,l,m,n for (char c = 'i'; c <= maxLoopVariableName; c++) { if (!typeNames.ContainsKey(c.ToString())) { proposedName = c.ToString(); break; } } } } if (string.IsNullOrEmpty(proposedName)) { var proposedNameForStores = (from expr in methodBody.EnumerateSelfAndChildrenRecursive().OfType <ILExpression>() where expr.Code == ILCode.Stloc && expr.Operand == variable select GetNameFromExpression(expr.Arguments.Single()) ).Except(fieldNamesInCurrentType).ToList(); if (proposedNameForStores.Count == 1) { proposedName = proposedNameForStores[0]; } } if (string.IsNullOrEmpty(proposedName)) { var proposedNameForLoads = (from expr in methodBody.EnumerateSelfAndChildrenRecursive().OfType <ILExpression>() from i in Enumerable.Range(0, expr.Arguments.Count) let arg = expr.Arguments[i] where arg.Code == ILCode.Ldloc && arg.Operand == variable select GetNameForArgument(expr, i) ).Except(fieldNamesInCurrentType).ToList(); if (proposedNameForLoads.Count == 1) { proposedName = proposedNameForLoads[0]; } } if (string.IsNullOrEmpty(proposedName)) { proposedName = GetNameByType(variable.Type); } // remove any numbers from the proposed name int number; proposedName = SplitName(proposedName, out number); if (!typeNames.ContainsKey(proposedName)) { typeNames.Add(proposedName, 0); } int count = ++typeNames[proposedName]; if (count > 1) { return(proposedName + count.ToString()); } else { return(proposedName); } }
public static void RemoveRedundantCode(ILBlock method) { // Remove dead lables and nops var liveLabels = new HashSet<ILLabel>( from e in method.EnumerateSelfAndChildrenRecursive().OfType<ILExpression>() where e.IsBranch() from t in e.GetBranchTargets() select t); foreach(ILBlock block in method.EnumerateSelfAndChildrenRecursive().OfType<ILBlock>()) { var liveBlockNodes = from n in block.Body where !n.Match(ILCode.Nop) && !(n is ILLabel && !liveLabels.Contains((ILLabel)n)) select n; block.Body = liveBlockNodes.ToList(); } // Remove redundant continue foreach(ILWhileLoop loop in method.EnumerateSelfAndChildrenRecursive().OfType<ILWhileLoop>()) { var body = loop.BodyBlock.Body; if (body.Count > 0 && body.Last().Match(ILCode.LoopContinue)) { body.RemoveAt(body.Count - 1); } } // Remove redundant break at the end of case // Remove redundant case blocks altogether foreach(ILSwitch ilSwitch in method.EnumerateSelfAndChildrenRecursive().OfType<ILSwitch>()) { foreach(ILBlock ilCase in ilSwitch.CaseBlocks) { Debug.Assert(ilCase.EntryGoto == null); int count = ilCase.Body.Count; if (count >= 2) { if (ilCase.Body[count - 2].IsUnconditionalControlFlow() && ilCase.Body[count - 1].Match(ILCode.LoopOrSwitchBreak)) { ilCase.Body.RemoveAt(count - 1); } } } var defaultCase = ilSwitch.CaseBlocks.SingleOrDefault(cb => cb.Values == null); // If there is no default block, remove empty case blocks if (defaultCase == null || (defaultCase.Body.Count == 1 && defaultCase.Body.Single().Match(ILCode.LoopOrSwitchBreak))) { ilSwitch.CaseBlocks.RemoveAll(b => b.Body.Count == 1 && b.Body.Single().Match(ILCode.LoopOrSwitchBreak)); } } // Remove redundant return at the end of method if (method.Body.Count > 0 && method.Body.Last().Match(ILCode.Ret) && ((ILExpression)method.Body.Last()).Arguments.Count == 0) { method.Body.RemoveAt(method.Body.Count - 1); } // Remove unreachable return statements bool modified = false; foreach(ILBlock block in method.EnumerateSelfAndChildrenRecursive().OfType<ILBlock>().ToList()) { for (int i = 0; i < block.Body.Count - 1;) { if (block.Body[i].IsUnconditionalControlFlow() && block.Body[i+1].Match(ILCode.Ret)) { modified = true; block.Body.RemoveAt(i+1); } else { i++; } } } if (modified) { // More removals might be possible new GotoRemoval().RemoveGotos(method); } }
public BlockStatement CreateMethodBody(IEnumerable<ParameterDeclaration> parameters, /*Concurrent*/Dictionary<int, IEnumerable<ILVariable>> localVariables) { if (methodDef.Body == null) return null; if (localVariables == null) throw new ArgumentException("localVariables must be instantiated"); context.VerifyProgress(); ILBlock ilMethod = new ILBlock(); var astBuilder = ILMethodAstBuilder.Build(methodDef, true); ilMethod.Body = astBuilder.Nodes.ToList(); context.VerifyProgress(); ILAstOptimizer bodyGraph = new ILAstOptimizer(); bodyGraph.Optimize(context, ilMethod); context.VerifyProgress(); var allVariables = (from e in ilMethod.EnumerateSelfAndChildrenRecursive().OfType<ILExpression>() let v = e.Operand as ILVariable where v!=null && !v.IsParameter select v).Distinct(); Debug.Assert(context.CurrentMethod == methodDef); NameVariables.AssignNamesToVariables(context, astBuilder.Parameters, allVariables, ilMethod); if (parameters != null) { foreach (var pair in (from p in parameters join v in astBuilder.Parameters on p.Annotation<ParameterDefinition>() equals v.OriginalParameter select new { p, v.Name })) { pair.p.Name = pair.Name; } } context.VerifyProgress(); BlockStatement astBlock = TransformBlock(ilMethod); CommentStatement.ReplaceAll(astBlock); // convert CommentStatements to Comments Statement insertionPoint = astBlock.Statements.FirstOrDefault(); foreach (ILVariable v in localVariablesToDefine) { AstType type; if (v.Type.ContainsAnonymousType()) type = new SimpleType("var"); else type = AstBuilder.ConvertType(v.Type); var newVarDecl = new VariableDeclarationStatement(type, v.Name); astBlock.Statements.InsertBefore(insertionPoint, newVarDecl); } // store the variables - used for debugger int token = methodDef.MetadataToken.ToInt32(); localVariables[token] = allVariables; return astBlock; }
/// <summary> /// Clears the type inference data on the method. /// </summary> public static void Reset(ILBlock method) { foreach (ILExpression expr in method.EnumerateSelfAndChildrenRecursive().OfType<ILExpression>()) { expr.InferredType = null; expr.ExpectedType = null; ILVariable v = expr.Operand as ILVariable; if (v != null && v.IsGenerated) v.Type = null; } }