-
Notifications
You must be signed in to change notification settings - Fork 5.4k
cDAC: Add GetGCDescSeries contract API and continuation pretty-printing #127419
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -564,6 +564,74 @@ private Data.EEClass GetClassData(TypeHandle typeHandle) | |||
| public bool IsContinuation(TypeHandle typeHandle) => typeHandle.IsMethodTable() | ||||
| && _continuationMethodTablePointer != TargetPointer.Null | ||||
| && _methodTables[typeHandle.Address].ParentMethodTable == _continuationMethodTablePointer; | ||||
|
|
||||
| IEnumerable<(uint SeriesOffset, uint SeriesSize)> IRuntimeTypeSystem.GetGCDescSeries(TypeHandle typeHandle, uint numComponents) | ||||
| { | ||||
| if (!typeHandle.IsMethodTable()) | ||||
| yield break; | ||||
|
|
||||
| if (!ContainsGCPointers(typeHandle)) | ||||
| yield break; | ||||
|
|
||||
| uint baseSize = GetBaseSize(typeHandle); | ||||
| uint componentSize = GetComponentSize(typeHandle); | ||||
| uint objectSize = baseSize + numComponents * componentSize; | ||||
|
|
||||
| ulong mtAddress = typeHandle.Address; | ||||
| ulong pointerSize = (ulong)_target.PointerSize; | ||||
|
|
||||
| // Sign-extend NumSeries from native pointer width. | ||||
| long numSeries = _target.PointerSize == sizeof(uint) | ||||
| ? (long)(int)_target.ReadPointer(mtAddress - pointerSize).Value | ||||
| : (long)_target.ReadPointer(mtAddress - pointerSize).Value; | ||||
| if (numSeries == 0) | ||||
| yield break; | ||||
|
|
||||
| if (numSeries > 0) | ||||
| { | ||||
| // Regular series: iterate from highest (closest to MT) to lowest. | ||||
| for (ulong i = 0; i < (ulong)numSeries; i++) | ||||
| { | ||||
| ulong seriesBase = mtAddress - (3 + 2 * i) * pointerSize; | ||||
| ulong rawSeriesSize = _target.ReadPointer(seriesBase).Value; | ||||
| ulong seriesOffset = _target.ReadPointer(seriesBase + pointerSize).Value; | ||||
| yield return ((uint)seriesOffset, (uint)(rawSeriesSize + objectSize)); | ||||
| } | ||||
| } | ||||
| else | ||||
| { | ||||
| // Value-class (repeating) series. | ||||
| long absNumSeries = -numSeries; | ||||
| ulong startOffset = _target.ReadPointer(mtAddress - 2 * pointerSize).Value; | ||||
|
|
||||
| ulong currentOffset = startOffset; | ||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this is trying to replicate https://github.com/microsoft/clrmd/blob/main/src/Microsoft.Diagnostics.Runtime/GCDesc.cs exactly, this would need to take the passed in object size into account too and keep repeating the sequence. I am not sure whether the API shape that takes object size works best for all cases. It assumes that you have object size that is not always the case, like for the Continuation pretty printing.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok. I don't see an issue with taking the object size; Continuation method tables do have the total object size stored on the method table flags, accessible through the GetBaseSize API. runtime/src/coreclr/vm/asynccontinuations.cpp Line 157 in 23d2e12
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we take an optional For non-array types, This removes redundant lookups at the call sites. The non-array path in Suggested shape: Inside the implementation: This also matches native's
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds good
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This shape works well for enumerating all GC references in the given object instance. It does not work well for dumping GCInfo without an object instance, or for efficient or partial enumeration of GC references. We can start with this shape; I am just pointing its short-comings. |
||||
| while (currentOffset <= objectSize - pointerSize) | ||||
| { | ||||
| for (long i = 0; i < absNumSeries; i++) | ||||
| { | ||||
| ulong itemAddress = mtAddress - (3 + (ulong)i) * pointerSize; | ||||
|
|
||||
| // Read val_serie_item fields individually for endianness safety. | ||||
| uint nptrs, skip; | ||||
| if (_target.PointerSize == sizeof(uint)) | ||||
| { | ||||
| nptrs = _target.Read<ushort>(itemAddress); | ||||
| skip = _target.Read<ushort>(itemAddress + sizeof(ushort)); | ||||
| } | ||||
| else | ||||
| { | ||||
| nptrs = _target.Read<uint>(itemAddress); | ||||
| skip = _target.Read<uint>(itemAddress + sizeof(uint)); | ||||
| } | ||||
|
|
||||
| uint runBytes = nptrs * (uint)pointerSize; | ||||
| yield return ((uint)currentOffset, runBytes); | ||||
| currentOffset += runBytes + skip; | ||||
| } | ||||
| } | ||||
| } | ||||
| } | ||||
|
|
||||
| public bool IsDynamicStatics(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.IsDynamicStatics; | ||||
| public ushort GetNumInterfaces(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (ushort)0 : _methodTables[typeHandle.Address].NumInterfaces; | ||||
|
|
||||
|
|
||||
Uh oh!
There was an error while loading. Please reload this page.