// insert the given new target basic block (given by start and end block) between the given conditional branch to manipulate
        public void insertBasicBlockBetweenBranch(ConditionalBranchTarget branchToManipulate, bool manipulateTakenBranch, BasicBlock newTargetStart, BasicBlock newTargetEnd, NoBranchTarget exitBranch) {

            // get the basic block from that the branch is taken and the basic block to that the branch is taken
            BasicBlock introBasicBlock = branchToManipulate.sourceBasicBlock;
            BasicBlock outroBasicBlock = null;

            // manipulate the correct branch
            if (manipulateTakenBranch) {
                outroBasicBlock = branchToManipulate.takenTarget;
                this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulate.takenTarget, newTargetStart, newTargetEnd, exitBranch, ref exitBranch.takenTarget);
            }
            else {
                outroBasicBlock = branchToManipulate.notTakenTarget;
                this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulate.notTakenTarget, newTargetStart, newTargetEnd, exitBranch, ref exitBranch.takenTarget);
            }
        }
        // this function splits a basic block on the given index
        public void splitBasicBlock(BasicBlock firstPartBB, int splitIndex) {

            // check if the index is out of bounds
            if (splitIndex >= firstPartBB.operations.Count()) {
                throw new ArgumentException("Index is equal or greater than existing basic block operations.");
            }

            // check if there are at least 2 operations inside the basic block to split
            if (firstPartBB.operations.Count() < 2) {
                throw new ArgumentException("Too few operations in basic block for splitting.");
            }

            // create the new basic block that will become the second part of the basic block to split
            BasicBlock secondPartBB = new BasicBlock();

            // move the exit basic blocks to the new created basic block
            // and make the new created basic block the exit of the splitted one   
            secondPartBB.exitBranch = firstPartBB.exitBranch;
            secondPartBB.exitBranch.sourceBasicBlock = secondPartBB;
            NoBranchTarget tempExitBranch = new NoBranchTarget();
            tempExitBranch.takenTarget = secondPartBB;
            tempExitBranch.sourceBasicBlock = firstPartBB;
            firstPartBB.exitBranch = tempExitBranch;

            // add splitted basic block branch
            // to the entries of the new basic block
            secondPartBB.entryBranches.Add(tempExitBranch);

            // distribute the instructions to the basic blocks 
            List<IOperation> previousOperations = new List<IOperation>();
            List<IOperation> nextOperations = new List<IOperation>();
            for (int operationIdx = 0; operationIdx < firstPartBB.operations.Count(); operationIdx++) {

                if (operationIdx < splitIndex) {
                    previousOperations.Add(firstPartBB.operations.ElementAt(operationIdx));
                }
                else {
                    nextOperations.Add(firstPartBB.operations.ElementAt(operationIdx));
                }
            }
            firstPartBB.operations = previousOperations;
            secondPartBB.operations = nextOperations;

            
            // add a semantic id to the new basic block
            if (firstPartBB.semanticId == -1) {
                secondPartBB.semanticId = -1;
            }
            else {
                int highestSemanticId = 0;
                foreach (BasicBlock tempBB in methodCfg.basicBlocks) {
                    if (tempBB.semanticId > highestSemanticId) {
                        highestSemanticId = tempBB.semanticId;
                    }
                }

                secondPartBB.semanticId = highestSemanticId + 1;
            }


            // add new basic block to the cfg
            methodCfg.basicBlocks.Add(secondPartBB);

        }
        // insert the given new target basic block between the given conditional branch to manipulate
        public void insertBasicBlockBetweenBranch(NoBranchTarget branchToManipulate, BasicBlock newTarget, SwitchBranchTarget exitBranch, int switchTakenBranchIdx) {

            // get the basic block from that the branch is taken and the basic block to that the branch is taken
            BasicBlock introBasicBlock = branchToManipulate.sourceBasicBlock;
            BasicBlock outroBasicBlock = branchToManipulate.takenTarget;
            BasicBlock tempTakenTarget = null;

            this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulate.takenTarget, newTarget, newTarget, exitBranch, ref tempTakenTarget);

            // fill switch taken branch list with null when index is out of range
            while (exitBranch.takenTarget.Count() <= switchTakenBranchIdx) {
                exitBranch.takenTarget.Add(null);
            }

            exitBranch.takenTarget[switchTakenBranchIdx] = tempTakenTarget;

        }
        // insert the given new target basic block (given by start and end block) between the given unconditional branch to manipulate
        public void insertBasicBlockBetweenBranch(UnconditionalBranchTarget branchToManipulate, BasicBlock newTargetStart, BasicBlock newTargetEnd, NoBranchTarget exitBranch) {

            // get the basic block from that the branch is taken and the basic block to that the branch is taken
            BasicBlock introBasicBlock = branchToManipulate.sourceBasicBlock;
            BasicBlock outroBasicBlock = branchToManipulate.takenTarget;

            this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulate.takenTarget, newTargetStart, newTargetEnd, exitBranch, ref exitBranch.takenTarget);
        }
Exemple #5
0
        // build recursively the cfg of the given operations
        private void buildRecursivelyCfg(MethodCfg methodCfg, IEnumerable<IOperation> operations, int currentIdx, IBranchTarget entryBranch, ref BasicBlock currentBasicBlock) {

            // check if a new basic block has to be created
            for (int bbIdx = 0; bbIdx < methodCfg.basicBlocks.Count(); bbIdx++) {

                // check if the current index points into an existing basic block
                // => split basic block
                BasicBlock tempBB = methodCfg.basicBlocks.ElementAt(bbIdx);
                if (tempBB.startIdx < currentIdx && tempBB.endIdx >= currentIdx) {

                    // create new basic block which will be the second half of the found one
                    BasicBlock newBasicBlock = new BasicBlock(this.semanticId);
                    this.semanticId++;
                    newBasicBlock.startIdx = currentIdx;
                    newBasicBlock.endIdx = tempBB.endIdx;
                    tempBB.endIdx = currentIdx - 1;

                    // move the exit basic blocks to the new created basic block
                    // and make the new created basic block the exit of the splitted one                    
                    newBasicBlock.exitBranch = tempBB.exitBranch;
                    newBasicBlock.exitBranch.sourceBasicBlock = newBasicBlock;
                    NoBranchTarget tempExitBranch = new NoBranchTarget();
                    tempExitBranch.takenTarget = newBasicBlock;
                    tempExitBranch.sourceBasicBlock = tempBB;
                    tempBB.exitBranch = tempExitBranch;

                    // set the current basic block to the new created basic block
                    currentBasicBlock = newBasicBlock;

                    // add splitted basic block branch and basic block branch that leads to this split
                    // to the entries of the new one
                    newBasicBlock.entryBranches.Add(entryBranch);
                    newBasicBlock.entryBranches.Add(tempExitBranch);

                    // distribute the instructions to the basic blocks 
                    List<IOperation> previousOperations = new List<IOperation>();
                    List<IOperation> nextOperations = new List<IOperation>();
                    for (int operationIdx = 0; (operationIdx + tempBB.startIdx) <= newBasicBlock.endIdx; operationIdx++) {

                        if ((operationIdx + tempBB.startIdx) < currentIdx) {
                            previousOperations.Add(tempBB.operations.ElementAt(operationIdx));
                        }
                        else {
                            nextOperations.Add(tempBB.operations.ElementAt(operationIdx));
                        }
                    }
                    tempBB.operations = previousOperations;
                    newBasicBlock.operations = nextOperations;

                    // add new basic block to the cfg
                    methodCfg.basicBlocks.Add(newBasicBlock);

                    return;
                }

                // if the current index of the operation points to the start index of an existing basic block
                // => update entry branches
                else if (tempBB.startIdx == currentIdx && entryBranch != null && currentBasicBlock != null) {
                    tempBB.entryBranches.Add(entryBranch);

                    // set the found basic block as the current basic block
                    currentBasicBlock = tempBB;
                    return;
                }

                // if the current index of the operation points to the start index of an existing basic block, has no entry branch
                // and is not the first instruction
                // set the current basic block to the found one
                else if (currentIdx != 0 && tempBB.startIdx == currentIdx && currentBasicBlock != null) {

                    // set the found basic block as the current basic block
                    currentBasicBlock = tempBB;
                    return;

                }

            }

            // set index of current basic block and add it to the cfg
            currentBasicBlock.startIdx = currentIdx;
            methodCfg.basicBlocks.Add(currentBasicBlock);

            // check if the basic block was jumped to from another basic block
            // => update entry branches
            if (entryBranch != null) {
                currentBasicBlock.entryBranches.Add(entryBranch);
            }

            // parse every instruction to find branches etc
            for (int idx = currentIdx; idx < operations.Count(); idx++) {

                // check if the current instruction is the start instruction of an already existing basic block (except the current basic block)
                // => add the current basic block to the list of entry basic blocks, the found basic block to the list of exit basic blocks and set the index
                for (int bbIdx = 0; bbIdx < methodCfg.basicBlocks.Count(); bbIdx++) {
                    BasicBlock tempBB = methodCfg.basicBlocks.ElementAt(bbIdx);
                    if (tempBB.startIdx == idx && tempBB != currentBasicBlock) {
                        currentBasicBlock.endIdx = idx - 1;

                        // create new exit branch and add it
                        NoBranchTarget currentExitBranch = new NoBranchTarget();
                        currentExitBranch.sourceBasicBlock = currentBasicBlock;
                        currentExitBranch.takenTarget = tempBB;
                        currentBasicBlock.exitBranch = currentExitBranch;

                        // add current exit branch as entry for the found one
                        tempBB.entryBranches.Add(currentExitBranch);
                        return;
                    }
                }

                // add current instruction to the basic block
                var operation = operations.ElementAt(idx);
                currentBasicBlock.operations.Add(operation);

                // check for special instructions like branches
                switch (operation.OperationCode) {

                    // conditional branch instructions
                    case OperationCode.Beq:
                    case OperationCode.Bge:
                    case OperationCode.Bge_Un:
                    case OperationCode.Bgt:
                    case OperationCode.Bgt_Un:
                    case OperationCode.Ble:
                    case OperationCode.Ble_Un:
                    case OperationCode.Blt:
                    case OperationCode.Blt_Un:
                    case OperationCode.Bne_Un:
                    case OperationCode.Brfalse:
                    case OperationCode.Brtrue:
                    case OperationCode.Beq_S:
                    case OperationCode.Bge_S:
                    case OperationCode.Bge_Un_S:
                    case OperationCode.Bgt_S:
                    case OperationCode.Bgt_Un_S:
                    case OperationCode.Ble_S:
                    case OperationCode.Ble_Un_S:
                    case OperationCode.Blt_S:
                    case OperationCode.Blt_Un_S:
                    case OperationCode.Bne_Un_S:
                    case OperationCode.Brfalse_S:
                    case OperationCode.Brtrue_S: {

                            // the current basic block ends here
                            currentBasicBlock.endIdx = idx;

                            // calculate the target index of the branch
                            int branchTargetIdx = 0;
                            uint branchTargetOffset;

                            // do operation value can be of type long which can not be casted in this way
                            if (operation.Value is long) {
                                branchTargetOffset = Convert.ToUInt32(operation.Value);
                            }
                            else {
                                branchTargetOffset = (uint)operation.Value;
                            }

                            while (true) {
                                if (operations.ElementAt(branchTargetIdx).Offset == branchTargetOffset) {
                                    break;
                                }
                                else if (operations.ElementAt(branchTargetIdx).Offset > branchTargetOffset) {
                                    throw new ArgumentException("Could not find target off branch.");
                                }
                                branchTargetIdx++;
                            }

                            // create new exit branch object
                            ConditionalBranchTarget currentExitBranch = new ConditionalBranchTarget();
                            currentExitBranch.sourceBasicBlock = currentBasicBlock;
                            currentExitBranch.notTakenTarget = new BasicBlock(this.semanticId);
                            this.semanticId++;
                            currentExitBranch.takenTarget = new BasicBlock(this.semanticId);
                            this.semanticId++;
                            currentBasicBlock.exitBranch = currentExitBranch;

                            // start two new basic blocks from this branch on and end current execution
                            this.buildRecursivelyCfg(methodCfg, operations, idx + 1, currentExitBranch, ref currentExitBranch.notTakenTarget);
                            this.buildRecursivelyCfg(methodCfg, operations, branchTargetIdx, currentExitBranch, ref currentExitBranch.takenTarget);
                            return;
                        }

                    // unconditional branch instructions
                    case OperationCode.Br:
                    case OperationCode.Br_S: {

                            // the current basic block ends here
                            currentBasicBlock.endIdx = idx;

                            // calculate the target index of the branch
                            int branchTargetIdx = 0;
                            uint branchTargetOffset = (uint)operation.Value;
                            while (true) {
                                if (operations.ElementAt(branchTargetIdx).Offset == branchTargetOffset) {
                                    break;
                                }
                                else if (operations.ElementAt(branchTargetIdx).Offset > branchTargetOffset) {
                                    throw new ArgumentException("Could not find target off branch.");
                                }
                                branchTargetIdx++;
                            }

                            // create new exit branch object
                            UnconditionalBranchTarget currentExitBranch = new UnconditionalBranchTarget();
                            currentExitBranch.sourceBasicBlock = currentBasicBlock;
                            currentExitBranch.takenTarget = new BasicBlock(this.semanticId);
                            this.semanticId++;
                            currentBasicBlock.exitBranch = currentExitBranch;

                            // start one new basic block from this branch on and end current execution
                            this.buildRecursivelyCfg(methodCfg, operations, branchTargetIdx, currentExitBranch, ref currentExitBranch.takenTarget);
                            return;
                        }

                    // exit operation
                    case OperationCode.Ret: {

                            // the current basic block ends here
                            currentBasicBlock.endIdx = idx;

                            // create new exit branch object
                            ExitBranchTarget currentExitBranch = new ExitBranchTarget();
                            currentExitBranch.sourceBasicBlock = currentBasicBlock;
                            currentBasicBlock.exitBranch = currentExitBranch;

                            // end current execution
                            return;
                        }

                    // operations that exit the current function/control flow
                    case OperationCode.Throw: {

                            // the current basic block ends here
                            currentBasicBlock.endIdx = idx;

                            // create new exit branch object
                            ThrowBranchTarget currentExitBranch = new ThrowBranchTarget();
                            currentExitBranch.sourceBasicBlock = currentBasicBlock;
                            currentBasicBlock.exitBranch = currentExitBranch;

                            // start a new basic block if this was not the last instruction of the method
                            // (needed because some control flows that are reached via throw are not found without it) 
                            if ((idx + 1) < operations.Count()) {
                                BasicBlock newStartBasicBlock = new BasicBlock(this.semanticId);
                                this.semanticId++;
                                this.buildRecursivelyCfg(methodCfg, operations, idx + 1, null, ref newStartBasicBlock);
                            }

                            // end current execution
                            return;
                        }

                    // switch instruction (has a variable set of jump targets)
                    case OperationCode.Switch: {

                            // the current basic block ends here
                            currentBasicBlock.endIdx = idx;

                            // create new exit branch object
                            SwitchBranchTarget currentExitBranch = new SwitchBranchTarget();
                            currentExitBranch.sourceBasicBlock = currentBasicBlock;
                            currentExitBranch.notTakenTarget = new BasicBlock(this.semanticId);
                            this.semanticId++;
                            currentBasicBlock.exitBranch = currentExitBranch;

                            // calculate the target index of all switch branches
                            int counter = 0;
                            foreach (uint branchTargetOffset in (uint[])operation.Value) {
                                int branchTargetIdx = 0;
                                while (true) {
                                    if (operations.ElementAt(branchTargetIdx).Offset == branchTargetOffset) {
                                        break;
                                    }
                                    else if (operations.ElementAt(branchTargetIdx).Offset > branchTargetOffset) {
                                        throw new ArgumentException("Could not find target off branch.");
                                    }
                                    branchTargetIdx++;
                                }

                                // start a new basic block from this branch on
                                BasicBlock tempNextBasicBlock = new BasicBlock(this.semanticId);
                                this.semanticId++;
                                this.buildRecursivelyCfg(methodCfg, operations, branchTargetIdx, currentExitBranch, ref tempNextBasicBlock);

                                // add new basic block to branch targets
                                currentExitBranch.takenTarget.Add(tempNextBasicBlock);

                                counter++;
                            }

                            // start a new basic block directly after the switch instruction and end current execution
                            this.buildRecursivelyCfg(methodCfg, operations, idx + 1, currentExitBranch, ref currentExitBranch.notTakenTarget);

                            return;
                        }

                    // exception handler beginning or end (end of try block or catch block)
                    case OperationCode.Leave:
                    case OperationCode.Leave_S: {

                            // the current basic block ends here
                            currentBasicBlock.endIdx = idx;

                            // calculate the target index of the branch
                            int branchTargetIdx = 0;
                            uint branchTargetOffset = (uint)operation.Value;
                            while (true) {
                                if (operations.ElementAt(branchTargetIdx).Offset == branchTargetOffset) {
                                    break;
                                }
                                else if (operations.ElementAt(branchTargetIdx).Offset > branchTargetOffset) {
                                    throw new ArgumentException("Could not find target off branch.");
                                }
                                branchTargetIdx++;
                            }

                            // create new exit branch object
                            ExceptionBranchTarget currentExitBranch = new ExceptionBranchTarget();
                            currentExitBranch.sourceBasicBlock = currentBasicBlock;
                            currentExitBranch.exceptionTarget = new BasicBlock(this.semanticId);
                            this.semanticId++;
                            currentExitBranch.exitTarget = new BasicBlock(this.semanticId);
                            this.semanticId++;
                            currentBasicBlock.exitBranch = currentExitBranch;

                            // start two new basic blocks from this branch on and end current execution
                            this.buildRecursivelyCfg(methodCfg, operations, idx + 1, currentExitBranch, ref currentExitBranch.exceptionTarget);
                            this.buildRecursivelyCfg(methodCfg, operations, branchTargetIdx, currentExitBranch, ref currentExitBranch.exitTarget);
                            return;
                        }

                    // create a virtual basic block at the end of a catch/finally handler
                    case OperationCode.Rethrow:
                    case OperationCode.Endfinally: {

                            // the current basic block ends here
                            currentBasicBlock.endIdx = idx;

                            // create new exit branch object
                            NoBranchTarget currentExitBranch = new NoBranchTarget();
                            currentExitBranch.sourceBasicBlock = currentBasicBlock;
                            currentExitBranch.takenTarget = new BasicBlock(this.semanticId);
                            this.semanticId++;
                            currentBasicBlock.exitBranch = currentExitBranch;

                            // start a new basic block from this branch on and end current execution
                            this.buildRecursivelyCfg(methodCfg, operations, idx + 1, currentExitBranch, ref currentExitBranch.takenTarget);

                            return;
                        }


                    default:
                        break;
                }
            }
        }
        // insert the given new target basic block between the given no branch to manipulate
        public void insertBasicBlockBetweenBranch(NoBranchTarget branchToManipulate, BasicBlock newTarget, ConditionalBranchTarget exitBranch, bool useTakenBranch) {

            // get the basic block from that the branch is taken and the basic block to that the branch is taken
            BasicBlock introBasicBlock = branchToManipulate.sourceBasicBlock;
            BasicBlock outroBasicBlock = branchToManipulate.takenTarget;

            // check wether to use the taken or not taken part of the exit branch
            if (useTakenBranch) {
                this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulate.takenTarget, newTarget, newTarget, exitBranch, ref exitBranch.takenTarget);
            }
            else {
                this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulate.takenTarget, newTarget, newTarget, exitBranch, ref exitBranch.notTakenTarget);
            }
        }
        // this constructor copies the given source method cfg and all its elements
        // NOTE: it ignores the transformation metadata
        public MethodCfg(MethodCfg sourceMethodCfg) {

            // copy link to the method
            this.method = sourceMethodCfg.method;

            // generate a list of already processed basic blocks
            List<BasicBlock> processedBasicBlocks = new List<BasicBlock>();

            // set start basic block of the CFG as already processed
            processedBasicBlocks.Add(sourceMethodCfg.startBasicBlock);

            // create copy of start basic block
            BasicBlock copiedStartBasicBlock = new BasicBlock();
            this.startBasicBlock = copiedStartBasicBlock;
            this.basicBlocks.Add(copiedStartBasicBlock);

            // copy simple values
            copiedStartBasicBlock.id = sourceMethodCfg.startBasicBlock.id;
            copiedStartBasicBlock.semanticId = sourceMethodCfg.startBasicBlock.semanticId;
            copiedStartBasicBlock.startIdx = sourceMethodCfg.startBasicBlock.startIdx;
            copiedStartBasicBlock.endIdx = sourceMethodCfg.startBasicBlock.endIdx;

            // copy all operations of the basic block
            foreach (IOperation operation in sourceMethodCfg.startBasicBlock.operations) {
                InternalOperation copiedOperation = new InternalOperation();
                copiedOperation.OperationCode = operation.OperationCode;
                copiedOperation.Value = operation.Value;
                copiedOperation.Offset = operation.Offset;
                copiedOperation.Location = operation.Location;
                copiedStartBasicBlock.operations.Add(copiedOperation);
            }


            // process rest of the cfg and copy the exit branch
            if ((sourceMethodCfg.startBasicBlock.exitBranch as NoBranchTarget) != null) {
                NoBranchTarget exitBranch = (sourceMethodCfg.startBasicBlock.exitBranch as NoBranchTarget);

                // create a copied exit branch
                NoBranchTarget copiedExitBranch = new NoBranchTarget();
                copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock;
                copiedStartBasicBlock.exitBranch = copiedExitBranch;

                // process branch and next basic block
                BasicBlock nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget, ref nextCopiedBasicBlock, copiedExitBranch);

            }

            else if (sourceMethodCfg.startBasicBlock.exitBranch as UnconditionalBranchTarget != null) {
                UnconditionalBranchTarget exitBranch = (sourceMethodCfg.startBasicBlock.exitBranch as UnconditionalBranchTarget);

                // create a copied exit branch
                UnconditionalBranchTarget copiedExitBranch = new UnconditionalBranchTarget();
                copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock;
                copiedStartBasicBlock.exitBranch = copiedExitBranch;

                // process branch and next basic block
                BasicBlock nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget, ref nextCopiedBasicBlock, copiedExitBranch);

            }

            else if (sourceMethodCfg.startBasicBlock.exitBranch as ConditionalBranchTarget != null) {
                ConditionalBranchTarget exitBranch = (sourceMethodCfg.startBasicBlock.exitBranch as ConditionalBranchTarget);

                // create a copied exit branch
                ConditionalBranchTarget copiedExitBranch = new ConditionalBranchTarget();
                copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock;
                copiedStartBasicBlock.exitBranch = copiedExitBranch;

                // process branch and next basic block
                BasicBlock nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget, ref nextCopiedBasicBlock, copiedExitBranch, true);

                // process branch and next basic block
                nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.notTakenTarget, ref nextCopiedBasicBlock, copiedExitBranch, false);

            }

            else if (sourceMethodCfg.startBasicBlock.exitBranch as SwitchBranchTarget != null) {
                SwitchBranchTarget exitBranch = (sourceMethodCfg.startBasicBlock.exitBranch as SwitchBranchTarget);

                // create a copied exit branch
                SwitchBranchTarget copiedExitBranch = new SwitchBranchTarget();
                copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock;
                copiedStartBasicBlock.exitBranch = copiedExitBranch;

                // first process not taken branch and next basic block
                BasicBlock nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.notTakenTarget, ref nextCopiedBasicBlock, copiedExitBranch, -1);

                // process all taken branches and next basic blocks
                for (int idx = 0; idx < exitBranch.takenTarget.Count(); idx++) {
                    nextCopiedBasicBlock = null;
                    this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget.ElementAt(idx), ref nextCopiedBasicBlock, copiedExitBranch, idx);
                }

            }

            else if (sourceMethodCfg.startBasicBlock.exitBranch as ExitBranchTarget != null) {

                // create a copied exit branch
                ExitBranchTarget copiedExitBranch = new ExitBranchTarget();
                copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock;
                copiedStartBasicBlock.exitBranch = copiedExitBranch;

            }

            else if (sourceMethodCfg.startBasicBlock.exitBranch as ThrowBranchTarget != null) {

                // create a copied exit branch
                ThrowBranchTarget copiedExitBranch = new ThrowBranchTarget();
                copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock;
                copiedStartBasicBlock.exitBranch = copiedExitBranch;

            }

            else if (sourceMethodCfg.startBasicBlock.exitBranch as TryBlockTarget != null) {
                TryBlockTarget exitBranch = (sourceMethodCfg.startBasicBlock.exitBranch as TryBlockTarget);

                // create a copied exit branch
                TryBlockTarget copiedExitBranch = new TryBlockTarget();
                copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock;
                copiedStartBasicBlock.exitBranch = copiedExitBranch;

                // process branch and next basic block
                BasicBlock nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget, ref nextCopiedBasicBlock, copiedExitBranch);

            }

            else if (sourceMethodCfg.startBasicBlock.exitBranch as ExceptionBranchTarget != null) {
                ExceptionBranchTarget exitBranch = (sourceMethodCfg.startBasicBlock.exitBranch as ExceptionBranchTarget);

                // create a copied exit branch
                ExceptionBranchTarget copiedExitBranch = new ExceptionBranchTarget();
                copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock;
                copiedStartBasicBlock.exitBranch = copiedExitBranch;

                // process branch and next basic block
                BasicBlock nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.exceptionTarget, ref nextCopiedBasicBlock, copiedExitBranch, true);

                // process branch and next basic block
                nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.exitTarget, ref nextCopiedBasicBlock, copiedExitBranch, false);

            }

            else {
                throw new ArgumentException("Do not know how to handle exit branch.");
            }


            // copy all try blocks
            foreach (TryBlock sourceTryBlock in sourceMethodCfg.startBasicBlock.tryBlocks) {

                TryBlock copiedTryBlock = new TryBlock();
                copiedTryBlock.exceptionHandler = sourceTryBlock.exceptionHandler;
                copiedTryBlock.firstBasicBlockOfTryBlock = sourceTryBlock.firstBasicBlockOfTryBlock;
                copiedTryBlock.lastBasicBlockOfTryBlock = sourceTryBlock.lastBasicBlockOfTryBlock;

                copiedStartBasicBlock.tryBlocks.Add(copiedTryBlock);
            }


            // copy all handler blocks
            foreach (HandlerBlock sourceHandlerBlock in sourceMethodCfg.startBasicBlock.handlerBlocks) {

                HandlerBlock copiedHandlerBlock = new HandlerBlock();
                copiedHandlerBlock.exceptionHandler = sourceHandlerBlock.exceptionHandler;
                copiedHandlerBlock.typeOfHandler = sourceHandlerBlock.typeOfHandler;
                copiedHandlerBlock.firstBasicBlockOfHandlerBlock = sourceHandlerBlock.firstBasicBlockOfHandlerBlock;
                copiedHandlerBlock.lastBasicBlockOfHandlerBlock = sourceHandlerBlock.lastBasicBlockOfHandlerBlock;

                copiedStartBasicBlock.handlerBlocks.Add(copiedHandlerBlock);
            }

        }
        // copies recursively the next basic block of the method CFG (with a switch branch as entry branch)
        private void copyMethodCfgRecursively(List<BasicBlock> processedBasicBlocks, BasicBlock sourceBasicBlock, ref BasicBlock targetBasicBlock, SwitchBranchTarget copiedEntryBranch, int takenEntryBranchIdx) {

            // check if source basic block was already processed
            if (processedBasicBlocks.Contains(sourceBasicBlock)) {

                bool found = false;
                foreach (BasicBlock searchBasicBlock in this.basicBlocks) {
                    if (searchBasicBlock.id == sourceBasicBlock.id) {

                        // set entry branch target
                        if (takenEntryBranchIdx == -1) {
                            copiedEntryBranch.notTakenTarget = searchBasicBlock;

                        }
                        else {

                            // fill switch taken branch list with empty elements when index is out of range
                            while (copiedEntryBranch.takenTarget.Count() <= takenEntryBranchIdx) {
                                copiedEntryBranch.takenTarget.Add(null);
                            }

                            copiedEntryBranch.takenTarget[takenEntryBranchIdx] = searchBasicBlock;
                        }

                        searchBasicBlock.entryBranches.Add(copiedEntryBranch);
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    throw new ArgumentException("Copied basic block was not found.");
                }

                return;
            }

            // add source basic block to the list of already processed basic blocks
            processedBasicBlocks.Add(sourceBasicBlock);

            // create copy of the source basic block
            targetBasicBlock = new BasicBlock();
            this.basicBlocks.Add(targetBasicBlock);

            // set entry branch target
            if (takenEntryBranchIdx == -1) {
                copiedEntryBranch.notTakenTarget = targetBasicBlock;

            }
            else {

                // fill switch taken branch list with empty elements when index is out of range
                while (copiedEntryBranch.takenTarget.Count() <= takenEntryBranchIdx) {
                    copiedEntryBranch.takenTarget.Add(null);
                }

                copiedEntryBranch.takenTarget[takenEntryBranchIdx] = targetBasicBlock;
            }
            targetBasicBlock.entryBranches.Add(copiedEntryBranch);

            // copy simple values
            targetBasicBlock.id = sourceBasicBlock.id;
            targetBasicBlock.semanticId = sourceBasicBlock.semanticId;
            targetBasicBlock.startIdx = sourceBasicBlock.startIdx;
            targetBasicBlock.endIdx = sourceBasicBlock.endIdx;

            // copy all operations of the basic block
            foreach (IOperation operation in sourceBasicBlock.operations) {
                InternalOperation copiedOperation = new InternalOperation();
                copiedOperation.OperationCode = operation.OperationCode;
                copiedOperation.Value = operation.Value;
                copiedOperation.Offset = operation.Offset;
                copiedOperation.Location = operation.Location;
                targetBasicBlock.operations.Add(copiedOperation);
            }


            // process rest of the cfg and copy the exit branch
            if ((sourceBasicBlock.exitBranch as NoBranchTarget) != null) {
                NoBranchTarget exitBranch = (sourceBasicBlock.exitBranch as NoBranchTarget);

                // create a copied exit branch
                NoBranchTarget copiedExitBranch = new NoBranchTarget();
                copiedExitBranch.sourceBasicBlock = targetBasicBlock;
                targetBasicBlock.exitBranch = copiedExitBranch;

                // process branch and next basic block
                BasicBlock nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget, ref nextCopiedBasicBlock, copiedExitBranch);

            }

            else if (sourceBasicBlock.exitBranch as UnconditionalBranchTarget != null) {
                UnconditionalBranchTarget exitBranch = (sourceBasicBlock.exitBranch as UnconditionalBranchTarget);

                // create a copied exit branch
                UnconditionalBranchTarget copiedExitBranch = new UnconditionalBranchTarget();
                copiedExitBranch.sourceBasicBlock = targetBasicBlock;
                targetBasicBlock.exitBranch = copiedExitBranch;

                // process branch and next basic block
                BasicBlock nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget, ref nextCopiedBasicBlock, copiedExitBranch);

            }

            else if (sourceBasicBlock.exitBranch as ConditionalBranchTarget != null) {
                ConditionalBranchTarget exitBranch = (sourceBasicBlock.exitBranch as ConditionalBranchTarget);

                // create a copied exit branch
                ConditionalBranchTarget copiedExitBranch = new ConditionalBranchTarget();
                copiedExitBranch.sourceBasicBlock = targetBasicBlock;
                targetBasicBlock.exitBranch = copiedExitBranch;

                // process branch and next basic block
                BasicBlock nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget, ref nextCopiedBasicBlock, copiedExitBranch, true);

                // process branch and next basic block
                nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.notTakenTarget, ref nextCopiedBasicBlock, copiedExitBranch, false);

            }

            else if (sourceBasicBlock.exitBranch as SwitchBranchTarget != null) {
                SwitchBranchTarget exitBranch = (sourceBasicBlock.exitBranch as SwitchBranchTarget);

                // create a copied exit branch
                SwitchBranchTarget copiedExitBranch = new SwitchBranchTarget();
                copiedExitBranch.sourceBasicBlock = targetBasicBlock;
                targetBasicBlock.exitBranch = copiedExitBranch;

                // first process not taken branch and next basic block
                BasicBlock nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.notTakenTarget, ref nextCopiedBasicBlock, copiedExitBranch, -1);

                // process all taken branches and next basic blocks
                for (int idx = 0; idx < exitBranch.takenTarget.Count(); idx++) {
                    nextCopiedBasicBlock = null;
                    this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget.ElementAt(idx), ref nextCopiedBasicBlock, copiedExitBranch, idx);
                }

            }

            else if (sourceBasicBlock.exitBranch as ExitBranchTarget != null) {

                // create a copied exit branch
                ExitBranchTarget copiedExitBranch = new ExitBranchTarget();
                copiedExitBranch.sourceBasicBlock = targetBasicBlock;
                targetBasicBlock.exitBranch = copiedExitBranch;

            }

            else if (sourceBasicBlock.exitBranch as ThrowBranchTarget != null) {

                // create a copied exit branch
                ThrowBranchTarget copiedExitBranch = new ThrowBranchTarget();
                copiedExitBranch.sourceBasicBlock = targetBasicBlock;
                targetBasicBlock.exitBranch = copiedExitBranch;

            }

            else if (sourceBasicBlock.exitBranch as TryBlockTarget != null) {
                TryBlockTarget exitBranch = (sourceBasicBlock.exitBranch as TryBlockTarget);

                // create a copied exit branch
                TryBlockTarget copiedExitBranch = new TryBlockTarget();
                copiedExitBranch.sourceBasicBlock = targetBasicBlock;
                targetBasicBlock.exitBranch = copiedExitBranch;

                // process branch and next basic block
                BasicBlock nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget, ref nextCopiedBasicBlock, copiedExitBranch);

            }

            else if (sourceBasicBlock.exitBranch as ExceptionBranchTarget != null) {
                ExceptionBranchTarget exitBranch = (sourceBasicBlock.exitBranch as ExceptionBranchTarget);

                // create a copied exit branch
                ExceptionBranchTarget copiedExitBranch = new ExceptionBranchTarget();
                copiedExitBranch.sourceBasicBlock = targetBasicBlock;
                targetBasicBlock.exitBranch = copiedExitBranch;

                // process branch and next basic block
                BasicBlock nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.exceptionTarget, ref nextCopiedBasicBlock, copiedExitBranch, true);

                // process branch and next basic block
                nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.exitTarget, ref nextCopiedBasicBlock, copiedExitBranch, false);

            }

            else {
                throw new ArgumentException("Do not know how to handle exit branch.");
            }


            // copy all try blocks
            foreach (TryBlock sourceTryBlock in sourceBasicBlock.tryBlocks) {

                TryBlock copiedTryBlock = new TryBlock();
                copiedTryBlock.exceptionHandler = sourceTryBlock.exceptionHandler;
                copiedTryBlock.firstBasicBlockOfTryBlock = sourceTryBlock.firstBasicBlockOfTryBlock;
                copiedTryBlock.lastBasicBlockOfTryBlock = sourceTryBlock.lastBasicBlockOfTryBlock;

                targetBasicBlock.tryBlocks.Add(copiedTryBlock);
            }


            // copy all handler blocks
            foreach (HandlerBlock sourceHandlerBlock in sourceBasicBlock.handlerBlocks) {

                HandlerBlock copiedHandlerBlock = new HandlerBlock();
                copiedHandlerBlock.exceptionHandler = sourceHandlerBlock.exceptionHandler;
                copiedHandlerBlock.typeOfHandler = sourceHandlerBlock.typeOfHandler;
                copiedHandlerBlock.firstBasicBlockOfHandlerBlock = sourceHandlerBlock.firstBasicBlockOfHandlerBlock;
                copiedHandlerBlock.lastBasicBlockOfHandlerBlock = sourceHandlerBlock.lastBasicBlockOfHandlerBlock;

                targetBasicBlock.handlerBlocks.Add(copiedHandlerBlock);
            }

        }
Exemple #9
0
        void createNoBranch(BasicBlock deadCodeBasicBlock)
        {
            // Set the dead code block above some other block.
            var exitBranch = new NoBranchTarget();
            exitBranch.sourceBasicBlock = deadCodeBasicBlock;
            deadCodeBasicBlock.exitBranch = exitBranch;

            BasicBlock targetBlock = null;
            do {
                targetBlock = randomTargetBlock();

                // Skip blocks that already have a "no branch" as entry.
                foreach(var entryBranch in targetBlock.entryBranches) {
                    if(entryBranch is NoBranchTarget) {
                        targetBlock = null;
                        break;
                    }
                }
            } while(targetBlock == null);

            targetBlock.entryBranches.Add(exitBranch);
            exitBranch.takenTarget = targetBlock;
        }
        // this function creates all methods that are needed for the generated graph
        public void createGraphMethods() {

            this.logger.writeLine("Adding graph methods to \"" + this.targetClass.ToString() + "\"");

            // check if the graph is already initialized (needed to create the methods)
            if (this.graph == null) {
                throw new ArgumentException("Graph is not initialized.");
            }

            // if debugging is activated
            // => add field for the basic block trace file
            if (this.debugging
                || this.trace) {

                this.logger.writeLine("Debugging activated: Adding field for a basic block tracer file");

                // add trace writer field
                this.debuggingTraceWriter = new FieldDefinition();
                this.debuggingTraceWriter.IsCompileTimeConstant = false;
                this.debuggingTraceWriter.IsNotSerialized = false;
                this.debuggingTraceWriter.IsReadOnly = false;
                this.debuggingTraceWriter.IsRuntimeSpecial = false;
                this.debuggingTraceWriter.IsSpecialName = false;
                this.debuggingTraceWriter.Type = this.helperClass.systemIOStreamWriter;
                this.debuggingTraceWriter.IsStatic = false;
                this.debuggingTraceWriter.Name = host.NameTable.GetNameFor("DEBUG_traceWriter");
                this.debuggingTraceWriter.Visibility = TypeMemberVisibility.Public;
                this.debuggingTraceWriter.InternFactory = host.InternFactory;
                this.debuggingTraceWriter.ContainingTypeDefinition = this.targetClass;
                this.targetClass.Fields.Add(this.debuggingTraceWriter);

            }

            // create a method that can be called to generate the graph
            this.buildGraphMethod = this.helperClass.createNewMethod("buildGraph", this.targetClass, host.PlatformType.SystemVoid, TypeMemberVisibility.Public, null, CallingConvention.HasThis, false, false, true); // TODO RENAME

            ILGenerator ilGenerator = new ILGenerator(host, this.buildGraphMethod);

            // check if graph was already build
            // => if it was jump to exit
            ILGeneratorLabel buildGraphExitLabel = new ILGeneratorLabel();
            ilGenerator.Emit(OperationCode.Ldarg_0);
            ilGenerator.Emit(OperationCode.Callvirt, this.interfaceStartPointerGet);
            ilGenerator.Emit(OperationCode.Ldnull);
            ilGenerator.Emit(OperationCode.Ceq);
            ilGenerator.Emit(OperationCode.Brfalse, buildGraphExitLabel);
            
            // set initial node (root of the tree)
            ilGenerator.Emit(OperationCode.Ldarg_0);
            ilGenerator.Emit(OperationCode.Ldarg_0); // needed as argument for the constructor
            ilGenerator.Emit(OperationCode.Newobj, this.graph.startingNode.constructorToUse);
            ilGenerator.Emit(OperationCode.Callvirt, this.interfaceStartPointerSet);

            // build rest of graph in a "pseudo recursive" manner
            MethodDefinition newMethodToCall = this.addNodeRecursively(this.graph.startingNode, 1, "addNode_0"); // TODO: method name
            ilGenerator.Emit(OperationCode.Ldarg_0);
            ilGenerator.Emit(OperationCode.Ldarg_0);
            ilGenerator.Emit(OperationCode.Callvirt, this.interfaceStartPointerGet);
            ilGenerator.Emit(OperationCode.Ldc_I4_1);
            ilGenerator.Emit(OperationCode.Callvirt, newMethodToCall);

            // exit
            ilGenerator.MarkLabel(buildGraphExitLabel);
            ilGenerator.Emit(OperationCode.Ret);

            // create body
            IMethodBody body = new ILGeneratorMethodBody(ilGenerator, true, 8, this.buildGraphMethod, Enumerable<ILocalDefinition>.Empty, Enumerable<ITypeDefinition>.Empty);
            this.buildGraphMethod.Body = body;

            // create exchangeNodes method
            List<IParameterDefinition> parameters = new List<IParameterDefinition>();
            // node type parameter
            ParameterDefinition parameter = new ParameterDefinition();
            parameter.IsIn = false;
            parameter.IsOptional = false;
            parameter.IsOut = false;
            parameter.Type = this.nodeInterface;
            parameters.Add(parameter);
            // int array parameter for path to node one
            VectorTypeReference intArrayType = new VectorTypeReference();
            intArrayType.ElementType = this.host.PlatformType.SystemInt32;
            intArrayType.Rank = 1;
            intArrayType.IsFrozen = true;
            intArrayType.IsValueType = false;
            intArrayType.InternFactory = host.InternFactory;
            parameter = new ParameterDefinition();
            parameter.IsIn = false;
            parameter.IsOptional = false;
            parameter.IsOut = false;
            parameter.Type = intArrayType;
            parameters.Add(parameter);
            // int array parameter for path to node two
            parameter = new ParameterDefinition();
            parameter.IsIn = false;
            parameter.IsOptional = false;
            parameter.IsOut = false;
            parameter.Type = intArrayType;
            parameters.Add(parameter);

            this.exchangeNodesMethod = this.helperClass.createNewMethod("exchangeNodes", this.targetClass, host.PlatformType.SystemVoid, TypeMemberVisibility.Public, parameters, CallingConvention.HasThis, false, false, true); // TODO RENAME

            ilGenerator = new ILGenerator(host, this.exchangeNodesMethod);
            List<ILocalDefinition> localVariables = new List<ILocalDefinition>();

            // create local integer variable needed for the loops
            LocalDefinition loopIntLocal = new LocalDefinition();
            loopIntLocal.IsReference = false;
            loopIntLocal.IsPinned = false;
            loopIntLocal.IsModified = false;
            loopIntLocal.Type = this.host.PlatformType.SystemInt32;
            loopIntLocal.MethodDefinition = this.exchangeNodesMethod;
            localVariables.Add(loopIntLocal);

            // create local iNode variable needed for nodeOne
            LocalDefinition nodeOneLocal = new LocalDefinition();
            nodeOneLocal.IsReference = false;
            nodeOneLocal.IsPinned = false;
            nodeOneLocal.IsModified = false;
            nodeOneLocal.Type = this.nodeInterface;
            nodeOneLocal.MethodDefinition = this.exchangeNodesMethod;
            localVariables.Add(nodeOneLocal);

            // create local iNode variable needed for prevNodeOne
            LocalDefinition prevNodeOneLocal = new LocalDefinition();
            prevNodeOneLocal.IsReference = false;
            prevNodeOneLocal.IsPinned = false;
            prevNodeOneLocal.IsModified = false;
            prevNodeOneLocal.Type = this.nodeInterface;
            prevNodeOneLocal.MethodDefinition = this.exchangeNodesMethod;
            localVariables.Add(prevNodeOneLocal);

            // create local integer variable needed for prevNodeOneIdx
            LocalDefinition prevNodeOneIdxLocal = new LocalDefinition();
            prevNodeOneIdxLocal.IsReference = false;
            prevNodeOneIdxLocal.IsPinned = false;
            prevNodeOneIdxLocal.IsModified = false;
            prevNodeOneIdxLocal.Type = this.host.PlatformType.SystemInt32;
            prevNodeOneIdxLocal.MethodDefinition = this.exchangeNodesMethod;
            localVariables.Add(prevNodeOneIdxLocal);

            // create local iNode variable needed for nodeTwo
            LocalDefinition nodeTwoLocal = new LocalDefinition();
            nodeTwoLocal.IsReference = false;
            nodeTwoLocal.IsPinned = false;
            nodeTwoLocal.IsModified = false;
            nodeTwoLocal.Type = this.nodeInterface;
            nodeTwoLocal.MethodDefinition = this.exchangeNodesMethod;
            localVariables.Add(nodeTwoLocal);

            // create local iNode variable needed for prevNodeOne
            LocalDefinition prevNodeTwoLocal = new LocalDefinition();
            prevNodeTwoLocal.IsReference = false;
            prevNodeTwoLocal.IsPinned = false;
            prevNodeTwoLocal.IsModified = false;
            prevNodeTwoLocal.Type = this.nodeInterface;
            prevNodeTwoLocal.MethodDefinition = this.exchangeNodesMethod;
            localVariables.Add(prevNodeTwoLocal);

            // create local integer variable needed for prevNodeOneIdx
            LocalDefinition prevNodeTwoIdxLocal = new LocalDefinition();
            prevNodeTwoIdxLocal.IsReference = false;
            prevNodeTwoIdxLocal.IsPinned = false;
            prevNodeTwoIdxLocal.IsModified = false;
            prevNodeTwoIdxLocal.Type = this.host.PlatformType.SystemInt32;
            prevNodeTwoIdxLocal.MethodDefinition = this.exchangeNodesMethod;
            localVariables.Add(prevNodeTwoIdxLocal);

            // create local iNode variable needed for temp
            LocalDefinition tempNodeLocal = new LocalDefinition();
            tempNodeLocal.IsReference = false;
            tempNodeLocal.IsPinned = false;
            tempNodeLocal.IsModified = false;
            tempNodeLocal.Type = this.nodeInterface;
            tempNodeLocal.MethodDefinition = this.exchangeNodesMethod;
            localVariables.Add(tempNodeLocal);

            // initialize local variables
            /*
            iNode nodeOne = givenStartingNode;
            iNode prevNodeOne = null;
            int prevNodeOneIdx = 0;
            */
            ilGenerator.Emit(OperationCode.Ldarg_1);
            ilGenerator.Emit(OperationCode.Stloc, nodeOneLocal);
            ilGenerator.Emit(OperationCode.Ldnull);
            ilGenerator.Emit(OperationCode.Stloc, prevNodeOneLocal);
            ilGenerator.Emit(OperationCode.Ldc_I4_0);
            ilGenerator.Emit(OperationCode.Stloc, prevNodeOneIdxLocal);

            // initialize loop
            ilGenerator.Emit(OperationCode.Ldc_I4_0);
            ilGenerator.Emit(OperationCode.Stloc, loopIntLocal);
            ILGeneratorLabel loopConditionAndIncBranch = new ILGeneratorLabel();
            ILGeneratorLabel loopConditionBranch = new ILGeneratorLabel();
            ILGeneratorLabel loopStartBranch = new ILGeneratorLabel();
            ilGenerator.Emit(OperationCode.Br, loopConditionBranch);

            // start of the code in the loop
            /*
            if (nodeOne.getNode(pathToNodeOne[i]) != null) {
            */
            ilGenerator.MarkLabel(loopStartBranch);
            ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal);
            ilGenerator.Emit(OperationCode.Ldarg_2);
            ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal);
            ilGenerator.Emit(OperationCode.Ldelem_I4);
            ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet);
            ilGenerator.Emit(OperationCode.Ldnull);
            ilGenerator.Emit(OperationCode.Ceq);
            ilGenerator.Emit(OperationCode.Brtrue, loopConditionAndIncBranch);

            // get the node of the graph that should be exchanged (nodeOne)
            /*
            prevNodeOne = nodeOne;
            prevNodeOneIdx = pathToNodeOne[i];
            nodeOne = nodeOne.getNode(pathToNodeOne[i]);
            */
            ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal);
            ilGenerator.Emit(OperationCode.Stloc, prevNodeOneLocal);
            ilGenerator.Emit(OperationCode.Ldarg_2);
            ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal);
            ilGenerator.Emit(OperationCode.Ldelem_I4);
            ilGenerator.Emit(OperationCode.Stloc, prevNodeOneIdxLocal);
            ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal);
            ilGenerator.Emit(OperationCode.Ldloc, prevNodeOneIdxLocal);
            ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet);
            ilGenerator.Emit(OperationCode.Stloc, nodeOneLocal);

            // increment counter of loop
            ilGenerator.MarkLabel(loopConditionAndIncBranch);
            ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal);
            ilGenerator.Emit(OperationCode.Ldc_I4_1);
            ilGenerator.Emit(OperationCode.Add);
            ilGenerator.Emit(OperationCode.Stloc, loopIntLocal);

            // loop condition
            /*
            for (int i = 0; i < pathToNodeOne.Length; i++) {
            */
            ilGenerator.MarkLabel(loopConditionBranch);
            ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal);
            ilGenerator.Emit(OperationCode.Ldarg_2);
            ilGenerator.Emit(OperationCode.Ldlen);
            ilGenerator.Emit(OperationCode.Conv_I4);
            ilGenerator.Emit(OperationCode.Clt);
            ilGenerator.Emit(OperationCode.Brtrue, loopStartBranch);

            // initialize local variables
            /*
            iNode nodeTwo = givenStartingNode;
            iNode prevNodeTwo = null;
            int prevNodeTwoIdx = 0;
            */
            ilGenerator.Emit(OperationCode.Ldarg_1);
            ilGenerator.Emit(OperationCode.Stloc, nodeTwoLocal);
            ilGenerator.Emit(OperationCode.Ldnull);
            ilGenerator.Emit(OperationCode.Stloc, prevNodeTwoLocal);
            ilGenerator.Emit(OperationCode.Ldc_I4_0);
            ilGenerator.Emit(OperationCode.Stloc, prevNodeTwoIdxLocal);

            // initialize loop
            ilGenerator.Emit(OperationCode.Ldc_I4_0);
            ilGenerator.Emit(OperationCode.Stloc, loopIntLocal);
            loopConditionAndIncBranch = new ILGeneratorLabel();
            loopConditionBranch = new ILGeneratorLabel();
            loopStartBranch = new ILGeneratorLabel();
            ilGenerator.Emit(OperationCode.Br, loopConditionBranch);

            // start of the code in the loop
            /*
            if (nodeTwo.getNode(pathToNodeTwo[i]) != null) {
            */
            ilGenerator.MarkLabel(loopStartBranch);
            ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal);
            ilGenerator.Emit(OperationCode.Ldarg_3);
            ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal);
            ilGenerator.Emit(OperationCode.Ldelem_I4);
            ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet);
            ilGenerator.Emit(OperationCode.Ldnull);
            ilGenerator.Emit(OperationCode.Ceq);
            ilGenerator.Emit(OperationCode.Brtrue, loopConditionAndIncBranch);

            // get the node of the graph that should be exchanged (nodeTwo)
            /*
            prevNodeTwo = nodeTwo;
            prevNodeTwoIdx = pathToNodeTwo[i];
            nodeTwo = nodeTwo.getNode(pathToNodeTwo[i]);
            */
            ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal);
            ilGenerator.Emit(OperationCode.Stloc, prevNodeTwoLocal);
            ilGenerator.Emit(OperationCode.Ldarg_2);
            ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal);
            ilGenerator.Emit(OperationCode.Ldelem_I4);
            ilGenerator.Emit(OperationCode.Stloc, prevNodeTwoIdxLocal);
            ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal);
            ilGenerator.Emit(OperationCode.Ldloc, prevNodeTwoIdxLocal);
            ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet);
            ilGenerator.Emit(OperationCode.Stloc, nodeTwoLocal);

            // increment counter of loop
            ilGenerator.MarkLabel(loopConditionAndIncBranch);
            ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal);
            ilGenerator.Emit(OperationCode.Ldc_I4_1);
            ilGenerator.Emit(OperationCode.Add);
            ilGenerator.Emit(OperationCode.Stloc, loopIntLocal);

            // loop condition
            /*
            for (int i = 0; i < pathToNodeTwo.Length; i++) {
            */
            ilGenerator.MarkLabel(loopConditionBranch);
            ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal);
            ilGenerator.Emit(OperationCode.Ldarg_3);
            ilGenerator.Emit(OperationCode.Ldlen);
            ilGenerator.Emit(OperationCode.Conv_I4);
            ilGenerator.Emit(OperationCode.Clt);
            ilGenerator.Emit(OperationCode.Brtrue, loopStartBranch);

            // initialize loop
            ilGenerator.Emit(OperationCode.Ldc_I4_0);
            ilGenerator.Emit(OperationCode.Stloc, loopIntLocal);
            loopConditionAndIncBranch = new ILGeneratorLabel();
            loopConditionBranch = new ILGeneratorLabel();
            loopStartBranch = new ILGeneratorLabel();
            ilGenerator.Emit(OperationCode.Br, loopConditionBranch);

            // start of the code in the loop
            ilGenerator.MarkLabel(loopStartBranch);

            /*
            if (nodeOne.getNode(i) == nodeTwo) {
            */
            ILGeneratorLabel conditionBranch = new ILGeneratorLabel();
            ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal);
            ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal);
            ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet);
            ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal);
            ilGenerator.Emit(OperationCode.Ceq);
            ilGenerator.Emit(OperationCode.Brfalse, conditionBranch);

            /*
            nodeOne.setNode(nodeTwo.getNode(i), i);
            */
            ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal);
            ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal);
            ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal);
            ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet);
            ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal);
            ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesSet);

            /*
            nodeTwo.setNode(nodeOne, i);
            */
            ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal);
            ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal);
            ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal);
            ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesSet);
            ilGenerator.Emit(OperationCode.Br, loopConditionAndIncBranch);

            /*
            else if (nodeTwo.getNode(i) == nodeOne) {
            */
            ilGenerator.MarkLabel(conditionBranch);
            ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal);
            ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal);
            ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet);
            ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal);
            ilGenerator.Emit(OperationCode.Ceq);
            conditionBranch = new ILGeneratorLabel();
            ilGenerator.Emit(OperationCode.Brfalse, conditionBranch);

            /*
            nodeTwo.setNode(nodeOne.getNode(i), i);
            */
            ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal);
            ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal);
            ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal);
            ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet);
            ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal);
            ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesSet);

            /*
            nodeOne.setNode(nodeTwo, i);
            */
            ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal);
            ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal);
            ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal);
            ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesSet);
            ilGenerator.Emit(OperationCode.Br, loopConditionAndIncBranch);

            /*
            else {
            */
            ilGenerator.MarkLabel(conditionBranch);

            /*
            temp = nodeOne.getNode(i);
            */
            ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal);
            ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal);
            ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet);
            ilGenerator.Emit(OperationCode.Stloc, tempNodeLocal);

            /*
            nodeOne.setNode(nodeTwo.getNode(i), i);
            */
            ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal);
            ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal);
            ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal);
            ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet);
            ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal);
            ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesSet);

            /*
            nodeTwo.setNode(temp, i);
            */
            ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal);
            ilGenerator.Emit(OperationCode.Ldloc, tempNodeLocal);
            ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal);
            ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesSet);

            // increment counter of loop
            ilGenerator.MarkLabel(loopConditionAndIncBranch);
            ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal);
            ilGenerator.Emit(OperationCode.Ldc_I4_1);
            ilGenerator.Emit(OperationCode.Add);
            ilGenerator.Emit(OperationCode.Stloc, loopIntLocal);

            // loop condition
            /*
            for (int i = 0; i < GRAPH_DIMENSION; i++) {
            */
            ilGenerator.MarkLabel(loopConditionBranch);
            ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal);
            ilGenerator.Emit(OperationCode.Ldc_I4, this.graphDimension);
            ilGenerator.Emit(OperationCode.Clt);
            ilGenerator.Emit(OperationCode.Brtrue, loopStartBranch);

            /*
            if (prevNodeOne != null) {
            */
            conditionBranch = new ILGeneratorLabel();
            ilGenerator.Emit(OperationCode.Ldloc, prevNodeOneLocal);
            ilGenerator.Emit(OperationCode.Ldnull);
            ilGenerator.Emit(OperationCode.Ceq);
            ilGenerator.Emit(OperationCode.Brtrue, conditionBranch);

            /*
            if (prevNodeOne != nodeTwo) {
            */
            ILGeneratorLabel exitConditionBranch = new ILGeneratorLabel();
            ilGenerator.Emit(OperationCode.Ldloc, prevNodeOneLocal);
            ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal);
            ilGenerator.Emit(OperationCode.Ceq);
            ilGenerator.Emit(OperationCode.Brtrue, exitConditionBranch);

            /*
            prevNodeOne.setNode(nodeTwo, prevNodeOneIdx);
            */
            ilGenerator.Emit(OperationCode.Ldloc, prevNodeOneLocal);
            ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal);
            ilGenerator.Emit(OperationCode.Ldloc, prevNodeOneIdxLocal);
            ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesSet);
            ilGenerator.Emit(OperationCode.Br, exitConditionBranch);

            /*
            else {
            */
            ilGenerator.MarkLabel(conditionBranch);

            /*
            this.graphStartNode = nodeTwo;
            */
            ilGenerator.Emit(OperationCode.Ldarg_0);
            ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal);
            ilGenerator.Emit(OperationCode.Callvirt, this.interfaceStartPointerSet);

            ilGenerator.MarkLabel(exitConditionBranch);

            /*
            if (prevNodeTwo != null) {
            */
            conditionBranch = new ILGeneratorLabel();
            ilGenerator.Emit(OperationCode.Ldloc, prevNodeTwoLocal);
            ilGenerator.Emit(OperationCode.Ldnull);
            ilGenerator.Emit(OperationCode.Ceq);
            ilGenerator.Emit(OperationCode.Brtrue, conditionBranch);

            /*
            if (prevNodeTwo != nodeOne) {
            */
            exitConditionBranch = new ILGeneratorLabel();
            ilGenerator.Emit(OperationCode.Ldloc, prevNodeTwoLocal);
            ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal);
            ilGenerator.Emit(OperationCode.Ceq);
            ilGenerator.Emit(OperationCode.Brtrue, exitConditionBranch);

            /*
            prevNodeTwo.setNode(nodeOne, prevNodeTwoIdx);
            */
            ilGenerator.Emit(OperationCode.Ldloc, prevNodeTwoLocal);
            ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal);
            ilGenerator.Emit(OperationCode.Ldloc, prevNodeTwoIdxLocal);
            ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesSet);
            ilGenerator.Emit(OperationCode.Br, exitConditionBranch);

            /*
            else {
            */
            ilGenerator.MarkLabel(conditionBranch);

            /*
            this.graphStartNode = nodeOne;
            */
            ilGenerator.Emit(OperationCode.Ldarg_0);
            ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal);
            ilGenerator.Emit(OperationCode.Callvirt, this.interfaceStartPointerSet);

            ilGenerator.MarkLabel(exitConditionBranch);
            ilGenerator.Emit(OperationCode.Ret);

            // create body
            body = new ILGeneratorMethodBody(ilGenerator, true, 8, this.exchangeNodesMethod, localVariables, Enumerable<ITypeDefinition>.Empty);
            this.exchangeNodesMethod.Body = body;

            // check if debugging is activated
            // => add function to dump graph as .dot file
            if (this.debugging) {

                this.logger.writeLine("Debugging activated: Adding code to dump graph as .dot file");

                // create dumpGraph method
                parameters = new List<IParameterDefinition>();
                // string parameter
                parameter = new ParameterDefinition();
                parameter.IsIn = false;
                parameter.IsOptional = false;
                parameter.IsOut = false;
                parameter.Type = this.host.PlatformType.SystemString;
                parameter.Index = 0;
                parameters.Add(parameter);
                // node type parameter (current pointer of debug method)
                parameter = new ParameterDefinition();
                parameter.IsIn = false;
                parameter.IsOptional = false;
                parameter.IsOut = false;
                parameter.Type = this.nodeInterface;
                parameter.Index = 1;
                parameters.Add(parameter);
                // node type parameter (current pointer of caller)
                parameter = new ParameterDefinition();
                parameter.IsIn = false;
                parameter.IsOptional = false;
                parameter.IsOut = false;
                parameter.Type = this.nodeInterface;
                parameter.Index = 2;
                parameters.Add(parameter);

                this.debuggingDumpGraphMethod = this.helperClass.createNewMethod("DEBUG_dumpGraph", this.targetClass, host.PlatformType.SystemVoid, TypeMemberVisibility.Public, parameters, CallingConvention.HasThis, false, false, true);

                // create dumpGraphRec method
                parameters = new List<IParameterDefinition>();
                // stream writer parameter
                parameter = new ParameterDefinition();
                parameter.IsIn = false;
                parameter.IsOptional = false;
                parameter.IsOut = false;
                parameter.Type = this.helperClass.systemIOStreamWriter;
                parameter.Index = 0;
                parameters.Add(parameter);
                // string parameter
                parameter = new ParameterDefinition();
                parameter.IsIn = false;
                parameter.IsOptional = false;
                parameter.IsOut = false;
                parameter.Type = this.host.PlatformType.SystemString;
                parameter.Index = 1;
                parameters.Add(parameter);
                // node type parameter (current pointer of debug method)
                parameter = new ParameterDefinition();
                parameter.IsIn = false;
                parameter.IsOptional = false;
                parameter.IsOut = false;
                parameter.Type = this.nodeInterface;
                parameter.Index = 2;
                parameters.Add(parameter);
                // node type parameter (current pointer of caller)
                ParameterDefinition currentNodeCallerParameter = new ParameterDefinition();
                currentNodeCallerParameter.IsIn = false;
                currentNodeCallerParameter.IsOptional = false;
                currentNodeCallerParameter.IsOut = false;
                currentNodeCallerParameter.Type = this.nodeInterface;
                currentNodeCallerParameter.Index = 3;
                parameters.Add(currentNodeCallerParameter);

                MethodDefinition dumpGraphRecMethod = this.helperClass.createNewMethod("DEBUG_dumpGraphRec", this.targetClass, host.PlatformType.SystemVoid, TypeMemberVisibility.Public, parameters, CallingConvention.HasThis, false, false, true);
                currentNodeCallerParameter.ContainingSignature = dumpGraphRecMethod; // is needed when parameter is accessed via Ldarg

                // create body for dumpGraph method
                ilGenerator = new ILGenerator(host, this.debuggingDumpGraphMethod);
                localVariables = new List<ILocalDefinition>();

                // create local string variable needed for debugging code
                LocalDefinition nodeNameLocal = new LocalDefinition();
                nodeNameLocal.IsReference = false;
                nodeNameLocal.IsPinned = false;
                nodeNameLocal.IsModified = false;
                nodeNameLocal.Type = this.host.PlatformType.SystemString;
                nodeNameLocal.MethodDefinition = this.debuggingDumpGraphMethod;
                localVariables.Add(nodeNameLocal);

                // create local stream writer variable needed for debugging code
                LocalDefinition streamWriterLocal = new LocalDefinition();
                streamWriterLocal.IsReference = false;
                streamWriterLocal.IsPinned = false;
                streamWriterLocal.IsModified = false;
                streamWriterLocal.Type = this.helperClass.systemIOStreamWriter;
                streamWriterLocal.MethodDefinition = this.debuggingDumpGraphMethod;
                localVariables.Add(streamWriterLocal);

                // create local integer variable for the for loop needed for debugging code
                LocalDefinition forIntegerLocal = new LocalDefinition();
                forIntegerLocal.IsReference = false;
                forIntegerLocal.IsPinned = false;
                forIntegerLocal.IsModified = false;
                forIntegerLocal.Type = this.host.PlatformType.SystemInt32;
                forIntegerLocal.MethodDefinition = this.debuggingDumpGraphMethod;
                localVariables.Add(forIntegerLocal);

                // generate dump file location string
                ilGenerator.Emit(OperationCode.Ldstr, this.debuggingDumpLocation + this.debuggingDumpFilePrefix);
                ilGenerator.Emit(OperationCode.Ldarg_1);
                ilGenerator.Emit(OperationCode.Ldstr, ".dot");
                ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatThree);

                // initialize io stream writer
                ilGenerator.Emit(OperationCode.Newobj, this.helperClass.streamWriterCtor);
                ilGenerator.Emit(OperationCode.Stloc, streamWriterLocal);

                // initialize .dot file
                ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal);
                ilGenerator.Emit(OperationCode.Ldstr, "digraph G {");
                ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine);

                // check if the node to dump is the same as the current node of the class
                // if it is => color the current dumped node
                ilGenerator.Emit(OperationCode.Ldarg_3);
                ilGenerator.Emit(OperationCode.Ldarg_2);
                ilGenerator.Emit(OperationCode.Ceq);
                ILGeneratorLabel currentNodeEqualDumpedNodeBranch = new ILGeneratorLabel();
                ilGenerator.Emit(OperationCode.Brtrue, currentNodeEqualDumpedNodeBranch);

                // case: current dumped node is not the current node of the class
                // create name for the nodes
                ilGenerator.Emit(OperationCode.Ldstr, "node_0");
                ilGenerator.Emit(OperationCode.Stloc, nodeNameLocal);

                // write current node to .dot file
                ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal);
                ilGenerator.Emit(OperationCode.Ldloc, nodeNameLocal);
                ilGenerator.Emit(OperationCode.Ldstr, " [shape=record]");
                ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatTwo);
                ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine);

                // jump to the end of this case
                ILGeneratorLabel currentNodeDumpedBranch = new ILGeneratorLabel();
                ilGenerator.Emit(OperationCode.Br, currentNodeDumpedBranch);

                // case: current dumped node is the current node of the class
                ilGenerator.MarkLabel(currentNodeEqualDumpedNodeBranch);

                // create name for the nodes
                ilGenerator.Emit(OperationCode.Ldstr, "node_0");
                ilGenerator.Emit(OperationCode.Stloc, nodeNameLocal);

                // write current node to .dot file
                ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal);
                ilGenerator.Emit(OperationCode.Ldloc, nodeNameLocal);
                ilGenerator.Emit(OperationCode.Ldstr, " [shape=record, color=blue]");
                ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatTwo);
                ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine);

                // end of the case
                ilGenerator.MarkLabel(currentNodeDumpedBranch);

                // write start of label of the current node to .dot file
                ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal);
                ilGenerator.Emit(OperationCode.Ldloc, nodeNameLocal);
                ilGenerator.Emit(OperationCode.Ldstr, " [label=\"{");
                ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatTwo);
                ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWrite);

                // write current node name to .dot file
                ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal);
                ilGenerator.Emit(OperationCode.Ldstr, "Node: ");
                ilGenerator.Emit(OperationCode.Ldloc, nodeNameLocal);
                ilGenerator.Emit(OperationCode.Ldstr, "|");
                ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatThree);
                ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWrite);

                // write current node id to .dot file
                ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal);
                ilGenerator.Emit(OperationCode.Ldstr, "Id: ");
                ilGenerator.Emit(OperationCode.Ldarg_2);
                ilGenerator.Emit(OperationCode.Callvirt, this.debuggingInterfaceIdGet);
                ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatTwo);
                ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWrite);

                // write end of label of the current node to .dot file
                ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal);
                ilGenerator.Emit(OperationCode.Ldstr, "}\"]");
                ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine);

                // initialize counter of for loop
                ilGenerator.Emit(OperationCode.Ldc_I4_0);
                ilGenerator.Emit(OperationCode.Stloc, forIntegerLocal);

                // jump to loop condition
                loopConditionBranch = new ILGeneratorLabel();
                loopStartBranch = new ILGeneratorLabel();
                ilGenerator.Emit(OperationCode.Br, loopConditionBranch);

                // start of loop
                ilGenerator.MarkLabel(loopStartBranch);

                // check if childNodes[i] == startNode
                ilGenerator.Emit(OperationCode.Ldarg_2);
                ilGenerator.Emit(OperationCode.Ldloc, forIntegerLocal);
                ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet);
                ilGenerator.Emit(OperationCode.Ldarg_0);
                ilGenerator.Emit(OperationCode.Callvirt, this.interfaceStartPointerGet);
                ilGenerator.Emit(OperationCode.Ceq);
                loopConditionAndIncBranch = new ILGeneratorLabel();
                ilGenerator.Emit(OperationCode.Brtrue, loopConditionAndIncBranch);

                // write connection of current node to next node to .dot file
                ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal);

                // generate first part of the string
                ilGenerator.Emit(OperationCode.Ldloc, nodeNameLocal);
                ilGenerator.Emit(OperationCode.Ldstr, " -> ");
                ilGenerator.Emit(OperationCode.Ldloc, nodeNameLocal);
                ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatThree);

                // generate second part of string and concat to first part
                ilGenerator.Emit(OperationCode.Ldstr, "_");
                ilGenerator.Emit(OperationCode.Ldloca, forIntegerLocal);
                ilGenerator.Emit(OperationCode.Call, this.helperClass.int32ToString);
                ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatThree);

                // write to .dot file
                ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine);

                // call method that dumps graph recursively ( this.dumpGraphRec(streamWriter, String name, nextNode) )
                ilGenerator.Emit(OperationCode.Ldarg_0);

                // push stream writer parameter
                ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal);

                // push string parameter
                ilGenerator.Emit(OperationCode.Ldloc, nodeNameLocal);
                ilGenerator.Emit(OperationCode.Ldstr, "_");
                ilGenerator.Emit(OperationCode.Ldloca, forIntegerLocal);
                ilGenerator.Emit(OperationCode.Call, this.helperClass.int32ToString);
                ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatThree);

                // push node parameter (current pointer of debug method)
                ilGenerator.Emit(OperationCode.Ldarg_2);
                ilGenerator.Emit(OperationCode.Ldloc, forIntegerLocal);
                ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet);

                // push node parameter (current pointer of the caller)
                ilGenerator.Emit(OperationCode.Ldarg_3);

                ilGenerator.Emit(OperationCode.Callvirt, dumpGraphRecMethod);

                // increment loop counter
                ilGenerator.MarkLabel(loopConditionAndIncBranch);
                ilGenerator.Emit(OperationCode.Ldloc, forIntegerLocal);
                ilGenerator.Emit(OperationCode.Ldc_I4_1);
                ilGenerator.Emit(OperationCode.Add);
                ilGenerator.Emit(OperationCode.Stloc, forIntegerLocal);

                // loop condition
                ilGenerator.MarkLabel(loopConditionBranch);
                ilGenerator.Emit(OperationCode.Ldloc, forIntegerLocal);
                ilGenerator.Emit(OperationCode.Ldc_I4, this.graphDimension);
                ilGenerator.Emit(OperationCode.Clt);
                ilGenerator.Emit(OperationCode.Brtrue, loopStartBranch);

                // end .dot file
                ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal);
                ilGenerator.Emit(OperationCode.Ldstr, "}");
                ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine);

                // close io stream writer                
                ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal);
                ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterClose);

                ilGenerator.Emit(OperationCode.Ret);

                // create body
                body = new ILGeneratorMethodBody(ilGenerator, true, 8, this.debuggingDumpGraphMethod, localVariables, Enumerable<ITypeDefinition>.Empty);
                this.debuggingDumpGraphMethod.Body = body;

                // create body for dumpGraphRec method
                localVariables = new List<ILocalDefinition>();
                ilGenerator = new ILGenerator(host, dumpGraphRecMethod);

                // create local integer variable for the for loop needed for debugging code
                forIntegerLocal = new LocalDefinition();
                forIntegerLocal.IsReference = false;
                forIntegerLocal.IsPinned = false;
                forIntegerLocal.IsModified = false;
                forIntegerLocal.Type = this.host.PlatformType.SystemInt32;
                forIntegerLocal.MethodDefinition = dumpGraphRecMethod;
                localVariables.Add(forIntegerLocal);

                // check if the node to dump is the same as the current node of the class
                // if it is => color the current dumped node
                ilGenerator.Emit(OperationCode.Ldarg, currentNodeCallerParameter);
                ilGenerator.Emit(OperationCode.Ldarg_3);
                ilGenerator.Emit(OperationCode.Ceq);
                currentNodeEqualDumpedNodeBranch = new ILGeneratorLabel();
                ilGenerator.Emit(OperationCode.Brtrue, currentNodeEqualDumpedNodeBranch);

                // case: current dumped node is not the current node of the class
                // write current node to .dot file
                ilGenerator.Emit(OperationCode.Ldarg_1);
                ilGenerator.Emit(OperationCode.Ldarg_2);
                ilGenerator.Emit(OperationCode.Ldstr, " [shape=record]");
                ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatTwo);
                ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine);

                // jump to the end of this case
                currentNodeDumpedBranch = new ILGeneratorLabel();
                ilGenerator.Emit(OperationCode.Br, currentNodeDumpedBranch);

                // case: current dumped node is the current node of the class
                ilGenerator.MarkLabel(currentNodeEqualDumpedNodeBranch);

                // write current node to .dot file
                ilGenerator.Emit(OperationCode.Ldarg_1);
                ilGenerator.Emit(OperationCode.Ldarg_2);
                ilGenerator.Emit(OperationCode.Ldstr, " [shape=record, color=blue]");
                ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatTwo);
                ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine);

                // end of the case
                ilGenerator.MarkLabel(currentNodeDumpedBranch);

                // write start of label of the current node to .dot file
                ilGenerator.Emit(OperationCode.Ldarg_1);
                ilGenerator.Emit(OperationCode.Ldarg_2);
                ilGenerator.Emit(OperationCode.Ldstr, " [label=\"{");
                ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatTwo);
                ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWrite);

                // write current node name to .dot file
                ilGenerator.Emit(OperationCode.Ldarg_1);
                ilGenerator.Emit(OperationCode.Ldstr, "Node: ");
                ilGenerator.Emit(OperationCode.Ldarg_2);
                ilGenerator.Emit(OperationCode.Ldstr, "|");
                ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatThree);
                ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWrite);

                // write current node id to .dot file
                ilGenerator.Emit(OperationCode.Ldarg_1);
                ilGenerator.Emit(OperationCode.Ldstr, "Id: ");
                ilGenerator.Emit(OperationCode.Ldarg_3);
                ilGenerator.Emit(OperationCode.Callvirt, this.debuggingInterfaceIdGet);
                ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatTwo);
                ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWrite);

                // write end of label of the current node to .dot file
                ilGenerator.Emit(OperationCode.Ldarg_1);
                ilGenerator.Emit(OperationCode.Ldstr, "}\"]");
                ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine);

                // initialize counter of for loop
                ilGenerator.Emit(OperationCode.Ldc_I4_0);
                ilGenerator.Emit(OperationCode.Stloc, forIntegerLocal);

                // jump to loop condition
                loopConditionBranch = new ILGeneratorLabel();
                loopStartBranch = new ILGeneratorLabel();
                ilGenerator.Emit(OperationCode.Br, loopConditionBranch);

                // start of loop
                ilGenerator.MarkLabel(loopStartBranch);

                // check if childNodes[i] == startNode
                ilGenerator.Emit(OperationCode.Ldarg_3);
                ilGenerator.Emit(OperationCode.Ldloc, forIntegerLocal);
                ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet);
                ilGenerator.Emit(OperationCode.Ldarg_0);
                ilGenerator.Emit(OperationCode.Callvirt, this.interfaceStartPointerGet);
                ilGenerator.Emit(OperationCode.Ceq);
                loopConditionAndIncBranch = new ILGeneratorLabel();
                ilGenerator.Emit(OperationCode.Brtrue, loopConditionAndIncBranch);

                // write connection of current node to next node to .dot file
                ilGenerator.Emit(OperationCode.Ldarg_1);

                // generate first part of the string
                ilGenerator.Emit(OperationCode.Ldarg_2);
                ilGenerator.Emit(OperationCode.Ldstr, " -> ");
                ilGenerator.Emit(OperationCode.Ldarg_2);
                ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatThree);

                // generate second part of string and concat to first part
                ilGenerator.Emit(OperationCode.Ldstr, "_");
                ilGenerator.Emit(OperationCode.Ldloca, forIntegerLocal);
                ilGenerator.Emit(OperationCode.Call, this.helperClass.int32ToString);
                ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatThree);

                // write to .dot file
                ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine);

                // call method that dumps graph recursively ( this.dumpGraphRec(streamWriter, String name, nextNode) )
                ilGenerator.Emit(OperationCode.Ldarg_0);

                // push stream writer parameter
                ilGenerator.Emit(OperationCode.Ldarg_1);

                // push string parameter
                ilGenerator.Emit(OperationCode.Ldarg_2);
                ilGenerator.Emit(OperationCode.Ldstr, "_");
                ilGenerator.Emit(OperationCode.Ldloca, forIntegerLocal);
                ilGenerator.Emit(OperationCode.Call, this.helperClass.int32ToString);
                ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatThree);

                // push node parameter (current pointer of debug method)
                ilGenerator.Emit(OperationCode.Ldarg_3);
                ilGenerator.Emit(OperationCode.Ldloc, forIntegerLocal);
                ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet);

                // push node parameter (current pointer of the caller)
                ilGenerator.Emit(OperationCode.Ldarg, currentNodeCallerParameter);

                ilGenerator.Emit(OperationCode.Callvirt, dumpGraphRecMethod);

                // increment loop counter
                ilGenerator.MarkLabel(loopConditionAndIncBranch);
                ilGenerator.Emit(OperationCode.Ldloc, forIntegerLocal);
                ilGenerator.Emit(OperationCode.Ldc_I4_1);
                ilGenerator.Emit(OperationCode.Add);
                ilGenerator.Emit(OperationCode.Stloc, forIntegerLocal);

                // loop condition
                ilGenerator.MarkLabel(loopConditionBranch);
                ilGenerator.Emit(OperationCode.Ldloc, forIntegerLocal);
                ilGenerator.Emit(OperationCode.Ldc_I4, this.graphDimension);
                ilGenerator.Emit(OperationCode.Clt);
                ilGenerator.Emit(OperationCode.Brtrue, loopStartBranch);

                ilGenerator.Emit(OperationCode.Ret);

                // create body
                body = new ILGeneratorMethodBody(ilGenerator, true, 8, dumpGraphRecMethod, localVariables, Enumerable<ITypeDefinition>.Empty);
                dumpGraphRecMethod.Body = body;

            }

            // inject code to build the graph to all constructors (except the artificial added ctor for a graph node)
            foreach (MethodDefinition ctorMethod in this.targetClass.Methods) {

                // only process constructors
                if (!ctorMethod.IsConstructor) {
                    continue;
                }

                // skip the artificial added ctor with the node interface as parameter
                bool skip = false;
                if (ctorMethod.Parameters != null) {
                    foreach (IParameterDefinition ctorParameter in ctorMethod.Parameters) {
                        if (ctorParameter.Type == this.nodeInterface) {
                            skip = true;
                            break;
                        }
                    }
                }
                if (skip) {
                    continue;
                }

                this.logger.writeLine("Injecting code to build graph to \"" + this.logger.makeFuncSigString(ctorMethod) + "\"");

                MethodCfg ctorMethodCfg = this.cfgBuilder.buildCfgForMethod(ctorMethod);

                // create new basic block that builds the graph
                // (will be the new starting basic block of the method)
                BasicBlock startBasicBlock = new BasicBlock();
                startBasicBlock.startIdx = 0;
                startBasicBlock.endIdx = 0;

                startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0));
                startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.buildGraphMethod));

                if (this.debugging) {

                    // dump generated graph
                    startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0));
                    startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(ctorMethodCfg.method)));
                    startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0));
                    startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet));
                    startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0));
                    startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet));
                    startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.debuggingDumpGraphMethod));

                }

                // create exit branch for the new start basic block
                NoBranchTarget startExitBranch = new NoBranchTarget();
                startExitBranch.sourceBasicBlock = startBasicBlock;
                startBasicBlock.exitBranch = startExitBranch;

                // set the original start basic block as the target of the exit branch
                startExitBranch.takenTarget = ctorMethodCfg.startBasicBlock;
                ctorMethodCfg.startBasicBlock.entryBranches.Add(startExitBranch);

                // set new start basic block as start basic block of the method cfg
                ctorMethodCfg.startBasicBlock = startBasicBlock;
                ctorMethodCfg.basicBlocks.Add(startBasicBlock);

                this.cfgBuilder.createMethodFromCfg(ctorMethodCfg);

            }

        }
        private void removeReplaceUnconditionalBranchesIter(CfgManipulator cfgManipulator, GraphRandomStateGenerator randomStateGenerator, MethodCfg originalMethodCfg, MethodCfg methodCfg, BasicBlock startBasicBlock, LocalDefinition intStateLocal, LocalDefinition currentNodeLocal) {

            // create a list of basic blocks that still have to be processed by the algorithm
            List<BasicBlock> basicBlocksToProcess = new List<BasicBlock>(methodCfg.basicBlocks);

            System.Console.WriteLine("Basic Blocks to process (Replace Unconditional Branches): " + basicBlocksToProcess.Count());

            while (true) {

                List<BasicBlock> copiedList = new List<BasicBlock>(basicBlocksToProcess);
                foreach (BasicBlock currentBasicBlock in copiedList) {

                    // check if basic block has entry branches that can be optimized
                    bool hasUnconditionalBranchTarget = false;
                    bool hasNoBranchTarget = false;
                    foreach (IBranchTarget entryBranch in currentBasicBlock.entryBranches) {
                        if ((entryBranch as NoBranchTarget) != null) {
                            hasNoBranchTarget = true;
                            continue;
                        }
                        else if ((entryBranch as UnconditionalBranchTarget) != null) {
                            hasUnconditionalBranchTarget = true;
                            continue;
                        }
                    }

                    // skip if basic block already has no branch target
                    if (hasNoBranchTarget) {
                        // remove currently processed basic block from the list of basic blocks to process
                        basicBlocksToProcess.Remove(currentBasicBlock);
                        continue;
                    }

                    // skip if basic block does not have an unconditional branch target
                    if (!hasUnconditionalBranchTarget) {
                        // remove currently processed basic block from the list of basic blocks to process
                        basicBlocksToProcess.Remove(currentBasicBlock);
                        continue;
                    }

                    // replace one unconditional branch by a no branch
                    List<IBranchTarget> copiedBranchList = new List<IBranchTarget>(currentBasicBlock.entryBranches);
                    foreach (IBranchTarget entryBranch in copiedBranchList) {

                        if ((entryBranch as UnconditionalBranchTarget) != null) {
                            BasicBlock sourceBasicBlock = entryBranch.sourceBasicBlock;

                            // create replacement branch
                            NoBranchTarget replacementBranch = new NoBranchTarget();
                            replacementBranch.sourceBasicBlock = sourceBasicBlock;
                            replacementBranch.takenTarget = currentBasicBlock;

                            // replace old branch with new one
                            sourceBasicBlock.exitBranch = replacementBranch;
                            currentBasicBlock.entryBranches.Remove(entryBranch);
                            currentBasicBlock.entryBranches.Add(replacementBranch);

                            // replace unconditional branch instruction with nop
                            IOperation lastOperation = sourceBasicBlock.operations.ElementAt(sourceBasicBlock.operations.Count() - 1);
                            if (!CfgBuilder.isUnconditionalBranchOperation(lastOperation)) {
                                throw new ArgumentException("Last instruction of basic block have to be an unconditional branch.");
                            }
                            IOperation replacementOperation = this.helperClass.createNewOperation(OperationCode.Nop);
                            sourceBasicBlock.operations[sourceBasicBlock.operations.Count() - 1] = replacementOperation;

                            break;
                        }

                    }

                    // remove currently processed basic block from the list of basic blocks to process
                    basicBlocksToProcess.Remove(currentBasicBlock);

                }

                System.Console.WriteLine("Basic Blocks to process (Replace Unconditional Branches): " + basicBlocksToProcess.Count());

                // check if basic blocks exist to process => if not break loop
                if (basicBlocksToProcess.Count() == 0) {
                    break;
                }

            }

        }
        public void addObfuscationToMethod(MethodCfg methodCfg) {

            MethodCfg copyMethodCfg = new MethodCfg(methodCfg);
            CfgManipulator cfgManipulator = new CfgManipulator(this.module, this.host, this.logger, methodCfg);
            GraphRandomStateGenerator randomStateGenerator = new GraphRandomStateGenerator(this.module, this.host, this.logger, cfgManipulator, this.helperClass, this.graph, methodCfg, this.debugging);

            // DEBUG
            if (this.debugging) {
                //this.logger.dumpMethodCfg(methodCfg, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method));
                this.debuggingNumber++;
            }

            // add local state variable
            LocalDefinition intStateLocal = new LocalDefinition();
            intStateLocal.IsReference = false;
            intStateLocal.IsPinned = false;
            intStateLocal.IsModified = false;
            intStateLocal.Type = this.host.PlatformType.SystemInt32;
            intStateLocal.MethodDefinition = methodCfg.method;
            cfgManipulator.addLocalVariable(intStateLocal);

            // add local current graph node variable
            LocalDefinition currentNodeLocal = new LocalDefinition();
            currentNodeLocal.IsReference = false;
            currentNodeLocal.IsPinned = false;
            currentNodeLocal.IsModified = false;
            currentNodeLocal.Type = this.nodeInterface;
            currentNodeLocal.MethodDefinition = methodCfg.method;
            cfgManipulator.addLocalVariable(currentNodeLocal);

            // create new basic block that sets the current node to the start node and get the state
            // (will be the new starting basic block of the method)
            BasicBlock startBasicBlock = new BasicBlock();
            startBasicBlock.startIdx = 0;
            startBasicBlock.endIdx = 0;

            // set the current node pointer to the start node
            startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0));
            startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet));
            startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Stloc, currentNodeLocal));

            // initialize the random state generator
            List<IOperation> tempOperations = randomStateGenerator.generateCodeInitializeRandomState();
            startBasicBlock.operations.AddRange(tempOperations);

            // set global state
            tempOperations = randomStateGenerator.generateCodeSetRandomState(intStateLocal);
            startBasicBlock.operations.AddRange(tempOperations);

            // create exit branch for the new start basic block
            NoBranchTarget startExitBranch = new NoBranchTarget();
            startExitBranch.sourceBasicBlock = startBasicBlock;
            startBasicBlock.exitBranch = startExitBranch;

            // set the original start basic block as the target of the exit branch
            startExitBranch.takenTarget = methodCfg.startBasicBlock;
            methodCfg.startBasicBlock.entryBranches.Add(startExitBranch);

            // set new start basic block as start basic block of the method cfg
            methodCfg.startBasicBlock = startBasicBlock;
            methodCfg.basicBlocks.Add(startBasicBlock);

            // obfuscate the control flow
            this.addMetadataIter(cfgManipulator, randomStateGenerator, copyMethodCfg, methodCfg, startBasicBlock, intStateLocal, currentNodeLocal);
            this.processExitBranchesIter(cfgManipulator, randomStateGenerator, copyMethodCfg, methodCfg, startBasicBlock, intStateLocal, currentNodeLocal);
            this.addOpaquePredicatesIter(cfgManipulator, randomStateGenerator, copyMethodCfg, methodCfg, startBasicBlock, intStateLocal, currentNodeLocal);
            this.removeReplaceUnconditionalBranchesIter(cfgManipulator, randomStateGenerator, copyMethodCfg, methodCfg, startBasicBlock, intStateLocal, currentNodeLocal);

            // fill dead code basic blocks with actual dead code
            this.fillDeadCodeBasicBlocks(methodCfg);
            this.obfuscateSemanticallyEquivalentBlocks(methodCfg);

            // TODO QUICK FIX
            // mutateBlocks() does not work when debugging is deactivated
            // but since we only focus on probabilistic control flow, ignore it for now
            this.debugging = true;
            this.mutateBlocks(methodCfg);
            this.debugging = false;
            
            // if debugging is activated => add code that allows to trace the control flow through the method
            if (this.debugging
                || this.trace) {

                List<IOperation> traceWriterOperations = null;

                // add code to the beginning of each basic block that writes to the trace file
                for (int idx = 0; idx < methodCfg.basicBlocks.Count(); idx++) {

                    traceWriterOperations = new List<IOperation>();
                    traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0));
                    traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldfld, this.debuggingTraceWriter));
                    traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, "BB" + idx.ToString() + ";ID" + methodCfg.basicBlocks.ElementAt(idx).id.ToString()));
                    traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.helperClass.textWriterWriteLine));

                    methodCfg.basicBlocks.ElementAt(idx).operations.InsertRange(0, traceWriterOperations);

                    // check if the basic block has an exit branch
                    // => add code that closes the file handler of the trace file before the ret instruction
                    if ((methodCfg.basicBlocks.ElementAt(idx).exitBranch as ExitBranchTarget) != null) {

                        traceWriterOperations = new List<IOperation>();

                        traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0));
                        traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldfld, this.debuggingTraceWriter));
                        traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.helperClass.textWriterClose));

                        methodCfg.basicBlocks.ElementAt(idx).operations.InsertRange(methodCfg.basicBlocks.ElementAt(idx).operations.Count() - 1, traceWriterOperations);

                    }
                }

                // create local integer variable needed for the trace file code
                LocalDefinition intLocal = new LocalDefinition();
                intLocal.IsReference = false;
                intLocal.IsPinned = false;
                intLocal.IsModified = false;
                intLocal.Type = this.host.PlatformType.SystemInt32;
                intLocal.MethodDefinition = methodCfg.method;
                cfgManipulator.addLocalVariable(intLocal);

                traceWriterOperations = new List<IOperation>();

                // get the hash code of this instance as unique object id                    
                traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0));
                traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.helperClass.objectGetHashCode));
                traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Stloc, intLocal));

                // initialize io stream writer for trace file (use object hash as id for this trace and only append)
                traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0));

                traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingDumpLocation + "\\" + this.debuggingTraceFilePrefix + "_"));

                // cast random integer to string and store in object id
                traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldloca, intLocal));
                traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Call, this.helperClass.int32ToString));

                traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, ".txt"));
                traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Call, this.helperClass.stringConcatThree));

                // only append to file
                traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldc_I4_1));

                traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Newobj, this.helperClass.streamWriterCtorAppend));
                traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Stfld, this.debuggingTraceWriter));

                // write marker to trace file that marks the beginning of this trace
                traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0));
                traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldfld, this.debuggingTraceWriter));
                traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, "\n------NEWSTART------\n"));
                traceWriterOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.helperClass.textWriterWriteLine));

                // add code to the beginning of the start basic block
                methodCfg.startBasicBlock.operations.InsertRange(0, traceWriterOperations);

            }

            logger.dumpMethodCfg(copyMethodCfg, "copy_final");

            return;
        }
        // creates a duplicate of the given source basic block with the branch targets to semantically equivalent basic blocks
        // (not necessary the target basic block of the given source basic block)
        private BasicBlock duplicateBasicBlock(MethodCfg originalMethodCfg, MethodCfg methodCfg, BasicBlock sourceBasicBlock) {

            // search for a semantically equal basic block in the unmodified method CFG
            int searchSementicId = sourceBasicBlock.semanticId;
            BasicBlock copiedOriginalTargetBasicBlock = null;
            if (searchSementicId == -1) {
                throw new ArgumentException("No distinct semantic id given to search for.");
            }
            foreach (BasicBlock searchBasicBlock in originalMethodCfg.basicBlocks) {
                if (searchBasicBlock.semanticId == searchSementicId) {
                    copiedOriginalTargetBasicBlock = searchBasicBlock;
                    break;
                }
            }
            if (copiedOriginalTargetBasicBlock == null) {
                throw new ArgumentException("Not able to find semantically equal basic block in copied CFG.");
            }

            // create a new basic block
            BasicBlock newBasicBlock = new BasicBlock();

            // copy simple values
            newBasicBlock.semanticId = copiedOriginalTargetBasicBlock.semanticId;
            newBasicBlock.startIdx = copiedOriginalTargetBasicBlock.startIdx;
            newBasicBlock.endIdx = copiedOriginalTargetBasicBlock.endIdx;

            // copy all operations of the basic block
            foreach (IOperation operation in copiedOriginalTargetBasicBlock.operations) {
                newBasicBlock.operations.Add(this.helperClass.createNewOperation(operation.OperationCode, operation.Value, operation.Location, operation.Offset));
            }

            if (copiedOriginalTargetBasicBlock.tryBlocks.Count() != 0
                || copiedOriginalTargetBasicBlock.handlerBlocks.Count() != 0) {
                throw new ArgumentException("Not implemented yet.");
            }

            // create an exit branch for the new basic block
            if ((copiedOriginalTargetBasicBlock.exitBranch as NoBranchTarget) != null) {

                //throw new ArgumentException("Not implemented yet."); // TODO: problem here with having 2 no branches before a basic block (but not necessarily because all branches are processed and exchanged)

                NoBranchTarget exitBranch = (copiedOriginalTargetBasicBlock.exitBranch as NoBranchTarget);

                // create a copied exit branch
                NoBranchTarget copiedExitBranch = new NoBranchTarget();
                copiedExitBranch.sourceBasicBlock = newBasicBlock;
                newBasicBlock.exitBranch = copiedExitBranch;

                // search for all semantically equal basic blocks in the modified method CFG (as possible targets)
                searchSementicId = exitBranch.takenTarget.semanticId;
                List<BasicBlock> possibleTargetBasicBlocks = new List<BasicBlock>();
                foreach (BasicBlock searchBasicBlock in methodCfg.basicBlocks) {
                    if (searchBasicBlock.semanticId == searchSementicId) {
                        possibleTargetBasicBlocks.Add(searchBasicBlock);
                    }
                }
                if (possibleTargetBasicBlocks.Count() == 0) {
                    throw new ArgumentException("Not able to find any semantically equal basic block in CFG.");
                }

                // use a random possible basic block as target
                int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count());
                BasicBlock targetBasicBlock = possibleTargetBasicBlocks.ElementAt(randPosition);

                // set basic block as target for the branch
                targetBasicBlock.entryBranches.Add(copiedExitBranch);
                copiedExitBranch.takenTarget = targetBasicBlock;

            }

            else if (copiedOriginalTargetBasicBlock.exitBranch as UnconditionalBranchTarget != null) {
                UnconditionalBranchTarget exitBranch = (copiedOriginalTargetBasicBlock.exitBranch as UnconditionalBranchTarget);

                // create a copied exit branch
                UnconditionalBranchTarget copiedExitBranch = new UnconditionalBranchTarget();
                copiedExitBranch.sourceBasicBlock = newBasicBlock;
                newBasicBlock.exitBranch = copiedExitBranch;

                // search for all semantically equal basic blocks in the modified method CFG (as possible targets)
                searchSementicId = exitBranch.takenTarget.semanticId;
                List<BasicBlock> possibleTargetBasicBlocks = new List<BasicBlock>();
                foreach (BasicBlock searchBasicBlock in methodCfg.basicBlocks) {
                    if (searchBasicBlock.semanticId == searchSementicId) {
                        possibleTargetBasicBlocks.Add(searchBasicBlock);
                    }
                }
                if (possibleTargetBasicBlocks.Count() == 0) {
                    throw new ArgumentException("Not able to find any semantically equal basic block in CFG.");
                }

                // use a random possible basic block as target
                int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count());
                BasicBlock targetBasicBlock = possibleTargetBasicBlocks.ElementAt(randPosition);

                // set basic block as target for the branch
                targetBasicBlock.entryBranches.Add(copiedExitBranch);
                copiedExitBranch.takenTarget = targetBasicBlock;

            }

            else if (copiedOriginalTargetBasicBlock.exitBranch as ConditionalBranchTarget != null) {
                ConditionalBranchTarget exitBranch = (copiedOriginalTargetBasicBlock.exitBranch as ConditionalBranchTarget);

                // create a copied exit branch
                ConditionalBranchTarget copiedExitBranch = new ConditionalBranchTarget();
                copiedExitBranch.sourceBasicBlock = newBasicBlock;
                newBasicBlock.exitBranch = copiedExitBranch;

                // search for all semantically equal basic blocks in the modified method CFG (as possible targets) (for "taken" branch)
                searchSementicId = exitBranch.takenTarget.semanticId;
                List<BasicBlock> possibleTargetBasicBlocks = new List<BasicBlock>();
                foreach (BasicBlock searchBasicBlock in methodCfg.basicBlocks) {
                    if (searchBasicBlock.semanticId == searchSementicId) {
                        possibleTargetBasicBlocks.Add(searchBasicBlock);
                    }
                }
                if (possibleTargetBasicBlocks.Count() == 0) {
                    throw new ArgumentException("Not able to find any semantically equal basic block in CFG.");
                }

                // use a random possible basic block as target
                int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count());
                BasicBlock targetBasicBlock = possibleTargetBasicBlocks.ElementAt(randPosition);

                // set basic block as target for the branch
                targetBasicBlock.entryBranches.Add(copiedExitBranch);
                copiedExitBranch.takenTarget = targetBasicBlock;

                // search for all semantically equal basic blocks in the modified method CFG (as possible targets) (for "not taken" branch)
                searchSementicId = exitBranch.notTakenTarget.semanticId;
                possibleTargetBasicBlocks = new List<BasicBlock>();
                foreach (BasicBlock searchBasicBlock in methodCfg.basicBlocks) {
                    if (searchBasicBlock.semanticId == searchSementicId) {
                        possibleTargetBasicBlocks.Add(searchBasicBlock);
                    }
                }
                if (possibleTargetBasicBlocks.Count() == 0) {
                    throw new ArgumentException("Not able to find any semantically equal basic block in CFG.");
                }

                // use a random possible basic block as target
                randPosition = this.prng.Next(possibleTargetBasicBlocks.Count());
                targetBasicBlock = possibleTargetBasicBlocks.ElementAt(randPosition);

                // set basic block as target for the branch
                targetBasicBlock.entryBranches.Add(copiedExitBranch);
                copiedExitBranch.notTakenTarget = targetBasicBlock;

            }

            else if (copiedOriginalTargetBasicBlock.exitBranch as SwitchBranchTarget != null) {
                throw new ArgumentException("Not implemented yet.");
            }

            else if (copiedOriginalTargetBasicBlock.exitBranch as ExitBranchTarget != null) {

                // create a copied exit branch
                ExitBranchTarget copiedExitBranch = new ExitBranchTarget();
                copiedExitBranch.sourceBasicBlock = newBasicBlock;
                newBasicBlock.exitBranch = copiedExitBranch;

            }

            else if (copiedOriginalTargetBasicBlock.exitBranch as ThrowBranchTarget != null) {
                throw new ArgumentException("Not implemented yet.");
            }

            else if (copiedOriginalTargetBasicBlock.exitBranch as TryBlockTarget != null) {
                throw new ArgumentException("Not implemented yet.");
            }

            else if (copiedOriginalTargetBasicBlock.exitBranch as ExceptionBranchTarget != null) {
                throw new ArgumentException("Not implemented yet.");
            }

            else {
                throw new ArgumentException("Do not know how to handle exit branch.");
            }

            return newBasicBlock;

        }