Skip to content

Improve handling of dynamic types in BulkType events #116629

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

Merged
merged 1 commit into from
Jun 14, 2025

Conversation

MichalStrehovsky
Copy link
Member

Dynamically allocated types (e.g. result of MakeGenericType) don't have debug information associated with them so we can't really reconstruct their names from PDB. However, we know the canonical form of the type and that one does have debug info. Emit RVA of the canonical form instead a non-sensical number.

Consumers can still distinguish this is a different thing using the TypeID field (that is still the MethodTable pointer). The canonical form is only used for TypeNameID, which is RVA in native AOT case and definition token in the JIT case. The consumer can quickly see that ModuleID + TypeNameID != TypeID`.

We could generate enough information to fully reconstruct the type name because the event can actually carry composition information, but that support was deleted in #94673 on native AOT side and it's currently not consumed by any tools I know of. It can be done later; Project N went to retirement with not even having the canonical forms in traces.

Cc @dotnet/ilc-contrib

Dynamically allocated types (e.g. result of `MakeGenericType`) don't have debug information associated with them so we can't really reconstruct their names from PDB. However, we know the canonical form of the type and that one does have debug info. Emit RVA of the canonical form instead a non-sensical number.

Consumers can still distinguish this is a different thing using the `TypeID` field (that is still the MethodTable pointer). The canonical form is only used for `TypeNameID`, which is RVA in native AOT case and definition token in the JIT case. The consumer can quickly see that `ModuleID + `TypeNameID != TypeID`.

We could generate enough information to fully reconstruct the type name because the event can actually carry composition information, but that support was deleted in dotnet#94673 on native AOT side and it's currently not consumed by any tools I know of. It can be done later; Project N went to retirement with not even having the canonical forms in traces.
Copy link
Contributor

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.

Copy link
Contributor

@Copilot Copilot AI left a comment

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 enhances dynamic type support in BulkType events by emitting the RVA of a type’s canonical template rather than an arbitrary pointer value. Key changes include:

  • Added GetDynamicTemplateType and extended GetFieldOffset to support function-pointer parameters and dynamic template types.
  • Updated EETypeField enum, flags, and Kinds in MethodTable.h for function pointers and dynamic-type metadata.
  • Modified BulkTypeEventLogger::LogSingleType to calculate TypeNameID from the canonical template for dynamic types.

Reviewed Changes

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

File Description
src/coreclr/nativeaot/Runtime/inc/MethodTable.inl Added GetDynamicTemplateType and extended GetFieldOffset logic.
src/coreclr/nativeaot/Runtime/inc/MethodTable.h Extended EETypeField, added flags/Kinds and helper methods.
src/coreclr/nativeaot/Runtime/eventtrace_bulktype.cpp Adjusted TypeNameID calculation to use dynamic template types.
Comments suppressed due to low confidence (4)

src/coreclr/nativeaot/Runtime/inc/MethodTable.inl:127

  • GetFieldOffset does not handle the newly introduced ETF_DynamicTypeFlags (and subsequent dynamic fields), causing these enum values to hit the NYI assertion. Implement cases for ETF_DynamicTypeFlags, ETF_DynamicGcStatics, ETF_DynamicNonGcStatics, and ETF_DynamicThreadStaticOffset.
ASSERT(!"NYI");

src/coreclr/nativeaot/Runtime/eventtrace_bulktype.cpp:322

  • The new dynamic template type path in LogSingleType isn’t covered by existing tests. Please add tests verifying the computed TypeNameID for dynamic types.
ULONGLONG rvaType = ULONGLONG(pTypeForRva) - osModuleHandle;

src/coreclr/nativeaot/Runtime/inc/MethodTable.h:287

  • [nitpick] Consider marking GetDynamicTemplateType as __forceinline to match other inline methods and avoid call overhead in performance-critical paths.
MethodTable* GetDynamicTemplateType();

src/coreclr/nativeaot/Runtime/eventtrace_bulktype.cpp:321

  • Add an assertion (e.g., ASSERT(pTypeForRva)) to ensure GetDynamicTemplateType returns a valid pointer before computing the RVA.
MethodTable* pTypeForRva = pEEType->IsDynamicType() ? pEEType->GetDynamicTemplateType() : pEEType;

Copy link
Member

@jkotas jkotas left a comment

Choose a reason for hiding this comment

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

Thanks

@MichalStrehovsky MichalStrehovsky merged commit 33ce341 into dotnet:main Jun 14, 2025
95 checks passed
@MichalStrehovsky MichalStrehovsky deleted the dynamictypelog branch June 14, 2025 10:32
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