internal static void EnsureFieldLayoutLoadedForGenericType(DefType type)
        {
            if (type.NativeLayoutFields != null)
            {
                return;
            }

            if (!type.IsTemplateUniversal())
            {
                // We can hit this case where the template of type in question is not a universal canonical type.
                // Example:
                //  BaseType<T> { ... }
                //  DerivedType<T, U> : BaseType<T> { ... }
                // and an instantiation like DerivedType<string, int>. In that case, BaseType<string> will have a non-universal
                // template type, and requires special handling to compute its size and field layout.
                EnsureFieldLayoutLoadedForNonUniversalType(type);
            }
            else
            {
                TypeBuilderState state             = type.GetOrCreateTypeBuilderState();
                NativeParser     typeInfoParser    = state.GetParserForNativeLayoutInfo();
                NativeParser     fieldLayoutParser = typeInfoParser.GetParserForBagElementKind(BagElementKind.FieldLayout);
                EnsureFieldLayoutLoadedForUniversalType(type, state.NativeLayoutInfo.LoadContext, fieldLayoutParser);
            }
        }
        internal void GetFieldSizeAlignment(TypeDesc fieldType, out LayoutInt size, out LayoutInt alignment)
        {
            Debug.Assert(!fieldType.IsCanonicalSubtype(CanonicalFormKind.Any));

            // All reference and array types are pointer-sized
            if (!fieldType.IsValueType)
            {
                size      = new LayoutInt(IntPtr.Size);
                alignment = new LayoutInt(IntPtr.Size);
                return;
            }

            // Is this a type that already exists? If so, get its size from the EEType directly
            if (fieldType.RetrieveRuntimeTypeHandleIfPossible())
            {
                unsafe
                {
                    EEType *eeType = fieldType.RuntimeTypeHandle.ToEETypePtr();
                    size      = new LayoutInt((int)eeType->ValueTypeSize);
                    alignment = new LayoutInt(eeType->FieldAlignmentRequirement);
                    return;
                }
            }

            // The type of the field must be a generic valuetype that is dynamically being constructed
            Debug.Assert(fieldType.IsValueType);
            DefType fieldDefType = (DefType)fieldType;

            TypeBuilderState state = fieldType.GetOrCreateTypeBuilderState();

            size      = fieldDefType.InstanceFieldSize;
            alignment = fieldDefType.InstanceFieldAlignment;
        }
Beispiel #3
0
        // Get the GC layout of a type. Handles pre-created, universal template, and non-universal template cases
        // Only to be used for getting the instance layout of non-valuetypes.
        /// <summary>
        /// Get the GC layout of a type. Handles pre-created, universal template, and non-universal template cases
        /// Only to be used for getting the instance layout of non-valuetypes that are used as base types
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private unsafe TypeBuilder.GCLayout GetInstanceGCLayout(TypeDesc type)
        {
            Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Any));
            Debug.Assert(!type.IsValueType);

            if (type.RetrieveRuntimeTypeHandleIfPossible())
            {
                return(new TypeBuilder.GCLayout(type.RuntimeTypeHandle));
            }

            if (type.IsTemplateCanonical())
            {
                var  templateType = type.ComputeTemplate();
                bool success      = templateType.RetrieveRuntimeTypeHandleIfPossible();
                Debug.Assert(success && !templateType.RuntimeTypeHandle.IsNull());

                return(new TypeBuilder.GCLayout(templateType.RuntimeTypeHandle));
            }
            else
            {
                TypeBuilderState state = type.GetOrCreateTypeBuilderState();
                if (state.InstanceGCLayout == null)
                {
                    return(TypeBuilder.GCLayout.None);
                }
                else
                {
                    return(new TypeBuilder.GCLayout(state.InstanceGCLayout, true));
                }
            }
        }
Beispiel #4
0
        private ComputedStaticFieldLayout ParseStaticRegionSizesFromNativeLayout(TypeDesc type)
        {
            LayoutInt nonGcDataSize  = LayoutInt.Zero;
            LayoutInt gcDataSize     = LayoutInt.Zero;
            LayoutInt threadDataSize = LayoutInt.Zero;

            TypeBuilderState state          = type.GetOrCreateTypeBuilderState();
            NativeParser     typeInfoParser = state.GetParserForNativeLayoutInfo();

            BagElementKind kind;

            while ((kind = typeInfoParser.GetBagElementKind()) != BagElementKind.End)
            {
                switch (kind)
                {
                case BagElementKind.NonGcStaticDataSize:
                    TypeLoaderLogger.WriteLine("Found BagElementKind.NonGcStaticDataSize");
                    // Use checked typecast to int to ensure there aren't any overflows/truncations (size value used in allocation of memory later)
                    nonGcDataSize = new LayoutInt(checked ((int)typeInfoParser.GetUnsigned()));
                    break;

                case BagElementKind.GcStaticDataSize:
                    TypeLoaderLogger.WriteLine("Found BagElementKind.GcStaticDataSize");
                    // Use checked typecast to int to ensure there aren't any overflows/truncations (size value used in allocation of memory later)
                    gcDataSize = new LayoutInt(checked ((int)typeInfoParser.GetUnsigned()));
                    break;

                case BagElementKind.ThreadStaticDataSize:
                    TypeLoaderLogger.WriteLine("Found BagElementKind.ThreadStaticDataSize");
                    // Use checked typecast to int to ensure there aren't any overflows/truncations (size value used in allocation of memory later)
                    threadDataSize = new LayoutInt(checked ((int)typeInfoParser.GetUnsigned()));
                    break;

                default:
                    typeInfoParser.SkipInteger();
                    break;
                }
            }

            ComputedStaticFieldLayout staticLayout = new ComputedStaticFieldLayout()
            {
                GcStatics = new StaticsBlock()
                {
                    Size = gcDataSize, LargestAlignment = DefType.MaximumAlignmentPossible
                },
                NonGcStatics = new StaticsBlock()
                {
                    Size = nonGcDataSize, LargestAlignment = DefType.MaximumAlignmentPossible
                },
                Offsets       = null, // We're not computing field offsets here, so return null
                ThreadStatics = new StaticsBlock()
                {
                    Size = threadDataSize, LargestAlignment = DefType.MaximumAlignmentPossible
                },
            };

            return(staticLayout);
        }
Beispiel #5
0
        public static RuntimeTypeHandle CreatePointerEEType(UInt32 hashCodeOfNewType, RuntimeTypeHandle pointeeTypeHandle, TypeDesc pointerType)
        {
            TypeBuilderState state = new TypeBuilderState(pointerType);

            CreateEETypeWorker(typeof(void *).TypeHandle.ToEETypePtr(), hashCodeOfNewType, 0, false, state);
            Debug.Assert(!state.HalfBakedRuntimeTypeHandle.IsNull());

            state.HalfBakedRuntimeTypeHandle.ToEETypePtr()->RelatedParameterType = pointeeTypeHandle.ToEETypePtr();

            return(state.HalfBakedRuntimeTypeHandle);
        }
Beispiel #6
0
        private bool ComputeHasDictionaryInVTable()
        {
            if (!HasDictionarySlotInVTable)
            {
                return(false);
            }

            if (TypeBeingBuilt.RetrieveRuntimeTypeHandleIfPossible())
            {
                // Type was already constructed
                return(TypeBeingBuilt.RuntimeTypeHandle.GetDictionary() != IntPtr.Zero);
            }
            else
            {
                // Type is being newly constructed
                if (TemplateType != null)
                {
                    NativeParser parser = GetParserForNativeLayoutInfo();
                    // Template type loader case
#if GENERICS_FORCE_USG
                    bool isTemplateUniversalCanon = state.TemplateType.IsCanonicalSubtype(CanonicalFormKind.UniversalCanonLookup);
                    if (isTemplateUniversalCanon && type.CanShareNormalGenericCode())
                    {
                        TypeBuilderState tempState = new TypeBuilderState();
                        tempState.NativeLayoutInfo = new NativeLayoutInfo();
                        tempState.TemplateType     = type.Context.TemplateLookup.TryGetNonUniversalTypeTemplate(type, ref tempState.NativeLayoutInfo);
                        if (tempState.TemplateType != null)
                        {
                            Debug.Assert(!tempState.TemplateType.IsCanonicalSubtype(CanonicalFormKind.UniversalCanonLookup));
                            parser = GetNativeLayoutInfoParser(type, ref tempState.NativeLayoutInfo);
                        }
                    }
#endif
                    var dictionaryLayoutParser = parser.GetParserForBagElementKind(BagElementKind.DictionaryLayout);

                    return(!dictionaryLayoutParser.IsNull);
                }
                else
                {
                    NativeParser parser = GetParserForReadyToRunNativeLayoutInfo();
                    // ReadyToRun case
                    // Dictionary is directly encoded instead of the NativeLayout being a collection of bags
                    if (parser.IsNull)
                    {
                        return(false);
                    }

                    // First unsigned value in the native layout is the number of dictionary entries
                    return(parser.GetUnsigned() != 0);
                }
            }
        }
Beispiel #7
0
        private static void CreateInstanceGCDesc(TypeBuilderState state, EEType *pTemplateEEType, EEType *pEEType, int baseSize, int cbGCDesc, bool isValueType, bool isArray, bool isSzArray, int arrayRank)
        {
            var gcBitfield = state.InstanceGCLayout;

            if (isArray)
            {
                if (cbGCDesc != 0)
                {
                    pEEType->HasGCPointers = true;
                    if (state.IsArrayOfReferenceTypes)
                    {
                        IntPtr *gcDescStart = (IntPtr *)((byte *)pEEType - cbGCDesc);
                        gcDescStart[0] = new IntPtr(-baseSize);
                        gcDescStart[1] = new IntPtr(baseSize - sizeof(IntPtr));
                        gcDescStart[2] = new IntPtr(1);
                    }
                    else
                    {
                        CreateArrayGCDesc(gcBitfield, arrayRank, isSzArray, ((void **)pEEType) - 1);
                    }
                }
                else
                {
                    pEEType->HasGCPointers = false;
                }
            }
            else if (gcBitfield != null)
            {
                if (cbGCDesc != 0)
                {
                    pEEType->HasGCPointers = true;
                    CreateGCDesc(gcBitfield, baseSize, isValueType, false, ((void **)pEEType) - 1);
                }
                else
                {
                    pEEType->HasGCPointers = false;
                }
            }
            else if (pTemplateEEType != null)
            {
                Buffer.MemoryCopy((byte *)pTemplateEEType - cbGCDesc, (byte *)pEEType - cbGCDesc, cbGCDesc, cbGCDesc);
                pEEType->HasGCPointers = pTemplateEEType->HasGCPointers;
            }
            else
            {
                pEEType->HasGCPointers = false;
            }
        }
Beispiel #8
0
        public static RuntimeTypeHandle CreateEEType(TypeDesc type, TypeBuilderState state)
        {
            Debug.Assert(type != null && state != null);

            EEType *pTemplateEEType          = null;
            bool    requireVtableSlotMapping = false;

            if (type is PointerType)
            {
                Debug.Assert(0 == state.NonGcDataSize);
                Debug.Assert(false == state.HasStaticConstructor);
                Debug.Assert(0 == state.GcDataSize);
                Debug.Assert(0 == state.ThreadStaticOffset);
                Debug.Assert(0 == state.NumSealedVTableEntries);
                Debug.Assert(IntPtr.Zero == state.GcStaticDesc);
                Debug.Assert(IntPtr.Zero == state.ThreadStaticDesc);
                RuntimeTypeHandle templateTypeHandle = typeof(void *).TypeHandle;
                pTemplateEEType = templateTypeHandle.ToEETypePtr();
            }
            else if ((type is MetadataType) && (state.TemplateType == null || !state.TemplateType.RetrieveRuntimeTypeHandleIfPossible()))
            {
                requireVtableSlotMapping = true;
                pTemplateEEType          = null;
            }
            else if (type.IsMdArray)
            {
                pTemplateEEType          = typeof(object[, ]).TypeHandle.ToEETypePtr();
                requireVtableSlotMapping = false;
            }
            else
            {
                Debug.Assert(state.TemplateType != null && !state.TemplateType.RuntimeTypeHandle.IsNull());
                requireVtableSlotMapping = state.TemplateType.IsCanonicalSubtype(CanonicalFormKind.Universal);
                RuntimeTypeHandle templateTypeHandle = state.TemplateType.RuntimeTypeHandle;
                pTemplateEEType = templateTypeHandle.ToEETypePtr();
            }

            DefType typeAsDefType = type as DefType;
            // Use a checked typecast to 'ushort' for the arity to ensure its value never exceeds 65535 and cause integer
            // overflows later when computing size of memory blocks to allocate for the type and its GenericInstanceDescriptor structures
            int arity = checked ((ushort)((typeAsDefType != null && typeAsDefType.HasInstantiation ? typeAsDefType.Instantiation.Length : 0)));

            CreateEETypeWorker(pTemplateEEType, (uint)type.GetHashCode(), arity, requireVtableSlotMapping, state);

            return(state.HalfBakedRuntimeTypeHandle);
        }
Beispiel #9
0
        private static unsafe int GetInstanceGCDescSize(TypeBuilderState state, EEType *pTemplateEEType, bool isValueType, bool isArray)
        {
            var gcBitfield = state.InstanceGCLayout;

            if (isArray)
            {
                if (state.IsArrayOfReferenceTypes)
                {
                    // Reference type arrays have a GC desc the size of 3 pointers
                    return(3 * sizeof(IntPtr));
                }
                else
                {
                    int series = 0;
                    if (gcBitfield != null)
                    {
                        series = CreateArrayGCDesc(gcBitfield, 1, true, null);
                    }

                    return(series > 0 ? (series + 2) * IntPtr.Size : 0);
                }
            }
            else if (gcBitfield != null)
            {
                int series = CreateGCDesc(gcBitfield, 0, isValueType, false, null);
                return(series > 0 ? (series * 2 + 1) * IntPtr.Size : 0);
            }
            else if (pTemplateEEType != null)
            {
                return(RuntimeAugments.GetGCDescSize(pTemplateEEType->ToRuntimeTypeHandle()));
            }
            else
            {
                return(0);
            }
        }
        /// <summary>
        /// Add information about dynamically created non-generic native format type
        /// to the diagnostic stream in form of a NativeFormatType blob.
        /// </summary>
        /// <param name="typeBuilder">TypeBuilder is used to query runtime type handle for the type</param>
        /// <param name="defType">Type to emit to the diagnostic stream</param>
        /// <param name="state"></param>
        public static void RegisterDebugDataForNativeFormatType(TypeBuilder typeBuilder, DefType defType, TypeBuilderState state)
        {
#if SUPPORTS_NATIVE_METADATA_TYPE_LOADING
            NativeFormatType nativeFormatType = defType as NativeFormatType;
            if (nativeFormatType == null)
            {
                return;
            }

            NativePrimitiveEncoder encoder = new NativePrimitiveEncoder();
            encoder.Init();

            byte nativeFormatTypeFlags = 0;

            SerializeDataBlobTypeAndFlags(
                ref encoder,
                SerializedDataBlobKind.NativeFormatType,
                nativeFormatTypeFlags);

            TypeManagerHandle moduleHandle = ModuleList.Instance.GetModuleForMetadataReader(nativeFormatType.MetadataReader);

            encoder.WriteUnsignedLong(unchecked ((ulong)typeBuilder.GetRuntimeTypeHandle(defType).ToIntPtr().ToInt64()));
            encoder.WriteUnsigned(nativeFormatType.Handle.ToHandle(nativeFormatType.MetadataReader).AsUInt());
            encoder.WriteUnsignedLong(unchecked ((ulong)moduleHandle.GetIntPtrUNSAFE().ToInt64()));

            Instance.ThreadSafeWriteBytes(encoder.GetBytes());
#else
            return;
#endif
        }
Beispiel #11
0
        public static RuntimeTypeHandle CreateEEType(TypeDesc type, TypeBuilderState state)
        {
            Debug.Assert(type != null && state != null);

            EEType* pTemplateEEType = null;
            bool requireVtableSlotMapping = false;

            if (type is PointerType)
            {
                Debug.Assert(0 == state.NonGcDataSize);
                Debug.Assert(false == state.HasStaticConstructor);
                Debug.Assert(0 == state.GcDataSize);
                Debug.Assert(0 == state.ThreadStaticOffset);
                Debug.Assert(0 == state.NumSealedVTableEntries);
                Debug.Assert(IntPtr.Zero == state.GcStaticDesc);
                Debug.Assert(IntPtr.Zero == state.ThreadStaticDesc);
                RuntimeTypeHandle templateTypeHandle = typeof(void*).TypeHandle;
                pTemplateEEType = templateTypeHandle.ToEETypePtr();
            }
            else if ((type is MetadataType) && (state.TemplateType == null || !state.TemplateType.RetrieveRuntimeTypeHandleIfPossible()))
            {
                requireVtableSlotMapping = true;
                pTemplateEEType = null;
            }
            else if (type.IsMdArray)
            {
                pTemplateEEType = typeof(object[,]).TypeHandle.ToEETypePtr();
                requireVtableSlotMapping = false;
            }
            else
            {
                Debug.Assert(state.TemplateType != null && !state.TemplateType.RuntimeTypeHandle.IsNull());
                requireVtableSlotMapping = state.TemplateType.IsCanonicalSubtype(CanonicalFormKind.Universal);
                RuntimeTypeHandle templateTypeHandle = state.TemplateType.RuntimeTypeHandle;
                pTemplateEEType = templateTypeHandle.ToEETypePtr();
            }

            DefType typeAsDefType = type as DefType;
            // Use a checked typecast to 'ushort' for the arity to ensure its value never exceeds 65535 and cause integer
            // overflows later when computing size of memory blocks to allocate for the type and its GenericInstanceDescriptor structures
            int arity = checked((ushort)((typeAsDefType != null && typeAsDefType.HasInstantiation ? typeAsDefType.Instantiation.Length : 0)));

            CreateEETypeWorker(pTemplateEEType, (uint)type.GetHashCode(), arity, requireVtableSlotMapping, state);

            return state.HalfBakedRuntimeTypeHandle;
        }
        public static void RegisterDebugDataForType(TypeBuilder typeBuilder, DefType defType, TypeBuilderState state)
        {
            if (!defType.IsGeneric())
            {
                RegisterDebugDataForNativeFormatType(typeBuilder, defType, state);
                return;
            }

            if (defType.IsGenericDefinition)
            {
                // We don't yet have an encoding for open generic types
                // TODO! fill this in
                return;
            }

            NativePrimitiveEncoder encoder = new NativePrimitiveEncoder();

            encoder.Init();

            IntPtr gcStaticFieldData    = TypeLoaderEnvironment.Instance.TryGetGcStaticFieldData(typeBuilder.GetRuntimeTypeHandle(defType));
            IntPtr nonGcStaticFieldData = TypeLoaderEnvironment.Instance.TryGetNonGcStaticFieldData(typeBuilder.GetRuntimeTypeHandle(defType));

            bool isUniversalGenericType          = state.TemplateType != null && state.TemplateType.IsCanonicalSubtype(CanonicalFormKind.Universal);
            bool embeddedTypeSizeAndFieldOffsets = isUniversalGenericType || (state.TemplateType == null);
            uint instanceFieldCount = 0;
            uint staticFieldCount   = 0;

            // GetDiagnosticFields only returns the fields that are of interest for diagnostic reporting. So it doesn't
            // return a meaningful list for non-universal canonical templates
            IEnumerable <FieldDesc> diagnosticFields = defType.GetDiagnosticFields();

            foreach (var f in diagnosticFields)
            {
                if (f.IsLiteral)
                {
                    continue;
                }

                if (f.IsStatic)
                {
                    ++staticFieldCount;
                }
                else
                {
                    ++instanceFieldCount;
                }
            }

            SharedTypeFlags sharedTypeFlags = 0;

            if (gcStaticFieldData != IntPtr.Zero)
            {
                sharedTypeFlags |= SharedTypeFlags.HasGCStaticFieldRegion;
            }
            if (nonGcStaticFieldData != IntPtr.Zero)
            {
                sharedTypeFlags |= SharedTypeFlags.HasNonGCStaticFieldRegion;
            }
            if (state.ThreadDataSize != 0)
            {
                sharedTypeFlags |= SharedTypeFlags.HasThreadStaticFieldRegion;
            }
            if (embeddedTypeSizeAndFieldOffsets)
            {
                sharedTypeFlags |= SerializedDebugData.SharedTypeFlags.HasTypeSize;

                if (instanceFieldCount > 0)
                {
                    sharedTypeFlags |= SerializedDebugData.SharedTypeFlags.HasInstanceFields;
                }

                if (staticFieldCount > 0)
                {
                    sharedTypeFlags |= SerializedDebugData.SharedTypeFlags.HasStaticFields;
                }
            }

            SerializeDataBlobTypeAndFlags(ref encoder, SerializedDataBlobKind.SharedType, (byte)sharedTypeFlags);

            //
            // The order of these writes is a contract shared between the runtime and debugger engine.
            // Changes here must also be updated in the debugger reader code
            //
            encoder.WriteUnsignedLong((ulong)typeBuilder.GetRuntimeTypeHandle(defType).ToIntPtr().ToInt64());
            encoder.WriteUnsigned((uint)defType.Instantiation.Length);

            foreach (var instParam in defType.Instantiation)
            {
                encoder.WriteUnsignedLong((ulong)typeBuilder.GetRuntimeTypeHandle(instParam).ToIntPtr().ToInt64());
            }

            if (gcStaticFieldData != IntPtr.Zero)
            {
                encoder.WriteUnsignedLong((ulong)gcStaticFieldData.ToInt64());
            }

            if (nonGcStaticFieldData != IntPtr.Zero)
            {
                encoder.WriteUnsignedLong((ulong)nonGcStaticFieldData.ToInt64());
            }

            // Write the TLS offset into the native thread's TLS buffer. That index de-referenced is the thread static
            // data region for this type
            if (state.ThreadDataSize != 0)
            {
                encoder.WriteUnsigned(state.ThreadStaticOffset);
            }

            // Collect information debugger only requires for universal generics and dynamically loaded types
            if (embeddedTypeSizeAndFieldOffsets)
            {
                Debug.Assert(state.TypeSize != null);
                encoder.WriteUnsigned((uint)state.TypeSize);

                if (instanceFieldCount > 0)
                {
                    encoder.WriteUnsigned(instanceFieldCount);

                    uint i = 0;
                    foreach (FieldDesc f in diagnosticFields)
                    {
                        if (f.IsLiteral)
                        {
                            continue;
                        }
                        if (f.IsStatic)
                        {
                            continue;
                        }

                        encoder.WriteUnsigned(i);
                        encoder.WriteUnsigned((uint)f.Offset.AsInt);
                        i++;
                    }
                }

                if (staticFieldCount > 0)
                {
                    encoder.WriteUnsigned(staticFieldCount);

                    uint i = 0;
                    foreach (FieldDesc f in diagnosticFields)
                    {
                        if (f.IsLiteral)
                        {
                            continue;
                        }
                        if (!f.IsStatic)
                        {
                            continue;
                        }

                        NativeLayoutFieldDesc nlfd = f as NativeLayoutFieldDesc;
                        FieldStorage          fieldStorage;
                        if (nlfd != null)
                        {
                            // NativeLayoutFieldDesc's have the field storage information directly embedded in them
                            fieldStorage = nlfd.FieldStorage;
                        }
                        else
                        {
                            // Metadata based types do not, but the api's to get the info are available
                            if (f.IsThreadStatic)
                            {
                                fieldStorage = FieldStorage.TLSStatic;
                            }
                            else if (f.HasGCStaticBase)
                            {
                                fieldStorage = FieldStorage.GCStatic;
                            }
                            else
                            {
                                fieldStorage = FieldStorage.NonGCStatic;
                            }
                        }

                        encoder.WriteUnsigned(i);
                        encoder.WriteUnsigned((uint)fieldStorage);
                        encoder.WriteUnsigned((uint)f.Offset.AsInt);
                        i++;
                    }
                }
            }

            Instance.ThreadSafeWriteBytes(encoder.GetBytes());
        }
Beispiel #13
0
        private static unsafe int GetInstanceGCDescSize(TypeBuilderState state, EEType* pTemplateEEType, bool isValueType, bool isArray)
        {
            var gcBitfield = state.InstanceGCLayout;
            if (isArray)
            {
                if (state.IsArrayOfReferenceTypes)
                {
                    // Reference type arrays have a GC desc the size of 3 pointers
                    return 3 * sizeof(IntPtr);
                }
                else
                {
                    int series = 0;
                    if (gcBitfield != null)
                        series = CreateArrayGCDesc(gcBitfield, 1, true, null);

                    return series > 0 ? (series + 2) * IntPtr.Size : 0;
                }
            }
            else if (gcBitfield != null)
            {
                int series = CreateGCDesc(gcBitfield, 0, isValueType, false, null);
                return series > 0 ? (series * 2 + 1) * IntPtr.Size : 0;
            }
            else if (pTemplateEEType != null)
            {
                return RuntimeAugments.GetGCDescSize(pTemplateEEType->ToRuntimeTypeHandle());
            }
            else
            {
                return 0;
            }
        }
Beispiel #14
0
        public static RuntimeTypeHandle CreatePointerEEType(UInt32 hashCodeOfNewType, RuntimeTypeHandle pointeeTypeHandle, TypeDesc pointerType)
        {
            TypeBuilderState state = new TypeBuilderState(pointerType);

            CreateEETypeWorker(typeof(void*).TypeHandle.ToEETypePtr(), hashCodeOfNewType, 0, false, state);
            Debug.Assert(!state.HalfBakedRuntimeTypeHandle.IsNull());

            state.HalfBakedRuntimeTypeHandle.ToEETypePtr()->RelatedParameterType = pointeeTypeHandle.ToEETypePtr();

            return state.HalfBakedRuntimeTypeHandle;
        }
Beispiel #15
0
        private static void CreateEETypeWorker(EEType* pTemplateEEType, UInt32 hashCodeOfNewType,
            int arity, bool requireVtableSlotMapping, TypeBuilderState state)
        {
            bool successful = false;
            IntPtr eeTypePtrPlusGCDesc = IntPtr.Zero;
            IntPtr dynamicDispatchMapPtr = IntPtr.Zero;
            DynamicModule* dynamicModulePtr = null;

            try
            {
                Debug.Assert((pTemplateEEType != null) || (state.TypeBeingBuilt as MetadataType != null));

                // In some situations involving arrays we can find as a template a dynamically generated type.
                // In that case, the correct template would be the template used to create the dynamic type in the first
                // place.
                if (pTemplateEEType != null && pTemplateEEType->IsDynamicType)
                {
                    pTemplateEEType = pTemplateEEType->DynamicTemplateType;
                }

                ModuleInfo moduleInfo = TypeLoaderEnvironment.GetModuleInfoForType(state.TypeBeingBuilt);
                dynamicModulePtr = moduleInfo.DynamicModulePtr;
                Debug.Assert(dynamicModulePtr != null);

                bool requiresDynamicDispatchMap = requireVtableSlotMapping && (pTemplateEEType != null) && pTemplateEEType->HasDispatchMap;

                uint valueTypeFieldPaddingEncoded = 0;
                int baseSize = 0;

                bool isValueType;
                bool hasFinalizer;
                bool isNullable;
                bool isArray;
                bool isGeneric;
                ushort componentSize = 0;
                ushort flags;
                ushort runtimeInterfacesLength = 0;
                bool isGenericEETypeDef = false;

                if (state.RuntimeInterfaces != null)
                {
                    runtimeInterfacesLength = checked((ushort)state.RuntimeInterfaces.Length);
                }

                if (pTemplateEEType != null)
                {
                    valueTypeFieldPaddingEncoded = EEType.ComputeValueTypeFieldPaddingFieldValue(
                        pTemplateEEType->ValueTypeFieldPadding, 
                        (uint)pTemplateEEType->FieldAlignmentRequirement);
                    baseSize = (int)pTemplateEEType->BaseSize;
                    isValueType = pTemplateEEType->IsValueType;
                    hasFinalizer = pTemplateEEType->IsFinalizable;
                    isNullable = pTemplateEEType->IsNullable;
                    componentSize = pTemplateEEType->ComponentSize;
                    flags = pTemplateEEType->Flags;
                    isArray = pTemplateEEType->IsArray;
                    isGeneric = pTemplateEEType->IsGeneric;
                    Debug.Assert(pTemplateEEType->NumInterfaces == runtimeInterfacesLength);
                }
                else if (state.TypeBeingBuilt.IsGenericDefinition)
                {
                    flags = (ushort)EETypeKind.GenericTypeDefEEType;
                    isValueType = state.TypeBeingBuilt.IsValueType;
                    if (isValueType)
                        flags |= (ushort)EETypeFlags.ValueTypeFlag;

                    if (state.TypeBeingBuilt.IsInterface)
                        flags |= (ushort)EETypeFlags.IsInterfaceFlag;
                    hasFinalizer = false;
                    isArray = false;
                    isNullable = false;
                    isGeneric = false;
                    isGenericEETypeDef = true;
                    componentSize = checked((ushort)state.TypeBeingBuilt.Instantiation.Length);
                    baseSize = 0;
                }
                else
                {
                    isValueType = state.TypeBeingBuilt.IsValueType;
                    hasFinalizer = state.TypeBeingBuilt.HasFinalizer;
                    isNullable = state.TypeBeingBuilt.GetTypeDefinition().IsNullable;
                    flags = EETypeBuilderHelpers.ComputeFlags(state.TypeBeingBuilt);
                    isArray = false;
                    isGeneric = state.TypeBeingBuilt.HasInstantiation;

                    if (state.TypeBeingBuilt.HasVariance)
                    {
                        state.GenericVarianceFlags = new int[state.TypeBeingBuilt.Instantiation.Length];
                        int i = 0;

                        foreach (GenericParameterDesc gpd in state.TypeBeingBuilt.GetTypeDefinition().Instantiation)
                        {
                            state.GenericVarianceFlags[i] = (int)gpd.Variance;
                            i++;
                        }
                        Debug.Assert(i == state.GenericVarianceFlags.Length);
                    }
                }

                // TODO! Change to if template is Universal or non-Existent
                if (state.TypeSize.HasValue)
                {
                    baseSize = state.TypeSize.Value;

                    int baseSizeBeforeAlignment = baseSize;

                    baseSize = MemoryHelpers.AlignUp(baseSize, IntPtr.Size);

                    if (isValueType)
                    {
                        // Compute the valuetype padding size based on size before adding the object type pointer field to the size
                        uint cbValueTypeFieldPadding = (uint)(baseSize - baseSizeBeforeAlignment);

                        // Add Object type pointer field to base size
                        baseSize += IntPtr.Size;

                        valueTypeFieldPaddingEncoded = (uint)EEType.ComputeValueTypeFieldPaddingFieldValue(cbValueTypeFieldPadding, (uint)state.FieldAlignment.Value);
                    }

                    // Minimum base size is 3 pointers, and requires us to bump the size of an empty class type
                    if (baseSize <= IntPtr.Size)
                    {
                        // ValueTypes should already have had their size bumped up by the normal type layout process
                        Debug.Assert(!isValueType);
                        baseSize += IntPtr.Size;
                    }

                    // Add sync block skew
                    baseSize += IntPtr.Size;

                    // Minimum basesize is 3 pointers
                    Debug.Assert(baseSize >= (IntPtr.Size * 3));
                }

                // Optional fields encoding
                int cbOptionalFieldsSize;
                OptionalFieldsRuntimeBuilder optionalFields;
                {
                    optionalFields = new OptionalFieldsRuntimeBuilder(pTemplateEEType != null ? pTemplateEEType->OptionalFieldsPtr : null);

                    UInt32 rareFlags = optionalFields.GetFieldValue(EETypeOptionalFieldTag.RareFlags, 0);
                    rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeFlag;          // Set the IsDynamicTypeFlag
                    rareFlags &= ~(uint)EETypeRareFlags.NullableTypeViaIATFlag;    // Remove the NullableTypeViaIATFlag flag
                    rareFlags &= ~(uint)EETypeRareFlags.HasSealedVTableEntriesFlag;// Remove the HasSealedVTableEntriesFlag
                                                                                   // we'll set IsDynamicTypeWithSealedVTableEntriesFlag instead

                    // Set the IsDynamicTypeWithSealedVTableEntriesFlag if needed
                    if (state.NumSealedVTableEntries > 0)
                        rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeWithSealedVTableEntriesFlag;

                    if (requiresDynamicDispatchMap)
                        rareFlags |= (uint)EETypeRareFlags.HasDynamicallyAllocatedDispatchMapFlag;

                    if (state.NonGcDataSize != 0)
                        rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeWithNonGcStatics;

                    if (state.GcDataSize != 0)
                        rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeWithGcStatics;

                    if (state.ThreadDataSize != 0)
                        rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeWithThreadStatics;

#if ARM
                    if (state.FieldAlignment == 8)
                        rareFlags |= (uint)EETypeRareFlags.RequiresAlign8Flag;
                    else
                        rareFlags &= ~(uint)EETypeRareFlags.RequiresAlign8Flag;

                    if (state.IsHFA)
                        rareFlags |= (uint)EETypeRareFlags.IsHFAFlag;
                    else
                        rareFlags &= ~(uint)EETypeRareFlags.IsHFAFlag;
#endif
                    if (state.HasStaticConstructor)
                        rareFlags |= (uint)EETypeRareFlags.HasCctorFlag;
                    else
                        rareFlags &= ~(uint)EETypeRareFlags.HasCctorFlag;

                    rareFlags |= (uint)EETypeRareFlags.HasDynamicModuleFlag;

                    optionalFields.SetFieldValue(EETypeOptionalFieldTag.RareFlags, rareFlags);

                    // Dispatch map is fetched either from template type, or from the dynamically allocated DispatchMap field
                    optionalFields.ClearField(EETypeOptionalFieldTag.DispatchMap);

                    optionalFields.ClearField(EETypeOptionalFieldTag.ValueTypeFieldPadding);

                    if (valueTypeFieldPaddingEncoded != 0)
                        optionalFields.SetFieldValue(EETypeOptionalFieldTag.ValueTypeFieldPadding, valueTypeFieldPaddingEncoded);

                    // Compute size of optional fields encoding
                    cbOptionalFieldsSize = optionalFields.Encode();
                    Debug.Assert(cbOptionalFieldsSize > 0);
                }

                // Note: The number of vtable slots on the EEType to create is not necessary equal to the number of
                // vtable slots on the template type for universal generics (see ComputeVTableLayout)
                ushort numVtableSlots = state.NumVTableSlots;

                // Compute the EEType size and allocate it
                EEType* pEEType;
                {
                    // In order to get the size of the EEType to allocate we need the following information 
                    // 1) The number of VTable slots (from the TypeBuilderState)
                    // 2) The number of Interfaces (from the template)
                    // 3) Whether or not there is a finalizer (from the template)
                    // 4) Optional fields size
                    // 5) Whether or not the type is nullable (from the template)
                    // 6) Whether or not the type has sealed virtuals (from the TypeBuilderState)
                    int cbEEType = (int)EEType.GetSizeofEEType(
                        numVtableSlots,
                        runtimeInterfacesLength,
                        hasFinalizer,
                        true,
                        isNullable,
                        state.NumSealedVTableEntries > 0,
                        isGeneric,
                        state.NonGcDataSize != 0,
                        state.GcDataSize != 0,
                        state.ThreadDataSize != 0);

                    // Dynamic types have an extra pointer-sized field that contains a pointer to their template type
                    cbEEType += IntPtr.Size;

                    // Check if we need another pointer sized field for a dynamic DispatchMap
                    cbEEType += (requiresDynamicDispatchMap ? IntPtr.Size : 0);

                    // Add another pointer sized field for a DynamicModule
                    cbEEType += IntPtr.Size;

                    int cbGCDesc = GetInstanceGCDescSize(state, pTemplateEEType, isValueType, isArray);
                    int cbGCDescAligned = MemoryHelpers.AlignUp(cbGCDesc, IntPtr.Size);

                    // Allocate enough space for the EEType + gcDescSize
                    eeTypePtrPlusGCDesc = MemoryHelpers.AllocateMemory(cbGCDescAligned + cbEEType + cbOptionalFieldsSize);

                    // Get the EEType pointer, and the template EEType pointer
                    pEEType = (EEType*)(eeTypePtrPlusGCDesc + cbGCDescAligned);
                    state.HalfBakedRuntimeTypeHandle = pEEType->ToRuntimeTypeHandle();

                    // Set basic EEType fields
                    pEEType->ComponentSize = componentSize;
                    pEEType->Flags = flags;
                    pEEType->BaseSize = (uint)baseSize;
                    pEEType->NumVtableSlots = numVtableSlots;
                    pEEType->NumInterfaces = runtimeInterfacesLength;
                    pEEType->HashCode = hashCodeOfNewType;

                    // Write the GCDesc
                    bool isSzArray = isArray ? state.ArrayRank < 1 : false;
                    int arrayRank = isArray ? state.ArrayRank.Value : 0;
                    CreateInstanceGCDesc(state, pTemplateEEType, pEEType, baseSize, cbGCDesc, isValueType, isArray, isSzArray, arrayRank);
                    Debug.Assert(pEEType->HasGCPointers == (cbGCDesc != 0));

#if GENERICS_FORCE_USG
                    if (state.NonUniversalTemplateType != null)
                    {
                        Debug.Assert(state.NonUniversalInstanceGCDescSize == cbGCDesc, "Non-universal instance GCDesc size not matching with universal GCDesc size!");
                        Debug.Assert(cbGCDesc == 0 || pEEType->HasGCPointers);

                        // The TestGCDescsForEquality helper will compare 2 GCDescs for equality, 4 bytes at a time (GCDesc contents treated as integers), and will read the 
                        // GCDesc data in *reverse* order for instance GCDescs (subtracts 4 from the pointer values at each iteration).
                        //    - For the first GCDesc, we use (pEEType - 4) to point to the first 4-byte integer directly preceeding the EEType
                        //    - For the second GCDesc, given that the state.NonUniversalInstanceGCDesc already points to the first byte preceeding the template EEType, we 
                        //      subtract 3 to point to the first 4-byte integer directly preceeding the template EEtype
                        TestGCDescsForEquality(new IntPtr((byte*)pEEType - 4), state.NonUniversalInstanceGCDesc - 3, cbGCDesc, true);
                    }
#endif

                    // Copy the encoded optional fields buffer to the newly allocated memory, and update the OptionalFields field on the EEType
                    // It is important to set the optional fields first on the newly created EEType, because all other 'setters' 
                    // will assert that the type is dynamic, just to make sure we are not making any changes to statically compiled types
                    pEEType->OptionalFieldsPtr = (byte*)pEEType + cbEEType;
                    optionalFields.WriteToEEType(pEEType, cbOptionalFieldsSize);

#if CORERT
                    pEEType->PointerToTypeManager = PermanentAllocatedMemoryBlobs.GetPointerToIntPtr(moduleInfo.Handle);
#endif
                    pEEType->DynamicModule = dynamicModulePtr;

                    // Copy VTable entries from template type
                    int numSlotsFilled = 0;
                    IntPtr* pVtable = (IntPtr*)((byte*)pEEType + sizeof(EEType));
                    if (pTemplateEEType != null)
                    {
                        IntPtr* pTemplateVtable = (IntPtr*)((byte*)pTemplateEEType + sizeof(EEType));
                        for (int i = 0; i < pTemplateEEType->NumVtableSlots; i++)
                        {
                            int vtableSlotInDynamicType = requireVtableSlotMapping ? state.VTableSlotsMapping.GetVTableSlotInTargetType(i) : i;
                            if (vtableSlotInDynamicType != -1)
                            {
                                Debug.Assert(vtableSlotInDynamicType < numVtableSlots);

                                IntPtr dictionaryPtrValue;
                                if (requireVtableSlotMapping && state.VTableSlotsMapping.IsDictionarySlot(i, out dictionaryPtrValue))
                                {
                                    // This must be the dictionary pointer value of one of the base types of the 
                                    // current universal generic type being constructed.
                                    pVtable[vtableSlotInDynamicType] = dictionaryPtrValue;

                                    // Assert that the current template vtable slot is also a NULL value since all 
                                    // universal generic template types have NULL dictionary slot values in their vtables
                                    Debug.Assert(pTemplateVtable[i] == IntPtr.Zero);
                                }
                                else
                                {
                                    pVtable[vtableSlotInDynamicType] = pTemplateVtable[i];
                                }
                                numSlotsFilled++;
                            }
                        }
                    }
                    else if (isGenericEETypeDef)
                    {
                        // If creating a Generic Type Definition
                        Debug.Assert(pEEType->NumVtableSlots == 0);
                    }
                    else
                    {
#if SUPPORTS_NATIVE_METADATA_TYPE_LOADING
                        // Dynamically loaded type

                        // Fill the vtable with vtable resolution thunks in all slots except for
                        // the dictionary slots, which should be filled with dictionary pointers if those
                        // dictionaries are already published.

                        TypeDesc nextTypeToExamineForDictionarySlot = state.TypeBeingBuilt;
                        TypeDesc typeWithDictionary;
                        int nextDictionarySlot = GetMostDerivedDictionarySlot(ref nextTypeToExamineForDictionarySlot, out typeWithDictionary);

                        for (int iSlot = pEEType->NumVtableSlots - 1; iSlot >= 0; iSlot--)
                        {
                            bool isDictionary = iSlot == nextDictionarySlot;
                            if (!isDictionary)
                            {
                                pVtable[iSlot] = LazyVTableResolver.GetThunkForSlot(iSlot);
                            }
                            else
                            {
                                if (typeWithDictionary.RetrieveRuntimeTypeHandleIfPossible())
                                {
                                    pVtable[iSlot] = typeWithDictionary.RuntimeTypeHandle.GetDictionary();
                                }
                                nextDictionarySlot = GetMostDerivedDictionarySlot(ref nextTypeToExamineForDictionarySlot, out typeWithDictionary);
                            }
                            numSlotsFilled++;
                        }
#else
                        Environment.FailFast("Template type loader is null, but metadata based type loader is not in use");
#endif
                    }

                    Debug.Assert(numSlotsFilled == numVtableSlots);

                    // Copy Pointer to finalizer method from the template type
                    if (hasFinalizer)
                    {
                        if (pTemplateEEType != null)
                        {
                            pEEType->FinalizerCode = pTemplateEEType->FinalizerCode;
                        }
                        else
                        {
#if SUPPORTS_NATIVE_METADATA_TYPE_LOADING
                            pEEType->FinalizerCode = LazyVTableResolver.GetFinalizerThunk();
#else
                            Environment.FailFast("Template type loader is null, but metadata based type loader is not in use");
#endif
                        }
                    }
                }

                // Copy the sealed vtable entries if they exist on the template type
                if (state.NumSealedVTableEntries > 0)
                {
                    state.HalfBakedSealedVTable = MemoryHelpers.AllocateMemory((int)state.NumSealedVTableEntries * IntPtr.Size);

                    UInt32 cbSealedVirtualSlotsTypeOffset = pEEType->GetFieldOffset(EETypeField.ETF_SealedVirtualSlots);
                    *((IntPtr*)((byte*)pEEType + cbSealedVirtualSlotsTypeOffset)) = state.HalfBakedSealedVTable;

                    for (UInt16 i = 0; i < state.NumSealedVTableEntries; i++)
                    {
                        IntPtr value = pTemplateEEType->GetSealedVirtualSlot(i);
                        pEEType->SetSealedVirtualSlot(value, i);
                    }
                }

                // Create a new DispatchMap for the type
                if (requiresDynamicDispatchMap)
                {
                    DispatchMap* pTemplateDispatchMap = (DispatchMap*)RuntimeAugments.GetDispatchMapForType(pTemplateEEType->ToRuntimeTypeHandle());

                    dynamicDispatchMapPtr = MemoryHelpers.AllocateMemory(pTemplateDispatchMap->Size);

                    UInt32 cbDynamicDispatchMapOffset = pEEType->GetFieldOffset(EETypeField.ETF_DynamicDispatchMap);
                    *((IntPtr*)((byte*)pEEType + cbDynamicDispatchMapOffset)) = dynamicDispatchMapPtr;

                    DispatchMap* pDynamicDispatchMap = (DispatchMap*)dynamicDispatchMapPtr;
                    pDynamicDispatchMap->NumEntries = pTemplateDispatchMap->NumEntries;

                    for (int i = 0; i < pTemplateDispatchMap->NumEntries; i++)
                    {
                        DispatchMap.DispatchMapEntry* pTemplateEntry = (*pTemplateDispatchMap)[i];
                        DispatchMap.DispatchMapEntry* pDynamicEntry = (*pDynamicDispatchMap)[i];

                        pDynamicEntry->_usInterfaceIndex = pTemplateEntry->_usInterfaceIndex;
                        pDynamicEntry->_usInterfaceMethodSlot = pTemplateEntry->_usInterfaceMethodSlot;
                        if (pTemplateEntry->_usImplMethodSlot < pTemplateEEType->NumVtableSlots)
                        {
                            pDynamicEntry->_usImplMethodSlot = (ushort)state.VTableSlotsMapping.GetVTableSlotInTargetType(pTemplateEntry->_usImplMethodSlot);
                            Debug.Assert(pDynamicEntry->_usImplMethodSlot < numVtableSlots);
                        }
                        else
                        {
                            // This is an entry in the sealed vtable. We need to adjust the slot number based on the number of vtable slots
                            // in the dynamic EEType
                            pDynamicEntry->_usImplMethodSlot = (ushort)(pTemplateEntry->_usImplMethodSlot - pTemplateEEType->NumVtableSlots + numVtableSlots);
                            Debug.Assert(state.NumSealedVTableEntries > 0 &&
                                pDynamicEntry->_usImplMethodSlot >= numVtableSlots &&
                                (pDynamicEntry->_usImplMethodSlot - numVtableSlots) < state.NumSealedVTableEntries);
                        }
                    }
                }

                if (pTemplateEEType != null)
                {
                    pEEType->DynamicTemplateType = pTemplateEEType;
                }
                else
                {
                    // Use object as the template type for non-template based EETypes. This will
                    // allow correct Module identification for types.

                    if (state.TypeBeingBuilt.HasVariance)
                    {
                        // TODO! We need to have a variant EEType here if the type has variance, as the 
                        // CreateGenericInstanceDescForType requires it. However, this is a ridiculous api surface
                        // When we remove GenericInstanceDescs from the product, get rid of this weird special
                        // case
                        pEEType->DynamicTemplateType = typeof(IEnumerable<int>).TypeHandle.ToEETypePtr();
                    }
                    else
                    {
                        pEEType->DynamicTemplateType = typeof(object).TypeHandle.ToEETypePtr();
                    }
                }

                int nonGCStaticDataOffset = 0;

                if (!isArray && !isGenericEETypeDef)
                {
                    nonGCStaticDataOffset = state.HasStaticConstructor ? -TypeBuilder.ClassConstructorOffset : 0;

                    // create GC desc
                    if (state.GcDataSize != 0 && state.GcStaticDesc == IntPtr.Zero)
                    {
                        int cbStaticGCDesc;
                        state.GcStaticDesc = CreateStaticGCDesc(state.StaticGCLayout, out state.AllocatedStaticGCDesc, out cbStaticGCDesc);
#if GENERICS_FORCE_USG
                        TestGCDescsForEquality(state.GcStaticDesc, state.NonUniversalStaticGCDesc, cbStaticGCDesc, false);
#endif
                    }

                    if (state.ThreadDataSize != 0 && state.ThreadStaticDesc == IntPtr.Zero)
                    {
                        int cbThreadStaticGCDesc;
                        state.ThreadStaticDesc = CreateStaticGCDesc(state.ThreadStaticGCLayout, out state.AllocatedThreadStaticGCDesc, out cbThreadStaticGCDesc);
#if GENERICS_FORCE_USG
                        TestGCDescsForEquality(state.ThreadStaticDesc, state.NonUniversalThreadStaticGCDesc, cbThreadStaticGCDesc, false);
#endif
                    }

                    // If we have a class constructor, our NonGcDataSize MUST be non-zero
                    Debug.Assert(!state.HasStaticConstructor || (state.NonGcDataSize != 0));
                }

                if (isGeneric)
                {
                    if (!RuntimeAugments.CreateGenericInstanceDescForType(*(RuntimeTypeHandle*)&pEEType, arity, state.NonGcDataSize, nonGCStaticDataOffset,
                        state.GcDataSize, (int)state.ThreadStaticOffset, state.GcStaticDesc, state.ThreadStaticDesc, state.GenericVarianceFlags))
                    {
                        throw new OutOfMemoryException();
                    }
                }
                else
                {
                    Debug.Assert(arity == 0 || isGenericEETypeDef);
                    // We don't need to report the non-gc and gc static data regions and allocate them for non-generics, 
                    // as we currently place these fields directly into the image
                    if (!isGenericEETypeDef && state.ThreadDataSize != 0)
                    {
                        // Types with thread static fields ALWAYS get a GID. The GID is used to perform GC 
                        // and lifetime management of the thread static data. However, these GIDs are only used for that
                        // so the specified GcDataSize, etc are 0
                        if (!RuntimeAugments.CreateGenericInstanceDescForType(*(RuntimeTypeHandle*)&pEEType, 0, 0, 0, 0, (int)state.ThreadStaticOffset, IntPtr.Zero, state.ThreadStaticDesc, null))
                        {
                            throw new OutOfMemoryException();
                        }
                    }
                }

                if (state.Dictionary != null)
                    state.HalfBakedDictionary = state.Dictionary.Allocate();

                Debug.Assert(!state.HalfBakedRuntimeTypeHandle.IsNull());
                Debug.Assert((state.NumSealedVTableEntries == 0 && state.HalfBakedSealedVTable == IntPtr.Zero) || (state.NumSealedVTableEntries > 0 && state.HalfBakedSealedVTable != IntPtr.Zero));
                Debug.Assert((state.Dictionary == null && state.HalfBakedDictionary == IntPtr.Zero) || (state.Dictionary != null && state.HalfBakedDictionary != IntPtr.Zero));

                successful = true;
            }
            finally
            {
                if (!successful)
                {
                    if (eeTypePtrPlusGCDesc != IntPtr.Zero)
                        MemoryHelpers.FreeMemory(eeTypePtrPlusGCDesc);
                    if (dynamicDispatchMapPtr != IntPtr.Zero)
                        MemoryHelpers.FreeMemory(dynamicDispatchMapPtr);
                    if (state.HalfBakedSealedVTable != IntPtr.Zero)
                        MemoryHelpers.FreeMemory(state.HalfBakedSealedVTable);
                    if (state.HalfBakedDictionary != IntPtr.Zero)
                        MemoryHelpers.FreeMemory(state.HalfBakedDictionary);
                    if (state.AllocatedStaticGCDesc)
                        MemoryHelpers.FreeMemory(state.GcStaticDesc);
                    if (state.AllocatedThreadStaticGCDesc)
                        MemoryHelpers.FreeMemory(state.ThreadStaticDesc);
                }
            }
        }
Beispiel #16
0
 private static void CreateInstanceGCDesc(TypeBuilderState state, EEType* pTemplateEEType, EEType* pEEType, int baseSize, int cbGCDesc, bool isValueType, bool isArray, bool isSzArray, int arrayRank)
 {
     var gcBitfield = state.InstanceGCLayout;
     if (isArray)
     {
         if (cbGCDesc != 0)
         {
             pEEType->HasGCPointers = true;
             if (state.IsArrayOfReferenceTypes)
             {
                 IntPtr* gcDescStart = (IntPtr*)((byte*)pEEType - cbGCDesc);
                 gcDescStart[0] = new IntPtr(-baseSize);
                 gcDescStart[1] = new IntPtr(baseSize - sizeof(IntPtr));
                 gcDescStart[2] = new IntPtr(1);
             }
             else
             {
                 CreateArrayGCDesc(gcBitfield, arrayRank, isSzArray, ((void**)pEEType) - 1);
             }
         }
         else
         {
             pEEType->HasGCPointers = false;
         }
     }
     else if (gcBitfield != null)
     {
         if (cbGCDesc != 0)
         {
             pEEType->HasGCPointers = true;
             CreateGCDesc(gcBitfield, baseSize, isValueType, false, ((void**)pEEType) - 1);
         }
         else
         {
             pEEType->HasGCPointers = false;
         }
     }
     else if (pTemplateEEType != null)
     {
         Buffer.MemoryCopy((byte*)pTemplateEEType - cbGCDesc, (byte*)pEEType - cbGCDesc, cbGCDesc, cbGCDesc);
         pEEType->HasGCPointers = pTemplateEEType->HasGCPointers;
     }
     else
     {
         pEEType->HasGCPointers = false;
     }
 }
Beispiel #17
0
        public static void RegisterDebugDataForType(TypeBuilder typeBuilder, DefType defType, TypeBuilderState state)
        {
            if (!defType.IsGeneric())
            {
                RegisterDebugDataForNativeFormatType(typeBuilder, defType, state);
                return;
            }

            if (defType.IsGenericDefinition)
            {
                // We don't yet have an encoding for open generic types
                // TODO! fill this in
                return;
            }

            NativePrimitiveEncoder encoder = new NativePrimitiveEncoder();
            encoder.Init();

            IntPtr gcStaticFieldData = TypeLoaderEnvironment.Instance.TryGetGcStaticFieldData(typeBuilder.GetRuntimeTypeHandle(defType));
            IntPtr nonGcStaticFieldData = TypeLoaderEnvironment.Instance.TryGetNonGcStaticFieldData(typeBuilder.GetRuntimeTypeHandle(defType));

            bool isUniversalGenericType = state.TemplateType != null && state.TemplateType.IsCanonicalSubtype(CanonicalFormKind.Universal);
            bool embeddedTypeSizeAndFieldOffsets = isUniversalGenericType || (state.TemplateType == null);
            uint instanceFieldCount = 0;
            uint staticFieldCount = 0;

            // GetDiagnosticFields only returns the fields that are of interest for diagnostic reporting. So it doesn't
            // return a meaningful list for non-universal canonical templates
            IEnumerable<FieldDesc> diagnosticFields = defType.GetDiagnosticFields();
            foreach (var f in diagnosticFields)
            {
                if (f.IsLiteral)
                    continue;

                if (f.IsStatic)
                {
                    ++staticFieldCount;
                }
                else
                {
                    ++instanceFieldCount;
                }
            }

            SharedTypeFlags sharedTypeFlags = 0;
            if (gcStaticFieldData != IntPtr.Zero) sharedTypeFlags |= SharedTypeFlags.HasGCStaticFieldRegion;
            if (nonGcStaticFieldData != IntPtr.Zero) sharedTypeFlags |= SharedTypeFlags.HasNonGCStaticFieldRegion;
            if (state.ThreadDataSize != 0) sharedTypeFlags |= SharedTypeFlags.HasThreadStaticFieldRegion;
            if (embeddedTypeSizeAndFieldOffsets)
            {
                sharedTypeFlags |= SerializedDebugData.SharedTypeFlags.HasTypeSize;

                if (instanceFieldCount > 0)
                    sharedTypeFlags |= SerializedDebugData.SharedTypeFlags.HasInstanceFields;

                if (staticFieldCount > 0)
                    sharedTypeFlags |= SerializedDebugData.SharedTypeFlags.HasStaticFields;
            }

            Instance.SerializeDataBlobTypeAndFlags(ref encoder, SerializedDataBlobKind.SharedType, (byte)sharedTypeFlags);

            //
            // The order of these writes is a contract shared between the runtime and debugger engine.
            // Changes here must also be updated in the debugger reader code
            //
            encoder.WriteUnsignedLong((ulong)typeBuilder.GetRuntimeTypeHandle(defType).ToIntPtr().ToInt64());
            encoder.WriteUnsigned((uint)defType.Instantiation.Length);

            foreach (var instParam in defType.Instantiation)
            {
                encoder.WriteUnsignedLong((ulong)typeBuilder.GetRuntimeTypeHandle(instParam).ToIntPtr().ToInt64());
            }

            if (gcStaticFieldData != IntPtr.Zero)
            {
                encoder.WriteUnsignedLong((ulong)gcStaticFieldData.ToInt64());
            }

            if (nonGcStaticFieldData != IntPtr.Zero)
            {
                encoder.WriteUnsignedLong((ulong)nonGcStaticFieldData.ToInt64());
            }

            // Write the TLS offset into the native thread's TLS buffer. That index de-referenced is the thread static
            // data region for this type
            if (state.ThreadDataSize != 0)
            {
                encoder.WriteUnsigned(state.ThreadStaticOffset);
            }

            // Collect information debugger only requires for universal generics and dynamically loaded types
            if (embeddedTypeSizeAndFieldOffsets)
            {
                Debug.Assert(state.TypeSize != null);
                encoder.WriteUnsigned((uint)state.TypeSize);

                if (instanceFieldCount > 0)
                {
                    encoder.WriteUnsigned(instanceFieldCount);

                    uint i = 0;
                    foreach (FieldDesc f in diagnosticFields)
                    {
                        if (f.IsLiteral)
                            continue;
                        if (f.IsStatic)
                            continue;

                        encoder.WriteUnsigned(i);
                        encoder.WriteUnsigned((uint)f.Offset);
                        i++;
                    }
                }

                if (staticFieldCount > 0)
                {
                    encoder.WriteUnsigned(staticFieldCount);

                    uint i = 0;
                    foreach (FieldDesc f in diagnosticFields)
                    {
                        if (f.IsLiteral)
                            continue;
                        if (!f.IsStatic)
                            continue;

                        NativeLayoutFieldDesc nlfd = f as NativeLayoutFieldDesc;
                        FieldStorage fieldStorage;
                        if (nlfd != null)
                        {
                            // NativeLayoutFieldDesc's have the field storage information directly embedded in them
                            fieldStorage = nlfd.FieldStorage;
                        }
                        else
                        {
                            // Metadata based types do not, but the api's to get the info are available
                            if (f.IsThreadStatic)
                            {
                                fieldStorage = FieldStorage.TLSStatic;
                            }
                            else if (f.HasGCStaticBase)
                            {
                                fieldStorage = FieldStorage.GCStatic;
                            }
                            else
                            {
                                fieldStorage = FieldStorage.NonGCStatic;
                            }
                        }

                        encoder.WriteUnsigned(i);
                        encoder.WriteUnsigned((uint)fieldStorage);
                        encoder.WriteUnsigned((uint)f.Offset);
                        i++;
                    }
                }
            }

            Instance.ThreadSafeWriteBytes(encoder.GetBytes());
        }
Beispiel #18
0
        private bool ComputeHasDictionaryInVTable()
        {
            if (!HasDictionarySlotInVTable)
                return false;

            if (TypeBeingBuilt.RetrieveRuntimeTypeHandleIfPossible())
            {
                // Type was already constructed
                return TypeBeingBuilt.RuntimeTypeHandle.GetDictionary() != IntPtr.Zero;
            }
            else
            {
                // Type is being newly constructed
                if (TemplateType != null)
                {
                    NativeParser parser = GetParserForNativeLayoutInfo();
                    // Template type loader case
#if GENERICS_FORCE_USG
                    bool isTemplateUniversalCanon = state.TemplateType.IsCanonicalSubtype(CanonicalFormKind.UniversalCanonLookup);
                    if (isTemplateUniversalCanon && type.CanShareNormalGenericCode())
                    {
                        TypeBuilderState tempState = new TypeBuilderState();
                        tempState.NativeLayoutInfo = new NativeLayoutInfo();
                        tempState.TemplateType = type.Context.TemplateLookup.TryGetNonUniversalTypeTemplate(type, ref tempState.NativeLayoutInfo);
                        if (tempState.TemplateType != null)
                        {
                            Debug.Assert(!tempState.TemplateType.IsCanonicalSubtype(CanonicalFormKind.UniversalCanonLookup));
                            parser = GetNativeLayoutInfoParser(type, ref tempState.NativeLayoutInfo);
                        }
                    }
#endif
                    var dictionaryLayoutParser = parser.GetParserForBagElementKind(BagElementKind.DictionaryLayout);

                    return !dictionaryLayoutParser.IsNull;
                }
                else
                {
                    NativeParser parser = GetParserForReadyToRunNativeLayoutInfo();
                    // ReadyToRun case
                    // Dictionary is directly encoded instead of the NativeLayout being a collection of bags
                    if (parser.IsNull)
                        return false;

                    // First unsigned value in the native layout is the number of dictionary entries
                    return parser.GetUnsigned() != 0;
                }
            }
        }
Beispiel #19
0
        /// <summary>
        /// Add information about dynamically created non-generic native format type
        /// to the diagnostic stream in form of a NativeFormatType blob.
        /// </summary>
        /// <param name="typeBuilder">TypeBuilder is used to query runtime type handle for the type</param>
        /// <param name="defType">Type to emit to the diagnostic stream</param>
        /// <param name="state"></param>
        public static void RegisterDebugDataForNativeFormatType(TypeBuilder typeBuilder, DefType defType, TypeBuilderState state)
        {
#if SUPPORTS_NATIVE_METADATA_TYPE_LOADING
            NativeFormatType nativeFormatType = defType as NativeFormatType;
            if (nativeFormatType == null)
            {
                return;
            }

            NativePrimitiveEncoder encoder = new NativePrimitiveEncoder();
            encoder.Init();

            byte nativeFormatTypeFlags = 0;

            Instance.SerializeDataBlobTypeAndFlags(
                ref encoder,
                SerializedDataBlobKind.NativeFormatType,
                nativeFormatTypeFlags);

            IntPtr moduleHandle = ModuleList.Instance.GetModuleForMetadataReader(nativeFormatType.MetadataReader);

            encoder.WriteUnsignedLong(unchecked((ulong)typeBuilder.GetRuntimeTypeHandle(defType).ToIntPtr().ToInt64()));
            encoder.WriteUnsigned(nativeFormatType.Handle.ToHandle(nativeFormatType.MetadataReader).AsUInt());
            encoder.WriteUnsignedLong(unchecked((ulong)moduleHandle.ToInt64()));

            Instance.ThreadSafeWriteBytes(encoder.GetBytes());
#else
            return;
#endif
        }
        public override DefType[] ComputeRuntimeInterfaces(TypeDesc type)
        {
            TypeBuilderState state = type.GetOrCreateTypeBuilderState();
            int totalInterfaces    = RuntimeAugments.GetInterfaceCount(state.TemplateType.RuntimeTypeHandle);

            TypeLoaderLogger.WriteLine("Building runtime interfaces for type " + type.ToString() + " (total interfaces = " + totalInterfaces.LowLevelToString() + ") ...");

            DefType[] interfaces    = new DefType[totalInterfaces];
            int       numInterfaces = 0;

            //
            // Copy over all interfaces from base class
            //
            if (type.BaseType != null)
            {
                foreach (var baseInterface in type.BaseType.RuntimeInterfaces)
                {
                    // There should be no duplicates
                    Debug.Assert(!InterfaceInSet(interfaces, numInterfaces, baseInterface));
                    interfaces[numInterfaces++] = baseInterface;
                    TypeLoaderLogger.WriteLine("    -> Added basetype interface " + baseInterface.ToString() + " on type " + type.ToString());
                }
            }

            NativeParser typeInfoParser  = state.GetParserForNativeLayoutInfo();
            NativeParser interfaceParser = typeInfoParser.GetParserForBagElementKind(BagElementKind.ImplementedInterfaces);

            TypeDesc[] implementedInterfaces;
            if (!interfaceParser.IsNull)
            {
                implementedInterfaces = state.NativeLayoutInfo.LoadContext.GetTypeSequence(ref interfaceParser);
            }
            else
            {
                implementedInterfaces = TypeDesc.EmptyTypes;
            }

            // Note that the order in which the interfaces are added to the list is same as the order in which the MDIL binder adds them.
            // It is required for correctness

            foreach (TypeDesc interfaceType in implementedInterfaces)
            {
                DefType interfaceTypeAsDefType = (DefType)interfaceType;

                // Skip duplicates
                if (InterfaceInSet(interfaces, numInterfaces, interfaceTypeAsDefType))
                {
                    continue;
                }
                interfaces[numInterfaces++] = interfaceTypeAsDefType;

                TypeLoaderLogger.WriteLine("    -> Added interface " + interfaceTypeAsDefType.ToString() + " on type " + type.ToString());

                foreach (var inheritedInterface in interfaceTypeAsDefType.RuntimeInterfaces)
                {
                    // Skip duplicates
                    if (InterfaceInSet(interfaces, numInterfaces, inheritedInterface))
                    {
                        continue;
                    }
                    interfaces[numInterfaces++] = inheritedInterface;
                    TypeLoaderLogger.WriteLine("    -> Added inherited interface " + inheritedInterface.ToString() + " on type " + type.ToString());
                }
            }

            // TODO: Handle the screwy cases of generic interface folding
            Debug.Assert(numInterfaces == totalInterfaces, "Unexpected number of interfaces");

            return(interfaces);
        }
Beispiel #21
0
 //
 // Get or create existing type builder state. This method should not be called during final phase of type building.
 //
 internal TypeBuilderState GetOrCreateTypeBuilderState()
 {
     TypeBuilderState state = (TypeBuilderState)TypeBuilderState;
     if (state == null)
     {
         state = new TypeBuilderState(this);
         TypeBuilderState = state;
         Context.RegisterTypeForTypeSystemStateFlushing(this);
     }
     return state;
 }
Beispiel #22
0
        internal TypeDesc ComputeTemplate(TypeBuilderState state, bool templateRequired = true)
        {
            TypeDesc templateType = state.TemplateType;

            if (templateRequired && (templateType == null))
            {
                throw new TypeBuilder.MissingTemplateException();
            }

            return templateType;
        }
Beispiel #23
0
        private static void CreateEETypeWorker(EEType *pTemplateEEType, UInt32 hashCodeOfNewType,
                                               int arity, bool requireVtableSlotMapping, TypeBuilderState state)
        {
            bool           successful            = false;
            IntPtr         eeTypePtrPlusGCDesc   = IntPtr.Zero;
            IntPtr         dynamicDispatchMapPtr = IntPtr.Zero;
            DynamicModule *dynamicModulePtr      = null;

            try
            {
                Debug.Assert((pTemplateEEType != null) || (state.TypeBeingBuilt as MetadataType != null));

                // In some situations involving arrays we can find as a template a dynamically generated type.
                // In that case, the correct template would be the template used to create the dynamic type in the first
                // place.
                if (pTemplateEEType != null && pTemplateEEType->IsDynamicType)
                {
                    pTemplateEEType = pTemplateEEType->DynamicTemplateType;
                }

                ModuleInfo moduleInfo = TypeLoaderEnvironment.GetModuleInfoForType(state.TypeBeingBuilt);
                dynamicModulePtr = moduleInfo.DynamicModulePtr;
                Debug.Assert(dynamicModulePtr != null);

                bool requiresDynamicDispatchMap = requireVtableSlotMapping && (pTemplateEEType != null) && pTemplateEEType->HasDispatchMap;

                uint valueTypeFieldPaddingEncoded = 0;
                int  baseSize = 0;

                bool   isValueType;
                bool   hasFinalizer;
                bool   isNullable;
                bool   isArray;
                bool   isGeneric;
                ushort componentSize = 0;
                ushort flags;
                ushort runtimeInterfacesLength = 0;
                bool   isGenericEETypeDef      = false;

                if (state.RuntimeInterfaces != null)
                {
                    runtimeInterfacesLength = checked ((ushort)state.RuntimeInterfaces.Length);
                }

                if (pTemplateEEType != null)
                {
                    valueTypeFieldPaddingEncoded = EEType.ComputeValueTypeFieldPaddingFieldValue(
                        pTemplateEEType->ValueTypeFieldPadding,
                        (uint)pTemplateEEType->FieldAlignmentRequirement);
                    baseSize      = (int)pTemplateEEType->BaseSize;
                    isValueType   = pTemplateEEType->IsValueType;
                    hasFinalizer  = pTemplateEEType->IsFinalizable;
                    isNullable    = pTemplateEEType->IsNullable;
                    componentSize = pTemplateEEType->ComponentSize;
                    flags         = pTemplateEEType->Flags;
                    isArray       = pTemplateEEType->IsArray;
                    isGeneric     = pTemplateEEType->IsGeneric;
                    Debug.Assert(pTemplateEEType->NumInterfaces == runtimeInterfacesLength);
                }
                else if (state.TypeBeingBuilt.IsGenericDefinition)
                {
                    flags       = (ushort)EETypeKind.GenericTypeDefEEType;
                    isValueType = state.TypeBeingBuilt.IsValueType;
                    if (isValueType)
                    {
                        flags |= (ushort)EETypeFlags.ValueTypeFlag;
                    }

                    if (state.TypeBeingBuilt.IsInterface)
                    {
                        flags |= (ushort)EETypeFlags.IsInterfaceFlag;
                    }
                    hasFinalizer       = false;
                    isArray            = false;
                    isNullable         = false;
                    isGeneric          = false;
                    isGenericEETypeDef = true;
                    componentSize      = checked ((ushort)state.TypeBeingBuilt.Instantiation.Length);
                    baseSize           = 0;
                }
                else
                {
                    isValueType  = state.TypeBeingBuilt.IsValueType;
                    hasFinalizer = state.TypeBeingBuilt.HasFinalizer;
                    isNullable   = state.TypeBeingBuilt.GetTypeDefinition().IsNullable;
                    flags        = EETypeBuilderHelpers.ComputeFlags(state.TypeBeingBuilt);
                    isArray      = false;
                    isGeneric    = state.TypeBeingBuilt.HasInstantiation;

                    if (state.TypeBeingBuilt.HasVariance)
                    {
                        state.GenericVarianceFlags = new int[state.TypeBeingBuilt.Instantiation.Length];
                        int i = 0;

                        foreach (GenericParameterDesc gpd in state.TypeBeingBuilt.GetTypeDefinition().Instantiation)
                        {
                            state.GenericVarianceFlags[i] = (int)gpd.Variance;
                            i++;
                        }
                        Debug.Assert(i == state.GenericVarianceFlags.Length);
                    }
                }

                // TODO! Change to if template is Universal or non-Existent
                if (state.TypeSize.HasValue)
                {
                    baseSize = state.TypeSize.Value;

                    int baseSizeBeforeAlignment = baseSize;

                    baseSize = MemoryHelpers.AlignUp(baseSize, IntPtr.Size);

                    if (isValueType)
                    {
                        // Compute the valuetype padding size based on size before adding the object type pointer field to the size
                        uint cbValueTypeFieldPadding = (uint)(baseSize - baseSizeBeforeAlignment);

                        // Add Object type pointer field to base size
                        baseSize += IntPtr.Size;

                        valueTypeFieldPaddingEncoded = (uint)EEType.ComputeValueTypeFieldPaddingFieldValue(cbValueTypeFieldPadding, (uint)state.FieldAlignment.Value);
                    }

                    // Minimum base size is 3 pointers, and requires us to bump the size of an empty class type
                    if (baseSize <= IntPtr.Size)
                    {
                        // ValueTypes should already have had their size bumped up by the normal type layout process
                        Debug.Assert(!isValueType);
                        baseSize += IntPtr.Size;
                    }

                    // Add sync block skew
                    baseSize += IntPtr.Size;

                    // Minimum basesize is 3 pointers
                    Debug.Assert(baseSize >= (IntPtr.Size * 3));
                }

                // Optional fields encoding
                int cbOptionalFieldsSize;
                OptionalFieldsRuntimeBuilder optionalFields;
                {
                    optionalFields = new OptionalFieldsRuntimeBuilder(pTemplateEEType != null ? pTemplateEEType->OptionalFieldsPtr : null);

                    UInt32 rareFlags = optionalFields.GetFieldValue(EETypeOptionalFieldTag.RareFlags, 0);
                    rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeFlag;           // Set the IsDynamicTypeFlag
                    rareFlags &= ~(uint)EETypeRareFlags.NullableTypeViaIATFlag;     // Remove the NullableTypeViaIATFlag flag
                    rareFlags &= ~(uint)EETypeRareFlags.HasSealedVTableEntriesFlag; // Remove the HasSealedVTableEntriesFlag
                                                                                    // we'll set IsDynamicTypeWithSealedVTableEntriesFlag instead

                    // Set the IsDynamicTypeWithSealedVTableEntriesFlag if needed
                    if (state.NumSealedVTableEntries > 0)
                    {
                        rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeWithSealedVTableEntriesFlag;
                    }

                    if (requiresDynamicDispatchMap)
                    {
                        rareFlags |= (uint)EETypeRareFlags.HasDynamicallyAllocatedDispatchMapFlag;
                    }

                    if (state.NonGcDataSize != 0)
                    {
                        rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeWithNonGcStatics;
                    }

                    if (state.GcDataSize != 0)
                    {
                        rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeWithGcStatics;
                    }

                    if (state.ThreadDataSize != 0)
                    {
                        rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeWithThreadStatics;
                    }

#if ARM
                    if (state.FieldAlignment == 8)
                    {
                        rareFlags |= (uint)EETypeRareFlags.RequiresAlign8Flag;
                    }
                    else
                    {
                        rareFlags &= ~(uint)EETypeRareFlags.RequiresAlign8Flag;
                    }

                    if (state.IsHFA)
                    {
                        rareFlags |= (uint)EETypeRareFlags.IsHFAFlag;
                    }
                    else
                    {
                        rareFlags &= ~(uint)EETypeRareFlags.IsHFAFlag;
                    }
#endif
                    if (state.HasStaticConstructor)
                    {
                        rareFlags |= (uint)EETypeRareFlags.HasCctorFlag;
                    }
                    else
                    {
                        rareFlags &= ~(uint)EETypeRareFlags.HasCctorFlag;
                    }

                    rareFlags |= (uint)EETypeRareFlags.HasDynamicModuleFlag;

                    optionalFields.SetFieldValue(EETypeOptionalFieldTag.RareFlags, rareFlags);

                    // Dispatch map is fetched either from template type, or from the dynamically allocated DispatchMap field
                    optionalFields.ClearField(EETypeOptionalFieldTag.DispatchMap);

                    optionalFields.ClearField(EETypeOptionalFieldTag.ValueTypeFieldPadding);

                    if (valueTypeFieldPaddingEncoded != 0)
                    {
                        optionalFields.SetFieldValue(EETypeOptionalFieldTag.ValueTypeFieldPadding, valueTypeFieldPaddingEncoded);
                    }

                    // Compute size of optional fields encoding
                    cbOptionalFieldsSize = optionalFields.Encode();
                    Debug.Assert(cbOptionalFieldsSize > 0);
                }

                // Note: The number of vtable slots on the EEType to create is not necessary equal to the number of
                // vtable slots on the template type for universal generics (see ComputeVTableLayout)
                ushort numVtableSlots = state.NumVTableSlots;

                // Compute the EEType size and allocate it
                EEType *pEEType;
                {
                    // In order to get the size of the EEType to allocate we need the following information
                    // 1) The number of VTable slots (from the TypeBuilderState)
                    // 2) The number of Interfaces (from the template)
                    // 3) Whether or not there is a finalizer (from the template)
                    // 4) Optional fields size
                    // 5) Whether or not the type is nullable (from the template)
                    // 6) Whether or not the type has sealed virtuals (from the TypeBuilderState)
                    int cbEEType = (int)EEType.GetSizeofEEType(
                        numVtableSlots,
                        runtimeInterfacesLength,
                        hasFinalizer,
                        true,
                        isNullable,
                        state.NumSealedVTableEntries > 0,
                        isGeneric,
                        state.NonGcDataSize != 0,
                        state.GcDataSize != 0,
                        state.ThreadDataSize != 0);

                    // Dynamic types have an extra pointer-sized field that contains a pointer to their template type
                    cbEEType += IntPtr.Size;

                    // Check if we need another pointer sized field for a dynamic DispatchMap
                    cbEEType += (requiresDynamicDispatchMap ? IntPtr.Size : 0);

                    // Add another pointer sized field for a DynamicModule
                    cbEEType += IntPtr.Size;

                    int cbGCDesc        = GetInstanceGCDescSize(state, pTemplateEEType, isValueType, isArray);
                    int cbGCDescAligned = MemoryHelpers.AlignUp(cbGCDesc, IntPtr.Size);

                    // Allocate enough space for the EEType + gcDescSize
                    eeTypePtrPlusGCDesc = MemoryHelpers.AllocateMemory(cbGCDescAligned + cbEEType + cbOptionalFieldsSize);

                    // Get the EEType pointer, and the template EEType pointer
                    pEEType = (EEType *)(eeTypePtrPlusGCDesc + cbGCDescAligned);
                    state.HalfBakedRuntimeTypeHandle = pEEType->ToRuntimeTypeHandle();

                    // Set basic EEType fields
                    pEEType->ComponentSize  = componentSize;
                    pEEType->Flags          = flags;
                    pEEType->BaseSize       = (uint)baseSize;
                    pEEType->NumVtableSlots = numVtableSlots;
                    pEEType->NumInterfaces  = runtimeInterfacesLength;
                    pEEType->HashCode       = hashCodeOfNewType;

                    // Write the GCDesc
                    bool isSzArray = isArray ? state.ArrayRank < 1 : false;
                    int  arrayRank = isArray ? state.ArrayRank.Value : 0;
                    CreateInstanceGCDesc(state, pTemplateEEType, pEEType, baseSize, cbGCDesc, isValueType, isArray, isSzArray, arrayRank);
                    Debug.Assert(pEEType->HasGCPointers == (cbGCDesc != 0));

#if GENERICS_FORCE_USG
                    if (state.NonUniversalTemplateType != null)
                    {
                        Debug.Assert(state.NonUniversalInstanceGCDescSize == cbGCDesc, "Non-universal instance GCDesc size not matching with universal GCDesc size!");
                        Debug.Assert(cbGCDesc == 0 || pEEType->HasGCPointers);

                        // The TestGCDescsForEquality helper will compare 2 GCDescs for equality, 4 bytes at a time (GCDesc contents treated as integers), and will read the
                        // GCDesc data in *reverse* order for instance GCDescs (subtracts 4 from the pointer values at each iteration).
                        //    - For the first GCDesc, we use (pEEType - 4) to point to the first 4-byte integer directly preceeding the EEType
                        //    - For the second GCDesc, given that the state.NonUniversalInstanceGCDesc already points to the first byte preceeding the template EEType, we
                        //      subtract 3 to point to the first 4-byte integer directly preceeding the template EEtype
                        TestGCDescsForEquality(new IntPtr((byte *)pEEType - 4), state.NonUniversalInstanceGCDesc - 3, cbGCDesc, true);
                    }
#endif

                    // Copy the encoded optional fields buffer to the newly allocated memory, and update the OptionalFields field on the EEType
                    // It is important to set the optional fields first on the newly created EEType, because all other 'setters'
                    // will assert that the type is dynamic, just to make sure we are not making any changes to statically compiled types
                    pEEType->OptionalFieldsPtr = (byte *)pEEType + cbEEType;
                    optionalFields.WriteToEEType(pEEType, cbOptionalFieldsSize);

#if CORERT
                    pEEType->PointerToTypeManager = PermanentAllocatedMemoryBlobs.GetPointerToIntPtr(moduleInfo.Handle);
#endif
                    pEEType->DynamicModule = dynamicModulePtr;

                    // Copy VTable entries from template type
                    int     numSlotsFilled = 0;
                    IntPtr *pVtable        = (IntPtr *)((byte *)pEEType + sizeof(EEType));
                    if (pTemplateEEType != null)
                    {
                        IntPtr *pTemplateVtable = (IntPtr *)((byte *)pTemplateEEType + sizeof(EEType));
                        for (int i = 0; i < pTemplateEEType->NumVtableSlots; i++)
                        {
                            int vtableSlotInDynamicType = requireVtableSlotMapping ? state.VTableSlotsMapping.GetVTableSlotInTargetType(i) : i;
                            if (vtableSlotInDynamicType != -1)
                            {
                                Debug.Assert(vtableSlotInDynamicType < numVtableSlots);

                                IntPtr dictionaryPtrValue;
                                if (requireVtableSlotMapping && state.VTableSlotsMapping.IsDictionarySlot(i, out dictionaryPtrValue))
                                {
                                    // This must be the dictionary pointer value of one of the base types of the
                                    // current universal generic type being constructed.
                                    pVtable[vtableSlotInDynamicType] = dictionaryPtrValue;

                                    // Assert that the current template vtable slot is also a NULL value since all
                                    // universal generic template types have NULL dictionary slot values in their vtables
                                    Debug.Assert(pTemplateVtable[i] == IntPtr.Zero);
                                }
                                else
                                {
                                    pVtable[vtableSlotInDynamicType] = pTemplateVtable[i];
                                }
                                numSlotsFilled++;
                            }
                        }
                    }
                    else if (isGenericEETypeDef)
                    {
                        // If creating a Generic Type Definition
                        Debug.Assert(pEEType->NumVtableSlots == 0);
                    }
                    else
                    {
#if SUPPORTS_NATIVE_METADATA_TYPE_LOADING
                        // Dynamically loaded type

                        // Fill the vtable with vtable resolution thunks in all slots except for
                        // the dictionary slots, which should be filled with dictionary pointers if those
                        // dictionaries are already published.

                        TypeDesc nextTypeToExamineForDictionarySlot = state.TypeBeingBuilt;
                        TypeDesc typeWithDictionary;
                        int      nextDictionarySlot = GetMostDerivedDictionarySlot(ref nextTypeToExamineForDictionarySlot, out typeWithDictionary);

                        for (int iSlot = pEEType->NumVtableSlots - 1; iSlot >= 0; iSlot--)
                        {
                            bool isDictionary = iSlot == nextDictionarySlot;
                            if (!isDictionary)
                            {
                                pVtable[iSlot] = LazyVTableResolver.GetThunkForSlot(iSlot);
                            }
                            else
                            {
                                if (typeWithDictionary.RetrieveRuntimeTypeHandleIfPossible())
                                {
                                    pVtable[iSlot] = typeWithDictionary.RuntimeTypeHandle.GetDictionary();
                                }
                                nextDictionarySlot = GetMostDerivedDictionarySlot(ref nextTypeToExamineForDictionarySlot, out typeWithDictionary);
                            }
                            numSlotsFilled++;
                        }
#else
                        Environment.FailFast("Template type loader is null, but metadata based type loader is not in use");
#endif
                    }

                    Debug.Assert(numSlotsFilled == numVtableSlots);

                    // Copy Pointer to finalizer method from the template type
                    if (hasFinalizer)
                    {
                        if (pTemplateEEType != null)
                        {
                            pEEType->FinalizerCode = pTemplateEEType->FinalizerCode;
                        }
                        else
                        {
#if SUPPORTS_NATIVE_METADATA_TYPE_LOADING
                            pEEType->FinalizerCode = LazyVTableResolver.GetFinalizerThunk();
#else
                            Environment.FailFast("Template type loader is null, but metadata based type loader is not in use");
#endif
                        }
                    }
                }

                // Copy the sealed vtable entries if they exist on the template type
                if (state.NumSealedVTableEntries > 0)
                {
                    state.HalfBakedSealedVTable = MemoryHelpers.AllocateMemory((int)state.NumSealedVTableEntries * IntPtr.Size);

                    UInt32 cbSealedVirtualSlotsTypeOffset = pEEType->GetFieldOffset(EETypeField.ETF_SealedVirtualSlots);
                    *((IntPtr *)((byte *)pEEType + cbSealedVirtualSlotsTypeOffset)) = state.HalfBakedSealedVTable;

                    for (UInt16 i = 0; i < state.NumSealedVTableEntries; i++)
                    {
                        IntPtr value = pTemplateEEType->GetSealedVirtualSlot(i);
                        pEEType->SetSealedVirtualSlot(value, i);
                    }
                }

                // Create a new DispatchMap for the type
                if (requiresDynamicDispatchMap)
                {
                    DispatchMap *pTemplateDispatchMap = (DispatchMap *)RuntimeAugments.GetDispatchMapForType(pTemplateEEType->ToRuntimeTypeHandle());

                    dynamicDispatchMapPtr = MemoryHelpers.AllocateMemory(pTemplateDispatchMap->Size);

                    UInt32 cbDynamicDispatchMapOffset = pEEType->GetFieldOffset(EETypeField.ETF_DynamicDispatchMap);
                    *((IntPtr *)((byte *)pEEType + cbDynamicDispatchMapOffset)) = dynamicDispatchMapPtr;

                    DispatchMap *pDynamicDispatchMap = (DispatchMap *)dynamicDispatchMapPtr;
                    pDynamicDispatchMap->NumEntries = pTemplateDispatchMap->NumEntries;

                    for (int i = 0; i < pTemplateDispatchMap->NumEntries; i++)
                    {
                        DispatchMap.DispatchMapEntry *pTemplateEntry = (*pTemplateDispatchMap)[i];
                        DispatchMap.DispatchMapEntry *pDynamicEntry  = (*pDynamicDispatchMap)[i];

                        pDynamicEntry->_usInterfaceIndex      = pTemplateEntry->_usInterfaceIndex;
                        pDynamicEntry->_usInterfaceMethodSlot = pTemplateEntry->_usInterfaceMethodSlot;
                        if (pTemplateEntry->_usImplMethodSlot < pTemplateEEType->NumVtableSlots)
                        {
                            pDynamicEntry->_usImplMethodSlot = (ushort)state.VTableSlotsMapping.GetVTableSlotInTargetType(pTemplateEntry->_usImplMethodSlot);
                            Debug.Assert(pDynamicEntry->_usImplMethodSlot < numVtableSlots);
                        }
                        else
                        {
                            // This is an entry in the sealed vtable. We need to adjust the slot number based on the number of vtable slots
                            // in the dynamic EEType
                            pDynamicEntry->_usImplMethodSlot = (ushort)(pTemplateEntry->_usImplMethodSlot - pTemplateEEType->NumVtableSlots + numVtableSlots);
                            Debug.Assert(state.NumSealedVTableEntries > 0 &&
                                         pDynamicEntry->_usImplMethodSlot >= numVtableSlots &&
                                         (pDynamicEntry->_usImplMethodSlot - numVtableSlots) < state.NumSealedVTableEntries);
                        }
                    }
                }

                if (pTemplateEEType != null)
                {
                    pEEType->DynamicTemplateType = pTemplateEEType;
                }
                else
                {
                    // Use object as the template type for non-template based EETypes. This will
                    // allow correct Module identification for types.

                    if (state.TypeBeingBuilt.HasVariance)
                    {
                        // TODO! We need to have a variant EEType here if the type has variance, as the
                        // CreateGenericInstanceDescForType requires it. However, this is a ridiculous api surface
                        // When we remove GenericInstanceDescs from the product, get rid of this weird special
                        // case
                        pEEType->DynamicTemplateType = typeof(IEnumerable <int>).TypeHandle.ToEETypePtr();
                    }
                    else
                    {
                        pEEType->DynamicTemplateType = typeof(object).TypeHandle.ToEETypePtr();
                    }
                }

                int nonGCStaticDataOffset = 0;

                if (!isArray && !isGenericEETypeDef)
                {
                    nonGCStaticDataOffset = state.HasStaticConstructor ? -TypeBuilder.ClassConstructorOffset : 0;

                    // create GC desc
                    if (state.GcDataSize != 0 && state.GcStaticDesc == IntPtr.Zero)
                    {
                        int cbStaticGCDesc;
                        state.GcStaticDesc = CreateStaticGCDesc(state.StaticGCLayout, out state.AllocatedStaticGCDesc, out cbStaticGCDesc);
#if GENERICS_FORCE_USG
                        TestGCDescsForEquality(state.GcStaticDesc, state.NonUniversalStaticGCDesc, cbStaticGCDesc, false);
#endif
                    }

                    if (state.ThreadDataSize != 0 && state.ThreadStaticDesc == IntPtr.Zero)
                    {
                        int cbThreadStaticGCDesc;
                        state.ThreadStaticDesc = CreateStaticGCDesc(state.ThreadStaticGCLayout, out state.AllocatedThreadStaticGCDesc, out cbThreadStaticGCDesc);
#if GENERICS_FORCE_USG
                        TestGCDescsForEquality(state.ThreadStaticDesc, state.NonUniversalThreadStaticGCDesc, cbThreadStaticGCDesc, false);
#endif
                    }

                    // If we have a class constructor, our NonGcDataSize MUST be non-zero
                    Debug.Assert(!state.HasStaticConstructor || (state.NonGcDataSize != 0));
                }

                if (isGeneric)
                {
                    if (!RuntimeAugments.CreateGenericInstanceDescForType(*(RuntimeTypeHandle *)&pEEType, arity, state.NonGcDataSize, nonGCStaticDataOffset,
                                                                          state.GcDataSize, (int)state.ThreadStaticOffset, state.GcStaticDesc, state.ThreadStaticDesc, state.GenericVarianceFlags))
                    {
                        throw new OutOfMemoryException();
                    }
                }
                else
                {
                    Debug.Assert(arity == 0 || isGenericEETypeDef);
                    // We don't need to report the non-gc and gc static data regions and allocate them for non-generics,
                    // as we currently place these fields directly into the image
                    if (!isGenericEETypeDef && state.ThreadDataSize != 0)
                    {
                        // Types with thread static fields ALWAYS get a GID. The GID is used to perform GC
                        // and lifetime management of the thread static data. However, these GIDs are only used for that
                        // so the specified GcDataSize, etc are 0
                        if (!RuntimeAugments.CreateGenericInstanceDescForType(*(RuntimeTypeHandle *)&pEEType, 0, 0, 0, 0, (int)state.ThreadStaticOffset, IntPtr.Zero, state.ThreadStaticDesc, null))
                        {
                            throw new OutOfMemoryException();
                        }
                    }
                }

                if (state.Dictionary != null)
                {
                    state.HalfBakedDictionary = state.Dictionary.Allocate();
                }

                Debug.Assert(!state.HalfBakedRuntimeTypeHandle.IsNull());
                Debug.Assert((state.NumSealedVTableEntries == 0 && state.HalfBakedSealedVTable == IntPtr.Zero) || (state.NumSealedVTableEntries > 0 && state.HalfBakedSealedVTable != IntPtr.Zero));
                Debug.Assert((state.Dictionary == null && state.HalfBakedDictionary == IntPtr.Zero) || (state.Dictionary != null && state.HalfBakedDictionary != IntPtr.Zero));

                successful = true;
            }
            finally
            {
                if (!successful)
                {
                    if (eeTypePtrPlusGCDesc != IntPtr.Zero)
                    {
                        MemoryHelpers.FreeMemory(eeTypePtrPlusGCDesc);
                    }
                    if (dynamicDispatchMapPtr != IntPtr.Zero)
                    {
                        MemoryHelpers.FreeMemory(dynamicDispatchMapPtr);
                    }
                    if (state.HalfBakedSealedVTable != IntPtr.Zero)
                    {
                        MemoryHelpers.FreeMemory(state.HalfBakedSealedVTable);
                    }
                    if (state.HalfBakedDictionary != IntPtr.Zero)
                    {
                        MemoryHelpers.FreeMemory(state.HalfBakedDictionary);
                    }
                    if (state.AllocatedStaticGCDesc)
                    {
                        MemoryHelpers.FreeMemory(state.GcStaticDesc);
                    }
                    if (state.AllocatedThreadStaticGCDesc)
                    {
                        MemoryHelpers.FreeMemory(state.ThreadStaticDesc);
                    }
                }
            }
        }