Пример #1
0
        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;
                }
            }
        }
        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);
        }
        void ConstructExceptionTable()
        {
            disposeMethod = enumeratorType.Methods.FirstOrDefault(m => m.Name == "System.IDisposable.Dispose");
            ILBlock ilMethod = CreateILAst(disposeMethod);

            finallyMethodToStateInterval = new Dictionary <MethodDefinition, Interval>();

            InitStateRanges(ilMethod.Body[0]);
            AssignStateRanges(ilMethod.Body, ilMethod.Body.Count, forDispose: true);

            // Now look at the finally blocks:
            foreach (var tryFinally in ilMethod.EnumerateSelfAndChildrenRecursive().OfType <ILTryCatchBlock>())
            {
                Interval interval    = ranges[tryFinally.TryBlock.Body[0]].ToEnclosingInterval();
                var      finallyBody = tryFinally.FinallyBlock.Body;
                if (finallyBody.Count != 2)
                {
                    throw new YieldAnalysisFailedException();
                }
                ILExpression call = finallyBody[0] as ILExpression;
                if (call == null || call.Code != ILCode.Call || call.Arguments.Count != 1)
                {
                    throw new YieldAnalysisFailedException();
                }
                if (!call.Arguments[0].MatchThis())
                {
                    throw new YieldAnalysisFailedException();
                }
                if (!finallyBody[1].Match(ILCode.Endfinally))
                {
                    throw new YieldAnalysisFailedException();
                }

                MethodDefinition mdef = GetMethodDefinition(call.Operand as MethodReference);
                if (mdef == null || finallyMethodToStateInterval.ContainsKey(mdef))
                {
                    throw new YieldAnalysisFailedException();
                }
                finallyMethodToStateInterval.Add(mdef, interval);
            }
            ranges = null;
        }
        ILBlock ConvertFinallyBlock(MethodDefinition finallyMethod)
        {
            ILBlock block = CreateILAst(finallyMethod);
            // Get rid of assignment to state
            FieldReference      stfld;
            List <ILExpression> args;

            if (block.Body.Count > 0 && block.Body[0].Match(ILCode.Stfld, out stfld, out args))
            {
                if (GetFieldDefinition(stfld) == stateField && args[0].MatchThis())
                {
                    block.Body.RemoveAt(0);
                }
            }
            // Convert ret to endfinally
            foreach (ILExpression expr in block.EnumerateSelfAndChildrenRecursive().OfType <ILExpression>())
            {
                if (expr.Code == ILCode.Ret)
                {
                    expr.Code = ILCode.Endfinally;
                }
            }
            return(block);
        }
        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 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);
        }