diff --git a/src/AstMetodBodyBuilder.cs b/src/AstMetodBodyBuilder.cs index f4fff2ec5..0e5380bb8 100644 --- a/src/AstMetodBodyBuilder.cs +++ b/src/AstMetodBodyBuilder.cs @@ -92,6 +92,37 @@ namespace Decompiler ConditionType.While, ConditionPosition.Start ); + } else if (node is Block) { + foreach(Ast.INode inode in TransformNodes(node.Childs)) { + yield return inode; + } + } else if (node is ConditionalNode) { + ConditionalNode conditionalNode = (ConditionalNode)node; + yield return new Ast.LabelStatement(conditionalNode.Condition.Label); + Ast.Statement lastStatement = null; + foreach(StackExpression expr in conditionalNode.Condition.Body) { + lastStatement = TransformExpression(expr); + yield return lastStatement; + } + Ast.IfElseStatement ifElseStmt = (Ast.IfElseStatement)lastStatement; + Ast.Statement oldTrueBody = ifElseStmt.TrueStatement[0]; + ifElseStmt.TrueStatement.Clear(); + // Swap the method bodies + ifElseStmt.Condition = new Ast.UnaryOperatorExpression(new Ast.ParenthesizedExpression(ifElseStmt.Condition), UnaryOperatorType.Not); + + Ast.BlockStatement trueBlock = new Ast.BlockStatement(); + // The block entry code + trueBlock.Children.Add(MakeBranchCommand(node, conditionalNode.Condition.FallThroughBasicBlock)); + // Sugested content + trueBlock.Children.AddRange(TransformNode(conditionalNode.TrueBody)); + ifElseStmt.TrueStatement.Add(trueBlock); + + Ast.BlockStatement falseBlock = new Ast.BlockStatement(); + // The block entry code + falseBlock.Children.Add(oldTrueBody); + // Sugested content + falseBlock.Children.AddRange(TransformNode(conditionalNode.FalseBody)); + ifElseStmt.FalseStatement.Add(falseBlock); } else { throw new Exception("Bad node type"); } diff --git a/src/ControlFlow/Node-Optimize.cs b/src/ControlFlow/Node-Optimize.cs index 19de7507d..c9258da2b 100644 --- a/src/ControlFlow/Node-Optimize.cs +++ b/src/ControlFlow/Node-Optimize.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Diagnostics; namespace Decompiler.ControlFlow { @@ -9,6 +10,7 @@ namespace Decompiler.ControlFlow public void Optimize() { OptimizeLoops(); + OptimizeIf(); } public void OptimizeLoops() @@ -39,19 +41,12 @@ namespace Decompiler.ControlFlow NodeCollection GetReachableNodes() { - NodeCollection accumulator = new NodeCollection(); - AddReachableNode(accumulator, this); - return accumulator; - } - - static void AddReachableNode(NodeCollection accumulator, Node node) - { - if (!accumulator.Contains(node)) { - accumulator.Add(node); - foreach(Node successor in node.Successors) { - AddReachableNode(accumulator, successor); - } + NodeCollection reachableNodes = new NodeCollection(); + reachableNodes.Add(this); + for(int i = 0; i < reachableNodes.Count; i++) { + reachableNodes.AddRange(reachableNodes[i].Successors); } + return reachableNodes; } public void OptimizeIf() @@ -60,14 +55,47 @@ namespace Decompiler.ControlFlow // Find conditionNode (the start) while(true) { if (conditionNode is BasicBlock && conditionNode.Successors.Count == 2) { - break; // Found + // Found if start + OptimizeIf((BasicBlock)conditionNode); + return; } else if (conditionNode.Successors.Count == 1) { conditionNode = conditionNode.Successors[0]; continue; // Next } else { - return; + return; // Just give up } } } + + public static void OptimizeIf(BasicBlock condition) + { + Node trueStart = condition.FloatUpToNeighbours(condition.FallThroughBasicBlock); + Node falseStart = condition.FloatUpToNeighbours(condition.BranchBasicBlock); + Debug.Assert(trueStart != null); + Debug.Assert(falseStart != null); + Debug.Assert(trueStart != falseStart); + + NodeCollection trueReachable = trueStart.GetReachableNodes(); + NodeCollection falseReachable = falseStart.GetReachableNodes(); + NodeCollection commonReachable = NodeCollection.Intersect(trueReachable, falseReachable); + + NodeCollection trueNodes = trueReachable.Clone(); + trueNodes.RemoveRange(commonReachable); + NodeCollection falseNodes = falseReachable.Clone(); + falseNodes.RemoveRange(commonReachable); + + // Replace the basic block with condition node + if (Options.ReduceGraph-- <= 0) return; + Node conditionParent = condition.Parent; + int conditionIndex = condition.Index; + ConditionalNode conditionalNode = new ConditionalNode(condition); + conditionalNode.MoveTo(conditionParent, conditionIndex); + + if (Options.ReduceGraph-- <= 0) return; + trueNodes.MoveTo(conditionalNode.TrueBody); + + if (Options.ReduceGraph-- <= 0) return; + falseNodes.MoveTo(conditionalNode.FalseBody); + } } } diff --git a/src/ControlFlow/Node-Structure.cs b/src/ControlFlow/Node-Structure.cs index 528b67184..e588c488c 100644 --- a/src/ControlFlow/Node-Structure.cs +++ b/src/ControlFlow/Node-Structure.cs @@ -60,16 +60,12 @@ namespace Decompiler.ControlFlow } } - NodeCollection FloatUpToNeighbours(IEnumerable basickBlocks) + NodeCollection FloatUpToNeighbours(IEnumerable basicBlocks) { NodeCollection neighbours = new NodeCollection(); if (this.Parent != null) { - foreach(BasicBlock basicBlock in basickBlocks) { - // Find neighbour coresponding to the target - Node targetNode = basicBlock; - while(targetNode != null && targetNode.Parent != this.Parent) { - targetNode = targetNode.Parent; - } + foreach(BasicBlock basicBlock in basicBlocks) { + Node targetNode = FloatUpToNeighbours(basicBlock); // The target is outside the scope of the parent node if (targetNode == null) continue; // This child is a loop @@ -81,6 +77,16 @@ namespace Decompiler.ControlFlow return neighbours; } + Node FloatUpToNeighbours(BasicBlock basicBlock) + { + // Find neighbour coresponding to the basickBlock + Node targetNode = basicBlock; + while(targetNode != null && targetNode.Parent != this.Parent) { + targetNode = targetNode.Parent; + } + return targetNode; + } + public NodeCollection Predecessors { get { if (predecessors_cache == null) { diff --git a/src/ControlFlow/NodeCollection.cs b/src/ControlFlow/NodeCollection.cs index fd49ecfed..b0f4b2084 100644 --- a/src/ControlFlow/NodeCollection.cs +++ b/src/ControlFlow/NodeCollection.cs @@ -81,20 +81,35 @@ namespace Decompiler.ControlFlow public void MoveTo(Node newNode) { - while(this.Count > 0) { - this[0].MoveTo(newNode); + foreach(Node child in this.Clone()) { + child.MoveTo(newNode); } } public void MoveTo(Node newNode, int index) { - while(this.Count > 0) { - this[0].MoveTo(newNode, index); + foreach(Node child in this.Clone()) { + child.MoveTo(newNode, index); index++; } } - public static NodeCollection Intersection(NodeCollection collectionA, NodeCollection collectionB) + public NodeCollection() + { + + } + + public NodeCollection(IEnumerable items) + { + this.AddRange(items); + } + + public NodeCollection Clone() + { + return new NodeCollection(this); + } + + public static NodeCollection Intersect(NodeCollection collectionA, NodeCollection collectionB) { NodeCollection result = new NodeCollection(); foreach(Node a in collectionA) { diff --git a/src/ControlFlow/Nodes.cs b/src/ControlFlow/Nodes.cs index 7ea624bac..1567a01d3 100644 --- a/src/ControlFlow/Nodes.cs +++ b/src/ControlFlow/Nodes.cs @@ -5,6 +5,49 @@ using Mono.Cecil.Cil; namespace Decompiler.ControlFlow { + public class BasicBlock: Node + { + List body = new List(); + List basicBlockPredecessors = new List(); + BasicBlock fallThroughBasicBlock; + BasicBlock branchBasicBlock; + + public List Body { + get { return body; } + } + + public List BasicBlockPredecessors { + get { return basicBlockPredecessors; } + } + + public BasicBlock FallThroughBasicBlock { + get { return fallThroughBasicBlock; } + set { fallThroughBasicBlock = value; } + } + + public BasicBlock BranchBasicBlock { + get { return branchBasicBlock; } + set { branchBasicBlock = value; } + } + + public IEnumerable BasicBlockSuccessors { + get { + if (this.FallThroughBasicBlock != null) { + yield return this.FallThroughBasicBlock; + } + if (this.BranchBasicBlock != null) { + yield return this.BranchBasicBlock; + } + } + } + + public bool IsConditionalBranch { + get { + return fallThroughBasicBlock != null && branchBasicBlock != null; + } + } + } + public class MethodBodyGraph: Node { BasicBlock methodEntry; @@ -69,40 +112,35 @@ namespace Decompiler.ControlFlow { } - public class BasicBlock: Node + public class Block: Node { - List body = new List(); - List basicBlockPredecessors = new List(); - BasicBlock fallThroughBasicBlock; - BasicBlock branchBasicBlock; - - public List Body { - get { return body; } - } + } + + public class ConditionalNode: Node + { + BasicBlock condition; + Block trueBody = new Block(); + Block falseBody = new Block(); - public List BasicBlockPredecessors { - get { return basicBlockPredecessors; } + public BasicBlock Condition { + get { return condition; } } - public BasicBlock FallThroughBasicBlock { - get { return fallThroughBasicBlock; } - set { fallThroughBasicBlock = value; } + public Block TrueBody { + get { return trueBody; } } - public BasicBlock BranchBasicBlock { - get { return branchBasicBlock; } - set { branchBasicBlock = value; } + public Block FalseBody { + get { return falseBody; } } - public IEnumerable BasicBlockSuccessors { - get { - if (this.FallThroughBasicBlock != null) { - yield return this.FallThroughBasicBlock; - } - if (this.BranchBasicBlock != null) { - yield return this.BranchBasicBlock; - } - } + public ConditionalNode(BasicBlock condition) + { + this.condition = condition; + + condition.MoveTo(this); + trueBody.MoveTo(this); + falseBody.MoveTo(this); } } }