diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/EETypeCreator.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/EETypeCreator.cs index 9a5995e17fb9ef..cccb25742a8aa5 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/EETypeCreator.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/EETypeCreator.cs @@ -399,27 +399,20 @@ private static void CreateInstanceGCDesc(TypeBuilderState state, MethodTable* pT pEEType->ContainsGCPointers = false; } } - else if (gcBitfield != null) + else { - if (cbGCDesc != 0) + Debug.Assert(gcBitfield == null); + + if (pTemplateEEType != null) { - pEEType->ContainsGCPointers = true; - CreateGCDesc(gcBitfield, baseSize, isValueType, false, ((void**)pEEType) - 1); + Buffer.MemoryCopy((byte*)pTemplateEEType - cbGCDesc, (byte*)pEEType - cbGCDesc, cbGCDesc, cbGCDesc); + pEEType->ContainsGCPointers = pTemplateEEType->ContainsGCPointers; } else { pEEType->ContainsGCPointers = false; } } - else if (pTemplateEEType != null) - { - Buffer.MemoryCopy((byte*)pTemplateEEType - cbGCDesc, (byte*)pEEType - cbGCDesc, cbGCDesc, cbGCDesc); - pEEType->ContainsGCPointers = pTemplateEEType->ContainsGCPointers; - } - else - { - pEEType->ContainsGCPointers = false; - } } private static unsafe int GetInstanceGCDescSize(TypeBuilderState state, MethodTable* pTemplateEEType, bool isValueType, bool isArray) @@ -442,24 +435,24 @@ private static unsafe int GetInstanceGCDescSize(TypeBuilderState state, MethodTa 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; + Debug.Assert(gcBitfield == null); + + if (pTemplateEEType != null) + { + return RuntimeAugments.GetGCDescSize(pTemplateEEType->ToRuntimeTypeHandle()); + } + else + { + return 0; + } } } - private static bool IsAllGCPointers(LowLevelList bitfield) + private static bool IsAllGCPointers(bool[] bitfield) { - int count = bitfield.Count; + int count = bitfield.Length; Debug.Assert(count > 0); for (int i = 0; i < count; i++) @@ -471,7 +464,7 @@ private static bool IsAllGCPointers(LowLevelList bitfield) return true; } - private static unsafe int CreateArrayGCDesc(LowLevelList bitfield, int rank, bool isSzArray, void* gcdesc) + private static unsafe int CreateArrayGCDesc(bool[] bitfield, int rank, bool isSzArray, void* gcdesc) { if (bitfield == null) return 0; @@ -495,7 +488,7 @@ private static unsafe int CreateArrayGCDesc(LowLevelList bitfield, int ran int first = -1; int last = 0; short numPtrs = 0; - while (i < bitfield.Count) + while (i < bitfield.Length) { if (bitfield[i]) { @@ -513,7 +506,7 @@ private static unsafe int CreateArrayGCDesc(LowLevelList bitfield, int ran numSeries++; numPtrs = 0; - while ((i < bitfield.Count) && (bitfield[i])) + while ((i < bitfield.Length) && (bitfield[i])) { numPtrs++; i++; @@ -531,7 +524,7 @@ private static unsafe int CreateArrayGCDesc(LowLevelList bitfield, int ran { if (numSeries > 0) { - *ptr-- = (short)((first + bitfield.Count - last) * IntPtr.Size); + *ptr-- = (short)((first + bitfield.Length - last) * IntPtr.Size); *ptr-- = numPtrs; *(void**)gcdesc = (void*)-numSeries; @@ -542,69 +535,6 @@ private static unsafe int CreateArrayGCDesc(LowLevelList bitfield, int ran return numSeries; } - private static unsafe int CreateGCDesc(LowLevelList bitfield, int size, bool isValueType, bool isStatic, void* gcdesc) - { - int offs = 0; - // if this type is a class we have to account for the gcdesc. - if (isValueType) - offs = IntPtr.Size; - - if (bitfield == null) - return 0; - - void** ptr = (void**)gcdesc - 1; - - int* staticPtr = isStatic ? ((int*)gcdesc + 1) : null; - - int numSeries = 0; - int i = 0; - while (i < bitfield.Count) - { - if (bitfield[i]) - { - numSeries++; - int seriesOffset = i * IntPtr.Size + offs; - int seriesSize = 0; - - while ((i < bitfield.Count) && (bitfield[i])) - { - seriesSize += IntPtr.Size; - i++; - } - - - if (gcdesc != null) - { - if (staticPtr != null) - { - *staticPtr++ = seriesSize; - *staticPtr++ = seriesOffset; - } - else - { - seriesSize -= size; - *ptr-- = (void*)seriesOffset; - *ptr-- = (void*)seriesSize; - } - } - } - else - { - i++; - } - } - - if (gcdesc != null) - { - if (staticPtr != null) - *(int*)gcdesc = numSeries; - else - *(void**)gcdesc = (void*)numSeries; - } - - return numSeries; - } - public static RuntimeTypeHandle CreateFunctionPointerEEType(uint hashCodeOfNewType, RuntimeTypeHandle returnTypeHandle, RuntimeTypeHandle[] parameterHandles, FunctionPointerType functionPointerType) { TypeBuilderState state = new TypeBuilderState(functionPointerType); diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs index 48bb6c91b6169d..6f8b02d93ead60 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs @@ -13,18 +13,6 @@ namespace Internal.Runtime.TypeLoader { - internal static class LowLevelListExtensions - { - public static void Expand(this LowLevelList list, int count) - { - if (list.Capacity < count) - list.Capacity = count; - - while (list.Count < count) - list.Add(default(T)); - } - } - internal class TypeBuilder { public TypeBuilder() @@ -447,24 +435,22 @@ internal void ParseNativeLayoutInfo(TypeBuilderState state, TypeDesc type) /// internal unsafe struct GCLayout { - private LowLevelList _bitfield; + private bool[] _bitfield; private unsafe void* _gcdesc; private int _size; - private bool _isReferenceTypeGCLayout; public static GCLayout None { get { return default(GCLayout); } } - public static GCLayout SingleReference { get; } = new GCLayout(new LowLevelList(new bool[1] { true }), false); + public static GCLayout SingleReference { get; } = new GCLayout([true]); public bool IsNone { get { return _bitfield == null && _gcdesc == null; } } - public GCLayout(LowLevelList bitfield, bool isReferenceTypeGCLayout) + public GCLayout(bool[] bitfield) { Debug.Assert(bitfield != null); _bitfield = bitfield; _gcdesc = null; _size = 0; - _isReferenceTypeGCLayout = isReferenceTypeGCLayout; } public GCLayout(RuntimeTypeHandle rtth) @@ -473,37 +459,27 @@ public GCLayout(RuntimeTypeHandle rtth) Debug.Assert(MethodTable != null); _bitfield = null; - _isReferenceTypeGCLayout = false; // This field is only used for the LowLevelList path _gcdesc = MethodTable->ContainsGCPointers ? (void**)MethodTable - 1 : null; _size = (int)MethodTable->BaseSize; } /// - /// Writes this layout to the given bitfield. + /// Gets this layout in bitfield array. /// - /// The bitfield to write a layout to (may be null, at which - /// point it will be created and assigned). - /// The offset at which we need to write the bitfield. - public void WriteToBitfield(LowLevelList bitfield, int offset) + /// The layout in bitfield. + public bool[] AsBitfield() { - ArgumentNullException.ThrowIfNull(bitfield); - - if (IsNone) - return; + // This method should only be called when not none. + Debug.Assert(!IsNone); // Ensure exactly one of these two are set. Debug.Assert(_gcdesc != null ^ _bitfield != null); - if (_bitfield != null) - MergeBitfields(bitfield, offset); - else - WriteGCDescToBitfield(bitfield, offset); + return _bitfield ?? WriteGCDescToBitfield(); } - private unsafe void WriteGCDescToBitfield(LowLevelList bitfield, int offset) + private unsafe bool[] WriteGCDescToBitfield() { - int startIndex = offset / IntPtr.Size; - void** ptr = (void**)_gcdesc; Debug.Assert(_gcdesc != null); @@ -512,8 +488,8 @@ private unsafe void WriteGCDescToBitfield(LowLevelList bitfield, int offse Debug.Assert(count >= 0); // Ensure capacity for the values we are about to write - int capacity = startIndex + _size / IntPtr.Size - 2; - bitfield.Expand(capacity); + int capacity = _size / IntPtr.Size - 2; + bool[] bitfield = new bool[capacity]; while (count-- >= 0) { @@ -524,35 +500,10 @@ private unsafe void WriteGCDescToBitfield(LowLevelList bitfield, int offse Debug.Assert(offs >= 0); for (int i = 0; i < len; i++) - bitfield[startIndex + offs + i] = true; + bitfield[offs + i] = true; } - } - private void MergeBitfields(LowLevelList outputBitfield, int offset) - { - int startIndex = offset / IntPtr.Size; - - // These routines represent the GC layout after the MethodTable pointer - // in an object, but the LowLevelList bitfield logically contains - // the EETypepointer if it is describing a reference type. So, skip the - // first value. - int itemsToSkip = _isReferenceTypeGCLayout ? 1 : 0; - - // Assert that we only skip a non-reported pointer. - Debug.Assert(itemsToSkip == 0 || _bitfield[0] == false); - - // Ensure capacity for the values we are about to write - int capacity = startIndex + _bitfield.Count - itemsToSkip; - outputBitfield.Expand(capacity); - - - for (int i = itemsToSkip; i < _bitfield.Count; i++) - { - // We should never overwrite a TRUE value in the table. - Debug.Assert(!outputBitfield[startIndex + i - itemsToSkip] || _bitfield[i]); - - outputBitfield[startIndex + i - itemsToSkip] = _bitfield[i]; - } + return bitfield; } } diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilderState.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilderState.cs index 39915c06576a15..f351a128572459 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilderState.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilderState.cs @@ -306,9 +306,9 @@ public ushort NumVTableSlots // Sentinel static to allow us to initialize _instanceLayout to something // and then detect that InstanceGCLayout should return null - private static LowLevelList s_emptyLayout = new LowLevelList(); + private static readonly bool[] s_emptyLayout = []; - private LowLevelList _instanceGCLayout; + private bool[] _instanceGCLayout; /// /// The instance gc layout of a dynamically laid out type. @@ -324,14 +324,12 @@ public ushort NumVTableSlots /// If the type is a valuetype array, this is the layout of the valuetype held in the array if the type has GC reference fields /// Otherwise, it is the layout of the fields in the type. /// - public LowLevelList InstanceGCLayout + public bool[] InstanceGCLayout { get { if (_instanceGCLayout == null) { - LowLevelList instanceGCLayout; - if (TypeBeingBuilt is ArrayType) { if (!IsArrayOfReferenceTypes) @@ -340,9 +338,7 @@ public LowLevelList InstanceGCLayout TypeBuilder.GCLayout elementGcLayout = GetFieldGCLayout(arrayType.ElementType); if (!elementGcLayout.IsNone) { - instanceGCLayout = new LowLevelList(); - elementGcLayout.WriteToBitfield(instanceGCLayout, 0); - _instanceGCLayout = instanceGCLayout; + _instanceGCLayout = elementGcLayout.AsBitfield(); } } else