Beispiel #1
0
        public void Compile(string fileName)
        {
            string appName = Path.GetFileNameWithoutExtension(fileName);
            string exeName = appName + ".exe";
            string src = "";
            using (TextReader file = new StreamReader(fileName))
            {
                src = file.ReadToEnd();
            }

            var nameTable = new NameTable();
            using (var host = new PeReader.DefaultHost(nameTable))
            {
                // Load Mirage types

                IModule module = host.LoadUnitFrom("Mirage.dll") as IModule;
                if (module == null || module is Dummy)
                {
                    return;
                }
                var machineType = module.GetAllTypes().First(x => x.Name.Value == "Machine");
                var inputType = module.GetAllTypes().First(x => x.Name.Value == "ConsoleInput");
                var outputType = module.GetAllTypes().First(x => x.Name.Value == "ConsoleOutput");

                // Create assembly

                var coreAssembly = host.LoadAssembly(host.CoreAssemblySymbolicIdentity);
                var assembly = new Assembly()
                {
                    Name = nameTable.GetNameFor(appName),
                    ModuleName = nameTable.GetNameFor(exeName),
                    PlatformType = host.PlatformType,
                    Kind = ModuleKind.ConsoleApplication,
                    RequiresStartupStub = host.PointerSize == 4,
                    TargetRuntimeVersion = coreAssembly.TargetRuntimeVersion,
                };
                assembly.AssemblyReferences.Add(coreAssembly);

                // Create namespace

                var rootUnitNamespace = new RootUnitNamespace();
                assembly.UnitNamespaceRoot = rootUnitNamespace;
                rootUnitNamespace.Unit = assembly;

                // Create module class

                var moduleClass = new NamespaceTypeDefinition()
                {
                    ContainingUnitNamespace = rootUnitNamespace,
                    InternFactory = host.InternFactory,
                    IsClass = true,
                    Name = nameTable.GetNameFor("<Module>"),
                };
                assembly.AllTypes.Add(moduleClass);

                // Create program class

                var programClass = new NamespaceTypeDefinition()
                {
                    ContainingUnitNamespace = rootUnitNamespace,
                    InternFactory = host.InternFactory,
                    IsClass = true,
                    IsPublic = true,
                    Methods = new List<IMethodDefinition>(1),
                    Name = nameTable.GetNameFor("Program"),
                };
                programClass.BaseClasses = new List<ITypeReference>() { host.PlatformType.SystemObject };
                rootUnitNamespace.Members.Add(programClass);

                // Add types to the assembly

                assembly.AllTypes.Add(machineType);
                foreach (var t in machineType.NestedTypes)
                {
                    assembly.AllTypes.Add(t);
                }
                assembly.AllTypes.Add(inputType);
                assembly.AllTypes.Add(outputType);
                assembly.AllTypes.Add(programClass);

                // Create main method

                var mainMethod = new MethodDefinition()
                {
                    ContainingTypeDefinition = programClass,
                    InternFactory = host.InternFactory,
                    IsCil = true,
                    IsStatic = true,
                    Name = nameTable.GetNameFor("Main"),
                    Type = host.PlatformType.SystemVoid,
                    Visibility = TypeMemberVisibility.Public,
                };
                assembly.EntryPoint = mainMethod;
                programClass.Methods.Add(mainMethod);

                // Create constructors and methods

                IMethodReference machineConstructor = new Microsoft.Cci.MethodReference(
                    host,
                    machineType,
                    CallingConvention.HasThis,
                    host.PlatformType.SystemVoid,
                    host.NameTable.Ctor,
                    0
                );

                IMethodReference inputConstructor = new Microsoft.Cci.MethodReference(
                    host,
                    inputType,
                    CallingConvention.HasThis,
                    host.PlatformType.SystemVoid,
                    host.NameTable.Ctor,
                    0
                );
                var inputCast = TypeHelper.GetMethod(inputType, nameTable.GetNameFor("op_Implicit"), inputType);

                IMethodReference outputConstructor = new Microsoft.Cci.MethodReference(
                    host,
                    outputType,
                    CallingConvention.HasThis,
                    host.PlatformType.SystemVoid,
                    host.NameTable.Ctor,
                    0
                );
                var outputCast = TypeHelper.GetMethod(outputType, nameTable.GetNameFor("op_Implicit"), outputType);

                var opIncPointers = TypeHelper.GetMethod(machineType, nameTable.GetNameFor("IncPointers"));
                var opDecPointers = TypeHelper.GetMethod(machineType, nameTable.GetNameFor("DecPointers"));
                var opIncHiPointer = TypeHelper.GetMethod(machineType, nameTable.GetNameFor("IncHiPointer"));
                var opDecHiPointer = TypeHelper.GetMethod(machineType, nameTable.GetNameFor("DecHiPointer"));
                var opReflectHiPointer = TypeHelper.GetMethod(machineType, nameTable.GetNameFor("ReflectHiPointer"));
                var opLoadHiPointer = TypeHelper.GetMethod(machineType, nameTable.GetNameFor("LoadHiPointer"));
                var opDragLoPointer = TypeHelper.GetMethod(machineType, nameTable.GetNameFor("DragLoPointer"));
                var opXchPointers = TypeHelper.GetMethod(machineType, nameTable.GetNameFor("XchPointers"));

                var opClear = TypeHelper.GetMethod(machineType, nameTable.GetNameFor("Clear"));
                var opAdd = TypeHelper.GetMethod(machineType, nameTable.GetNameFor("Add"));
                var opDec = TypeHelper.GetMethod(machineType, nameTable.GetNameFor("Dec"));
                var opNot = TypeHelper.GetMethod(machineType, nameTable.GetNameFor("Not"));
                var opAnd = TypeHelper.GetMethod(machineType, nameTable.GetNameFor("And"));
                var opOr = TypeHelper.GetMethod(machineType, nameTable.GetNameFor("Or"));
                var opXor = TypeHelper.GetMethod(machineType, nameTable.GetNameFor("Xor"));
                var opSal = TypeHelper.GetMethod(machineType, nameTable.GetNameFor("Sal"));
                var opSar = TypeHelper.GetMethod(machineType, nameTable.GetNameFor("Sar"));

                var opLoadData = TypeHelper.GetMethod(machineType, nameTable.GetNameFor("LoadData"), host.PlatformType.SystemString);
                var opInput = TypeHelper.GetMethod(machineType, nameTable.GetNameFor("Input"), inputCast.Type);
                var opOutput = TypeHelper.GetMethod(machineType, nameTable.GetNameFor("Output"), outputCast.Type);

                var opJz = TypeHelper.GetMethod(machineType, nameTable.GetNameFor("Jz"));

                // Create program code

                var labels = new Stack<ILGeneratorLabel>(100);

                var ilGenerator = new ILGenerator(host, mainMethod);
                ilGenerator.Emit(OperationCode.Newobj, machineConstructor);
                ilGenerator.Emit(OperationCode.Stloc_0);
                ilGenerator.Emit(OperationCode.Newobj, inputConstructor);
                ilGenerator.Emit(OperationCode.Stloc_1);
                ilGenerator.Emit(OperationCode.Newobj, outputConstructor);
                ilGenerator.Emit(OperationCode.Stloc_2);

                int pc = 0;
                while (pc < src.Length)
                {
                    char opcode = src[pc++];

                    switch (opcode)
                    {
                        case '>':
                            ilGenerator.Emit(OperationCode.Ldloc_0);
                            ilGenerator.Emit(OperationCode.Callvirt, opIncPointers);
                            break;
                        case '<':
                            ilGenerator.Emit(OperationCode.Ldloc_0);
                            ilGenerator.Emit(OperationCode.Callvirt, opDecPointers);
                            break;
                        case ']':
                            ilGenerator.Emit(OperationCode.Ldloc_0);
                            ilGenerator.Emit(OperationCode.Callvirt, opIncHiPointer);
                            break;
                        case '[':
                            ilGenerator.Emit(OperationCode.Ldloc_0);
                            ilGenerator.Emit(OperationCode.Callvirt, opDecHiPointer);
                            break;
                        case '#':
                            ilGenerator.Emit(OperationCode.Ldloc_0);
                            ilGenerator.Emit(OperationCode.Callvirt, opReflectHiPointer);
                            break;
                        case '$':
                            ilGenerator.Emit(OperationCode.Ldloc_0);
                            ilGenerator.Emit(OperationCode.Callvirt, opLoadHiPointer);
                            break;
                        case '=':
                            ilGenerator.Emit(OperationCode.Ldloc_0);
                            ilGenerator.Emit(OperationCode.Callvirt, opDragLoPointer);
                            break;
                        case '%':
                            ilGenerator.Emit(OperationCode.Ldloc_0);
                            ilGenerator.Emit(OperationCode.Callvirt, opXchPointers);
                            break;
                        case '_':
                            ilGenerator.Emit(OperationCode.Ldloc_0);
                            ilGenerator.Emit(OperationCode.Callvirt, opClear);
                            break;
                        case '+':
                            ilGenerator.Emit(OperationCode.Ldloc_0);
                            ilGenerator.Emit(OperationCode.Callvirt, opAdd);
                            break;
                        case '-':
                            ilGenerator.Emit(OperationCode.Ldloc_0);
                            ilGenerator.Emit(OperationCode.Callvirt, opDec);
                            break;
                        case '~':
                            ilGenerator.Emit(OperationCode.Ldloc_0);
                            ilGenerator.Emit(OperationCode.Callvirt, opNot);
                            break;
                        case '&':
                            ilGenerator.Emit(OperationCode.Ldloc_0);
                            ilGenerator.Emit(OperationCode.Callvirt, opAnd);
                            break;
                        case '|':
                            ilGenerator.Emit(OperationCode.Ldloc_0);
                            ilGenerator.Emit(OperationCode.Callvirt, opOr);
                            break;
                        case '^':
                            ilGenerator.Emit(OperationCode.Ldloc_0);
                            ilGenerator.Emit(OperationCode.Callvirt, opXor);
                            break;
                        case '*':
                            ilGenerator.Emit(OperationCode.Ldloc_0);
                            ilGenerator.Emit(OperationCode.Callvirt, opSal);
                            break;
                        case '/':
                            ilGenerator.Emit(OperationCode.Ldloc_0);
                            ilGenerator.Emit(OperationCode.Callvirt, opSar);
                            break;
                        case '(':
                            int dataStart = pc;
                            int dataEnd = dataStart;
                            while (src[pc++] != ')')
                            {
                                dataEnd = pc;
                            }
                            ilGenerator.Emit(OperationCode.Ldloc_0);
                            ilGenerator.Emit(OperationCode.Ldstr, src.Substring(dataStart, dataEnd - dataStart));
                            ilGenerator.Emit(OperationCode.Callvirt, opLoadData);
                            break;
                        case '?':
                            ilGenerator.Emit(OperationCode.Ldloc_0);
                            ilGenerator.Emit(OperationCode.Ldloc_1);
                            ilGenerator.Emit(OperationCode.Call, inputCast);
                            ilGenerator.Emit(OperationCode.Callvirt, opInput);
                            break;
                        case '!':
                            ilGenerator.Emit(OperationCode.Ldloc_0);
                            ilGenerator.Emit(OperationCode.Ldloc_2);
                            ilGenerator.Emit(OperationCode.Call, outputCast);
                            ilGenerator.Emit(OperationCode.Callvirt, opOutput);
                            break;
                        case '{':
                            var cycleStart = new ILGeneratorLabel();
                            var cycleEnd = new ILGeneratorLabel();
                            labels.Push(cycleStart);
                            labels.Push(cycleEnd);
                            ilGenerator.Emit(OperationCode.Br, cycleEnd);
                            ilGenerator.MarkLabel(cycleStart);
                            break;
                        case '}':
                            ilGenerator.MarkLabel(labels.Pop());
                            ilGenerator.Emit(OperationCode.Ldloc_0);
                            ilGenerator.Emit(OperationCode.Callvirt, opJz);
                            ilGenerator.Emit(OperationCode.Ldc_I4_0);
                            ilGenerator.Emit(OperationCode.Ceq);
                            ilGenerator.Emit(OperationCode.Stloc_3);
                            ilGenerator.Emit(OperationCode.Ldloc_3);
                            ilGenerator.Emit(OperationCode.Brtrue, labels.Pop());
                            break;
                        default:
                            break;
                    }
                }

                ilGenerator.Emit(OperationCode.Ret);

                mainMethod.Body = new ILGeneratorMethodBody(
                    ilGenerator,
                    true,
                    8,
                    mainMethod,
                    new List<ILocalDefinition>() {
                        new LocalDefinition() { Type = machineType },
                        new LocalDefinition() { Type = inputType },
                        new LocalDefinition() { Type = outputType },
                        new LocalDefinition() { Type = host.PlatformType.SystemInt32 },
                    },
                    Enumerable<ITypeDefinition>.Empty
                );

                using (var peStream = File.Create(exeName))
                {
                    PeWriter.WritePeToStream(assembly, host, peStream);
                }
            }
        }
        // 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 ProcessOperations(IMethodBody methodBody) {

      List<IOperation> operations = ((methodBody.Operations == null) ? new List<IOperation>(): new List<IOperation>(methodBody.Operations));
      int count = operations.Count;

      ILGenerator generator = new ILGenerator(this.host, methodBody.MethodDefinition);
      if (this.pdbReader != null) {
        foreach (var ns in this.pdbReader.GetNamespaceScopes(methodBody)) {
          foreach (var uns in ns.UsedNamespaces)
            generator.UseNamespace(uns.NamespaceName.Value);
        }
      }

      this.currentGenerator = generator;
      this.scopeEnumerator = this.pdbReader == null ? null : this.pdbReader.GetLocalScopes(methodBody).GetEnumerator();
      this.scopeEnumeratorIsValid = this.scopeEnumerator != null && this.scopeEnumerator.MoveNext();

      var methodName = MemberHelper.GetMemberSignature(methodBody.MethodDefinition, NameFormattingOptions.SmartTypeName);

      #region Record all offsets that appear as part of an exception handler
      Dictionary<uint, bool> offsetsUsedInExceptionInformation = new Dictionary<uint, bool>();
      foreach (var exceptionInfo in methodBody.OperationExceptionInformation??Enumerable<IOperationExceptionInformation>.Empty) {
        uint x = exceptionInfo.TryStartOffset;
        if (!offsetsUsedInExceptionInformation.ContainsKey(x)) offsetsUsedInExceptionInformation.Add(x, true);
        x = exceptionInfo.TryEndOffset;
        if (!offsetsUsedInExceptionInformation.ContainsKey(x)) offsetsUsedInExceptionInformation.Add(x, true);
        x = exceptionInfo.HandlerStartOffset;
        if (!offsetsUsedInExceptionInformation.ContainsKey(x)) offsetsUsedInExceptionInformation.Add(x, true);
        x = exceptionInfo.HandlerEndOffset;
        if (!offsetsUsedInExceptionInformation.ContainsKey(x)) offsetsUsedInExceptionInformation.Add(x, true);
        if (exceptionInfo.HandlerKind == HandlerKind.Filter) {
          x = exceptionInfo.FilterDecisionStartOffset;
          if (!offsetsUsedInExceptionInformation.ContainsKey(x)) offsetsUsedInExceptionInformation.Add(x, true);
        }
      }
      #endregion Record all offsets that appear as part of an exception handler

      Dictionary<uint, ILGeneratorLabel> offset2Label = new Dictionary<uint, ILGeneratorLabel>();
      #region Pass 1: Make a label for each branch target
      for (int i = 0; i < count; i++) {
        IOperation op = operations[i];
        switch (op.OperationCode) {
          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.Br:
          case OperationCode.Brfalse:
          case OperationCode.Brtrue:
          case OperationCode.Leave:
          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.Br_S:
          case OperationCode.Brfalse_S:
          case OperationCode.Brtrue_S:
          case OperationCode.Leave_S:
            uint x = (uint)op.Value;
            if (!offset2Label.ContainsKey(x))
              offset2Label.Add(x, new ILGeneratorLabel());
            break;
          case OperationCode.Switch:
            uint[] offsets = op.Value as uint[];
            foreach (var offset in offsets) {
              if (!offset2Label.ContainsKey(offset))
                offset2Label.Add(offset, new ILGeneratorLabel());
            }
            break;
          default:
            break;
        }
      }
      #endregion Pass 1: Make a label for each branch target

      #region Pass 2: Emit each operation, along with labels
      for (int i = 0; i < count; i++) {
        IOperation op = operations[i];
        ILGeneratorLabel label;
        this.EmitDebugInformationFor(op);
        #region Mark operation if it is a label for a branch
        if (offset2Label.TryGetValue(op.Offset, out label)) {
          generator.MarkLabel(label);
        }
        #endregion Mark operation if it is a label for a branch

        #region Mark operation if it is pointed to by an exception handler
        bool ignore;
        uint offset = op.Offset;
        if (offsetsUsedInExceptionInformation.TryGetValue(offset, out ignore)) {
          foreach (var exceptionInfo in methodBody.OperationExceptionInformation) {
            if (offset == exceptionInfo.TryStartOffset)
              generator.BeginTryBody();

            // Never need to do anthing when offset == exceptionInfo.TryEndOffset because
            // we pick up an EndTryBody from the HandlerEndOffset below
            //  generator.EndTryBody();

            if (offset == exceptionInfo.HandlerStartOffset) {
              switch (exceptionInfo.HandlerKind) {
                case HandlerKind.Catch:
                  generator.BeginCatchBlock(exceptionInfo.ExceptionType);
                  break;
                case HandlerKind.Fault:
                  generator.BeginFaultBlock();
                  break;
                case HandlerKind.Filter:
                  generator.BeginFilterBody();
                  break;
                case HandlerKind.Finally:
                  generator.BeginFinallyBlock();
                  break;
              }
            }
            if (exceptionInfo.HandlerKind == HandlerKind.Filter && offset == exceptionInfo.FilterDecisionStartOffset) {
              generator.BeginFilterBlock();
            }
            if (offset == exceptionInfo.HandlerEndOffset)
              generator.EndTryBody();
          }
        }
        #endregion Mark operation if it is pointed to by an exception handler

        #region Emit operation along with any injection
        switch (op.OperationCode) {
          #region Branches
          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.Br:
          case OperationCode.Brfalse:
          case OperationCode.Brtrue:
          case OperationCode.Leave:
          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.Br_S:
          case OperationCode.Brfalse_S:
          case OperationCode.Brtrue_S:
          case OperationCode.Leave_S:
            generator.Emit(ILGenerator.LongVersionOf(op.OperationCode), offset2Label[(uint)op.Value]);
            break;
          case OperationCode.Switch:
            uint[] offsets = op.Value as uint[];
            ILGeneratorLabel[] labels = new ILGeneratorLabel[offsets.Length];
            for (int j = 0, n = offsets.Length; j < n; j++) {
              labels[j] = offset2Label[offsets[j]];
            }
            generator.Emit(OperationCode.Switch, labels);
            break;
          #endregion Branches
          #region Everything else
          case OperationCode.Stloc_0:
          case OperationCode.Stloc_1:
          case OperationCode.Stloc_2:
          case OperationCode.Stloc_3:
            generator.Emit(op.OperationCode);
            EmitStoreLocal(generator, op);
            break;
          case OperationCode.Stloc:
          case OperationCode.Stloc_S:
            generator.Emit(op.OperationCode, op.Value);
            EmitStoreLocal(generator, op);
            break;
          default:
            if (op.Value == null) {
              generator.Emit(op.OperationCode);
              break;
            }
            var typeCode = System.Convert.GetTypeCode(op.Value);
            switch (typeCode) {
              case TypeCode.Byte:
                generator.Emit(op.OperationCode, (byte)op.Value);
                break;
              case TypeCode.Double:
                generator.Emit(op.OperationCode, (double)op.Value);
                break;
              case TypeCode.Int16:
                generator.Emit(op.OperationCode, (short)op.Value);
                break;
              case TypeCode.Int32:
                generator.Emit(op.OperationCode, (int)op.Value);
                break;
              case TypeCode.Int64:
                generator.Emit(op.OperationCode, (long)op.Value);
                break;
              case TypeCode.Object:
                IFieldReference fieldReference = op.Value as IFieldReference;
                if (fieldReference != null) {
                  generator.Emit(op.OperationCode, this.Rewrite(fieldReference));
                  break;
                }
                ILocalDefinition localDefinition = op.Value as ILocalDefinition;
                if (localDefinition != null) {
                  generator.Emit(op.OperationCode, localDefinition);
                  break;
                }
                IMethodReference methodReference = op.Value as IMethodReference;
                if (methodReference != null) {
                  generator.Emit(op.OperationCode, this.Rewrite(methodReference));
                  break;
                }
                IParameterDefinition parameterDefinition = op.Value as IParameterDefinition;
                if (parameterDefinition != null) {
                  generator.Emit(op.OperationCode, parameterDefinition);
                  break;
                }
                ISignature signature = op.Value as ISignature;
                if (signature != null) {
                  generator.Emit(op.OperationCode, signature);
                  break;
                }
                ITypeReference typeReference = op.Value as ITypeReference;
                if (typeReference != null) {
                  generator.Emit(op.OperationCode, this.Rewrite(typeReference));
                  break;
                }
                throw new ILMutatorException("Should never get here: no other IOperation argument types should exist");
              case TypeCode.SByte:
                generator.Emit(op.OperationCode, (sbyte)op.Value);
                break;
              case TypeCode.Single:
                generator.Emit(op.OperationCode, (float)op.Value);
                break;
              case TypeCode.String:
                generator.Emit(op.OperationCode, (string)op.Value);
                break;
              default:
                // The other cases are the other enum values that TypeCode has.
                // But no other argument types should be in the Operations. ILGenerator cannot handle anything else,
                // so such IOperations should never exist.
                //case TypeCode.Boolean:
                //case TypeCode.Char:
                //case TypeCode.DateTime:
                //case TypeCode.DBNull:
                //case TypeCode.Decimal:
                //case TypeCode.Empty: // this would be the value for null, but the case when op.Value is null is handled before the switch statement
                //case TypeCode.UInt16:
                //case TypeCode.UInt32:
                //case TypeCode.UInt64:
                throw new ILMutatorException("Should never get here: no other IOperation argument types should exist");
            }
            break;
          #endregion Everything else
        }
        #endregion Emit operation along with any injection

      }
      while (generator.InTryBody)
        generator.EndTryBody();
      while (this.scopeStack.Count > 0) {
        this.currentGenerator.EndScope();
        this.scopeStack.Pop();
      }
      #endregion Pass 2: Emit each operation, along with labels

    }
        // this function adds recursively methods that adds the left and the right node to the current node in the graph
        // (and calls the next method that adds the left and right node)
        private MethodDefinition addNodeRecursively(NodeObject currentNode, int currentDepth, String newMethodName) {

            // create first parameter that is the current node in the graph
            List<IParameterDefinition> parameters = new List<IParameterDefinition>();
            ParameterDefinition parameter = new ParameterDefinition();
            parameter.IsIn = false;
            parameter.IsOptional = false;
            parameter.IsOut = false;
            parameter.Type = this.nodeInterface;
            parameters.Add(parameter);

            // create second parameter that is the current depth in the graph
            parameter = new ParameterDefinition();
            parameter.IsIn = false;
            parameter.IsOptional = false;
            parameter.IsOut = false;
            parameter.Type = host.PlatformType.SystemInt32;
            parameters.Add(parameter);

            // create method to add left and right node to the graph
            MethodDefinition newAddNodeMethod = this.helperClass.createNewMethod(newMethodName, this.targetClass, host.PlatformType.SystemVoid, TypeMemberVisibility.Public, parameters, CallingConvention.HasThis, false, false, true); // TODO: method name

            // create body of method
            ILGenerator ilGenerator = new ILGenerator(this.host, newAddNodeMethod);

            // check if max depth of tree is reached
            ilGenerator.Emit(OperationCode.Ldarg_2);
            ilGenerator.Emit(OperationCode.Ldc_I4, this.graph.graphDepth);
            ilGenerator.Emit(OperationCode.Ceq);
            ilGenerator.Emit(OperationCode.Ldc_I4_0);
            ilGenerator.Emit(OperationCode.Ceq);
            ILGeneratorLabel depthReachedBranch = new ILGeneratorLabel();
            ilGenerator.Emit(OperationCode.Brfalse, depthReachedBranch);

            // set child nodes of this node
            MethodDefinition constructorToUse;

            for (int i = 0; i < this.graphDimension; i++) {

                // get constructor of the child node element
                constructorToUse = null;

                // check if the child node exists in the graph and the max depth is not yet reached
                if (currentNode.nodeObjects[i] == null
                    && currentDepth != this.graph.graphDepth) {
                    throw new ArgumentException("Given depth of graph is larger than the actual graph.");
                }
                else {
                    // check if the child node does not exist
                    // => use a random constructor node
                    if (currentNode.nodeObjects[i] == null) {
                        constructorToUse = currentNode.constructorToUse; // TODO: use random node constructor here
                    }
                    // else use constructor of given graph node
                    else {
                        constructorToUse = currentNode.nodeObjects[i].constructorToUse;
                    }
                }

                // set child node
                ilGenerator.Emit(OperationCode.Ldarg_1); // current node from which the function is called
                ilGenerator.Emit(OperationCode.Ldarg_0); // needed as argument for the constructor
                ilGenerator.Emit(OperationCode.Newobj, constructorToUse); // iNode parameter
                ilGenerator.Emit(OperationCode.Ldc_I4, i); // index parameter
                ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesSet);

                // get child node and set it recursively
                ilGenerator.Emit(OperationCode.Ldarg_0);
                ilGenerator.Emit(OperationCode.Ldarg_1); // current node from which the function is called
                ilGenerator.Emit(OperationCode.Ldc_I4, i); // index parameter
                ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet);

                ilGenerator.Emit(OperationCode.Ldarg_2); // arg2 (current depth) + 1
                ilGenerator.Emit(OperationCode.Ldc_I4_1);
                ilGenerator.Emit(OperationCode.Add);

                MethodDefinition newMethodToCall = null;
                if (currentDepth == this.graph.graphDepth) {
                    newMethodToCall = newAddNodeMethod; // TODO: call random node generation method here
                }
                else {
                    newMethodToCall = this.addNodeRecursively(currentNode.nodeObjects[i], currentDepth + 1, newMethodName + "_" + i.ToString()); // TODO: method name
                }

                ilGenerator.Emit(OperationCode.Callvirt, newMethodToCall);
            }

            ilGenerator.Emit(OperationCode.Ret);

            // set child nodes of this node to null
            ilGenerator.MarkLabel(depthReachedBranch);
            for (int i = 0; i < this.graphDimension; i++) {
                ilGenerator.Emit(OperationCode.Ldarg_1);
                ilGenerator.Emit(OperationCode.Ldarg_0);
                ilGenerator.Emit(OperationCode.Callvirt, this.interfaceStartPointerGet); // iNode parameter
                ilGenerator.Emit(OperationCode.Ldc_I4, i); // index parameter
                ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesSet);
            }
            ilGenerator.Emit(OperationCode.Ret);

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

            return newAddNodeMethod;
        }