.NET Decompiler with support for PDB generation, ReadyToRun, Metadata (&more) - cross-platform!
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.
 
 
 
 

180 lines
5.5 KiB

// Copyright (c) 2010 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using Mono.Cecil.Cil;
namespace ICSharpCode.Decompiler.FlowAnalysis
{
/// <summary>
/// Contains the control flow graph.
/// </summary>
public sealed class ControlFlowGraph
{
readonly ReadOnlyCollection<ControlFlowNode> nodes;
public ControlFlowNode EntryPoint {
get { return nodes[0]; }
}
public ControlFlowNode RegularExit {
get { return nodes[1]; }
}
public ControlFlowNode ExceptionalExit {
get { return nodes[2]; }
}
public ReadOnlyCollection<ControlFlowNode> Nodes {
get { return nodes; }
}
internal ControlFlowGraph(ControlFlowNode[] nodes)
{
this.nodes = new ReadOnlyCollection<ControlFlowNode>(nodes);
Debug.Assert(EntryPoint.NodeType == ControlFlowNodeType.EntryPoint);
Debug.Assert(RegularExit.NodeType == ControlFlowNodeType.RegularExit);
Debug.Assert(ExceptionalExit.NodeType == ControlFlowNodeType.ExceptionalExit);
}
#if DEBUG
public GraphVizGraph ExportGraph()
{
GraphVizGraph graph = new GraphVizGraph();
foreach (ControlFlowNode node in nodes) {
graph.AddNode(new GraphVizNode(node.BlockIndex) { label = node.ToString(), shape = "box" });
}
foreach (ControlFlowNode node in nodes) {
foreach (ControlFlowEdge edge in node.Outgoing) {
GraphVizEdge e = new GraphVizEdge(edge.Source.BlockIndex, edge.Target.BlockIndex);
switch (edge.Type) {
case JumpType.Normal:
break;
case JumpType.LeaveTry:
e.color = "red";
break;
default:
e.color = "gray";
//e.constraint = false;
break;
}
graph.AddEdge(e);
}
if (node.ImmediateDominator != null) {
graph.AddEdge(new GraphVizEdge(node.ImmediateDominator.BlockIndex, node.BlockIndex) { color = "green", constraint = false });
}
}
return graph;
}
#endif
internal void ResetVisited()
{
foreach (ControlFlowNode node in nodes) {
node.Visited = false;
}
}
public void ComputeDominance()
{
// A Simple, Fast Dominance Algorithm
// Keith D. Cooper, Timothy J. Harvey and Ken Kennedy
EntryPoint.ImmediateDominator = EntryPoint;
bool changed = true;
while (changed) {
changed = false;
ResetVisited();
// for all nodes b except the entry point
EntryPoint.TraversePreOrder(
b => b.Successors,
b => {
if (b != EntryPoint) {
ControlFlowNode newIdom = b.Predecessors.First(block => block.Visited);
// for all other predecessors p of b
foreach (ControlFlowNode p in b.Predecessors) {
if (p != b && p.ImmediateDominator != null) {
newIdom = FindCommonDominator(p, newIdom);
}
}
if (b.ImmediateDominator != newIdom) {
b.ImmediateDominator = newIdom;
changed = true;
}
}
});
}
EntryPoint.ImmediateDominator = null;
foreach (ControlFlowNode node in nodes) {
if (node.ImmediateDominator != null)
node.ImmediateDominator.DominatorTreeChildren.Add(node);
}
}
static ControlFlowNode FindCommonDominator(ControlFlowNode b1, ControlFlowNode b2)
{
// Here we could use the postorder numbers to get rid of the hashset, see "A Simple, Fast Dominance Algorithm"
HashSet<ControlFlowNode> path1 = new HashSet<ControlFlowNode>();
while (b1 != null && path1.Add(b1))
b1 = b1.ImmediateDominator;
while (b2 != null) {
if (path1.Contains(b2))
return b2;
else
b2 = b2.ImmediateDominator;
}
throw new Exception("No common dominator found!");
}
public void ComputeDominanceFrontier()
{
ResetVisited();
EntryPoint.TraversePostOrder(
b => b.DominatorTreeChildren,
n => {
//logger.WriteLine("Calculating dominance frontier for " + n.Name);
n.DominanceFrontier = new HashSet<ControlFlowNode>();
// DF_local computation
foreach (ControlFlowNode succ in n.Successors) {
if (succ.ImmediateDominator != n) {
//logger.WriteLine(" local: " + succ.Name);
n.DominanceFrontier.Add(succ);
}
}
// DF_up computation
foreach (ControlFlowNode child in n.DominatorTreeChildren) {
foreach (ControlFlowNode p in child.DominanceFrontier) {
if (p.ImmediateDominator != n) {
//logger.WriteLine(" DF_up: " + p.Name + " (child=" + child.Name);
n.DominanceFrontier.Add(p);
}
}
}
});
}
}
}