in src/Microsoft.Diagnostics.Runtime/ClrHeap.cs [888:950]
internal IEnumerable<ClrObject> EnumerateObjectReferences(ulong obj, ClrType type, bool carefully, bool considerDependantHandles)
{
if (type is null)
throw new ArgumentNullException(nameof(type));
if (considerDependantHandles)
{
(ulong Source, ulong Target)[] dependent = GetDependentHandles();
if (dependent.Length > 0)
{
int index = dependent.Search(obj, (x, y) => x.Source.CompareTo(y));
if (index != -1)
{
while (index >= 1 && dependent[index - 1].Source == obj)
index--;
while (index < dependent.Length && dependent[index].Source == obj)
{
ulong dependantObj = dependent[index++].Target;
yield return new(dependantObj, GetObjectType(dependantObj) ?? ErrorType);
}
}
}
}
if (type.IsCollectible)
{
ulong la = _memoryReader.ReadPointer(type.LoaderAllocatorHandle);
if (la != 0)
yield return new(la, GetObjectType(la) ?? ErrorType);
}
if (type.ContainsPointers)
{
GCDesc gcdesc = type.GCDesc;
if (!gcdesc.IsEmpty)
{
ulong size = GetObjectSize(obj, type);
if (carefully)
{
ClrSegment? seg = GetSegmentByAddress(obj);
if (seg is null)
yield break;
bool large = seg.Kind is GCSegmentKind.Large or GCSegmentKind.Pinned;
if (obj + size > seg.End || (!large && size > MaxGen2ObjectSize))
yield break;
}
int intSize = (int)size;
byte[] buffer = ArrayPool<byte>.Shared.Rent(intSize);
int read = _memoryReader.Read(obj, new Span<byte>(buffer, 0, intSize));
if (read > IntPtr.Size)
{
foreach ((ulong reference, int offset) in gcdesc.WalkObject(buffer, read))
yield return new(reference, GetObjectType(reference) ?? ErrorType);
}
ArrayPool<byte>.Shared.Return(buffer);
}
}
}