diff options
author | Stephane Delcroix <stephane@delcroix.org> | 2016-12-05 13:31:31 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-12-05 13:31:31 +0100 |
commit | 1a5bead2f2e24cc16da23753eaf0882d38d54ea1 (patch) | |
tree | 2fb4bf607ca11d9ed5163ed329796ca651054a6a /ICSharpCode.Decompiler/FlowAnalysis/ControlFlowGraphBuilder.cs | |
parent | 3692786c3a0f9ba01ffe9516caa624a018ac885a (diff) | |
download | xamarin-forms-1a5bead2f2e24cc16da23753eaf0882d38d54ea1.tar.gz xamarin-forms-1a5bead2f2e24cc16da23753eaf0882d38d54ea1.tar.bz2 xamarin-forms-1a5bead2f2e24cc16da23753eaf0882d38d54ea1.zip |
[XamlC] drop ICSharpCode.Decompiler (#586)
* [XamlC] drop ICSharpCode.Decompiler
* update nuspec
* fix typo
Diffstat (limited to 'ICSharpCode.Decompiler/FlowAnalysis/ControlFlowGraphBuilder.cs')
-rw-r--r-- | ICSharpCode.Decompiler/FlowAnalysis/ControlFlowGraphBuilder.cs | 439 |
1 files changed, 0 insertions, 439 deletions
diff --git a/ICSharpCode.Decompiler/FlowAnalysis/ControlFlowGraphBuilder.cs b/ICSharpCode.Decompiler/FlowAnalysis/ControlFlowGraphBuilder.cs deleted file mode 100644 index 7570884a..00000000 --- a/ICSharpCode.Decompiler/FlowAnalysis/ControlFlowGraphBuilder.cs +++ /dev/null @@ -1,439 +0,0 @@ -// 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 Mono.Cecil.Cil; - -namespace ICSharpCode.Decompiler.FlowAnalysis -{ - /// <summary> - /// Constructs the Control Flow Graph from a Cecil method body. - /// </summary> - public sealed class ControlFlowGraphBuilder - { - public static ControlFlowGraph Build(MethodBody methodBody) - { - return new ControlFlowGraphBuilder(methodBody).Build(); - } - - // This option controls how finally blocks are handled: - // false means that the endfinally instruction will jump to any of the leave targets (EndFinally edge type). - // true means that a copy of the whole finally block is created for each leave target. In this case, each endfinally node will be connected with the leave - // target using a normal edge. - bool copyFinallyBlocks = false; - - MethodBody methodBody; - int[] offsets; // array index = instruction index; value = IL offset - bool[] hasIncomingJumps; // array index = instruction index - List<ControlFlowNode> nodes = new List<ControlFlowNode>(); - ControlFlowNode entryPoint; - ControlFlowNode regularExit; - ControlFlowNode exceptionalExit; - - ControlFlowGraphBuilder(MethodBody methodBody) - { - this.methodBody = methodBody; - offsets = methodBody.Instructions.Select(i => i.Offset).ToArray(); - hasIncomingJumps = new bool[methodBody.Instructions.Count]; - - entryPoint = new ControlFlowNode(0, 0, ControlFlowNodeType.EntryPoint); - nodes.Add(entryPoint); - regularExit = new ControlFlowNode(1, -1, ControlFlowNodeType.RegularExit); - nodes.Add(regularExit); - exceptionalExit = new ControlFlowNode(2, -1, ControlFlowNodeType.ExceptionalExit); - nodes.Add(exceptionalExit); - Debug.Assert(nodes.Count == 3); - } - - /// <summary> - /// Determines the index of the instruction (for use with the hasIncomingJumps array) - /// </summary> - int GetInstructionIndex(Instruction inst) - { - int index = Array.BinarySearch(offsets, inst.Offset); - Debug.Assert(index >= 0); - return index; - } - - /// <summary> - /// Builds the ControlFlowGraph. - /// </summary> - public ControlFlowGraph Build() - { - CalculateHasIncomingJumps(); - CreateNodes(); - CreateRegularControlFlow(); - CreateExceptionalControlFlow(); - if (copyFinallyBlocks) - CopyFinallyBlocksIntoLeaveEdges(); - else - TransformLeaveEdges(); - return new ControlFlowGraph(nodes.ToArray()); - } - - #region Step 1: calculate which instructions are the targets of jump instructions. - void CalculateHasIncomingJumps() - { - foreach (Instruction inst in methodBody.Instructions) { - if (inst.OpCode.OperandType == OperandType.InlineBrTarget || inst.OpCode.OperandType == OperandType.ShortInlineBrTarget) { - hasIncomingJumps[GetInstructionIndex((Instruction)inst.Operand)] = true; - } else if (inst.OpCode.OperandType == OperandType.InlineSwitch) { - foreach (Instruction i in (Instruction[])inst.Operand) - hasIncomingJumps[GetInstructionIndex(i)] = true; - } - } - foreach (ExceptionHandler eh in methodBody.ExceptionHandlers) { - if (eh.FilterStart != null) { - hasIncomingJumps[GetInstructionIndex(eh.FilterStart)] = true; - } - hasIncomingJumps[GetInstructionIndex(eh.HandlerStart)] = true; - } - } - #endregion - - #region Step 2: create nodes - void CreateNodes() - { - // Step 2a: find basic blocks and create nodes for them - for (int i = 0; i < methodBody.Instructions.Count; i++) { - Instruction blockStart = methodBody.Instructions[i]; - ExceptionHandler blockStartEH = FindInnermostExceptionHandler(blockStart.Offset); - // try and see how big we can make that block: - for (; i + 1 < methodBody.Instructions.Count; i++) { - Instruction inst = methodBody.Instructions[i]; - if (IsBranch(inst.OpCode) || CanThrowException(inst.OpCode)) - break; - if (hasIncomingJumps[i + 1]) - break; - if (inst.Next != null) { - // ensure that blocks never contain instructions from different try blocks - ExceptionHandler instEH = FindInnermostExceptionHandler(inst.Next.Offset); - if (instEH != blockStartEH) - break; - } - } - - nodes.Add(new ControlFlowNode(nodes.Count, blockStart, methodBody.Instructions[i])); - } - // Step 2b: Create special nodes for the exception handling constructs - foreach (ExceptionHandler handler in methodBody.ExceptionHandlers) { - if (handler.HandlerType == ExceptionHandlerType.Filter) - throw new NotSupportedException(); - ControlFlowNode endFinallyOrFaultNode = null; - if (handler.HandlerType == ExceptionHandlerType.Finally || handler.HandlerType == ExceptionHandlerType.Fault) { - endFinallyOrFaultNode = new ControlFlowNode(nodes.Count, handler.HandlerEnd.Offset, ControlFlowNodeType.EndFinallyOrFault); - nodes.Add(endFinallyOrFaultNode); - } - nodes.Add(new ControlFlowNode(nodes.Count, handler, endFinallyOrFaultNode)); - } - } - #endregion - - #region Step 3: create edges for the normal flow of control (assuming no exceptions thrown) - void CreateRegularControlFlow() - { - CreateEdge(entryPoint, methodBody.Instructions[0], JumpType.Normal); - foreach (ControlFlowNode node in nodes) { - if (node.End != null) { - // create normal edges from one instruction to the next - if (!OpCodeInfo.IsUnconditionalBranch(node.End.OpCode)) - CreateEdge(node, node.End.Next, JumpType.Normal); - - // create edges for branch instructions - if (node.End.OpCode.OperandType == OperandType.InlineBrTarget || node.End.OpCode.OperandType == OperandType.ShortInlineBrTarget) { - if (node.End.OpCode == OpCodes.Leave || node.End.OpCode == OpCodes.Leave_S) { - var handlerBlock = FindInnermostHandlerBlock(node.End.Offset); - if (handlerBlock.NodeType == ControlFlowNodeType.FinallyOrFaultHandler) - CreateEdge(node, (Instruction)node.End.Operand, JumpType.LeaveTry); - else - CreateEdge(node, (Instruction)node.End.Operand, JumpType.Normal); - } else { - CreateEdge(node, (Instruction)node.End.Operand, JumpType.Normal); - } - } else if (node.End.OpCode.OperandType == OperandType.InlineSwitch) { - foreach (Instruction i in (Instruction[])node.End.Operand) - CreateEdge(node, i, JumpType.Normal); - } - - // create edges for return instructions - if (node.End.OpCode.FlowControl == FlowControl.Return) { - switch (node.End.OpCode.Code) { - case Code.Ret: - CreateEdge(node, regularExit, JumpType.Normal); - break; - case Code.Endfinally: - ControlFlowNode handlerBlock = FindInnermostHandlerBlock(node.End.Offset); - if (handlerBlock.EndFinallyOrFaultNode == null) - throw new InvalidProgramException("Found endfinally in block " + handlerBlock); - CreateEdge(node, handlerBlock.EndFinallyOrFaultNode, JumpType.Normal); - break; - default: - throw new NotSupportedException(node.End.OpCode.ToString()); - } - } - } - } - } - #endregion - - #region Step 4: create edges for the exceptional control flow (from instructions that might throw, to the innermost containing exception handler) - void CreateExceptionalControlFlow() - { - foreach (ControlFlowNode node in nodes) { - if (node.End != null && CanThrowException(node.End.OpCode)) { - CreateEdge(node, FindInnermostExceptionHandlerNode(node.End.Offset), JumpType.JumpToExceptionHandler); - } - if (node.ExceptionHandler != null) { - if (node.EndFinallyOrFaultNode != null) { - // For Fault and Finally blocks, create edge from "EndFinally" to next exception handler. - // This represents the exception bubbling up after finally block was executed. - CreateEdge(node.EndFinallyOrFaultNode, FindParentExceptionHandlerNode(node), JumpType.JumpToExceptionHandler); - } else { - // For Catch blocks, create edge from "CatchHandler" block (at beginning) to next exception handler. - // This represents the exception bubbling up because it did not match the type of the catch block. - CreateEdge(node, FindParentExceptionHandlerNode(node), JumpType.JumpToExceptionHandler); - } - CreateEdge(node, node.ExceptionHandler.HandlerStart, JumpType.Normal); - } - } - } - - ExceptionHandler FindInnermostExceptionHandler(int instructionOffsetInTryBlock) - { - foreach (ExceptionHandler h in methodBody.ExceptionHandlers) { - if (h.TryStart.Offset <= instructionOffsetInTryBlock && instructionOffsetInTryBlock < h.TryEnd.Offset) { - return h; - } - } - return null; - } - - ControlFlowNode FindInnermostExceptionHandlerNode(int instructionOffsetInTryBlock) - { - ExceptionHandler h = FindInnermostExceptionHandler(instructionOffsetInTryBlock); - if (h != null) - return nodes.Single(n => n.ExceptionHandler == h && n.CopyFrom == null); - else - return exceptionalExit; - } - - ControlFlowNode FindInnermostHandlerBlock(int instructionOffset) - { - foreach (ExceptionHandler h in methodBody.ExceptionHandlers) { - if (h.TryStart.Offset <= instructionOffset && instructionOffset < h.TryEnd.Offset - || h.HandlerStart.Offset <= instructionOffset && instructionOffset < h.HandlerEnd.Offset) - { - return nodes.Single(n => n.ExceptionHandler == h && n.CopyFrom == null); - } - } - return exceptionalExit; - } - - ControlFlowNode FindParentExceptionHandlerNode(ControlFlowNode exceptionHandler) - { - Debug.Assert(exceptionHandler.NodeType == ControlFlowNodeType.CatchHandler - || exceptionHandler.NodeType == ControlFlowNodeType.FinallyOrFaultHandler); - int offset = exceptionHandler.ExceptionHandler.TryStart.Offset; - for (int i = exceptionHandler.BlockIndex + 1; i < nodes.Count; i++) { - ExceptionHandler h = nodes[i].ExceptionHandler; - if (h != null && h.TryStart.Offset <= offset && offset < h.TryEnd.Offset) - return nodes[i]; - } - return exceptionalExit; - } - #endregion - - #region Step 5a: replace LeaveTry edges with EndFinally edges - // this is used only for copyFinallyBlocks==false; see Step 5b otherwise - void TransformLeaveEdges() - { - for (int i = nodes.Count - 1; i >= 0; i--) { - ControlFlowNode node = nodes[i]; - if (node.End != null && node.Outgoing.Count == 1 && node.Outgoing[0].Type == JumpType.LeaveTry) { - Debug.Assert(node.End.OpCode == OpCodes.Leave || node.End.OpCode == OpCodes.Leave_S); - - ControlFlowNode target = node.Outgoing[0].Target; - // remove the edge - target.Incoming.Remove(node.Outgoing[0]); - node.Outgoing.Clear(); - - ControlFlowNode handler = FindInnermostExceptionHandlerNode(node.End.Offset); - Debug.Assert(handler.NodeType == ControlFlowNodeType.FinallyOrFaultHandler); - - CreateEdge(node, handler, JumpType.Normal); - CreateEdge(handler.EndFinallyOrFaultNode, target, JumpType.EndFinally); - } - } - } - #endregion - - #region Step 5b: copy finally blocks into the LeaveTry edges - void CopyFinallyBlocksIntoLeaveEdges() - { - // We need to process try-finally blocks inside-out. - // We'll do that by going through all instructions in reverse order - for (int i = nodes.Count - 1; i >= 0; i--) { - ControlFlowNode node = nodes[i]; - if (node.End != null && node.Outgoing.Count == 1 && node.Outgoing[0].Type == JumpType.LeaveTry) { - Debug.Assert(node.End.OpCode == OpCodes.Leave || node.End.OpCode == OpCodes.Leave_S); - - ControlFlowNode target = node.Outgoing[0].Target; - // remove the edge - target.Incoming.Remove(node.Outgoing[0]); - node.Outgoing.Clear(); - - ControlFlowNode handler = FindInnermostExceptionHandlerNode(node.End.Offset); - Debug.Assert(handler.NodeType == ControlFlowNodeType.FinallyOrFaultHandler); - - ControlFlowNode copy = CopyFinallySubGraph(handler, handler.EndFinallyOrFaultNode, target); - CreateEdge(node, copy, JumpType.Normal); - } - } - } - - /// <summary> - /// Creates a copy of all nodes pointing to 'end' and replaces those references with references to 'newEnd'. - /// Nodes pointing to the copied node are copied recursively to update those references, too. - /// This recursion stops at 'start'. The modified version of start is returned. - /// </summary> - ControlFlowNode CopyFinallySubGraph(ControlFlowNode start, ControlFlowNode end, ControlFlowNode newEnd) - { - return new CopyFinallySubGraphLogic(this, start, end, newEnd).CopyFinallySubGraph(); - } - - class CopyFinallySubGraphLogic - { - readonly ControlFlowGraphBuilder builder; - readonly Dictionary<ControlFlowNode, ControlFlowNode> oldToNew = new Dictionary<ControlFlowNode, ControlFlowNode>(); - readonly ControlFlowNode start; - readonly ControlFlowNode end; - readonly ControlFlowNode newEnd; - - public CopyFinallySubGraphLogic(ControlFlowGraphBuilder builder, ControlFlowNode start, ControlFlowNode end, ControlFlowNode newEnd) - { - this.builder = builder; - this.start = start; - this.end = end; - this.newEnd = newEnd; - } - - internal ControlFlowNode CopyFinallySubGraph() - { - foreach (ControlFlowNode n in end.Predecessors) { - CollectNodes(n); - } - foreach (var pair in oldToNew) - ReconstructEdges(pair.Key, pair.Value); - return GetNew(start); - } - - void CollectNodes(ControlFlowNode node) - { - if (node == end || node == newEnd) - throw new InvalidOperationException("unexpected cycle involving finally construct"); - if (!oldToNew.ContainsKey(node)) { - int newBlockIndex = builder.nodes.Count; - ControlFlowNode copy; - switch (node.NodeType) { - case ControlFlowNodeType.Normal: - copy = new ControlFlowNode(newBlockIndex, node.Start, node.End); - break; - case ControlFlowNodeType.FinallyOrFaultHandler: - copy = new ControlFlowNode(newBlockIndex, node.ExceptionHandler, node.EndFinallyOrFaultNode); - break; - default: - // other nodes shouldn't occur when copying finally blocks - throw new NotSupportedException(node.NodeType.ToString()); - } - copy.CopyFrom = node; - builder.nodes.Add(copy); - oldToNew.Add(node, copy); - - if (node != start) { - foreach (ControlFlowNode n in node.Predecessors) { - CollectNodes(n); - } - } - } - } - - void ReconstructEdges(ControlFlowNode oldNode, ControlFlowNode newNode) - { - foreach (ControlFlowEdge oldEdge in oldNode.Outgoing) { - builder.CreateEdge(newNode, GetNew(oldEdge.Target), oldEdge.Type); - } - } - - ControlFlowNode GetNew(ControlFlowNode oldNode) - { - if (oldNode == end) - return newEnd; - ControlFlowNode newNode; - if (oldToNew.TryGetValue(oldNode, out newNode)) - return newNode; - return oldNode; - } - } - #endregion - - #region CreateEdge methods - void CreateEdge(ControlFlowNode fromNode, Instruction toInstruction, JumpType type) - { - CreateEdge(fromNode, nodes.Single(n => n.Start == toInstruction), type); - } - - void CreateEdge(ControlFlowNode fromNode, ControlFlowNode toNode, JumpType type) - { - ControlFlowEdge edge = new ControlFlowEdge(fromNode, toNode, type); - fromNode.Outgoing.Add(edge); - toNode.Incoming.Add(edge); - } - #endregion - - #region OpCode info - static bool CanThrowException(OpCode opcode) - { - if (opcode.OpCodeType == OpCodeType.Prefix) - return false; - return OpCodeInfo.Get(opcode).CanThrow; - } - - static bool IsBranch(OpCode opcode) - { - if (opcode.OpCodeType == OpCodeType.Prefix) - return false; - switch (opcode.FlowControl) { - case FlowControl.Cond_Branch: - case FlowControl.Branch: - case FlowControl.Throw: - case FlowControl.Return: - return true; - case FlowControl.Next: - case FlowControl.Call: - return false; - default: - throw new NotSupportedException(opcode.FlowControl.ToString()); - } - } - #endregion - } -} |