Ejemplo n.º 1
0
    void AddGuards()
    {
        foreach (var method in TargetType.Methods)
        {
            if (method.Name == ".ctor")
            {
                continue;
            }

            if (method.IsMatch("Finalize"))
            {
                continue;
            }

            if (method.IsStatic)
            {
                continue;
            }

            if (method.Name.StartsWith("Dispose"))
            {
                continue;
            }

            if (method.Name == "ThrowIfDisposed")
            {
                continue;
            }

            if (method.Name == "IsDisposed")
            {
                continue;
            }

            if (!method.HasBody)
            {
                continue;
            }

            if (method.IsPrivate)
            {
                continue;
            }

            var validSequencePoint = method.DebugInformation.SequencePoints.FirstOrDefault();
            method.Body.SimplifyMacros();
            var instructions = method.Body.Instructions;
            instructions.InsertAtStart(
                Instruction.Create(OpCodes.Ldarg_0),
                Instruction.Create(OpCodes.Call, throwIfDisposed));
            if (validSequencePoint != null)
            {
                CecilExtensions.HideLineFromDebugger(validSequencePoint);
            }

            method.Body.OptimizeMacros();
        }
    }
Ejemplo n.º 2
0
        public void should_return_false_on_null()
        {
            var context = new ModuleWeavingContext(null !, null !);

            CecilExtensions.IsInlineILTypeUsage(default(CustomAttribute), context).ShouldBeFalse();
            CecilExtensions.IsInlineILTypeUsage(default(FieldReference), context).ShouldBeFalse();
            CecilExtensions.IsInlineILTypeUsage(default(IMethodSignature), context).ShouldBeFalse();
            CecilExtensions.IsInlineILTypeUsage(default(ParameterDefinition), context).ShouldBeFalse();
            CecilExtensions.IsInlineILTypeUsage(default(TypeReference), context).ShouldBeFalse();
            CecilExtensions.IsInlineILTypeUsage(default(EventReference), context).ShouldBeFalse();
            CecilExtensions.IsInlineILTypeUsage(default(PropertyReference), context).ShouldBeFalse();
            CecilExtensions.IsInlineILTypeUsage(default(InterfaceImplementation), context).ShouldBeFalse();
            CecilExtensions.IsInlineILTypeUsage(default(GenericParameterConstraint), context).ShouldBeFalse();
            CecilExtensions.IsInlineILTypeUsageDeep(null, context).ShouldBeFalse();
        }
        //Check and enforce some restriction for IBufferElementData:
        // "Buffer element MUST have all fields annotated with the GhostFieldAttribute"
        //
        //This rule must be enforced to avoid having uninitialized data when a dynamic buffer is restored from the history
        //(see GhostPredictionHistorySystem.cs).
        //When a buffer is restored it might get resized and in that case, since we don't clear the buffer memory (for performance reason),
        //some portion of the data could be left untouched by the RestoreFromBackup function if some element fields are are not replicated.
        //The above requirement avoid that problem. We migh relax it later.
        private TypeDefinition[] CheckAndFilterInvalidGhostTypes(TypeDefinition[] ghostTypes)
        {
            bool CheckIsValid(TypeDefinition t)
            {
                if (CecilExtensions.IsBufferElementData(t) &&
                    t.Fields.Any(f => f.IsPublic && !f.HasAttribute <GhostFieldAttribute>()))
                {
                    Debug.LogError($"BufferElementData {t.FullName} has some members without a GhostField attribute.\n" +
                                   "In order to be replicated, BufferElementData requires that all fields must be annotated with a GhostField attribute.");
                    return(false);
                }
                return(true);
            }

            return(ghostTypes.Where(CheckIsValid).ToArray());
        }
Ejemplo n.º 4
0
 public static void WriteTo(this Instruction instruction, ITextOutput writer)
 {
     writer.WriteDefinition(CecilExtensions.OffsetToString(instruction.Offset), instruction);
     writer.Write(": ");
     writer.WriteReference(instruction.OpCode.Name, instruction.OpCode);
     if (instruction.Operand != null)
     {
         writer.Write(' ');
         if (instruction.OpCode == OpCodes.Ldtoken)
         {
             if (instruction.Operand is MethodReference)
             {
                 writer.Write("method ");
             }
             else if (instruction.Operand is FieldReference)
             {
                 writer.Write("field ");
             }
         }
         WriteOperand(writer, instruction.Operand);
     }
 }
Ejemplo n.º 5
0
        public SymbolicValue Eval(ILExpression expr)
        {
            SymbolicValue left, right;

            switch (expr.Code)
            {
            case ILCode.Sub:
                left  = Eval(expr.Arguments[0]);
                right = Eval(expr.Arguments[1]);
                if (left.Type != SymbolicValueType.State && left.Type != SymbolicValueType.IntegerConstant)
                {
                    return(Failed());
                }
                if (right.Type != SymbolicValueType.IntegerConstant)
                {
                    return(Failed());
                }
                return(new SymbolicValue(left.Type, unchecked (left.Constant - right.Constant)));

            case ILCode.Ldfld:
                if (Eval(expr.Arguments[0]).Type != SymbolicValueType.This)
                {
                    return(Failed());
                }
                if (CecilExtensions.ResolveWithinSameModule(expr.Operand as FieldReference) != stateField)
                {
                    return(Failed());
                }
                return(new SymbolicValue(SymbolicValueType.State));

            case ILCode.Ldloc:
                ILVariable loadedVariable = (ILVariable)expr.Operand;
                if (stateVariables.Contains(loadedVariable))
                {
                    return(new SymbolicValue(SymbolicValueType.State));
                }
                else if (loadedVariable.IsParameter && loadedVariable.OriginalParameter.Index < 0)
                {
                    return(new SymbolicValue(SymbolicValueType.This));
                }
                else
                {
                    return(Failed());
                }

            case ILCode.Ldc_I4:
                return(new SymbolicValue(SymbolicValueType.IntegerConstant, (int)expr.Operand));

            case ILCode.Ceq:
            case ILCode.Cne:
                left  = Eval(expr.Arguments[0]);
                right = Eval(expr.Arguments[1]);
                if (left.Type != SymbolicValueType.State || right.Type != SymbolicValueType.IntegerConstant)
                {
                    return(Failed());
                }
                // bool: (state + left.Constant == right.Constant)
                // bool: (state == right.Constant - left.Constant)
                return(new SymbolicValue(expr.Code == ILCode.Ceq ? SymbolicValueType.StateEquals : SymbolicValueType.StateInEquals, unchecked (right.Constant - left.Constant)));

            case ILCode.LogicNot:
                SymbolicValue val = Eval(expr.Arguments[0]);
                if (val.Type == SymbolicValueType.StateEquals)
                {
                    return(new SymbolicValue(SymbolicValueType.StateInEquals, val.Constant));
                }
                else if (val.Type == SymbolicValueType.StateInEquals)
                {
                    return(new SymbolicValue(SymbolicValueType.StateEquals, val.Constant));
                }
                else
                {
                    return(Failed());
                }

            default:
                return(Failed());
            }
        }
Ejemplo n.º 6
0
        void PrepareClassMethods(Type type)
        {
            var @class = GetClass(type);

            // Already processed?
            if (@class == null || @class.MethodCompiled)
            {
                return;
            }

            @class.MethodCompiled = true;

            // Array: no need to do anything (its type definition, Array, has already been processed)
            if (@class.Type.TypeReference is ArrayType)
            {
                return;
            }

            var typeDefinition = GetMethodTypeDefinition(@class.Type.TypeReference);

            bool isInterface = typeDefinition.IsInterface;

            // Process methods, Virtual first, then non virtual, then static
            foreach (var method in typeDefinition.Methods.OrderBy(x => x.IsVirtual ? 0 : (!x.IsStatic ? 1 : 2)))
            {
                var methodReference = ResolveGenericMethod(@class.Type.TypeReference, method);

                // If a method contains generic parameters, skip it
                // Its closed instantiations (with generic arguments) is what needs to be generated.
                // (except interface methods)
                // Using ResolveGenericsVisitor.ContainsGenericParameters because Cecil one's doesn't seem to match what .NET Type does.
                // TODO: Might need a more robust generic resolver/analyzer system soon.
                if (ResolveGenericsVisitor.ContainsGenericParameters(methodReference))
                {
                    continue;
                }

                var function = CreateFunction(methodReference);

                @class.Functions.Add(function);

                if (method.IsSpecialName && method.Name == ".cctor")
                {
                    @class.StaticCtor = function;
                }

                if (method.IsVirtual)
                {
                    if (isInterface)
                    {
                        // Store IMT slot
                        function.VirtualSlot = (int)(GetMethodId(methodReference) % InterfaceMethodTableSize);
                    }
                    else if (method.IsNewSlot)
                    {
                        // New slot
                        function.VirtualSlot = @class.VirtualTable.Count;
                        @class.VirtualTable.Add(function);
                    }
                    else
                    {
                        // Find slot in base types
                        var      baseType      = @class.BaseType;
                        Function matchedMethod = null;
                        while (baseType != null)
                        {
                            matchedMethod = CecilExtensions.TryMatchMethod(baseType, methodReference);
                            if (matchedMethod != null)
                            {
                                break;
                            }
                            baseType = baseType.BaseType;
                        }

                        if (matchedMethod == null)
                        {
                            throw new InvalidOperationException(string.Format("Could not find a slot for virtual function {0} in parents of class {1}", method, @class.Type.TypeReference));
                        }

                        function.VirtualSlot = matchedMethod.VirtualSlot;
                        @class.VirtualTable[function.VirtualSlot] = function;
                    }
                }
                else
                {
                    // New slot
                    function.VirtualSlot = @class.VirtualTable.Count;
                    @class.VirtualTable.Add(function);
                }
            }
        }
 public void WriteTo(TextWriter writer)
 {
     foreach (Instruction prefix in this.Prefixes)
     {
         Disassembler.DisassemblerHelpers.WriteTo(prefix, new PlainTextOutput(writer));
         writer.WriteLine();
     }
     if (Instruction != null && Instruction.Offset >= 0)
     {
         writer.Write(CecilExtensions.OffsetToString(Instruction.Offset));
         writer.Write(": ");
     }
     if (Target != null)
     {
         writer.Write(Target.ToString());
         writer.Write(" = ");
     }
     if (IsMoveInstruction)
     {
         writer.Write(Operands[0].ToString());
         if (Instruction != null)
         {
             writer.Write(" (" + Instruction.OpCode.Name + ")");
         }
     }
     else
     {
         if (Instruction == null)
         {
             writer.Write(SpecialOpCode.ToString());
         }
         else
         {
             writer.Write(Instruction.OpCode.Name);
             if (null != Instruction.Operand)
             {
                 writer.Write(' ');
                 Disassembler.DisassemblerHelpers.WriteOperand(new PlainTextOutput(writer), Instruction.Operand);
                 writer.Write(' ');
             }
         }
         if (TypeOperand != null)
         {
             writer.Write(' ');
             writer.Write(TypeOperand.ToString());
             writer.Write(' ');
         }
         if (Operands.Length > 0)
         {
             writer.Write('(');
             for (int i = 0; i < Operands.Length; i++)
             {
                 if (i > 0)
                 {
                     writer.Write(", ");
                 }
                 writer.Write(Operands[i].ToString());
             }
             writer.Write(')');
         }
     }
 }
Ejemplo n.º 8
0
        void CompileClassMethods(Class @class)
        {
            // Already processed?
            if (@class.MethodCompiled)
            {
                return;
            }

            @class.MethodCompiled = true;

            var typeDefinition = @class.TypeReference.Resolve();

            bool isInterface = typeDefinition.IsInterface;

            // Process methods
            foreach (var method in typeDefinition.Methods)
            {
                // If a method contains generic parameters, skip it
                // Its closed instantiations (with generic arguments) is what needs to be generated.
                if (method.ContainsGenericParameter())
                {
                    continue;
                }

                var methodReference = ResolveGenericMethod(@class.TypeReference, method);
                var function        = CreateFunction(methodReference);

                @class.Functions.Add(function);

                if (method.IsVirtual)
                {
                    if (isInterface)
                    {
                        // Store IMT slot
                        function.VirtualSlot = (int)(GetMethodId(methodReference) % InterfaceMethodTableSize);
                    }
                    else if (method.IsNewSlot)
                    {
                        // New slot
                        function.VirtualSlot = @class.VirtualTable.Count;
                        @class.VirtualTable.Add(function);
                    }
                    else
                    {
                        // Find slot in base types
                        var      baseType      = @class.BaseType;
                        Function matchedMethod = null;
                        while (baseType != null)
                        {
                            matchedMethod = CecilExtensions.TryMatchMethod(baseType, method);
                            if (matchedMethod != null)
                            {
                                break;
                            }
                            baseType = baseType.BaseType;
                        }

                        if (matchedMethod == null)
                        {
                            throw new InvalidOperationException(string.Format("Could not find a slot for virtual function {0} in parents of class {1}", method, @class.TypeReference));
                        }

                        function.VirtualSlot = matchedMethod.VirtualSlot;
                        @class.VirtualTable[function.VirtualSlot] = function;
                    }
                }
            }
        }
Ejemplo n.º 9
0
        private void BuildRuntimeType(Class @class)
        {
            if (@class.IsEmitted)
            {
                return;
            }

            @class.IsEmitted = true;

            // Build IMT
            var interfaceMethodTable = new LinkedList <InterfaceMethodTableEntry> [InterfaceMethodTableSize];

            foreach (var @interface in @class.Interfaces)
            {
                foreach (var interfaceMethod in @interface.Type.TypeReference.Resolve().Methods)
                {
                    var resolvedInterfaceMethod = ResolveGenericMethod(@interface.Type.TypeReference, interfaceMethod);

                    // If method is not fully resolved (generic method in interface), ignore it
                    // We are waiting for actual closed uses.
                    if (ResolveGenericsVisitor.ContainsGenericParameters(resolvedInterfaceMethod))
                    {
                        continue;
                    }

                    var resolvedFunction = CecilExtensions.TryMatchMethod(@class, resolvedInterfaceMethod);
                    if (resolvedFunction == null && @class.Type.TypeReference is ArrayType)
                    {
                        var arrayType      = corlib.MainModule.GetType(typeof(Array).FullName);
                        var matchingMethod = (MethodReference)arrayType.Methods.First(x => x.Name.StartsWith("InternalArray_") && x.Name.EndsWith(resolvedInterfaceMethod.Name));
                        if (matchingMethod != null)
                        {
                            if (matchingMethod.HasGenericParameters)
                            {
                                matchingMethod = matchingMethod.MakeGenericMethod(((ArrayType)@class.Type.TypeReference).ElementType);
                            }

                            resolvedFunction = GetFunction(matchingMethod);

                            // Manually emit Array functions locally (until proper mscorlib + generic instantiation exists).
                            EmitFunction(resolvedFunction);
                        }
                    }

                    if (resolvedFunction == null)
                    {
                        throw new InvalidOperationException(string.Format("Could not find matching method for {0} in {1}", resolvedInterfaceMethod, @class));
                    }

                    var isInterface = resolvedFunction.DeclaringType.TypeReference.Resolve().IsInterface;
                    if (!isInterface && resolvedFunction.MethodReference.Resolve().IsVirtual&& resolvedFunction.VirtualSlot != -1)
                    {
                        // We might have found a base virtual method matching this interface method.
                        // Let's get the actual method override for this virtual slot.
                        resolvedFunction = @class.VirtualTable[resolvedFunction.VirtualSlot];
                    }

                    // If method is not found, it could be due to covariance/contravariance
                    if (resolvedFunction == null)
                    {
                        throw new InvalidOperationException("Interface method not found");
                    }

                    var methodId     = GetMethodId(resolvedInterfaceMethod);
                    var imtSlotIndex = (int)(methodId % interfaceMethodTable.Length);

                    var imtSlot = interfaceMethodTable[imtSlotIndex];
                    if (imtSlot == null)
                    {
                        interfaceMethodTable[imtSlotIndex] = imtSlot = new LinkedList <InterfaceMethodTableEntry>();
                    }

                    imtSlot.AddLast(new InterfaceMethodTableEntry
                    {
                        Function  = resolvedFunction,
                        MethodId  = methodId,
                        SlotIndex = imtSlotIndex
                    });
                }
            }
            var interfaceMethodTableConstant = LLVM.ConstArray(intPtrType, interfaceMethodTable.Select(imtSlot =>
            {
                if (imtSlot == null)
                {
                    // No entries: null slot
                    return(LLVM.ConstNull(intPtrType));
                }

                if (imtSlot.Count == 1)
                {
                    // Single entry
                    var imtEntry = imtSlot.First.Value;
                    return(LLVM.ConstPointerCast(imtEntry.Function.GeneratedValue, intPtrType));
                }
                else
                {
                    // Multiple entries, create IMT array with all entries
                    // TODO: Support covariance/contravariance?
                    var imtEntries = LLVM.ConstArray(imtEntryType, imtSlot.Select(imtEntry =>
                    {
                        return(LLVM.ConstNamedStruct(imtEntryType, new[]
                        {
                            LLVM.ConstInt(int32Type, (ulong)imtEntry.MethodId, false),           // i32 functionId
                            LLVM.ConstPointerCast(imtEntry.Function.GeneratedValue, intPtrType), // i8* functionPtr
                        }));
                    })
                                                     .Concat(Enumerable.Repeat(LLVM.ConstNull(imtEntryType), 1)).ToArray()); // Append { 0, 0 } terminator
                    var imtEntryGlobal = LLVM.AddGlobal(module, LLVM.TypeOf(imtEntries), @class.Type.TypeReference.MangledName() + ".imt");
                    LLVM.SetInitializer(imtEntryGlobal, imtEntries);

                    // Add 1 to differentiate between single entry and IMT array
                    return(LLVM.ConstIntToPtr(
                               LLVM.ConstAdd(
                                   LLVM.ConstPtrToInt(imtEntryGlobal, nativeIntType),
                                   LLVM.ConstInt(nativeIntType, 1, false)),
                               intPtrType));
                }
            }).ToArray());


            // Build list of super types
            var superTypes   = new List <Class>(@class.Depth);
            var currentClass = @class;

            while (currentClass != null)
            {
                superTypes.Add(currentClass);
                currentClass = currentClass.BaseType;
            }

            // Reverse so that the list start with most inherited object
            // (allows faster type checking since a given type will always be at a given index)
            superTypes.Reverse();

            // Build super types
            // Helpful for fast is/as checks on class hierarchy
            var superTypeCount  = LLVM.ConstInt(int32Type, (ulong)@class.Depth + 1, false);
            var interfacesCount = LLVM.ConstInt(int32Type, (ulong)@class.Interfaces.Count, false);

            var zero = LLVM.ConstInt(int32Type, 0, false);

            // Super types global
            var superTypesConstantGlobal = LLVM.AddGlobal(module, LLVM.ArrayType(intPtrType, (uint)superTypes.Count),
                                                          @class.Type.TypeReference.MangledName() + ".supertypes");
            var superTypesGlobal = LLVM.ConstInBoundsGEP(superTypesConstantGlobal, new[] { zero, zero });

            // Interface map global
            var interfacesConstantGlobal = LLVM.AddGlobal(module, LLVM.ArrayType(intPtrType, (uint)@class.Interfaces.Count),
                                                          @class.Type.TypeReference.MangledName() + ".interfaces");
            var interfacesGlobal = LLVM.ConstInBoundsGEP(interfacesConstantGlobal, new[] { zero, zero });

            // Build VTable
            var vtableConstant = LLVM.ConstStructInContext(context, @class.VirtualTable.Select(x => x.GeneratedValue).ToArray(), false);

            // Build RTTI
            var runtimeTypeInfoGlobal       = @class.GeneratedRuntimeTypeInfoGlobal;
            var runtimeTypeInfoType         = LLVM.GetElementType(LLVM.TypeOf(runtimeTypeInfoGlobal));
            var runtimeTypeInfoTypeElements = new TypeRef[LLVM.CountStructElementTypes(runtimeTypeInfoType)];

            LLVM.GetStructElementTypes(runtimeTypeInfoType, runtimeTypeInfoTypeElements);
            var runtimeTypeInfoConstant = LLVM.ConstNamedStruct(runtimeTypeInfoType, new[]
            {
                @class.BaseType != null ? @class.BaseType.GeneratedRuntimeTypeInfoGlobal : LLVM.ConstPointerNull(intPtrType),
                superTypeCount,
                interfacesCount,
                superTypesGlobal,
                interfacesGlobal,
                LLVM.ConstInt(LLVM.Int1TypeInContext(context), 0, false), // Class initialized?
                interfaceMethodTableConstant,
                vtableConstant,
                LLVM.ConstNull(runtimeTypeInfoTypeElements[(int)RuntimeTypeInfoFields.StaticFields]),
            });

            LLVM.SetInitializer(runtimeTypeInfoGlobal, runtimeTypeInfoConstant);

            // Build super type list (after RTTI since we need pointer to RTTI)
            var superTypesConstant = LLVM.ConstArray(intPtrType,
                                                     superTypes.Select(superType => LLVM.ConstPointerCast(superType.GeneratedRuntimeTypeInfoGlobal, intPtrType))
                                                     .ToArray());

            LLVM.SetInitializer(superTypesConstantGlobal, superTypesConstant);

            // Build interface map
            var interfacesConstant = LLVM.ConstArray(intPtrType,
                                                     @class.Interfaces.Select(
                                                         @interface => LLVM.ConstPointerCast(@interface.GeneratedRuntimeTypeInfoGlobal, intPtrType)).ToArray());

            LLVM.SetInitializer(interfacesConstantGlobal, interfacesConstant);

            // Mark RTTI as external
            LLVM.SetLinkage(runtimeTypeInfoGlobal, Linkage.ExternalLinkage);
        }
Ejemplo n.º 10
0
 public static void WriteOffsetReference(ITextOutput writer, Instruction instruction)
 {
     writer.WriteReference(CecilExtensions.OffsetToString(instruction.Offset), instruction);
 }
Ejemplo n.º 11
0
        private void BuildRuntimeType(Class @class)
        {
            if (@class.IsEmitted)
            {
                return;
            }

            //Console.WriteLine("Build type {0}", @class);

            @class.IsEmitted = true;

            var  zero           = LLVM.ConstInt(int32LLVM, 0, false);
            bool isConcreteType = IsConcreteType(@class.Type);

            // Prepare metadata info
            var sharpLangModule = TestMode ? LLVM.ConstNull(intPtrLLVM) : metadataPerModule[@class.Type.TypeDefinitionCecil.Module];
            var extraTypeInfo   = LLVM.ConstNull(intPtrLLVM);

            var elementTypeSize = zero;

            // Build RTTI
            var runtimeTypeInfoGlobal       = @class.GeneratedEETypeTokenLLVM;
            var runtimeTypeInfoType         = LLVM.GetElementType(LLVM.TypeOf(runtimeTypeInfoGlobal));
            var runtimeTypeInfoTypeElements = new TypeRef[LLVM.CountStructElementTypes(runtimeTypeInfoType)];

            LLVM.GetStructElementTypes(runtimeTypeInfoType, runtimeTypeInfoTypeElements);

            var typeSpecification = @class.Type.TypeReferenceCecil as TypeSpecification;

            if (typeSpecification != null)
            {
                if (typeSpecification is ArrayType || typeSpecification is ByReferenceType || typeSpecification is PointerType)
                {
                    // Get element type
                    var elementType = GetType(typeSpecification.ElementType, TypeState.VTableEmitted);
                    elementTypeSize = LLVM.ConstIntCast(LLVM.SizeOf(elementType.DefaultTypeLLVM), int32LLVM, false);
                    extraTypeInfo   = LLVM.ConstPtrToInt(elementType.Class.GeneratedEETypeRuntimeLLVM, nativeIntLLVM);

                    if (typeSpecification is ArrayType)
                    {
                        extraTypeInfo = LLVM.ConstAdd(extraTypeInfo, LLVM.ConstInt(nativeIntLLVM, (int)ExtraTypeKind.Array, false));
                    }
                    else if (typeSpecification is ByReferenceType)
                    {
                        extraTypeInfo = LLVM.ConstAdd(extraTypeInfo, LLVM.ConstInt(nativeIntLLVM, (int)ExtraTypeKind.ByRef, false));
                    }
                    else if (typeSpecification is PointerType)
                    {
                        extraTypeInfo = LLVM.ConstAdd(extraTypeInfo, LLVM.ConstInt(nativeIntLLVM, (int)ExtraTypeKind.Pointer, false));
                    }

                    extraTypeInfo = LLVM.ConstIntToPtr(extraTypeInfo, intPtrLLVM);
                }

                var genericInstanceType = typeSpecification as GenericInstanceType;
                if (genericInstanceType != null)
                {
                    // Build global with array of VTable (one for each generic argument)
                    var genericArgumentsTypes           = genericInstanceType.GenericArguments.Select(x => GetType(x, TypeState.VTableEmitted)).ToArray();
                    var genericArgumentesTypeGlobalType = LLVM.ArrayType(intPtrLLVM, (uint)genericArgumentsTypes.Length + 1);
                    var genericArgumentsTypesGlobal     = LLVM.AddGlobal(module, genericArgumentesTypeGlobalType, @class.Type.TypeReferenceCecil.MangledName() + ".genericarguments");
                    LLVM.SetLinkage(genericArgumentsTypesGlobal, Linkage.PrivateLinkage);
                    LLVM.SetInitializer(genericArgumentsTypesGlobal, LLVM.ConstArray(intPtrLLVM,
                                                                                     genericArgumentsTypes
                                                                                     .Select(x => LLVM.ConstPointerCast(x.Class.GeneratedEETypeTokenLLVM, intPtrLLVM))
                                                                                     .Concat(new[] { LLVM.ConstPointerNull(intPtrLLVM) })
                                                                                     .ToArray()));
                    extraTypeInfo = LLVM.ConstInBoundsGEP(genericArgumentsTypesGlobal, new[] { zero, zero });
                    extraTypeInfo = LLVM.ConstPointerCast(extraTypeInfo, intPtrLLVM);
                }
            }

            var runtimeTypeFields = new List <ValueRef>
            {
                @class.BaseType != null ? @class.BaseType.GeneratedEETypeTokenLLVM : LLVM.ConstPointerNull(intPtrLLVM),
                LLVM.ConstInt(LLVM.Int8TypeInContext(context), isConcreteType ? 1U : 0U, false),
                LLVM.ConstNamedStruct(typeDefLLVM, new[]
                {
                    sharpLangModule,
                    LLVM.ConstInt(int32LLVM, @class.Type.TypeDefinitionCecil.MetadataToken.ToUInt32(), false),
                }),
                extraTypeInfo,
                LLVM.ConstNull(sharpLangTypeType.DefaultTypeLLVM),
            };

            // Prepare the runtime type object
            var mangledTypeName     = Regex.Replace(@class.Type.TypeReferenceCecil.MangledName() + ".sharplangtype", @"(\W)", "_");
            var sharpLangTypeGlobal = LLVM.AddGlobal(module, sharpLangTypeType.ObjectTypeLLVM, mangledTypeName);

            LLVM.SetLinkage(sharpLangTypeGlobal, Linkage.PrivateLinkage);
            LLVM.SetInitializer(sharpLangTypeGlobal, LLVM.ConstNull(sharpLangTypeType.ObjectTypeLLVM));

            if (isConcreteType)
            {
                // Build IMT
                var interfaceMethodTable = new LinkedList <InterfaceMethodTableEntry> [InterfaceMethodTableSize];
                foreach (var @interface in @class.Interfaces)
                {
                    foreach (var interfaceMethod in @interface.Type.TypeReferenceCecil.Resolve().Methods)
                    {
                        var resolvedInterfaceMethod = ResolveGenericMethod(@interface.Type.TypeReferenceCecil, interfaceMethod);

                        // If method is not fully resolved (generic method in interface), ignore it
                        // We are waiting for actual closed uses.
                        if (ResolveGenericsVisitor.ContainsGenericParameters(resolvedInterfaceMethod))
                        {
                            continue;
                        }

                        var resolvedFunction = CecilExtensions.TryMatchMethod(@class, resolvedInterfaceMethod);
                        if (resolvedFunction == null && @class.Type.TypeReferenceCecil is ArrayType)
                        {
                            var arrayType      = corlib.MainModule.GetType(typeof(Array).FullName);
                            var matchingMethod = (MethodReference)arrayType.Methods.First(x => x.Name.StartsWith("InternalArray_") && x.Name.EndsWith(resolvedInterfaceMethod.Name));
                            if (matchingMethod != null)
                            {
                                if (matchingMethod.HasGenericParameters)
                                {
                                    matchingMethod = matchingMethod.MakeGenericMethod(((ArrayType)@class.Type.TypeReferenceCecil).ElementType);
                                }

                                resolvedFunction = GetFunction(matchingMethod);

                                // Manually emit Array functions locally (until proper mscorlib + generic instantiation exists).
                                EmitFunction(resolvedFunction);
                                LLVM.SetLinkage(resolvedFunction.GeneratedValue, Linkage.LinkOnceAnyLinkage);
                            }
                        }

                        if (resolvedFunction == null)
                        {
                            throw new InvalidOperationException(string.Format("Could not find matching method for {0} in {1}", resolvedInterfaceMethod, @class));
                        }

                        var isInterface = resolvedFunction.DeclaringType.TypeReferenceCecil.Resolve().IsInterface;
                        if (!isInterface && resolvedFunction.MethodReference.Resolve().IsVirtual&& resolvedFunction.VirtualSlot != -1)
                        {
                            // We might have found a base virtual method matching this interface method.
                            // Let's get the actual method override for this virtual slot.
                            resolvedFunction = @class.VirtualTable[resolvedFunction.VirtualSlot];
                        }

                        // If method is not found, it could be due to covariance/contravariance
                        if (resolvedFunction == null)
                        {
                            throw new InvalidOperationException("Interface method not found");
                        }

                        var methodId     = GetMethodId(resolvedInterfaceMethod);
                        var imtSlotIndex = (int)(methodId % InterfaceMethodTableSize);

                        var imtSlot = interfaceMethodTable[imtSlotIndex];
                        if (imtSlot == null)
                        {
                            interfaceMethodTable[imtSlotIndex] = imtSlot = new LinkedList <InterfaceMethodTableEntry>();
                        }

                        imtSlot.AddLast(new InterfaceMethodTableEntry
                        {
                            Function = resolvedFunction,
                            MethodId = GetFunction(resolvedInterfaceMethod).GeneratedValue, // Should be a fake global, that we use as IMT key
                        });
                    }
                }
                var interfaceMethodTableConstant = LLVM.ConstArray(intPtrLLVM, interfaceMethodTable.Select(imtSlot =>
                {
                    if (imtSlot == null)
                    {
                        // No entries: null slot
                        return(LLVM.ConstNull(intPtrLLVM));
                    }

                    if (imtSlot.Count == 1)
                    {
                        // Single entry
                        var imtEntry = imtSlot.First.Value;
                        return(LLVM.ConstPointerCast(GetVirtualMethod(imtEntry.Function), intPtrLLVM));
                    }
                    else
                    {
                        // Multiple entries, create IMT array with all entries
                        // TODO: Support covariance/contravariance?
                        var imtEntries = LLVM.ConstArray(imtEntryLLVM, imtSlot.Select(imtEntry =>
                        {
                            return(LLVM.ConstNamedStruct(imtEntryLLVM, new[]
                            {
                                imtEntry.MethodId,                                                      // i8* functionId
                                LLVM.ConstPointerCast(GetVirtualMethod(imtEntry.Function), intPtrLLVM), // i8* functionPtr
                            }));
                        })
                                                         .Concat(Enumerable.Repeat(LLVM.ConstNull(imtEntryLLVM), 1)).ToArray()); // Append { 0, 0 } terminator
                        var imtEntryGlobal = LLVM.AddGlobal(module, LLVM.TypeOf(imtEntries), @class.Type.TypeReferenceCecil.MangledName() + ".imt");
                        LLVM.SetLinkage(imtEntryGlobal, Linkage.PrivateLinkage);
                        LLVM.SetInitializer(imtEntryGlobal, imtEntries);

                        // Add 1 to differentiate between single entry and IMT array
                        return(LLVM.ConstIntToPtr(
                                   LLVM.ConstAdd(
                                       LLVM.ConstPtrToInt(imtEntryGlobal, nativeIntLLVM),
                                       LLVM.ConstInt(nativeIntLLVM, 1, false)),
                                   intPtrLLVM));
                    }
                }).ToArray());


                // Build list of super types
                var superTypes   = new List <Class>(@class.Depth);
                var currentClass = @class;
                while (currentClass != null)
                {
                    superTypes.Add(currentClass);
                    currentClass = currentClass.BaseType;
                }

                // Reverse so that the list start with most inherited object
                // (allows faster type checking since a given type will always be at a given index)
                superTypes.Reverse();

                // Build super types
                // Helpful for fast is/as checks on class hierarchy
                var superTypeCount  = LLVM.ConstInt(int32LLVM, (ulong)@class.Depth + 1, false);
                var interfacesCount = LLVM.ConstInt(int32LLVM, (ulong)@class.Interfaces.Count, false);

                // Super types global
                var superTypesConstantGlobal = LLVM.AddGlobal(module, LLVM.ArrayType(intPtrLLVM, (uint)superTypes.Count),
                                                              @class.Type.TypeReferenceCecil.MangledName() + ".supertypes");
                LLVM.SetLinkage(superTypesConstantGlobal, Linkage.PrivateLinkage);
                var superTypesGlobal = LLVM.ConstInBoundsGEP(superTypesConstantGlobal, new[] { zero, zero });

                // Interface map global
                var interfacesConstantGlobal = LLVM.AddGlobal(module, LLVM.ArrayType(intPtrLLVM, (uint)@class.Interfaces.Count),
                                                              @class.Type.TypeReferenceCecil.MangledName() + ".interfaces");
                LLVM.SetLinkage(interfacesConstantGlobal, Linkage.PrivateLinkage);
                var interfacesGlobal = LLVM.ConstInBoundsGEP(interfacesConstantGlobal, new[] { zero, zero });

                // Build VTable
                var vtableConstant = LLVM.ConstNamedStruct(@class.VTableTypeLLVM, @class.VirtualTable.Select(x => GetVirtualMethod(x)).ToArray());

                var staticFieldsInitializer = LLVM.ConstNamedStruct(runtimeTypeInfoTypeElements[(int)RuntimeTypeInfoFields.StaticFields], @class.StaticFields.Select(field =>
                {
                    var fieldType = field.Value.Type;

                    if ((field.Key.Attributes & FieldAttributes.HasFieldRVA) != 0)
                    {
                        var initialValue = field.Key.InitialValue;

                        // Seems like if type size is 8, it uses int64 as backing type
                        // Maybe at some point it might be better to encode static fields in a big byte array and use casts instead?
                        if (LLVM.GetTypeKind(fieldType.DefaultTypeLLVM) == TypeKind.IntegerTypeKind)
                        {
                            unsafe
                            {
                                fixed(byte *initalValueStart = initialValue)
                                {
                                    if (LLVM.GetIntTypeWidth(fieldType.DefaultTypeLLVM) == 64)
                                    {
                                        return(LLVM.ConstInt(fieldType.DefaultTypeLLVM, *(ulong *)initalValueStart, false));
                                    }
                                    if (LLVM.GetIntTypeWidth(fieldType.DefaultTypeLLVM) == 32)
                                    {
                                        return(LLVM.ConstInt(fieldType.DefaultTypeLLVM, *(uint *)initalValueStart, false));
                                    }
                                }
                            }
                        }

                        // Otherwise, for now we assume that if there was a RVA, it was a type with custom layout (default type is i8[]),
                        // as currently generated by compiler in <PrivateImplementationDetails> class.
                        if (LLVM.GetTypeKind(fieldType.DefaultTypeLLVM) != TypeKind.ArrayTypeKind)
                        {
                            throw new NotSupportedException();
                        }

                        var arrayElementType = LLVM.Int8TypeInContext(context);
                        return(LLVM.ConstArray(arrayElementType, initialValue.Select(x => LLVM.ConstInt(arrayElementType, x, false)).ToArray()));
                    }

                    return(LLVM.ConstNull(fieldType.DefaultTypeLLVM));
                }).ToArray());

                runtimeTypeFields.AddRange(new[]
                {
                    superTypeCount,
                    interfacesCount,
                    superTypesGlobal,
                    interfacesGlobal,
                    LLVM.ConstInt(LLVM.Int8TypeInContext(context), 0, false), // Class initialized?
                    LLVM.ConstIntCast(LLVM.SizeOf(@class.Type.ObjectTypeLLVM), int32LLVM, false),
                    elementTypeSize,
                    interfaceMethodTableConstant,

                    LLVM.ConstInt(int32LLVM, (ulong)@class.VirtualTable.Count, false),
                    vtableConstant,
                    staticFieldsInitializer,
                });

                var runtimeTypeInfoConstant = LLVM.ConstNamedStruct(runtimeTypeInfoType, runtimeTypeFields.ToArray());
                LLVM.SetInitializer(runtimeTypeInfoGlobal, runtimeTypeInfoConstant);

                // Build super type list (after RTTI since we need pointer to RTTI)
                var superTypesConstant = LLVM.ConstArray(intPtrLLVM,
                                                         superTypes.Select(superType => LLVM.ConstPointerCast(superType.GeneratedEETypeTokenLLVM, intPtrLLVM))
                                                         .ToArray());
                LLVM.SetInitializer(superTypesConstantGlobal, superTypesConstant);

                // Build interface map
                var interfacesConstant = LLVM.ConstArray(intPtrLLVM,
                                                         @class.Interfaces.Select(
                                                             @interface => LLVM.ConstPointerCast(@interface.GeneratedEETypeTokenLLVM, intPtrLLVM)).ToArray());
                LLVM.SetInitializer(interfacesConstantGlobal, interfacesConstant);
            }
            else
            {
                // Non-concrete type, create type with current fields
                var runtimeTypeInfoConstant = LLVM.ConstNamedStruct(runtimeTypeInfoType, runtimeTypeFields.ToArray());
                LLVM.SetInitializer(runtimeTypeInfoGlobal, runtimeTypeInfoConstant);
            }

            // Mark RTTI as external
            LLVM.SetLinkage(runtimeTypeInfoGlobal, Linkage.ExternalLinkage);
        }
Ejemplo n.º 12
0
        // MethodReference ObjectDisposedExceptionRef;
        // MethodReference ExceptionRef;

        // enum OnFinalize
        // {
        //     Nothing,
        //     Dispose,
        //     Custom,
        // }

        public override void Execute()
        {
            var onFinalizeAttr = Config.Attributes().FirstOrDefault(x => x.Name == "OnFinalize").Value.ToString();
            // OnFinalize onFinalize = OnFinalize.Nothing;
            // MethodReference customMethod = null;
            MethodReference finalizer = null;

            if (!string.IsNullOrWhiteSpace(onFinalizeAttr))// && onFinalizeAttr.Contains('.'))
            {
                try
                {
                    finalizer = ModuleDefinition
                                .GetTypes()
                                .First(x =>
                                       x.IsClass &&
                                       x.FullName == Path.GetFileNameWithoutExtension(onFinalizeAttr)
                                       )
                                .Methods
                                .First(x =>
                                       x.IsStatic &&
                                       x.IsMatch(
                                           Path.GetExtension(onFinalizeAttr).TrimStart('.'),
                                           "IDisposable",
                                           ModuleDefinition.TypeSystem.Boolean.Name
                                           )
                                       );
                }
                catch {}

                if (finalizer == null)
                {
                    LogError($"Could not find static method '{onFinalizeAttr}(IDisposable, bool)'");
                    return;
                }
                else
                {
                    LogInfo($"Finalizer for disposable objects registered '{finalizer.FullName}'");
                }
            }

            /*switch (onFinalizeAttr?.Value.ToString())
             * {
             *  // case "Nothing":
             *  //     onFinalize = OnFinalize.Nothing;
             *  //     break;
             *  case "Dispose":
             *      onFinalize = OnFinalize.Dispose;
             *      break;
             *  case "Custom":
             *      onFinalize = OnFinalize.Custom;
             *      customMethod = ModuleDefinition
             *          .GetTypes()
             *          .Where(x =>
             *              x.IsClass &&
             *              !x.IsGeneratedCode() &&
             *              x.Methods.Any(x =>
             *                  x.IsStatic &&
             *                  x.CustomAttributes.ContainsOnFinalize() &&
             *                  x.IsMatch(ModuleDefinition.TypeSystem.Object.Name, ModuleDefinition.TypeSystem.Boolean.Name)
             *              )
             *          );
             *      if (customMethod == null)
             *      {
             *          LogError("Could not find static method with attribute 'DisposeGuard.Fody.OnFinalize'");
             *          return;
             *      }
             *      break;
             *      // default:
             *      //     onFinalize = OnFinalize.Nothing;
             *      //     break;
             *      // LogWarning("You must specify 'OnFinalize' parameter.");
             *      // return;
             * }*/

            var objectDisposedExceptionCtor = ModuleDefinition.ImportReference(
                FindType("System.ObjectDisposedException").Find(".ctor", "String")
                );
            var exceptionCtor = ModuleDefinition.ImportReference(
                FindType("System.Exception").Find(".ctor", "String")
                );

            foreach (var type in ModuleDefinition
                     .GetTypes()
                     .Where(x =>
                            x.IsClass &&
                                                 // !x.IsAbstract &&
                            !x.IsGeneratedCode() //&&
                                                 // !x.CustomAttributes.ContainsDoNotTrack()
                            )
                     )
            {
                // if (!type.Interfaces.Any(x => x.InterfaceType.FullName == "System.IDisposable"))
                // {
                //     continue;
                // }

                var disposeMethod = type.Methods
                                    .FirstOrDefault(x =>
                                                    !x.IsStatic &&
                                                    !x.HasParameters &&
                                                    (x.Name == "Dispose" || x.Name == "System.IDisposable.Dispose")
                                                    );

                if (disposeMethod == null)
                {
                    // LogInfo($"Cannot find dispose method in class {type.FullName}");
                    continue;
                }

                if (!isIDisposable(type))
                {
                    LogWarning($"Class '{type.FullName}' contains 'Dispose' method but not implements 'IDisposable' interface");
                    continue;
                }

                LogInfo($"Patching class '{type.FullName}'");

                var disposedField = createDisposedField();
                type.Fields.Add(disposedField);



                ////// MODIFY DISPOSE begin //////
                {
                    // var validSequencePoint = disposeMethod.DebugInformation.SequencePoints.FirstOrDefault();
                    disposeMethod.Body.SimplifyMacros();
                    disposeMethod.Body.Instructions.InsertAtStart(
                        Instruction.Create(OpCodes.Ldarg_0),
                        Instruction.Create(OpCodes.Ldc_I4_1),
                        Instruction.Create(OpCodes.Stfld, disposedField)
                        );
                    // if (validSequencePoint != null)
                    //     CecilExtensions.HideLineFromDebugger(validSequencePoint);
                    disposeMethod.Body.OptimizeMacros();
                }
                ////// MODIFY DISPOSE end //////



                var throwIfDisposedMethod = createThrowIfDisposedMethod(disposedField, type.FullName);
                type.Methods.Add(throwIfDisposedMethod);



                ////// ADD GUARDS begin //////
                foreach (var method in type.Methods)
                {
                    if (method.Name == ".ctor")
                    {
                        continue;
                    }
                    if (method.IsMatch("Finalize"))
                    {
                        continue;
                    }
                    if (method.IsStatic)
                    {
                        continue;
                    }
                    if (method.Name == "Dispose")
                    {
                        continue;
                    }
                    if (method.Name == "IsDisposed")
                    {
                        continue;
                    }
                    if (method.Name == throwIfDisposedMethod.Name)
                    {
                        continue;
                    }
                    // if (!method.HasBody)
                    //     continue;
                    if (method.IsPrivate)
                    {
                        continue;
                    }

                    var validSequencePoint = method.DebugInformation.SequencePoints.FirstOrDefault();
                    method.Body.SimplifyMacros();
                    method.Body.Instructions.InsertAtStart(
                        Instruction.Create(OpCodes.Ldarg_0),
                        Instruction.Create(OpCodes.Call, throwIfDisposedMethod)
                        );
                    if (validSequencePoint != null)
                    {
                        CecilExtensions.HideLineFromDebugger(validSequencePoint);
                    }
                    method.Body.OptimizeMacros();
                }
                ////// ADD GUARDS end //////



                ////// MODIFY FINALIZER begin //////
                MethodDefinition _finalizeMethod()
                {
                    var finalizeMethod = type.Methods.FirstOrDefault(x => !x.IsStatic && x.IsMatch("Finalize"));

                    if (finalizeMethod == null)
                    {
                        finalizeMethod = new MethodDefinition(
                            "Finalize",
                            MethodAttributes.HideBySig | MethodAttributes.Family | MethodAttributes.Virtual,
                            ModuleDefinition.TypeSystem.Void
                            );
                        finalizeMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
                        type.Methods.Add(finalizeMethod);
                    }
                    return(finalizeMethod);
                }

                if (finalizer != null)
                {
                    var method = _finalizeMethod();
                    method.Body.SimplifyMacros();
                    method.Body.Instructions.InsertAtStart(
                        Instruction.Create(OpCodes.Ldarg_0),
                        Instruction.Create(OpCodes.Ldarg_0),
                        Instruction.Create(OpCodes.Ldfld, disposedField),
                        Instruction.Create(OpCodes.Call, finalizer)
                        );
                    method.Body.OptimizeMacros();
                }

                /*switch (onFinalize)
                 * {
                 *  case OnFinalize.Dispose:
                 *      {
                 *          var method = _finalizeMethod();
                 *          method.Body.SimplifyMacros();
                 *          method.Body.Instructions.InsertAtStart(
                 *              Instruction.Create(OpCodes.Ldarg_0),
                 *              Instruction.Create(OpCodes.Call, disposeMethod)
                 *          );
                 *          method.Body.OptimizeMacros();
                 *      }
                 *      break;
                 *  case OnFinalize.Custom:
                 *      {
                 *          var method = _finalizeMethod();
                 *          method.Body.SimplifyMacros();
                 *          method.Body.Instructions.InsertAtStart(
                 *              Instruction.Create(OpCodes.Ldarg_0),
                 *              Instruction.Create(OpCodes.Ldarg_0),
                 *              Instruction.Create(OpCodes.Ldfld, disposedField),
                 *              Instruction.Create(OpCodes.Call, customMethod)
                 *          );
                 *          method.Body.OptimizeMacros();
                 *      }
                 *      break;
                 * }*/
                ////// MODIFY FINALIZER end //////

                // var disposeMethod = disposeMethods.FirstOrDefault(x => !x.HasParameters);
                // if (disposeMethod == null)
                // {
                //  // If the base type is not in the same assembly as the type we're processing
                //  // then we want to patch the Dispose method. If it is in the same
                //  // assembly then the patch code gets added to the Dispose method of the
                //  // base class, so we skip this type.
                //  if (type.BaseType.Scope == type.Scope)
                //      continue;

                //  disposeMethod = disposeMethods[0];
                // }

                // ProcessDisposeMethod(disposeMethod);

                // var constructors = type.Methods.Where(x => !x.IsStatic && x.IsConstructor).ToList();
                // if (constructors.Count != 0)
                // {
                //  foreach (var ctor in constructors)
                //  {
                //      ProcessConstructor(ctor);
                //  }
                // }
            }

            // CleanReferences();

            FieldDefinition createDisposedField()
            {
                return(new FieldDefinition(
                           "__disposed__" + suffix,
                           FieldAttributes.Private | FieldAttributes.HasFieldRVA,
                           ModuleDefinition.TypeSystem.Boolean
                           ));
            }

            MethodDefinition createThrowIfDisposedMethod(FieldDefinition disposedField, string className)
            {
                var method = new MethodDefinition(
                    "__ThrowIfDisposed__" + suffix,
                    MethodAttributes.Private | MethodAttributes.HideBySig,
                    ModuleDefinition.TypeSystem.Void
                    );

                var returnInstruction = Instruction.Create(OpCodes.Ret);

                method.Body.Instructions.InsertAtStart(
                    Instruction.Create(OpCodes.Ldarg_0),
                    Instruction.Create(OpCodes.Ldfld, disposedField),
                    Instruction.Create(OpCodes.Brfalse_S, returnInstruction),
                    Instruction.Create(OpCodes.Ldstr, className),
                    Instruction.Create(OpCodes.Newobj, objectDisposedExceptionCtor),
                    Instruction.Create(OpCodes.Throw),
                    returnInstruction
                    );

                return(method);
            }

            bool isIDisposable(TypeDefinition type)
            {
                if (type.Interfaces.Any(i => i.InterfaceType.FullName.Equals("System.IDisposable")))
                {
                    return(true);
                }
                if (type.FullName.Equals("System.IDisposable"))
                {
                    return(true);
                }
                return(type.BaseType != null && isIDisposable(type.BaseType.Resolve()));
            }
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Compiles the specified class.
        /// </summary>
        /// <param name="typeReference">The type definition.</param>
        /// <returns></returns>
        private Class CreateClass(TypeReference typeReference)
        {
            Class @class;

            if (classes.TryGetValue(typeReference, out @class))
            {
                return(@class);
            }

            bool processFields = false;

            switch (typeReference.MetadataType)
            {
            case MetadataType.Void:
            case MetadataType.Boolean:
            case MetadataType.Char:
            case MetadataType.Byte:
            case MetadataType.SByte:
            case MetadataType.Int16:
            case MetadataType.UInt16:
            case MetadataType.Int32:
            case MetadataType.UInt32:
            case MetadataType.Int64:
            case MetadataType.UInt64:
            case MetadataType.IntPtr:
            case MetadataType.UIntPtr:
            case MetadataType.Single:
            case MetadataType.Double:
            case MetadataType.String:
            {
                break;
            }

            case MetadataType.ValueType:
            case MetadataType.Class:
            case MetadataType.Object:
            case MetadataType.GenericInstance:
            {
                // Process non-static fields
                processFields = true;
                break;
            }

            default:
                throw new NotImplementedException();
            }

            var type = GetType(typeReference);

            // Create class version (boxed version with VTable)
            var boxedType = type.ObjectType;
            var dataType  = type.DataType;
            var stackType = type.StackType;

            @class = new Class(type, typeReference, dataType, boxedType, stackType);
            classes.Add(typeReference, @class);

            if (processFields)
            {
                var typeDefinition = typeReference.Resolve();

                var fieldTypes = new List <TypeRef>(typeDefinition.Fields.Count);

                var parentClass = typeDefinition.BaseType != null?GetClass(ResolveGenericsVisitor.Process(typeReference, typeDefinition.BaseType)) : null;

                // Add parent class
                if (parentClass != null)
                {
                    @class.BaseType = parentClass;

                    // Add parent classes
                    @class.VirtualTable.AddRange(parentClass.VirtualTable);
                    foreach (var @interface in parentClass.Interfaces)
                    {
                        @class.Interfaces.Add(@interface);
                    }
                }

                // Build methods slots
                // TODO: This will trigger their compilation, but maybe we might want to defer that later
                // (esp. since vtable is not built yet => recursion issues)
                CompileClassMethods(@class);

                if (typeDefinition.IsInterface)
                {
                    // Interface: No need for vtable, we can just use object's one
                    var vtableGlobal = GetClass(assembly.MainModule.Import(typeof(object))).GeneratedRuntimeTypeInfoGlobal;
                    LLVM.StructSetBody(boxedType, new[] { LLVM.TypeOf(vtableGlobal), dataType }, false);
                    @class.GeneratedRuntimeTypeInfoGlobal = vtableGlobal;
                }
                else
                {
                    // Get parent type RTTI
                    var runtimeTypeInfoType   = LLVM.PointerType(LLVM.Int8TypeInContext(context), 0);
                    var parentRuntimeTypeInfo = parentClass != null
                        ? LLVM.ConstPointerCast(parentClass.GeneratedRuntimeTypeInfoGlobal, runtimeTypeInfoType)
                        : LLVM.ConstPointerNull(runtimeTypeInfoType);

                    // Build vtable
                    var vtableConstant = LLVM.ConstStructInContext(context, @class.VirtualTable.Select(x => x.GeneratedValue).ToArray(), false);

                    // Build IMT
                    var interfaceMethodTable = new LinkedList <InterfaceMethodTableEntry> [InterfaceMethodTableSize];
                    foreach (var @interface in typeDefinition.Interfaces)
                    {
                        var resolvedInterface = ResolveGenericsVisitor.Process(typeReference, @interface);
                        @class.Interfaces.Add(GetClass(resolvedInterface));

                        // TODO: Add any inherited interface inherited by the resolvedInterface as well
                    }

                    foreach (var @interface in @class.Interfaces)
                    {
                        foreach (var interfaceMethod in @interface.TypeReference.Resolve().Methods)
                        {
                            var resolvedInterfaceMethod = ResolveGenericMethod(@interface.TypeReference, interfaceMethod);

                            var resolvedFunction = CecilExtensions.TryMatchMethod(@class, resolvedInterfaceMethod);

                            // If method is not found, it could be due to covariance/contravariance
                            if (resolvedFunction == null)
                            {
                                throw new InvalidOperationException("Interface method not found");
                            }

                            var methodId     = GetMethodId(resolvedInterfaceMethod);
                            var imtSlotIndex = (int)(methodId % interfaceMethodTable.Length);

                            var imtSlot = interfaceMethodTable[imtSlotIndex];
                            if (imtSlot == null)
                            {
                                interfaceMethodTable[imtSlotIndex] = imtSlot = new LinkedList <InterfaceMethodTableEntry>();
                            }

                            imtSlot.AddLast(new InterfaceMethodTableEntry {
                                Function = resolvedFunction, MethodId = methodId, SlotIndex = imtSlotIndex
                            });
                        }
                    }
                    var interfaceMethodTableConstant = LLVM.ConstArray(imtEntryType, interfaceMethodTable.Select(imtSlot =>
                    {
                        if (imtSlot == null)
                        {
                            // No entries: null slot
                            return(LLVM.ConstNull(imtEntryType));
                        }

                        if (imtSlot.Count > 1)
                        {
                            throw new NotImplementedException("IMT with more than one entry per slot is not implemented yet.");
                        }

                        var imtEntry = imtSlot.First.Value;
                        return(LLVM.ConstNamedStruct(imtEntryType, new[]
                        {
                            LLVM.ConstPointerCast(imtEntry.Function.GeneratedValue, intPtrType),                // i8* functionPtr
                            LLVM.ConstInt(int32Type, (ulong)imtEntry.MethodId, false),                          // i32 functionId
                            LLVM.ConstPointerNull(LLVM.PointerType(imtEntryType, 0)),                           // IMTEntry* nextSlot
                        }));
                    }).ToArray());

                    // Build static fields
                    foreach (var field in typeDefinition.Fields)
                    {
                        if (!field.IsStatic)
                        {
                            continue;
                        }

                        var fieldType = CreateType(assembly.MainModule.Import(ResolveGenericsVisitor.Process(typeReference, field.FieldType)));
                        @class.Fields.Add(field, new Field(field, @class, fieldType, fieldTypes.Count));
                        fieldTypes.Add(fieldType.DefaultType);
                    }

                    var staticFieldsEmpty = LLVM.ConstNull(LLVM.StructTypeInContext(context, fieldTypes.ToArray(), false));
                    fieldTypes.Clear(); // Reused for non-static fields after

                    // Build RTTI
                    var runtimeTypeInfoConstant = LLVM.ConstStructInContext(context, new[] { parentRuntimeTypeInfo, interfaceMethodTableConstant, vtableConstant, staticFieldsEmpty }, false);
                    var vtableGlobal            = LLVM.AddGlobal(module, LLVM.TypeOf(runtimeTypeInfoConstant), string.Empty);
                    LLVM.SetInitializer(vtableGlobal, runtimeTypeInfoConstant);
                    LLVM.StructSetBody(boxedType, new[] { LLVM.TypeOf(vtableGlobal), dataType }, false);
                    @class.GeneratedRuntimeTypeInfoGlobal = vtableGlobal;
                }

                // Build actual type data (fields)
                // Add fields and vtable slots from parent class
                if (parentClass != null && typeReference.MetadataType == MetadataType.Class)
                {
                    fieldTypes.Add(parentClass.DataType);
                }

                foreach (var field in typeDefinition.Fields)
                {
                    if (field.IsStatic)
                    {
                        continue;
                    }

                    var fieldType = CreateType(assembly.MainModule.Import(ResolveGenericsVisitor.Process(typeReference, field.FieldType)));
                    @class.Fields.Add(field, new Field(field, @class, fieldType, fieldTypes.Count));
                    fieldTypes.Add(fieldType.DefaultType);
                }

                LLVM.StructSetBody(dataType, fieldTypes.ToArray(), false);
            }

            return(@class);
        }
 static FieldDefinition GetFieldDefinition(FieldReference field)
 {
     return(CecilExtensions.ResolveWithinSameModule(field));
 }
Ejemplo n.º 15
0
        public override void Execute()
        {
//            Debugger.Launch();

            var soMeta = ModuleDefinition.FindAssembly("Someta");

            CecilExtensions.LogInfo    = LogInfo;
            CecilExtensions.LogWarning = LogWarning;
            CecilExtensions.LogError   = LogError;
            CecilExtensions.Initialize(ModuleDefinition, TypeSystem, soMeta);

            var extensionPointInterface          = ModuleDefinition.FindType("Someta", "IExtensionPoint", soMeta);
            var stateExtensionPointInterface     = ModuleDefinition.FindType("Someta", "IStateExtensionPoint`1", soMeta, "T");
            var stateExtensionPointInterfaceBase = ModuleDefinition.FindType("Someta", "IStateExtensionPoint", soMeta);
            var propertyGetInterceptorInterface  = ModuleDefinition.FindType("Someta", "IPropertyGetInterceptor", soMeta);
            var propertySetInterceptorInterface  = ModuleDefinition.FindType("Someta", "IPropertySetInterceptor", soMeta);
            var eventAddInterceptorInterface     = ModuleDefinition.FindType("Someta", "IEventAddInterceptor", soMeta);
            var eventRemoveInterceptorInterface  = ModuleDefinition.FindType("Someta", "IEventRemoveInterceptor", soMeta);
            var methodInterceptorInterface       = ModuleDefinition.FindType("Someta", "IMethodInterceptor", soMeta);
            var asyncMethodInterceptorInterface  = ModuleDefinition.FindType("Someta", "IAsyncMethodInterceptor", soMeta);
            var nonPublicAccessInterface         = ModuleDefinition.FindType("Someta", "INonPublicAccess", soMeta);
            var asyncInvoker       = ModuleDefinition.FindType("Someta.Helpers", "AsyncInvoker", soMeta);
            var asyncInvokerWrap   = ModuleDefinition.FindMethod(asyncInvoker, "Wrap");
            var asyncInvokerUnwrap = ModuleDefinition.FindMethod(asyncInvoker, "Unwrap");
            var instanceInitializerInterfaceBase = ModuleDefinition.FindType("Someta", "IInstanceInitializer", soMeta);
            var instanceInitializerInterface     = ModuleDefinition.FindType("Someta", "IInstanceInitializer`1", soMeta, "T");
//            var interceptorScopeAttribute = ModuleDefinition.FindType("Someta", "InterceptorScopeAttribute", soMeta);
//            var requireScopeInterceptorInterface = ModuleDefinition.FindType("Someta", "IRequireScopeInterceptor", soMeta);

            var extensionPointScopesClass           = ModuleDefinition.FindType("Someta", "ExtensionPointScopes", soMeta);
            var extensionPointScopesClassDefinition = extensionPointScopesClass.Resolve();
//            var interceptorScopeInterface = interceptorScopesClassDefinition.NestedTypes.Single(x => x.Name == "Scope");
            var extensionPointScopePropertyInterface = extensionPointScopesClassDefinition.NestedTypes.Single(x => x.Name == "Property");
            var extensionPointScopeMethodInterface   = extensionPointScopesClassDefinition.NestedTypes.Single(x => x.Name == "Method");
            var extensionPointScopeClassInterface    = extensionPointScopesClassDefinition.NestedTypes.Single(x => x.Name == "Class");

            var propertyGetInterceptions = new List <(PropertyDefinition, ExtensionPointAttribute)>();
            var propertySetInterceptions = new List <(PropertyDefinition, ExtensionPointAttribute)>();
            var eventAddInterceptions    = new List <(EventDefinition, ExtensionPointAttribute)>();
            var eventRemoveInterceptions = new List <(EventDefinition, ExtensionPointAttribute)>();
            var methodInterceptions      = new List <(MethodDefinition, ExtensionPointAttribute)>();
            var asyncMethodInterceptions = new List <(MethodDefinition, ExtensionPointAttribute)>();
            var classEnhancers           = new List <(TypeDefinition, ExtensionPointAttribute)>();
            var stateInterceptions       = new List <(IMemberDefinition, ExtensionPointAttribute)>();
            var instanceInitializers     = new List <(IMemberDefinition, ExtensionPointAttribute)>();

            var propertyGetInterceptorWeaver = new PropertyGetInterceptorWeaver(CecilExtensions.Context, propertyGetInterceptorInterface);
            var propertySetInterceptorWeaver = new PropertySetInterceptorWeaver(CecilExtensions.Context, propertySetInterceptorInterface);
            var eventInterceptorWeaver       = new EventInterceptorWeaver(CecilExtensions.Context);
            var methodInterceptorWeaver      = new MethodInterceptorWeaver(CecilExtensions.Context, methodInterceptorInterface, asyncMethodInterceptorInterface);
            var asyncMethodInterceptorWeaver = new AsyncMethodInterceptorWeaver(CecilExtensions.Context, asyncMethodInterceptorInterface, asyncInvokerWrap, asyncInvokerUnwrap);
            var classEnhancerWeaver          = new ClassEnhancerWeaver(CecilExtensions.Context);
            var stateWeaver = new StateWeaver(CecilExtensions.Context);
            var instanceInitializerWeaver = new InstanceInitializerWeaver(CecilExtensions.Context);

            // unscopedInterface: If present, and if genericTypes is empty (meaning no specific scope was specified),
            // unscopedInterface will be checked as a fallback.
            bool HasScope(ExtensionPointAttribute interceptor, TypeReference interfaceType, ExtensionPointScope scope, TypeReference unscopedInterface = null)
            {
                var genericTypes = interceptor.AttributeType.FindGenericInterfaces(interfaceType).ToArray();

                foreach (var genericType in genericTypes)
                {
                    var           argument       = genericType.GenericArguments[0];
                    TypeReference scopeInterface = null;
                    switch (scope)
                    {
                    case ExtensionPointScope.Class:
                        scopeInterface = extensionPointScopeClassInterface;
                        break;

                    case ExtensionPointScope.Property:
                        scopeInterface = extensionPointScopePropertyInterface;
                        break;

                    case ExtensionPointScope.Method:
                        scopeInterface = extensionPointScopeMethodInterface;
                        break;
                    }

                    if (argument.CompareTo(scopeInterface))
                    {
                        return(true);
                    }
                }

                // If no scope was specified, we consider the scope satisfied if an unscoped version is satisfied
                // Furthermore, the scope must match the member type.
                var isScopeMatchedWithMember = interceptor.Scope == scope;

                return(unscopedInterface != null && genericTypes.Length == 0 && unscopedInterface.IsAssignableFrom(interceptor.AttributeType) && isScopeMatchedWithMember);
            }

            // Inventory candidate classes
            var allTypes = ModuleDefinition.GetAllTypes();
            var assemblyInterceptorAttributes = ModuleDefinition.Assembly
                                                .GetCustomAttributesIncludingSubtypes(extensionPointInterface)
                                                .ToArray();

            ExtensionPointAttribute[] assemblyInterceptors;

            // If we have any assembly-level interceptors, we create a special state class to hold the attribute instances (since attributes
            // can contain state, but getting attributes through reflection always returns a new instance.
            if (assemblyInterceptorAttributes.Any())
            {
//                Debugger.Launch();
                var assemblyState = new TypeDefinition("Someta", "AssemblyState", TypeAttributes.Public, TypeSystem.ObjectReference);
                ModuleDefinition.Types.Add(assemblyState);

/*
 *              var constructorWithTarget = new MethodDefinition(".ctor", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, TypeSystem.VoidReference);
 *              constructorWithTarget.Body.Emit(il =>
 *              {
 *                  il.Emit(OpCodes.Ret);
 *              });
 *              assemblyState.Methods.Add(constructorWithTarget);
 */

                CecilExtensions.Context.AssemblyState = assemblyState;
                assemblyInterceptors = assemblyInterceptorAttributes
                                       .Select(x => new ExtensionPointAttribute(assemblyState, ModuleDefinition.Assembly, x, ModuleDefinition.Assembly.CustomAttributes.IndexOf(x), ExtensionPointScope.Assembly))
                                       .ToArray();

                foreach (var interceptor in assemblyInterceptors)
                {
                    var fieldName      = interceptor.AttributeType.FullName.Replace(".", "$");
                    var attributeField = new FieldDefinition(fieldName, FieldAttributes.Static | FieldAttributes.Public, interceptor.AttributeType);
                    var index          = ModuleDefinition.Assembly.CustomAttributes.IndexOf(interceptor.Attribute);
                    assemblyState.Fields.Add(attributeField);

                    assemblyState.EmitToStaticConstructor(il =>
                    {
                        il.EmitGetAssemblyAttributeByIndex(index, interceptor.AttributeType);
                        il.SaveField(attributeField);
                    });
                }
            }
            else
            {
                assemblyInterceptors = new ExtensionPointAttribute[0];
            }

//            var moduleInterceptors = ModuleDefinition
//                .GetCustomAttributesIncludingSubtypes(extensionPointInterface)
//                .Select(x => new ExtensionPointAttribute(null, ModuleDefinition, x, ModuleDefinition.CustomAttributes.IndexOf(x), ExtensionPointScope.Module))
//                .ToArray();
//            var assemblyAndModuleInterceptors = assemblyInterceptors.Concat(moduleInterceptors).ToArray();
            foreach (var type in allTypes)
            {
                // We can get into recursion scenarios if we allow extension points on extension points.  For now, let's naively prohibit this
                if (extensionPointInterface.IsAssignableFrom(type))
                {
                    continue;
                }

                var classInterceptors = type
                                        .GetCustomAttributesInAncestry(extensionPointInterface)
                                        .Select(x => new ExtensionPointAttribute(x.DeclaringType, x.DeclaringType, x.Attribute, x.DeclaringType.CustomAttributes.IndexOf(x.Attribute), ExtensionPointScope.Class))
                                        .Concat(assemblyInterceptors /*.Select(x => new ExtensionPointAttribute(type, x.DeclaringMember, x.Attribute, x.Index, x.Scope))*/)
                                        .ToArray();

                foreach (var classInterceptor in classInterceptors)
                {
                    LogInfo($"Found class interceptor {classInterceptor.AttributeType}");
                    if (nonPublicAccessInterface.IsAssignableFrom(classInterceptor.AttributeType))
                    {
                        LogInfo($"Discovered class enhancer {classInterceptor.AttributeType.FullName} at {type.FullName}");
                        classEnhancers.Add((type, classInterceptor));
                    }
                    if (HasScope(classInterceptor, stateExtensionPointInterface, ExtensionPointScope.Class, stateExtensionPointInterfaceBase))
                    {
                        LogInfo($"Discovered class state interceptor {classInterceptor.AttributeType.FullName} at {type.FullName}");
                        stateInterceptions.Add((type, classInterceptor));
                    }
                    if (HasScope(classInterceptor, instanceInitializerInterface, ExtensionPointScope.Class, instanceInitializerInterfaceBase))
                    {
                        LogInfo($"Discovered instance initializer {classInterceptor.AttributeType.FullName} at {type.FullName}");
                        instanceInitializers.Add((type, classInterceptor));
                    }
                }

                foreach (var property in type.Properties)
                {
                    var interceptors = property.GetCustomAttributesIncludingSubtypes(extensionPointInterface)
                                       .Select(x => new ExtensionPointAttribute(type, property, x, property.CustomAttributes.IndexOf(x), ExtensionPointScope.Property))
                                       .Concat(classInterceptors);
                    foreach (var interceptor in interceptors)
                    {
                        if (propertyGetInterceptorInterface.IsAssignableFrom(interceptor.AttributeType))
                        {
                            LogInfo($"Discovered property get interceptor {interceptor.AttributeType.FullName} at {type.FullName}.{property.Name}");
                            propertyGetInterceptions.Add((property, interceptor));
                        }
                        if (propertySetInterceptorInterface.IsAssignableFrom(interceptor.AttributeType))
                        {
                            LogInfo($"Discovered property set interceptor {interceptor.AttributeType.FullName} at {type.FullName}.{property.Name}");
                            propertySetInterceptions.Add((property, interceptor));
                        }
                        if (HasScope(interceptor, stateExtensionPointInterface, ExtensionPointScope.Property, stateExtensionPointInterfaceBase))
                        {
                            LogInfo($"Discovered property state interceptor {interceptor.AttributeType.FullName} at {type.FullName}.{property.Name}");
                            stateInterceptions.Add((property, interceptor));
                        }
                        if (HasScope(interceptor, instanceInitializerInterface, ExtensionPointScope.Property, instanceInitializerInterfaceBase))
                        {
                            LogInfo($"Discovered instance initializer {interceptor.AttributeType.FullName} at {type.FullName}");
                            instanceInitializers.Add((property, interceptor));
                        }
                    }
                }

                foreach (var @event in type.Events)
                {
//                    Debugger.Launch();
                    var interceptors = @event.GetCustomAttributesIncludingSubtypes(extensionPointInterface)
                                       .Select(x => new ExtensionPointAttribute(type, @event, x, @event.CustomAttributes.IndexOf(x), ExtensionPointScope.Event))
                                       .Concat(classInterceptors);

                    foreach (var interceptor in interceptors)
                    {
                        if (eventAddInterceptorInterface.IsAssignableFrom(interceptor.AttributeType))
                        {
                            LogInfo($"Discovered event add interceptor {interceptor.AttributeType.FullName} at {type.FullName}.{@event.Name}");
                            eventAddInterceptions.Add((@event, interceptor));
                        }
                        if (eventRemoveInterceptorInterface.IsAssignableFrom(interceptor.AttributeType))
                        {
                            LogInfo($"Discovered event remove interceptor {interceptor.AttributeType.FullName} at {type.FullName}.{@event.Name}");
                            eventRemoveInterceptions.Add((@event, interceptor));
                        }
                    }
                }

                foreach (var method in type.Methods.Where(x => !x.IsConstructor))
                {
                    var interceptors = method.GetCustomAttributesIncludingSubtypes(extensionPointInterface)
                                       .Select(x => new ExtensionPointAttribute(type, method, x, method.CustomAttributes.IndexOf(x), ExtensionPointScope.Method))
                                       .Concat(classInterceptors);
                    foreach (var interceptor in interceptors)
                    {
                        if (methodInterceptorInterface.IsAssignableFrom(interceptor.AttributeType))
                        {
                            LogInfo($"Discovered method interceptor {interceptor.AttributeType.FullName} at {type.FullName}.{method.Name}");
                            methodInterceptions.Add((method, interceptor));
                        }
                        if (asyncMethodInterceptorInterface.IsAssignableFrom(interceptor.AttributeType))
                        {
                            LogInfo($"Discovered async method interceptor {interceptor.AttributeType.FullName} at {type.FullName}.{method.Name}");
                            asyncMethodInterceptions.Add((method, interceptor));
                        }
                        if (HasScope(interceptor, stateExtensionPointInterface, ExtensionPointScope.Method, stateExtensionPointInterfaceBase))
                        {
                            LogInfo($"Discovered method state interceptor {interceptor.AttributeType.FullName} at {type.FullName}.{method.Name}");
                            stateInterceptions.Add((method, interceptor));
                        }
                        if (HasScope(interceptor, instanceInitializerInterface, ExtensionPointScope.Method, instanceInitializerInterfaceBase))
                        {
                            LogInfo($"Discovered instance initializer {interceptor.AttributeType.FullName} at {type.FullName}");
                            instanceInitializers.Add((method, interceptor));
                        }
                    }
                }
            }

            foreach (var(property, interceptor) in propertyGetInterceptions)
            {
                propertyGetInterceptorWeaver.Weave(property, interceptor);
            }

            foreach (var(property, interceptor) in propertySetInterceptions)
            {
                propertySetInterceptorWeaver.Weave(property, interceptor);
            }

            foreach (var(@event, interceptor) in eventAddInterceptions)
            {
                eventInterceptorWeaver.Weave(@event, interceptor, isAdd: true);
            }

            foreach (var(@event, interceptor) in eventRemoveInterceptions)
            {
                eventInterceptorWeaver.Weave(@event, interceptor, isAdd: false);
            }

            foreach (var(method, interceptor) in methodInterceptions)
            {
                methodInterceptorWeaver.Weave(method, interceptor);
            }

            foreach (var(method, interceptor) in asyncMethodInterceptions)
            {
                asyncMethodInterceptorWeaver.Weave(method, interceptor);
            }

            foreach (var(type, interceptor) in classEnhancers)
            {
                classEnhancerWeaver.Weave(type, interceptor);
            }

            foreach (var(member, interceptor) in stateInterceptions)
            {
                stateWeaver.Weave(member, interceptor);
            }

            foreach (var(type, interceptor) in instanceInitializers)
            {
                instanceInitializerWeaver.Weave(type, interceptor);
            }
        }
 static MethodDefinition GetMethodDefinition(MethodReference method)
 {
     return(CecilExtensions.ResolveWithinSameModule(method));
 }
Ejemplo n.º 17
0
        public DataConverterGenerator(IAssemblyResolver assemblyResolver, AssemblyDefinition assembly)
        {
            this.assembly = assembly;

            // Early exit if Serialization assembly is not referenced.
            AssemblyDefinition mscorlibAssembly;

            try
            {
                // In case assembly has been modified,
                // add AssemblyProcessedAttribute to assembly so that it doesn't get processed again
                mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assembly);
                if (mscorlibAssembly == null)
                {
                    throw new InvalidOperationException("Missing mscorlib.dll from assembly");
                }
            }
            catch
            {
                return;
            }

            listType       = mscorlibAssembly.MainModule.GetTypeResolved(typeof(List <>).FullName);
            dictionaryType = mscorlibAssembly.MainModule.GetTypeResolved(typeof(Dictionary <,>).FullName);

            this.dataPropertyTypeVisitor = new DataPropertyTypeVisitor(this);

            // Process types with DataConverterAttribute
            foreach (var type in assembly.EnumerateTypes())
            {
                // Generic types are not supported.
                if (type.HasGenericParameters)
                {
                    continue;
                }

                // Do not allow nested type to be generic (not properly supported, since it could be the enclosing type which is generic)
                if (!(type.IsPublic || (type.IsNestedPublic && !type.HasGenericParameters)))
                {
                    continue;
                }

                var dataInfo = this.GenerateDataTypeInfo(type);
                if (dataInfo != null)
                {
                    var dataConverterInfo = new DataConverterInfo
                    {
                        Generate = (dataInfo.Flags & DataTypeFlags.Generated) != 0,
                        DataInfo = dataInfo,
                        Type     = this.GetDataConverterType(type),
                    };

                    this.processedTypes.Add(type, dataInfo);
                    this.processedConverterTypes.Add(type, dataConverterInfo);
                }

                var additionalConverterAttribute = GetAdditionalDataAttribute(type);
                if (additionalConverterAttribute != null)
                {
                    var baseTypeArgument  = GetAdditionalBaseType(type);
                    var dataConverterInfo = new DataConverterInfo
                    {
                        DataInfo = this.GenerateDataTypeInfo(baseTypeArgument),
                        Type     = this.GetDataConverterType(type),
                    };

                    foreach (var namedArgument in additionalConverterAttribute.Properties)
                    {
                        switch (namedArgument.Name)
                        {
                        case "AutoGenerate":
                            dataConverterInfo.Generate = (bool)namedArgument.Argument.Value;
                            break;
                        }
                    }

                    this.processedConverterTypes.Add(type, dataConverterInfo);
                }
            }
        }