-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Optimize away GVM resolution metadata #118632
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
Conversation
Ever since GVM support was added to native AOT, we were generating the GVM resolution metadata for every type considered allocated. This included GVMs that were never even called (see `TypeGVMEntriesNode` that simply goes over everything on the type). This PR introduces tracking with method level granularity. I ran into this in a different PR where this was dragging `double`/`float` into compilation just because `int` implements generic math.
Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas |
There was a problem hiding this 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 optimizes GVM (Generic Virtual Method) resolution metadata generation in native AOT by implementing method-level granularity tracking instead of type-level tracking. Previously, GVM metadata was generated for all allocated types that had any relationship to GVMs, even if specific GVMs were never called. Now, metadata is only generated for GVMs that are actually used in the program.
Key changes include:
- Replace type-based
TypeGVMEntriesNode
with method-specificGVMMetadataNode
andInterfaceGVMMetadataNode
- Update dependency tracking to register metadata nodes only when GVMs are actually needed
- Modify table generation logic to use the new granular metadata nodes
Reviewed Changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.
Show a summary per file
File | Description |
---|---|
ILCompiler.Compiler.csproj | Updates project file to remove TypeGVMEntriesNode and add new metadata node files |
MetadataManager.cs | Replaces type-based GVM tracking with method-specific collections and accessors |
TypeGVMEntriesNode.cs | Removes the old type-level GVM metadata tracking implementation |
NodeFactory.cs | Adds factory methods and cache structures for the new method-specific metadata nodes |
InterfaceGenericVirtualMethodTableNode.cs | Updates table generation to use new granular interface GVM metadata |
InterfaceGVMMetadataNode.cs | New node for tracking interface GVM metadata at method level |
GenericVirtualMethodTableNode.cs | Updates table generation to use new granular GVM metadata |
GVMMetadataNode.cs | New node for tracking GVM metadata at method level |
GVMDependenciesNode.cs | Updates dependency registration to create metadata nodes when GVMs are used |
EETypeNode.cs | Removes automatic creation of type-level GVM entries |
ConstructedEETypeNode.cs | Removes type-level GVM dependency tracking for canonical types |
|
||
public override bool Equals(object obj) => obj is InterfaceGVMMetadataKey other && Equals(other); | ||
public bool Equals(InterfaceGVMMetadataKey other) => CallingMethod == other.CallingMethod && ImplementationType == other.ImplementationType; | ||
public override int GetHashCode() => HashCode.Combine(CallingMethod, ImplementationType); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Equals method for InterfaceGVMMetadataKey is incomplete. It only compares CallingMethod and ImplementationType, but ignores ImplementationMethod and DefaultResolution fields. This could lead to incorrect equality comparisons and potential cache key collisions.
public override int GetHashCode() => HashCode.Combine(CallingMethod, ImplementationType); | |
public bool Equals(InterfaceGVMMetadataKey other) => | |
CallingMethod == other.CallingMethod && | |
ImplementationMethod == other.ImplementationMethod && | |
ImplementationType == other.ImplementationType && | |
DefaultResolution == other.DefaultResolution; | |
public override int GetHashCode() => HashCode.Combine(CallingMethod, ImplementationMethod, ImplementationType, DefaultResolution); |
Copilot uses AI. Check for mistakes.
/azp run runtime-nativeaot-outerloop |
Azure Pipelines successfully started running 1 pipeline(s). |
Ever since GVM support was added to native AOT, we were generating the GVM resolution metadata for every type considered allocated. This included GVMs that were never even called: see `TypeGVMEntriesNode` that simply goes over everything on the type - we were adding a `TypeGVMEntriesNode` for all allocated types that have something to do with GVMs. This PR changes it so that we only generate `TypeGVMEntries` for types that have at least one used GVM. This is a scoped down version of dotnet#118632 (that tries to track things per-method) with a lot less risk.
This is problematic because we don't keep track of all Scoped down version of this at #118704. |
Ever since GVM support was added to native AOT, we were generating the GVM resolution metadata for every type considered allocated. This included GVMs that were never even called: see `TypeGVMEntriesNode` that simply goes over everything on the type - we were adding a `TypeGVMEntriesNode` for all allocated types that have something to do with GVMs. This PR changes it so that we only generate `TypeGVMEntries` for types that have at least one used GVM. This is a scoped down version of #118632 (that tries to track things per-method) with a lot less risk.
Ever since GVM support was added to native AOT, we were generating the GVM resolution metadata for every type considered allocated. This included GVMs that were never even called: see
TypeGVMEntriesNode
that simply goes over everything on the type - we were adding aTypeGVMEntriesNode
for all allocated types that have something to do with GVMs.This PR introduces tracking with method level granularity. I ran into this in a different PR where this was dragging
double
/float
into compilation just becauseint
implements generic math.After this PR, we'll have a
GVMMetadataNode
for every generic virtual method slot definition or slot override (uninstantiated) that is used in the program. We'll also have aInterfaceGVMMetadataNode
that is the same but for interface methods. The generation logic inInterfaceGenericVirtualMethodTableNode
andGenericVirtualMethodTableNode
was updated to look at these new nodes instead of walking everything on the type.Cc @dotnet/ilc-contrib