コード例 #1
0
 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);
 }
コード例 #2
0
ファイル: ILAstOptimizer.cs プロジェクト: FriedWishes/ILSpy
 static void FindLoopContents(HashSet<ControlFlowNode> nodes, HashSet<ControlFlowNode> loopContents, ControlFlowNode loopHead, ControlFlowNode addNode)
 {
     if (nodes.Contains(addNode) && loopHead.Dominates(addNode) && loopContents.Add(addNode)) {
         foreach (var edge in addNode.Incoming) {
             FindLoopContents(nodes, loopContents, loopHead, edge.Source);
         }
     }
 }
コード例 #3
0
ファイル: LoopsAndConditions.cs プロジェクト: levisre/dnSpy
		ControlFlowGraph BuildGraph(List<ILNode> nodes, ILLabel entryLabel)
		{
			cached_ControlFlowGraph.Nodes.Clear();
			int index = 0;
			var cfNodes = cached_ControlFlowGraph.Nodes;
			ControlFlowNode entryPoint = new ControlFlowNode(index++, 0, ControlFlowNodeType.EntryPoint);
			cfNodes.Add(entryPoint);
			ControlFlowNode regularExit = new ControlFlowNode(index++, null, ControlFlowNodeType.RegularExit);
			cfNodes.Add(regularExit);
			ControlFlowNode exceptionalExit = new ControlFlowNode(index++, null, ControlFlowNodeType.ExceptionalExit);
			cfNodes.Add(exceptionalExit);

			// Create graph nodes
			labelToCfNode.Clear();
			Dictionary<ILNode, ControlFlowNode> astNodeToCfNode = new Dictionary<ILNode, ControlFlowNode>();
			List<ILLabel> listLabels = null;
			foreach(ILBasicBlock node in nodes) {
				ControlFlowNode cfNode = new ControlFlowNode(index++, null, ControlFlowNodeType.Normal);
				cfNodes.Add(cfNode);
				astNodeToCfNode[node] = cfNode;
				cfNode.UserData = node;
				
				// Find all contained labels
				foreach(ILLabel label in node.GetSelfAndChildrenRecursive<ILLabel>(listLabels ?? (listLabels = new List<ILLabel>()))) {
					labelToCfNode[label] = cfNode;
				}
			}
			
			// Entry endge
			ControlFlowNode entryNode = labelToCfNode[entryLabel];
			ControlFlowEdge entryEdge = new ControlFlowEdge(entryPoint, entryNode, JumpType.Normal);
			entryPoint.Outgoing.Add(entryEdge);
			entryNode.Incoming.Add(entryEdge);

			// Create edges
			List<ILExpression> listExpressions = null;
			foreach(ILBasicBlock node in nodes) {
				ControlFlowNode source = astNodeToCfNode[node];
				
				// Find all branches
				foreach(ILLabel target in node.GetSelfAndChildrenRecursive<ILExpression>(listExpressions ?? (listExpressions = new List<ILExpression>()), e => e.IsBranch()).SelectMany(e => e.GetBranchTargets())) {
					ControlFlowNode destination;
					// Labels which are out of out scope will not be in the collection
					// Insert self edge only if we are sure we are a loop
					if (labelToCfNode.TryGetValue(target, out destination) && (destination != source || target == node.Body.FirstOrDefault())) {
						ControlFlowEdge edge = new ControlFlowEdge(source, destination, JumpType.Normal);
						source.Outgoing.Add(edge);
						destination.Incoming.Add(edge);
					}
				}
			}

			return cached_ControlFlowGraph;
		}
コード例 #4
0
		private 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);
		}
コード例 #5
0
ファイル: LoopsAndConditions.cs プロジェクト: n017/dnSpy
        static HashSet<ControlFlowNode> FindDominatedNodes(HashSet<ControlFlowNode> scope, ControlFlowNode head)
        {
            HashSet<ControlFlowNode> agenda = new HashSet<ControlFlowNode>();
            HashSet<ControlFlowNode> result = new HashSet<ControlFlowNode>();
            agenda.Add(head);

            while(agenda.Count > 0) {
                ControlFlowNode addNode = agenda.First();
                agenda.Remove(addNode);

                if (scope.Contains(addNode) && head.Dominates(addNode) && result.Add(addNode)) {
                    for (int i = 0; i < addNode.Outgoing.Count; i++) {
                        agenda.Add(addNode.Outgoing[i].Target);
                    }
                }
            }

            return result;
        }
コード例 #6
0
ファイル: ILAstOptimizer.cs プロジェクト: FriedWishes/ILSpy
        static HashSet<ControlFlowNode> FindDominatedNodes(HashSet<ControlFlowNode> nodes, ControlFlowNode head)
        {
            var exitNodes = head.DominanceFrontier.SelectMany(n => n.Predecessors);
            HashSet<ControlFlowNode> agenda = new HashSet<ControlFlowNode>(exitNodes);
            HashSet<ControlFlowNode> result = new HashSet<ControlFlowNode>();

            while(agenda.Count > 0) {
                ControlFlowNode addNode = agenda.First();
                agenda.Remove(addNode);

                if (nodes.Contains(addNode) && head.Dominates(addNode) && result.Add(addNode)) {
                    foreach (var predecessor in addNode.Predecessors) {
                        agenda.Add(predecessor);
                    }
                }
            }
            if (nodes.Contains(head))
                result.Add(head);

            return result;
        }
コード例 #7
0
		/// <summary>
		/// Gets whether <c>this</c> dominates <paramref name="node"/>.
		/// </summary>
		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;
		}
コード例 #8
0
		internal ControlFlowNode(int blockIndex, ExceptionHandler exceptionHandler, ControlFlowNode endFinallyOrFaultNode)
		{
			BlockIndex = blockIndex;
			NodeType = endFinallyOrFaultNode != null ? ControlFlowNodeType.FinallyOrFaultHandler : ControlFlowNodeType.CatchHandler;
			ExceptionHandler = exceptionHandler;
			EndFinallyOrFaultNode = endFinallyOrFaultNode;
			Debug.Assert((exceptionHandler.HandlerType == ExceptionHandlerType.Finally || exceptionHandler.HandlerType == ExceptionHandlerType.Fault) == (endFinallyOrFaultNode != null));
			Offset = exceptionHandler.HandlerStart.Offset;
		}
コード例 #9
0
ファイル: ControlFlowGraph.cs プロジェクト: GreenDamTan/dnSpy
		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"
			FindCommonDominator_path1.Clear();
			while (b1 != null && FindCommonDominator_path1.Add(b1))
				b1 = b1.ImmediateDominator;
			while (b2 != null) {
				if (FindCommonDominator_path1.Contains(b2))
					return b2;
				else
					b2 = b2.ImmediateDominator;
			}
			throw new Exception("No common dominator found!");
		}
コード例 #10
0
		void CreateEdge(ControlFlowNode fromNode, ControlFlowNode toNode, JumpType type)
		{
			ControlFlowEdge edge = new ControlFlowEdge(fromNode, toNode, type);
			fromNode.Outgoing.Add(edge);
			toNode.Incoming.Add(edge);
		}
コード例 #11
0
			ControlFlowNode GetNew(ControlFlowNode oldNode)
			{
				if (oldNode == end)
					return newEnd;
				ControlFlowNode newNode;
				if (oldToNew.TryGetValue(oldNode, out newNode))
					return newNode;
				return oldNode;
			}
コード例 #12
0
			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);
						}
					}
				}
			}
コード例 #13
0
		/// <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();
		}
コード例 #14
0
ファイル: ILAstOptimizer.cs プロジェクト: FriedWishes/ILSpy
        ControlFlowGraph BuildGraph(List<ILNode> nodes, ILLabel entryLabel)
        {
            int index = 0;
            List<ControlFlowNode> cfNodes = new List<ControlFlowNode>();
            ControlFlowNode entryPoint = new ControlFlowNode(index++, 0, ControlFlowNodeType.EntryPoint);
            cfNodes.Add(entryPoint);
            ControlFlowNode regularExit = new ControlFlowNode(index++, -1, ControlFlowNodeType.RegularExit);
            cfNodes.Add(regularExit);
            ControlFlowNode exceptionalExit = new ControlFlowNode(index++, -1, ControlFlowNodeType.ExceptionalExit);
            cfNodes.Add(exceptionalExit);

            // Create graph nodes
            labelToCfNode = new Dictionary<ILLabel, ControlFlowNode>();
            Dictionary<ILNode, ControlFlowNode>  astNodeToCfNode = new Dictionary<ILNode, ControlFlowNode>();
            foreach(ILNode node in nodes) {
                ControlFlowNode cfNode = new ControlFlowNode(index++, -1, ControlFlowNodeType.Normal);
                cfNodes.Add(cfNode);
                astNodeToCfNode[node] = cfNode;
                cfNode.UserData = node;

                // Find all contained labels
                foreach(ILLabel label in node.GetSelfAndChildrenRecursive<ILLabel>()) {
                    labelToCfNode[label] = cfNode;
                }
            }

            // Entry endge
            ControlFlowNode entryNode = labelToCfNode[entryLabel];
            ControlFlowEdge entryEdge = new ControlFlowEdge(entryPoint, entryNode, JumpType.Normal);
            entryPoint.Outgoing.Add(entryEdge);
            entryNode.Incoming.Add(entryEdge);

            // Create edges
            foreach(ILNode node in nodes) {
                ControlFlowNode source = astNodeToCfNode[node];

                // Find all branches
                foreach(ILExpression child in node.GetSelfAndChildrenRecursive<ILExpression>()) {
                    IEnumerable<ILLabel> targets = child.GetBranchTargets();
                    if (targets != null) {
                        foreach(ILLabel target in targets) {
                            ControlFlowNode destination;
                            // Labels which are out of out scope will not be int the collection
                            if (labelToCfNode.TryGetValue(target, out destination) && destination != source) {
                                ControlFlowEdge edge = new ControlFlowEdge(source, destination, JumpType.Normal);
                                source.Outgoing.Add(edge);
                                destination.Incoming.Add(edge);
                            }
                        }
                    }
                }
            }

            return new ControlFlowGraph(cfNodes.ToArray());
        }
コード例 #15
0
ファイル: ILAstOptimizer.cs プロジェクト: petr-k/ILSpy
        List<ILNode> FindLoops(HashSet<ControlFlowNode> scope, ControlFlowNode entryPoint, bool excludeEntryPoint)
        {
            List<ILNode> result = new List<ILNode>();

            Queue<ControlFlowNode> agenda  = new Queue<ControlFlowNode>();
            agenda.Enqueue(entryPoint);
            while(agenda.Count > 0) {
                ControlFlowNode node = agenda.Dequeue();

                if (scope.Contains(node)
                        && node.DominanceFrontier.Contains(node)
                        && (node != entryPoint || !excludeEntryPoint))
                {
                    HashSet<ControlFlowNode> loopContents = FindDominatedNodes(scope, node);

                    ILWhileLoop loop = new ILWhileLoop();

                    ILCondition cond;
                    HashSet<ControlFlowNode> condNodes;
                    ILLabel condLabel;
                    if (TryMatchCondition(loopContents, new ControlFlowNode[]{}, node, out cond, out condNodes, out condLabel)) {
                        loopContents.ExceptWith(condNodes);
                        scope.ExceptWith(condNodes);
                        // Use loop to implement condition
                        loop.Condition      = cond.Condition;
                        loop.PreLoopLabel   = condLabel;
                        loop.PostLoopGoto   = cond.FalseBlock.EntryGoto;
                        loop.BodyBlock      = new ILBlock() { EntryGoto = cond.TrueBlock.EntryGoto };
                    } else {
                        // Give the block some explicit entry point
                        ILLabel entryLabel  = new ILLabel() { Name = "Loop_" + (nextBlockIndex++) };
                        loop.BodyBlock      = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, entryLabel) };
                        ((ILBasicBlock)node.UserData).Body.Insert(0, entryLabel);
                    }
                    loop.BodyBlock.Body = FindLoops(loopContents, node, true);

                    // Move the content into loop block
                    scope.ExceptWith(loopContents);
                    result.Add(loop);
                }

                // Using the dominator tree should ensure we find the the widest loop first
                foreach(var child in node.DominatorTreeChildren) {
                    agenda.Enqueue(child);
                }
            }

            // Add whatever is left
            foreach(var node in scope) {
                result.Add((ILNode)node.UserData);
            }

            return result;
        }
コード例 #16
0
ファイル: ILAstOptimizer.cs プロジェクト: FriedWishes/ILSpy
        List<ILNode> FindLoops(HashSet<ControlFlowNode> nodes, ControlFlowNode entryPoint, bool excludeEntryPoint)
        {
            List<ILNode> result = new List<ILNode>();

            Queue<ControlFlowNode> agenda  = new Queue<ControlFlowNode>();
            agenda.Enqueue(entryPoint);
            while(agenda.Count > 0) {
                ControlFlowNode node = agenda.Dequeue();

                if (nodes.Contains(node)
                        && node.DominanceFrontier.Contains(node)
                        && (node != entryPoint || !excludeEntryPoint))
                {
                    HashSet<ControlFlowNode> loopContents = new HashSet<ControlFlowNode>();
                    FindLoopContents(nodes, loopContents, node, node);

                    // Move the content into loop block
                    nodes.ExceptWith(loopContents);
                    ILLabel entryLabel = new ILLabel() { Name = "Loop_" + (nextBlockIndex++) };
                    ((ILBlock)node.UserData).Body.Insert(0, entryLabel);
                    result.Add(new ILLoop() { ContentBlock = new ILBlock(FindLoops(loopContents, node, true)) { EntryPoint = entryLabel } });
                }

                // Using the dominator tree should ensure we find the the widest loop first
                foreach(var child in node.DominatorTreeChildren) {
                    agenda.Enqueue(child);
                }
            }

            // Add whatever is left
            foreach(var node in nodes) {
                result.Add((ILNode)node.UserData);
            }

            return result;
        }
コード例 #17
0
ファイル: ILAstOptimizer.cs プロジェクト: FriedWishes/ILSpy
        List<ILNode> FindConditions(HashSet<ControlFlowNode> nodes, ControlFlowNode entryNode)
        {
            List<ILNode> result = new List<ILNode>();

            Queue<ControlFlowNode> agenda  = new Queue<ControlFlowNode>();
            agenda.Enqueue(entryNode);
            while(agenda.Count > 0) {
                ControlFlowNode node = agenda.Dequeue();

                // Find a block that represents a simple condition
                if (nodes.Contains(node)) {

                    ILMoveableBlock block = node.UserData as ILMoveableBlock;

                    if (block != null && block.Body.Count == 3) {

                        ILLabel      label      = block.Body[0] as ILLabel;
                        ILExpression condBranch = block.Body[1] as ILExpression;
                        ILExpression statBranch = block.Body[2] as ILExpression;

                        // Switch
                        if (label != null &&
                            condBranch != null && condBranch.Operand is ILLabel[] && condBranch.Arguments.Count > 0 &&
                            statBranch != null && statBranch.Operand is ILLabel   && statBranch.Arguments.Count == 0)
                        {
                            ILSwitch ilSwitch = new ILSwitch() { Condition = condBranch };

                            // Replace the two branches with a conditional structure - this preserves the node label
                            block.Body.Remove(condBranch);
                            block.Body.Remove(statBranch);
                            block.Body.Add(ilSwitch);

                            ControlFlowNode statTarget = null;
                            labelToCfNode.TryGetValue((ILLabel)statBranch.Operand, out statTarget);

                            // Pull in the conditional code
                            HashSet<ControlFlowNode> frontiers = new HashSet<ControlFlowNode>();

                            if (statTarget != null)
                                frontiers.UnionWith(statTarget.DominanceFrontier);

                            foreach(ILLabel condLabel in (ILLabel[])condBranch.Operand) {
                                ControlFlowNode condTarget = null;
                                labelToCfNode.TryGetValue(condLabel, out condTarget);

                                if (condTarget != null)
                                    frontiers.UnionWith(condTarget.DominanceFrontier);
                            }

                            foreach(ILLabel condLabel in (ILLabel[])condBranch.Operand) {
                                ControlFlowNode condTarget = null;
                                labelToCfNode.TryGetValue(condLabel, out condTarget);

                                ILBlock caseBlock = new ILBlock() { EntryPoint = condLabel };
                                if (condTarget != null && !frontiers.Contains(condTarget)) {
                                    HashSet<ControlFlowNode> content = FindDominatedNodes(nodes, condTarget);
                                    nodes.ExceptWith(content);
                                    caseBlock.Body.AddRange(FindConditions(content, condTarget));
                                }
                                ilSwitch.CaseBlocks.Add(caseBlock);
                            }

                            // The labels will not be used - kill them
                            condBranch.Operand = null;

                            result.Add(block);
                            nodes.Remove(node);
                        }

                        // Two-way branch
                        if (label != null &&
                            condBranch != null && condBranch.Operand is ILLabel && condBranch.Arguments.Count > 0 &&
                            statBranch != null && statBranch.Operand is ILLabel && statBranch.Arguments.Count == 0)
                        {
                            ControlFlowNode statTarget = null;
                            labelToCfNode.TryGetValue((ILLabel)statBranch.Operand, out statTarget);
                            ControlFlowNode condTarget = null;
                            labelToCfNode.TryGetValue((ILLabel)condBranch.Operand, out condTarget);

                            ILCondition condition = new ILCondition() {
                                Condition  = condBranch,
                                TrueBlock  = new ILBlock() { EntryPoint = (ILLabel)condBranch.Operand },
                                FalseBlock = new ILBlock() { EntryPoint = (ILLabel)statBranch.Operand }
                            };

                            // Replace the two branches with a conditional structure - this preserves the node label
                            block.Body.Remove(condBranch);
                            block.Body.Remove(statBranch);
                            block.Body.Add(condition);

                            // Pull in the conditional code
                            HashSet<ControlFlowNode> frontiers = new HashSet<ControlFlowNode>();
                            if (statTarget != null)
                                frontiers.UnionWith(statTarget.DominanceFrontier);
                            if (condTarget != null)
                                frontiers.UnionWith(condTarget.DominanceFrontier);

                            if (condTarget != null && !frontiers.Contains(condTarget)) {
                                HashSet<ControlFlowNode> content = FindDominatedNodes(nodes, condTarget);
                                nodes.ExceptWith(content);
                                condition.TrueBlock.Body.AddRange(FindConditions(content, condTarget));
                            }
                            if (statTarget != null && !frontiers.Contains(statTarget)) {
                                HashSet<ControlFlowNode> content = FindDominatedNodes(nodes, statTarget);
                                nodes.ExceptWith(content);
                                condition.FalseBlock.Body.AddRange(FindConditions(content, statTarget));
                            }

                            // The label will not be used - kill it
                            condBranch.Operand = null;

                            result.Add(block);
                            nodes.Remove(node);
                        }
                    }

                    // Add the node now so that we have good ordering
                    if (nodes.Contains(node)) {
                        result.Add((ILNode)node.UserData);
                        nodes.Remove(node);
                    }
                }

                // Using the dominator tree should ensure we find the the widest loop first
                foreach(var child in node.DominatorTreeChildren) {
                    agenda.Enqueue(child);
                }
            }

            // Add whatever is left
            foreach(var node in nodes) {
                result.Add((ILNode)node.UserData);
            }

            return result;
        }
コード例 #18
0
ファイル: SsaBlock.cs プロジェクト: FaceHunter/ILSpy
		internal SsaBlock(ControlFlowNode node)
		{
			this.NodeType = node.NodeType;
			this.BlockIndex = node.BlockIndex;
		}
コード例 #19
0
		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));
			}
		}
コード例 #20
0
		List<ILNode> FindLoops(HashSet<ControlFlowNode> scope, ControlFlowNode entryPoint, bool excludeEntryPoint)
		{
			List<ILNode> result = new List<ILNode>();
			
			// Do not modify entry data
			scope = new HashSet<ControlFlowNode>(scope);
			
			Queue<ControlFlowNode> agenda  = new Queue<ControlFlowNode>();
			agenda.Enqueue(entryPoint);
			while(agenda.Count > 0) {
				ControlFlowNode node = agenda.Dequeue();
				
				// If the node is a loop header
				if (scope.Contains(node)
				    && node.DominanceFrontier.Contains(node)
				    && (node != entryPoint || !excludeEntryPoint))
				{
					HashSet<ControlFlowNode> loopContents = FindLoopContent(scope, node);
					
					// If the first expression is a loop condition
					ILBasicBlock basicBlock = (ILBasicBlock)node.UserData;
					ILExpression condExpr;
					ILLabel trueLabel;
					ILLabel falseLabel;
					// It has to be just brtrue - any preceding code would introduce goto
					if(basicBlock.MatchSingleAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel))
					{
						ControlFlowNode trueTarget;
						labelToCfNode.TryGetValue(trueLabel, out trueTarget);
						ControlFlowNode falseTarget;
						labelToCfNode.TryGetValue(falseLabel, out falseTarget);
						
						// If one point inside the loop and the other outside
						if ((!loopContents.Contains(trueTarget) && loopContents.Contains(falseTarget)) ||
						    (loopContents.Contains(trueTarget) && !loopContents.Contains(falseTarget)) )
						{
							loopContents.RemoveOrThrow(node);
							scope.RemoveOrThrow(node);
							
							// If false means enter the loop
							if (loopContents.Contains(falseTarget) || falseTarget == node)
							{
								// Negate the condition
								condExpr = new ILExpression(ILCode.LogicNot, null, condExpr);
								ILLabel tmp = trueLabel;
								trueLabel = falseLabel;
								falseLabel = tmp;
							}
							
							ControlFlowNode postLoopTarget;
							labelToCfNode.TryGetValue(falseLabel, out postLoopTarget);
							if (postLoopTarget != null) {
								// Pull more nodes into the loop
								HashSet<ControlFlowNode> postLoopContents = FindDominatedNodes(scope, postLoopTarget);
								var pullIn = scope.Except(postLoopContents).Where(n => node.Dominates(n));
								loopContents.UnionWith(pullIn);
							}
							
							// Use loop to implement the brtrue
							basicBlock.Body.RemoveTail(ILCode.Brtrue, ILCode.Br);
							basicBlock.Body.Add(new ILWhileLoop() {
								Condition = condExpr,
								BodyBlock = new ILBlock() {
									EntryGoto = new ILExpression(ILCode.Br, trueLabel),
									Body = FindLoops(loopContents, node, false)
								}
							});
							basicBlock.Body.Add(new ILExpression(ILCode.Br, falseLabel));
							result.Add(basicBlock);
							
							scope.ExceptWith(loopContents);
						}
					}
					
					// Fallback method: while(true)
					if (scope.Contains(node)) {
						result.Add(new ILBasicBlock() {
							Body = new List<ILNode>() {
								new ILLabel() { Name = "Loop_" + (nextLabelIndex++) },
								new ILWhileLoop() {
									BodyBlock = new ILBlock() {
										EntryGoto = new ILExpression(ILCode.Br, (ILLabel)basicBlock.Body.First()),
										Body = FindLoops(loopContents, node, true)
									}
								},
							},
						});
						
						scope.ExceptWith(loopContents);
					}
				}

				// Using the dominator tree should ensure we find the the widest loop first
				foreach(var child in node.DominatorTreeChildren) {
					agenda.Enqueue(child);
				}
			}
			
			// Add whatever is left
			foreach(var node in scope) {
				result.Add((ILNode)node.UserData);
			}
			scope.Clear();
			
			return result;
		}
コード例 #21
0
		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;
		}
コード例 #22
0
		List<ILNode> FindConditions(HashSet<ControlFlowNode> scope, ControlFlowNode entryNode)
		{
			List<ILNode> result = new List<ILNode>();
			
			// Do not modify entry data
			scope = new HashSet<ControlFlowNode>(scope);
			
			Stack<ControlFlowNode> agenda  = new Stack<ControlFlowNode>();
			agenda.Push(entryNode);
			while(agenda.Count > 0) {
				ControlFlowNode node = agenda.Pop();
				
				// Find a block that represents a simple condition
				if (scope.Contains(node)) {
					
					ILBasicBlock block = (ILBasicBlock)node.UserData;
					
					{
						// Switch
						ILLabel[] caseLabels;
						ILExpression switchArg;
						ILLabel fallLabel;
						if (block.MatchLastAndBr(ILCode.Switch, out caseLabels, out switchArg, out fallLabel)) {
							
							// Replace the switch code with ILSwitch
							ILSwitch ilSwitch = new ILSwitch() { Condition = switchArg };
							block.Body.RemoveTail(ILCode.Switch, ILCode.Br);
							block.Body.Add(ilSwitch);
							block.Body.Add(new ILExpression(ILCode.Br, fallLabel));
							result.Add(block);

							// Remove the item so that it is not picked up as content
							scope.RemoveOrThrow(node);
							
							// Find the switch offset
							int addValue = 0;
							List<ILExpression> subArgs;
							if (ilSwitch.Condition.Match(ILCode.Sub, out subArgs) && subArgs[1].Match(ILCode.Ldc_I4, out addValue)) {
								ilSwitch.Condition = subArgs[0];
							}
							
							// Pull in code of cases
							ControlFlowNode fallTarget = null;
							labelToCfNode.TryGetValue(fallLabel, out fallTarget);
							
							HashSet<ControlFlowNode> frontiers = new HashSet<ControlFlowNode>();
							if (fallTarget != null)
								frontiers.UnionWith(fallTarget.DominanceFrontier.Except(new [] { fallTarget }));
							
							foreach(ILLabel condLabel in caseLabels) {
								ControlFlowNode condTarget = null;
								labelToCfNode.TryGetValue(condLabel, out condTarget);
								if (condTarget != null)
									frontiers.UnionWith(condTarget.DominanceFrontier.Except(new [] { condTarget }));
							}
							
							for (int i = 0; i < caseLabels.Length; i++) {
								ILLabel condLabel = caseLabels[i];
								
								// Find or create new case block
								ILSwitch.CaseBlock caseBlock = ilSwitch.CaseBlocks.FirstOrDefault(b => b.EntryGoto.Operand == condLabel);
								if (caseBlock == null) {
									caseBlock = new ILSwitch.CaseBlock() {
										Values = new List<int>(),
										EntryGoto = new ILExpression(ILCode.Br, condLabel)
									};
									ilSwitch.CaseBlocks.Add(caseBlock);
									
									ControlFlowNode condTarget = null;
									labelToCfNode.TryGetValue(condLabel, out condTarget);
									if (condTarget != null && !frontiers.Contains(condTarget)) {
										HashSet<ControlFlowNode> content = FindDominatedNodes(scope, condTarget);
										scope.ExceptWith(content);
										caseBlock.Body.AddRange(FindConditions(content, condTarget));
										// Add explicit break which should not be used by default, but the goto removal might decide to use it
										caseBlock.Body.Add(new ILBasicBlock() {
											Body = {
												new ILLabel() { Name = "SwitchBreak_" + (nextLabelIndex++) },
												new ILExpression(ILCode.LoopOrSwitchBreak, null)
											}
										});
									}
								}
								caseBlock.Values.Add(i + addValue);
							}
							
							// Heuristis to determine if we want to use fallthough as default case
							if (fallTarget != null && !frontiers.Contains(fallTarget)) {
								HashSet<ControlFlowNode> content = FindDominatedNodes(scope, fallTarget);
								if (content.Any()) {
									var caseBlock = new ILSwitch.CaseBlock() { EntryGoto = new ILExpression(ILCode.Br, fallLabel) };
									ilSwitch.CaseBlocks.Add(caseBlock);
									block.Body.RemoveTail(ILCode.Br);
									
									scope.ExceptWith(content);
									caseBlock.Body.AddRange(FindConditions(content, fallTarget));
									// Add explicit break which should not be used by default, but the goto removal might decide to use it
									caseBlock.Body.Add(new ILBasicBlock() {
										Body = {
											new ILLabel() { Name = "SwitchBreak_" + (nextLabelIndex++) },
											new ILExpression(ILCode.LoopOrSwitchBreak, null)
										}
									});
								}
							}
						}
						
						// Two-way branch
						ILExpression condExpr;
						ILLabel trueLabel;
						ILLabel falseLabel;
						if(block.MatchLastAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel)) {
							
							// Swap bodies since that seems to be the usual C# order
							ILLabel temp = trueLabel;
							trueLabel = falseLabel;
							falseLabel = temp;
							condExpr = new ILExpression(ILCode.LogicNot, null, condExpr);
							
							// Convert the brtrue to ILCondition
							ILCondition ilCond = new ILCondition() {
								Condition  = condExpr,
								TrueBlock  = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, trueLabel) },
								FalseBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, falseLabel) }
							};
							block.Body.RemoveTail(ILCode.Brtrue, ILCode.Br);
							block.Body.Add(ilCond);
							result.Add(block);
							
							// Remove the item immediately so that it is not picked up as content
							scope.RemoveOrThrow(node);
							
							ControlFlowNode trueTarget = null;
							labelToCfNode.TryGetValue(trueLabel, out trueTarget);
							ControlFlowNode falseTarget = null;
							labelToCfNode.TryGetValue(falseLabel, out falseTarget);
							
							// Pull in the conditional code
							if (trueTarget != null && HasSingleEdgeEnteringBlock(trueTarget)) {
								HashSet<ControlFlowNode> content = FindDominatedNodes(scope, trueTarget);
								scope.ExceptWith(content);
								ilCond.TrueBlock.Body.AddRange(FindConditions(content, trueTarget));
							}
							if (falseTarget != null && HasSingleEdgeEnteringBlock(falseTarget)) {
								HashSet<ControlFlowNode> content = FindDominatedNodes(scope, falseTarget);
								scope.ExceptWith(content);
								ilCond.FalseBlock.Body.AddRange(FindConditions(content, falseTarget));
							}
						}
					}
					
					// Add the node now so that we have good ordering
					if (scope.Contains(node)) {
						result.Add((ILNode)node.UserData);
						scope.Remove(node);
					}
				}

				// depth-first traversal of dominator tree
				for (int i = node.DominatorTreeChildren.Count - 1; i >= 0; i--) {
					agenda.Push(node.DominatorTreeChildren[i]);
				}
			}
			
			// Add whatever is left
			foreach(var node in scope) {
				result.Add((ILNode)node.UserData);
			}
			
			return result;
		}
コード例 #23
0
			public CopyFinallySubGraphLogic(ControlFlowGraphBuilder builder, ControlFlowNode start, ControlFlowNode end, ControlFlowNode newEnd)
			{
				this.builder = builder;
				this.start = start;
				this.end = end;
				this.newEnd = newEnd;
			}
コード例 #24
0
ファイル: ILAstOptimizer.cs プロジェクト: petr-k/ILSpy
        List<ILNode> FindConditions(HashSet<ControlFlowNode> scope, ControlFlowNode entryNode)
        {
            List<ILNode> result = new List<ILNode>();

            HashSet<ControlFlowNode> agenda  = new HashSet<ControlFlowNode>();
            agenda.Add(entryNode);
            while(agenda.Any()) {
                ControlFlowNode node = agenda.First();
                // Attempt for a good order
                while(agenda.Contains(node.ImmediateDominator)) {
                    node = node.ImmediateDominator;
                }
                agenda.Remove(node);

                // Find a block that represents a simple condition
                if (scope.Contains(node)) {

                    ILBasicBlock block = node.UserData as ILBasicBlock;

                    if (block != null && block.Body.Count == 1) {

                        ILExpression condBranch = block.Body[0] as ILExpression;

                        // Switch
                        if (condBranch != null && condBranch.Operand is ILLabel[] && condBranch.Arguments.Count > 0) {

                            ILSwitch ilSwitch = new ILSwitch() {
                                Condition = condBranch,
                                DefaultGoto = block.FallthoughGoto
                            };

                            ControlFlowNode fallTarget = null;
                            labelToCfNode.TryGetValue((ILLabel)block.FallthoughGoto.Operand, out fallTarget);

                            HashSet<ControlFlowNode> frontiers = new HashSet<ControlFlowNode>();
                            if (fallTarget != null)
                                frontiers.UnionWith(fallTarget.DominanceFrontier);

                            foreach(ILLabel condLabel in (ILLabel[])condBranch.Operand) {
                                ControlFlowNode condTarget = null;
                                labelToCfNode.TryGetValue(condLabel, out condTarget);
                                if (condTarget != null)
                                    frontiers.UnionWith(condTarget.DominanceFrontier);
                            }

                            foreach(ILLabel condLabel in (ILLabel[])condBranch.Operand) {
                                ControlFlowNode condTarget = null;
                                labelToCfNode.TryGetValue(condLabel, out condTarget);

                                ILBlock caseBlock = new ILBlock() {
                                    EntryGoto = new ILExpression(ILCode.Br, condLabel)
                                };
                                if (condTarget != null && !frontiers.Contains(condTarget)) {
                                    HashSet<ControlFlowNode> content = FindDominatedNodes(scope, condTarget);
                                    scope.ExceptWith(content);
                                    caseBlock.Body.AddRange(FindConditions(content, condTarget));
                                }
                                ilSwitch.CaseBlocks.Add(caseBlock);
                            }

                            // The labels will not be used - kill them
                            condBranch.Operand = null;

                            result.Add(new ILBasicBlock() {
                                EntryLabel = block.EntryLabel,  // Keep the entry label
                                Body = { ilSwitch }
                            });
                            scope.Remove(node);
                        }

                        // Two-way branch
                        ILCondition ilCond;
                        HashSet<ControlFlowNode> matchedNodes;
                        ILLabel condEntryLabel;
                        if (TryMatchCondition(scope, new ControlFlowNode[] {}, node, out ilCond, out matchedNodes, out condEntryLabel)) {

                            // The branch labels will not be used - kill them
                            foreach(ILExpression expr in ilCond.Condition.GetSelfAndChildrenRecursive<ILExpression>()) {
                                if (expr.GetBranchTargets().Any()) {
                                    expr.Operand = null;
                                }
                            }

                            ControlFlowNode trueTarget = null;
                            labelToCfNode.TryGetValue((ILLabel)ilCond.TrueBlock.EntryGoto.Operand, out trueTarget);
                            ControlFlowNode falseTarget = null;
                            labelToCfNode.TryGetValue((ILLabel)ilCond.FalseBlock.EntryGoto.Operand, out falseTarget);

                            // Pull in the conditional code
                            HashSet<ControlFlowNode> frontiers = new HashSet<ControlFlowNode>();
                            if (trueTarget != null)
                                frontiers.UnionWith(trueTarget.DominanceFrontier);
                            if (falseTarget != null)
                                frontiers.UnionWith(falseTarget.DominanceFrontier);

                            if (trueTarget != null && !frontiers.Contains(trueTarget)) {
                                HashSet<ControlFlowNode> content = FindDominatedNodes(scope, trueTarget);
                                scope.ExceptWith(content);
                                ilCond.TrueBlock.Body.AddRange(FindConditions(content, trueTarget));
                            }
                            if (falseTarget != null && !frontiers.Contains(falseTarget)) {
                                HashSet<ControlFlowNode> content = FindDominatedNodes(scope, falseTarget);
                                scope.ExceptWith(content);
                                ilCond.FalseBlock.Body.AddRange(FindConditions(content, falseTarget));
                            }

                            result.Add(new ILBasicBlock() {
                                EntryLabel = condEntryLabel,  // Keep the entry label
                                Body = { ilCond }
                            });
                            scope.ExceptWith(matchedNodes);
                        }
                    }

                    // Add the node now so that we have good ordering
                    if (scope.Contains(node)) {
                        result.Add((ILNode)node.UserData);
                        scope.Remove(node);
                    }
                }

                // Using the dominator tree should ensure we find the the widest loop first
                foreach(var child in node.DominatorTreeChildren) {
                    agenda.Add(child);
                }
            }

            // Add whatever is left
            foreach(var node in scope) {
                result.Add((ILNode)node.UserData);
            }

            return result;
        }
コード例 #25
0
			void ReconstructEdges(ControlFlowNode oldNode, ControlFlowNode newNode)
			{
				foreach (ControlFlowEdge oldEdge in oldNode.Outgoing) {
					builder.CreateEdge(newNode, GetNew(oldEdge.Target), oldEdge.Type);
				}
			}
コード例 #26
0
		static HashSet<ControlFlowNode> FindDominatedNodes(HashSet<ControlFlowNode> scope, ControlFlowNode head)
		{
			HashSet<ControlFlowNode> agenda = new HashSet<ControlFlowNode>();
			HashSet<ControlFlowNode> result = new HashSet<ControlFlowNode>();
			agenda.Add(head);
			
			while(agenda.Count > 0) {
				ControlFlowNode addNode = agenda.First();
				agenda.Remove(addNode);
				
				if (scope.Contains(addNode) && head.Dominates(addNode) && result.Add(addNode)) {
					foreach (var successor in addNode.Successors) {
						agenda.Add(successor);
					}
				}
			}
			
			return result;
		}
コード例 #27
0
		void CreateEdge(ControlFlowNode fromNode, Instruction toInstruction, JumpType type)
		{
			CreateEdge(fromNode, nodes.Single(n => n.Start == toInstruction), type);
		}
コード例 #28
0
		static HashSet<ControlFlowNode> FindLoopContent(HashSet<ControlFlowNode> scope, ControlFlowNode head)
		{
			var viaBackEdges = head.Predecessors.Where(p => head.Dominates(p));
			HashSet<ControlFlowNode> agenda = new HashSet<ControlFlowNode>(viaBackEdges);
			HashSet<ControlFlowNode> result = new HashSet<ControlFlowNode>();
			
			while(agenda.Count > 0) {
				ControlFlowNode addNode = agenda.First();
				agenda.Remove(addNode);
				
				if (scope.Contains(addNode) && head.Dominates(addNode) && result.Add(addNode)) {
					foreach (var predecessor in addNode.Predecessors) {
						agenda.Add(predecessor);
					}
				}
			}
			if (scope.Contains(head))
				result.Add(head);
			
			return result;
		}
コード例 #29
0
		static bool HasSingleEdgeEnteringBlock(ControlFlowNode node)
		{
			return node.Incoming.Count(edge => !node.Dominates(edge.Source)) == 1;
		}
コード例 #30
0
ファイル: ILAstOptimizer.cs プロジェクト: petr-k/ILSpy
        bool TryMatchCondition(HashSet<ControlFlowNode> scope, IEnumerable<ControlFlowNode> scopeExcept, ControlFlowNode head, out ILCondition condition, out HashSet<ControlFlowNode> matchedNodes, out ILLabel entryLabel)
        {
            condition = null;
            matchedNodes = null;
            entryLabel = null;
            if (!scope.Contains(head) || scopeExcept.Contains(head))
                return false;

            ILBasicBlock basicBlock = head.UserData as ILBasicBlock;

            if (basicBlock == null || basicBlock.Body.Count != 1)
                return false;

            ILExpression condBranch = basicBlock.Body[0] as ILExpression;

            if (condBranch != null && condBranch.Operand is ILLabel && condBranch.Arguments.Count > 0) {

                // We have found a two-way condition
                condition = new ILCondition() {
                    Condition  = condBranch,
                    TrueBlock  = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, condBranch.Operand) },
                    FalseBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, basicBlock.FallthoughGoto.Operand) }
                };
                // We are done with the node so "remove" it from scope
                scopeExcept  = scopeExcept.Union(new[] {head});
                matchedNodes = new HashSet<ControlFlowNode>() { head };
                entryLabel   = basicBlock.EntryLabel;

                // Optimize short-circut expressions
                while(true) {

                    // Consider condition.TrueBlock
                    {
                        ILLabel nextLabel = (ILLabel)condition.TrueBlock.EntryGoto.Operand;
                        ControlFlowNode nextTarget;
                        labelToCfNode.TryGetValue(nextLabel, out nextTarget);
                        ILCondition nextCond;
                        HashSet<ControlFlowNode> nextMatchedNodes;
                        ILLabel nextEnteryLabel;
                        if (nextTarget != null &&
                            TryMatchCondition(scope, scopeExcept, nextTarget, out nextCond, out nextMatchedNodes, out nextEnteryLabel) &&
                            labelRefCount[nextEnteryLabel] == 1)
                        {
                            if (condition.FalseBlock.EntryGoto.Operand == nextCond.FalseBlock.EntryGoto.Operand) {
                                    condition.Condition  = new ILExpression(ILCode.LogicAnd, null, condition.Condition, nextCond.Condition);
                                    condition.TrueBlock  = nextCond.TrueBlock;
                                    condition.FalseBlock = nextCond.FalseBlock;
                                    scopeExcept = scopeExcept.Union(nextMatchedNodes);
                                    matchedNodes.UnionWith(nextMatchedNodes);
                                    continue;
                            }

                            if (condition.FalseBlock.EntryGoto.Operand == nextCond.TrueBlock.EntryGoto.Operand) {
                                condition.Condition  = new ILExpression(ILCode.LogicOr, null, new ILExpression(ILCode.LogicNot, null, condition.Condition), nextCond.Condition);
                                    condition.TrueBlock  = nextCond.TrueBlock;
                                    condition.FalseBlock = nextCond.FalseBlock;
                                    scopeExcept = scopeExcept.Union(nextMatchedNodes);
                                    matchedNodes.UnionWith(nextMatchedNodes);
                                    continue;
                            }
                        }
                    }

                    // Consider condition.FalseBlock
                    {
                        ILLabel nextLabel = (ILLabel)condition.FalseBlock.EntryGoto.Operand;
                        ControlFlowNode nextTarget;
                        labelToCfNode.TryGetValue(nextLabel, out nextTarget);
                        ILCondition nextCond;
                        HashSet<ControlFlowNode> nextMatchedNodes;
                        ILLabel nextEnteryLabel;
                        if (nextTarget != null &&
                            TryMatchCondition(scope, scopeExcept, nextTarget, out nextCond, out nextMatchedNodes, out nextEnteryLabel) &&
                            labelRefCount[nextEnteryLabel] == 1)
                        {
                            if (condition.TrueBlock.EntryGoto.Operand == nextCond.FalseBlock.EntryGoto.Operand) {
                                condition.Condition  = new ILExpression(ILCode.LogicAnd, null, new ILExpression(ILCode.LogicNot, null, condition.Condition), nextCond.Condition);
                                    condition.TrueBlock  = nextCond.TrueBlock;
                                    condition.FalseBlock = nextCond.FalseBlock;
                                    scopeExcept = scopeExcept.Union(nextMatchedNodes);
                                    matchedNodes.UnionWith(nextMatchedNodes);
                                    continue;
                            }

                            if (condition.TrueBlock.EntryGoto.Operand == nextCond.TrueBlock.EntryGoto.Operand) {
                                condition.Condition  = new ILExpression(ILCode.LogicOr, null, condition.Condition, nextCond.Condition);
                                    condition.TrueBlock  = nextCond.TrueBlock;
                                    condition.FalseBlock = nextCond.FalseBlock;
                                    scopeExcept = scopeExcept.Union(nextMatchedNodes);
                                    matchedNodes.UnionWith(nextMatchedNodes);
                                    continue;
                            }
                        }
                    }
                    break;
                }
                return true;
            }
            return false;
        }