protected void AppendEmitExceptionThrow(ILGenerator generator) { var systemExceptionTypeReference = GarbageCollectHelper.CreateTypeReference(host, coreAssemblyReference, "System.Exception"); IMethodReference exceptionConstructor = new Microsoft.Cci.MethodReference( host, systemExceptionTypeReference, CallingConvention.HasThis, host.PlatformType.SystemVoid, host.NameTable.Ctor, 0); generator.Emit(OperationCode.Newobj, exceptionConstructor); generator.Emit(OperationCode.Throw); }
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 }
private IMethodReference InjectNewEntryPoint(IMethodDefinition oldEntryPoint) { var containingType = (NamespaceTypeDefinition)oldEntryPoint.ContainingTypeDefinition; var entryPoint = new MethodDefinition() { ContainingTypeDefinition = containingType, InternFactory = this.host.InternFactory, IsCil = true, IsStatic = true, Name = this.host.NameTable.GetNameFor("InstrumentedMain"), Parameters = new List<IParameterDefinition>(oldEntryPoint.Parameters), Type = this.host.PlatformType.SystemVoid, Visibility = TypeMemberVisibility.Public, }; containingType.Methods.Add(entryPoint); var ilGenerator = new ILGenerator(host, entryPoint); foreach (var par in entryPoint.Parameters) ilGenerator.Emit(OperationCode.Ldarg, par); ilGenerator.Emit(OperationCode.Call, oldEntryPoint); foreach (var dumper in this.dumperMethods) { ilGenerator.Emit(OperationCode.Call, dumper); } ilGenerator.Emit(OperationCode.Ret); var body = new ILGeneratorMethodBody(ilGenerator, true, (ushort)entryPoint.Parameters.Count, entryPoint, Enumerable<ILocalDefinition>.Empty, Enumerable<ITypeDefinition>.Empty); entryPoint.Body = body; return entryPoint; }
private void InjectMethodToDumpCounters() { var dumper = new MethodDefinition() { ContainingTypeDefinition = this.counterFieldsForCurrentMethod, InternFactory = this.host.InternFactory, IsCil = true, IsStatic = true, Name = this.host.NameTable.GetNameFor("DumpCounters"), Type = this.host.PlatformType.SystemVoid, Visibility = TypeMemberVisibility.Public, }; this.counterFieldsForCurrentMethod.Methods.Add(dumper); this.dumperMethods.Add(dumper); var ilGenerator = new ILGenerator(this.host, dumper); for (int i = 0, n = this.fieldOffsets.Count; i < n; i++) { ilGenerator.Emit(OperationCode.Ldsfld, this.counterFieldsForCurrentMethod.Fields[i]); ilGenerator.Emit(OperationCode.Call, this.logger); } ilGenerator.Emit(OperationCode.Ret); var body = new ILGeneratorMethodBody(ilGenerator, false, 2, dumper, Enumerable<ILocalDefinition>.Empty, Enumerable<ITypeDefinition>.Empty ); dumper.Body = body; }
public override ILGenerator DebugReplacementGeneratorForBody(IMethodBody methodBody) { string warningText = "Attempt to execute garbage collected method: " + methodBody.MethodDefinition.ToString(); var generator = new ILGenerator(host, methodBody.MethodDefinition); // emit console warning generator.Emit(OperationCode.Ldstr, warningText); generator.Emit(OperationCode.Call, this.consoleWriteLine); //emit stack trace // pushes stack trace on stack generator.Emit(OperationCode.Call, this.environmentGetStackTrace); // consumes stack trace generator.Emit(OperationCode.Call, this.consoleWriteLine); // may want to flush output? // emit exit generator.Emit(OperationCode.Ldc_I4_M1); generator.Emit(OperationCode.Call, this.environmentExit); // Makes the verifier happy; this should never be reached AppendEmitExceptionThrow(generator); return generator; }
// this function adds the created iNode interface to the class and also implements all neded functions public void addNodeInterfaceToTargetClass(NamespaceTypeDefinition givenClass) { this.logger.writeLine(""); this.logger.writeLine("Add node interface \"" + this.nodeInterface.ToString() + "\" to class \"" + givenClass.ToString() + "\""); // check if generated interface was already added to target class if (givenClass.Interfaces != null && givenClass.Interfaces.Contains(this.nodeInterface)) { this.logger.writeLine("Class \"" + givenClass.ToString() + "\" already contains node interface \"" + this.nodeInterface.ToString() + "\""); return; } // add nodes interface to class if (givenClass.Interfaces != null) { givenClass.Interfaces.Add(this.nodeInterface); } else { givenClass.Interfaces = new List<ITypeReference>(); givenClass.Interfaces.Add(this.nodeInterface); } // add start pointer field FieldDefinition startPointerField = new FieldDefinition(); startPointerField.IsCompileTimeConstant = false; startPointerField.IsNotSerialized = false; startPointerField.IsReadOnly = false; startPointerField.IsRuntimeSpecial = false; startPointerField.IsSpecialName = false; startPointerField.Type = this.nodeInterface; startPointerField.IsStatic = false; startPointerField.Visibility = TypeMemberVisibility.Public; startPointerField.Name = host.NameTable.GetNameFor("startPointer"); startPointerField.InternFactory = host.InternFactory; startPointerField.ContainingTypeDefinition = givenClass; if (givenClass.Fields != null) { givenClass.Fields.Add(startPointerField); } else { givenClass.Fields = new List<IFieldDefinition>(); givenClass.Fields.Add(startPointerField); } // create getter for the startPointer variable MethodDefinition startPointerGetMethod = this.helperClass.createNewMethod("startPointer_get", givenClass, this.nodeInterface, TypeMemberVisibility.Public, null, CallingConvention.HasThis, false, false, true); // TODO: method name // create a body for the getter method ILGenerator ilGenerator = new ILGenerator(host, startPointerGetMethod); ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Ldfld, startPointerField); ilGenerator.Emit(OperationCode.Ret); IMethodBody body = new ILGeneratorMethodBody(ilGenerator, true, 1, startPointerGetMethod, Enumerable<ILocalDefinition>.Empty, Enumerable<ITypeDefinition>.Empty); startPointerGetMethod.Body = body; // create setter for the startPointer variable List<IParameterDefinition> parameters = new List<IParameterDefinition>(); ParameterDefinition parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Name = host.NameTable.GetNameFor("value"); parameter.Type = this.nodeInterface; parameters.Add(parameter); MethodDefinition startPointerSetMethod = this.helperClass.createNewMethod("startPointer_set", givenClass, host.PlatformType.SystemVoid, TypeMemberVisibility.Public, parameters, CallingConvention.HasThis, false, false, true); // TODO: method name // create a body for the setter method ilGenerator = new ILGenerator(host, startPointerSetMethod); ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Ldarg_1); ilGenerator.Emit(OperationCode.Stfld, startPointerField); ilGenerator.Emit(OperationCode.Ret); body = new ILGeneratorMethodBody(ilGenerator, true, 1, startPointerSetMethod, Enumerable<ILocalDefinition>.Empty, Enumerable<ITypeDefinition>.Empty); startPointerSetMethod.Body = body; // add childNodes array field FieldDefinition childNodesField = new FieldDefinition(); childNodesField.IsCompileTimeConstant = false; childNodesField.IsNotSerialized = false; childNodesField.IsReadOnly = false; childNodesField.IsRuntimeSpecial = false; childNodesField.IsSpecialName = false; // create array of node interface type VectorTypeReference nodeInterfaceArrayType = new VectorTypeReference(); nodeInterfaceArrayType.ElementType = this.nodeInterface; nodeInterfaceArrayType.Rank = 1; nodeInterfaceArrayType.IsFrozen = true; nodeInterfaceArrayType.IsValueType = false; nodeInterfaceArrayType.InternFactory = host.InternFactory; childNodesField.Type = nodeInterfaceArrayType; childNodesField.IsStatic = false; childNodesField.Visibility = TypeMemberVisibility.Public; childNodesField.Name = host.NameTable.GetNameFor("childNodes"); childNodesField.InternFactory = host.InternFactory; childNodesField.ContainingTypeDefinition = givenClass; givenClass.Fields.Add(childNodesField); // create getter for the childNodes variable parameters = new List<IParameterDefinition>(); // int parameter parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Type = this.host.PlatformType.SystemInt32; parameters.Add(parameter); MethodDefinition childNodesGetMethod = this.helperClass.createNewMethod("childNodes_get", givenClass, this.nodeInterface, TypeMemberVisibility.Public, parameters, CallingConvention.HasThis, false, false, true); // TODO: method name // create a body for the getter method ilGenerator = new ILGenerator(host, childNodesGetMethod); ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Ldfld, childNodesField); ilGenerator.Emit(OperationCode.Ldarg_1); ilGenerator.Emit(OperationCode.Ldelem_Ref); ilGenerator.Emit(OperationCode.Ret); body = new ILGeneratorMethodBody(ilGenerator, true, 1, childNodesGetMethod, Enumerable<ILocalDefinition>.Empty, Enumerable<ITypeDefinition>.Empty); childNodesGetMethod.Body = body; // create setter for the childNodes variable parameters = new List<IParameterDefinition>(); // iNode parameter parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Type = this.nodeInterface; parameters.Add(parameter); // int parameter parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Type = this.host.PlatformType.SystemInt32; parameters.Add(parameter); MethodDefinition childNodesSetMethod = this.helperClass.createNewMethod("childNodes_set", givenClass, host.PlatformType.SystemVoid, TypeMemberVisibility.Public, parameters, CallingConvention.HasThis, false, false, true); // TODO: method name // create a body for the setter method ilGenerator = new ILGenerator(host, childNodesSetMethod); ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Ldfld, childNodesField); ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Ldarg_1); ilGenerator.Emit(OperationCode.Stelem_Ref); ilGenerator.Emit(OperationCode.Ret); body = new ILGeneratorMethodBody(ilGenerator, true, 1, childNodesSetMethod, Enumerable<ILocalDefinition>.Empty, Enumerable<ITypeDefinition>.Empty); childNodesSetMethod.Body = body; // add current node field FieldDefinition currentNodeField = new FieldDefinition(); currentNodeField.IsCompileTimeConstant = false; currentNodeField.IsNotSerialized = false; currentNodeField.IsReadOnly = false; currentNodeField.IsRuntimeSpecial = false; currentNodeField.IsSpecialName = false; currentNodeField.Type = this.nodeInterface; currentNodeField.IsStatic = false; currentNodeField.Visibility = TypeMemberVisibility.Public; currentNodeField.Name = host.NameTable.GetNameFor("currentNode"); currentNodeField.InternFactory = host.InternFactory; currentNodeField.ContainingTypeDefinition = givenClass; givenClass.Fields.Add(currentNodeField); // create getter for the currentNode variable MethodDefinition currentNodeGetMethod = this.helperClass.createNewMethod("currentNode_get", givenClass, this.nodeInterface, TypeMemberVisibility.Public, null, CallingConvention.HasThis, false, false, true); // TODO: method name // create a body for the getter method ilGenerator = new ILGenerator(host, currentNodeGetMethod); ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Ldfld, currentNodeField); ilGenerator.Emit(OperationCode.Ret); body = new ILGeneratorMethodBody(ilGenerator, true, 1, currentNodeGetMethod, Enumerable<ILocalDefinition>.Empty, Enumerable<ITypeDefinition>.Empty); currentNodeGetMethod.Body = body; // create setter for the currentNode variable parameters = new List<IParameterDefinition>(); parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Name = host.NameTable.GetNameFor("value"); parameter.Type = this.nodeInterface; parameters.Add(parameter); MethodDefinition currentNodeSetMethod = this.helperClass.createNewMethod("currentNode_set", givenClass, host.PlatformType.SystemVoid, TypeMemberVisibility.Public, parameters, CallingConvention.HasThis, false, false, true); // TODO: method name // create a body for the setter method ilGenerator = new ILGenerator(host, currentNodeSetMethod); ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Ldarg_1); ilGenerator.Emit(OperationCode.Stfld, currentNodeField); ilGenerator.Emit(OperationCode.Ret); body = new ILGeneratorMethodBody(ilGenerator, true, 1, currentNodeSetMethod, Enumerable<ILocalDefinition>.Empty, Enumerable<ITypeDefinition>.Empty); currentNodeSetMethod.Body = body; // check if debugging is activated // => add graph debugging attributes and methods MethodDefinition objectIdGetMethod = null; FieldDefinition objectIdField = null; if (this.debugging) { this.logger.writeLine("Debugging activated: Adding field for unique object id and getter method"); // add objectId field objectIdField = new FieldDefinition(); objectIdField.IsCompileTimeConstant = false; objectIdField.IsNotSerialized = false; objectIdField.IsReadOnly = false; objectIdField.IsRuntimeSpecial = false; objectIdField.IsSpecialName = false; objectIdField.Type = this.host.PlatformType.SystemString; objectIdField.IsStatic = false; objectIdField.Name = host.NameTable.GetNameFor("DEBUG_objectId"); objectIdField.Visibility = TypeMemberVisibility.Public; objectIdField.InternFactory = host.InternFactory; objectIdField.ContainingTypeDefinition = givenClass; givenClass.Fields.Add(objectIdField); // create getter for the objectId variable objectIdGetMethod = this.helperClass.createNewMethod("DEBUG_objectId_get", givenClass, this.host.PlatformType.SystemString, TypeMemberVisibility.Public, null, CallingConvention.HasThis, false, false, true); // TODO: method name // create a body for the getter method ilGenerator = new ILGenerator(host, objectIdGetMethod); ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Ldfld, objectIdField); ilGenerator.Emit(OperationCode.Ret); body = new ILGeneratorMethodBody(ilGenerator, true, 1, objectIdGetMethod, Enumerable<ILocalDefinition>.Empty, Enumerable<ITypeDefinition>.Empty); objectIdGetMethod.Body = body; } // add .ctor(iNode) to target class parameters = new List<IParameterDefinition>(); parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Type = this.nodeInterface; parameters.Add(parameter); MethodDefinition nodeConstructor = this.helperClass.createNewMethod(".ctor", givenClass, host.PlatformType.SystemVoid, TypeMemberVisibility.Public, parameters, CallingConvention.HasThis, false, false, false); nodeConstructor.IsSpecialName = true; nodeConstructor.IsHiddenBySignature = true; nodeConstructor.IsRuntimeSpecial = true; // generate node constructor body ilGenerator = new ILGenerator(host, currentNodeSetMethod); // create local variable list List<ILocalDefinition> localVariables = new List<ILocalDefinition>(); // call system.object constructor ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Call, this.helperClass.objectCtor); // initialize childNodes array ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Ldc_I4, this.graphDimension); ilGenerator.Emit(OperationCode.Newarr, nodeInterfaceArrayType); ilGenerator.Emit(OperationCode.Stfld, childNodesField); // check if debugging is activated // => add code to constructor that generates a unique id for this object if (this.debugging) { this.logger.writeLine("Debugging activated: Adding code to generate unique id to node constructor"); // create local integer variable needed for debugging code LocalDefinition intLocal = new LocalDefinition(); intLocal.IsReference = false; intLocal.IsPinned = false; intLocal.IsModified = false; intLocal.Type = this.host.PlatformType.SystemInt32; intLocal.MethodDefinition = nodeConstructor; localVariables.Add(intLocal); // use the hash code of this instance as unique object id ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.objectGetHashCode); ilGenerator.Emit(OperationCode.Stloc, intLocal); // cast random integer to string and store in object id ilGenerator.Emit(OperationCode.Ldloca, intLocal); ilGenerator.Emit(OperationCode.Call, this.helperClass.int32ToString); ilGenerator.Emit(OperationCode.Stfld, objectIdField); } ilGenerator.Emit(OperationCode.Ret); body = new ILGeneratorMethodBody(ilGenerator, true, 8, nodeConstructor, localVariables, Enumerable<ITypeDefinition>.Empty); nodeConstructor.Body = body; // add class to the list of possible nodes for the graph PossibleNode tempStruct = new PossibleNode(); tempStruct.nodeConstructor = nodeConstructor; tempStruct.givenClass = givenClass; // for each interface the class implements add it to the according list foreach (ITypeReference interfaceRef in givenClass.Interfaces) { this.logger.writeLine("Add class \"" + givenClass.ToString() + "\" to graph interface list \"" + interfaceRef.ToString() + "\""); // check if a list with this interface already exists // => if it does just add current class to list if (this.graphInterfaces.ContainsKey(interfaceRef)) { List<PossibleNode> tempList = (List<PossibleNode>)this.graphInterfaces[interfaceRef]; tempList.Add(tempStruct); } // if not => add new list for this interface else { List<PossibleNode> tempList = new List<PossibleNode>(); tempList.Add(tempStruct); this.graphInterfaces.Add(interfaceRef, tempList); } } this.logger.writeLine(""); }
static void Main(string[] args) { var nameTable = new NameTable(); using (var host = new PeReader.DefaultHost(nameTable)) { var coreAssembly = host.LoadAssembly(host.CoreAssemblySymbolicIdentity); var assembly = new Assembly() { Name = nameTable.GetNameFor("hello"), ModuleName = nameTable.GetNameFor("hello.exe"), PlatformType = host.PlatformType, Kind = ModuleKind.ConsoleApplication, RequiresStartupStub = host.PointerSize == 4, TargetRuntimeVersion = coreAssembly.TargetRuntimeVersion, }; assembly.AssemblyReferences.Add(coreAssembly); var rootUnitNamespace = new RootUnitNamespace(); assembly.UnitNamespaceRoot = rootUnitNamespace; rootUnitNamespace.Unit = assembly; var moduleClass = new NamespaceTypeDefinition() { ContainingUnitNamespace = rootUnitNamespace, InternFactory = host.InternFactory, IsClass = true, Name = nameTable.GetNameFor("<Module>"), }; assembly.AllTypes.Add(moduleClass); var testClass = new NamespaceTypeDefinition() { ContainingUnitNamespace = rootUnitNamespace, InternFactory = host.InternFactory, IsClass = true, IsPublic = true, Methods = new List<IMethodDefinition>(1), Name = nameTable.GetNameFor("Test"), }; rootUnitNamespace.Members.Add(testClass); assembly.AllTypes.Add(testClass); testClass.BaseClasses = new List<ITypeReference>() { host.PlatformType.SystemObject }; var mainMethod = new MethodDefinition() { ContainingTypeDefinition = testClass, InternFactory = host.InternFactory, IsCil = true, IsStatic = true, Name = nameTable.GetNameFor("Main"), Type = host.PlatformType.SystemVoid, Visibility = TypeMemberVisibility.Public, }; assembly.EntryPoint = mainMethod; testClass.Methods.Add(mainMethod); var ilGenerator = new ILGenerator(host, mainMethod); var systemConsole = UnitHelper.FindType(nameTable, coreAssembly, "System.Console"); var writeLine = TypeHelper.GetMethod(systemConsole, nameTable.GetNameFor("WriteLine"), host.PlatformType.SystemString); ilGenerator.Emit(OperationCode.Ldstr, "hello"); ilGenerator.Emit(OperationCode.Call, writeLine); ilGenerator.Emit(OperationCode.Ret); var body = new ILGeneratorMethodBody(ilGenerator, true, 1, mainMethod, Enumerable<ILocalDefinition>.Empty, Enumerable<ITypeDefinition>.Empty); mainMethod.Body = body; using (var peStream = File.Create("hello.exe")) { PeWriter.WritePeToStream(assembly, host, peStream); } } }
static void mergeClassWithAncestor(NamespaceTypeDefinition mergeTargetClass, PeReader.DefaultHost host) { // get class from which was inherited ITypeDefinition ancestorClass = null; INamedEntity ancestorClassName = null; if (mergeTargetClass.BaseClasses.Count == 1) { // TODO // entferne wenn Methode umgeschrieben /* // ignore inheritance from System.Object if (mergeTargetClass.BaseClasses[0].ToString() != "System.Object") { ancestorClass = (mergeTargetClass.BaseClasses[0] as NamespaceTypeDefinition); } // return if ancestor class equals System.Object else { return; } */ // check base class is of type NamespaceTypeDefinition if (mergeTargetClass.BaseClasses.ElementAt(0) as NamespaceTypeDefinition != null) { ancestorClass = (mergeTargetClass.BaseClasses.ElementAt(0) as ITypeDefinition); ancestorClassName = (mergeTargetClass.BaseClasses.ElementAt(0) as INamedEntity); } // ignore inheritance from System.Object else if (mergeTargetClass.BaseClasses[0].ToString() == "System.Object") { return; } // check for needed values in base class and its resolved value (for example when base class of type NamespaceTypeReference) else if ((mergeTargetClass.BaseClasses.ElementAt(0).ResolvedType as ITypeDefinition != null) && (mergeTargetClass.BaseClasses.ElementAt(0) as INamedEntity != null)) { // TODO // weiss nicht ob es Sinn macht externe Klassen wie z.B. system.ValueType // in die aktuelle Klasse rein zu mergen => denn Trick mit methoden auf Virtual stellen // damit JIT Compiler unsere Methoden aufruft klappt nicht in dem Fall (da wir die Methoden von System.ValueType nicht umschreiben koennen) //ancestorClass = (mergeTargetClass.BaseClasses[0].ResolvedType as ITypeDefinition); //ancestorClassName = (mergeTargetClass.BaseClasses[0].ResolvedType as INamedEntity); return; } else { throw new ArgumentException("Do not know how to handle base class."); } } else { throw new ArgumentException("Do not know how to handle multiple inheritance."); } // copy all attributes from the ancestor class to the current class if (ancestorClass.Fields != null) { globalLog.writeLine("Copying fileds"); foreach (FieldDefinition field in ancestorClass.Fields) { FieldDefinition copy = new FieldDefinition(); globalLog.writeLine("Copying field: " + field.Name.ToString()); copyField(copy, field); copy.ContainingTypeDefinition = mergeTargetClass; // set intern factory of the copied field to the one of the class // (without it, the generated binary file will have strange results like use only the same field) copy.InternFactory = mergeTargetClass.InternFactory; mergeTargetClass.Fields.Add(copy); } globalLog.writeLine(""); } // list of all constructors of the ancestor class List<MethodDefinition> copiedAncestorConstructors = new List<MethodDefinition>(); // copy methods from the ancestor class to the current class if (ancestorClass.Methods != null) { globalLog.writeLine("Copying methods"); foreach (IMethodDefinition method in ancestorClass.Methods) { globalLog.writeLine("Copying method: " + method.Name.ToString()); // check if the method is a constructor if (method.IsConstructor) { MethodDefinition copiedAncestorConstructor = new MethodDefinition(); copyMethod(copiedAncestorConstructor, method, host); // TODO // name muss noch geaendert werden String tempName = "ctor_" + ancestorClassName.Name.ToString(); copiedAncestorConstructor.Name = host.NameTable.GetNameFor(tempName); // constructor has the "SpecialName" (the name describes the functionality) // and "RTSpecialName" (runtime should check name encoding) flag set // runtime will raise an exception if these flags are set for a copied constructor // which is added as a normal function copiedAncestorConstructor.IsSpecialName = false; copiedAncestorConstructor.IsRuntimeSpecial = false; // TODO: // vielleicht einfach von späterer Schleife machen lassen (sollte jetzt schon gehen, aber noch nicht getestet, // deshalb erst ein mal drin gelassen) // copy constructor and rewrite instructions to use attributes and functions // inside the same class var testIlGenerator = new ILGenerator(host, copiedAncestorConstructor); foreach (var operation in copiedAncestorConstructor.Body.Operations) { switch (operation.OperationCode) { case OperationCode.Call: // HIER NOCH CHECKEN OB ANDERE FUNKTIONEN INNERHALB DES ANCESTORS AUFGERUFEN WERDEN // DIESE MUESSEN UMGELEITET WERDEN /* Microsoft.Cci.MutableCodeModel.MethodDefinition blah = null; if (operation.Value is Microsoft.Cci.MutableCodeModel.MethodDefinition) { blah = (Microsoft.Cci.MutableCodeModel.MethodDefinition)(operation.Value); NamespaceTypeDefinition test = (NamespaceTypeDefinition)blah.ContainingTypeDefinition; if (ancestorClass.Name.Equals(test.Name)) { System.Console.WriteLine("Ja"); } } */ testIlGenerator.Emit(operation.OperationCode, operation.Value); break; case OperationCode.Stfld: FieldDefinition attribute = (FieldDefinition)operation.Value; // search for the method attribute that is used in the copied constructor // and replace it with the method attribute from the current class FieldDefinition foundField = null; foreach (FieldDefinition field in mergeTargetClass.Fields) { if (attribute.Name.Equals(field.Name) && attribute.Type.Equals(field.Type)) { foundField = field; break; } } if (foundField == null) { System.Console.WriteLine("Attribute not found"); return; } testIlGenerator.Emit(operation.OperationCode, foundField); break; default: testIlGenerator.Emit(operation.OperationCode, operation.Value); break; } } // create new body List<ILocalDefinition> variableListCopy = new List<ILocalDefinition>(method.Body.LocalVariables); List<ITypeDefinition> privateHelperTypesListCopy = new List<ITypeDefinition>(method.Body.PrivateHelperTypes); var newBody = new ILGeneratorMethodBody(testIlGenerator, method.Body.LocalsAreZeroed, method.Body.MaxStack, copiedAncestorConstructor, variableListCopy, privateHelperTypesListCopy); copiedAncestorConstructor.Body = newBody; // set intern factory of the copied constructor to the one of the class // (without it, the generated binary file will have strange results like call always the same method) copiedAncestorConstructor.InternFactory = mergeTargetClass.InternFactory; // add copied constructor to the class copiedAncestorConstructor.ContainingTypeDefinition = mergeTargetClass; copiedAncestorConstructor.Visibility = TypeMemberVisibility.Private; mergeTargetClass.Methods.Add(copiedAncestorConstructor); // add copied ancestor constructor to the list of copied ancestor constructors copiedAncestorConstructors.Add(copiedAncestorConstructor); continue; } else { // copy method MethodDefinition copy = new MethodDefinition(); copyMethod(copy, method, host); copy.ContainingTypeDefinition = mergeTargetClass; // set intern factory of the copied method to the one of the class // (without it, the generating of the binary file will have strange results) copy.InternFactory = mergeTargetClass.InternFactory; // add method to the class if (mergeTargetClass.Methods == null) { mergeTargetClass.Methods = new List<IMethodDefinition>(); } mergeTargetClass.Methods.Add(copy); } } globalLog.writeLine(""); } // rewrite constructors of the class to call the copied constructor instead of // the constructor of the ancestor class // (rewriting methods is handled later) foreach (MethodDefinition method in mergeTargetClass.Methods) { // check if method is a constructor if (method.IsConstructor) { var testIlGenerator = new ILGenerator(host, method); foreach (var operation in method.Body.Operations) { switch (operation.OperationCode) { // only call instructions that call a constructor have to be redirected case OperationCode.Call: MethodDefinition calledMethod = (MethodDefinition)operation.Value; if (calledMethod.IsConstructor) { // TODO hier treten noch Probleme auf, wenn System.Object ist nicht der oberste Ancestor // sondern z.B. System.ValueType // check if the called constructor is not the constructor of System.Object // and if the constructor that is called is not a constructor of THIS class NamespaceTypeDefinition calledMethodNamespace = (NamespaceTypeDefinition)calledMethod.ContainingTypeDefinition; if (calledMethodNamespace.ToString() != "System.Object" && !calledMethodNamespace.Name.Equals(mergeTargetClass.Name)) { // search for the copied constructor that has to be called // (it is searched by parameter types because they always are named the same ".ctor") MethodDefinition copiedConstructorToCall = null; foreach (MethodDefinition copiedAncestorConstructor in copiedAncestorConstructors) { // check if the count of the parameters of the called constructor and the copied constructor are the same if (copiedAncestorConstructor.ParameterCount == calledMethod.ParameterCount) { // check if the parameters have the same type in the same order bool found = true; for (int i = 0; i < calledMethod.ParameterCount; i++) { if (calledMethod.Parameters[i].Type != copiedAncestorConstructor.Parameters[i].Type) { found = false; break; } } if (found) { copiedConstructorToCall = copiedAncestorConstructor; break; } } } if (copiedConstructorToCall == null) { throw new ArgumentException("No copied constructor with the same parameter types in the same order."); } // call copied constructor instead of constructor of the ancestor testIlGenerator.Emit(operation.OperationCode, copiedConstructorToCall); } // just emit if the called constructor is the constructor of System.Object else { testIlGenerator.Emit(operation.OperationCode, operation.Value); } } // just emit operation if no constructor is called // (rewriting methods is handled later) else { testIlGenerator.Emit(operation.OperationCode, operation.Value); } break; // just emit operation if none of the above cases match default: testIlGenerator.Emit(operation.OperationCode, operation.Value); break; } } // create new body List<ILocalDefinition> variableListCopy = new List<ILocalDefinition>(method.Body.LocalVariables); List<ITypeDefinition> privateHelperTypesListCopy = new List<ITypeDefinition>(method.Body.PrivateHelperTypes); var newBody = new ILGeneratorMethodBody(testIlGenerator, method.Body.LocalsAreZeroed, method.Body.MaxStack, method, variableListCopy, privateHelperTypesListCopy); method.Body = newBody; } } // rewrite all methods to use local attributes/methods instead of the ones of the ancestor foreach (MethodDefinition method in mergeTargetClass.Methods) { var testIlGenerator = new ILGenerator(host, method); foreach (var operation in method.Body.Operations) { switch (operation.OperationCode) { case OperationCode.Stfld: case OperationCode.Ldfld: // get namespace of attribute FieldDefinition attribute = (FieldDefinition)operation.Value; INamedTypeDefinition attributeNamespace = (INamedTypeDefinition)attribute.ContainingTypeDefinition; // check if namespace of attribute equals the namespace of THIS class // => just emit operation if (mergeTargetClass.Name.Equals(attributeNamespace.Name)) { testIlGenerator.Emit(operation.OperationCode, operation.Value); continue; } // try the namespace of all ancestors of this class to see if it was copied else { // flag that indicates if the operation was emitted during the search loop bool operationEmitted = false; // search through all ancestors to find the namespace of the used attribute NamespaceTypeDefinition tempAncestorClass = mergeTargetClass; while (true) { // get class from which was inherited if (tempAncestorClass.BaseClasses.Count == 1) { // ignore inheritance from System.Object if (tempAncestorClass.BaseClasses[0].ToString() != "System.Object") { tempAncestorClass = (tempAncestorClass.BaseClasses[0] as NamespaceTypeDefinition); } // return if ancestor class equals System.Object else { break; } } else { throw new ArgumentException("Do not know how to handle multiple inheritance."); } // check namespace of used attribute is equal to namespace of ancestor // => change target of operation to THIS class if (tempAncestorClass.Name.Equals(attributeNamespace.Name)) { // search for the method attribute that is used in the copied method // and replace it with the method attribute from the current class FieldDefinition foundField = null; foreach (FieldDefinition field in mergeTargetClass.Fields) { if (attribute.Name.Equals(field.Name) && attribute.Type.Equals(field.Type)) { foundField = field; break; } } if (foundField == null) { throw new ArgumentException("Attribute not found."); } // emit operation and set flag that it was emitted operationEmitted = true; testIlGenerator.Emit(operation.OperationCode, foundField); break; } } // if operation was not emitted yet => emit it if (operationEmitted == false) { testIlGenerator.Emit(operation.OperationCode, operation.Value); } } break; case OperationCode.Call: // just emit if value is of type method reference if (operation.Value is Microsoft.Cci.MutableCodeModel.MethodReference) { testIlGenerator.Emit(operation.OperationCode, operation.Value); continue; } // get namespace of called method MethodDefinition calledMethod = (MethodDefinition)operation.Value; NamespaceTypeDefinition calledMethodNamespace = (NamespaceTypeDefinition)calledMethod.ContainingTypeDefinition; // check if namespace of called method equals the namespace of THIS class // => just emit operation if (mergeTargetClass.Name.Equals(calledMethodNamespace.Name)) { testIlGenerator.Emit(operation.OperationCode, operation.Value); continue; } // try the namespace of all ancestors of this class to see if it was copied else { // flag that indicates if the operation was emitted during the search loop bool operationEmitted = false; // search through all ancestors to find the namespace of the called method NamespaceTypeDefinition tempAncestorClass = mergeTargetClass; while (true) { // get class from which was inherited if (tempAncestorClass.BaseClasses.Count == 1) { // ignore inheritance from System.Object if (tempAncestorClass.BaseClasses[0].ToString() != "System.Object") { tempAncestorClass = (tempAncestorClass.BaseClasses[0] as NamespaceTypeDefinition); } // return if ancestor class equals System.Object else { break; } } else { throw new ArgumentException("Do not know how to handle multiple inheritance."); } // check namespace of called method is equal to namespace of ancestor, if the same // => find copied method in THIS class // => change target of operation to method in THIS class if (tempAncestorClass.Name.Equals(calledMethodNamespace.Name)) { // search through all methods in THISS class and search for the copied one MethodDefinition foundMethod = null; foreach (MethodDefinition newMethod in mergeTargetClass.Methods) { // skip constructors (can not be called from the ancestor) if (newMethod.IsConstructor) { continue; } if (newMethod.ParameterCount == calledMethod.ParameterCount) { // check if the parameters have the same type in the same order bool parameterCorrect = true; for (int i = 0; i < calledMethod.ParameterCount; i++) { if (calledMethod.Parameters[i].Type != newMethod.Parameters[i].Type) { parameterCorrect = false; break; } } // if the parameters are correct => check the name if (parameterCorrect) { if (calledMethod.Name.Equals(newMethod.Name)) { // if name is the same => found method to call foundMethod = newMethod; break; } } } } // check if the method we want to call was found if (foundMethod == null) { throw new ArgumentException("Did not find a method to call."); } // emit operation and set flag that it was emitted operationEmitted = true; testIlGenerator.Emit(operation.OperationCode, foundMethod); break; } } // if operation was not emitted yet => emit it if (operationEmitted == false) { testIlGenerator.Emit(operation.OperationCode, operation.Value); } } break; // just emit operation if none of the above cases match default: testIlGenerator.Emit(operation.OperationCode, operation.Value); break; } } // create new body List<ILocalDefinition> variableListCopy = new List<ILocalDefinition>(method.Body.LocalVariables); List<ITypeDefinition> privateHelperTypesListCopy = new List<ITypeDefinition>(method.Body.PrivateHelperTypes); var newBody = new ILGeneratorMethodBody(testIlGenerator, method.Body.LocalsAreZeroed, method.Body.MaxStack, method, variableListCopy, privateHelperTypesListCopy); method.Body = newBody; } }
private INamedTypeDefinition GenerateTypeA(IUnitNamespace rootNamespace) { var nt = Host.NameTable; var typeA = new NamespaceTypeDefinition { ContainingUnitNamespace = rootNamespace, Name = nt.GetNameFor("A"), InternFactory = Host.InternFactory, IsClass = true }; var typeParameter = new GenericTypeParameter { Name = nt.GetNameFor("T"), InternFactory = Host.InternFactory, DefiningType = typeA, }; typeA.GenericParameters.Add(typeParameter); var baseGetMethod = new MethodDefinition { Name = nt.GetNameFor("Get"), IsCil = true, IsVirtual = true, Visibility = TypeMemberVisibility.Assembly, Type = typeParameter, ContainingTypeDefinition = typeA, InternFactory = Host.InternFactory, IsNewSlot = true }; typeA.Methods.Add(baseGetMethod); var il = new ILGenerator(Host); var localVar = new LocalDefinition { Type = typeParameter, Name = nt.GetNameFor("local1"), }; // tricky moment, ILGeneratorMethodBody fills internal collection of local vars only in constructor. // lines below should not be swapped il.AddVariableToCurrentScope(localVar); var body = new ILGeneratorMethodBody(il, true, 1) {MethodDefinition = baseGetMethod}; baseGetMethod.Body = body; il.Emit(OperationCode.Ldloca, localVar); il.Emit(OperationCode.Initobj, typeParameter); il.Emit(OperationCode.Ldloc_0); il.Emit(OperationCode.Ret); return typeA; }
// creates a method for a given method CFG (IMPORTANT: it updates the operations // and exception handlers of the existing method, does not create a new method) public void createMethodFromCfg(MethodCfg methodCfg) { // list of basic blocks that belong together logically (i.e. BB2 lies directly behind BB1 because it reaches it without a branch) IList<BasicBlockUnion> basicBlockUnions = new List<BasicBlockUnion>(); // first step: create basic block unions // create first basic block union starting from the start basic block BasicBlockUnion firstBasicBlockUnion = new BasicBlockUnion(); this.createRecursivelyBasicBlockUnion(basicBlockUnions, firstBasicBlockUnion, methodCfg.startBasicBlock); basicBlockUnions.Add(firstBasicBlockUnion); // create basic block unions for the rest of the basic blocks foreach (BasicBlock tempBB in methodCfg.basicBlocks) { // create a basic block union (if basic block is not contained by another existing basic block union) BasicBlockUnion basicBlockUnion = new BasicBlockUnion(); this.createRecursivelyBasicBlockUnion(basicBlockUnions, basicBlockUnion, tempBB); // if the newly created basic block union contains basic blocks // => add to list of basic block unions if (basicBlockUnion.basicBlocks.Count() != 0) { basicBlockUnions.Add(basicBlockUnion); } } // step two: merge basic block unions with respect to the exception handler foreach (OperationExceptionInformation exceptionHandler in methodCfg.method.Body.OperationExceptionInformation) { // create a temporary object to reorder the basic block unions with respect to the exception handler BasicBlockUnionExceptionHandlerOrder tempNewOrder = new BasicBlockUnionExceptionHandlerOrder(); tempNewOrder.exceptionHandler = exceptionHandler; // find all basic blocks that are connected to the current exception handler foreach (BasicBlockUnion basicBlockUnion in basicBlockUnions) { foreach (BasicBlock basicBlock in basicBlockUnion.basicBlocks) { // ignore all basic blocks that do not have any try/catch/finally handler in it if (basicBlock.tryBlocks.Count() == 0 && basicBlock.handlerBlocks.Count() == 0) { continue; } // find the try block that is connected to the current exception handler foreach (TryBlock tryBlock in basicBlock.tryBlocks) { // ignore try blocks that do not belong to the current exception handler if (tryBlock.exceptionHandler != exceptionHandler) { continue; } // check if basic block union already resides in try body // if not => add to try body if (!tempNewOrder.tryBody.Contains(basicBlockUnion)) { tempNewOrder.tryBody.Add(basicBlockUnion); } // check if the basic block starts the try block if (tryBlock.firstBasicBlockOfTryBlock) { tempNewOrder.tryStart = basicBlockUnion; } // check if the basic block ends the try block if (tryBlock.lastBasicBlockOfTryBlock) { tempNewOrder.tryEnd = basicBlockUnion; } } // find the handler block that is connected to the current exception handler foreach (HandlerBlock handlerBlock in basicBlock.handlerBlocks) { // ignore handler blocks that do not belong to the current exception handler if (handlerBlock.exceptionHandler != exceptionHandler) { continue; } // check if basic block union already resides in handler body // if not => add to handler body if (!tempNewOrder.handlerBody.Contains(basicBlockUnion)) { tempNewOrder.handlerBody.Add(basicBlockUnion); } // check if the basic block starts the handler block if (handlerBlock.firstBasicBlockOfHandlerBlock) { tempNewOrder.handlerStart = basicBlockUnion; } // check if the basic block ends the handler block if (handlerBlock.lastBasicBlockOfHandlerBlock) { tempNewOrder.handlerEnd = basicBlockUnion; } } } } if (tempNewOrder.tryStart == null || tempNewOrder.tryEnd == null || tempNewOrder.handlerStart == null || tempNewOrder.handlerEnd == null) { throw new ArgumentException("Could not find all try/catch beginnings/ends."); } // merge basic block unions with respect to the current exception handler // check if the complete exception handling is done in only one basic block union // => ignore it if (tempNewOrder.tryStart == tempNewOrder.tryEnd && tempNewOrder.handlerStart == tempNewOrder.handlerEnd && tempNewOrder.tryStart == tempNewOrder.handlerStart) { continue; } // if not everything lies in the same basic block union // extend the basic block union that starts the try block BasicBlockUnion extendedUnion = tempNewOrder.tryStart; // if try block start and end are the same => nothing to merge // else merge the basic block unions if (tempNewOrder.tryStart != tempNewOrder.tryEnd) { foreach (BasicBlockUnion tryBodyBasicBlockUnion in tempNewOrder.tryBody) { // ignore the basic block union that starts the try block (already in extended union) // and ignore the basic block union that ends the try block (is added last) if (tryBodyBasicBlockUnion == tempNewOrder.tryStart || tryBodyBasicBlockUnion == tempNewOrder.tryEnd) { continue; } // extend first basic block union with the basic block union of the // try block body and remove the added one from the list of basic block unions extendedUnion.basicBlocks.AddRange(tryBodyBasicBlockUnion.basicBlocks); basicBlockUnions.Remove(tryBodyBasicBlockUnion); } // extend first basic block union with the basic block union of the // try block end and remove the added one from the list of basic block unions extendedUnion.basicBlocks.AddRange(tempNewOrder.tryEnd.basicBlocks); basicBlockUnions.Remove(tempNewOrder.tryEnd); } // if the try block end and the handler block start are not the same basic block union // => merge the union of the handler block start to the current basic block union if (tempNewOrder.tryEnd != tempNewOrder.handlerStart) { extendedUnion.basicBlocks.AddRange(tempNewOrder.handlerStart.basicBlocks); basicBlockUnions.Remove(tempNewOrder.handlerStart); } // if handler block start and end are the same => nothing to merge // else merge the basic block unions if (tempNewOrder.handlerStart != tempNewOrder.handlerEnd) { foreach (BasicBlockUnion handlerBodyBasicBlockUnion in tempNewOrder.handlerBody) { // ignore the basic block union that starts the handler block (already in extended union) // and ignore the basic block union that ends the handler block (is added last) if (handlerBodyBasicBlockUnion == tempNewOrder.handlerStart || handlerBodyBasicBlockUnion == tempNewOrder.handlerEnd) { continue; } // add basic block union of the handler block body to the extended basic block union // and remove the added one from the list of basic block unions extendedUnion.basicBlocks.AddRange(handlerBodyBasicBlockUnion.basicBlocks); basicBlockUnions.Remove(handlerBodyBasicBlockUnion); } // extend the extended basic block union with the basic block union of the // handler block end and remove the added one from the list of basic block unions extendedUnion.basicBlocks.AddRange(tempNewOrder.handlerEnd.basicBlocks); basicBlockUnions.Remove(tempNewOrder.handlerEnd); } } // step three: create one list of operations and modify jump offsets // create a list of operations from the basic blocks, // update basic block start/end indices accordingly // and update the offsets of the operations (needed to update branch operations) IList<IOperation> methodOperations = new List<IOperation>(); int operationIdx = 0; uint currentOffset = 0; foreach (BasicBlockUnion basicBlockUnion in basicBlockUnions) { foreach (BasicBlock basicBlock in basicBlockUnion.basicBlocks) { basicBlock.startIdx = operationIdx; //foreach (IOperation operation in basicBlock.operations) { for (int opIdx = 0; opIdx < basicBlock.operations.Count(); opIdx++) { IOperation operation = basicBlock.operations.ElementAt(opIdx); // a new operation object is needed because the old operations // are read only due to cci InternalOperation newOperation = new InternalOperation(); // exchange every short instruction with its larger one switch (operation.OperationCode) { case OperationCode.Beq_S: newOperation.OperationCode = OperationCode.Beq; break; case OperationCode.Bge_S: newOperation.OperationCode = OperationCode.Bge; break; case OperationCode.Bge_Un_S: newOperation.OperationCode = OperationCode.Bge_Un; break; case OperationCode.Bgt_S: newOperation.OperationCode = OperationCode.Bgt; break; case OperationCode.Bgt_Un_S: newOperation.OperationCode = OperationCode.Bgt_Un; break; case OperationCode.Ble_S: newOperation.OperationCode = OperationCode.Ble; break; case OperationCode.Ble_Un_S: newOperation.OperationCode = OperationCode.Ble_Un; break; case OperationCode.Blt_S: newOperation.OperationCode = OperationCode.Blt; break; case OperationCode.Blt_Un_S: newOperation.OperationCode = OperationCode.Blt_Un; break; case OperationCode.Bne_Un_S: newOperation.OperationCode = OperationCode.Bne_Un; break; case OperationCode.Br_S: newOperation.OperationCode = OperationCode.Br; break; case OperationCode.Brfalse_S: newOperation.OperationCode = OperationCode.Brfalse; break; case OperationCode.Brtrue_S: newOperation.OperationCode = OperationCode.Brtrue; break; case OperationCode.Ldarg_S: newOperation.OperationCode = OperationCode.Ldarg; break; case OperationCode.Ldarga_S: newOperation.OperationCode = OperationCode.Ldarga; break; case OperationCode.Ldc_I4_S: newOperation.OperationCode = OperationCode.Ldc_I4; break; case OperationCode.Ldloc_S: newOperation.OperationCode = OperationCode.Ldloc; break; case OperationCode.Ldloca_S: newOperation.OperationCode = OperationCode.Ldloca; break; case OperationCode.Leave_S: newOperation.OperationCode = OperationCode.Leave; break; case OperationCode.Starg_S: newOperation.OperationCode = OperationCode.Starg; break; case OperationCode.Stloc_S: newOperation.OperationCode = OperationCode.Stloc; break; default: newOperation.OperationCode = operation.OperationCode; break; } newOperation.Value = operation.Value; newOperation.Location = operation.Location; newOperation.Offset = currentOffset; methodOperations.Add(newOperation); // replace old operation in basic block with newly created one basicBlock.operations[opIdx] = newOperation; operationIdx++; currentOffset += CfgBuilder.getSizeOfOperation(newOperation); } basicBlock.endIdx = operationIdx - 1; } } // step four: update branches with new target offsets foreach (BasicBlock tempBB in methodCfg.basicBlocks) { InternalOperation branchOperation = (InternalOperation)methodOperations.ElementAt(tempBB.endIdx); // check which kind of exit branch is used by this basic block and update its operation accordingly if (tempBB.exitBranch as NoBranchTarget != null) { continue; } else if (tempBB.exitBranch as TryBlockTarget != null) { continue; } else if (tempBB.exitBranch as ConditionalBranchTarget != null) { ConditionalBranchTarget tempExitBranch = (tempBB.exitBranch as ConditionalBranchTarget); // check if the branch is done by a branch operation if (!CfgBuilder.isBranchOperation(branchOperation)) { throw new ArgumentException("Branch is not done by a valid branch operation."); } // get index of the branch target int targetBranchIdx = tempExitBranch.takenTarget.startIdx; // update offset of the taken branch branchOperation.Value = methodOperations.ElementAt(targetBranchIdx).Offset; } else if (tempBB.exitBranch as SwitchBranchTarget != null) { SwitchBranchTarget tempExitBranch = (tempBB.exitBranch as SwitchBranchTarget); // check if the branch is done by a branch operation if (!CfgBuilder.isBranchOperation(branchOperation)) { throw new ArgumentException("Branch is not done by a valid branch operation."); } // update all switch branches for (int switchIdx = 0; switchIdx < tempExitBranch.takenTarget.Count(); switchIdx++) { // get index of the branch target int targetBranchIdx = tempExitBranch.takenTarget.ElementAt(switchIdx).startIdx; // update offset of the taken branch ((uint[])branchOperation.Value)[switchIdx] = methodOperations.ElementAt(targetBranchIdx).Offset; } } else if (tempBB.exitBranch as UnconditionalBranchTarget != null) { UnconditionalBranchTarget tempExitBranch = (tempBB.exitBranch as UnconditionalBranchTarget); // check if the branch is done by a branch operation if (!CfgBuilder.isBranchOperation(branchOperation)) { throw new ArgumentException("Branch is not done by a valid branch operation."); } // get index of the branch target int targetBranchIdx = tempExitBranch.takenTarget.startIdx; // update offset of the taken branch branchOperation.Value = methodOperations.ElementAt(targetBranchIdx).Offset; } else if (tempBB.exitBranch as ExitBranchTarget != null) { continue; } else if (tempBB.exitBranch as ThrowBranchTarget != null) { continue; } else if (tempBB.exitBranch as ExceptionBranchTarget != null) { ExceptionBranchTarget tempExitBranch = (tempBB.exitBranch as ExceptionBranchTarget); // check if the branch is done by a branch operation if (!CfgBuilder.isBranchOperation(branchOperation)) { throw new ArgumentException("Branch is not done by a valid branch operation."); } // get index of the branch target int targetBranchIdx = tempExitBranch.exitTarget.startIdx; // update offset of the taken branch branchOperation.Value = methodOperations.ElementAt(targetBranchIdx).Offset; } else { throw new ArgumentException("Do not know how to handle exit branch."); } } // step five: create new exception handler with updated offsets and // create new method body of the cci method MethodDefinition method = methodCfg.method; var ilGenerator = new ILGenerator(this.host, method); // emit all operations to the new body foreach (IOperation operation in methodOperations) { ilGenerator.Emit(operation.OperationCode, operation.Value); } // list that is used to replace the pointer to the old exception handler in the basic blocks to the new exception handler List<OldExceptionHandlerMapping> oldExceptionHandlerMappings = new List<OldExceptionHandlerMapping>(); // create for each old exception handler a new one with updated data foreach (IOperationExceptionInformation exceptionHandler in method.Body.OperationExceptionInformation) { // create mapping object for old exception handler OldExceptionHandlerMapping oldExceptionHandlerMapping = new OldExceptionHandlerMapping(); oldExceptionHandlerMapping.oldExceptionHandler = exceptionHandler; oldExceptionHandlerMappings.Add(oldExceptionHandlerMapping); ILGeneratorLabel tryStart = new ILGeneratorLabel(); ILGeneratorLabel tryEnd = new ILGeneratorLabel(); ILGeneratorLabel handlerStart = new ILGeneratorLabel(); ILGeneratorLabel handlerEnd = new ILGeneratorLabel(); ILGeneratorLabel filterStart = new ILGeneratorLabel(); // search for the basic blocks that start/end the try block and handler block foreach (BasicBlock tempBB in methodCfg.basicBlocks) { foreach (TryBlock tempTryBlock in tempBB.tryBlocks) { // ignore try blocks that do not belong to the current exception handler if (tempTryBlock.exceptionHandler != exceptionHandler) { continue; } // get offset of the instruction that starts the try block if (tempTryBlock.firstBasicBlockOfTryBlock) { tryStart.Offset = tempBB.operations.ElementAt(0).Offset; oldExceptionHandlerMapping.tryStartOffset = tryStart.Offset; } // get offset of the instruction that ends the try block (always the last instruction of the basic block) if (tempTryBlock.lastBasicBlockOfTryBlock) { tryEnd.Offset = tempBB.operations.ElementAt(tempBB.operations.Count() - 1).Offset; // exception handler object needs offset of the end of the instruction (not the beginning) tryEnd.Offset += CfgBuilder.getSizeOfOperation(tempBB.operations.ElementAt(tempBB.operations.Count() - 1)); oldExceptionHandlerMapping.tryEndOffset = tryEnd.Offset; } } foreach (HandlerBlock tempHandlerBlock in tempBB.handlerBlocks) { // ignore handler blocks that do not belong to the current exception handler if (tempHandlerBlock.exceptionHandler != exceptionHandler) { continue; } // get offset ot the instruction that starts the handler block if (tempHandlerBlock.firstBasicBlockOfHandlerBlock) { handlerStart.Offset = tempBB.operations.ElementAt(0).Offset; oldExceptionHandlerMapping.handlerStartOffset = handlerStart.Offset; } // get offset of the instruction that ends the handler block if (tempHandlerBlock.lastBasicBlockOfHandlerBlock) { handlerEnd.Offset = tempBB.operations.ElementAt(tempBB.operations.Count() - 1).Offset; // exception handler object needs offset of the end of the instruction (not the beginning) handlerEnd.Offset += CfgBuilder.getSizeOfOperation(tempBB.operations.ElementAt(tempBB.operations.Count() - 1)); oldExceptionHandlerMapping.handlerEndOffset = handlerEnd.Offset; } } } // copy the exception handler filter filterStart.Offset = exceptionHandler.FilterDecisionStartOffset; oldExceptionHandlerMapping.filterStartOffset = filterStart.Offset; // add new exception handler oldExceptionHandlerMapping.exceptionType = exceptionHandler.ExceptionType; oldExceptionHandlerMapping.handlerKind = exceptionHandler.HandlerKind; ilGenerator.AddExceptionHandlerInformation(exceptionHandler.HandlerKind, exceptionHandler.ExceptionType, tryStart, tryEnd, handlerStart, handlerEnd, filterStart); } // create the body List<ILocalDefinition> variableListCopy = new List<ILocalDefinition>(method.Body.LocalVariables); List<ITypeDefinition> privateHelperTypesListCopy = new List<ITypeDefinition>(method.Body.PrivateHelperTypes); var newBody = new ILGeneratorMethodBody(ilGenerator, method.Body.LocalsAreZeroed, 8, method, variableListCopy, privateHelperTypesListCopy); // TODO dynamic max stack size? method.Body = newBody; // step six: replace pointer to the old exception handler with the new exception handler // map all old exception handler to the new objects foreach (IOperationExceptionInformation exceptionHandler in method.Body.OperationExceptionInformation) { // search for the new exception handler object to get the mapping to the old one bool found = false; foreach (OldExceptionHandlerMapping oldExceptionHandlerMapping in oldExceptionHandlerMappings) { if (oldExceptionHandlerMapping.exceptionType == exceptionHandler.ExceptionType && oldExceptionHandlerMapping.handlerKind == exceptionHandler.HandlerKind && oldExceptionHandlerMapping.filterStartOffset == exceptionHandler.FilterDecisionStartOffset && oldExceptionHandlerMapping.tryStartOffset == exceptionHandler.TryStartOffset && oldExceptionHandlerMapping.tryEndOffset == exceptionHandler.TryEndOffset && oldExceptionHandlerMapping.handlerStartOffset == exceptionHandler.HandlerStartOffset && oldExceptionHandlerMapping.handlerEndOffset == exceptionHandler.HandlerEndOffset) { oldExceptionHandlerMapping.newExceptionHandler = exceptionHandler; found = true; break; } } if (!found) { throw new ArgumentException("Not able to map old exception handler to new one."); } } // replace all old exception handler in the basic blocks with the new exception handler foreach (BasicBlock tempBB in methodCfg.basicBlocks) { // replace all exception handler in the try blocks foreach (TryBlock tryBlock in tempBB.tryBlocks) { foreach (OldExceptionHandlerMapping oldExceptionHandlerMapping in oldExceptionHandlerMappings) { if (tryBlock.exceptionHandler == oldExceptionHandlerMapping.oldExceptionHandler) { tryBlock.exceptionHandler = oldExceptionHandlerMapping.newExceptionHandler; break; } } } // replace all exception handler in the handler blocks foreach (HandlerBlock handlerBlock in tempBB.handlerBlocks) { foreach (OldExceptionHandlerMapping oldExceptionHandlerMapping in oldExceptionHandlerMappings) { if (handlerBlock.exceptionHandler == oldExceptionHandlerMapping.oldExceptionHandler) { handlerBlock.exceptionHandler = oldExceptionHandlerMapping.newExceptionHandler; break; } } } } // TODO // DEBUG /* // sanitize method name to store it as a file String invalidChars = System.Text.RegularExpressions.Regex.Escape(new string(System.IO.Path.GetInvalidFileNameChars())); String invalidRegStr = string.Format(@"([{0}]*\.+$)|([{0}]+)", invalidChars); String fileName = System.Text.RegularExpressions.Regex.Replace(methodCfg.method.ToString(), invalidRegStr, "_"); fileName = fileName.Length >= 230 ? fileName.Substring(0, 230) : fileName; // dump cfg created from the exit branches System.IO.StreamWriter dotFile = new System.IO.StreamWriter("e:\\" + "\\BBUnion_" + fileName + ".dot"); // start .dot file graph dotFile.WriteLine("digraph G {"); for (int bbuidx = 0; bbuidx < basicBlockUnions.Count(); bbuidx++) { BasicBlockUnion basicBlockUnion = basicBlockUnions.ElementAt(bbuidx); // write all basic blocks to .dot file for (int idx = 0; idx < basicBlockUnion.basicBlocks.Count(); idx++) { BasicBlock currentBasicBlock = basicBlockUnion.basicBlocks.ElementAt(idx); // write the current basic block to the file and all its instructions dotFile.WriteLine("BB" + bbuidx.ToString() + "_" + idx.ToString() + " [shape=record]"); bool first = true; for (int opIdx = 0; opIdx < currentBasicBlock.operations.Count(); opIdx++) { var operation = currentBasicBlock.operations.ElementAt(opIdx); if (first) { dotFile.Write("BB" + bbuidx.ToString() + "_" + idx.ToString() + " [label=\"{"); first = false; } else { dotFile.Write("|"); } // insert try block beginnings foreach (var tryBlock in currentBasicBlock.tryBlocks) { if (tryBlock.firstBasicBlockOfTryBlock && opIdx == 0) { dotFile.Write("TRY START (" + tryBlock.exceptionHandler.ExceptionType.ToString() + ")|"); } } // insert catch block beginnings foreach (var handlerBlock in currentBasicBlock.handlerBlocks) { if (handlerBlock.firstBasicBlockOfHandlerBlock && opIdx == 0) { if (handlerBlock.typeOfHandler == HandlerKind.Catch) { dotFile.Write("CATCH START (" + handlerBlock.exceptionHandler.ExceptionType.ToString() + ")|"); } else if (handlerBlock.typeOfHandler == HandlerKind.Finally) { dotFile.Write("FINALLY START (" + handlerBlock.exceptionHandler.ExceptionType.ToString() + ")|"); } else { throw new ArgumentException("Do not know how to handle handler."); } } } // check if instruction has an argument if (operation.Value != null) { dotFile.Write(operation.OperationCode.ToString() + " " + operation.Value.ToString()); } else { dotFile.Write(operation.OperationCode.ToString()); } // insert try block endings foreach (var tryBlock in currentBasicBlock.tryBlocks) { if (tryBlock.lastBasicBlockOfTryBlock && (currentBasicBlock.operations.Count() - 1) == opIdx) { dotFile.Write("|TRY END (" + tryBlock.exceptionHandler.ExceptionType.ToString() + ")"); } } // insert catch block endings foreach (var handlerBlock in currentBasicBlock.handlerBlocks) { if (handlerBlock.lastBasicBlockOfHandlerBlock && (currentBasicBlock.operations.Count() - 1) == opIdx) { if (handlerBlock.typeOfHandler == HandlerKind.Catch) { dotFile.Write("|CATCH END (" + handlerBlock.exceptionHandler.ExceptionType.ToString() + ")"); } else if (handlerBlock.typeOfHandler == HandlerKind.Finally) { dotFile.Write("|FINALLY END (" + handlerBlock.exceptionHandler.ExceptionType.ToString() + ")"); } else { throw new ArgumentException("Do not know how to handle handler."); } } } } dotFile.WriteLine("}\"]"); if ((idx + 1) < basicBlockUnion.basicBlocks.Count()) { dotFile.WriteLine("BB" + bbuidx.ToString() + "_" + idx.ToString() + " -> BB" + bbuidx.ToString() + "_" + (idx + 1).ToString() + "[ color=\"blue\" ]"); } } } // finish graph dotFile.WriteLine("}"); dotFile.Close(); */ }
private NamespaceTypeDefinition GenerateTypeB(IUnitNamespace rootNamespace, ITypeReference baseType) { var nt = Host.NameTable; var typeB = new NamespaceTypeDefinition { ContainingUnitNamespace = rootNamespace, Name = nt.GetNameFor("B"), InternFactory = Host.InternFactory, IsClass = true, BaseClasses = { baseType } }; var overrideGetMethod = new MethodDefinition { Name = nt.GetNameFor("Get"), IsCil = true, IsVirtual = true, Visibility = TypeMemberVisibility.Assembly, Type = Host.PlatformType.SystemString, ContainingTypeDefinition = typeB, InternFactory = Host.InternFactory }; typeB.Methods.Add(overrideGetMethod); var il = new ILGenerator(Host); var body = new ILGeneratorMethodBody(il, true, 1) {MethodDefinition = overrideGetMethod}; overrideGetMethod.Body = body; il.Emit(OperationCode.Ldstr, "1"); il.Emit(OperationCode.Ret); return typeB; }
// makes a copy of the method public void copyMethod(MethodDefinition dest, IMethodDefinition source) { // only copy body if it is not a dummy (= empty) if (!(source.Body is Microsoft.Cci.Dummy)) { // copy instructions ILGenerator ilGenerator = new ILGenerator(this.host, dest); foreach (var operation in source.Body.Operations) { ilGenerator.Emit(operation.OperationCode, operation.Value); } // copy the exception handler foreach (IOperationExceptionInformation exceptionToCopy in source.Body.OperationExceptionInformation) { ILGeneratorLabel tryStart = new ILGeneratorLabel(); tryStart.Offset = exceptionToCopy.TryStartOffset; ILGeneratorLabel tryEnd = new ILGeneratorLabel(); tryEnd.Offset = exceptionToCopy.TryEndOffset; ILGeneratorLabel handlerStart = new ILGeneratorLabel(); handlerStart.Offset = exceptionToCopy.HandlerStartOffset; ILGeneratorLabel handlerEnd = new ILGeneratorLabel(); handlerEnd.Offset = exceptionToCopy.HandlerEndOffset; ILGeneratorLabel filterStart = new ILGeneratorLabel(); filterStart.Offset = exceptionToCopy.FilterDecisionStartOffset; ilGenerator.AddExceptionHandlerInformation(exceptionToCopy.HandlerKind, exceptionToCopy.ExceptionType, tryStart, tryEnd, handlerStart, handlerEnd, filterStart); } // create the body List<ILocalDefinition> variableListCopy = new List<ILocalDefinition>(source.Body.LocalVariables); List<ITypeDefinition> privateHelperTypesListCopy = new List<ITypeDefinition>(source.Body.PrivateHelperTypes); var newBody = new ILGeneratorMethodBody(ilGenerator, source.Body.LocalsAreZeroed, source.Body.MaxStack, dest, variableListCopy, privateHelperTypesListCopy); dest.Body = newBody; } dest.CallingConvention = source.CallingConvention; if (source.IsGeneric) dest.GenericParameters = new List<IGenericMethodParameter>(source.GenericParameters); else dest.GenericParameters = null; if (source.ParameterCount > 0) dest.Parameters = new List<IParameterDefinition>(source.Parameters); else dest.Parameters = null; if (source.IsPlatformInvoke) dest.PlatformInvokeData = source.PlatformInvokeData; else dest.PlatformInvokeData = Dummy.PlatformInvokeInformation; dest.ReturnValueAttributes = new List<ICustomAttribute>(source.ReturnValueAttributes); if (source.ReturnValueIsModified) dest.ReturnValueCustomModifiers = new List<ICustomModifier>(source.ReturnValueCustomModifiers); else dest.ReturnValueCustomModifiers = new List<ICustomModifier>(0); if (source.ReturnValueIsMarshalledExplicitly) dest.ReturnValueMarshallingInformation = source.ReturnValueMarshallingInformation; else dest.ReturnValueMarshallingInformation = Dummy.MarshallingInformation; if (source.HasDeclarativeSecurity && IteratorHelper.EnumerableIsNotEmpty(source.SecurityAttributes)) dest.SecurityAttributes = new List<ISecurityAttribute>(source.SecurityAttributes); else dest.SecurityAttributes = null; dest.Type = source.Type; dest.AcceptsExtraArguments = source.AcceptsExtraArguments; dest.HasDeclarativeSecurity = source.HasDeclarativeSecurity; dest.IsAbstract = source.IsAbstract; dest.IsAccessCheckedOnOverride = source.IsAccessCheckedOnOverride; dest.IsCil = source.IsCil; dest.IsExternal = source.IsExternal; dest.IsForwardReference = source.IsForwardReference; dest.IsHiddenBySignature = source.IsHiddenBySignature; dest.IsNativeCode = source.IsNativeCode; dest.IsNewSlot = source.IsNewSlot; dest.IsNeverInlined = source.IsNeverInlined; dest.IsAggressivelyInlined = source.IsAggressivelyInlined; dest.IsNeverOptimized = source.IsNeverOptimized; dest.IsPlatformInvoke = source.IsPlatformInvoke; dest.IsRuntimeImplemented = source.IsRuntimeImplemented; dest.IsRuntimeInternal = source.IsRuntimeInternal; dest.IsRuntimeSpecial = source.IsRuntimeSpecial; dest.IsSealed = source.IsSealed; dest.IsSpecialName = source.IsSpecialName; dest.IsStatic = source.IsStatic; dest.IsSynchronized = source.IsSynchronized; dest.IsUnmanaged = source.IsUnmanaged; if (dest.IsStatic) dest.IsVirtual = false; else dest.IsVirtual = source.IsVirtual; dest.PreserveSignature = source.PreserveSignature; dest.RequiresSecurityObject = source.RequiresSecurityObject; dest.ReturnValueIsByRef = source.ReturnValueIsByRef; dest.ReturnValueIsMarshalledExplicitly = source.ReturnValueIsMarshalledExplicitly; dest.ReturnValueName = source.ReturnValueName; dest.Name = source.Name; dest.Visibility = source.Visibility; }
// 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 EmitStoreLocal(ILGenerator generator, IOperation op) { #region Emit: call Console.WriteLine("foo"); //generator.Emit(OperationCode.Ldstr, "foo"); //generator.Emit(OperationCode.Call, this.consoleDotWriteLine); #endregion Emit: call Console.WriteLine("foo"); string localName; switch (op.OperationCode) { case OperationCode.Stloc: case OperationCode.Stloc_S: ILocalDefinition loc = op.Value as ILocalDefinition; if (loc == null) throw new ILMutatorException("Stloc operation found without a valid operand"); if (TryGetLocalName(loc, out localName)) { generator.Emit(OperationCode.Ldstr, localName); generator.Emit(OperationCode.Call, this.consoleDotWriteLine); } break; case OperationCode.Stloc_0: if (this.currentLocals.Count < 1) throw new ILMutatorException("stloc.0 operation found but no corresponding local in method body"); if (TryGetLocalName(this.currentLocals[0], out localName)) { generator.Emit(OperationCode.Ldstr, localName); generator.Emit(OperationCode.Call, this.consoleDotWriteLine); } break; case OperationCode.Stloc_1: if (this.currentLocals.Count < 2) throw new ILMutatorException("stloc.1 operation found but no corresponding local in method body"); if (TryGetLocalName(this.currentLocals[1], out localName)) { generator.Emit(OperationCode.Ldstr, localName); generator.Emit(OperationCode.Call, this.consoleDotWriteLine); } break; case OperationCode.Stloc_2: if (this.currentLocals.Count < 3) throw new ILMutatorException("stloc.2 operation found but no corresponding local in method body"); if (TryGetLocalName(this.currentLocals[2], out localName)) { generator.Emit(OperationCode.Ldstr, localName); generator.Emit(OperationCode.Call, this.consoleDotWriteLine); } break; case OperationCode.Stloc_3: if (this.currentLocals.Count < 4) throw new ILMutatorException("stloc.3 operation found but no corresponding local in method body"); if (TryGetLocalName(this.currentLocals[3], out localName)) { generator.Emit(OperationCode.Ldstr, localName); generator.Emit(OperationCode.Call, this.consoleDotWriteLine); } break; default: throw new ILMutatorException("Should never get here: switch statement was meant to be exhaustive"); } }
// adds the given interface to the given class public void addInterface(NamespaceTypeDefinition addTargetClass, ITypeDefinition interfaceToAdd) { // add interface to target class if (addTargetClass.Interfaces != null) { // check if interface is already implemented by class if (addTargetClass.Interfaces.Contains(interfaceToAdd)) { this.logger.writeLine("Class \"" + addTargetClass.ToString() + "\" already implements interface \"" + interfaceToAdd.ToString() + "\""); return; } else { this.logger.writeLine("Add interface \"" + interfaceToAdd.ToString() + "\" to class \"" + addTargetClass.ToString() + "\""); addTargetClass.Interfaces.Add(interfaceToAdd); } } else { List<ITypeReference> interfaceList = new List<ITypeReference>(); interfaceList.Add(interfaceToAdd); addTargetClass.Interfaces = interfaceList; } // copy all attributes from the interface to the target class if (interfaceToAdd.Fields != null) { foreach (FieldDefinition field in interfaceToAdd.Fields) { FieldDefinition copy = new FieldDefinition(); this.helperClass.copyField(copy, field); copy.ContainingTypeDefinition = addTargetClass; // set intern factory of the copied field to the one of the class // (without it, the generated binary file will have strange results like use only the same field) copy.InternFactory = addTargetClass.InternFactory; addTargetClass.Fields.Add(copy); } } // copy all methods from the interface to the target class if (interfaceToAdd.Methods != null) { foreach (IMethodDefinition method in interfaceToAdd.Methods) { // search through all methods in the target class // to see if this method was already added bool foundMethod = false; foreach (IMethodDefinition tempMethod in addTargetClass.Methods) { // skip constructors if (tempMethod.IsConstructor) { continue; } // check if the number of parameters are the same if (tempMethod.ParameterCount == method.ParameterCount) { // check if the parameters have the same type in the same order bool parameterCorrect = true; for (int i = 0; i < method.ParameterCount; i++) { if (method.Parameters.ElementAt(i).Type != tempMethod.Parameters.ElementAt(i).Type) { parameterCorrect = false; break; } } // check if the return type is the same bool returnTypeCorrect = false; if (method.Type.Equals(tempMethod.Type)) { returnTypeCorrect = true; } // check if both methods are static // (c# compiler does not allow static + non-static function with // same signature in same class, but CIL does) bool bothStatic = false; if (method.IsStatic == tempMethod.IsStatic) { bothStatic = true; } // if the parameters and return type are correct => check the name if (parameterCorrect && returnTypeCorrect && bothStatic) { if (method.Name.Equals(tempMethod.Name)) { // if name is the same => method already added foundMethod = true; break; } } } } // skip if method was already added if (foundMethod) { this.logger.writeLine("Method \"" + method.Name.ToString() + "\" already exists"); continue; } this.logger.writeLine("Add method: " + method.Name.ToString()); // copy method MethodDefinition copy = new MethodDefinition(); this.helperClass.copyMethod(copy, method); copy.ContainingTypeDefinition = addTargetClass; // generate random dead code for newly created method ILGenerator ilGenerator = new ILGenerator(host, method); foreach (IOperation tempOperation in CodeGenerator.generateDeadCode(true)) { ilGenerator.Emit(tempOperation.OperationCode, tempOperation.Value); } IMethodBody newBody = new ILGeneratorMethodBody(ilGenerator, true, 8, method, Enumerable<ILocalDefinition>.Empty, Enumerable<ITypeDefinition>.Empty); copy.Body = newBody; // set intern factory of the copied method to the one of the class // (without it, the generated binary file will have strange results like call always the same method) copy.InternFactory = addTargetClass.InternFactory; // set method to not abstract copy.IsAbstract = false; // set method to not external copy.IsExternal = false; // set intern factory of the copied method to the one of the class // (without it, the generating of the binary file will have strange results) copy.InternFactory = addTargetClass.InternFactory; // add method to the class addTargetClass.Methods.Add(copy); } } }
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); } } }
public override ILGenerator DebugReplacementGeneratorForBody(IMethodBody methodBody) { var generator = new ILGenerator(host, methodBody.MethodDefinition); string warningText = "\n\n!!!!!!!!!!\nAttempt to execute garbage collected method: " + methodBody.MethodDefinition.ToString() + "\n\n"; // emit console warning generator.Emit(OperationCode.Ldstr, warningText); generator.Emit(OperationCode.Call, this.consoleWriteLine); // emit stack trace generator.Emit(OperationCode.Newobj, this.stackTraceConstructor); generator.Emit(OperationCode.Callvirt, this.toString); generator.Emit(OperationCode.Call, this.consoleWriteLine); // This will actually exit the app, assuming it is not caught. // Apparently there is no programmatic Exit(-1) in SilverLight for Windows Phone. Hmm. AppendEmitExceptionThrow(generator); return generator; }
static void copyMethod(MethodDefinition dest, IMethodDefinition source, PeReader.DefaultHost host) { // only copy body if it is not a dummy (= empty) if (!(source.Body is Microsoft.Cci.Dummy)) { // TODO // langsames kopieren des Bodies, schnellerer weg möglich? var testIlGenerator = new ILGenerator(host, dest); foreach (var operation in source.Body.Operations) { testIlGenerator.Emit(operation.OperationCode, operation.Value); } List<ILocalDefinition> variableListCopy = new List<ILocalDefinition>(source.Body.LocalVariables); List<ITypeDefinition> privateHelperTypesListCopy = new List<ITypeDefinition>(source.Body.PrivateHelperTypes); var newBody = new ILGeneratorMethodBody(testIlGenerator, source.Body.LocalsAreZeroed, source.Body.MaxStack, dest, variableListCopy, privateHelperTypesListCopy); dest.Body = newBody; } dest.CallingConvention = source.CallingConvention; if (source.IsGeneric) dest.GenericParameters = new List<IGenericMethodParameter>(source.GenericParameters); else dest.GenericParameters = null; if (source.ParameterCount > 0) dest.Parameters = new List<IParameterDefinition>(source.Parameters); else dest.Parameters = null; if (source.IsPlatformInvoke) dest.PlatformInvokeData = source.PlatformInvokeData; else dest.PlatformInvokeData = Dummy.PlatformInvokeInformation; dest.ReturnValueAttributes = new List<ICustomAttribute>(source.ReturnValueAttributes); if (source.ReturnValueIsModified) dest.ReturnValueCustomModifiers = new List<ICustomModifier>(source.ReturnValueCustomModifiers); else dest.ReturnValueCustomModifiers = new List<ICustomModifier>(0); if (source.ReturnValueIsMarshalledExplicitly) dest.ReturnValueMarshallingInformation = source.ReturnValueMarshallingInformation; else dest.ReturnValueMarshallingInformation = Dummy.MarshallingInformation; if (source.HasDeclarativeSecurity && IteratorHelper.EnumerableIsNotEmpty(source.SecurityAttributes)) dest.SecurityAttributes = new List<ISecurityAttribute>(source.SecurityAttributes); else dest.SecurityAttributes = null; dest.Type = source.Type; dest.AcceptsExtraArguments = source.AcceptsExtraArguments; dest.HasDeclarativeSecurity = source.HasDeclarativeSecurity; dest.IsAbstract = source.IsAbstract; dest.IsAccessCheckedOnOverride = source.IsAccessCheckedOnOverride; dest.IsCil = source.IsCil; dest.IsExternal = source.IsExternal; dest.IsForwardReference = source.IsForwardReference; dest.IsHiddenBySignature = source.IsHiddenBySignature; dest.IsNativeCode = source.IsNativeCode; dest.IsNewSlot = source.IsNewSlot; dest.IsNeverInlined = source.IsNeverInlined; dest.IsAggressivelyInlined = source.IsAggressivelyInlined; dest.IsNeverOptimized = source.IsNeverOptimized; dest.IsPlatformInvoke = source.IsPlatformInvoke; dest.IsRuntimeImplemented = source.IsRuntimeImplemented; dest.IsRuntimeInternal = source.IsRuntimeInternal; dest.IsRuntimeSpecial = source.IsRuntimeSpecial; dest.IsSealed = source.IsSealed; dest.IsSpecialName = source.IsSpecialName; dest.IsStatic = source.IsStatic; dest.IsSynchronized = source.IsSynchronized; dest.IsUnmanaged = source.IsUnmanaged; if (dest.IsStatic) dest.IsVirtual = false; else dest.IsVirtual = source.IsVirtual; dest.PreserveSignature = source.PreserveSignature; dest.RequiresSecurityObject = source.RequiresSecurityObject; dest.ReturnValueIsByRef = source.ReturnValueIsByRef; dest.ReturnValueIsMarshalledExplicitly = source.ReturnValueIsMarshalledExplicitly; dest.ReturnValueName = source.ReturnValueName; dest.Name = source.Name; dest.Visibility = source.Visibility; }
// 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; }