void DuplicateReturnStatements(ILBlock method) { Dictionary <ILLabel, ILNode> nextSibling = new Dictionary <ILLabel, ILNode>(); // Build navigation data foreach (ILBlock block in method.GetSelfAndChildrenRecursive().OfType <ILBlock>()) { for (int i = 0; i < block.Body.Count - 1; i++) { ILLabel curr = block.Body[i] as ILLabel; if (curr != null) { nextSibling[curr] = block.Body[i + 1]; } } } // Duplicate returns foreach (ILBlock block in method.GetSelfAndChildrenRecursive().OfType <ILBlock>()) { for (int i = 0; i < block.Body.Count; i++) { ILLabel targetLabel; if (block.Body[i].Match(ILCode.Br, out targetLabel) || block.Body[i].Match(ILCode.Leave, out targetLabel)) { // Skip extra labels while (nextSibling.ContainsKey(targetLabel) && nextSibling[targetLabel] is ILLabel) { targetLabel = (ILLabel)nextSibling[targetLabel]; } // Inline return statement ILNode target; List <ILExpression> retArgs; if (nextSibling.TryGetValue(targetLabel, out target)) { if (target.Match(ILCode.Ret, out retArgs)) { ILVariable locVar; object constValue; if (retArgs.Count == 0) { block.Body[i] = new ILExpression(ILCode.Ret, null); } else if (retArgs.Single().Match(ILCode.Ldloc, out locVar)) { block.Body[i] = new ILExpression(ILCode.Ret, null, new ILExpression(ILCode.Ldloc, locVar)); } else if (retArgs.Single().Match(ILCode.Ldc_I4, out constValue)) { block.Body[i] = new ILExpression(ILCode.Ret, null, new ILExpression(ILCode.Ldc_I4, constValue)); } } } else { if (method.Body.Count > 0 && method.Body.Last() == targetLabel) { // It exits the main method - so it is same as return; block.Body[i] = new ILExpression(ILCode.Ret, null); } } } } } }
public void Optimize(DecompilerContext context, ILBlock method, ILAstOptimizationStep abortBeforeStep = ILAstOptimizationStep.None) { this.context = context; this.typeSystem = context.CurrentMethod.Module.TypeSystem; this.method = method; if (abortBeforeStep == ILAstOptimizationStep.RemoveRedundantCode) { return; } RemoveRedundantCode(method); if (abortBeforeStep == ILAstOptimizationStep.ReduceBranchInstructionSet) { return; } foreach (ILBlock block in method.GetSelfAndChildrenRecursive().OfType <ILBlock>()) { ReduceBranchInstructionSet(block); } // ReduceBranchInstructionSet runs before inlining because the non-aggressive inlining heuristic // looks at which type of instruction consumes the inlined variable. if (abortBeforeStep == ILAstOptimizationStep.InlineVariables) { return; } // Works better after simple goto removal because of the following debug pattern: stloc X; br Next; Next:; ldloc X ILInlining inlining1 = new ILInlining(method); inlining1.InlineAllVariables(); if (abortBeforeStep == ILAstOptimizationStep.CopyPropagation) { return; } inlining1.CopyPropagation(); if (abortBeforeStep == ILAstOptimizationStep.YieldReturn) { return; } YieldReturnDecompiler.Run(context, method); if (abortBeforeStep == ILAstOptimizationStep.PropertyAccessInstructions) { return; } IntroducePropertyAccessInstructions(method); if (abortBeforeStep == ILAstOptimizationStep.SplitToMovableBlocks) { return; } foreach (ILBlock block in method.EnumerateSelfAndChildrenRecursive().OfType <ILBlock>()) { SplitToBasicBlocks(block); } if (abortBeforeStep == ILAstOptimizationStep.TypeInference) { return; } // Types are needed for the ternary operator optimization TypeAnalysis.Run(context, method); var controlFlow = new SimpleControlFlow(context, method); foreach (ILBlock block in method.GetSelfAndChildrenRecursive().OfType <ILBlock>()) { bool modified; do { modified = false; if (abortBeforeStep == ILAstOptimizationStep.SimplifyShortCircuit) { return; } modified |= block.RunOptimization(controlFlow.SimplifyShortCircuit); if (abortBeforeStep == ILAstOptimizationStep.SimplifyTernaryOperator) { return; } modified |= block.RunOptimization(controlFlow.SimplifyTernaryOperator); if (abortBeforeStep == ILAstOptimizationStep.SimplifyNullCoalescing) { return; } modified |= block.RunOptimization(controlFlow.SimplifyNullCoalescing); if (abortBeforeStep == ILAstOptimizationStep.JoinBasicBlocks) { return; } modified |= block.RunOptimization(new SimpleControlFlow(context, method).JoinBasicBlocks); if (abortBeforeStep == ILAstOptimizationStep.SimplifyShiftOperators) { return; } modified |= block.RunOptimization(SimplifyShiftOperators); if (abortBeforeStep == ILAstOptimizationStep.TransformDecimalCtorToConstant) { return; } modified |= block.RunOptimization(TransformDecimalCtorToConstant); modified |= block.RunOptimization(SimplifyLdcI4ConvI8); if (abortBeforeStep == ILAstOptimizationStep.SimplifyLdObjAndStObj) { return; } modified |= block.RunOptimization(SimplifyLdObjAndStObj); if (abortBeforeStep == ILAstOptimizationStep.SimplifyCustomShortCircuit) { return; } modified |= block.RunOptimization(controlFlow.SimplifyCustomShortCircuit); if (abortBeforeStep == ILAstOptimizationStep.TransformArrayInitializers) { return; } modified |= block.RunOptimization(TransformArrayInitializers); if (abortBeforeStep == ILAstOptimizationStep.TransformMultidimensionalArrayInitializers) { return; } modified |= block.RunOptimization(TransformMultidimensionalArrayInitializers); if (abortBeforeStep == ILAstOptimizationStep.TransformObjectInitializers) { return; } modified |= block.RunOptimization(TransformObjectInitializers); if (abortBeforeStep == ILAstOptimizationStep.MakeAssignmentExpression) { return; } modified |= block.RunOptimization(MakeAssignmentExpression); modified |= block.RunOptimization(MakeCompoundAssignments); if (abortBeforeStep == ILAstOptimizationStep.IntroducePostIncrement) { return; } modified |= block.RunOptimization(IntroducePostIncrement); if (abortBeforeStep == ILAstOptimizationStep.InlineVariables2) { return; } modified |= new ILInlining(method).InlineAllInBlock(block); new ILInlining(method).CopyPropagation(); } while(modified); } if (abortBeforeStep == ILAstOptimizationStep.FindLoops) { return; } foreach (ILBlock block in method.GetSelfAndChildrenRecursive().OfType <ILBlock>()) { new LoopsAndConditions(context).FindLoops(block); } if (abortBeforeStep == ILAstOptimizationStep.FindConditions) { return; } foreach (ILBlock block in method.GetSelfAndChildrenRecursive().OfType <ILBlock>()) { new LoopsAndConditions(context).FindConditions(block); } if (abortBeforeStep == ILAstOptimizationStep.FlattenNestedMovableBlocks) { return; } FlattenBasicBlocks(method); if (abortBeforeStep == ILAstOptimizationStep.RemoveEndFinally) { return; } RemoveEndFinally(method); if (abortBeforeStep == ILAstOptimizationStep.RemoveRedundantCode2) { return; } RemoveRedundantCode(method); if (abortBeforeStep == ILAstOptimizationStep.GotoRemoval) { return; } new GotoRemoval().RemoveGotos(method); if (abortBeforeStep == ILAstOptimizationStep.DuplicateReturns) { return; } DuplicateReturnStatements(method); if (abortBeforeStep == ILAstOptimizationStep.GotoRemoval2) { return; } new GotoRemoval().RemoveGotos(method); if (abortBeforeStep == ILAstOptimizationStep.ReduceIfNesting) { return; } ReduceIfNesting(method); if (abortBeforeStep == ILAstOptimizationStep.InlineVariables3) { return; } // The 2nd inlining pass is necessary because DuplicateReturns and the introduction of ternary operators // open up additional inlining possibilities. new ILInlining(method).InlineAllVariables(); if (abortBeforeStep == ILAstOptimizationStep.CachedDelegateInitialization) { return; } foreach (ILBlock block in method.GetSelfAndChildrenRecursive().OfType <ILBlock>()) { for (int i = 0; i < block.Body.Count; i++) { // TODO: Move before loops CachedDelegateInitializationWithField(block, ref i); CachedDelegateInitializationWithLocal(block, ref i); } } if (abortBeforeStep == ILAstOptimizationStep.IntroduceFixedStatements) { return; } // we need post-order traversal, not pre-order, for "fixed" to work correctly foreach (ILBlock block in TreeTraversal.PostOrder <ILNode>(method, n => n.GetChildren()).OfType <ILBlock>()) { for (int i = block.Body.Count - 1; i >= 0; i--) { // TODO: Move before loops if (i < block.Body.Count) { IntroduceFixedStatements(block.Body, i); } } } if (abortBeforeStep == ILAstOptimizationStep.RecombineVariables) { return; } RecombineVariables(method); if (abortBeforeStep == ILAstOptimizationStep.TypeInference2) { return; } TypeAnalysis.Reset(method); TypeAnalysis.Run(context, method); if (abortBeforeStep == ILAstOptimizationStep.RemoveRedundantCode3) { return; } GotoRemoval.RemoveRedundantCode(method); // ReportUnassignedILRanges(method); }
/// <summary> /// Removes redundatant Br, Nop, Dup, Pop /// </summary> /// <param name="method"></param> void RemoveRedundantCode(ILBlock method) { Dictionary <ILLabel, int> labelRefCount = new Dictionary <ILLabel, int>(); var targets = from e in method.GetSelfAndChildrenRecursive().OfType <ILExpression>() where e.IsBranch() from t in e.GetBranchTargets() select t; foreach (ILLabel target in targets) { labelRefCount[target] = labelRefCount.GetOrDefault(target) + 1; } foreach (ILBlock block in method.GetSelfAndChildrenRecursive().OfType <ILBlock>()) { List <ILNode> body = block.Body; List <ILNode> newBody = new List <ILNode>(body.Count); for (int i = 0; i < body.Count; i++) { ILLabel target; ILExpression popExpr; if (body[i].Match(ILCode.Br, out target) && i + 1 < body.Count && body[i + 1] == target) { // Ignore the branch if (labelRefCount[target] == 1) { i++; // Ignore the label as well } } else if (body[i].Match(ILCode.Nop)) { // Ignore nop } else if (body[i].Match(ILCode.Pop, out popExpr)) { ILVariable v; if (!popExpr.Match(ILCode.Ldloc, out v)) { throw new Exception("Pop should have just ldloc at this stage"); } // Best effort to move the ILRange to previous statement ILVariable prevVar; ILExpression prevExpr; if (i - 1 >= 0 && body[i - 1].Match(ILCode.Stloc, out prevVar, out prevExpr) && prevVar == v) { prevExpr.ILRanges.AddRange(((ILExpression)body[i]).ILRanges); } // Ignore pop } else { newBody.Add(body[i]); } } block.Body = newBody; } // 'dup' removal foreach (ILExpression expr in method.GetSelfAndChildrenRecursive().OfType <ILExpression>()) { for (int i = 0; i < expr.Arguments.Count; i++) { ILExpression child; if (expr.Arguments[i].Match(ILCode.Dup, out child)) { child.ILRanges.AddRange(expr.Arguments[i].ILRanges); expr.Arguments[i] = child; } } } }