Skip to content
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

Mark most specific static DIM for types marked RelevantToVariantCasting #97487

Merged
merged 23 commits into from
Feb 10, 2024

Conversation

jtschuster
Copy link
Member

@jtschuster jtschuster commented Jan 25, 2024

Fixes #96855
Fixes #96854

Previously, we weren't handling static DIMs to ensure that DIMs that provided an implementation of an interface method for an inheriting type would be kept.

This method gets rid of _interfaceOverrides and uses _virtual_methods with TypeMapInfo to find all interface method / implementation pairs.

This PR adds static method handling to the ProcessDefaultImplementation method where it previously only handled instance interface methods. It assumes all static interface methods will be needed if the type implementing the interface IsRelevantToVariantCasting.

The DIM cache also is updated to include the method that provides the implementation for a type.

@ghost ghost added the linkable-framework Issues associated with delivering a linker friendly framework label Jan 25, 2024
@dotnet-issue-labeler dotnet-issue-labeler bot added the area-Tools-ILLink .NET linker development as well as trimming analyzers label Jan 25, 2024
@ghost ghost assigned jtschuster Jan 25, 2024
@ghost
Copy link

ghost commented Jan 25, 2024

Tagging subscribers to 'linkable-framework': @eerhardt, @vitek-karas, @LakshanF, @sbomer, @joperezr, @marek-safar
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #96855
Fixes #96854

When a type is marked as relevant to variant casting we should consider all it's interfaces and base types also relevant to variant casting. This causes these lines to mark overrides of static interfaces whose types are relevant to variant casting, so we mark all static default interface methods. This causes a little bit of overmarking (IMiddle in the tests could be removed).

Author: jtschuster
Assignees: -
Labels:

linkable-framework

Milestone: -

@jtschuster jtschuster changed the title Mark all base types and interfaces as RelevantToVariantCasting Mark most specific static DIM for types marked RelevantToVariantCasting Feb 1, 2024
@jtschuster jtschuster marked this pull request as ready for review February 1, 2024 00:33
src/tools/illink/src/linker/Linker.Steps/MarkStep.cs Outdated Show resolved Hide resolved
src/tools/illink/src/linker/Linker.Steps/MarkStep.cs Outdated Show resolved Hide resolved
var overridingMethods = Annotations.GetOverrides (method);
if (overridingMethods is not null) {
foreach (var ov in overridingMethods ?? []) {
if (IsInterfaceImplementationMethodNeededByTypeDueToInterface (ov, ov.Override.DeclaringType))
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure using ov.Override.DeclaringType as the type with interfaceimpl is correct. I'm worried this could miss a case where we added an interface method due to IgnoreScope, and the type with interfaceimpl was passed as a generic arg, but the override declaring type is an interface that provides the default impl (but wasn't passed as a generic arg).

Copy link
Member Author

Choose a reason for hiding this comment

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

Shouldn't that situation be caught above when we loop over the default implementations of each interface method?

Copy link
Member

Choose a reason for hiding this comment

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

I suppose that's true. It still worries me that the override declaring type isn't the same as the type with interfaceimpl that IsInterfaceImplementationMethodNeededByTypeDueToInterface expects. But I can't think of any problems with it. Maybe add a comment here in case we need to look at this again?

Copy link
Member Author

Choose a reason for hiding this comment

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

I thought about this a little more, and it's another one of those "It works all the time, but not because the logic is correct". The DIM logic above handles static interface methods since they cannot be provided by a base type, only a DIM, but If a base method provides an instance method, we'll pass the wrong type in, but if the type implementing the interface is instantiated, the type providing the method for the interface will also be marked as instantiated.

Copy link
Member Author

Choose a reason for hiding this comment

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

Looks like this fix is going to be more involved. I'll make an issue and make a separate PR.

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

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

Uh oh, I really thought static interface methods couldn't be provided by the base, and I think that assumption might be made in the linker. I'll set up some test cases and see what's broken.

Copy link
Member Author

@jtschuster jtschuster Feb 16, 2024

Choose a reason for hiding this comment

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

Ah, the compiler injects a static interface method on D that call's C's method, so I think the assumption is valid. If the implementation on D is removed, ilasm can compile the IL, but it fails at runtime with a TypeLoadException:

Unhandled exception. System.TypeLoadException: Virtual static method 'M' is not implemented on type 'D' from assembly '_, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.

Copy link
Member

Choose a reason for hiding this comment

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

Oh, good to know. Thanks for checking!

Copy link
Member

@sbomer sbomer left a comment

Choose a reason for hiding this comment

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

Thank you!

MarkMethod (ov.Override, new DependencyInfo (DependencyKind.Override, ov.Base), ScopeStack.CurrentScope.Origin);
}
}
var overridingMethods = Annotations.GetOverrides (method);
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if this might be causing the perf regression dotnet/sdk#40060, since it looks like we're newly walking the overrides of a virtual method every time we get here.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-Tools-ILLink .NET linker development as well as trimming analyzers linkable-framework Issues associated with delivering a linker friendly framework
Projects
None yet
2 participants