| File: Contracts\ExternalMemoryHandles_1.cs | Web Access |
| Project: Microsoft.Diagnostics.DataContractReader.Contracts.csproj (Microsoft.Diagnostics.DataContractReader.Contracts) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; using Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers; namespace Microsoft.Diagnostics.DataContractReader.Contracts; internal sealed class ExternalMemoryHandles_1 : IExternalMemoryHandles { private readonly Target _target; private readonly IGC _gc; private readonly IRuntimeTypeSystem _rts; private readonly GCInteriorPointerResolver _interiorPointerResolver; internal ExternalMemoryHandles_1(Target target) { _target = target; _gc = target.Contracts.GC; _rts = target.Contracts.RuntimeTypeSystem; _interiorPointerResolver = new GCInteriorPointerResolver(target); } IReadOnlyList<ExternalMemoryHandleRootData> IExternalMemoryHandles.GetRoots(bool resolveInteriorPointers) { List<ExternalMemoryHandleRootData> roots = []; TargetPointer headPointer = _target.ReadGlobalPointer(Constants.Globals.ExternalMemoryHandles); TargetPointer current = _target.ReadPointer(headPointer); HashSet<TargetPointer> visited = []; while (current != TargetPointer.Null) { if (!visited.Add(current)) throw new InvalidOperationException("ExternalMemoryHandle list is cyclic."); Data.ExternalMemoryHandle handle = _target.ProcessedData.GetOrAdd<Data.ExternalMemoryHandle>(current); ITypeHandle typeHandle = _rts.GetTypeHandle(handle.MethodTable); if (_rts.IsValueType(typeHandle)) { AddValueTypeRoots(roots, typeHandle, handle.Memory, resolveInteriorPointers); } else if (handle.GCFlags != 0) { AddInteriorRoot(roots, handle.Memory, resolveInteriorPointers); } else { roots.Add(new ExternalMemoryHandleRootData { Address = handle.Memory }); } current = handle.Next; } return roots; } private void AddValueTypeRoots( List<ExternalMemoryHandleRootData> roots, ITypeHandle typeHandle, TargetPointer memory, bool resolveInteriorPointers) { ulong pointerSize = (ulong)_target.PointerSize; if (_rts.IsByRefLike(typeHandle)) { ByRefPointerOffsetsReporter reporter = new(_target); foreach (ulong offset in reporter.Find(typeHandle)) AddInteriorRoot(roots, memory + offset, resolveInteriorPointers); } if (_rts.ContainsGCPointers(typeHandle)) { foreach ((uint seriesOffset, uint seriesSize) in _rts.GetGCDescSeries(typeHandle)) { // GCDesc series offsets include the boxed object's MethodTable pointer. ulong fieldStart = memory.Value + seriesOffset - pointerSize; for (ulong suboffset = 0; suboffset < seriesSize; suboffset += pointerSize) roots.Add(new ExternalMemoryHandleRootData { Address = new TargetPointer(fieldStart + suboffset) }); } } } private void AddInteriorRoot( List<ExternalMemoryHandleRootData> roots, TargetPointer slotAddress, bool resolveInteriorPointers) { TargetPointer obj = _target.ReadPointer(slotAddress.Value); ulong invalidPointer = _target.PointerSize == 8 ? ulong.MaxValue : uint.MaxValue; if (obj == TargetPointer.Null || obj.Value == invalidPointer) return; if (resolveInteriorPointers) { obj = _interiorPointerResolver.Resolve(obj); if (obj == TargetPointer.Null) return; } roots.Add(new ExternalMemoryHandleRootData { IsInteriorPointer = true, Address = slotAddress, Object = obj, }); } }