Пример #1
0
        /// <summary>
        /// Reduces the branch codes to just br and brtrue.
        /// Moves ILRanges to the branch argument
        /// </summary>
        void ReduceBranchInstructionSet(ILBlock block)
        {
            for (int i = 0; i < block.Body.Count; i++)
            {
                ILExpression expr = block.Body[i] as ILExpression;
                if (expr != null && expr.Prefixes == null)
                {
                    switch (expr.Code)
                    {
                    case ILCode.Switch:
                    case ILCode.Brtrue:
                        expr.Arguments.Single().ILRanges.AddRange(expr.ILRanges);
                        expr.ILRanges.Clear();
                        continue;

                    case ILCode.__Brfalse:  block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, expr.Arguments.Single())); break;

                    case ILCode.__Beq:      block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Ceq, null, expr.Arguments)); break;

                    case ILCode.__Bne_Un:   block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Ceq, null, expr.Arguments))); break;

                    case ILCode.__Bgt:      block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Cgt, null, expr.Arguments)); break;

                    case ILCode.__Bgt_Un:   block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Cgt_Un, null, expr.Arguments)); break;

                    case ILCode.__Ble:      block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Cgt, null, expr.Arguments))); break;

                    case ILCode.__Ble_Un:   block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Cgt_Un, null, expr.Arguments))); break;

                    case ILCode.__Blt:      block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Clt, null, expr.Arguments)); break;

                    case ILCode.__Blt_Un:   block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Clt_Un, null, expr.Arguments)); break;

                    case ILCode.__Bge:          block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Clt, null, expr.Arguments))); break;

                    case ILCode.__Bge_Un:   block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Clt_Un, null, expr.Arguments))); break;

                    default:
                        continue;
                    }
                    ((ILExpression)block.Body[i]).Arguments.Single().ILRanges.AddRange(expr.ILRanges);
                }
            }
        }
Пример #2
0
        /// <summary>
        /// Flattens all nested basic blocks, except the the top level 'node' argument
        /// </summary>
        void FlattenBasicBlocks(ILNode node)
        {
            ILBlock block = node as ILBlock;

            if (block != null)
            {
                List <ILNode> flatBody = new List <ILNode>();
                foreach (ILNode child in block.GetChildren())
                {
                    FlattenBasicBlocks(child);
                    ILBasicBlock childAsBB = child as ILBasicBlock;
                    if (childAsBB != null)
                    {
                        if (!(childAsBB.Body.FirstOrDefault() is ILLabel))
                        {
                            throw new Exception("Basic block has to start with a label. \n" + childAsBB.ToString());
                        }
                        if (childAsBB.Body.LastOrDefault() is ILExpression && !childAsBB.Body.LastOrDefault().IsUnconditionalControlFlow())
                        {
                            throw new Exception("Basci block has to end with unconditional control flow. \n" + childAsBB.ToString());
                        }
                        flatBody.AddRange(childAsBB.GetChildren());
                    }
                    else
                    {
                        flatBody.Add(child);
                    }
                }
                block.EntryGoto = null;
                block.Body      = flatBody;
            }
            else if (node is ILExpression)
            {
                // Optimization - no need to check expressions
            }
            else if (node != null)
            {
                // Recursively find all ILBlocks
                foreach (ILNode child in node.GetChildren())
                {
                    FlattenBasicBlocks(child);
                }
            }
        }
Пример #3
0
        public bool InlineAllInBlock(ILBlock block)
        {
            bool          modified = false;
            List <ILNode> body     = block.Body;

            if (block is ILTryCatchBlock.CatchBlock && body.Count > 1)
            {
                ILVariable v = ((ILTryCatchBlock.CatchBlock)block).ExceptionVariable;
                if (v != null && v.GeneratedByDecompiler)
                {
                    if (numLdloca.GetOrDefault(v) == 0 && numStloc.GetOrDefault(v) == 1 && numLdloc.GetOrDefault(v) == 1)
                    {
                        ILVariable   v2;
                        ILExpression ldException;
                        if (body[0].Match(ILCode.Stloc, out v2, out ldException) && ldException.MatchLdloc(v))
                        {
                            body[0].AddSelfAndChildrenRecursiveILRanges(((ILTryCatchBlock.CatchBlock)block).StlocILRanges);
                            body.RemoveAt(0);
                            ((ILTryCatchBlock.CatchBlock)block).ExceptionVariable = v2;
                            modified = true;
                        }
                    }
                }
            }
            for (int i = 0; i < body.Count - 1;)
            {
                ILVariable   locVar;
                ILExpression expr;
                if (body[i].Match(ILCode.Stloc, out locVar, out expr) && InlineOneIfPossible(block, block.Body, i, aggressive: false))
                {
                    modified = true;
                    i        = Math.Max(0, i - 1);              // Go back one step
                }
                else
                {
                    i++;
                }
            }
            foreach (ILBasicBlock bb in body.OfType <ILBasicBlock>())
            {
                modified |= InlineAllInBasicBlock(bb);
            }
            return(modified);
        }
Пример #4
0
        /// <summary>
        /// Converts call and callvirt instructions that read/write properties into CallGetter/CallSetter instructions.
        ///
        /// CallGetter/CallSetter is used to allow the ILAst to represent "while ((SomeProperty = value) != null)".
        /// </summary>
        void IntroducePropertyAccessInstructions(ILBlock method)
        {
            foreach (ILExpression expr in method.GetSelfAndChildrenRecursive <ILExpression>())
            {
                if (expr.Code == ILCode.Call || expr.Code == ILCode.Callvirt)
                {
                    MethodReference cecilMethod = (MethodReference)expr.Operand;
                    if (cecilMethod.DeclaringType is ArrayType)
                    {
                        switch (cecilMethod.Name)
                        {
                        case "Get":
                            expr.Code = ILCode.CallGetter;
                            break;

                        case "Set":
                            expr.Code = ILCode.CallSetter;
                            break;

                        case "Address":
                            expr.Code = ILCode.CallGetter;
                            expr.AddPrefix(new ILExpressionPrefix(ILCode.PropertyAddress));
                            break;
                        }
                    }
                    else
                    {
                        MethodDefinition cecilMethodDef = cecilMethod.Resolve();
                        if (cecilMethodDef != null)
                        {
                            if (cecilMethodDef.IsGetter)
                            {
                                expr.Code = (expr.Code == ILCode.Call) ? ILCode.CallGetter : ILCode.CallvirtGetter;
                            }
                            else if (cecilMethodDef.IsSetter)
                            {
                                expr.Code = (expr.Code == ILCode.Call) ? ILCode.CallSetter : ILCode.CallvirtSetter;
                            }
                        }
                    }
                }
            }
        }
        public static void Run(DecompilerContext context, ILBlock method)
        {
            if (!context.Settings.YieldReturn)
            {
                return; // abort if enumerator decompilation is disabled
            }
            var yrd = new YieldReturnDecompiler();

            yrd.context = context;
            if (!yrd.MatchEnumeratorCreationPattern(method))
            {
                return;
            }
            yrd.enumeratorType = yrd.enumeratorCtor.DeclaringType;
#if DEBUG
            if (Debugger.IsAttached)
            {
                yrd.Run();
            }
            else
            {
#endif
            try
            {
                yrd.Run();
            }
            catch (SymbolicAnalysisFailedException)
            {
                return;
            }
#if DEBUG
        }
#endif
            method.Body.Clear();
            method.EntryGoto = null;
            method.Body.AddRange(yrd.newBody);

            // Repeat the inlining/copy propagation optimization because the conversion of field access
            // to local variables can open up additional inlining possibilities.
            ILInlining inlining = new ILInlining(method);
            inlining.InlineAllVariables();
            inlining.CopyPropagation();
        }
        void ConstructExceptionTable()
        {
            disposeMethod = enumeratorType.Methods.FirstOrDefault(m => m.Name == "System.IDisposable.Dispose");
            ILBlock ilMethod = CreateILAst(disposeMethod);

            var rangeAnalysis = new StateRangeAnalysis(ilMethod.Body[0], StateRangeAnalysisMode.IteratorDispose, stateField);

            rangeAnalysis.AssignStateRanges(ilMethod.Body, ilMethod.Body.Count);
            finallyMethodToStateInterval = rangeAnalysis.finallyMethodToStateInterval;

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

                MethodDefinition mdef = GetMethodDefinition(call.Operand as MethodReference);
                if (mdef == null || finallyMethodToStateInterval.ContainsKey(mdef))
                {
                    throw new SymbolicAnalysisFailedException();
                }
                finallyMethodToStateInterval.Add(mdef, interval);
            }
            rangeAnalysis = null;
        }
        /// <summary>
        /// Looks at the enumerator's get_Current method and figures out which of the fields holds the current value.
        /// </summary>
        void AnalyzeCurrentProperty()
        {
            MethodDefinition getCurrentMethod = enumeratorType.Methods.FirstOrDefault(
                m => m.Name.StartsWith("System.Collections.Generic.IEnumerator", StringComparison.Ordinal) &&
                m.Name.EndsWith(".get_Current", StringComparison.Ordinal));
            ILBlock method = CreateILAst(getCurrentMethod);

            if (method.Body.Count == 1)
            {
                // release builds directly return the current field
                ILExpression   retExpr;
                FieldReference field;
                ILExpression   ldFromObj;
                if (method.Body[0].Match(ILCode.Ret, out retExpr) &&
                    retExpr.Match(ILCode.Ldfld, out field, out ldFromObj) &&
                    ldFromObj.MatchThis())
                {
                    currentField = GetFieldDefinition(field);
                }
            }
            else if (method.Body.Count == 2)
            {
                ILVariable     v, v2;
                ILExpression   stExpr;
                FieldReference field;
                ILExpression   ldFromObj;
                ILExpression   retExpr;
                if (method.Body[0].Match(ILCode.Stloc, out v, out stExpr) &&
                    stExpr.Match(ILCode.Ldfld, out field, out ldFromObj) &&
                    ldFromObj.MatchThis() &&
                    method.Body[1].Match(ILCode.Ret, out retExpr) &&
                    retExpr.Match(ILCode.Ldloc, out v2) &&
                    v == v2)
                {
                    currentField = GetFieldDefinition(field);
                }
            }
            if (currentField == null)
            {
                throw new SymbolicAnalysisFailedException();
            }
        }
Пример #8
0
        public void RemoveGotos(ILBlock method)
        {
            // Build the navigation data
            parent[method] = null;
            foreach (ILNode node in method.GetSelfAndChildrenRecursive <ILNode>())
            {
                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 list = method.GetSelfAndChildrenRecursive <ILExpression>(e => e.Code == ILCode.Br || e.Code == ILCode.Leave);
                for (int i = list.Count - 1; i >= 0; i--)
                {
                    var gotoExpr = list[i];
                    modified |= TrySimplifyGoto(gotoExpr);
                }
            } while(modified);

            RemoveRedundantCode(method);
        }
Пример #9
0
        public static void Run(DecompilerContext context, ILBlock method, List <ILNode> list_ILNode, Func <ILBlock, ILInlining> getILInlining)
        {
            if (!context.Settings.YieldReturn)
            {
                return;                 // abort if enumerator decompilation is disabled
            }
            var yrd = new YieldReturnDecompiler();

            yrd.context = context;
            if (!yrd.MatchEnumeratorCreationPattern(method))
            {
                return;
            }
            yrd.enumeratorType = yrd.enumeratorCtor.DeclaringType;
                        #if DEBUG && CRASH_IN_DEBUG_MODE
            if (Debugger.IsAttached)
            {
                yrd.Run();
            }
            else
            {
                                #endif
            try {
                yrd.Run();
            } catch (SymbolicAnalysisFailedException) {
                return;
            }
                                #if DEBUG && CRASH_IN_DEBUG_MODE
        }
                        #endif
            method.Body.Clear();
            method.EntryGoto = null;
            method.Body.AddRange(yrd.newBody);            //TODO: Make sure that the removed ILRanges from Clear() above is saved in the new body

            // Repeat the inlining/copy propagation optimization because the conversion of field access
            // to local variables can open up additional inlining possibilities.
            var inlining = getILInlining(method);
            inlining.InlineAllVariables();
            inlining.CopyPropagation(list_ILNode);
        }
Пример #10
0
        void RecombineVariables(ILBlock method)
        {
            // Recombine variables that were split when the ILAst was created
            // This ensures that a single IL variable is a single C# variable (gets assigned only one name)
            // The DeclareVariables transformation might then split up the C# variable again if it is used indendently in two separate scopes.
            Dictionary <VariableDefinition, ILVariable> dict = new Dictionary <VariableDefinition, ILVariable>();

            foreach (ILExpression expr in method.GetSelfAndChildrenRecursive <ILExpression>())
            {
                ILVariable v = expr.Operand as ILVariable;
                if (v != null && v.OriginalVariable != null)
                {
                    ILVariable combinedVariable;
                    if (!dict.TryGetValue(v.OriginalVariable, out combinedVariable))
                    {
                        dict.Add(v.OriginalVariable, v);
                        combinedVariable = v;
                    }
                    expr.Operand = combinedVariable;
                }
            }
        }
Пример #11
0
 /// <summary>
 /// Replace endfinally with jump to the end of the finally block
 /// </summary>
 void RemoveEndFinally(ILBlock method)
 {
     // Go thought the list in reverse so that we do the nested blocks first
     foreach (var tryCatch in method.GetSelfAndChildrenRecursive <ILTryCatchBlock>(tc => tc.FinallyBlock != null).Reverse())
     {
         ILLabel label = new ILLabel()
         {
             Name = "EndFinally_" + nextLabelIndex++
         };
         tryCatch.FinallyBlock.Body.Add(label);
         foreach (var block in tryCatch.FinallyBlock.GetSelfAndChildrenRecursive <ILBlock>())
         {
             for (int i = 0; i < block.Body.Count; i++)
             {
                 if (block.Body[i].Match(ILCode.Endfinally))
                 {
                     block.Body[i] = new ILExpression(ILCode.Br, label).WithILRanges(((ILExpression)block.Body[i]).ILRanges);
                 }
             }
         }
     }
 }
        public static void RunStep1(DecompilerContext context, ILBlock method)
        {
            if (!context.Settings.AsyncAwait)
            {
                return; // abort if async decompilation is disabled
            }
            var yrd = new AsyncDecompiler();

            yrd.context = context;
            if (!yrd.MatchTaskCreationPattern(method))
            {
                return;
            }
#if DEBUG
            if (Debugger.IsAttached)
            {
                yrd.Run();
            }
            else
            {
#endif
            try
            {
                yrd.Run();
            }
            catch (SymbolicAnalysisFailedException)
            {
                return;
            }
#if DEBUG
        }
#endif
            context.CurrentMethodIsAsync = true;

            method.Body.Clear();
            method.EntryGoto = null;
            method.Body.AddRange(yrd.newTopLevelBody);
            ILAstOptimizer.RemoveRedundantCode(method);
        }
        /// <summary>
        /// Looks at the enumerator's ctor and figures out which of the fields holds the state.
        /// </summary>
        void AnalyzeCtor()
        {
            ILBlock method = CreateILAst(enumeratorCtor);

            foreach (ILNode node in method.Body)
            {
                FieldReference field;
                ILExpression   instExpr;
                ILExpression   stExpr;
                ILVariable     arg;
                if (node.Match(ILCode.Stfld, out field, out instExpr, out stExpr) &&
                    instExpr.MatchThis() &&
                    stExpr.Match(ILCode.Ldloc, out arg) &&
                    arg.IsParameter && arg.OriginalParameter.Index == 0)
                {
                    stateField = GetFieldDefinition(field);
                }
            }
            if (stateField == null)
            {
                throw new SymbolicAnalysisFailedException();
            }
        }
Пример #14
0
        void RecombineVariables(ILBlock method)
        {
            // Recombine variables that were split when the ILAst was created
            // This ensures that a single IL variable is a single C# variable (gets assigned only one name)
            // The DeclareVariables transformation might then split up the C# variable again if it is used indendently in two separate scopes.
            Dictionary <VariableDefinition, ILVariable> dict = new Dictionary <VariableDefinition, ILVariable>();

            ReplaceVariables(
                method,
                delegate(ILVariable v) {
                if (v.OriginalVariable == null)
                {
                    return(v);
                }
                ILVariable combinedVariable;
                if (!dict.TryGetValue(v.OriginalVariable, out combinedVariable))
                {
                    dict.Add(v.OriginalVariable, v);
                    combinedVariable = v;
                }
                return(combinedVariable);
            });
        }
        void AnalyzeStateMachine(ILBlock block)
        {
            var body = block.Body;

            if (body.Count == 0)
            {
                throw new SymbolicAnalysisFailedException();
            }
            if (DetectDoFinallyBodies(body))
            {
                body.RemoveAt(0);
                if (body.Count == 0)
                {
                    throw new SymbolicAnalysisFailedException();
                }
            }
            StateRangeAnalysis rangeAnalysis = new StateRangeAnalysis(body[0], StateRangeAnalysisMode.AsyncMoveNext, stateField);
            int bodyLength = block.Body.Count;
            int pos        = rangeAnalysis.AssignStateRanges(body, bodyLength);

            rangeAnalysis.EnsureLabelAtPos(body, ref pos, ref bodyLength);

            var labelStateRangeMapping = rangeAnalysis.CreateLabelRangeMapping(body, pos, bodyLength);

            newTopLevelBody = ConvertBody(body, pos, bodyLength, labelStateRangeMapping);
            newTopLevelBody.Insert(0, MakeGoTo(labelStateRangeMapping, initialState));
            newTopLevelBody.Add(setResultAndExitLabel);
            if (methodType == AsyncMethodType.TaskOfT)
            {
                newTopLevelBody.Add(new ILExpression(ILCode.Ret, null, resultExpr));
            }
            else
            {
                newTopLevelBody.Add(new ILExpression(ILCode.Ret, 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.GetSelfAndChildrenRecursive <ILExpression>())
            {
                if (expr.Code == ILCode.Ret)
                {
                    expr.Code = ILCode.Endfinally;
                }
            }
            return(block);
        }
        void ResolveIEnumerableIEnumeratorFieldMapping()
        {
            MethodDefinition getEnumeratorMethod = enumeratorType.Methods.FirstOrDefault(
                m => m.Name.StartsWith("System.Collections.Generic.IEnumerable", StringComparison.Ordinal) &&
                m.Name.EndsWith(".GetEnumerator", StringComparison.Ordinal));

            if (getEnumeratorMethod == null)
            {
                return; // no mappings (maybe it's just an IEnumerator implementation?)
            }
            ILBlock method = CreateILAst(getEnumeratorMethod);

            foreach (ILNode node in method.Body)
            {
                FieldReference stField;
                ILExpression   stToObj;
                ILExpression   stExpr;
                FieldReference ldField;
                ILExpression   ldFromObj;
                if (node.Match(ILCode.Stfld, out stField, out stToObj, out stExpr) &&
                    stExpr.Match(ILCode.Ldfld, out ldField, out ldFromObj) &&
                    ldFromObj.MatchThis())
                {
                    FieldDefinition storedField = GetFieldDefinition(stField);
                    FieldDefinition loadedField = GetFieldDefinition(ldField);
                    if (storedField != null && loadedField != null)
                    {
                        ILVariable mappedParameter;
                        if (fieldToParameterMap.TryGetValue(loadedField, out mappedParameter))
                        {
                            fieldToParameterMap[storedField] = mappedParameter;
                        }
                    }
                }
            }
        }
Пример #18
0
        public static void RunStep1(DecompilerContext context, ILBlock method, List <ILExpression> listExpr, List <ILBlock> listBlock, Dictionary <ILLabel, int> labelRefCount)
        {
            if (!context.Settings.AsyncAwait)
            {
                return;                 // abort if async decompilation is disabled
            }
            var yrd = new AsyncDecompiler();

            yrd.context = context;
            if (!yrd.MatchTaskCreationPattern(method))
            {
                return;
            }
                        #if DEBUG
            if (Debugger.IsAttached)
            {
                yrd.Run();
            }
            else
            {
                                #endif
            try {
                yrd.Run();
            } catch (SymbolicAnalysisFailedException) {
                return;
            }
                                #if DEBUG
        }
                        #endif
            context.CurrentMethodIsAsync = true;

            method.Body.Clear();
            method.EntryGoto = null;
            method.Body.AddRange(yrd.newTopLevelBody);            //TODO: Make sure that the removed ILRanges from Clear() above is saved in the new body
            ILAstOptimizer.RemoveRedundantCode(method, listExpr, listBlock, labelRefCount);
        }
        void AnalyzeMoveNext()
        {
            MethodDefinition moveNextMethod = enumeratorType.Methods.FirstOrDefault(m => m.Name == "MoveNext");
            ILBlock          ilMethod       = CreateILAst(moveNextMethod);

            if (ilMethod.Body.Count == 0)
            {
                throw new SymbolicAnalysisFailedException();
            }
            ILExpression lastReturnArg;

            if (!ilMethod.Body.Last().Match(ILCode.Ret, out lastReturnArg))
            {
                throw new SymbolicAnalysisFailedException();
            }

            // There are two possibilities:
            if (lastReturnArg.Code == ILCode.Ldloc)
            {
                // a) the compiler uses a variable for returns (in debug builds, or when there are try-finally blocks)
                returnVariable = (ILVariable)lastReturnArg.Operand;
                returnLabel    = ilMethod.Body.ElementAtOrDefault(ilMethod.Body.Count - 2) as ILLabel;
                if (returnLabel == null)
                {
                    throw new SymbolicAnalysisFailedException();
                }
            }
            else
            {
                // b) the compiler directly returns constants
                returnVariable = null;
                returnLabel    = null;
                // In this case, the last return must return false.
                if (lastReturnArg.Code != ILCode.Ldc_I4 || (int)lastReturnArg.Operand != 0)
                {
                    throw new SymbolicAnalysisFailedException();
                }
            }

            ILTryCatchBlock tryFaultBlock = ilMethod.Body[0] as ILTryCatchBlock;
            List <ILNode>   body;
            int             bodyLength;

            if (tryFaultBlock != null)
            {
                // there are try-finally blocks
                if (returnVariable == null) // in this case, we must use a return variable
                {
                    throw new SymbolicAnalysisFailedException();
                }
                // must be a try-fault block:
                if (tryFaultBlock.CatchBlocks.Count != 0 || tryFaultBlock.FinallyBlock != null || tryFaultBlock.FaultBlock == null)
                {
                    throw new SymbolicAnalysisFailedException();
                }

                ILBlock faultBlock = tryFaultBlock.FaultBlock;
                // Ensure the fault block contains the call to Dispose().
                if (faultBlock.Body.Count != 2)
                {
                    throw new SymbolicAnalysisFailedException();
                }
                MethodReference disposeMethodRef;
                ILExpression    disposeArg;
                if (!faultBlock.Body[0].Match(ILCode.Call, out disposeMethodRef, out disposeArg))
                {
                    throw new SymbolicAnalysisFailedException();
                }
                if (GetMethodDefinition(disposeMethodRef) != disposeMethod || !disposeArg.MatchThis())
                {
                    throw new SymbolicAnalysisFailedException();
                }
                if (!faultBlock.Body[1].Match(ILCode.Endfinally))
                {
                    throw new SymbolicAnalysisFailedException();
                }

                body       = tryFaultBlock.TryBlock.Body;
                bodyLength = body.Count;
            }
            else
            {
                // no try-finally blocks
                body = ilMethod.Body;
                if (returnVariable == null)
                {
                    bodyLength = body.Count - 1; // all except for the return statement
                }
                else
                {
                    bodyLength = body.Count - 2; // all except for the return label and statement
                }
            }

            // Now verify that the last instruction in the body is 'ret(false)'
            if (returnVariable != null)
            {
                // If we don't have a return variable, we already verified that above.
                // If we do have one, check for 'stloc(returnVariable, ldc.i4(0))'

                // Maybe might be a jump to the return label after the stloc:
                ILExpression leave = body.ElementAtOrDefault(bodyLength - 1) as ILExpression;
                if (leave != null && (leave.Code == ILCode.Br || leave.Code == ILCode.Leave) && leave.Operand == returnLabel)
                {
                    bodyLength--;
                }
                ILExpression store0 = body.ElementAtOrDefault(bodyLength - 1) as ILExpression;
                if (store0 == null || store0.Code != ILCode.Stloc || store0.Operand != returnVariable)
                {
                    throw new SymbolicAnalysisFailedException();
                }
                if (store0.Arguments[0].Code != ILCode.Ldc_I4 || (int)store0.Arguments[0].Operand != 0)
                {
                    throw new SymbolicAnalysisFailedException();
                }

                bodyLength--; // don't conside the stloc instruction to be part of the body
            }
            // verify that the last element in the body is a label pointing to the 'ret(false)'
            returnFalseLabel = body.ElementAtOrDefault(bodyLength - 1) as ILLabel;
            if (returnFalseLabel == null)
            {
                throw new SymbolicAnalysisFailedException();
            }

            var rangeAnalysis = new StateRangeAnalysis(body[0], StateRangeAnalysisMode.IteratorMoveNext, stateField);
            int pos           = rangeAnalysis.AssignStateRanges(body, bodyLength);

            rangeAnalysis.EnsureLabelAtPos(body, ref pos, ref bodyLength);

            var labels = rangeAnalysis.CreateLabelRangeMapping(body, pos, bodyLength);

            ConvertBody(body, pos, bodyLength, labels);
        }
Пример #20
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);
                                }
                                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);
                            }
                        }
                    }
                }
            }
        }
Пример #21
0
 public SimpleControlFlow(DecompilerContext context, ILBlock method)
 {
     Initialize(context, method);
 }
Пример #22
0
        void CachedDelegateInitialization(ILBlock block, ref int i)
        {
            // if (logicnot(ldsfld(field))) {
            //     stsfld(field, newobj(Action::.ctor, ldnull(), ldftn(method)))
            // } else {
            // }
            // ...(..., ldsfld(field), ...)

            ILCondition c = block.Body[i] as ILCondition;

            if (c == null || c.Condition == null && c.TrueBlock == null || c.FalseBlock == null)
            {
                return;
            }
            if (!(c.TrueBlock.Body.Count == 1 && c.FalseBlock.Body.Count == 0))
            {
                return;
            }
            if (!c.Condition.Match(ILCode.LogicNot))
            {
                return;
            }
            ILExpression condition = c.Condition.Arguments.Single() as ILExpression;

            if (condition == null || condition.Code != ILCode.Ldsfld)
            {
                return;
            }
            FieldDefinition field = ((FieldReference)condition.Operand).ResolveWithinSameModule();             // field is defined in current assembly

            if (field == null || !field.IsCompilerGeneratedOrIsInCompilerGeneratedClass())
            {
                return;
            }
            ILExpression stsfld = c.TrueBlock.Body[0] as ILExpression;

            if (!(stsfld != null && stsfld.Code == ILCode.Stsfld && ((FieldReference)stsfld.Operand).ResolveWithinSameModule() == field))
            {
                return;
            }
            ILExpression newObj = stsfld.Arguments[0];

            if (!(newObj.Code == ILCode.Newobj && newObj.Arguments.Count == 2))
            {
                return;
            }
            if (newObj.Arguments[0].Code != ILCode.Ldnull)
            {
                return;
            }
            if (newObj.Arguments[1].Code != ILCode.Ldftn)
            {
                return;
            }
            MethodDefinition anonymousMethod = ((MethodReference)newObj.Arguments[1].Operand).ResolveWithinSameModule();             // method is defined in current assembly

            if (!Ast.Transforms.DelegateConstruction.IsAnonymousMethod(context, anonymousMethod))
            {
                return;
            }

            ILNode followingNode = block.Body.ElementAtOrDefault(i + 1);

            if (followingNode != null && followingNode.GetSelfAndChildrenRecursive <ILExpression>().Count(
                    e => e.Code == ILCode.Ldsfld && ((FieldReference)e.Operand).ResolveWithinSameModule() == field) == 1)
            {
                foreach (ILExpression parent in followingNode.GetSelfAndChildrenRecursive <ILExpression>())
                {
                    for (int j = 0; j < parent.Arguments.Count; j++)
                    {
                        if (parent.Arguments[j].Code == ILCode.Ldsfld && ((FieldReference)parent.Arguments[j].Operand).ResolveWithinSameModule() == field)
                        {
                            parent.Arguments[j] = newObj;
                            block.Body.RemoveAt(i);
                            i -= new ILInlining(method).InlineInto(block.Body, i, aggressive: true);
                            return;
                        }
                    }
                }
            }
        }
        bool MatchEnumeratorCreationPattern(ILBlock method)
        {
            if (method.Body.Count == 0)
            {
                return(false);
            }
            ILExpression newObj;

            if (method.Body.Count == 1)
            {
                // ret(newobj(...))
                if (method.Body[0].Match(ILCode.Ret, out newObj))
                {
                    return(MatchEnumeratorCreationNewObj(newObj, out enumeratorCtor));
                }
                else
                {
                    return(false);
                }
            }
            // stloc(var_1, newobj(..)
            ILVariable var1;

            if (!method.Body[0].Match(ILCode.Stloc, out var1, out newObj))
            {
                return(false);
            }
            if (!MatchEnumeratorCreationNewObj(newObj, out enumeratorCtor))
            {
                return(false);
            }

            int i;

            for (i = 1; i < method.Body.Count; i++)
            {
                // stfld(..., ldloc(var_1), ldloc(parameter))
                FieldReference storedField;
                ILExpression   ldloc, loadParameter;
                if (!method.Body[i].Match(ILCode.Stfld, out storedField, out ldloc, out loadParameter))
                {
                    break;
                }
                ILVariable loadedVar, loadedArg;
                if (!ldloc.Match(ILCode.Ldloc, out loadedVar) || !loadParameter.Match(ILCode.Ldloc, out loadedArg))
                {
                    return(false);
                }
                storedField = GetFieldDefinition(storedField);
                if (loadedVar != var1 || storedField == null || !loadedArg.IsParameter)
                {
                    return(false);
                }
                fieldToParameterMap[(FieldDefinition)storedField] = loadedArg;
            }
            ILVariable   var2;
            ILExpression ldlocForStloc2;

            if (i < method.Body.Count && method.Body[i].Match(ILCode.Stloc, out var2, out ldlocForStloc2))
            {
                // stloc(var_2, ldloc(var_1))
                if (ldlocForStloc2.Code != ILCode.Ldloc || ldlocForStloc2.Operand != var1)
                {
                    return(false);
                }
                i++;
            }
            else
            {
                // the compiler might skip the above instruction in release builds; in that case, it directly returns stloc.Operand
                var2 = var1;
            }
            ILExpression retArg;

            if (i < method.Body.Count && method.Body[i].Match(ILCode.Ret, out retArg))
            {
                // ret(ldloc(var_2))
                if (retArg.Code == ILCode.Ldloc && retArg.Operand == var2)
                {
                    return(true);
                }
            }
            return(false);
        }
Пример #24
0
 public ILInlining(ILBlock method)
 {
     this.method = method;
     AnalyzeMethod();
 }
Пример #25
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);
            }

            if (method.Body.Count > 0 && method.Body.Last().Match(ILCode.YieldBreak) && ((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);
            }
        }
Пример #26
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);
        }
        bool MatchTaskCreationPattern(ILBlock method)
        {
            if (method.Body.Count < 5)
            {
                return(false);
            }
            // Check the second-to-last instruction (the start call) first, as we can get the most information from that
            MethodReference startMethod;
            ILExpression    loadStartTarget, loadStartArgument;

            // call(AsyncTaskMethodBuilder::Start, ldloca(builder), ldloca(stateMachine))
            if (!method.Body[method.Body.Count - 2].Match(ILCode.Call, out startMethod, out loadStartTarget, out loadStartArgument))
            {
                return(false);
            }
            if (startMethod.Name != "Start" || startMethod.DeclaringType == null || startMethod.DeclaringType.Namespace != "System.Runtime.CompilerServices")
            {
                return(false);
            }
            switch (startMethod.DeclaringType.Name)
            {
            case "AsyncTaskMethodBuilder`1":
                methodType = AsyncMethodType.TaskOfT;
                break;

            case "AsyncTaskMethodBuilder":
                methodType = AsyncMethodType.Task;
                break;

            case "AsyncVoidMethodBuilder":
                methodType = AsyncMethodType.Void;
                break;

            default:
                return(false);
            }
            ILVariable stateMachineVar, builderVar;

            if (!loadStartTarget.Match(ILCode.Ldloca, out builderVar))
            {
                return(false);
            }
            if (!loadStartArgument.Match(ILCode.Ldloca, out stateMachineVar))
            {
                return(false);
            }

            stateMachineStruct = stateMachineVar.Type.ResolveWithinSameModule();
            if (stateMachineStruct == null || !stateMachineStruct.IsValueType)
            {
                return(false);
            }
            moveNextMethod = stateMachineStruct.Methods.FirstOrDefault(f => f.Name == "MoveNext");
            if (moveNextMethod == null)
            {
                return(false);
            }

            // Check third-to-last instruction (copy of builder):
            // stloc(builder, ldfld(StateMachine::<>t__builder, ldloca(stateMachine)))
            ILExpression loadBuilderExpr;

            if (!method.Body[method.Body.Count - 3].MatchStloc(builderVar, out loadBuilderExpr))
            {
                return(false);
            }
            FieldReference builderFieldRef;
            ILExpression   loadStateMachineForBuilderExpr;

            if (!loadBuilderExpr.Match(ILCode.Ldfld, out builderFieldRef, out loadStateMachineForBuilderExpr))
            {
                return(false);
            }
            if (!loadStateMachineForBuilderExpr.MatchLdloca(stateMachineVar))
            {
                return(false);
            }
            builderField = builderFieldRef.ResolveWithinSameModule();
            if (builderField == null)
            {
                return(false);
            }

            // Check the last instruction (ret)
            if (methodType == AsyncMethodType.Void)
            {
                if (!method.Body[method.Body.Count - 1].Match(ILCode.Ret))
                {
                    return(false);
                }
            }
            else
            {
                // ret(call(AsyncTaskMethodBuilder::get_Task, ldflda(StateMachine::<>t__builder, ldloca(stateMachine))))
                ILExpression returnValue;
                if (!method.Body[method.Body.Count - 1].Match(ILCode.Ret, out returnValue))
                {
                    return(false);
                }
                MethodReference getTaskMethod;
                ILExpression    builderExpr;
                if (!returnValue.Match(ILCode.Call, out getTaskMethod, out builderExpr))
                {
                    return(false);
                }
                ILExpression   loadStateMachineForBuilderExpr2;
                FieldReference builderField2;
                if (!builderExpr.Match(ILCode.Ldflda, out builderField2, out loadStateMachineForBuilderExpr2))
                {
                    return(false);
                }
                if (builderField2.ResolveWithinSameModule() != builderField || !loadStateMachineForBuilderExpr2.MatchLdloca(stateMachineVar))
                {
                    return(false);
                }
            }

            // Check the last field assignment - this should be the state field
            ILExpression initialStateExpr;

            if (!MatchStFld(method.Body[method.Body.Count - 4], stateMachineVar, out stateField, out initialStateExpr))
            {
                return(false);
            }
            if (!initialStateExpr.Match(ILCode.Ldc_I4, out initialState))
            {
                return(false);
            }
            if (initialState != -1)
            {
                return(false);
            }

            // Check the second-to-last field assignment - this should be the builder field
            FieldDefinition builderField3;
            ILExpression    builderInitialization;

            if (!MatchStFld(method.Body[method.Body.Count - 5], stateMachineVar, out builderField3, out builderInitialization))
            {
                return(false);
            }
            MethodReference createMethodRef;

            if (builderField3 != builderField || !builderInitialization.Match(ILCode.Call, out createMethodRef))
            {
                return(false);
            }
            if (createMethodRef.Name != "Create")
            {
                return(false);
            }

            for (int i = 0; i < method.Body.Count - 5; i++)
            {
                FieldDefinition field;
                ILExpression    fieldInit;
                if (!MatchStFld(method.Body[i], stateMachineVar, out field, out fieldInit))
                {
                    return(false);
                }
                ILVariable v;
                if (!fieldInit.Match(ILCode.Ldloc, out v))
                {
                    return(false);
                }
                if (!v.IsParameter)
                {
                    return(false);
                }
                fieldToParameterMap[field] = v;
            }

            return(true);
        }
Пример #28
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>())
            {
                var newBody = new List <ILNode>(block.Body.Count);
                for (int i = 0; i < block.Body.Count; i++)
                {
                    var node = block.Body[i];
                    if (node.Match(ILCode.Nop))
                    {
                        Utils.NopMergeILRanges(block, newBody, i);
                    }
                    else if (node is ILLabel && !liveLabels.Contains((ILLabel)node))
                    {
                        Utils.LabelMergeILRanges(block, newBody, i);
                    }
                    else
                    {
                        newBody.Add(node);
                    }
                }
                block.Body = newBody;
            }

            // Remove redundant continue
            foreach (ILWhileLoop loop in method.GetSelfAndChildrenRecursive <ILWhileLoop>())
            {
                var body = loop.BodyBlock.Body;
                if (body.Count > 0 && body.Last().Match(ILCode.LoopContinue))
                {
                    loop.EndILRanges.AddRange(body[body.Count - 1].GetSelfAndChildrenRecursiveILRanges());
                    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))
                        {
                            var prev = ilCase.Body[count - 2];
                            prev.EndILRanges.AddRange(ilCase.Body[count - 1].GetSelfAndChildrenRecursiveILRanges());
                            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)))
                {
                    for (int i = ilSwitch.CaseBlocks.Count - 1; i >= 0; i--)
                    {
                        var caseBlock = ilSwitch.CaseBlocks[i];
                        if (caseBlock.Body.Count != 1 || !caseBlock.Body.Single().Match(ILCode.LoopOrSwitchBreak))
                        {
                            continue;
                        }
                        ilSwitch.EndILRanges.AddRange(caseBlock.Body[0].GetSelfAndChildrenRecursiveILRanges());
                        ilSwitch.CaseBlocks.RemoveAt(i);
                    }
                }
            }

            // 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.EndILRanges.AddRange(method.Body[method.Body.Count - 1].GetSelfAndChildrenRecursiveILRanges());
                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.EndILRanges.AddRange(block.Body[i + 1].GetSelfAndChildrenRecursiveILRanges());
                        block.Body.RemoveAt(i + 1);
                    }
                    else
                    {
                        i++;
                    }
                }
            }
            if (modified)
            {
                // More removals might be possible
                new GotoRemoval().RemoveGotos(method);
            }
        }
Пример #29
0
        /// <summary>
        /// Get the first expression to be excecuted if the instruction pointer is at the start of the given node.
        /// Try blocks may not be entered in any way.  If possible, the try block is returned as the node to be executed.
        /// </summary>
        ILNode Enter(ILNode node, HashSet <ILNode> visitedNodes)
        {
            if (node == null)
            {
                throw new ArgumentNullException();
            }

            if (!visitedNodes.Add(node))
            {
                return(null);                 // Infinite loop
            }
            ILLabel label = node as ILLabel;

            if (label != null)
            {
                return(Exit(label, visitedNodes));
            }

            ILExpression expr = node as ILExpression;

            if (expr != null)
            {
                if (expr.Code == ILCode.Br || expr.Code == ILCode.Leave)
                {
                    ILLabel target = (ILLabel)expr.Operand;
                    // Early exit - same try-block
                    if (GetParents(expr).OfType <ILTryCatchBlock>().FirstOrDefault() == GetParents(target).OfType <ILTryCatchBlock>().FirstOrDefault())
                    {
                        return(Enter(target, visitedNodes));
                    }
                    // Make sure we are not entering any try-block
                    var srcTryBlocks = GetParents(expr).OfType <ILTryCatchBlock>().Reverse().ToList();
                    var dstTryBlocks = GetParents(target).OfType <ILTryCatchBlock>().Reverse().ToList();
                    // Skip blocks that we are already in
                    int i = 0;
                    while (i < srcTryBlocks.Count && i < dstTryBlocks.Count && srcTryBlocks[i] == dstTryBlocks[i])
                    {
                        i++;
                    }
                    if (i == dstTryBlocks.Count)
                    {
                        return(Enter(target, visitedNodes));
                    }
                    else
                    {
                        ILTryCatchBlock dstTryBlock = dstTryBlocks[i];
                        // Check that the goto points to the start
                        ILTryCatchBlock current = dstTryBlock;
                        while (current != null)
                        {
                            foreach (ILNode n in current.TryBlock.Body)
                            {
                                if (n is ILLabel)
                                {
                                    if (n == target)
                                    {
                                        return(dstTryBlock);
                                    }
                                }
                                else if (!n.Match(ILCode.Nop))
                                {
                                    current = n as ILTryCatchBlock;
                                    break;
                                }
                            }
                        }
                        return(null);
                    }
                }
                else if (expr.Code == ILCode.Nop)
                {
                    return(Exit(expr, visitedNodes));
                }
                else if (expr.Code == ILCode.LoopOrSwitchBreak)
                {
                    ILNode breakBlock = GetParents(expr).First(n => n is ILWhileLoop || n is ILSwitch);
                    return(Exit(breakBlock, new HashSet <ILNode>()
                    {
                        expr
                    }));
                }
                else if (expr.Code == ILCode.LoopContinue)
                {
                    ILNode continueBlock = GetParents(expr).First(n => n is ILWhileLoop);
                    return(Enter(continueBlock, new HashSet <ILNode>()
                    {
                        expr
                    }));
                }
                else
                {
                    return(expr);
                }
            }

            ILBlock block = node as ILBlock;

            if (block != null)
            {
                if (block.EntryGoto != null)
                {
                    return(Enter(block.EntryGoto, visitedNodes));
                }
                else if (block.Body.Count > 0)
                {
                    return(Enter(block.Body[0], visitedNodes));
                }
                else
                {
                    return(Exit(block, visitedNodes));
                }
            }

            ILCondition cond = node as ILCondition;

            if (cond != null)
            {
                return(cond.Condition);
            }

            ILWhileLoop loop = node as ILWhileLoop;

            if (loop != null)
            {
                if (loop.Condition != null)
                {
                    return(loop.Condition);
                }
                else
                {
                    return(Enter(loop.BodyBlock, visitedNodes));
                }
            }

            ILTryCatchBlock tryCatch = node as ILTryCatchBlock;

            if (tryCatch != null)
            {
                return(tryCatch);
            }

            ILSwitch ilSwitch = node as ILSwitch;

            if (ilSwitch != null)
            {
                return(ilSwitch.Condition);
            }

            throw new NotSupportedException(node.GetType().ToString());
        }
Пример #30
0
        /// <summary>
        /// Group input into a set of blocks that can be later arbitraliby schufled.
        /// The method adds necessary branches to make control flow between blocks
        /// explicit and thus order independent.
        /// </summary>
        void SplitToBasicBlocks(ILBlock block)
        {
            List <ILNode> basicBlocks = new List <ILNode>();

            ILLabel entryLabel = block.Body.FirstOrDefault() as ILLabel ?? new ILLabel()
            {
                Name = "Block_" + (nextLabelIndex++)
            };
            ILBasicBlock basicBlock = new ILBasicBlock();

            basicBlocks.Add(basicBlock);
            basicBlock.Body.Add(entryLabel);
            block.EntryGoto = new ILExpression(ILCode.Br, entryLabel);

            if (block.Body.Count > 0)
            {
                if (block.Body[0] != entryLabel)
                {
                    basicBlock.Body.Add(block.Body[0]);
                }

                for (int i = 1; i < block.Body.Count; i++)
                {
                    ILNode lastNode = block.Body[i - 1];
                    ILNode currNode = block.Body[i];

                    // Start a new basic block if necessary
                    if (currNode is ILLabel ||
                        currNode is ILTryCatchBlock ||                     // Counts as label
                        lastNode.IsConditionalControlFlow() ||
                        lastNode.IsUnconditionalControlFlow())
                    {
                        // Try to reuse the label
                        ILLabel label = currNode is ILLabel ? ((ILLabel)currNode) : new ILLabel()
                        {
                            Name = "Block_" + (nextLabelIndex++)
                        };

                        // Terminate the last block
                        if (!lastNode.IsUnconditionalControlFlow())
                        {
                            // Explicit branch from one block to other
                            basicBlock.Body.Add(new ILExpression(ILCode.Br, label));
                        }

                        // Start the new block
                        basicBlock = new ILBasicBlock();
                        basicBlocks.Add(basicBlock);
                        basicBlock.Body.Add(label);

                        // Add the node to the basic block
                        if (currNode != label)
                        {
                            basicBlock.Body.Add(currNode);
                        }
                    }
                    else
                    {
                        basicBlock.Body.Add(currNode);
                    }
                }
            }

            block.Body = basicBlocks;
            return;
        }