/// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(DecompilerContext context, AstBlock ast, AssemblyCompiler compiler)
        {
            // Convert stobj/stind_ref
            foreach (var node in ast.GetExpressions(x => (x.Arguments.Count == 2) && ((x.Code == AstCode.Stobj) || (x.Code == AstCode.Stind_Ref))))
            {
                var addrNode  = node.Arguments[0];
                var valueNode = node.Arguments[1];

                AstVariable variable;
                if ((addrNode.GetResultType().IsByReference) && addrNode.Match(AstCode.Ldloc, out variable))
                {
                    if (variable.IsThis && valueNode.Match(AstCode.DefaultValue))
                    {
                        // Struct init : this()
                        node.CopyFrom(new AstExpression(node.SourceLocation, AstCode.Nop, null));
                    }
                    else if (!variable.IsThis)
                    {
                        // Convert byref type to array type
                        var addrType  = (XByReferenceType)addrNode.GetResultType();
                        var arrayType = new XArrayType(addrType.ElementType);
                        addrNode.ExpectedType = arrayType;
                        addrNode.InferredType = arrayType;

                        // Convert to stelem array, index, value
                        var int32Type = compiler.Module.TypeSystem.Int;
                        node.Arguments.Insert(1, new AstExpression(node.SourceLocation, AstCode.Ldc_I4, 0).SetType(int32Type));
                        node.Code = arrayType.ElementType.GetStElemCode();
                    }
                    else
                    {
                        // Convert to stloc
                    }
                }
            }

            // Convert ldobj
            var resetTypes = false;
            var processed  = new HashSet <AstExpression>();

            foreach (var pair in ast.GetExpressionPairs())
            {
                var node = pair.Expression;
                if ((node.Arguments.Count == 1) && ((node.Code == AstCode.Ldobj) || (node.Code == AstCode.Ldind_Ref)))
                {
                    var parent         = pair.Parent;
                    var useAsValue     = true;
                    var isCallArgument = (parent != null) && (parent.Code.IsCall());
                    var isBoxArgument  = (parent != null) && (parent.Match(AstCode.Box));
                    if (isCallArgument && (node.Code == AstCode.Ldobj))
                    {
                        if (IsArgByRefOrOut(node, parent))
                        {
                            useAsValue = false;
                        }
                    }

                    if (isBoxArgument)
                    {
                        var boxType = (XTypeReference)parent.Operand;
                        if (!boxType.IsGenericParameter)
                        {
                            useAsValue = false;
                        }
                    }

                    var ldlocNode = node.Arguments[0];
                    processed.Add(ldlocNode);
                    var addrNodeType = ldlocNode.GetResultType();

                    if (ldlocNode.MatchThis())
                    {
                        useAsValue = false;
                    }

                    if (useAsValue)
                    {
                        if ((addrNodeType.IsByReference) && (ldlocNode.Code == AstCode.Ldloc))
                        {
                            // Convert byref type to array type
                            var addrType  = (XByReferenceType)ldlocNode.GetResultType();
                            var arrayType = new XArrayType(addrType.ElementType);
                            ldlocNode.ExpectedType = arrayType;
                            ldlocNode.InferredType = arrayType;

                            // Convert to ldelem array, index, value
                            var int32Type = compiler.Module.TypeSystem.Int;
                            node.Arguments.Insert(1, new AstExpression(node.SourceLocation, AstCode.Ldc_I4, 0).SetType(int32Type));
                            node.Code = arrayType.ElementType.GetLdElemCode();
                            node.SetType(arrayType.ElementType);
                            resetTypes = true;
                        }
                    }
                    else if (isCallArgument && (ldlocNode.Code == AstCode.Ldloc))
                    {
                        var             typeRef = (XTypeReference)node.Operand;
                        XTypeDefinition typeDef;
                        if ((typeRef != null) && typeRef.TryResolve(out typeDef) && typeDef.IsValueType &&
                            !typeDef.IsPrimitive)
                        {
                            // Replace by ldloc
                            node.Code    = AstCode.Ldloc;
                            node.Operand = ldlocNode.Operand;
                            node.Arguments.Clear();
                        }
                    }
                }
                else if ((node.Code == AstCode.Ldloc) && ((AstVariable)node.Operand).IsParameter && (node.GetResultType().IsByReference))
                {
                    var parent = pair.Parent;
                    if ((parent != null) && (parent.Code == AstCode.Ldobj))
                    {
                        continue;
                    }
                    var useAsValue     = true;
                    var isCallArgument = (parent != null) && (parent.Code.IsCall());
                    var isBoxArgument  = (parent != null) && (parent.Match(AstCode.Box));
                    if (isCallArgument)
                    {
                        if (IsArgByRefOrOut(node, parent))
                        {
                            useAsValue = false;
                        }
                    }

                    if (isBoxArgument)
                    {
                        useAsValue = false;
                    }

                    if (node.MatchThis())
                    {
                        useAsValue = false;
                    }

                    if (useAsValue)
                    {
                        // Convert byref type to array type
                        var addrType  = (XByReferenceType)node.GetResultType();
                        var arrayType = new XArrayType(addrType.ElementType);
                        var clone     = new AstExpression(node).SetType(arrayType);

                        // Convert to ldelem array, index, value
                        var int32Type = compiler.Module.TypeSystem.Int;
                        node.SetArguments(clone, new AstExpression(node.SourceLocation, AstCode.Ldc_I4, 0).SetType(int32Type));
                        node.Code = arrayType.ElementType.GetLdElemCode();
                        node.SetType(arrayType.ElementType);
                        resetTypes = true;
                    }
                }
            }

            if (resetTypes)
            {
                TypeAnalysis.Run(context, ast);
            }
        }
Exemple #2
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);

            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.TransformDecimalCtorToConstant)
                    {
                        return;
                    }
                    modified |= block.RunOptimization(TransformDecimalCtorToConstant);
                    modified |= block.RunOptimization(SimplifyLdcI4ConvI8);

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

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

                    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 <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.RemoveRedundantCode2)
            {
                return;
            }
            RemoveRedundantCode(method);

            if (abortBeforeStep == ILAstOptimizationStep.GotoRemoval)
            {
                return;
            }
            new GotoRemoval().RemoveGotos(method);

            if (abortBeforeStep == ILAstOptimizationStep.DuplicateReturns)
            {
                return;
            }
            DuplicateReturnStatements(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 <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);
        }
Exemple #3
0
        public void Optimize(AstOptimizationStep abortBeforeStep = AstOptimizationStep.None)
        {
            if (abortBeforeStep == AstOptimizationStep.RemoveRedundantCode)
            {
                return;
            }
            RemoveRedundantCode(method);

            if (abortBeforeStep == AstOptimizationStep.ReduceBranchInstructionSet)
            {
                return;
            }
            foreach (AstBlock block in method.GetSelfAndChildrenRecursive <AstBlock>())
            {
                ReduceBranchInstructionSet(block);
            }
            // ReduceBranchInstructionSet runs before inlining because the non-aggressive inlining heuristic
            // looks at which type of instruction consumes the inlined variable.

            if (abortBeforeStep == AstOptimizationStep.InlineVariables)
            {
                return;
            }
            // Works better after simple goto removal because of the following debug pattern: stloc X; br Next; Next:; ldloc X
            var inlining1 = new AstInlining(method);

            inlining1.InlineAllVariables();

            if (abortBeforeStep == AstOptimizationStep.CopyPropagation)
            {
                return;
            }
            inlining1.CopyPropagation();

            if (abortBeforeStep == AstOptimizationStep.SplitToMovableBlocks)
            {
                return;
            }
            foreach (var block in method.GetSelfAndChildrenRecursive <AstBlock>())
            {
                SplitToBasicBlocks(block);
            }

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

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

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

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

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

                    if (abortBeforeStep == AstOptimizationStep.TransformDecimalCtorToConstant)
                    {
                        return;
                    }
                    modified |= block.RunOptimization(TransformDecimalCtorToConstant);
                    modified |= block.RunOptimization(SimplifyLdcI4ConvI8);

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

                    if (abortBeforeStep == AstOptimizationStep.TransformArrayInitializers)
                    {
                        return;
                    }
                    modified |= block.RunOptimization(TransformArrayInitializers);

                    if (abortBeforeStep == AstOptimizationStep.TransformMultidimensionalArrayInitializers)
                    {
                        return;
                    }
                    modified |= block.RunOptimization(TransformMultidimensionalArrayInitializers);

                    if (abortBeforeStep == AstOptimizationStep.MakeAssignmentExpression)
                    {
                        return;
                    }
                    modified |= block.RunOptimization(MakeAssignmentExpression);
#if COMPOUNDASSIGNMENT
                    modified |= block.RunOptimization(MakeCompoundAssignments);
#endif

#if POSTINCREMENT
                    if (abortBeforeStep == AstOptimizationStep.IntroducePostIncrement)
                    {
                        return;
                    }
                    modified |= block.RunOptimization(IntroducePostIncrement);
#endif

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

                    if (abortBeforeStep == AstOptimizationStep.InlineVariables2)
                    {
                        return;
                    }
                    modified |= new AstInlining(method).InlineAllInBlock(block);
                    new AstInlining(method).CopyPropagation();
                } while (modified);
            }

            /*if (abortBeforeStep == AstOptimizationStep.FindLoops) return;
             * foreach (AstBlock block in method.GetSelfAndChildrenRecursive<AstBlock>())
             * {
             *  new LoopsAndConditions(context).FindLoops(block);
             * }
             */

            /*if (abortBeforeStep == AstOptimizationStep.FindConditions) return;
             * foreach (AstBlock block in method.GetSelfAndChildrenRecursive<AstBlock>())
             * {
             *  new LoopsAndConditions(context).FindConditions(block);
             * }*/

            if (abortBeforeStep == AstOptimizationStep.FlattenNestedMovableBlocks)
            {
                return;
            }
            FlattenBasicBlocks(method);

            if (abortBeforeStep == AstOptimizationStep.RemoveEndFinally)
            {
                return;
            }
            RemoveEndFinally(method);

            if (abortBeforeStep == AstOptimizationStep.RemoveRedundantCode2)
            {
                return;
            }
            RemoveRedundantCode(method);

            if (abortBeforeStep == AstOptimizationStep.GotoRemoval)
            {
                return;
            }
            new GotoRemoval().RemoveGotos(method);

            if (abortBeforeStep == AstOptimizationStep.DuplicateReturns)
            {
                return;
            }
            DuplicateReturnStatements(method);

            if (abortBeforeStep == AstOptimizationStep.GotoRemoval2)
            {
                return;
            }
            new GotoRemoval().RemoveGotos(method);

            if (abortBeforeStep == AstOptimizationStep.InlineVariables3)
            {
                return;
            }
            // The 2nd inlining pass is necessary because DuplicateReturns and the introduction of ternary operators
            // open up additional inlining possibilities.
            new AstInlining(method).InlineAllVariables();

            if (abortBeforeStep == AstOptimizationStep.RecombineVariables)
            {
                return;
            }
            //RecombineVariables(method); // We do not recombine variables because the RL code depends on it.

            if (abortBeforeStep == AstOptimizationStep.TypeInference2)
            {
                return;
            }
            TypeAnalysis.Reset(method);
            TypeAnalysis.Run(context, method);

            if (abortBeforeStep == AstOptimizationStep.RemoveRedundantCode3)
            {
                return;
            }
            GotoRemoval.RemoveRedundantCode(method);

            // ReportUnassignedILRanges(method);
        }