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

Generate type generic composition information as constructed #105133

Merged
merged 4 commits into from
Jul 28, 2024

Conversation

MichalStrehovsky
Copy link
Member

@MichalStrehovsky MichalStrehovsky commented Jul 19, 2024

Fixes #105034.

Before this PR, whenever we had a generic instance Foo<SomeType, OtherType<SomeOtherType>> and we had a constructed MethodTable for this (i.e. MethodTable that is suitable to be used for types on the GC heap), we'd still try to optimize out the MethodTables for SomeType, OtherType<SomeOtherType> into the "unconstructed" form (i.e. without a GCDesc or vtable).

This is generally a safe optimization - if Foo<,> actually had a typeof(T) somewhere, we'd upgrade the unconstructed forms into constructed forms, for example.

One place where the unconstructed types can be obtained is when reflection-inspecting such instantiation - asking for GetGenericArguments of a type could produce things that have unconstructed MethodTables in them. In general, this is also fine - one can't do much reflection with these and asking for e.g. names would still work fine. Trying to access members or activating something obtained from GetGenericArguments would trigger trimming warnings, so that's also fine.

Enter Microsoft.Extension.DependencyInjection and a trimming warning suppression in there.

DI has support for something called IOption<T> where the T is annotated with DAM attributes. Then there's another type (OptionFactory<T>? Can't be bothered to look at that again.) that has the T annotated the same way. Then there's some code that will deconstruct the IOption instance that we saw statically, and MakeGenericType an OptionFactory with its generic arguments. The warnings on MakeGenericType are suppressed on account of: T is annotated the same, and T is not a valuetype.

The suppression sounds reasonable. It just doesn't hold right now, since nothing accesses the T in IOption and we're therefore left with the unconstructed form of the T. The OptionFactory though accesses the T and tries to activate it.

This is especially a problem if IOption is instantiated over a generic type that is instantiated over a valuetype. We know we need to keep the ctor due to the annotation, but not on unconstructed forms of the type.

I was struggling with how to fix this. The easiest fix is to just stop optimizing things into unconstructed forms. This is a size regression.

Cc @dotnet/ilc-contrib

Copy link
Contributor

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

@MichalStrehovsky MichalStrehovsky changed the title [Ignore] Test change Generate type generic composition information as constructed Jul 25, 2024
@MichalStrehovsky
Copy link
Member Author

Size statistics

Pull request #105133

Project Size before Size after Difference
avalonia.app-linux 24639504 24661200 21696
avalonia.app-windows 22122496 22139904 17408
hello-linux 1352384 1360672 8288
hello-minimal-linux 1077864 1086136 8272
hello-minimal-windows 858624 864768 6144
hello-windows 1105408 1112576 7168
kestrel-minimal-linux 5583712 5609680 25968
kestrel-minimal-windows 4929536 4949504 19968
reflection-linux 2228144 2252928 24784
reflection-windows 1885184 1898496 13312
webapiaot-linux 10230400 10255136 24736
webapiaot-windows 9161728 9183232 21504
winrt-component-full-windows 5515776 5520896 5120
winrt-component-minimal-windows 1833984 1847808 13824

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.

Sigh

@MichalStrehovsky
Copy link
Member Author

Sigh

Hmm, maybe we can restrict it to types that have DAM-annotations somewhere on the generic parameters? It still fixes the DI suppression case and I can't think of other holes right now. The extra code doesn't look too terrible and I'll run rt-sz to check how much that improves things.

@MichalStrehovsky
Copy link
Member Author

Looks better like this and the code is not much more complicated:

Size statistics

Pull request #105133

Project Size before Size after Difference
avalonia.app-linux 24706016 24706048 32
avalonia.app-windows 22172672 22174208 1536
hello-linux 1344176 1344176 0
hello-minimal-linux 1073752 1073752 0
hello-minimal-windows 856576 856576 0
hello-windows 1102848 1103360 512
kestrel-minimal-linux 5629104 5629104 0
kestrel-minimal-windows 4966912 4966912 0
reflection-linux 2075984 2075984 0
reflection-windows 1757184 1757184 0
webapiaot-linux 10237152 10237152 0
webapiaot-windows 9178112 9178624 512
winrt-component-full-windows 5506560 5507072 512
winrt-component-minimal-windows 1750528 1750528 0

@MichalStrehovsky
Copy link
Member Author

/azp run runtime-nativeaot-outerloop

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@MichalStrehovsky MichalStrehovsky merged commit 554d7c9 into dotnet:main Jul 28, 2024
110 of 115 checks passed
@MichalStrehovsky MichalStrehovsky deleted the test branch July 28, 2024 08:56
@github-actions github-actions bot locked and limited conversation to collaborators Aug 30, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
2 participants