private void SetTrueAndFalseSuccessors(CFGBlockLogicalConstruct cfgConditionBlock) { stackVariable1 = cfgConditionBlock.get_TheBlock(); V_0 = stackVariable1.get_Successors()[0]; V_1 = stackVariable1.get_Successors()[1]; V_2 = cfgConditionBlock.get_CFGSuccessors().GetEnumerator(); try { while (V_2.MoveNext()) { V_3 = V_2.get_Current(); if (InstructionBlock.op_Equality(V_3.get_TheBlock(), V_0)) { this.set_TrueCFGSuccessor(V_3); } if (!InstructionBlock.op_Equality(V_3.get_TheBlock(), V_1)) { continue; } this.set_FalseCFGSuccessor(V_3); } } finally { ((IDisposable)V_2).Dispose(); } return; }
private void ManageSuccessorInCaseOfLoop(CFGBlockLogicalConstruct cfgSuccessor) { if (this.get_FirstBlock() == cfgSuccessor) { this.AddToSuccessors(cfgSuccessor); V_0 = this.get_Children().GetEnumerator(); try { while (V_0.MoveNext()) { V_1 = (CFGBlockLogicalConstruct)V_0.get_Current(); if (!V_1.get_CFGSuccessors().Contains(cfgSuccessor)) { continue; } this.AddToPredecessors(V_1); } } finally { ((IDisposable)V_0).Dispose(); } } return; }
/// <summary> /// Negates the expression of the construct and switches the true and false successors. /// </summary> public void Negate(TypeSystem typeSystem) { CFGBlockLogicalConstruct successorHolder = TrueCFGSuccessor; TrueCFGSuccessor = FalseCFGSuccessor; FalseCFGSuccessor = successorHolder; ConditionExpression = Negator.Negate(ConditionExpression, typeSystem); }
private bool AllEndsAreThrow(ILogicalConstruct entry) { CFGBlockLogicalConstruct entryBlock = entry.FirstBlock; if (!SubtreeEndsInInstructionCode(entryBlock.TheBlock, new Code[] { Code.Throw })) { return(false); } return(true); }
private void MapSwitchBlocksToParents() { foreach (InstructionBlock instructionBlock in logicalContext.CFG.SwitchBlocksInformation.Keys) { CFGBlockLogicalConstruct[] constructs = logicalContext.CFGBlockToLogicalConstructMap[instructionBlock]; //We get the last CFG construct since it will hold the condition of the switch and its successors. CFGBlockLogicalConstruct instructionBlockConstruct = constructs[constructs.Length - 1]; AddSwitchCFGBlockToMap(instructionBlockConstruct); } }
private void AddSwitchCFGBlockToMap(CFGBlockLogicalConstruct cfgConstruct) { V_0 = cfgConstruct.get_Parent() as ILogicalConstruct; if (!this.logicalConstructToSwitchBlocksMap.TryGetValue(V_0, out V_1)) { V_1 = new List <CFGBlockLogicalConstruct>(); this.logicalConstructToSwitchBlocksMap.Add(V_0, V_1); } V_1.Add(cfgConstruct); return; }
private void AddSwitchCFGBlockToMap(CFGBlockLogicalConstruct cfgConstruct) { ILogicalConstruct parentConstruct = cfgConstruct.Parent as ILogicalConstruct; List<CFGBlockLogicalConstruct> switchCFGConstructs; if (!logicalConstructToSwitchBlocksMap.TryGetValue(parentConstruct, out switchCFGConstructs)) { switchCFGConstructs = new List<CFGBlockLogicalConstruct>(); logicalConstructToSwitchBlocksMap.Add(parentConstruct, switchCFGConstructs); } switchCFGConstructs.Add(cfgConstruct); }
private void AddSwitchCFGBlockToMap(CFGBlockLogicalConstruct cfgConstruct) { ILogicalConstruct parentConstruct = cfgConstruct.Parent as ILogicalConstruct; List <CFGBlockLogicalConstruct> switchCFGConstructs; if (!logicalConstructToSwitchBlocksMap.TryGetValue(parentConstruct, out switchCFGConstructs)) { switchCFGConstructs = new List <CFGBlockLogicalConstruct>(); logicalConstructToSwitchBlocksMap.Add(parentConstruct, switchCFGConstructs); } switchCFGConstructs.Add(cfgConstruct); }
private ConditionLogicalConstruct(CFGBlockLogicalConstruct cfgConditionBlock) { base(); this.set_Entry(cfgConditionBlock); this.SetTrueAndFalseSuccessors(cfgConditionBlock); this.set_ConditionExpression(cfgConditionBlock.get_LogicalConstructExpressions().get_Item(0)); stackVariable12 = new ILogicalConstruct[1]; stackVariable12[0] = cfgConditionBlock; this.RedirectChildrenToNewParent((IEnumerable <ILogicalConstruct>)stackVariable12); this.AddTrueFalseSuccessors(); this.set_LogicalContainer(null); return; }
private ConditionLogicalConstruct(CFGBlockLogicalConstruct cfgConditionBlock) { Entry = cfgConditionBlock; SetTrueAndFalseSuccessors(cfgConditionBlock); ConditionExpression = cfgConditionBlock.LogicalConstructExpressions[0]; RedirectChildrenToNewParent(new ILogicalConstruct[] { cfgConditionBlock }); AddTrueFalseSuccessors(); LogicalContainer = null; }
/// <summary> /// If the given successor is the entry of the condition we update the predecessor and successor collections of the condition. /// </summary> /// <param name="cfgSuccessor"></param> private void ManageSuccessorInCaseOfLoop(CFGBlockLogicalConstruct cfgSuccessor) { if (this.FirstBlock == cfgSuccessor) { this.AddToSuccessors(cfgSuccessor); foreach (CFGBlockLogicalConstruct cfgChild in this.Children) { if (cfgChild.CFGSuccessors.Contains(cfgSuccessor)) { this.AddToPredecessors(cfgChild); } } } }
/// <summary> /// Determines the weight of the given edge. /// </summary> /// <remarks> /// This is the heuristic part of the algorithm. /// The weight of an edge is determined by the number of CFG block constructs in the given <paramref name="start"/> construct, /// that have for successor the specified <paramref name="end"/> construct. /// </remarks> /// <param name="start"></param> /// <param name="end"></param> /// <returns></returns> private int GetWeight(ILogicalConstruct start, ILogicalConstruct end) { int weight = 0; CFGBlockLogicalConstruct endCFGEntry = end.FirstBlock; foreach (CFGBlockLogicalConstruct cfgChild in start.CFGBlocks) { if (cfgChild.CFGSuccessors.Contains(endCFGEntry)) { weight++; } } return(weight); }
private void CreateSwitchConstruct(CFGBlockLogicalConstruct switchBlock, ILogicalConstruct parentConstruct, SwitchData switchData, DominatorTree dominatorTree) { List <KeyValuePair <CFGBlockLogicalConstruct, List <int> > > cfgSuccessorToLabelsMap = GetOrderedCFGSuccessorToLabelsMap(switchData); Dictionary <ILogicalConstruct, HashSet <ISingleEntrySubGraph> > validCaseEntryToDominatedNodesMap = GetValidCases(dominatorTree, switchBlock); List <CaseLogicalConstruct> orderedCaseConstructs = new List <CaseLogicalConstruct>(); PairList <List <int>, CFGBlockLogicalConstruct> labelsToCFGSuccessorsList = new PairList <List <int>, CFGBlockLogicalConstruct>(); foreach (KeyValuePair <CFGBlockLogicalConstruct, List <int> > cfgSuccessorToLabelsPair in cfgSuccessorToLabelsMap) { ILogicalConstruct successor; HashSet <ISingleEntrySubGraph> dominatedNodes; if (LogicalFlowUtilities.TryGetParentConstructWithGivenParent(cfgSuccessorToLabelsPair.Key, parentConstruct, out successor) && validCaseEntryToDominatedNodesMap.TryGetValue(successor, out dominatedNodes)) { CaseLogicalConstruct newCaseConstruct = new CaseLogicalConstruct(successor); newCaseConstruct.CaseNumbers.AddRange(cfgSuccessorToLabelsPair.Value); newCaseConstruct.Body.UnionWith(dominatedNodes.Cast <ILogicalConstruct>()); newCaseConstruct.AttachCaseConstructToGraph(); orderedCaseConstructs.Add(newCaseConstruct); } else { labelsToCFGSuccessorsList.Add(cfgSuccessorToLabelsPair.Value, cfgSuccessorToLabelsPair.Key); } } CaseLogicalConstruct defaultCase = null; CFGBlockLogicalConstruct defaultCFGSuccessor = GetCFGLogicalConstructFromBlock(switchData.DefaultCase); ILogicalConstruct defaultSuccessor; HashSet <ISingleEntrySubGraph> defaultCaseNodes; if (LogicalFlowUtilities.TryGetParentConstructWithGivenParent(defaultCFGSuccessor, parentConstruct, out defaultSuccessor) && validCaseEntryToDominatedNodesMap.TryGetValue(defaultSuccessor, out defaultCaseNodes)) { defaultCase = new CaseLogicalConstruct(defaultSuccessor); if (HasSuccessors(defaultCaseNodes)) { defaultCase.Body.UnionWith(defaultCaseNodes.Cast <ILogicalConstruct>()); } defaultCase.AttachCaseConstructToGraph(); } SwitchLogicalConstruct theSwitch = SwitchLogicalConstruct.GroupInSwitchConstruct(switchBlock, orderedCaseConstructs, labelsToCFGSuccessorsList, defaultCase, defaultCFGSuccessor); UpdateDominatorTree(dominatorTree, theSwitch); }
ILogicalConstruct FindChildBlockBelongsTo(ILogicalConstruct parent, CFGBlockLogicalConstruct block) { ILogicalConstruct result = null, current = block; do { if (current.Parent == parent) { result = current; break; } current = (ILogicalConstruct)current.Parent; } while (current.Parent != null); return(result); }
private SwitchLogicalConstruct(CFGBlockLogicalConstruct entry, ICollection <CaseLogicalConstruct> body, PairList <List <int>, CFGBlockLogicalConstruct> nonDominatedCFGSuccessors, CaseLogicalConstruct defaultCase, CFGBlockLogicalConstruct defaultCFGSuccessor) { base(); this.set_SwitchConditionExpression(entry.get_LogicalConstructExpressions().get_Item(0)); this.set_DefaultCase(defaultCase); this.set_DefaultCFGSuccessor(defaultCFGSuccessor); this.set_NonDominatedCFGSuccessors(nonDominatedCFGSuccessors); this.FillCasesArray(body); this.set_Entry(entry); this.RedirectChildrenToNewParent(this.GetBodyCollection()); if (entry.get_CFGSuccessors().Contains(entry)) { this.AddToPredecessors(entry); this.AddToSuccessors(entry); } return; }
/// <summary> /// Creates simple conditions containing only one CFG construct (may be partial). /// </summary> private void CreateSimpleConditions() { //Since we've split the CFG constructs in the CFGBlockSplitter, we now know that if an instruction block is a condition block, //the last of the (partial) CFG constructs holds the condition expression. //The only thing left to check is if the block is not a switch block, since switch blocks are a special case and are not proccessed as //normal conditions. foreach (CFGBlockLogicalConstruct[] cfgConstructsArray in logicalBuilderContext.CFGBlockToLogicalConstructMap.Values) { CFGBlockLogicalConstruct cfgConstruct = cfgConstructsArray[cfgConstructsArray.Length - 1]; InstructionBlock theInstructionBlock = cfgConstruct.TheBlock; if (theInstructionBlock.Successors.Length == 2 && theInstructionBlock.Successors[0] != theInstructionBlock.Successors[1] && theInstructionBlock.Last.OpCode.Code != Code.Switch) { ConditionLogicalConstruct.GroupInSimpleConditionConstruct(cfgConstruct); } } }
private void CreateSwitchConstruct(CFGBlockLogicalConstruct switchBlock, ILogicalConstruct parentConstruct, SwitchData switchData, DominatorTree dominatorTree) { List<KeyValuePair<CFGBlockLogicalConstruct, List<int>>> cfgSuccessorToLabelsMap = GetOrderedCFGSuccessorToLabelsMap(switchData); Dictionary<ILogicalConstruct, HashSet<ISingleEntrySubGraph>> validCaseEntryToDominatedNodesMap = GetValidCases(dominatorTree, switchBlock); List<CaseLogicalConstruct> orderedCaseConstructs = new List<CaseLogicalConstruct>(); PairList<List<int>, CFGBlockLogicalConstruct> labelsToCFGSuccessorsList = new PairList<List<int>, CFGBlockLogicalConstruct>(); foreach (KeyValuePair<CFGBlockLogicalConstruct, List<int>> cfgSuccessorToLabelsPair in cfgSuccessorToLabelsMap) { ILogicalConstruct successor; HashSet<ISingleEntrySubGraph> dominatedNodes; if (LogicalFlowUtilities.TryGetParentConstructWithGivenParent(cfgSuccessorToLabelsPair.Key, parentConstruct, out successor) && validCaseEntryToDominatedNodesMap.TryGetValue(successor, out dominatedNodes)) { CaseLogicalConstruct newCaseConstruct = new CaseLogicalConstruct(successor); newCaseConstruct.CaseNumbers.AddRange(cfgSuccessorToLabelsPair.Value); newCaseConstruct.Body.UnionWith(dominatedNodes.Cast<ILogicalConstruct>()); newCaseConstruct.AttachCaseConstructToGraph(); orderedCaseConstructs.Add(newCaseConstruct); } else { labelsToCFGSuccessorsList.Add(cfgSuccessorToLabelsPair.Value, cfgSuccessorToLabelsPair.Key); } } CaseLogicalConstruct defaultCase = null; CFGBlockLogicalConstruct defaultCFGSuccessor = GetCFGLogicalConstructFromBlock(switchData.DefaultCase); ILogicalConstruct defaultSuccessor; HashSet<ISingleEntrySubGraph> defaultCaseNodes; if (LogicalFlowUtilities.TryGetParentConstructWithGivenParent(defaultCFGSuccessor, parentConstruct, out defaultSuccessor) && validCaseEntryToDominatedNodesMap.TryGetValue(defaultSuccessor, out defaultCaseNodes)) { defaultCase = new CaseLogicalConstruct(defaultSuccessor); if (HasSuccessors(defaultCaseNodes)) { defaultCase.Body.UnionWith(defaultCaseNodes.Cast<ILogicalConstruct>()); } defaultCase.AttachCaseConstructToGraph(); } SwitchLogicalConstruct theSwitch = SwitchLogicalConstruct.GroupInSwitchConstruct(switchBlock, orderedCaseConstructs, labelsToCFGSuccessorsList, defaultCase, defaultCFGSuccessor); UpdateDominatorTree(dominatorTree, theSwitch); }
private void CreateSwitchConstruct(CFGBlockLogicalConstruct switchBlock, ILogicalConstruct parentConstruct, SwitchData switchData, DominatorTree dominatorTree) { stackVariable2 = this.GetOrderedCFGSuccessorToLabelsMap(switchData); V_0 = this.GetValidCases(dominatorTree, switchBlock); V_1 = new List <CaseLogicalConstruct>(); V_2 = new PairList <List <int>, CFGBlockLogicalConstruct>(); V_8 = stackVariable2.GetEnumerator(); try { while (V_8.MoveNext()) { V_9 = V_8.get_Current(); if (!LogicalFlowUtilities.TryGetParentConstructWithGivenParent(V_9.get_Key(), parentConstruct, out V_10) || !V_0.TryGetValue(V_10, out V_11)) { V_2.Add(V_9.get_Value(), V_9.get_Key()); } else { V_12 = new CaseLogicalConstruct(V_10); V_12.get_CaseNumbers().AddRange(V_9.get_Value()); V_12.get_Body().UnionWith(V_11.Cast <ILogicalConstruct>()); V_12.AttachCaseConstructToGraph(); V_1.Add(V_12); } } } finally { ((IDisposable)V_8).Dispose(); } V_3 = null; V_4 = this.GetCFGLogicalConstructFromBlock(switchData.get_DefaultCase()); if (LogicalFlowUtilities.TryGetParentConstructWithGivenParent(V_4, parentConstruct, out V_5) && V_0.TryGetValue(V_5, out V_6)) { V_3 = new CaseLogicalConstruct(V_5); if (this.HasSuccessors(V_6)) { V_3.get_Body().UnionWith(V_6.Cast <ILogicalConstruct>()); } V_3.AttachCaseConstructToGraph(); } V_7 = SwitchLogicalConstruct.GroupInSwitchConstruct(switchBlock, V_1, V_2, V_3, V_4); this.UpdateDominatorTree(dominatorTree, V_7); return; }
private ILogicalConstruct FindChildBlockBelongsTo(ILogicalConstruct parent, CFGBlockLogicalConstruct block) { V_0 = null; V_1 = block; do { if (V_1.get_Parent() != parent) { V_1 = (ILogicalConstruct)V_1.get_Parent(); } else { V_0 = V_1; break; } }while (V_1.get_Parent() != null); return(V_0); }
/// <summary> /// Removes back edges from switch blocks. Switch cases can not form a loop. If the control flow forms a loop, it should be represented by goto-label contructs. /// </summary> /// <param name="theConstruct">The construct, that might contain switches.</param> private void RemoveBackEdgesFromSwitchConstructs(ILogicalConstruct theConstruct) { DFSTree dfsTree = DFSTBuilder.BuildTree(theConstruct); foreach (DFSTEdge edge in dfsTree.BackEdges) { ILogicalConstruct startConstruct = edge.Start.Construct as ILogicalConstruct; if (startConstruct is ConditionLogicalConstruct) { continue; } CFGBlockLogicalConstruct startCfgConstruct = startConstruct as CFGBlockLogicalConstruct; if ((startCfgConstruct != null && startCfgConstruct.TheBlock.Last.OpCode.Code == Mono.Cecil.Cil.Code.Switch)) { MarkAsGotoEdge(startConstruct, edge.End.Construct as ILogicalConstruct); } } }
private SwitchLogicalConstruct(CFGBlockLogicalConstruct entry, ICollection <CaseLogicalConstruct> body, PairList <List <int>, CFGBlockLogicalConstruct> nonDominatedCFGSuccessors, CaseLogicalConstruct defaultCase, CFGBlockLogicalConstruct defaultCFGSuccessor) { this.SwitchConditionExpression = entry.LogicalConstructExpressions[0]; this.DefaultCase = defaultCase; this.DefaultCFGSuccessor = defaultCFGSuccessor; this.NonDominatedCFGSuccessors = nonDominatedCFGSuccessors; FillCasesArray(body); this.Entry = entry; RedirectChildrenToNewParent(GetBodyCollection()); if (entry.CFGSuccessors.Contains(entry)) { this.AddToPredecessors(entry); this.AddToSuccessors(entry); } }
private SwitchLogicalConstruct(CFGBlockLogicalConstruct entry, ICollection<CaseLogicalConstruct> body, PairList<List<int>, CFGBlockLogicalConstruct> nonDominatedCFGSuccessors, CaseLogicalConstruct defaultCase, CFGBlockLogicalConstruct defaultCFGSuccessor) { this.SwitchConditionExpression = entry.LogicalConstructExpressions[0]; this.DefaultCase = defaultCase; this.DefaultCFGSuccessor = defaultCFGSuccessor; this.NonDominatedCFGSuccessors = nonDominatedCFGSuccessors; FillCasesArray(body); this.Entry = entry; RedirectChildrenToNewParent(GetBodyCollection()); if (entry.CFGSuccessors.Contains(entry)) { this.AddToPredecessors(entry); this.AddToSuccessors(entry); } }
/// <summary> /// Sets the true and false CFG successors of the construct. /// </summary> /// <param name="cfgConditionBlock"></param> private void SetTrueAndFalseSuccessors(CFGBlockLogicalConstruct cfgConditionBlock) { InstructionBlock block = cfgConditionBlock.TheBlock; //The successor at the last index is the near successor (by design). The ExpressionDecompilerStep ensures that the far successor will be //the true successor and the near successor will be the false successor. InstructionBlock trueSuccessorBlock = block.Successors[0]; //The far successor InstructionBlock falseSuccessorBlock = block.Successors[1]; //The near successor foreach (CFGBlockLogicalConstruct cfgSuccessor in cfgConditionBlock.CFGSuccessors) { if (cfgSuccessor.TheBlock == trueSuccessorBlock) { this.TrueCFGSuccessor = cfgSuccessor; } if (cfgSuccessor.TheBlock == falseSuccessorBlock) { this.FalseCFGSuccessor = cfgSuccessor; } } }
private bool CanBePartOfComplexCondition(ILogicalConstruct node, HashSet <ILogicalConstruct> nodesInCondition, CFGBlockLogicalConstruct commonSuccessor) { if (node == null || node as ConditionLogicalConstruct == null || !this.ArePredecessorsLegal(node, nodesInCondition) || !node.get_CFGSuccessors().Contains(commonSuccessor)) { return(false); } return(!nodesInCondition.Contains(node)); }
public static SwitchLogicalConstruct GroupInSwitchConstruct(CFGBlockLogicalConstruct entry, ICollection<CaseLogicalConstruct> body, PairList<List<int>, CFGBlockLogicalConstruct> nonDominatedCFGSuccessors, CaseLogicalConstruct defaultCase, CFGBlockLogicalConstruct defaultCFGSuccessor) { return new SwitchLogicalConstruct(entry, body, nonDominatedCFGSuccessors, defaultCase, defaultCFGSuccessor); }
/// <summary> /// Sets the true and false CFG successors of the construct. /// </summary> /// <param name="cfgConditionBlock"></param> private void SetTrueAndFalseSuccessors(CFGBlockLogicalConstruct cfgConditionBlock) { InstructionBlock block = cfgConditionBlock.TheBlock; //The successor at the last index is the near successor (by design). The ExpressionDecompilerStep ensures that the far successor will be //the true successor and the near successor will be the false successor. InstructionBlock trueSuccessorBlock = block.Successors[0]; //The far successor InstructionBlock falseSuccessorBlock = block.Successors[1]; //The near successor foreach (CFGBlockLogicalConstruct cfgSuccessor in cfgConditionBlock.CFGSuccessors) { if(cfgSuccessor.TheBlock == trueSuccessorBlock) { this.TrueCFGSuccessor = cfgSuccessor; } if(cfgSuccessor.TheBlock == falseSuccessorBlock) { this.FalseCFGSuccessor = cfgSuccessor; } } }
/// <summary> /// Changes the successors of the given instruction block to reflect the changes in the logical tree. /// </summary> /// <remarks> /// Also modifies switch data. /// Done because later substeps of the LogicalFlowBuilderStep depend on the successor information of the CFG /// (e.g. Determining the true and false successors of a ConditionLogicalConstruct, determining the cases of a switch/NWayConditional construct). /// </remarks> /// <param name="theCFGConstruct"></param> /// <param name="theCFGSuccessor"></param> private void ProcessMultiWayCFGPredecessor(CFGBlockLogicalConstruct finallyBody, InstructionBlock theBlock, InstructionBlock theNewSuccessor) { InstructionBlock theFinallyBlock = finallyBody.TheBlock; for (int i = 0; i < theBlock.Successors.Length; i++) { if (theBlock.Successors[i] == theFinallyBlock) { theBlock.Successors[i] = theNewSuccessor; } } SwitchData switchData; if(methodContext.ControlFlowGraph.SwitchBlocksInformation.TryGetValue(theBlock, out switchData)) { InstructionBlock[] theConditionCases = switchData.OrderedCasesArray; for (int i = 0; i < theConditionCases.Length; i++) { if (theConditionCases[i] == theFinallyBlock) { theConditionCases[i] = theNewSuccessor; } } if (switchData.DefaultCase == theFinallyBlock) { switchData.DefaultCase = theNewSuccessor; } } }
public static SwitchLogicalConstruct GroupInSwitchConstruct(CFGBlockLogicalConstruct entry, ICollection <CaseLogicalConstruct> body, PairList <List <int>, CFGBlockLogicalConstruct> nonDominatedCFGSuccessors, CaseLogicalConstruct defaultCase, CFGBlockLogicalConstruct defaultCFGSuccessor) { return(new SwitchLogicalConstruct(entry, body, nonDominatedCFGSuccessors, defaultCase, defaultCFGSuccessor)); }
/// <summary> /// Determines whether the specified node can be added in a complex condition. /// </summary> /// <param name="node">The node that we want to add to the condition.</param> /// <param name="nodesInCondition">The nodes that are in the complex condition.</param> /// <param name="commonSuccessor">The supposed common successor.</param> /// <returns></returns> private bool CanBePartOfComplexCondition(ILogicalConstruct node, HashSet<ILogicalConstruct> nodesInCondition, CFGBlockLogicalConstruct commonSuccessor) { //In order to add the node to the condition it has to be a condition node. All of it's predecessors should be in the complex condition. //The node should have for successor the supposed common successor (the check is optimized). And the node should not be part of the complex //condition. return node != null && node is ConditionLogicalConstruct && ArePredecessorsLegal(node, nodesInCondition) && node.CFGSuccessors.Contains(commonSuccessor) && !nodesInCondition.Contains(node); }
/// <summary> /// Generates the try/finally construct that is represented by the specifed exception handler info and attaches it to the logical tree. /// </summary> /// <param name="handlerInfo"></param> private void GenerateTryFinallyHandler(YieldExceptionHandlerInfo handlerInfo) { finallyBlocks = new HashSet<ILogicalConstruct>(); entryOfTry = GetStateBeginBlockConstruct(handlerInfo.TryBeginState); BuildTryBody(handlerInfo); BlockLogicalConstruct newFinally; if (handlerInfo.HandlerType == YieldExceptionHandlerType.Method) { if (newFinallyBody == null) { throw new Exception("Could not determine the end ot the try block"); } RemoveExcessNodesFromTheTryBlock(); ProcessFinallyNodes(); newFinally = new BlockLogicalConstruct(newFinallyBody, new ILogicalConstruct[] { newFinallyBody }); } else { newFinally = GenerateFinallyBlock(); } BlockLogicalConstruct newTry = new BlockLogicalConstruct(entryOfTry, newTryBody); TryFinallyLogicalConstruct newTryFinallyConstruct = new TryFinallyLogicalConstruct(newTry, newFinally); createdConstructsToIntervalMap[newTryFinallyConstruct] = handlerInfo; CleanUpOrderedNodes(newTryFinallyConstruct); }
private void DetachFromLogicalTree(CFGBlockLogicalConstruct node) { if(node.CFGPredecessors.Count > 0 || node.CFGSuccessors.Count > 0) { throw new Exception("This node cannot be detached from the logical tree."); } node.Parent.Children.Remove(node); CFGBlockLogicalConstruct[] cfgConstructsArray = logicalContext.CFGBlockToLogicalConstructMap[node.TheBlock]; if(cfgConstructsArray.Length == 1) { if(cfgConstructsArray[0] != node) { throw new Exception("Logical tree is inconsistent."); } logicalContext.CFGBlockToLogicalConstructMap.Remove(node.TheBlock); } CFGBlockLogicalConstruct[] newCFGConstructsArray = new CFGBlockLogicalConstruct[cfgConstructsArray.Length - 1]; for (int i = 0 , j = 0; i < cfgConstructsArray.Length; i++, j++) { if(cfgConstructsArray[i] == node) { --j; continue; } if(j == cfgConstructsArray.Length) { throw new Exception("Logical tree is inconsistent."); } newCFGConstructsArray[j] = cfgConstructsArray[i]; } logicalContext.CFGBlockToLogicalConstructMap[node.TheBlock] = newCFGConstructsArray; }
/// <summary> /// Checks each a node before adding its successors to the <paramref name="bfsQueue"/>. /// </summary> /// <remarks> /// If the node is a CFGBlockLC and it contains the invocation of the finally method, or the entry of the finally block, /// then we should not continue the traversal. /// </remarks> /// <param name="handlerInfo"></param> /// <param name="bfsQueue"></param> /// <param name="currentNode"></param> private void ProcessCurrentNode(YieldExceptionHandlerInfo handlerInfo, Queue<ILogicalConstruct> bfsQueue, ILogicalConstruct currentNode) { if(currentNode is CFGBlockLogicalConstruct) { CFGBlockLogicalConstruct currentCFGNode = currentNode as CFGBlockLogicalConstruct; for (int i = 0; i < currentCFGNode.LogicalConstructExpressions.Count; i++) { Expression currentExpression = currentCFGNode.LogicalConstructExpressions[i]; int value; if(TryGetStateAssignValue(currentExpression, out value)) { if(value < handlerInfo.TryBeginState || value > handlerInfo.TryEndState) //sanity check { if(handlerInfo.HandlerType != YieldExceptionHandlerType.Method && TryProcessConditionalDisposeHandler(handlerInfo, currentCFGNode)) { return; } throw new Exception("Invalid state value"); } } else if(handlerInfo.HandlerType == YieldExceptionHandlerType.Method && currentExpression.CodeNodeType == CodeNodeType.MethodInvocationExpression && (currentExpression as MethodInvocationExpression).MethodExpression.MethodDefinition == handlerInfo.FinallyMethodDefinition) { //For the finally block we need the CFGBlockLC that contains only the invocation of the finally method. //That's why we need to split the CFGBlockLC, if there are other expressions besides the invocation. CFGBlockLogicalConstruct currentFinallyBlock; if (currentCFGNode.LogicalConstructExpressions.Count == 1) { if(newFinallyBody == null) { newFinallyBody = currentCFGNode; } finallyBlocks.Add(newFinallyBody); orderedCFGNodes.Remove(currentCFGNode); return; } if (i == 0) { KeyValuePair<CFGBlockLogicalConstruct, CFGBlockLogicalConstruct> newConstructsPair = LogicalFlowUtilities.SplitCFGBlockAt(logicalContext, currentCFGNode, i + 1); currentFinallyBlock = newConstructsPair.Key; orderedCFGNodes[orderedCFGNodes.IndexOf(currentCFGNode)] = newConstructsPair.Value; } else if (i < currentCFGNode.LogicalConstructExpressions.Count - 1) { KeyValuePair<CFGBlockLogicalConstruct, CFGBlockLogicalConstruct> endOfTryPair = LogicalFlowUtilities.SplitCFGBlockAt(logicalContext, currentCFGNode, i); newTryBody.Add(endOfTryPair.Key); KeyValuePair<CFGBlockLogicalConstruct, CFGBlockLogicalConstruct> finallyRestOfBlockPair = LogicalFlowUtilities.SplitCFGBlockAt(logicalContext, endOfTryPair.Value, 1); currentFinallyBlock = finallyRestOfBlockPair.Key; orderedCFGNodes[orderedCFGNodes.IndexOf(currentCFGNode)] = finallyRestOfBlockPair.Value; } else // i == count - 1 { KeyValuePair<CFGBlockLogicalConstruct, CFGBlockLogicalConstruct> tryFinallyPair = LogicalFlowUtilities.SplitCFGBlockAt(logicalContext, currentCFGNode, i); newTryBody.Add(tryFinallyPair.Key); currentFinallyBlock = tryFinallyPair.Value; orderedCFGNodes.Remove(currentCFGNode); } if(newFinallyBody == null) { newFinallyBody = currentFinallyBlock; } finallyBlocks.Add(currentFinallyBlock); return; } } } else if(currentNode is TryFinallyLogicalConstruct) { TryFinallyLogicalConstruct tryFinallyConstruct = currentNode as TryFinallyLogicalConstruct; YieldExceptionHandlerInfo oldHandlerInfo; if(createdConstructsToIntervalMap.TryGetValue(tryFinallyConstruct, out oldHandlerInfo) && (oldHandlerInfo.TryBeginState < handlerInfo.TryBeginState || oldHandlerInfo.TryEndState > handlerInfo.TryEndState)) { throw new Exception("This try/finally construct cannot be nested in the current construct"); } } newTryBody.Add(currentNode); foreach (ILogicalConstruct successor in currentNode.SameParentSuccessors) { bfsQueue.Enqueue(successor); } }
/// <summary> /// Redirect the predecessors and successors of the finally node. /// </summary> /// <remarks> /// Check if the finally node is only reachable by nodes in the try block. /// Make the successor of the finally node successor to all of the predecessors of the finally node. /// This will detach the finally node from the subgraph, which is a desired result since every normal finally block is not reachable from any where /// (the CLR takes care of executing the code in the finally block). /// </remarks> /// <param name="finallyCFGBlock"></param> private void ProcessFinallyNode(CFGBlockLogicalConstruct finallyCFGBlock) { ProcessFinallyNode(finallyCFGBlock, finallyCFGBlock); }
/// <summary> /// Redirect the predecessors and successors of the finally block. /// </summary> /// <remarks> /// Check if the finallyBlockEntry is only reachable by nodes in the try block. /// Make the successor of the finallyBlockEnd successor to all of the predecessors of the finallyBlockEntry. /// This will detach the finally block from the subgraph, which is a desired result since every normal finally block is not reachable from any where /// (the CLR takes care of executing the code in the finally block). /// </remarks> /// <param name="finallyBlockEntry"></param> /// <param name="finallyBlockEnd"></param> /// <returns>The successor of the finally block.</returns> private CFGBlockLogicalConstruct ProcessFinallyNode(CFGBlockLogicalConstruct finallyBlockEntry, CFGBlockLogicalConstruct finallyBlockEnd) { foreach (ILogicalConstruct predecessor in finallyBlockEntry.SameParentPredecessors) { if (!newTryBody.Contains(predecessor)) { throw new Exception("Invalid entry to the finally block"); } } CFGBlockLogicalConstruct finallySuccessor; using (IEnumerator<CFGBlockLogicalConstruct> enumerator = finallyBlockEnd.CFGSuccessors.GetEnumerator()) { enumerator.MoveNext(); finallySuccessor = enumerator.Current; if (enumerator.MoveNext()) { throw new Exception("Invalid count of successors"); } } HashSet<CFGBlockLogicalConstruct> finallyCFGPredecessors = new HashSet<CFGBlockLogicalConstruct>(finallyBlockEntry.CFGPredecessors); foreach (CFGBlockLogicalConstruct cfgPredecessor in finallyCFGPredecessors) { if (cfgPredecessor.TheBlock != finallyBlockEntry.TheBlock && cfgPredecessor.TheBlock.Successors.Length > 1) { ProcessMultiWayCFGPredecessor(finallyBlockEntry, cfgPredecessor.TheBlock, finallySuccessor.TheBlock); } LogicalConstructBase currenConstruct = cfgPredecessor; while (currenConstruct != finallyBlockEntry.Parent) { currenConstruct.RemoveFromSuccessors(finallyBlockEntry); currenConstruct.AddToSuccessors(finallySuccessor); currenConstruct = currenConstruct.Parent as LogicalConstructBase; } finallySuccessor.AddToPredecessors(cfgPredecessor); finallyBlockEntry.RemoveFromPredecessors(cfgPredecessor); } finallySuccessor.RemoveFromPredecessors(finallyBlockEnd); finallyBlockEnd.RemoveFromSuccessors(finallySuccessor); return finallySuccessor; }
/// <summary> /// Creates a condition construct from the specified CFG construct and inserts it to the logical tree. /// </summary> /// <param name="cfgConditionBlock"></param> /// <returns>The created condition construct.</returns> public static ConditionLogicalConstruct GroupInSimpleConditionConstruct(CFGBlockLogicalConstruct cfgConditionBlock) { return(new ConditionLogicalConstruct(cfgConditionBlock)); }
/// <summary> /// Determines whether the specified node can be added in a complex condition. /// </summary> /// <param name="node">The node that we want to add to the condition.</param> /// <param name="nodesInCondition">The nodes that are in the complex condition.</param> /// <param name="commonSuccessor">The supposed common successor.</param> /// <returns></returns> private bool CanBePartOfComplexCondition(ILogicalConstruct node, HashSet <ILogicalConstruct> nodesInCondition, CFGBlockLogicalConstruct commonSuccessor) { //In order to add the node to the condition it has to be a condition node. All of it's predecessors should be in the complex condition. //The node should have for successor the supposed common successor (the check is optimized). And the node should not be part of the complex //condition. return(node != null && node is ConditionLogicalConstruct && ArePredecessorsLegal(node, nodesInCondition) && node.CFGSuccessors.Contains(commonSuccessor) && !nodesInCondition.Contains(node)); }
public PartialCFGBlockLogicalConstruct(CFGBlockLogicalConstruct originalCFGConstruct, IEnumerable<Expression> expressions) :base(originalCFGConstruct.TheBlock, expressions) { OriginalCFGConstruct = originalCFGConstruct; RedirectParent(); }
/// <summary> /// Splits the given CFG construct into two partial constructs. The first containing the expressions with indices 0 to expressionIndex - 1, the second - /// expressionIndex to end. This method modifies the logicalContext.CFGBlockToLogicalConstructMap /// </summary> /// <param name="logicalContext"></param> /// <param name="cfgBlock"></param> /// <param name="expressionIndex"></param> /// <returns>A key value pair containing the first partial construct as key and the second as value.</returns> public static KeyValuePair<CFGBlockLogicalConstruct, CFGBlockLogicalConstruct> SplitCFGBlockAt(LogicalFlowBuilderContext logicalContext, CFGBlockLogicalConstruct cfgBlock, int expressionIndex) { List<Expression> blockExpressions = cfgBlock.LogicalConstructExpressions; if(blockExpressions == null) { throw new ArgumentNullException("blockExpressions"); } if(expressionIndex <= 0 || expressionIndex >= blockExpressions.Count) { throw new ArgumentOutOfRangeException("expressionIndex"); } CFGBlockLogicalConstruct[] instructionBlockConstructs = logicalContext.CFGBlockToLogicalConstructMap[cfgBlock.TheBlock]; int cfgBlockArrayLength = instructionBlockConstructs.Length; int cfgBlockIndex; for (cfgBlockIndex = 0; cfgBlockIndex < cfgBlockArrayLength; cfgBlockIndex++) { if(cfgBlock == instructionBlockConstructs[cfgBlockIndex]) { break; } } if(cfgBlockIndex == cfgBlockArrayLength) { throw new ArgumentException("cfgBlock"); } List<Expression> firstExpressionsList = cfgBlock.LogicalConstructExpressions.GetRange(0, expressionIndex); PartialCFGBlockLogicalConstruct firstPartial = new PartialCFGBlockLogicalConstruct(cfgBlock, firstExpressionsList); firstPartial.RedirectPredecessors(); List<Expression> secondExpressionsList = cfgBlock.LogicalConstructExpressions.GetRange(expressionIndex, blockExpressions.Count - expressionIndex); PartialCFGBlockLogicalConstruct secondPartial = new PartialCFGBlockLogicalConstruct(cfgBlock, secondExpressionsList); secondPartial.RedirectSuccessors(); firstPartial.AddToSuccessors(secondPartial); secondPartial.AddToPredecessors(firstPartial); CFGBlockLogicalConstruct[] updatedCollection = new CFGBlockLogicalConstruct[cfgBlockArrayLength + 1]; for (int i = 0, j = 0; i < cfgBlockArrayLength; i++, j++) { if (i != cfgBlockIndex) { updatedCollection[j] = instructionBlockConstructs[i]; } else { updatedCollection[j] = firstPartial; updatedCollection[++j] = secondPartial; } } logicalContext.CFGBlockToLogicalConstructMap[cfgBlock.TheBlock] = updatedCollection; return new KeyValuePair<CFGBlockLogicalConstruct, CFGBlockLogicalConstruct>(firstPartial, secondPartial); }
ILogicalConstruct FindChildBlockBelongsTo(ILogicalConstruct parent, CFGBlockLogicalConstruct block) { ILogicalConstruct result = null, current = block; do { if (current.Parent == parent) { result = current; break; } current = (ILogicalConstruct)current.Parent; } while (current.Parent != null); return result; }
/// <summary> /// Builds the try body of the specified exception handler starting from the given entry node. /// </summary> /// <remarks> /// We assume that all nodes before reaching the finally block are in the try construct. /// </remarks> /// <param name="handlerInfo"></param> /// <param name="entryOfTry"></param> private void BuildTryBody(YieldExceptionHandlerInfo handlerInfo) { newTryBody = new HashSet<ILogicalConstruct>(); newTryBody.Add(entryOfTry); newFinallyBody = null; HashSet<ILogicalConstruct> traversedNodes = new HashSet<ILogicalConstruct>(); Queue<ILogicalConstruct> bfsQueue = new Queue<ILogicalConstruct>(); foreach (ILogicalConstruct successor in entryOfTry.SameParentSuccessors) { bfsQueue.Enqueue(successor); } while (bfsQueue.Count > 0) { ILogicalConstruct currentNode = bfsQueue.Dequeue(); if (!traversedNodes.Add(currentNode) || finallyBlocks.Contains(currentNode)) { continue; } ProcessCurrentNode(handlerInfo, bfsQueue, currentNode); } }
/// <summary> /// If the given successor is the entry of the condition we update the predecessor and successor collections of the condition. /// </summary> /// <param name="cfgSuccessor"></param> private void ManageSuccessorInCaseOfLoop(CFGBlockLogicalConstruct cfgSuccessor) { if(this.FirstBlock == cfgSuccessor) { this.AddToSuccessors(cfgSuccessor); foreach (CFGBlockLogicalConstruct cfgChild in this.Children) { if(cfgChild.CFGSuccessors.Contains(cfgSuccessor)) { this.AddToPredecessors(cfgChild); } } } }
internal static CFGBlockLogicalConstruct FindGuardedBlockCFGFollowNode(ExceptionHandlingLogicalConstruct construct, HashSet <CFGBlockLogicalConstruct> outOfconsideration) { //TODO: Don't consider leaves to blocks that end with return. The return can simpy be copied to the place where the leave originates by // the statement decompielr or the goto elimination later. //find all the targets the try/catch/filter/fault/finally blocks in the construct jump/leave to //record the number of leaves to each target Dictionary <CFGBlockLogicalConstruct, uint> numberOfHandlersLeavingToBlock = new Dictionary <CFGBlockLogicalConstruct, uint>(); AddSuccessorsToCount(construct.Try, numberOfHandlersLeavingToBlock); uint leavableConstructsCount = 1; if (construct is TryCatchFilterLogicalConstruct) { TryCatchFilterLogicalConstruct tcf = construct as TryCatchFilterLogicalConstruct; foreach (IFilteringExceptionHandler handler in tcf.Handlers) { AddSuccessorsToCount(handler, numberOfHandlersLeavingToBlock); leavableConstructsCount++; } } else if (construct is TryFaultLogicalConstruct) { AddSuccessorsToCount((construct as TryFaultLogicalConstruct).Fault, numberOfHandlersLeavingToBlock); leavableConstructsCount++; } else if (construct is TryFinallyLogicalConstruct) { AddSuccessorsToCount((construct as TryFinallyLogicalConstruct).Finally, numberOfHandlersLeavingToBlock); leavableConstructsCount++; } //remove the leave targets taht should nto be considered foreach (CFGBlockLogicalConstruct ooc in outOfconsideration) { if (numberOfHandlersLeavingToBlock.ContainsKey(ooc)) { numberOfHandlersLeavingToBlock.Remove(ooc); } } if (numberOfHandlersLeavingToBlock.Count == 0) { return(null); } //find the leave targets that greatest number of exception handling blocks (try/catch/filter/fault/finally) jump to HashSet <CFGBlockLogicalConstruct> mostBlocksExitTo = new HashSet <CFGBlockLogicalConstruct>(); CFGBlockLogicalConstruct randomLeaveTarget = numberOfHandlersLeavingToBlock.Keys.FirstOrDefault <CFGBlockLogicalConstruct>(); mostBlocksExitTo.Add(randomLeaveTarget); uint maxNumberOfLeaveTargetPredecessors = numberOfHandlersLeavingToBlock[randomLeaveTarget]; foreach (CFGBlockLogicalConstruct leaveTarget in numberOfHandlersLeavingToBlock.Keys) { if (numberOfHandlersLeavingToBlock[leaveTarget] > maxNumberOfLeaveTargetPredecessors) { maxNumberOfLeaveTargetPredecessors = numberOfHandlersLeavingToBlock[leaveTarget]; mostBlocksExitTo.Clear(); mostBlocksExitTo.Add(leaveTarget); } else if (numberOfHandlersLeavingToBlock[leaveTarget] == maxNumberOfLeaveTargetPredecessors) { mostBlocksExitTo.Add(leaveTarget); } } //use various heuristics to determine the best follow node //the follow node that will result in the smallest number of gotos is considered superior //the follow node could be changed once loops are created if it turns out loop condition was chosen as a follow node (i.e. we chose a continue edge) if (mostBlocksExitTo.Count == 1) { return(mostBlocksExitTo.FirstOrDefault <CFGBlockLogicalConstruct>()); } else { HashSet <CFGBlockLogicalConstruct> mostLeavesPointTo = new HashSet <CFGBlockLogicalConstruct>(); uint maxLeavesToSingleTarget = 0; foreach (CFGBlockLogicalConstruct leaveTarget in mostBlocksExitTo) { uint leavesToThisTarget = 0; HashSet <CFGBlockLogicalConstruct> constructCFGBlocks = construct.CFGBlocks; foreach (CFGBlockLogicalConstruct leaveTargetpredecessor in leaveTarget.CFGPredecessors) { if (constructCFGBlocks.Contains(leaveTargetpredecessor)) { leavesToThisTarget++; } } if (leavesToThisTarget >= maxLeavesToSingleTarget) { if (leavesToThisTarget > maxLeavesToSingleTarget) { maxLeavesToSingleTarget = leavesToThisTarget; mostLeavesPointTo.Clear(); } mostLeavesPointTo.Add(leaveTarget); } } //TODO: Try anoher heuristics here to chose the follow node that will minimize the number of gotos CFGBlockLogicalConstruct result = mostLeavesPointTo.FirstOrDefault <CFGBlockLogicalConstruct>(); //HEURISTICS: Of all possible follow nodes we try to chose the one which start index is greater than the index of the exception construct start //but less than the start indexes of all other possible candidates. We rely on the assumption that the control flow closely resembles the ordering of // the IL instructions, i.e. if Instr. A comes before Instr. B the chances are that Instr. A will have to be executed before Instr. B in any workflow. // That might not be the case but it's a good assumption since the compilers will try to express teh control flow in the least amount of jumps possible // for performance reasons. if (result.Index < construct.Entry.Index) { CFGBlockLogicalConstruct closestAfterConstruct = null; foreach (CFGBlockLogicalConstruct candidate in mostLeavesPointTo) { if (candidate.Index > construct.Entry.Index) { if (closestAfterConstruct != null && closestAfterConstruct.Index < candidate.Index) { continue; } closestAfterConstruct = candidate; } } if (closestAfterConstruct != null) { result = closestAfterConstruct; } } return(result); } }
/// <summary> /// Creates a condition construct from the specified CFG construct and inserts it to the logical tree. /// </summary> /// <param name="cfgConditionBlock"></param> /// <returns>The created condition construct.</returns> public static ConditionLogicalConstruct GroupInSimpleConditionConstruct(CFGBlockLogicalConstruct cfgConditionBlock) { return new ConditionLogicalConstruct(cfgConditionBlock); }
/// <summary> /// Determines whether or not there is a conditional dispose starting from this block. /// </summary> /// <remarks> /// Since the conditional dispose is the same as in the Dispose method, we are trying to find the same pattern. /// <code> /// this.stateField = nextState; /// (this.disposableField = this.enumeratorField as IDisposable;) -- this might be missing /// if(this.disposableField != null) /// { /// this.disposableField.Dispose(); /// } /// </code> /// </remarks> /// <param name="yieldExceptionHandler"></param> /// <param name="startBlock"></param> /// <returns></returns> private bool TryProcessConditionalDisposeHandler(YieldExceptionHandlerInfo yieldExceptionHandler, CFGBlockLogicalConstruct startBlock) { if(finallyBlocks.Count > 0) { return false; } if(!(startBlock is PartialCFGBlockLogicalConstruct) || startBlock.CFGSuccessors.Count != 1) { return false; } if(startBlock.LogicalConstructExpressions.Count == 0) { return false; } BinaryExpression stateAssignExpression = startBlock.LogicalConstructExpressions[0] as BinaryExpression; if(stateAssignExpression == null || !stateAssignExpression.IsAssignmentExpression || stateAssignExpression.Left.CodeNodeType != CodeNodeType.FieldReferenceExpression || (stateAssignExpression.Left as FieldReferenceExpression).Field.Resolve() != stateFieldRef || stateAssignExpression.Right.CodeNodeType != CodeNodeType.LiteralExpression || (int)((stateAssignExpression.Right as LiteralExpression).Value) != yieldExceptionHandler.NextState) { return false; } if(startBlock.LogicalConstructExpressions.Count == 2 && yieldExceptionHandler.HandlerType == YieldExceptionHandlerType.ConditionalDispose) { BinaryExpression disposableAssignExpression = startBlock.LogicalConstructExpressions[1] as BinaryExpression; if (disposableAssignExpression == null || !disposableAssignExpression.IsAssignmentExpression || disposableAssignExpression.Left.CodeNodeType != CodeNodeType.FieldReferenceExpression || (disposableAssignExpression.Left as FieldReferenceExpression).Field != yieldExceptionHandler.DisposableField || disposableAssignExpression.Right.CodeNodeType != CodeNodeType.SafeCastExpression || (disposableAssignExpression.Right as SafeCastExpression).Expression.CodeNodeType != CodeNodeType.FieldReferenceExpression || ((disposableAssignExpression.Right as SafeCastExpression).Expression as FieldReferenceExpression).Field != yieldExceptionHandler.EnumeratorField) { return false; } } else if(startBlock.LogicalConstructExpressions.Count != 1 || yieldExceptionHandler.HandlerType != YieldExceptionHandlerType.SimpleConditionalDispose) { return false; } CFGBlockLogicalConstruct conditionBlock; IEnumerator<CFGBlockLogicalConstruct> enumerator = startBlock.CFGSuccessors.GetEnumerator(); using(enumerator) { enumerator.MoveNext(); conditionBlock = enumerator.Current; } if(conditionBlock.LogicalConstructExpressions.Count != 1) { return false; } BinaryExpression isNullCheckExpression = conditionBlock.LogicalConstructExpressions[0] as BinaryExpression; if(isNullCheckExpression == null || isNullCheckExpression.Operator != BinaryOperator.ValueEquality || isNullCheckExpression.Left.CodeNodeType != CodeNodeType.FieldReferenceExpression || (isNullCheckExpression.Left as FieldReferenceExpression).Field != yieldExceptionHandler.DisposableField || isNullCheckExpression.Right.CodeNodeType != CodeNodeType.LiteralExpression || (isNullCheckExpression.Right as LiteralExpression).Value != null) { return false; } CFGBlockLogicalConstruct disposeCallBlock = null; foreach (ILogicalConstruct successor in conditionBlock.CFGSuccessors) { CFGBlockLogicalConstruct cfgSuccessor = successor as CFGBlockLogicalConstruct; if(cfgSuccessor != null && cfgSuccessor.CFGPredecessors.Count == 1) { disposeCallBlock = cfgSuccessor; break; } } if(disposeCallBlock == null || disposeCallBlock.LogicalConstructExpressions.Count != 1) { return false; } MethodInvocationExpression disposeMethodInvocation = disposeCallBlock.LogicalConstructExpressions[0] as MethodInvocationExpression; if(disposeMethodInvocation == null || !disposeMethodInvocation.VirtualCall || disposeMethodInvocation.MethodExpression.Target.CodeNodeType != CodeNodeType.FieldReferenceExpression || (disposeMethodInvocation.MethodExpression.Target as FieldReferenceExpression).Field != yieldExceptionHandler.DisposableField || disposeMethodInvocation.MethodExpression.Method.Name != "Dispose") { return false; } this.finallyEntryBlock = startBlock; finallyBlocks.Add(startBlock); this.conditionBlock = conditionBlock; finallyBlocks.Add(conditionBlock); this.disposeCallBlock = disposeCallBlock; finallyBlocks.Add(disposeCallBlock); return true; }