mirror of https://github.com/icsharpcode/ILSpy.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
233 lines
5.3 KiB
233 lines
5.3 KiB
using System; |
|
using System.Collections; |
|
using System.Collections.Generic; |
|
|
|
namespace Decompiler.ControlFlow |
|
{ |
|
public abstract partial class Node |
|
{ |
|
public static int NextNodeID = 1; |
|
|
|
int id; |
|
string label; |
|
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 string Label { |
|
get { return label; } |
|
} |
|
|
|
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> basicBlocks) |
|
{ |
|
NodeCollection neighbours = new NodeCollection(); |
|
if (this.Parent != null) { |
|
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 |
|
if (targetNode == this) continue; |
|
// We found a target in our scope |
|
neighbours.Add(targetNode); |
|
} |
|
} |
|
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) { |
|
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 Description { |
|
get { |
|
return ToString(); |
|
} |
|
} |
|
|
|
protected Node() |
|
{ |
|
this.id = NextNodeID++; |
|
this.label = this.GetType().Name + "_" + ID; |
|
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(); |
|
} |
|
} |
|
}
|
|
|