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; }