// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team // // 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.Diagnostics; using System.Linq; using ICSharpCode.NRefactory.Utils; namespace ICSharpCode.Decompiler.FlowAnalysis { /// /// Represents a block in the control flow graph. /// [DebuggerDisplay("CFG UserIndex={UserIndex}, UserData={UserData}")] public class ControlFlowNode { /// /// User index, can be used to look up additional information in an array. /// public int UserIndex; /// /// User data. /// public object UserData; /// /// Visited flag, used in various algorithms. /// public bool Visited; /// /// Gets the node index in a post-order traversal of the control flow graph, starting at the /// entry point. This field gets computed by dominance analysis. /// public int PostOrderNumber; /// /// Gets whether this node is reachable. Requires that dominance is computed! /// public bool IsReachable { get { return DominatorTreeChildren != null; } } /// /// Gets the immediate dominator (the parent in the dominator tree). /// Null if dominance has not been calculated; or if the node is unreachable. /// public ControlFlowNode ImmediateDominator { get; internal set; } /// /// List of children in the dominator tree. /// Null if dominance has not been calculated; or if the node is unreachable. /// public List DominatorTreeChildren { get; internal set; } /// /// List of incoming control flow edges. /// public readonly List Predecessors = new List(); /// /// List of outgoing control flow edges. /// public readonly List Successors = new List(); public void AddEdgeTo(ControlFlowNode target) { this.Successors.Add(target); target.Predecessors.Add(this); } public void TraversePreOrder(Func> children, Action visitAction) { if (Visited) return; Visited = true; visitAction(this); foreach (ControlFlowNode t in children(this)) t.TraversePreOrder(children, visitAction); } public void TraversePostOrder(Func> children, Action visitAction) { if (Visited) return; Visited = true; foreach (ControlFlowNode t in children(this)) t.TraversePostOrder(children, visitAction); visitAction(this); } /// /// Gets whether this dominates . /// public bool Dominates(ControlFlowNode node) { // TODO: this can be made O(1) by numbering the dominator tree ControlFlowNode tmp = node; while (tmp != null) { if (tmp == this) return true; tmp = tmp.ImmediateDominator; } return false; } //public static GraphVizGraph ExportGraph(IReadOnlyList nodes, Func labelFunc = null) //{ // if (labelFunc == null) { // labelFunc = node => { // var block = node.UserData as IL.Block; // return block != null ? block.Label : node.UserData?.ToString(); // }; // } // GraphVizGraph g = new GraphVizGraph(); // GraphVizNode[] n = new GraphVizNode[nodes.Count]; // for (int i = 0; i < n.Length; i++) { // n[i] = new GraphVizNode(nodes[i].UserIndex); // n[i].shape = "box"; // n[i].label = labelFunc(nodes[i]); // g.AddNode(n[i]); // } // foreach (var source in nodes) { // foreach (var target in source.Successors) { // g.AddEdge(new GraphVizEdge(source.UserIndex, target.UserIndex)); // } // if (source.ImmediateDominator != null) { // g.AddEdge( // new GraphVizEdge(source.ImmediateDominator.UserIndex, source.UserIndex) { // color = "green" // }); // } // } // return g; //} } }