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 @@ -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");
}

56
src/ControlFlow/Node-Optimize.cs

@ -1,6 +1,7 @@ @@ -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 @@ -9,6 +10,7 @@ namespace Decompiler.ControlFlow
public void Optimize()
{
OptimizeLoops();
OptimizeIf();
}
public void OptimizeLoops()
@ -39,19 +41,12 @@ namespace Decompiler.ControlFlow @@ -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 @@ -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);
}
}
}

20
src/ControlFlow/Node-Structure.cs

@ -60,16 +60,12 @@ namespace Decompiler.ControlFlow @@ -60,16 +60,12 @@ namespace Decompiler.ControlFlow
}
}
NodeCollection FloatUpToNeighbours(IEnumerable<BasicBlock> basickBlocks)
NodeCollection FloatUpToNeighbours(IEnumerable<BasicBlock> 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 @@ -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) {

25
src/ControlFlow/NodeCollection.cs

@ -81,20 +81,35 @@ namespace Decompiler.ControlFlow @@ -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<Node> 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) {

90
src/ControlFlow/Nodes.cs

@ -5,6 +5,49 @@ using Mono.Cecil.Cil; @@ -5,6 +5,49 @@ using Mono.Cecil.Cil;
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
{
BasicBlock methodEntry;
@ -69,40 +112,35 @@ namespace Decompiler.ControlFlow @@ -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;
BasicBlock branchBasicBlock;
public List<StackExpression> Body {
get { return body; }
}
}
public class ConditionalNode: Node
{
BasicBlock condition;
Block trueBody = new Block();
Block falseBody = new Block();
public List<BasicBlock> 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<BasicBlock> 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);
}
}
}

Loading…
Cancel
Save