// creates a method for a given method CFG (IMPORTANT: it updates the operations // and exception handlers of the existing method, does not create a new method) public void createMethodFromCfg(MethodCfg methodCfg) { // list of basic blocks that belong together logically (i.e. BB2 lies directly behind BB1 because it reaches it without a branch) IList<BasicBlockUnion> basicBlockUnions = new List<BasicBlockUnion>(); // first step: create basic block unions // create first basic block union starting from the start basic block BasicBlockUnion firstBasicBlockUnion = new BasicBlockUnion(); this.createRecursivelyBasicBlockUnion(basicBlockUnions, firstBasicBlockUnion, methodCfg.startBasicBlock); basicBlockUnions.Add(firstBasicBlockUnion); // create basic block unions for the rest of the basic blocks foreach (BasicBlock tempBB in methodCfg.basicBlocks) { // create a basic block union (if basic block is not contained by another existing basic block union) BasicBlockUnion basicBlockUnion = new BasicBlockUnion(); this.createRecursivelyBasicBlockUnion(basicBlockUnions, basicBlockUnion, tempBB); // if the newly created basic block union contains basic blocks // => add to list of basic block unions if (basicBlockUnion.basicBlocks.Count() != 0) { basicBlockUnions.Add(basicBlockUnion); } } // step two: merge basic block unions with respect to the exception handler foreach (OperationExceptionInformation exceptionHandler in methodCfg.method.Body.OperationExceptionInformation) { // create a temporary object to reorder the basic block unions with respect to the exception handler BasicBlockUnionExceptionHandlerOrder tempNewOrder = new BasicBlockUnionExceptionHandlerOrder(); tempNewOrder.exceptionHandler = exceptionHandler; // find all basic blocks that are connected to the current exception handler foreach (BasicBlockUnion basicBlockUnion in basicBlockUnions) { foreach (BasicBlock basicBlock in basicBlockUnion.basicBlocks) { // ignore all basic blocks that do not have any try/catch/finally handler in it if (basicBlock.tryBlocks.Count() == 0 && basicBlock.handlerBlocks.Count() == 0) { continue; } // find the try block that is connected to the current exception handler foreach (TryBlock tryBlock in basicBlock.tryBlocks) { // ignore try blocks that do not belong to the current exception handler if (tryBlock.exceptionHandler != exceptionHandler) { continue; } // check if basic block union already resides in try body // if not => add to try body if (!tempNewOrder.tryBody.Contains(basicBlockUnion)) { tempNewOrder.tryBody.Add(basicBlockUnion); } // check if the basic block starts the try block if (tryBlock.firstBasicBlockOfTryBlock) { tempNewOrder.tryStart = basicBlockUnion; } // check if the basic block ends the try block if (tryBlock.lastBasicBlockOfTryBlock) { tempNewOrder.tryEnd = basicBlockUnion; } } // find the handler block that is connected to the current exception handler foreach (HandlerBlock handlerBlock in basicBlock.handlerBlocks) { // ignore handler blocks that do not belong to the current exception handler if (handlerBlock.exceptionHandler != exceptionHandler) { continue; } // check if basic block union already resides in handler body // if not => add to handler body if (!tempNewOrder.handlerBody.Contains(basicBlockUnion)) { tempNewOrder.handlerBody.Add(basicBlockUnion); } // check if the basic block starts the handler block if (handlerBlock.firstBasicBlockOfHandlerBlock) { tempNewOrder.handlerStart = basicBlockUnion; } // check if the basic block ends the handler block if (handlerBlock.lastBasicBlockOfHandlerBlock) { tempNewOrder.handlerEnd = basicBlockUnion; } } } } if (tempNewOrder.tryStart == null || tempNewOrder.tryEnd == null || tempNewOrder.handlerStart == null || tempNewOrder.handlerEnd == null) { throw new ArgumentException("Could not find all try/catch beginnings/ends."); } // merge basic block unions with respect to the current exception handler // check if the complete exception handling is done in only one basic block union // => ignore it if (tempNewOrder.tryStart == tempNewOrder.tryEnd && tempNewOrder.handlerStart == tempNewOrder.handlerEnd && tempNewOrder.tryStart == tempNewOrder.handlerStart) { continue; } // if not everything lies in the same basic block union // extend the basic block union that starts the try block BasicBlockUnion extendedUnion = tempNewOrder.tryStart; // if try block start and end are the same => nothing to merge // else merge the basic block unions if (tempNewOrder.tryStart != tempNewOrder.tryEnd) { foreach (BasicBlockUnion tryBodyBasicBlockUnion in tempNewOrder.tryBody) { // ignore the basic block union that starts the try block (already in extended union) // and ignore the basic block union that ends the try block (is added last) if (tryBodyBasicBlockUnion == tempNewOrder.tryStart || tryBodyBasicBlockUnion == tempNewOrder.tryEnd) { continue; } // extend first basic block union with the basic block union of the // try block body and remove the added one from the list of basic block unions extendedUnion.basicBlocks.AddRange(tryBodyBasicBlockUnion.basicBlocks); basicBlockUnions.Remove(tryBodyBasicBlockUnion); } // extend first basic block union with the basic block union of the // try block end and remove the added one from the list of basic block unions extendedUnion.basicBlocks.AddRange(tempNewOrder.tryEnd.basicBlocks); basicBlockUnions.Remove(tempNewOrder.tryEnd); } // if the try block end and the handler block start are not the same basic block union // => merge the union of the handler block start to the current basic block union if (tempNewOrder.tryEnd != tempNewOrder.handlerStart) { extendedUnion.basicBlocks.AddRange(tempNewOrder.handlerStart.basicBlocks); basicBlockUnions.Remove(tempNewOrder.handlerStart); } // if handler block start and end are the same => nothing to merge // else merge the basic block unions if (tempNewOrder.handlerStart != tempNewOrder.handlerEnd) { foreach (BasicBlockUnion handlerBodyBasicBlockUnion in tempNewOrder.handlerBody) { // ignore the basic block union that starts the handler block (already in extended union) // and ignore the basic block union that ends the handler block (is added last) if (handlerBodyBasicBlockUnion == tempNewOrder.handlerStart || handlerBodyBasicBlockUnion == tempNewOrder.handlerEnd) { continue; } // add basic block union of the handler block body to the extended basic block union // and remove the added one from the list of basic block unions extendedUnion.basicBlocks.AddRange(handlerBodyBasicBlockUnion.basicBlocks); basicBlockUnions.Remove(handlerBodyBasicBlockUnion); } // extend the extended basic block union with the basic block union of the // handler block end and remove the added one from the list of basic block unions extendedUnion.basicBlocks.AddRange(tempNewOrder.handlerEnd.basicBlocks); basicBlockUnions.Remove(tempNewOrder.handlerEnd); } } // step three: create one list of operations and modify jump offsets // create a list of operations from the basic blocks, // update basic block start/end indices accordingly // and update the offsets of the operations (needed to update branch operations) IList<IOperation> methodOperations = new List<IOperation>(); int operationIdx = 0; uint currentOffset = 0; foreach (BasicBlockUnion basicBlockUnion in basicBlockUnions) { foreach (BasicBlock basicBlock in basicBlockUnion.basicBlocks) { basicBlock.startIdx = operationIdx; //foreach (IOperation operation in basicBlock.operations) { for (int opIdx = 0; opIdx < basicBlock.operations.Count(); opIdx++) { IOperation operation = basicBlock.operations.ElementAt(opIdx); // a new operation object is needed because the old operations // are read only due to cci InternalOperation newOperation = new InternalOperation(); // exchange every short instruction with its larger one switch (operation.OperationCode) { case OperationCode.Beq_S: newOperation.OperationCode = OperationCode.Beq; break; case OperationCode.Bge_S: newOperation.OperationCode = OperationCode.Bge; break; case OperationCode.Bge_Un_S: newOperation.OperationCode = OperationCode.Bge_Un; break; case OperationCode.Bgt_S: newOperation.OperationCode = OperationCode.Bgt; break; case OperationCode.Bgt_Un_S: newOperation.OperationCode = OperationCode.Bgt_Un; break; case OperationCode.Ble_S: newOperation.OperationCode = OperationCode.Ble; break; case OperationCode.Ble_Un_S: newOperation.OperationCode = OperationCode.Ble_Un; break; case OperationCode.Blt_S: newOperation.OperationCode = OperationCode.Blt; break; case OperationCode.Blt_Un_S: newOperation.OperationCode = OperationCode.Blt_Un; break; case OperationCode.Bne_Un_S: newOperation.OperationCode = OperationCode.Bne_Un; break; case OperationCode.Br_S: newOperation.OperationCode = OperationCode.Br; break; case OperationCode.Brfalse_S: newOperation.OperationCode = OperationCode.Brfalse; break; case OperationCode.Brtrue_S: newOperation.OperationCode = OperationCode.Brtrue; break; case OperationCode.Ldarg_S: newOperation.OperationCode = OperationCode.Ldarg; break; case OperationCode.Ldarga_S: newOperation.OperationCode = OperationCode.Ldarga; break; case OperationCode.Ldc_I4_S: newOperation.OperationCode = OperationCode.Ldc_I4; break; case OperationCode.Ldloc_S: newOperation.OperationCode = OperationCode.Ldloc; break; case OperationCode.Ldloca_S: newOperation.OperationCode = OperationCode.Ldloca; break; case OperationCode.Leave_S: newOperation.OperationCode = OperationCode.Leave; break; case OperationCode.Starg_S: newOperation.OperationCode = OperationCode.Starg; break; case OperationCode.Stloc_S: newOperation.OperationCode = OperationCode.Stloc; break; default: newOperation.OperationCode = operation.OperationCode; break; } newOperation.Value = operation.Value; newOperation.Location = operation.Location; newOperation.Offset = currentOffset; methodOperations.Add(newOperation); // replace old operation in basic block with newly created one basicBlock.operations[opIdx] = newOperation; operationIdx++; currentOffset += CfgBuilder.getSizeOfOperation(newOperation); } basicBlock.endIdx = operationIdx - 1; } } // step four: update branches with new target offsets foreach (BasicBlock tempBB in methodCfg.basicBlocks) { InternalOperation branchOperation = (InternalOperation)methodOperations.ElementAt(tempBB.endIdx); // check which kind of exit branch is used by this basic block and update its operation accordingly if (tempBB.exitBranch as NoBranchTarget != null) { continue; } else if (tempBB.exitBranch as TryBlockTarget != null) { continue; } else if (tempBB.exitBranch as ConditionalBranchTarget != null) { ConditionalBranchTarget tempExitBranch = (tempBB.exitBranch as ConditionalBranchTarget); // check if the branch is done by a branch operation if (!CfgBuilder.isBranchOperation(branchOperation)) { throw new ArgumentException("Branch is not done by a valid branch operation."); } // get index of the branch target int targetBranchIdx = tempExitBranch.takenTarget.startIdx; // update offset of the taken branch branchOperation.Value = methodOperations.ElementAt(targetBranchIdx).Offset; } else if (tempBB.exitBranch as SwitchBranchTarget != null) { SwitchBranchTarget tempExitBranch = (tempBB.exitBranch as SwitchBranchTarget); // check if the branch is done by a branch operation if (!CfgBuilder.isBranchOperation(branchOperation)) { throw new ArgumentException("Branch is not done by a valid branch operation."); } // update all switch branches for (int switchIdx = 0; switchIdx < tempExitBranch.takenTarget.Count(); switchIdx++) { // get index of the branch target int targetBranchIdx = tempExitBranch.takenTarget.ElementAt(switchIdx).startIdx; // update offset of the taken branch ((uint[])branchOperation.Value)[switchIdx] = methodOperations.ElementAt(targetBranchIdx).Offset; } } else if (tempBB.exitBranch as UnconditionalBranchTarget != null) { UnconditionalBranchTarget tempExitBranch = (tempBB.exitBranch as UnconditionalBranchTarget); // check if the branch is done by a branch operation if (!CfgBuilder.isBranchOperation(branchOperation)) { throw new ArgumentException("Branch is not done by a valid branch operation."); } // get index of the branch target int targetBranchIdx = tempExitBranch.takenTarget.startIdx; // update offset of the taken branch branchOperation.Value = methodOperations.ElementAt(targetBranchIdx).Offset; } else if (tempBB.exitBranch as ExitBranchTarget != null) { continue; } else if (tempBB.exitBranch as ThrowBranchTarget != null) { continue; } else if (tempBB.exitBranch as ExceptionBranchTarget != null) { ExceptionBranchTarget tempExitBranch = (tempBB.exitBranch as ExceptionBranchTarget); // check if the branch is done by a branch operation if (!CfgBuilder.isBranchOperation(branchOperation)) { throw new ArgumentException("Branch is not done by a valid branch operation."); } // get index of the branch target int targetBranchIdx = tempExitBranch.exitTarget.startIdx; // update offset of the taken branch branchOperation.Value = methodOperations.ElementAt(targetBranchIdx).Offset; } else { throw new ArgumentException("Do not know how to handle exit branch."); } } // step five: create new exception handler with updated offsets and // create new method body of the cci method MethodDefinition method = methodCfg.method; var ilGenerator = new ILGenerator(this.host, method); // emit all operations to the new body foreach (IOperation operation in methodOperations) { ilGenerator.Emit(operation.OperationCode, operation.Value); } // list that is used to replace the pointer to the old exception handler in the basic blocks to the new exception handler List<OldExceptionHandlerMapping> oldExceptionHandlerMappings = new List<OldExceptionHandlerMapping>(); // create for each old exception handler a new one with updated data foreach (IOperationExceptionInformation exceptionHandler in method.Body.OperationExceptionInformation) { // create mapping object for old exception handler OldExceptionHandlerMapping oldExceptionHandlerMapping = new OldExceptionHandlerMapping(); oldExceptionHandlerMapping.oldExceptionHandler = exceptionHandler; oldExceptionHandlerMappings.Add(oldExceptionHandlerMapping); ILGeneratorLabel tryStart = new ILGeneratorLabel(); ILGeneratorLabel tryEnd = new ILGeneratorLabel(); ILGeneratorLabel handlerStart = new ILGeneratorLabel(); ILGeneratorLabel handlerEnd = new ILGeneratorLabel(); ILGeneratorLabel filterStart = new ILGeneratorLabel(); // search for the basic blocks that start/end the try block and handler block foreach (BasicBlock tempBB in methodCfg.basicBlocks) { foreach (TryBlock tempTryBlock in tempBB.tryBlocks) { // ignore try blocks that do not belong to the current exception handler if (tempTryBlock.exceptionHandler != exceptionHandler) { continue; } // get offset of the instruction that starts the try block if (tempTryBlock.firstBasicBlockOfTryBlock) { tryStart.Offset = tempBB.operations.ElementAt(0).Offset; oldExceptionHandlerMapping.tryStartOffset = tryStart.Offset; } // get offset of the instruction that ends the try block (always the last instruction of the basic block) if (tempTryBlock.lastBasicBlockOfTryBlock) { tryEnd.Offset = tempBB.operations.ElementAt(tempBB.operations.Count() - 1).Offset; // exception handler object needs offset of the end of the instruction (not the beginning) tryEnd.Offset += CfgBuilder.getSizeOfOperation(tempBB.operations.ElementAt(tempBB.operations.Count() - 1)); oldExceptionHandlerMapping.tryEndOffset = tryEnd.Offset; } } foreach (HandlerBlock tempHandlerBlock in tempBB.handlerBlocks) { // ignore handler blocks that do not belong to the current exception handler if (tempHandlerBlock.exceptionHandler != exceptionHandler) { continue; } // get offset ot the instruction that starts the handler block if (tempHandlerBlock.firstBasicBlockOfHandlerBlock) { handlerStart.Offset = tempBB.operations.ElementAt(0).Offset; oldExceptionHandlerMapping.handlerStartOffset = handlerStart.Offset; } // get offset of the instruction that ends the handler block if (tempHandlerBlock.lastBasicBlockOfHandlerBlock) { handlerEnd.Offset = tempBB.operations.ElementAt(tempBB.operations.Count() - 1).Offset; // exception handler object needs offset of the end of the instruction (not the beginning) handlerEnd.Offset += CfgBuilder.getSizeOfOperation(tempBB.operations.ElementAt(tempBB.operations.Count() - 1)); oldExceptionHandlerMapping.handlerEndOffset = handlerEnd.Offset; } } } // copy the exception handler filter filterStart.Offset = exceptionHandler.FilterDecisionStartOffset; oldExceptionHandlerMapping.filterStartOffset = filterStart.Offset; // add new exception handler oldExceptionHandlerMapping.exceptionType = exceptionHandler.ExceptionType; oldExceptionHandlerMapping.handlerKind = exceptionHandler.HandlerKind; ilGenerator.AddExceptionHandlerInformation(exceptionHandler.HandlerKind, exceptionHandler.ExceptionType, tryStart, tryEnd, handlerStart, handlerEnd, filterStart); } // create the body List<ILocalDefinition> variableListCopy = new List<ILocalDefinition>(method.Body.LocalVariables); List<ITypeDefinition> privateHelperTypesListCopy = new List<ITypeDefinition>(method.Body.PrivateHelperTypes); var newBody = new ILGeneratorMethodBody(ilGenerator, method.Body.LocalsAreZeroed, 8, method, variableListCopy, privateHelperTypesListCopy); // TODO dynamic max stack size? method.Body = newBody; // step six: replace pointer to the old exception handler with the new exception handler // map all old exception handler to the new objects foreach (IOperationExceptionInformation exceptionHandler in method.Body.OperationExceptionInformation) { // search for the new exception handler object to get the mapping to the old one bool found = false; foreach (OldExceptionHandlerMapping oldExceptionHandlerMapping in oldExceptionHandlerMappings) { if (oldExceptionHandlerMapping.exceptionType == exceptionHandler.ExceptionType && oldExceptionHandlerMapping.handlerKind == exceptionHandler.HandlerKind && oldExceptionHandlerMapping.filterStartOffset == exceptionHandler.FilterDecisionStartOffset && oldExceptionHandlerMapping.tryStartOffset == exceptionHandler.TryStartOffset && oldExceptionHandlerMapping.tryEndOffset == exceptionHandler.TryEndOffset && oldExceptionHandlerMapping.handlerStartOffset == exceptionHandler.HandlerStartOffset && oldExceptionHandlerMapping.handlerEndOffset == exceptionHandler.HandlerEndOffset) { oldExceptionHandlerMapping.newExceptionHandler = exceptionHandler; found = true; break; } } if (!found) { throw new ArgumentException("Not able to map old exception handler to new one."); } } // replace all old exception handler in the basic blocks with the new exception handler foreach (BasicBlock tempBB in methodCfg.basicBlocks) { // replace all exception handler in the try blocks foreach (TryBlock tryBlock in tempBB.tryBlocks) { foreach (OldExceptionHandlerMapping oldExceptionHandlerMapping in oldExceptionHandlerMappings) { if (tryBlock.exceptionHandler == oldExceptionHandlerMapping.oldExceptionHandler) { tryBlock.exceptionHandler = oldExceptionHandlerMapping.newExceptionHandler; break; } } } // replace all exception handler in the handler blocks foreach (HandlerBlock handlerBlock in tempBB.handlerBlocks) { foreach (OldExceptionHandlerMapping oldExceptionHandlerMapping in oldExceptionHandlerMappings) { if (handlerBlock.exceptionHandler == oldExceptionHandlerMapping.oldExceptionHandler) { handlerBlock.exceptionHandler = oldExceptionHandlerMapping.newExceptionHandler; break; } } } } // TODO // DEBUG /* // sanitize method name to store it as a file String invalidChars = System.Text.RegularExpressions.Regex.Escape(new string(System.IO.Path.GetInvalidFileNameChars())); String invalidRegStr = string.Format(@"([{0}]*\.+$)|([{0}]+)", invalidChars); String fileName = System.Text.RegularExpressions.Regex.Replace(methodCfg.method.ToString(), invalidRegStr, "_"); fileName = fileName.Length >= 230 ? fileName.Substring(0, 230) : fileName; // dump cfg created from the exit branches System.IO.StreamWriter dotFile = new System.IO.StreamWriter("e:\\" + "\\BBUnion_" + fileName + ".dot"); // start .dot file graph dotFile.WriteLine("digraph G {"); for (int bbuidx = 0; bbuidx < basicBlockUnions.Count(); bbuidx++) { BasicBlockUnion basicBlockUnion = basicBlockUnions.ElementAt(bbuidx); // write all basic blocks to .dot file for (int idx = 0; idx < basicBlockUnion.basicBlocks.Count(); idx++) { BasicBlock currentBasicBlock = basicBlockUnion.basicBlocks.ElementAt(idx); // write the current basic block to the file and all its instructions dotFile.WriteLine("BB" + bbuidx.ToString() + "_" + idx.ToString() + " [shape=record]"); bool first = true; for (int opIdx = 0; opIdx < currentBasicBlock.operations.Count(); opIdx++) { var operation = currentBasicBlock.operations.ElementAt(opIdx); if (first) { dotFile.Write("BB" + bbuidx.ToString() + "_" + idx.ToString() + " [label=\"{"); first = false; } else { dotFile.Write("|"); } // insert try block beginnings foreach (var tryBlock in currentBasicBlock.tryBlocks) { if (tryBlock.firstBasicBlockOfTryBlock && opIdx == 0) { dotFile.Write("TRY START (" + tryBlock.exceptionHandler.ExceptionType.ToString() + ")|"); } } // insert catch block beginnings foreach (var handlerBlock in currentBasicBlock.handlerBlocks) { if (handlerBlock.firstBasicBlockOfHandlerBlock && opIdx == 0) { if (handlerBlock.typeOfHandler == HandlerKind.Catch) { dotFile.Write("CATCH START (" + handlerBlock.exceptionHandler.ExceptionType.ToString() + ")|"); } else if (handlerBlock.typeOfHandler == HandlerKind.Finally) { dotFile.Write("FINALLY START (" + handlerBlock.exceptionHandler.ExceptionType.ToString() + ")|"); } else { throw new ArgumentException("Do not know how to handle handler."); } } } // check if instruction has an argument if (operation.Value != null) { dotFile.Write(operation.OperationCode.ToString() + " " + operation.Value.ToString()); } else { dotFile.Write(operation.OperationCode.ToString()); } // insert try block endings foreach (var tryBlock in currentBasicBlock.tryBlocks) { if (tryBlock.lastBasicBlockOfTryBlock && (currentBasicBlock.operations.Count() - 1) == opIdx) { dotFile.Write("|TRY END (" + tryBlock.exceptionHandler.ExceptionType.ToString() + ")"); } } // insert catch block endings foreach (var handlerBlock in currentBasicBlock.handlerBlocks) { if (handlerBlock.lastBasicBlockOfHandlerBlock && (currentBasicBlock.operations.Count() - 1) == opIdx) { if (handlerBlock.typeOfHandler == HandlerKind.Catch) { dotFile.Write("|CATCH END (" + handlerBlock.exceptionHandler.ExceptionType.ToString() + ")"); } else if (handlerBlock.typeOfHandler == HandlerKind.Finally) { dotFile.Write("|FINALLY END (" + handlerBlock.exceptionHandler.ExceptionType.ToString() + ")"); } else { throw new ArgumentException("Do not know how to handle handler."); } } } } dotFile.WriteLine("}\"]"); if ((idx + 1) < basicBlockUnion.basicBlocks.Count()) { dotFile.WriteLine("BB" + bbuidx.ToString() + "_" + idx.ToString() + " -> BB" + bbuidx.ToString() + "_" + (idx + 1).ToString() + "[ color=\"blue\" ]"); } } } // finish graph dotFile.WriteLine("}"); dotFile.Close(); */ }
// builds recursively a basic block union (a list of basic blocks that belong together in the control flow because // they are lying directly behind each other) private void createRecursivelyBasicBlockUnion(IList<BasicBlockUnion> basicBlockUnions, BasicBlockUnion currentUnion, BasicBlock currentBasicBlock) { // check if current basic block already belongs to a basic block union foreach (BasicBlockUnion basicBlockUnion in basicBlockUnions) { // ignore current basic block union if (basicBlockUnion == currentUnion) { continue; } foreach (BasicBlock tempBB in basicBlockUnion.basicBlocks) { if (tempBB == currentBasicBlock) { return; } } } // if there are no basic blocks inside the current basic block union // check if the entry to the current basic block could be a not taken branch // or no branch at all => start building the basic block union from the predecessor basic block if (currentUnion.basicBlocks.Count() == 0) { foreach (IBranchTarget entryBranch in currentBasicBlock.entryBranches) { BasicBlock predecessorBasicBlock = entryBranch.sourceBasicBlock; if (predecessorBasicBlock.exitBranch as NoBranchTarget != null) { NoBranchTarget predecessorExitBranch = (predecessorBasicBlock.exitBranch as NoBranchTarget); // check if the basic block that comes directly after the predecessor basic block is the current one // => start building basic block union from the predecessor if (predecessorExitBranch.takenTarget == currentBasicBlock) { this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, predecessorBasicBlock); return; } continue; } else if (predecessorBasicBlock.exitBranch as TryBlockTarget != null) { TryBlockTarget predecessorExitBranch = (predecessorBasicBlock.exitBranch as TryBlockTarget); // check if the basic block that comes directly after the predecessor basic block is the current one // => start building basic block union from the predecessor if (predecessorExitBranch.takenTarget == currentBasicBlock) { this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, predecessorBasicBlock); return; } continue; } else if (predecessorBasicBlock.exitBranch as ConditionalBranchTarget != null) { ConditionalBranchTarget predecessorExitBranch = (predecessorBasicBlock.exitBranch as ConditionalBranchTarget); // check if the basic block that comes directly after the predecessor basic block is the current one // => start building basic block union from the predecessor if (predecessorExitBranch.notTakenTarget == currentBasicBlock) { this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, predecessorBasicBlock); return; } continue; } else if (predecessorBasicBlock.exitBranch as SwitchBranchTarget != null) { SwitchBranchTarget predecessorExitBranch = (predecessorBasicBlock.exitBranch as SwitchBranchTarget); // check if the basic block that comes directly after the predecessor basic block is the current one // => start building basic block union from the predecessor if (predecessorExitBranch.notTakenTarget == currentBasicBlock) { this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, predecessorBasicBlock); return; } continue; } else if (predecessorBasicBlock.exitBranch as ExceptionBranchTarget != null) { ExceptionBranchTarget predecessorExitBranch = (predecessorBasicBlock.exitBranch as ExceptionBranchTarget); // check if the basic block that comes directly after the predecessor basic block is the current one // => start building basic block union from the predecessor if (predecessorExitBranch.exceptionTarget == currentBasicBlock) { this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, predecessorBasicBlock); return; } continue; } } } // add current basic block to the union currentUnion.basicBlocks.Add(currentBasicBlock); // follow all not taken branches and add them to the current basic block union // (this means all basic blocks that follow directly the current one directly // because they lie directly behind the current one are added to the basic block union) if (currentBasicBlock.exitBranch as NoBranchTarget != null) { NoBranchTarget tempExitBranch = (currentBasicBlock.exitBranch as NoBranchTarget); this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, tempExitBranch.takenTarget); return; } else if (currentBasicBlock.exitBranch as TryBlockTarget != null) { TryBlockTarget tempExitBranch = (currentBasicBlock.exitBranch as TryBlockTarget); this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, tempExitBranch.takenTarget); return; } else if (currentBasicBlock.exitBranch as ConditionalBranchTarget != null) { ConditionalBranchTarget tempExitBranch = (currentBasicBlock.exitBranch as ConditionalBranchTarget); this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, tempExitBranch.notTakenTarget); return; } else if (currentBasicBlock.exitBranch as SwitchBranchTarget != null) { SwitchBranchTarget tempExitBranch = (currentBasicBlock.exitBranch as SwitchBranchTarget); this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, tempExitBranch.notTakenTarget); return; } else if (currentBasicBlock.exitBranch as UnconditionalBranchTarget != null) { return; } else if (currentBasicBlock.exitBranch as ExitBranchTarget != null) { return; } else if (currentBasicBlock.exitBranch as ThrowBranchTarget != null) { return; } else if (currentBasicBlock.exitBranch as ExceptionBranchTarget != null) { ExceptionBranchTarget tempExitBranch = (currentBasicBlock.exitBranch as ExceptionBranchTarget); this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, tempExitBranch.exceptionTarget); return; } else { throw new ArgumentException("Do not know how to handle exit branch."); } }