Example #1
0
        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);
                }
            }
        }
Example #2
0
        static void FixAllIfStatements(ILBlock expr)
        {
            bool modified = false;

            do
            {
                modified = false;
                var list = expr.GetSelfAndChildrenRecursive <ILCondition>().ToList();
                foreach (var ifs in list)
                {
                    modified |= SimplifyLogicNot(ref ifs.Condition);
                }
            } while (modified);
            do
            {
                modified = false;
                var list = expr.GetSelfAndChildrenRecursive <ILWhileLoop>().ToList();
                foreach (var loop in list)
                {
                    modified |= SimplifyLogicNot(ref loop.Condition);
                }
            } while (modified);
            //  return;
            do
            {
                modified = false;

                // combine ifstatements to logic ands
                List <ILCondition> test = expr.GetSelfAndChildrenRecursive <ILCondition>(x => x.FalseBlock == null && x.TrueBlock.Body.Count == 1 && x.TrueBlock.Body[0] is ILCondition).ToList();
                if (test == null || test.Count > 0)
                {
                    modified = true;
                }
                foreach (var ifs in test)
                {
                    var leftIf = (ifs.TrueBlock.Body[0] as ILCondition);
                    ifs.TrueBlock = leftIf.TrueBlock;
                    ifs.Condition = new ILExpression(GMCode.LogicAnd, null, ifs.Condition, leftIf.Condition);
                }
            }while (modified);
        }
Example #3
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;
                foreach (ILExpression gotoExpr in method.GetSelfAndChildrenRecursive <ILExpression>(e => e.Code == GMCode.B))
                {
                    modified |= TrySimplifyGoto(gotoExpr);
                }
            } while (modified);

            RemoveRedundantCode(method);
        }
Example #4
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>
        public static void SplitToBasicBlocks(ILBlock block)
        {
            int           nextLabelIndex = 0;
            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(GMCode.B, 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 ||
                        lastNode.IsConditionalControlFlow() ||
                        lastNode.IsUnconditionalControlFlow())
                    {
                        // Try to reuse the label
                        ILLabel label = currNode as ILLabel ?? new ILLabel()
                        {
                            Name = "Block_" + (nextLabelIndex++).ToString()
                        };

                        // Terminate the last block
                        if (!lastNode.IsUnconditionalControlFlow())
                        {
                            // Explicit branch from one block to other
                            basicBlock.Body.Add(new ILExpression(GMCode.B, 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;
        }
Example #5
0
        public ILBlock Build(SortedList <int, Instruction> code, bool optimize, GMContext context)  //  List<string> StringList, List<string> InstanceList = null) //DecompilerContext context)
        {
            if (code.Count == 0)
            {
                return(new ILBlock());
            }
            this.context = context;


            _method       = code;
            this.optimize = optimize;
            List <ILNode> ast = BuildPreAst();

            ILBlock method = new ILBlock();

            method.Body = ast;
            if (context.Debug)
            {
                method.DebugSave("raw_body.txt");
            }
            betteribttest.Dissasembler.Optimize.RemoveRedundantCode(method);
            foreach (var block in method.GetSelfAndChildrenRecursive <ILBlock>())
            {
                Optimize.SplitToBasicBlocks(block);
            }
            if (context.Debug)
            {
                method.DebugSave("basic_blocks.txt");
            }

            new BuildFullAst(method, context).ProcessAllExpressions(method);
            if (context.Debug)
            {
                method.DebugSave("basic_blocks2.txt");
            }
            foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>())
            {
                bool modified;
                do
                {
                    modified  = false;
                    modified |= block.RunOptimization(new SimpleControlFlow(method, context).PushEnviromentFix);
                    modified |= block.RunOptimization(new SimpleControlFlow(method, context).SimplifyShortCircuit);
                    modified |= block.RunOptimization(new SimpleControlFlow(method, context).SimplifyTernaryOperator);


                    modified |= block.RunOptimization(new SimpleControlFlow(method, context).JoinBasicBlocks);
                    modified |= block.RunOptimization(Optimize.SimplifyLogicNot);
                } while (modified);
            }
            if (context.Debug)
            {
                method.DebugSave("before_loop.txt");
            }
            foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>())
            {
                new LoopsAndConditions().FindLoops(block);
            }
            if (context.Debug)
            {
                method.DebugSave("before_conditions.txt");
            }
            foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>())
            {
                new LoopsAndConditions().FindConditions(block);
            }

            FlattenBasicBlocks(method);
            if (context.Debug)
            {
                method.DebugSave("before_gotos.txt");
            }
            Optimize.RemoveRedundantCode(method);
            new GotoRemoval().RemoveGotos(method);
            Optimize.RemoveRedundantCode(method);

            new GotoRemoval().RemoveGotos(method);

            GotoRemoval.RemoveRedundantCode(method);
            new GotoRemoval().RemoveGotos(method);

            if (context.Debug)
            {
                method.DebugSave("final.cpp");
            }
            return(method);
        }
Example #6
0
        public static void RemoveRedundantCode(ILBlock method)
        {
            // Remove dead lables and nops and any popzs left
            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(GMCode.BadOp) && !n.Match(GMCode.Popz) && !(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(GMCode.LoopContinue))
                {
                    body.RemoveAt(body.Count - 1);
                }
            }
            // Remove redundant continue
            foreach (ILWithStatement with in method.GetSelfAndChildrenRecursive <ILWithStatement>())
            {
                var body = with.Body.Body;
                if (body.Count > 0 && body.Last().Match(GMCode.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(GMCode.LoopOrSwitchBreak))
                        {
                            ilCase.Body.RemoveAt(count - 1);
                        }
                    }
                }
                // fix case block

                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(GMCode.LoopOrSwitchBreak)))
                {
                    ilSwitch.CaseBlocks.RemoveAll(b => b.Body.Count == 1 && b.Body.Single().Match(GMCode.LoopOrSwitchBreak));
                }
            }

            // Remove redundant return at the end of method
            if (method.Body.Count > 0 && (method.Body.Last().Match(GMCode.Ret) || method.Body.Last().Match(GMCode.Exit)) && ((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(GMCode.Ret) || block.Body[i + 1].Match(GMCode.Exit)))
                    {
                        modified = true;
                        block.Body.RemoveAt(i + 1);
                    }
                    else
                    {
                        i++;
                    }
                }
            }
            // Remove empty falseBlocks
            foreach (ILCondition condition in method.GetSelfAndChildrenRecursive <ILCondition>().Where(x => x.FalseBlock != null && x.FalseBlock.Body.Count == 0))
            {
                condition.FalseBlock = null;
                modified             = true;
            }

            if (modified)
            {
                // More removals might be possible
                new GotoRemoval().RemoveGotos(method);
            }
        }
Example #7
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 == GMCode.B)
                {
                    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(GMCode.BadOp))
                                {
                                    current = n as ILTryCatchBlock;
                                    break;
                                }
                            }
                        }
                        return(null);
                    }
                }
                else if (expr.Code == GMCode.BadOp)
                {
                    return(Exit(expr, visitedNodes));
                }
                else if (expr.Code == GMCode.LoopOrSwitchBreak)
                {
                    ILNode breakBlock = GetParents(expr).First(n => n is ILWhileLoop || n is ILSwitch || n is ILWithStatement);
                    return(Exit(breakBlock, new HashSet <ILNode>()
                    {
                        expr
                    }));
                }
                else if (expr.Code == GMCode.LoopContinue)
                {
                    ILNode continueBlock = GetParents(expr).First(n => n is ILWhileLoop || n is ILWithStatement);
                    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);
            }
            ILWithStatement with = node as ILWithStatement;

            if (with != null)
            {
                if (with.Enviroment != null)
                {
                    return(with.Enviroment);
                }
                else
                {
                    return(Enter(with.Body, visitedNodes));
                }
            }

            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());
        }