Esempio n. 1
0
        public static void RemoveRedundantCode(ILBlock method)
        {
            // Remove dead lables and nops
            HashSet <ILLabel> liveLabels = new HashSet <ILLabel>(method.GetSelfAndChildrenRecursive <ILExpression>(e => e.IsBranch()).SelectMany(e => e.GetBranchTargets()));

            foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>())
            {
                block.Body = block.Body.Where(n => !n.Match(ILCode.Nop) && !(n is ILLabel && !liveLabels.Contains((ILLabel)n))).ToList();
            }

            // Remove redundant continue
            foreach (ILWhileLoop loop in method.GetSelfAndChildrenRecursive <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.GetSelfAndChildrenRecursive <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.GetSelfAndChildrenRecursive <ILBlock>())
            {
                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);
            }
        }
Esempio n. 2
0
        void DuplicateReturnStatements(ILBlock method)
        {
            Dictionary <ILLabel, ILNode> nextSibling = new Dictionary <ILLabel, ILNode>();

            // Build navigation data
            foreach (ILBlock block in method.GetSelfAndChildrenRecursive <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 <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)
                                    {
                                        Original = new List <ILExpression> {
                                            (ILExpression)block.Body[i]
                                        }
                                    };
                                }
                                else if (retArgs.Single().Match(ILCode.Ldloc, out locVar))
                                {
                                    block.Body[i] = new ILExpression(ILCode.Ret, null, new ILExpression(ILCode.Ldloc, locVar))
                                    {
                                        Original = new List <ILExpression> {
                                            (ILExpression)block.Body[i]
                                        }
                                    };
                                }
                                else if (retArgs.Single().Match(ILCode.Ldc_I4, out constValue))
                                {
                                    block.Body[i] = new ILExpression(ILCode.Ret, null, new ILExpression(ILCode.Ldc_I4, constValue))
                                    {
                                        Original = new List <ILExpression> {
                                            (ILExpression)block.Body[i]
                                        }
                                    };
                                }
                            }
                        }
                        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);
                            }
                        }
                    }
                }
            }
        }
Esempio n. 3
0
        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 <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);
            AsyncDecompiler.RunStep1(context, method);

            if (abortBeforeStep == ILAstOptimizationStep.AsyncAwait)
            {
                return;
            }
            AsyncDecompiler.RunStep2(context, method);

            if (abortBeforeStep == ILAstOptimizationStep.PropertyAccessInstructions)
            {
                return;
            }
            IntroducePropertyAccessInstructions(method);

            if (abortBeforeStep == ILAstOptimizationStep.SplitToMovableBlocks)
            {
                return;
            }
            foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>())
            {
                SplitToBasicBlocks(block);
            }

            if (abortBeforeStep == ILAstOptimizationStep.TypeInference)
            {
                return;
            }
            // Types are needed for the ternary operator optimization
            TypeAnalysis.Run(context, method);

            foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>())
            {
                bool modified;
                do
                {
                    modified = false;

                    if (abortBeforeStep == ILAstOptimizationStep.SimplifyShortCircuit)
                    {
                        return;
                    }
                    modified |= block.RunOptimization(new SimpleControlFlow(context, method).SimplifyShortCircuit);

                    if (abortBeforeStep == ILAstOptimizationStep.SimplifyTernaryOperator)
                    {
                        return;
                    }
                    modified |= block.RunOptimization(new SimpleControlFlow(context, method).SimplifyTernaryOperator);

                    if (abortBeforeStep == ILAstOptimizationStep.SimplifyNullCoalescing)
                    {
                        return;
                    }
                    modified |= block.RunOptimization(new SimpleControlFlow(context, method).SimplifyNullCoalescing);

                    if (abortBeforeStep == ILAstOptimizationStep.JoinBasicBlocks)
                    {
                        return;
                    }
                    modified |= block.RunOptimization(new SimpleControlFlow(context, method).JoinBasicBlocks);

                    if (abortBeforeStep == ILAstOptimizationStep.SimplifyLogicNot)
                    {
                        return;
                    }
                    modified |= block.RunOptimization(SimplifyLogicNot);

                    if (abortBeforeStep == ILAstOptimizationStep.SimplifyShiftOperators)
                    {
                        return;
                    }
                    modified |= block.RunOptimization(SimplifyShiftOperators);

                    if (abortBeforeStep == ILAstOptimizationStep.TypeConversionSimplifications)
                    {
                        return;
                    }
                    modified |= block.RunOptimization(TypeConversionSimplifications);

                    if (abortBeforeStep == ILAstOptimizationStep.SimplifyLdObjAndStObj)
                    {
                        return;
                    }
                    modified |= block.RunOptimization(SimplifyLdObjAndStObj);

                    if (abortBeforeStep == ILAstOptimizationStep.SimplifyCustomShortCircuit)
                    {
                        return;
                    }
                    modified |= block.RunOptimization(new SimpleControlFlow(context, method).SimplifyCustomShortCircuit);

                    if (abortBeforeStep == ILAstOptimizationStep.SimplifyLiftedOperators)
                    {
                        return;
                    }
                    modified |= block.RunOptimization(SimplifyLiftedOperators);

                    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;
                    }
                    if (context.Settings.MakeAssignmentExpressions)
                    {
                        modified |= block.RunOptimization(MakeAssignmentExpression);
                    }
                    modified |= block.RunOptimization(MakeCompoundAssignments);

                    if (abortBeforeStep == ILAstOptimizationStep.IntroducePostIncrement)
                    {
                        return;
                    }
                    if (context.Settings.IntroduceIncrementAndDecrement)
                    {
                        modified |= block.RunOptimization(IntroducePostIncrement);
                    }

                    if (abortBeforeStep == ILAstOptimizationStep.InlineExpressionTreeParameterDeclarations)
                    {
                        return;
                    }
                    if (context.Settings.ExpressionTrees)
                    {
                        modified |= block.RunOptimization(InlineExpressionTreeParameterDeclarations);
                    }

                    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 <ILBlock>())
            {
                new LoopsAndConditions(context).FindLoops(block);
            }

            if (abortBeforeStep == ILAstOptimizationStep.FindConditions)
            {
                return;
            }
            foreach (ILBlock block in method.GetSelfAndChildrenRecursive <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;
            }
            if (context.Settings.AnonymousMethods)
            {
                foreach (ILBlock block in method.GetSelfAndChildrenRecursive <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);
        }
Esempio n. 4
0
        /// <summary>
        /// Removes redundatant Br, Nop, Dup, Pop
        /// Ignore arguments of 'leave'
        /// </summary>
        /// <param name="method"></param>
        internal static void RemoveRedundantCode(ILBlock method)
        {
            Dictionary <ILLabel, int> labelRefCount = new Dictionary <ILLabel, int>();

            foreach (ILLabel target in method.GetSelfAndChildrenRecursive <ILExpression>(e => e.IsBranch()).SelectMany(e => e.GetBranchTargets()))
            {
                labelRefCount[target] = labelRefCount.GetOrDefault(target) + 1;
            }

            foreach (ILBlock block in method.GetSelfAndChildrenRecursive <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
                    {
                        ILLabel label = body[i] as ILLabel;
                        if (label != null)
                        {
                            if (labelRefCount.GetOrDefault(label) > 0)
                            {
                                newBody.Add(label);
                            }
                        }
                        else
                        {
                            newBody.Add(body[i]);
                        }
                    }
                }
                block.Body = newBody;
            }

            // Ignore arguments of 'leave'
            foreach (ILExpression expr in method.GetSelfAndChildrenRecursive <ILExpression>(e => e.Code == ILCode.Leave))
            {
                if (expr.Arguments.Any(arg => !arg.Match(ILCode.Ldloc)))
                {
                    throw new Exception("Leave should have just ldloc at this stage");
                }
                expr.Arguments.Clear();
            }

            // 'dup' removal
            foreach (ILExpression expr in method.GetSelfAndChildrenRecursive <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;
                    }
                }
            }
        }