Skip to content

Commit 0f2bfae

Browse files
authored
Cleanup LowLevelList usage in GCLayout (#116316)
* Replace with bool[] in GC layout * Cleanup empty layout input * Cleanup _isReferenceTypeGCLayout * Use Array.Empty
1 parent b561607 commit 0f2bfae

File tree

3 files changed

+40
-163
lines changed

3 files changed

+40
-163
lines changed

src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/EETypeCreator.cs

Lines changed: 22 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -399,27 +399,20 @@ private static void CreateInstanceGCDesc(TypeBuilderState state, MethodTable* pT
399399
pEEType->ContainsGCPointers = false;
400400
}
401401
}
402-
else if (gcBitfield != null)
402+
else
403403
{
404-
if (cbGCDesc != 0)
404+
Debug.Assert(gcBitfield == null);
405+
406+
if (pTemplateEEType != null)
405407
{
406-
pEEType->ContainsGCPointers = true;
407-
CreateGCDesc(gcBitfield, baseSize, isValueType, false, ((void**)pEEType) - 1);
408+
Buffer.MemoryCopy((byte*)pTemplateEEType - cbGCDesc, (byte*)pEEType - cbGCDesc, cbGCDesc, cbGCDesc);
409+
pEEType->ContainsGCPointers = pTemplateEEType->ContainsGCPointers;
408410
}
409411
else
410412
{
411413
pEEType->ContainsGCPointers = false;
412414
}
413415
}
414-
else if (pTemplateEEType != null)
415-
{
416-
Buffer.MemoryCopy((byte*)pTemplateEEType - cbGCDesc, (byte*)pEEType - cbGCDesc, cbGCDesc, cbGCDesc);
417-
pEEType->ContainsGCPointers = pTemplateEEType->ContainsGCPointers;
418-
}
419-
else
420-
{
421-
pEEType->ContainsGCPointers = false;
422-
}
423416
}
424417

425418
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
442435
return series > 0 ? (series + 2) * IntPtr.Size : 0;
443436
}
444437
}
445-
else if (gcBitfield != null)
446-
{
447-
int series = CreateGCDesc(gcBitfield, 0, isValueType, false, null);
448-
return series > 0 ? (series * 2 + 1) * IntPtr.Size : 0;
449-
}
450-
else if (pTemplateEEType != null)
451-
{
452-
return RuntimeAugments.GetGCDescSize(pTemplateEEType->ToRuntimeTypeHandle());
453-
}
454438
else
455439
{
456-
return 0;
440+
Debug.Assert(gcBitfield == null);
441+
442+
if (pTemplateEEType != null)
443+
{
444+
return RuntimeAugments.GetGCDescSize(pTemplateEEType->ToRuntimeTypeHandle());
445+
}
446+
else
447+
{
448+
return 0;
449+
}
457450
}
458451
}
459452

460-
private static bool IsAllGCPointers(LowLevelList<bool> bitfield)
453+
private static bool IsAllGCPointers(bool[] bitfield)
461454
{
462-
int count = bitfield.Count;
455+
int count = bitfield.Length;
463456
Debug.Assert(count > 0);
464457

465458
for (int i = 0; i < count; i++)
@@ -471,7 +464,7 @@ private static bool IsAllGCPointers(LowLevelList<bool> bitfield)
471464
return true;
472465
}
473466

474-
private static unsafe int CreateArrayGCDesc(LowLevelList<bool> bitfield, int rank, bool isSzArray, void* gcdesc)
467+
private static unsafe int CreateArrayGCDesc(bool[] bitfield, int rank, bool isSzArray, void* gcdesc)
475468
{
476469
if (bitfield == null)
477470
return 0;
@@ -495,7 +488,7 @@ private static unsafe int CreateArrayGCDesc(LowLevelList<bool> bitfield, int ran
495488
int first = -1;
496489
int last = 0;
497490
short numPtrs = 0;
498-
while (i < bitfield.Count)
491+
while (i < bitfield.Length)
499492
{
500493
if (bitfield[i])
501494
{
@@ -513,7 +506,7 @@ private static unsafe int CreateArrayGCDesc(LowLevelList<bool> bitfield, int ran
513506
numSeries++;
514507
numPtrs = 0;
515508

516-
while ((i < bitfield.Count) && (bitfield[i]))
509+
while ((i < bitfield.Length) && (bitfield[i]))
517510
{
518511
numPtrs++;
519512
i++;
@@ -531,7 +524,7 @@ private static unsafe int CreateArrayGCDesc(LowLevelList<bool> bitfield, int ran
531524
{
532525
if (numSeries > 0)
533526
{
534-
*ptr-- = (short)((first + bitfield.Count - last) * IntPtr.Size);
527+
*ptr-- = (short)((first + bitfield.Length - last) * IntPtr.Size);
535528
*ptr-- = numPtrs;
536529

537530
*(void**)gcdesc = (void*)-numSeries;
@@ -542,69 +535,6 @@ private static unsafe int CreateArrayGCDesc(LowLevelList<bool> bitfield, int ran
542535
return numSeries;
543536
}
544537

545-
private static unsafe int CreateGCDesc(LowLevelList<bool> bitfield, int size, bool isValueType, bool isStatic, void* gcdesc)
546-
{
547-
int offs = 0;
548-
// if this type is a class we have to account for the gcdesc.
549-
if (isValueType)
550-
offs = IntPtr.Size;
551-
552-
if (bitfield == null)
553-
return 0;
554-
555-
void** ptr = (void**)gcdesc - 1;
556-
557-
int* staticPtr = isStatic ? ((int*)gcdesc + 1) : null;
558-
559-
int numSeries = 0;
560-
int i = 0;
561-
while (i < bitfield.Count)
562-
{
563-
if (bitfield[i])
564-
{
565-
numSeries++;
566-
int seriesOffset = i * IntPtr.Size + offs;
567-
int seriesSize = 0;
568-
569-
while ((i < bitfield.Count) && (bitfield[i]))
570-
{
571-
seriesSize += IntPtr.Size;
572-
i++;
573-
}
574-
575-
576-
if (gcdesc != null)
577-
{
578-
if (staticPtr != null)
579-
{
580-
*staticPtr++ = seriesSize;
581-
*staticPtr++ = seriesOffset;
582-
}
583-
else
584-
{
585-
seriesSize -= size;
586-
*ptr-- = (void*)seriesOffset;
587-
*ptr-- = (void*)seriesSize;
588-
}
589-
}
590-
}
591-
else
592-
{
593-
i++;
594-
}
595-
}
596-
597-
if (gcdesc != null)
598-
{
599-
if (staticPtr != null)
600-
*(int*)gcdesc = numSeries;
601-
else
602-
*(void**)gcdesc = (void*)numSeries;
603-
}
604-
605-
return numSeries;
606-
}
607-
608538
public static RuntimeTypeHandle CreateFunctionPointerEEType(uint hashCodeOfNewType, RuntimeTypeHandle returnTypeHandle, RuntimeTypeHandle[] parameterHandles, FunctionPointerType functionPointerType)
609539
{
610540
TypeBuilderState state = new TypeBuilderState(functionPointerType);

src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs

Lines changed: 14 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,6 @@
1313

1414
namespace Internal.Runtime.TypeLoader
1515
{
16-
internal static class LowLevelListExtensions
17-
{
18-
public static void Expand<T>(this LowLevelList<T> list, int count)
19-
{
20-
if (list.Capacity < count)
21-
list.Capacity = count;
22-
23-
while (list.Count < count)
24-
list.Add(default(T));
25-
}
26-
}
27-
2816
internal class TypeBuilder
2917
{
3018
public TypeBuilder()
@@ -447,24 +435,22 @@ internal void ParseNativeLayoutInfo(TypeBuilderState state, TypeDesc type)
447435
/// </summary>
448436
internal unsafe struct GCLayout
449437
{
450-
private LowLevelList<bool> _bitfield;
438+
private bool[] _bitfield;
451439
private unsafe void* _gcdesc;
452440
private int _size;
453-
private bool _isReferenceTypeGCLayout;
454441

455442
public static GCLayout None { get { return default(GCLayout); } }
456-
public static GCLayout SingleReference { get; } = new GCLayout(new LowLevelList<bool>(new bool[1] { true }), false);
443+
public static GCLayout SingleReference { get; } = new GCLayout([true]);
457444

458445
public bool IsNone { get { return _bitfield == null && _gcdesc == null; } }
459446

460-
public GCLayout(LowLevelList<bool> bitfield, bool isReferenceTypeGCLayout)
447+
public GCLayout(bool[] bitfield)
461448
{
462449
Debug.Assert(bitfield != null);
463450

464451
_bitfield = bitfield;
465452
_gcdesc = null;
466453
_size = 0;
467-
_isReferenceTypeGCLayout = isReferenceTypeGCLayout;
468454
}
469455

470456
public GCLayout(RuntimeTypeHandle rtth)
@@ -473,37 +459,27 @@ public GCLayout(RuntimeTypeHandle rtth)
473459
Debug.Assert(MethodTable != null);
474460

475461
_bitfield = null;
476-
_isReferenceTypeGCLayout = false; // This field is only used for the LowLevelList<bool> path
477462
_gcdesc = MethodTable->ContainsGCPointers ? (void**)MethodTable - 1 : null;
478463
_size = (int)MethodTable->BaseSize;
479464
}
480465

481466
/// <summary>
482-
/// Writes this layout to the given bitfield.
467+
/// Gets this layout in bitfield array.
483468
/// </summary>
484-
/// <param name="bitfield">The bitfield to write a layout to (may be null, at which
485-
/// point it will be created and assigned).</param>
486-
/// <param name="offset">The offset at which we need to write the bitfield.</param>
487-
public void WriteToBitfield(LowLevelList<bool> bitfield, int offset)
469+
/// <returns>The layout in bitfield.</returns>
470+
public bool[] AsBitfield()
488471
{
489-
ArgumentNullException.ThrowIfNull(bitfield);
490-
491-
if (IsNone)
492-
return;
472+
// This method should only be called when not none.
473+
Debug.Assert(!IsNone);
493474

494475
// Ensure exactly one of these two are set.
495476
Debug.Assert(_gcdesc != null ^ _bitfield != null);
496477

497-
if (_bitfield != null)
498-
MergeBitfields(bitfield, offset);
499-
else
500-
WriteGCDescToBitfield(bitfield, offset);
478+
return _bitfield ?? WriteGCDescToBitfield();
501479
}
502480

503-
private unsafe void WriteGCDescToBitfield(LowLevelList<bool> bitfield, int offset)
481+
private unsafe bool[] WriteGCDescToBitfield()
504482
{
505-
int startIndex = offset / IntPtr.Size;
506-
507483
void** ptr = (void**)_gcdesc;
508484
Debug.Assert(_gcdesc != null);
509485

@@ -512,8 +488,8 @@ private unsafe void WriteGCDescToBitfield(LowLevelList<bool> bitfield, int offse
512488
Debug.Assert(count >= 0);
513489

514490
// Ensure capacity for the values we are about to write
515-
int capacity = startIndex + _size / IntPtr.Size - 2;
516-
bitfield.Expand(capacity);
491+
int capacity = _size / IntPtr.Size - 2;
492+
bool[] bitfield = new bool[capacity];
517493

518494
while (count-- >= 0)
519495
{
@@ -524,35 +500,10 @@ private unsafe void WriteGCDescToBitfield(LowLevelList<bool> bitfield, int offse
524500
Debug.Assert(offs >= 0);
525501

526502
for (int i = 0; i < len; i++)
527-
bitfield[startIndex + offs + i] = true;
503+
bitfield[offs + i] = true;
528504
}
529-
}
530505

531-
private void MergeBitfields(LowLevelList<bool> outputBitfield, int offset)
532-
{
533-
int startIndex = offset / IntPtr.Size;
534-
535-
// These routines represent the GC layout after the MethodTable pointer
536-
// in an object, but the LowLevelList<bool> bitfield logically contains
537-
// the EETypepointer if it is describing a reference type. So, skip the
538-
// first value.
539-
int itemsToSkip = _isReferenceTypeGCLayout ? 1 : 0;
540-
541-
// Assert that we only skip a non-reported pointer.
542-
Debug.Assert(itemsToSkip == 0 || _bitfield[0] == false);
543-
544-
// Ensure capacity for the values we are about to write
545-
int capacity = startIndex + _bitfield.Count - itemsToSkip;
546-
outputBitfield.Expand(capacity);
547-
548-
549-
for (int i = itemsToSkip; i < _bitfield.Count; i++)
550-
{
551-
// We should never overwrite a TRUE value in the table.
552-
Debug.Assert(!outputBitfield[startIndex + i - itemsToSkip] || _bitfield[i]);
553-
554-
outputBitfield[startIndex + i - itemsToSkip] = _bitfield[i];
555-
}
506+
return bitfield;
556507
}
557508
}
558509

src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilderState.cs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -306,9 +306,9 @@ public ushort NumVTableSlots
306306

307307
// Sentinel static to allow us to initialize _instanceLayout to something
308308
// and then detect that InstanceGCLayout should return null
309-
private static LowLevelList<bool> s_emptyLayout = new LowLevelList<bool>();
309+
private static readonly bool[] s_emptyLayout = [];
310310

311-
private LowLevelList<bool> _instanceGCLayout;
311+
private bool[] _instanceGCLayout;
312312

313313
/// <summary>
314314
/// The instance gc layout of a dynamically laid out type.
@@ -324,14 +324,12 @@ public ushort NumVTableSlots
324324
/// 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
325325
/// Otherwise, it is the layout of the fields in the type.
326326
/// </summary>
327-
public LowLevelList<bool> InstanceGCLayout
327+
public bool[] InstanceGCLayout
328328
{
329329
get
330330
{
331331
if (_instanceGCLayout == null)
332332
{
333-
LowLevelList<bool> instanceGCLayout;
334-
335333
if (TypeBeingBuilt is ArrayType)
336334
{
337335
if (!IsArrayOfReferenceTypes)
@@ -340,9 +338,7 @@ public LowLevelList<bool> InstanceGCLayout
340338
TypeBuilder.GCLayout elementGcLayout = GetFieldGCLayout(arrayType.ElementType);
341339
if (!elementGcLayout.IsNone)
342340
{
343-
instanceGCLayout = new LowLevelList<bool>();
344-
elementGcLayout.WriteToBitfield(instanceGCLayout, 0);
345-
_instanceGCLayout = instanceGCLayout;
341+
_instanceGCLayout = elementGcLayout.AsBitfield();
346342
}
347343
}
348344
else

0 commit comments

Comments
 (0)