Browse Source

Try to reconstruct if statements. The following logic is used: Depending on the value of the condition, the control flow will branch to one of two locations - let's call then 'true entry' and 'false entry'. Nodes reachable *only* from the 'true entry' are assumed to be the 'true' body of the if statement. Similarly, nodes reachable only from the 'false entry' are the 'false' body. Nodes reachable from both 'true entry' and 'false entry' and not part of the if statement and are placed after it.

pull/1/head^2
David Srbecký 18 years ago
parent
commit
45bedc8d1d
  1. 31
      src/AstMetodBodyBuilder.cs
  2. 56
      src/ControlFlow/Node-Optimize.cs
  3. 20
      src/ControlFlow/Node-Structure.cs
  4. 25
      src/ControlFlow/NodeCollection.cs
  5. 90
      src/ControlFlow/Nodes.cs

31
src/AstMetodBodyBuilder.cs

@ -92,6 +92,37 @@ namespace Decompiler
ConditionType.While, ConditionType.While,
ConditionPosition.Start 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 { } else {
throw new Exception("Bad node type"); throw new Exception("Bad node type");
} }

56
src/ControlFlow/Node-Optimize.cs

@ -1,6 +1,7 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
namespace Decompiler.ControlFlow namespace Decompiler.ControlFlow
{ {
@ -9,6 +10,7 @@ namespace Decompiler.ControlFlow
public void Optimize() public void Optimize()
{ {
OptimizeLoops(); OptimizeLoops();
OptimizeIf();
} }
public void OptimizeLoops() public void OptimizeLoops()
@ -39,19 +41,12 @@ namespace Decompiler.ControlFlow
NodeCollection GetReachableNodes() NodeCollection GetReachableNodes()
{ {
NodeCollection accumulator = new NodeCollection(); NodeCollection reachableNodes = new NodeCollection();
AddReachableNode(accumulator, this); reachableNodes.Add(this);
return accumulator; for(int i = 0; i < reachableNodes.Count; i++) {
} reachableNodes.AddRange(reachableNodes[i].Successors);
static void AddReachableNode(NodeCollection accumulator, Node node)
{
if (!accumulator.Contains(node)) {
accumulator.Add(node);
foreach(Node successor in node.Successors) {
AddReachableNode(accumulator, successor);
}
} }
return reachableNodes;
} }
public void OptimizeIf() public void OptimizeIf()
@ -60,14 +55,47 @@ namespace Decompiler.ControlFlow
// Find conditionNode (the start) // Find conditionNode (the start)
while(true) { while(true) {
if (conditionNode is BasicBlock && conditionNode.Successors.Count == 2) { if (conditionNode is BasicBlock && conditionNode.Successors.Count == 2) {
break; // Found // Found if start
OptimizeIf((BasicBlock)conditionNode);
return;
} else if (conditionNode.Successors.Count == 1) { } else if (conditionNode.Successors.Count == 1) {
conditionNode = conditionNode.Successors[0]; conditionNode = conditionNode.Successors[0];
continue; // Next continue; // Next
} else { } 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);
}
} }
} }

20
src/ControlFlow/Node-Structure.cs

@ -60,16 +60,12 @@ namespace Decompiler.ControlFlow
} }
} }
NodeCollection FloatUpToNeighbours(IEnumerable<BasicBlock> basickBlocks) NodeCollection FloatUpToNeighbours(IEnumerable<BasicBlock> basicBlocks)
{ {
NodeCollection neighbours = new NodeCollection(); NodeCollection neighbours = new NodeCollection();
if (this.Parent != null) { if (this.Parent != null) {
foreach(BasicBlock basicBlock in basickBlocks) { foreach(BasicBlock basicBlock in basicBlocks) {
// Find neighbour coresponding to the target Node targetNode = FloatUpToNeighbours(basicBlock);
Node targetNode = basicBlock;
while(targetNode != null && targetNode.Parent != this.Parent) {
targetNode = targetNode.Parent;
}
// The target is outside the scope of the parent node // The target is outside the scope of the parent node
if (targetNode == null) continue; if (targetNode == null) continue;
// This child is a loop // This child is a loop
@ -81,6 +77,16 @@ namespace Decompiler.ControlFlow
return neighbours; 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 { public NodeCollection Predecessors {
get { get {
if (predecessors_cache == null) { if (predecessors_cache == null) {

25
src/ControlFlow/NodeCollection.cs

@ -81,20 +81,35 @@ namespace Decompiler.ControlFlow
public void MoveTo(Node newNode) public void MoveTo(Node newNode)
{ {
while(this.Count > 0) { foreach(Node child in this.Clone()) {
this[0].MoveTo(newNode); child.MoveTo(newNode);
} }
} }
public void MoveTo(Node newNode, int index) public void MoveTo(Node newNode, int index)
{ {
while(this.Count > 0) { foreach(Node child in this.Clone()) {
this[0].MoveTo(newNode, index); child.MoveTo(newNode, index);
index++; index++;
} }
} }
public static NodeCollection Intersection(NodeCollection collectionA, NodeCollection collectionB) public NodeCollection()
{
}
public NodeCollection(IEnumerable<Node> items)
{
this.AddRange(items);
}
public NodeCollection Clone()
{
return new NodeCollection(this);
}
public static NodeCollection Intersect(NodeCollection collectionA, NodeCollection collectionB)
{ {
NodeCollection result = new NodeCollection(); NodeCollection result = new NodeCollection();
foreach(Node a in collectionA) { foreach(Node a in collectionA) {

90
src/ControlFlow/Nodes.cs

@ -5,6 +5,49 @@ using Mono.Cecil.Cil;
namespace Decompiler.ControlFlow namespace Decompiler.ControlFlow
{ {
public class BasicBlock: Node
{
List<StackExpression> body = new List<StackExpression>();
List<BasicBlock> basicBlockPredecessors = new List<BasicBlock>();
BasicBlock fallThroughBasicBlock;
BasicBlock branchBasicBlock;
public List<StackExpression> Body {
get { return body; }
}
public List<BasicBlock> BasicBlockPredecessors {
get { return basicBlockPredecessors; }
}
public BasicBlock FallThroughBasicBlock {
get { return fallThroughBasicBlock; }
set { fallThroughBasicBlock = value; }
}
public BasicBlock BranchBasicBlock {
get { return branchBasicBlock; }
set { branchBasicBlock = value; }
}
public IEnumerable<BasicBlock> 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 public class MethodBodyGraph: Node
{ {
BasicBlock methodEntry; BasicBlock methodEntry;
@ -69,40 +112,35 @@ namespace Decompiler.ControlFlow
{ {
} }
public class BasicBlock: Node public class Block: Node
{ {
List<StackExpression> body = new List<StackExpression>(); }
List<BasicBlock> basicBlockPredecessors = new List<BasicBlock>();
BasicBlock fallThroughBasicBlock; public class ConditionalNode: Node
BasicBlock branchBasicBlock; {
BasicBlock condition;
public List<StackExpression> Body { Block trueBody = new Block();
get { return body; } Block falseBody = new Block();
}
public List<BasicBlock> BasicBlockPredecessors { public BasicBlock Condition {
get { return basicBlockPredecessors; } get { return condition; }
} }
public BasicBlock FallThroughBasicBlock { public Block TrueBody {
get { return fallThroughBasicBlock; } get { return trueBody; }
set { fallThroughBasicBlock = value; }
} }
public BasicBlock BranchBasicBlock { public Block FalseBody {
get { return branchBasicBlock; } get { return falseBody; }
set { branchBasicBlock = value; }
} }
public IEnumerable<BasicBlock> BasicBlockSuccessors { public ConditionalNode(BasicBlock condition)
get { {
if (this.FallThroughBasicBlock != null) { this.condition = condition;
yield return this.FallThroughBasicBlock;
} condition.MoveTo(this);
if (this.BranchBasicBlock != null) { trueBody.MoveTo(this);
yield return this.BranchBasicBlock; falseBody.MoveTo(this);
}
}
} }
} }
} }

Loading…
Cancel
Save