Skip to content

Emit a resolvable type name for Runtime Async continuations in GC heap dumps - #131684

Open
tommcdon wants to merge 5 commits into
dotnet:mainfrom
tommcdon:dev/tommcdon/gcdump-continuation-typename
Open

Emit a resolvable type name for Runtime Async continuations in GC heap dumps#131684
tommcdon wants to merge 5 commits into
dotnet:mainfrom
tommcdon:dev/tommcdon/gcdump-continuation-typename

Conversation

@tommcdon

Copy link
Copy Markdown
Member

The GCHeapDump BulkType event set fixedSizedData.TypeNameID = TypeHandle::GetCl() and the type name from TypeHandle::GetName(). For a metadata-less Runtime Async continuation MethodTable, GetCl() is the nil TypeDef token (0x02000000) and GetName() yields an empty string, so eventpipe readers such as dotnet-gcdump render every continuation as
Type(0x02000000) with no usable name.

Describe continuations using the base Continuation type (via UpCastTypeIfNeeded) for the module id, name token, and name, while keeping the per-object TypeID as the derived MethodTable so GCBulkNode entries still resolve to this record. This
also avoids MethodTable::GetModule()'s IsContinuationWithoutMetadata() assert on
checked builds.

Validated with dotnet-gcdump against a process holding 128 live continuations:

  • Baseline: 128 objects showed as Type(0x02000000)
  • Fix: they show as System.Runtime.CompilerServices.Continuation and the capture still succeeds.

Adds a test case for runtime-async to cover this scenario.

Relates to #120800

tommcdon and others added 3 commits July 31, 2026 18:27
…p dumps

The GCHeapDump BulkType event set fixedSizedData.TypeNameID = TypeHandle::GetCl()
and the type name from TypeHandle::GetName(). For a metadata-less Runtime Async
continuation MethodTable, GetCl() is the nil TypeDef token (0x02000000) and
GetName() yields an empty string, so dotnet-gcdump renders every continuation as
"Type(0x02000000)" with no usable name.

Describe continuations using the base Continuation type (via UpCastTypeIfNeeded)
for the module id, name token, and name, while keeping the per-object TypeID as
the derived MethodTable so GCBulkNode entries still resolve to this record. This
also avoids MethodTable::GetModule()'s IsContinuationWithoutMetadata() assert on
checked builds.

Validated with dotnet-gcdump against a process holding 128 live continuations:
before, 128 objects showed as "Type(0x02000000)"; after, they show as
"System.Runtime.CompilerServices.Continuation" and the capture still succeeds.

Relates to dotnet#120800

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Regression test for dotnet#120800. Creates live
Runtime Async continuations (metadata-less continuation MethodTables), captures a
GC heap snapshot over EventPipe (GCHeapSnapshot keyword), and asserts every logged
type in the GCBulkType events carries a non-empty name and that a continuation type
is observed. Before the accompanying runtime fix, the metadata-less continuations
were logged with an empty name (rendered as "Type(0x02000000)" by dotnet-gcdump);
the test's _emptyTypeNameCount==0 assertion guards that.

Models the existing gcdump test; enables Runtime Async via <Features>runtime-async=on</Features>
plus a DOTNET_RuntimeAsync=1 CLRTestEnvironmentVariable, and skips itself if Runtime
Async is not active.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tommcdon tommcdon added this to the 11.0.0 milestone Jul 31, 2026
@tommcdon tommcdon self-assigned this Jul 31, 2026
Copilot AI review requested due to automatic review settings July 31, 2026 23:14
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @steveisok, @tommcdon, @dotnet/dotnet-diag
See info in area-owners.md if you want to be subscribed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates CoreCLR GC heap dump type emission so runtime-async metadata-less continuation subtypes are reported with a resolvable, non-empty type name (by using an upcast “named” TypeHandle for module/token/name), and adds an EventPipe regression test to cover the scenario.

Changes:

  • Adjust GCHeapDump BulkType logging to use TypeHandle::UpCastTypeIfNeeded() for ModuleID, TypeNameID, and the emitted type name, while keeping TypeID as the actual object MethodTable.
  • Add a new EventPipe test app that creates suspended runtime-async continuations and validates that BulkType entries never have an empty TypeName.
  • Add a dedicated csproj configuring the feature flag and runtime-async enablement for the test.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/coreclr/vm/eventtrace_bulktype.cpp Emits module/token/name using an upcast type for metadata-less runtime-async continuation subtypes.
src/tests/tracing/eventpipe/gcdump_runtimeasync/gcdump_runtimeasync.csproj New test project enabling runtime-async=on and setting DOTNET_RuntimeAsync=1.
src/tests/tracing/eventpipe/gcdump_runtimeasync/gcdump_runtimeasync.cs New regression test that captures a GC heap snapshot and asserts type names are non-empty (and continuation types appear).

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 1, 2026 03:32
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: e8cd920d-9e3e-4b34-b898-de7bdad68f24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/tests/tracing/eventpipe/gcdump_runtimeasync/gcdump_runtimeasync.csproj:10

  • The comment says runtime-async is enabled via an AppContext switch set in Main, but the test doesn't set any AppContext switch. The only runtime enablement here appears to be the DOTNET_RuntimeAsync test environment variable below, so the comment is misleading.
    <!-- Emit Runtime Async method bodies so the runtime creates the dynamic metadata-less
         continuation MethodTables this test exercises. The runtime side is enabled in-process
         via the AppContext switch set in Main. -->
    <Features>$(Features);runtime-async=on</Features>

Copilot AI review requested due to automatic review settings August 1, 2026 03:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/tests/tracing/eventpipe/gcdump_runtimeasync/gcdump_runtimeasync.cs:72

  • This runtime-async guard makes the test silently pass (return 100) if runtime-async isn’t actually enabled, which can make the test vacuous and hide regressions. It also risks a NullReferenceException if reflection ever fails to locate the method. Prefer treating this as a hard failure (or use attribute-based skip logic) and avoid the possible null dereference.
            // Verify Runtime Async is actually active; otherwise the test would be vacuous.
            var mi = typeof(GCDumpRuntimeAsyncTest).GetMethod(nameof(Suspended),
                System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
            bool runtimeAsync = (mi.MethodImplementationFlags & System.Reflection.MethodImplAttributes.Async) != 0;
            if (!runtimeAsync)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants