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