in src/Microsoft.Diagnostics.Runtime/src/Implementation/ClrmdSegment.cs [69:141]
public override IEnumerable<ClrObject> EnumerateObjects()
{
bool large = IsLargeObjectSegment || IsPinnedObjectSegment;
uint minObjSize = (uint)IntPtr.Size * 3;
ulong obj = FirstObjectAddress;
IDataReader dataReader = _helpers.DataReader;
// C# isn't smart enough to understand that !large means memoryReader is non-null. We will just be
// careful here.
using MemoryReader memoryReader = (!large ? new MemoryReader(dataReader, 0x10000) : null)!;
byte[] buffer = ArrayPool<byte>.Shared.Rent(IntPtr.Size * 2 + sizeof(uint));
// The large object heap
if (!large)
memoryReader.EnsureRangeInCache(obj);
while (ObjectRange.Contains(obj))
{
ulong mt;
if (large)
{
if (dataReader.Read(obj, buffer) != buffer.Length)
break;
mt = Unsafe.As<byte, nuint>(ref buffer[0]);
}
else
{
if (!memoryReader.ReadPtr(obj, out mt))
break;
}
ClrType? type = _helpers.Factory.GetOrCreateType(_clrmdHeap, mt, obj);
if (type is null)
break;
int marker = GetMarkerIndex(obj);
if (marker != -1 && _markers[marker] == 0)
_markers[marker] = obj;
ClrObject result = new ClrObject(obj, type);
yield return result;
ulong size;
if (type.ComponentSize == 0)
{
size = (uint)type.StaticSize;
}
else
{
uint count;
if (large)
count = Unsafe.As<byte, uint>(ref buffer[IntPtr.Size]);
else
memoryReader.ReadDword(obj + (uint)IntPtr.Size, out count);
// Strings in v4+ contain a trailing null terminator not accounted for.
if (_clrmdHeap.StringType == type)
count++;
size = count * (ulong)type.ComponentSize + (ulong)type.StaticSize;
}
size = ClrmdHeap.Align(size, large);
if (size < minObjSize)
size = minObjSize;
obj += size;
obj = _clrmdHeap.SkipAllocationContext(this, obj);
}
ArrayPool<byte>.Shared.Return(buffer);
}