// // // // // $Revision$ // using System; using System.Collections.Generic; using System.IO; using System.Linq; using ICSharpCode.Decompiler.FlowAnalysis; using Mono.Cecil.Cil; namespace ICSharpCode.Decompiler.FlowAnalysis { /// /// Description of DominanceLoopDetector. /// public class ControlStructureDetector { public static ControlStructure DetectStructure(ControlFlowGraph g, IEnumerable exceptionHandlers) { ControlStructure root = new ControlStructure(new HashSet(g.Nodes), g.EntryPoint, ControlStructureType.Root); DetectExceptionHandling(root, g, exceptionHandlers); DetectLoops(g, root); g.ResetVisited(); return root; } #region Exception Handling static void DetectExceptionHandling(ControlStructure current, ControlFlowGraph g, IEnumerable exceptionHandlers) { foreach (ExceptionHandler eh in exceptionHandlers) { ControlStructure tryBlock = new ControlStructure( FindAndRemoveNodes(current, eh.TryStart, eh.TryEnd), g.Nodes.Single(n => n.Start == eh.TryStart), ControlStructureType.Try); tryBlock.ExceptionHandler = eh; MoveControlStructures(current, tryBlock, eh.TryStart, eh.TryEnd); current.Children.Add(tryBlock); if (eh.FilterStart != null) { ControlStructure filterBlock = new ControlStructure( FindAndRemoveNodes(current, eh.HandlerStart, eh.HandlerEnd), g.Nodes.Single(n => n.Start == eh.HandlerStart), ControlStructureType.Filter); filterBlock.ExceptionHandler = eh; MoveControlStructures(current, filterBlock, eh.FilterStart, eh.FilterEnd); current.Children.Add(filterBlock); } ControlStructure handlerBlock = new ControlStructure( FindAndRemoveNodes(current, eh.HandlerStart, eh.HandlerEnd), g.Nodes.Single(n => n.Start == eh.HandlerStart), ControlStructureType.Handler); handlerBlock.ExceptionHandler = eh; MoveControlStructures(current, handlerBlock, eh.HandlerStart, eh.HandlerEnd); current.Children.Add(handlerBlock); } } /// /// Removes all nodes from start to end (exclusive) from this ControlStructure and moves them to the target structure. /// static HashSet FindAndRemoveNodes(ControlStructure current, Instruction startInst, Instruction endInst) { HashSet result = new HashSet(); int start = startInst.Offset; int end = endInst.Offset; foreach (var node in current.Nodes.ToArray()) { if (node.Start != null && node.Start.Offset >= start && node.Start.Offset < end) { current.Nodes.Remove(node); result.Add(node); } } return result; } static void MoveControlStructures(ControlStructure current, ControlStructure target, Instruction startInst, Instruction endInst) { for (int i = 0; i < current.Children.Count; i++) { var child = current.Children[i]; if (child.EntryPoint.Start.Offset >= startInst.Offset && child.EntryPoint.Start.Offset <= endInst.Offset) { current.Children.RemoveAt(i--); target.Children.Add(child); } } } #endregion #region Loop Detection static void DetectLoops(ControlFlowGraph g, ControlStructure current) { g.ResetVisited(); FindLoops(current, current.EntryPoint); foreach (ControlStructure loop in current.Children) DetectLoops(g, loop); } static void FindLoops(ControlStructure current, ControlFlowNode node) { if (node.Visited) return; node.Visited = true; if (current.Nodes.Contains(node) && node.DominanceFrontier.Contains(node) && !(node == current.EntryPoint && current.Type == ControlStructureType.Loop)) { HashSet loopContents = new HashSet(); FindLoopContents(current, loopContents, node, node); current.Nodes.ExceptWith(loopContents); current.Children.Add(new ControlStructure(loopContents, node, ControlStructureType.Loop)); } foreach (var edge in node.Outgoing) { FindLoops(current, edge.Target); } } static void FindLoopContents(ControlStructure current, HashSet loopContents, ControlFlowNode loopHead, ControlFlowNode node) { if (current.Nodes.Contains(node) && loopHead.Dominates(node) && loopContents.Add(node)) { foreach (var edge in node.Incoming) { FindLoopContents(current, loopContents, loopHead, edge.Source); } } } #endregion } public enum ControlStructureType { Root, Loop, Try, Handler, Filter } public class ControlStructure { public readonly ControlStructureType Type; public readonly List Children = new List(); public readonly HashSet Nodes; public readonly ControlFlowNode EntryPoint; public ExceptionHandler ExceptionHandler; public ControlStructure(HashSet nodes, ControlFlowNode entryPoint, ControlStructureType type) { this.Nodes = nodes; this.EntryPoint = entryPoint; this.Type = type; } } }