mirror of https://github.com/icsharpcode/ILSpy.git
8 changed files with 506 additions and 382 deletions
@ -0,0 +1,73 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections; |
||||||
|
using System.Collections.Generic; |
||||||
|
|
||||||
|
namespace Decompiler.ControlFlow |
||||||
|
{ |
||||||
|
public abstract partial class Node |
||||||
|
{ |
||||||
|
public void Optimize() |
||||||
|
{ |
||||||
|
OptimizeLoops(); |
||||||
|
} |
||||||
|
|
||||||
|
public void OptimizeLoops() |
||||||
|
{ |
||||||
|
Reset: |
||||||
|
foreach(Node child in this.Childs) { |
||||||
|
if (child.Predecessors.Count == 1) { |
||||||
|
if (Options.ReduceGraph <= 0) return; |
||||||
|
Node predecessor = child.Predecessors[0]; |
||||||
|
Node mergedNode; |
||||||
|
if (child.Successors.Contains(predecessor)) { |
||||||
|
mergedNode = MergeChilds<Loop>(predecessor, child); |
||||||
|
} else { |
||||||
|
mergedNode = MergeChilds<AcyclicGraph>(predecessor, child); |
||||||
|
} |
||||||
|
mergedNode.FalttenAcyclicChilds(); |
||||||
|
goto Reset; |
||||||
|
} |
||||||
|
} |
||||||
|
// If the result is single acyclic node, eliminate it
|
||||||
|
if (this.Childs.Count == 1 && this.HeadChild is AcyclicGraph) { |
||||||
|
if (Options.ReduceGraph-- <= 0) return; |
||||||
|
Node headChild = this.HeadChild; |
||||||
|
this.Childs.Remove(this.HeadChild); |
||||||
|
headChild.Childs.MoveTo(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
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); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void OptimizeIf() |
||||||
|
{ |
||||||
|
Node conditionNode = this.HeadChild; |
||||||
|
// Find conditionNode (the start)
|
||||||
|
while(true) { |
||||||
|
if (conditionNode is BasicBlock && conditionNode.Successors.Count == 2) { |
||||||
|
break; // Found
|
||||||
|
} else if (conditionNode.Successors.Count == 1) { |
||||||
|
conditionNode = conditionNode.Successors[0]; |
||||||
|
continue; // Next
|
||||||
|
} else { |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,227 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections; |
||||||
|
using System.Collections.Generic; |
||||||
|
|
||||||
|
namespace Decompiler.ControlFlow |
||||||
|
{ |
||||||
|
public abstract partial class Node |
||||||
|
{ |
||||||
|
public static int NextNodeID = 1; |
||||||
|
|
||||||
|
int id; |
||||||
|
Node parent; |
||||||
|
NodeCollection childs = new NodeCollection(); |
||||||
|
|
||||||
|
// Structural and linking cache
|
||||||
|
NodeCollection basicBlocks_cache = null; |
||||||
|
NodeCollection predecessors_cache = null; |
||||||
|
NodeCollection successors_cache = null; |
||||||
|
|
||||||
|
public int ID { |
||||||
|
get { return id; } |
||||||
|
} |
||||||
|
|
||||||
|
public Node Parent { |
||||||
|
get { return parent; } |
||||||
|
} |
||||||
|
|
||||||
|
public Node HeadChild { |
||||||
|
get { |
||||||
|
if (this.Childs.Count > 0) { |
||||||
|
return this.Childs[0]; |
||||||
|
} else { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public NodeCollection Childs { |
||||||
|
get { |
||||||
|
return childs; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> All basic blocks within the scope of this node (inclusive) </summary>
|
||||||
|
public NodeCollection BasicBlocks { |
||||||
|
get { |
||||||
|
if (basicBlocks_cache == null) { |
||||||
|
NodeCollection basicBlocks = new NodeCollection(); |
||||||
|
|
||||||
|
if (this is BasicBlock) { |
||||||
|
basicBlocks.Add(this); |
||||||
|
} |
||||||
|
foreach(Node child in this.Childs) { |
||||||
|
basicBlocks.AddRange(child.BasicBlocks); |
||||||
|
} |
||||||
|
|
||||||
|
basicBlocks_cache = basicBlocks; |
||||||
|
} |
||||||
|
return basicBlocks_cache; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
NodeCollection FloatUpToNeighbours(IEnumerable<BasicBlock> basickBlocks) |
||||||
|
{ |
||||||
|
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; |
||||||
|
} |
||||||
|
// The target is outside the scope of the parent node
|
||||||
|
if (targetNode == null) continue; |
||||||
|
// This child is a loop
|
||||||
|
if (targetNode == this) continue; |
||||||
|
// We found a target in our scope
|
||||||
|
neighbours.Add(targetNode); |
||||||
|
} |
||||||
|
} |
||||||
|
return neighbours; |
||||||
|
} |
||||||
|
|
||||||
|
public NodeCollection Predecessors { |
||||||
|
get { |
||||||
|
if (predecessors_cache == null) { |
||||||
|
List<BasicBlock> basicBlockPredecessors = new List<BasicBlock>(); |
||||||
|
foreach(BasicBlock basicBlock in this.BasicBlocks) { |
||||||
|
foreach(BasicBlock basicBlockPredecessor in basicBlock.BasicBlockPredecessors) { |
||||||
|
basicBlockPredecessors.Add(basicBlockPredecessor); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
predecessors_cache = FloatUpToNeighbours(basicBlockPredecessors); |
||||||
|
} |
||||||
|
return predecessors_cache; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public NodeCollection Successors { |
||||||
|
get { |
||||||
|
if (successors_cache == null) { |
||||||
|
List<BasicBlock> basicBlockSuccessors = new List<BasicBlock>(); |
||||||
|
foreach(BasicBlock basicBlock in this.BasicBlocks) { |
||||||
|
foreach(BasicBlock basicBlockSuccessor in basicBlock.BasicBlockSuccessors) { |
||||||
|
basicBlockSuccessors.Add(basicBlockSuccessor); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
successors_cache = FloatUpToNeighbours(basicBlockSuccessors); |
||||||
|
} |
||||||
|
return successors_cache; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
int Index { |
||||||
|
get { |
||||||
|
if (this.Parent == null) throw new Exception("Does not have a parent"); |
||||||
|
return this.Parent.Childs.IndexOf(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public Node NextNode { |
||||||
|
get { |
||||||
|
int index = this.Index + 1; |
||||||
|
if (0 <= index && index < this.Parent.Childs.Count) { |
||||||
|
return this.Parent.Childs[index]; |
||||||
|
} else { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public string Label { |
||||||
|
get { |
||||||
|
return this.GetType().Name + "_" + ID; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public string Description { |
||||||
|
get { |
||||||
|
return ToString(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected Node() |
||||||
|
{ |
||||||
|
this.id = NextNodeID++; |
||||||
|
this.Childs.Added += delegate(object sender, NodeEventArgs e) { |
||||||
|
if (e.Node.Parent != null) { |
||||||
|
throw new Exception("Node is already assigned to other parent"); |
||||||
|
} |
||||||
|
e.Node.parent = this; |
||||||
|
NotifyChildsChanged(); |
||||||
|
}; |
||||||
|
this.Childs.Removed += delegate(object sender, NodeEventArgs e) { |
||||||
|
e.Node.parent = null; |
||||||
|
NotifyChildsChanged(); |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
void NotifyChildsChanged() |
||||||
|
{ |
||||||
|
this.basicBlocks_cache = null; |
||||||
|
foreach(Node child in this.Childs) { |
||||||
|
child.predecessors_cache = null; |
||||||
|
child.successors_cache = null; |
||||||
|
} |
||||||
|
if (this.Parent != null) { |
||||||
|
this.Parent.NotifyChildsChanged(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public override string ToString() |
||||||
|
{ |
||||||
|
System.Text.StringBuilder sb = new System.Text.StringBuilder(); |
||||||
|
sb.Append(this.GetType().Name); |
||||||
|
sb.Append(" "); |
||||||
|
sb.Append(ID); |
||||||
|
sb.Append(" "); |
||||||
|
|
||||||
|
sb.Append("("); |
||||||
|
|
||||||
|
if (this.Predecessors.Count > 0) { |
||||||
|
sb.Append("Predecessors:"); |
||||||
|
bool isFirst = true; |
||||||
|
foreach(Node predecessor in this.Predecessors) { |
||||||
|
if (isFirst) { |
||||||
|
isFirst = false; |
||||||
|
} else { |
||||||
|
sb.Append(","); |
||||||
|
} |
||||||
|
sb.Append(predecessor.ID); |
||||||
|
} |
||||||
|
sb.Append(" "); |
||||||
|
} |
||||||
|
|
||||||
|
if (this.Successors.Count > 0) { |
||||||
|
sb.Append("Successors:"); |
||||||
|
bool isFirst = true; |
||||||
|
foreach(Node successor in this.Successors) { |
||||||
|
if (isFirst) { |
||||||
|
isFirst = false; |
||||||
|
} else { |
||||||
|
sb.Append(","); |
||||||
|
} |
||||||
|
sb.Append(successor.ID); |
||||||
|
} |
||||||
|
sb.Append(" "); |
||||||
|
} |
||||||
|
|
||||||
|
if (this.Parent != null) { |
||||||
|
sb.Append("Parent:"); |
||||||
|
sb.Append(this.Parent.ID); |
||||||
|
sb.Append(" "); |
||||||
|
} |
||||||
|
|
||||||
|
if (sb[sb.Length - 1] == '(') { |
||||||
|
sb.Length -= 1; |
||||||
|
} else if (sb[sb.Length - 1] == ' ') { |
||||||
|
sb.Length -= 1; |
||||||
|
sb.Append(")"); |
||||||
|
} |
||||||
|
return sb.ToString(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,63 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections; |
||||||
|
using System.Collections.Generic; |
||||||
|
|
||||||
|
namespace Decompiler.ControlFlow |
||||||
|
{ |
||||||
|
public abstract partial class Node |
||||||
|
{ |
||||||
|
public void Remove() |
||||||
|
{ |
||||||
|
if (this.Parent != null) { |
||||||
|
this.Parent.Childs.Remove(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void MoveTo(Node newNode) |
||||||
|
{ |
||||||
|
MoveTo(newNode, newNode.Childs.Count); |
||||||
|
} |
||||||
|
|
||||||
|
public void MoveTo(Node newNode, int index) |
||||||
|
{ |
||||||
|
this.Remove(); |
||||||
|
newNode.Childs.Insert(index, this); |
||||||
|
} |
||||||
|
|
||||||
|
Node MergeChilds<T>(params Node[] nodes) where T: Node, new() |
||||||
|
{ |
||||||
|
foreach(Node node in nodes) { |
||||||
|
if (node == null) throw new ArgumentNullException("nodes"); |
||||||
|
if (node.Parent != this) throw new ArgumentException("The node is not my child"); |
||||||
|
} |
||||||
|
if (nodes.Length == 0) throw new ArgumentException("At least one node must be specified"); |
||||||
|
|
||||||
|
Node mergedNode = new T(); |
||||||
|
|
||||||
|
// Add the merged node
|
||||||
|
if (Options.ReduceGraph-- <= 0) return mergedNode; |
||||||
|
int headIndex = this.Childs.IndexOf(nodes[0]); |
||||||
|
this.Childs.Insert(headIndex, mergedNode); |
||||||
|
|
||||||
|
foreach(Node node in nodes) { |
||||||
|
if (Options.ReduceGraph-- <= 0) return mergedNode; |
||||||
|
node.MoveTo(mergedNode); |
||||||
|
} |
||||||
|
|
||||||
|
return mergedNode; |
||||||
|
} |
||||||
|
|
||||||
|
public void FalttenAcyclicChilds() |
||||||
|
{ |
||||||
|
Reset: |
||||||
|
foreach(Node child in this.Childs) { |
||||||
|
if (child is AcyclicGraph) { |
||||||
|
if (Options.ReduceGraph-- <= 0) return; |
||||||
|
child.Childs.MoveTo(this, child.Index); |
||||||
|
child.Remove(); |
||||||
|
goto Reset; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -1,366 +0,0 @@ |
|||||||
using System; |
|
||||||
using System.Collections; |
|
||||||
using System.Collections.Generic; |
|
||||||
|
|
||||||
namespace Decompiler.ControlFlow |
|
||||||
{ |
|
||||||
public class NodeCollection: System.Collections.ObjectModel.Collection<Node> |
|
||||||
{ |
|
||||||
public void AddRange(IEnumerable<Node> items) |
|
||||||
{ |
|
||||||
foreach(Node item in items) { |
|
||||||
this.Add(item); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public void RemoveRange(IEnumerable<Node> items) |
|
||||||
{ |
|
||||||
foreach(Node item in items) { |
|
||||||
this.Remove(item); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static NodeCollection Intersection(NodeCollection collectionA, NodeCollection collectionB) |
|
||||||
{ |
|
||||||
NodeCollection result = new NodeCollection(); |
|
||||||
foreach(Node a in collectionA) { |
|
||||||
if (collectionB.Contains(a)) { |
|
||||||
result.Add(a); |
|
||||||
} |
|
||||||
} |
|
||||||
return result; |
|
||||||
} |
|
||||||
|
|
||||||
protected override void InsertItem(int index, Node item) |
|
||||||
{ |
|
||||||
if (!this.Contains(item)) { |
|
||||||
base.InsertItem(index, item); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public bool ContainsRecursive(Node node) |
|
||||||
{ |
|
||||||
if (this.Contains(node)) { |
|
||||||
return true; |
|
||||||
} |
|
||||||
foreach(Node item in this.Items) { |
|
||||||
if (item.Childs.ContainsRecursive(node)) { |
|
||||||
return true; |
|
||||||
} |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
public Node FindContainer(Node node) |
|
||||||
{ |
|
||||||
foreach(Node item in this.Items) { |
|
||||||
if (item == node || item.Childs.ContainsRecursive(node)) { |
|
||||||
return item; |
|
||||||
} |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public abstract class Node |
|
||||||
{ |
|
||||||
public static int NextNodeID = 1; |
|
||||||
|
|
||||||
int id; |
|
||||||
Node parent; |
|
||||||
Node headChild; |
|
||||||
NodeCollection childs = new NodeCollection(); |
|
||||||
NodeCollection predecessors = new NodeCollection(); |
|
||||||
NodeCollection successors = new NodeCollection(); |
|
||||||
|
|
||||||
public int ID { |
|
||||||
get { return id; } |
|
||||||
} |
|
||||||
|
|
||||||
public Node Parent { |
|
||||||
get { return parent; } |
|
||||||
set { parent = value; } |
|
||||||
} |
|
||||||
|
|
||||||
public Node HeadChild { |
|
||||||
get { return headChild; } |
|
||||||
protected set { headChild = value; } |
|
||||||
} |
|
||||||
|
|
||||||
public NodeCollection Childs { |
|
||||||
get { return childs; } |
|
||||||
} |
|
||||||
|
|
||||||
public NodeCollection Predecessors { |
|
||||||
get { return predecessors; } |
|
||||||
} |
|
||||||
|
|
||||||
public NodeCollection Successors { |
|
||||||
get { return successors; } |
|
||||||
} |
|
||||||
|
|
||||||
public Node NextNode { |
|
||||||
get { |
|
||||||
if (this.Parent == null) throw new Exception("Does not have a parent"); |
|
||||||
int myIndex = this.Parent.Childs.IndexOf(this); |
|
||||||
int index = myIndex + 1; |
|
||||||
if (0 <= index && index < this.Parent.Childs.Count) { |
|
||||||
return this.Parent.Childs[index]; |
|
||||||
} else { |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public string Label { |
|
||||||
get { |
|
||||||
return this.GetType().Name + "_" + ID; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public Node(Node parent) |
|
||||||
{ |
|
||||||
this.parent = parent; |
|
||||||
this.id = NextNodeID++; |
|
||||||
} |
|
||||||
|
|
||||||
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(successor, accumulator); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void GetBasicBlockSuccessors(NodeCollection accumulator) |
|
||||||
{ |
|
||||||
BasicBlock me = this as BasicBlock; |
|
||||||
if (me != null) { |
|
||||||
if (me.FallThroughBasicBlock != null) { |
|
||||||
accumulator.Add(me.FallThroughBasicBlock); |
|
||||||
} |
|
||||||
if (me.BranchBasicBlock != null) { |
|
||||||
accumulator.Add(me.BranchBasicBlock); |
|
||||||
} |
|
||||||
} else { |
|
||||||
foreach(Node child in this.Childs) { |
|
||||||
child.GetBasicBlockSuccessors(accumulator); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public void RebuildNodeLinks() |
|
||||||
{ |
|
||||||
foreach(Node child in this.Childs) { |
|
||||||
NodeCollection successorBasicBlocks = new NodeCollection(); |
|
||||||
child.GetBasicBlockSuccessors(successorBasicBlocks); |
|
||||||
NodeCollection successorNodes = new NodeCollection(); |
|
||||||
foreach(Node successorBasicBlock in successorBasicBlocks) { |
|
||||||
Node container = this.Childs.FindContainer(successorBasicBlock); |
|
||||||
if (container != null) { |
|
||||||
successorNodes.Add(container); |
|
||||||
} |
|
||||||
} |
|
||||||
// Remove self link
|
|
||||||
if (successorNodes.Contains(child)) { |
|
||||||
successorNodes.Remove(child); |
|
||||||
} |
|
||||||
foreach(Node target in successorNodes) { |
|
||||||
child.Successors.Add(target); |
|
||||||
target.Predecessors.Add(child); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public void Optimize() |
|
||||||
{ |
|
||||||
for(int i = 0; i < this.Childs.Count;) { |
|
||||||
Node child = childs[i]; |
|
||||||
if (child.Predecessors.Count == 1) { |
|
||||||
if (Options.ReduceGraph-- <= 0) return; |
|
||||||
MergeChilds(child.Predecessors[0], child); |
|
||||||
i = 0; // Restart
|
|
||||||
} else { |
|
||||||
i++; // Next
|
|
||||||
} |
|
||||||
} |
|
||||||
// If it result is single acyclic node, eliminate it
|
|
||||||
if (this.Childs.Count == 1 && this.Childs[0] is AcyclicGraph) { |
|
||||||
this.headChild = this.Childs[0].HeadChild; |
|
||||||
this.childs = this.Childs[0].Childs; |
|
||||||
this.UpdateParentOfChilds(); |
|
||||||
} |
|
||||||
OptimizeIf(); |
|
||||||
} |
|
||||||
|
|
||||||
public void OptimizeIf() |
|
||||||
{ |
|
||||||
Node conditionNode = this.HeadChild; |
|
||||||
// Find conditionNode (the start)
|
|
||||||
while(true) { |
|
||||||
if (conditionNode is BasicBlock && conditionNode.Successors.Count == 2) { |
|
||||||
break; // Found
|
|
||||||
} else if (conditionNode.Successors == 1) { |
|
||||||
conditionNode = conditionNode.Successors[0]; |
|
||||||
continue; // Next
|
|
||||||
} else { |
|
||||||
return; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void UpdateParentOfChilds() |
|
||||||
{ |
|
||||||
foreach(Node child in this.Childs) { |
|
||||||
child.Parent = this; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
static void MergeChilds(Node head, Node tail) |
|
||||||
{ |
|
||||||
if (head == null) throw new ArgumentNullException("head"); |
|
||||||
if (tail == null) throw new ArgumentNullException("tail"); |
|
||||||
if (head.Parent != tail.Parent) throw new ArgumentException("different parents"); |
|
||||||
|
|
||||||
Node container = head.Parent; |
|
||||||
Node mergedNode; |
|
||||||
// Get type
|
|
||||||
if (tail.Successors.Contains(head)) { |
|
||||||
mergedNode = new Loop(container); |
|
||||||
} else { |
|
||||||
mergedNode = new AcyclicGraph(container); |
|
||||||
} |
|
||||||
|
|
||||||
// Add head
|
|
||||||
if (head is BasicBlock) { |
|
||||||
mergedNode.HeadChild = head; |
|
||||||
mergedNode.Childs.Add(head); |
|
||||||
} else if (head is AcyclicGraph) { |
|
||||||
mergedNode.HeadChild = ((AcyclicGraph)head).HeadChild; |
|
||||||
mergedNode.Childs.AddRange(((AcyclicGraph)head).Childs); |
|
||||||
} else if (head is Loop) { |
|
||||||
mergedNode.HeadChild = head; |
|
||||||
mergedNode.Childs.Add(head); |
|
||||||
} else { |
|
||||||
throw new Exception("Invalid head type"); |
|
||||||
} |
|
||||||
|
|
||||||
// Add tail
|
|
||||||
if (tail is BasicBlock) { |
|
||||||
mergedNode.Childs.Add(tail); |
|
||||||
} else if (tail is AcyclicGraph) { |
|
||||||
mergedNode.Childs.AddRange(((AcyclicGraph)tail).Childs); |
|
||||||
} else if (tail is Loop) { |
|
||||||
mergedNode.Childs.Add(tail); |
|
||||||
} else { |
|
||||||
throw new Exception("Invalid tail type"); |
|
||||||
} |
|
||||||
|
|
||||||
mergedNode.UpdateParentOfChilds(); |
|
||||||
|
|
||||||
// Remove links between the head and tail
|
|
||||||
if (head.Successors.Contains(tail)) { |
|
||||||
head.Successors.Remove(tail); |
|
||||||
tail.Predecessors.Remove(head); |
|
||||||
} |
|
||||||
if (tail.Successors.Contains(head)) { |
|
||||||
tail.Successors.Remove(head); |
|
||||||
head.Predecessors.Remove(tail); |
|
||||||
} |
|
||||||
|
|
||||||
Relink(head, mergedNode); |
|
||||||
Relink(tail, mergedNode); |
|
||||||
|
|
||||||
mergedNode.RebuildNodeLinks(); |
|
||||||
|
|
||||||
// Remove the old nodes and add the merged node - replace head with the merged node
|
|
||||||
container.Childs.Remove(tail); |
|
||||||
int headIndex = container.Childs.IndexOf(head); |
|
||||||
container.Childs.Remove(head); |
|
||||||
container.Childs.Insert(headIndex, mergedNode); |
|
||||||
} |
|
||||||
|
|
||||||
static void Relink(Node node, Node target) |
|
||||||
{ |
|
||||||
// Relink all neighbours to the target node
|
|
||||||
foreach(Node predecessor in node.Predecessors) { |
|
||||||
predecessor.Successors.Remove(node); |
|
||||||
predecessor.Successors.Add(target); |
|
||||||
} |
|
||||||
foreach(Node successor in node.Successors) { |
|
||||||
successor.Predecessors.Remove(node); |
|
||||||
successor.Predecessors.Add(target); |
|
||||||
} |
|
||||||
|
|
||||||
// Move our pointers to the target node
|
|
||||||
target.Predecessors.AddRange(node.Predecessors); |
|
||||||
target.Successors.AddRange(node.Successors); |
|
||||||
node.Predecessors.Clear(); |
|
||||||
node.Successors.Clear(); |
|
||||||
} |
|
||||||
|
|
||||||
public override string ToString() |
|
||||||
{ |
|
||||||
System.Text.StringBuilder sb = new System.Text.StringBuilder(); |
|
||||||
sb.Append(this.GetType().Name); |
|
||||||
sb.Append(" "); |
|
||||||
sb.Append(ID); |
|
||||||
sb.Append(" "); |
|
||||||
|
|
||||||
sb.Append("("); |
|
||||||
|
|
||||||
if (this.Predecessors.Count > 0) { |
|
||||||
sb.Append("Predecessors:"); |
|
||||||
bool isFirst = true; |
|
||||||
foreach(Node predecessor in this.Predecessors) { |
|
||||||
if (isFirst) { |
|
||||||
isFirst = false; |
|
||||||
} else { |
|
||||||
sb.Append(","); |
|
||||||
} |
|
||||||
sb.Append(predecessor.ID); |
|
||||||
} |
|
||||||
sb.Append(" "); |
|
||||||
} |
|
||||||
|
|
||||||
if (this.Successors.Count > 0) { |
|
||||||
sb.Append("Successors:"); |
|
||||||
bool isFirst = true; |
|
||||||
foreach(Node successor in this.Successors) { |
|
||||||
if (isFirst) { |
|
||||||
isFirst = false; |
|
||||||
} else { |
|
||||||
sb.Append(","); |
|
||||||
} |
|
||||||
sb.Append(successor.ID); |
|
||||||
} |
|
||||||
sb.Append(" "); |
|
||||||
} |
|
||||||
|
|
||||||
if (this.Parent != null) { |
|
||||||
sb.Append("Parent:"); |
|
||||||
sb.Append(this.Parent.ID); |
|
||||||
} |
|
||||||
sb.Append(" "); |
|
||||||
|
|
||||||
if (this.HeadChild != null) { |
|
||||||
sb.Append("Head:"); |
|
||||||
sb.Append(this.HeadChild.ID); |
|
||||||
} |
|
||||||
sb.Append(" "); |
|
||||||
|
|
||||||
sb.Length = sb.Length - 1; |
|
||||||
sb.Append(")"); |
|
||||||
return sb.ToString(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,113 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
|
||||||
|
namespace Decompiler.ControlFlow |
||||||
|
{ |
||||||
|
public class NodeEventArgs: EventArgs |
||||||
|
{ |
||||||
|
Node node; |
||||||
|
|
||||||
|
public Node Node { |
||||||
|
get { return node; } |
||||||
|
} |
||||||
|
|
||||||
|
public NodeEventArgs(Node node) |
||||||
|
{ |
||||||
|
this.node = node; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public class NodeCollection: System.Collections.ObjectModel.Collection<Node> |
||||||
|
{ |
||||||
|
public event EventHandler<NodeEventArgs> Added; |
||||||
|
public event EventHandler<NodeEventArgs> Removed; |
||||||
|
|
||||||
|
protected virtual void OnAdded(Node node) |
||||||
|
{ |
||||||
|
if (Added != null) { |
||||||
|
Added(this, new NodeEventArgs(node)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected virtual void OnRemoved(Node node) |
||||||
|
{ |
||||||
|
if (Removed != null) { |
||||||
|
Removed(this, new NodeEventArgs(node)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected override void ClearItems() |
||||||
|
{ |
||||||
|
while(this.Count > 0) { |
||||||
|
this.RemoveAt(this.Count - 1); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected override void InsertItem(int index, Node item) |
||||||
|
{ |
||||||
|
if (!this.Contains(item)) { |
||||||
|
base.InsertItem(index, item); |
||||||
|
} |
||||||
|
OnAdded(item); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void RemoveItem(int index) |
||||||
|
{ |
||||||
|
Node node = this[index]; |
||||||
|
base.RemoveItem(index); |
||||||
|
OnRemoved(node); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void SetItem(int index, Node item) |
||||||
|
{ |
||||||
|
this.RemoveAt(index); |
||||||
|
this.Insert(index, item); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void AddRange(IEnumerable<Node> items) |
||||||
|
{ |
||||||
|
foreach(Node item in items) { |
||||||
|
this.Add(item); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void RemoveRange(IEnumerable<Node> items) |
||||||
|
{ |
||||||
|
foreach(Node item in items) { |
||||||
|
this.Remove(item); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void MoveTo(Node newNode) |
||||||
|
{ |
||||||
|
while(this.Count > 0) { |
||||||
|
this[0].MoveTo(newNode); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void MoveTo(Node newNode, int index) |
||||||
|
{ |
||||||
|
while(this.Count > 0) { |
||||||
|
this[0].MoveTo(newNode, index); |
||||||
|
index++; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static NodeCollection Intersection(NodeCollection collectionA, NodeCollection collectionB) |
||||||
|
{ |
||||||
|
NodeCollection result = new NodeCollection(); |
||||||
|
foreach(Node a in collectionA) { |
||||||
|
if (collectionB.Contains(a)) { |
||||||
|
result.Add(a); |
||||||
|
} |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
public override string ToString() |
||||||
|
{ |
||||||
|
return string.Format("{0} Count = {1}", typeof(NodeCollection).Name, this.Count); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue