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; }
// 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)); } } }
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); }
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); }
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); } } }
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; } }
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); }
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 }
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()); }
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; } }
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; }
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); } } }
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; } }
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()); }
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; } } }
/// <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); }
// // 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; }
internal TypeDesc ComputeTemplate(TypeBuilderState state, bool templateRequired = true) { TypeDesc templateType = state.TemplateType; if (templateRequired && (templateType == null)) { throw new TypeBuilder.MissingTemplateException(); } return templateType; }
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); } } } }