diff --git a/ICSharpCode.Decompiler/ILAst/GotoRemoval.cs b/ICSharpCode.Decompiler/ILAst/GotoRemoval.cs index d1fc15c7c..6fb4acf8e 100644 --- a/ICSharpCode.Decompiler/ILAst/GotoRemoval.cs +++ b/ICSharpCode.Decompiler/ILAst/GotoRemoval.cs @@ -18,8 +18,8 @@ namespace ICSharpCode.Decompiler.ILAst foreach (ILNode node in method.GetSelfAndChildrenRecursive()) { ILNode previousChild = null; foreach (ILNode child in node.GetChildren()) { - // TODO: Add back - // Debug.Assert(!parent.ContainsKey(child)); + if (parent.ContainsKey(child)) + throw new Exception("The following expression is linked from several locations: " + child.ToString()); parent[child] = node; if (previousChild != null) nextSibling[previousChild] = child; diff --git a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs index 94e6f9628..eb19e00a8 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs @@ -168,6 +168,7 @@ namespace ICSharpCode.Decompiler.ILAst if (abortBeforeStep == ILAstOptimizationStep.CachedDelegateInitialization) return; foreach(ILBlock block in method.GetSelfAndChildrenRecursive()) { for (int i = 0; i < block.Body.Count; i++) { + // TODO: Move before loops CachedDelegateInitialization(block, ref i); } } @@ -175,6 +176,7 @@ namespace ICSharpCode.Decompiler.ILAst if (abortBeforeStep == ILAstOptimizationStep.IntroduceFixedStatements) return; foreach(ILBlock block in method.GetSelfAndChildrenRecursive()) { for (int i = 0; i < block.Body.Count; i++) { + // TODO: Move before loops IntroduceFixedStatements(block.Body, i); } } @@ -285,59 +287,51 @@ namespace ICSharpCode.Decompiler.ILAst List basicBlocks = new List(); ILBasicBlock basicBlock = new ILBasicBlock() { - EntryLabel = new ILLabel() { Name = "Block_" + (nextLabelIndex++) } + EntryLabel = block.Body.FirstOrDefault() as ILLabel ?? new ILLabel() { Name = "Block_" + (nextLabelIndex++) } }; basicBlocks.Add(basicBlock); block.EntryGoto = new ILExpression(ILCode.Br, basicBlock.EntryLabel); if (block.Body.Count > 0) { - basicBlock.Body.Add(block.Body[0]); + if (block.Body[0] != basicBlock.EntryLabel) + basicBlock.Body.Add(block.Body[0]); for (int i = 1; i < block.Body.Count; i++) { ILNode lastNode = block.Body[i - 1]; ILNode currNode = block.Body[i]; - // Insert split + // Start a new basic block if necessary if (currNode is ILLabel || lastNode is ILTryCatchBlock || currNode is ILTryCatchBlock || - (lastNode is ILExpression) && ((ILExpression)lastNode).IsBranch() || - (currNode is ILExpression) && (((ILExpression)currNode).IsBranch() && ((ILExpression)currNode).Code.CanFallThough() && basicBlock.Body.Count > 0)) + (lastNode is ILExpression && ((ILExpression)lastNode).IsBranch())) { - ILBasicBlock lastBlock = basicBlock; - basicBlock = new ILBasicBlock(); - basicBlocks.Add(basicBlock); + // Try to reuse the label + ILLabel label = currNode is ILLabel ? ((ILLabel)currNode) : new ILLabel() { Name = "Block_" + (nextLabelIndex++) }; - if (currNode is ILLabel) { - // Insert as entry label - basicBlock.EntryLabel = (ILLabel)currNode; - } else { - basicBlock.EntryLabel = new ILLabel() { Name = "Block_" + (nextLabelIndex++) }; - basicBlock.Body.Add(currNode); + // Terminate the last block + if (lastNode.CanFallThough()) { + // Explicit branch from one block to other + basicBlock.FallthoughGoto = new ILExpression(ILCode.Br, label); + } else if (lastNode.Match(ILCode.Br)) { + // Reuse the existing goto as FallthoughGoto + basicBlock.FallthoughGoto = (ILExpression)lastNode; + basicBlock.Body.RemoveAt(basicBlock.Body.Count - 1); } - // Explicit branch from one block to other - // (unless the last expression was unconditional branch) - if (!(lastNode is ILExpression) || ((ILExpression)lastNode).Code.CanFallThough()) { - lastBlock.FallthoughGoto = new ILExpression(ILCode.Br, basicBlock.EntryLabel); - } - } else { + // Start the new block + basicBlock = new ILBasicBlock(); + basicBlocks.Add(basicBlock); + basicBlock.EntryLabel = label; + } + + // Add the node to the basic block + if (currNode != basicBlock.EntryLabel) { basicBlock.Body.Add(currNode); } } } - foreach (ILBasicBlock bb in basicBlocks) { - if (bb.Body.Count > 0 && - bb.Body.Last() is ILExpression && - ((ILExpression)bb.Body.Last()).Code == ILCode.Br) - { - Debug.Assert(bb.FallthoughGoto == null); - bb.FallthoughGoto = (ILExpression)bb.Body.Last(); - bb.Body.RemoveAt(bb.Body.Count - 1); - } - } - block.Body = basicBlocks; return; } @@ -362,7 +356,6 @@ namespace ICSharpCode.Decompiler.ILAst } } - // scope is modified if successful bool SimplifyTernaryOperator(List body, ILBasicBlock head, int pos) { Debug.Assert(body.Contains(head)); @@ -378,13 +371,13 @@ namespace ICSharpCode.Decompiler.ILAst ILLabel falseFall; object unused; - if (head.Match(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel) && + if (head.MatchLast(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel) && labelGlobalRefCount[trueLabel] == 1 && labelGlobalRefCount[falseLabel] == 1 && - ((labelToBasicBlock[trueLabel].Match(ILCode.Stloc, out trueLocVar, out trueExpr, out trueFall) && - labelToBasicBlock[falseLabel].Match(ILCode.Stloc, out falseLocVar, out falseExpr, out falseFall)) || - (labelToBasicBlock[trueLabel].Match(ILCode.Ret, out unused, out trueExpr, out trueFall) && - labelToBasicBlock[falseLabel].Match(ILCode.Ret, out unused, out falseExpr, out falseFall))) && + ((labelToBasicBlock[trueLabel].MatchSingle(ILCode.Stloc, out trueLocVar, out trueExpr, out trueFall) && + labelToBasicBlock[falseLabel].MatchSingle(ILCode.Stloc, out falseLocVar, out falseExpr, out falseFall)) || + (labelToBasicBlock[trueLabel].MatchSingle(ILCode.Ret, out unused, out trueExpr, out trueFall) && + labelToBasicBlock[falseLabel].MatchSingle(ILCode.Ret, out unused, out falseExpr, out falseFall))) && trueLocVar == falseLocVar && trueFall == falseFall && body.Contains(labelToBasicBlock[trueLabel]) && @@ -436,7 +429,7 @@ namespace ICSharpCode.Decompiler.ILAst // Create ternary expression newExpr = new ILExpression(ILCode.TernaryOp, null, condExpr, trueExpr, falseExpr); } - head.Body = new List() { new ILExpression(opCode, trueLocVar, newExpr) }; + head.Body[head.Body.Count - 1] = new ILExpression(opCode, trueLocVar, newExpr); head.FallthoughGoto = trueFall != null ? new ILExpression(ILCode.Br, trueFall) : null; // Remove the old basic blocks @@ -455,57 +448,45 @@ namespace ICSharpCode.Decompiler.ILAst { // ... // v = ldloc(leftVar) - // br(condBBLabel) - // - // condBBLabel: // brtrue(endBBLabel, ldloc(leftVar)) // br(rightBBLabel) // // rightBBLabel: // v = rightExpr // br(endBBLabel) - // - // endBBLabel: // ... + // => + // ... + // v = NullCoalescing(ldloc(leftVar), rightExpr) + // br(endBBLabel) ILVariable v, v2; ILExpression leftExpr, leftExpr2; - ILVariable leftVar, leftVar2; - ILLabel condBBLabel; - ILBasicBlock condBB; + ILVariable leftVar; ILLabel endBBLabel, endBBLabel2; ILLabel rightBBLabel; ILBasicBlock rightBB; ILExpression rightExpr; - ILBasicBlock endBB; - if (head.Body.LastOrDefault().Match(ILCode.Stloc, out v, out leftExpr) && + if (head.Body.Count >= 2 && + head.Body[head.Body.Count - 2].Match(ILCode.Stloc, out v, out leftExpr) && leftExpr.Match(ILCode.Ldloc, out leftVar) && - head.FallthoughGoto.Match(ILCode.Br, out condBBLabel) && - labelToBasicBlock.TryGetValue(condBBLabel, out condBB) && - condBB.Match(ILCode.Brtrue, out endBBLabel, out leftExpr2, out rightBBLabel) && - leftExpr2.Match(ILCode.Ldloc, out leftVar2) && - leftVar == leftVar2 && + head.MatchLast(ILCode.Brtrue, out endBBLabel, out leftExpr2, out rightBBLabel) && + leftExpr2.Match(ILCode.Ldloc, leftVar) && labelToBasicBlock.TryGetValue(rightBBLabel, out rightBB) && - rightBB.Match(ILCode.Stloc, out v2, out rightExpr, out endBBLabel2) && + rightBB.MatchSingle(ILCode.Stloc, out v2, out rightExpr, out endBBLabel2) && v == v2 && endBBLabel == endBBLabel2 && - labelToBasicBlock.TryGetValue(endBBLabel, out endBB) && - labelGlobalRefCount.GetOrDefault(condBBLabel) == 1 && labelGlobalRefCount.GetOrDefault(rightBBLabel) == 1 && - labelGlobalRefCount.GetOrDefault(endBBLabel) == 2 && - body.Contains(condBB) && - body.Contains(rightBB) && - body.Contains(endBB) + body.Contains(rightBB) ) { - head.Body[head.Body.Count - 1] = new ILExpression(ILCode.Stloc, v, new ILExpression(ILCode.NullCoalescing, null, leftExpr, rightExpr)); + head.Body[head.Body.Count - 2] = new ILExpression(ILCode.Stloc, v, new ILExpression(ILCode.NullCoalescing, null, leftExpr, rightExpr)); + head.Body.RemoveAt(head.Body.Count - 1); head.FallthoughGoto = new ILExpression(ILCode.Br, endBBLabel); - foreach(ILLabel deleteLabel in new [] { condBBLabel, rightBBLabel }) { - body.RemoveOrThrow(labelToBasicBlock[deleteLabel]); - labelGlobalRefCount.RemoveOrThrow(deleteLabel); - labelToBasicBlock.RemoveOrThrow(deleteLabel); - } + body.RemoveOrThrow(labelToBasicBlock[rightBBLabel]); + labelGlobalRefCount.RemoveOrThrow(rightBBLabel); + labelToBasicBlock.RemoveOrThrow(rightBBLabel); return true; } return false; @@ -518,7 +499,7 @@ namespace ICSharpCode.Decompiler.ILAst ILExpression condExpr; ILLabel trueLabel; ILLabel falseLabel; - if(head.Match(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel)) { + if(head.MatchLast(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel)) { for (int pass = 0; pass < 2; pass++) { // On the second pass, swap labels and negate expression of the first branch @@ -534,14 +515,14 @@ namespace ICSharpCode.Decompiler.ILAst if (body.Contains(nextBasicBlock) && nextBasicBlock != head && labelGlobalRefCount[nextBasicBlock.EntryLabel] == 1 && - nextBasicBlock.Match(ILCode.Brtrue, out nextTrueLablel, out nextCondExpr, out nextFalseLabel) && + nextBasicBlock.MatchSingle(ILCode.Brtrue, out nextTrueLablel, out nextCondExpr, out nextFalseLabel) && (otherLablel == nextFalseLabel || otherLablel == nextTrueLablel)) { // Create short cicuit branch if (otherLablel == nextFalseLabel) { - head.Body[0] = new ILExpression(ILCode.Brtrue, nextTrueLablel, new ILExpression(ILCode.LogicAnd, null, negate ? new ILExpression(ILCode.LogicNot, null, condExpr) : condExpr, nextCondExpr)); + head.Body[head.Body.Count - 1] = new ILExpression(ILCode.Brtrue, nextTrueLablel, new ILExpression(ILCode.LogicAnd, null, negate ? new ILExpression(ILCode.LogicNot, null, condExpr) : condExpr, nextCondExpr)); } else { - head.Body[0] = new ILExpression(ILCode.Brtrue, nextTrueLablel, new ILExpression(ILCode.LogicOr, null, negate ? condExpr : new ILExpression(ILCode.LogicNot, null, condExpr), nextCondExpr)); + head.Body[head.Body.Count - 1] = new ILExpression(ILCode.Brtrue, nextTrueLablel, new ILExpression(ILCode.LogicOr, null, negate ? condExpr : new ILExpression(ILCode.LogicNot, null, condExpr), nextCondExpr)); } head.FallthoughGoto = new ILExpression(ILCode.Br, nextFalseLabel); diff --git a/ICSharpCode.Decompiler/ILAst/LoopsAndConditions.cs b/ICSharpCode.Decompiler/ILAst/LoopsAndConditions.cs index 7676bdb86..79516ceac 100644 --- a/ICSharpCode.Decompiler/ILAst/LoopsAndConditions.cs +++ b/ICSharpCode.Decompiler/ILAst/LoopsAndConditions.cs @@ -27,20 +27,24 @@ namespace ICSharpCode.Decompiler.ILAst public void FindLoops(ILBlock block) { - ControlFlowGraph graph; - graph = BuildGraph(block.Body, (ILLabel)block.EntryGoto.Operand); - graph.ComputeDominance(context.CancellationToken); - graph.ComputeDominanceFrontier(); - block.Body = FindLoops(new HashSet(graph.Nodes.Skip(3)), graph.EntryPoint, false); + if (block.Body.Count > 0) { + ControlFlowGraph graph; + graph = BuildGraph(block.Body, (ILLabel)block.EntryGoto.Operand); + graph.ComputeDominance(context.CancellationToken); + graph.ComputeDominanceFrontier(); + block.Body = FindLoops(new HashSet(graph.Nodes.Skip(3)), graph.EntryPoint, false); + } } public void FindConditions(ILBlock block) { - ControlFlowGraph graph; - graph = BuildGraph(block.Body, (ILLabel)block.EntryGoto.Operand); - graph.ComputeDominance(context.CancellationToken); - graph.ComputeDominanceFrontier(); - block.Body = FindConditions(new HashSet(graph.Nodes.Skip(3)), graph.EntryPoint); + if (block.Body.Count > 0) { + ControlFlowGraph graph; + graph = BuildGraph(block.Body, (ILLabel)block.EntryGoto.Operand); + graph.ComputeDominance(context.CancellationToken); + graph.ComputeDominanceFrontier(); + block.Body = FindConditions(new HashSet(graph.Nodes.Skip(3)), graph.EntryPoint); + } } ControlFlowGraph BuildGraph(List nodes, ILLabel entryLabel) @@ -57,7 +61,7 @@ namespace ICSharpCode.Decompiler.ILAst // Create graph nodes labelToCfNode = new Dictionary(); Dictionary astNodeToCfNode = new Dictionary(); - foreach(ILNode node in nodes) { + foreach(ILBasicBlock node in nodes) { ControlFlowNode cfNode = new ControlFlowNode(index++, -1, ControlFlowNodeType.Normal); cfNodes.Add(cfNode); astNodeToCfNode[node] = cfNode; @@ -76,22 +80,18 @@ namespace ICSharpCode.Decompiler.ILAst entryNode.Incoming.Add(entryEdge); // Create edges - foreach(ILNode node in nodes) { + foreach(ILBasicBlock node in nodes) { ControlFlowNode source = astNodeToCfNode[node]; // Find all branches - foreach(ILExpression child in node.GetSelfAndChildrenRecursive()) { - IEnumerable 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); - } - } + foreach(ILLabel target in node.GetSelfAndChildrenRecursive(e => e.IsBranch()).SelectMany(e => e.GetBranchTargets())) { + ControlFlowNode destination; + // Labels which are out of out scope will not be int the collection + // Insert self edge only if we are sure we are a loop + if (labelToCfNode.TryGetValue(target, out destination) && (destination != source || target == node.EntryLabel)) { + ControlFlowEdge edge = new ControlFlowEdge(source, destination, JumpType.Normal); + source.Outgoing.Add(edge); + destination.Incoming.Add(edge); } } } @@ -123,7 +123,7 @@ namespace ICSharpCode.Decompiler.ILAst ILExpression condExpr; ILLabel trueLabel; ILLabel falseLabel; - if(basicBlock.Match(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel)) + if(basicBlock.MatchSingle(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel)) { ControlFlowNode trueTarget; labelToCfNode.TryGetValue(trueLabel, out trueTarget); @@ -138,7 +138,7 @@ namespace ICSharpCode.Decompiler.ILAst scope.RemoveOrThrow(node); // If false means enter the loop - if (loopContents.Contains(falseTarget)) + if (loopContents.Contains(falseTarget) || falseTarget == node) { // Negate the condition condExpr = new ILExpression(ILCode.LogicNot, null, condExpr); @@ -156,42 +156,39 @@ namespace ICSharpCode.Decompiler.ILAst loopContents.UnionWith(pullIn); } - // Use loop to implement the condition - result.Add(new ILBasicBlock() { - EntryLabel = basicBlock.EntryLabel, - Body = new List() { - new ILWhileLoop() { - Condition = condExpr, - BodyBlock = new ILBlock() { - EntryGoto = new ILExpression(ILCode.Br, trueLabel), - Body = FindLoops(loopContents, node, true) - } - }, - new ILExpression(ILCode.Br, falseLabel) - }, - FallthoughGoto = null - }); + // Use loop to implement the brtrue + basicBlock.Body.RemoveAt(basicBlock.Body.Count - 1); + basicBlock.Body.Add(new ILWhileLoop() { + Condition = condExpr, + BodyBlock = new ILBlock() { + EntryGoto = new ILExpression(ILCode.Br, trueLabel), + Body = FindLoops(loopContents, node, false) + } + }); + basicBlock.FallthoughGoto = new ILExpression(ILCode.Br, falseLabel); + result.Add(basicBlock); + + scope.ExceptWith(loopContents); } } // Fallback method: while(true) if (scope.Contains(node)) { result.Add(new ILBasicBlock() { - EntryLabel = new ILLabel() { Name = "Loop_" + (nextLabelIndex++) }, - Body = new List() { - new ILWhileLoop() { - BodyBlock = new ILBlock() { - EntryGoto = new ILExpression(ILCode.Br, basicBlock.EntryLabel), - Body = FindLoops(loopContents, node, true) - } - }, - }, - FallthoughGoto = null - }); + EntryLabel = new ILLabel() { Name = "Loop_" + (nextLabelIndex++) }, + Body = new List() { + new ILWhileLoop() { + BodyBlock = new ILBlock() { + EntryGoto = new ILExpression(ILCode.Br, basicBlock.EntryLabel), + Body = FindLoops(loopContents, node, true) + } + }, + }, + FallthoughGoto = null + }); + + scope.ExceptWith(loopContents); } - - // Move the content into loop block - scope.ExceptWith(loopContents); } // Using the dominator tree should ensure we find the the widest loop first @@ -229,24 +226,20 @@ namespace ICSharpCode.Decompiler.ILAst // Find a block that represents a simple condition if (scope.Contains(node)) { - ILBasicBlock block = node.UserData as ILBasicBlock; + ILBasicBlock block = (ILBasicBlock)node.UserData; - if (block != null && block.Body.Count == 1) { - - ILExpression condBranch = block.Body[0] as ILExpression; - + { // Switch ILLabel[] caseLabels; - List switchArgs; - if (condBranch.Match(ILCode.Switch, out caseLabels, out switchArgs)) { + ILExpression switchArg; + ILLabel fallLabel; + if (block.MatchLast(ILCode.Switch, out caseLabels, out switchArg, out fallLabel)) { - ILSwitch ilSwitch = new ILSwitch() { Condition = switchArgs.Single() }; - ILBasicBlock newBB = new ILBasicBlock() { - EntryLabel = block.EntryLabel, // Keep the entry label - Body = { ilSwitch }, - FallthoughGoto = block.FallthoughGoto - }; - result.Add(newBB); + // Replace the switch code with ILSwitch + ILSwitch ilSwitch = new ILSwitch() { Condition = switchArg }; + block.Body.RemoveAt(block.Body.Count - 1); + block.Body.Add(ilSwitch); + result.Add(block); // Remove the item so that it is not picked up as content scope.RemoveOrThrow(node); @@ -259,19 +252,18 @@ namespace ICSharpCode.Decompiler.ILAst } // Pull in code of cases - ILLabel fallLabel = (ILLabel)block.FallthoughGoto.Operand; ControlFlowNode fallTarget = null; labelToCfNode.TryGetValue(fallLabel, out fallTarget); HashSet frontiers = new HashSet(); if (fallTarget != null) - frontiers.UnionWith(fallTarget.DominanceFrontier); + 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); + frontiers.UnionWith(condTarget.DominanceFrontier.Except(new [] { condTarget })); } for (int i = 0; i < caseLabels.Length; i++) { @@ -305,7 +297,7 @@ namespace ICSharpCode.Decompiler.ILAst if (content.Any()) { var caseBlock = new ILSwitch.CaseBlock() { EntryGoto = new ILExpression(ILCode.Br, fallLabel) }; ilSwitch.CaseBlocks.Add(caseBlock); - newBB.FallthoughGoto = null; + block.FallthoughGoto = null; scope.ExceptWith(content); caseBlock.Body.AddRange(FindConditions(content, fallTarget)); @@ -319,7 +311,7 @@ namespace ICSharpCode.Decompiler.ILAst ILExpression condExpr; ILLabel trueLabel; ILLabel falseLabel; - if(block.Match(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel)) { + if(block.MatchLast(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel)) { // Swap bodies since that seems to be the usual C# order ILLabel temp = trueLabel; @@ -327,16 +319,16 @@ namespace ICSharpCode.Decompiler.ILAst falseLabel = temp; condExpr = new ILExpression(ILCode.LogicNot, null, condExpr); - // Convert the basic block to ILCondition + // 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) } }; - result.Add(new ILBasicBlock() { - EntryLabel = block.EntryLabel, // Keep the entry label - Body = { ilCond } - }); + block.Body.RemoveAt(block.Body.Count - 1); + block.Body.Add(ilCond); + block.FallthoughGoto = null; + result.Add(block); // Remove the item immediately so that it is not picked up as content scope.RemoveOrThrow(node); @@ -349,9 +341,9 @@ namespace ICSharpCode.Decompiler.ILAst // Pull in the conditional code HashSet frontiers = new HashSet(); if (trueTarget != null) - frontiers.UnionWith(trueTarget.DominanceFrontier); + frontiers.UnionWith(trueTarget.DominanceFrontier.Except(new [] { trueTarget })); if (falseTarget != null) - frontiers.UnionWith(falseTarget.DominanceFrontier); + frontiers.UnionWith(falseTarget.DominanceFrontier.Except(new [] { falseTarget })); if (trueTarget != null && !frontiers.Contains(trueTarget)) { HashSet content = FindDominatedNodes(scope, trueTarget); diff --git a/ICSharpCode.Decompiler/ILAst/PatternMatching.cs b/ICSharpCode.Decompiler/ILAst/PatternMatching.cs index 727d04f18..b8d1f3651 100644 --- a/ICSharpCode.Decompiler/ILAst/PatternMatching.cs +++ b/ICSharpCode.Decompiler/ILAst/PatternMatching.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; - +using System.Linq; using Mono.Cecil; namespace ICSharpCode.Decompiler.ILAst @@ -98,7 +98,7 @@ namespace ICSharpCode.Decompiler.ILAst return false; } - public static bool Match(this ILBasicBlock bb, ILCode code, out T operand, out ILExpression arg, out ILLabel fallLabel) + public static bool MatchSingle(this ILBasicBlock bb, ILCode code, out T operand, out ILExpression arg, out ILLabel fallLabel) { if (bb.Body.Count == 1) { if (bb.Body[0].Match(code, out operand, out arg)) { @@ -112,6 +112,18 @@ namespace ICSharpCode.Decompiler.ILAst return false; } + public static bool MatchLast(this ILBasicBlock bb, ILCode code, out T operand, out ILExpression arg, out ILLabel fallLabel) + { + if (bb.Body.LastOrDefault().Match(code, out operand, out arg)) { + fallLabel = bb.FallthoughGoto != null ? (ILLabel)bb.FallthoughGoto.Operand : null; + return true; + } + operand = default(T); + arg = null; + fallLabel = null; + return false; + } + public static bool MatchThis(this ILNode node) { ILVariable v;