-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
Overview
This is a follow up to #102248 which primarily affects CsWinRT. In order to support marshalling types we don't own (meaning we cannot attach a vtable to them via an attribute), the AOT generators in CsWinRT also generate a global lookup table with all necessary vtables for types it has seen as possibly used across the ABI boundary, in a given project. This looks something like this:
internal static class GlobalVtableLookup
{
[ModuleInitializer]
internal static void InitializeGlobalVtableLookup()
{
ComWrappersSupport.RegisterTypeComInterfaceEntriesLookup(LookupVtableEntries);
ComWrappersSupport.RegisterTypeRuntimeClassNameLookup(LookupRuntimeClassName);
}
private static ComWrappers.ComInterfaceEntry[] LookupVtableEntries(System.Type type)
{
switch (type.ToString())
{
case "System.Collections.Generic.Dictionary`2[System.String,System.String]":
case "System.Collections.ObjectModel.ReadOnlyDictionary`2[System.String,System.String]":
// Bunch of initialization...
return TheVTableForThisType();
case "System.ComponentModel.DataAnnotations.ValidationResult[]":
// Bunch of initialization...
return TheVTableForThisType();
case "ABI.System.Collections.Generic.ToAbiEnumeratorAdapter`1[System.Collections.IList]":
// Bunch of initialization...
return TheVTableForThisType();
// ...
default:
return null;
}
}
// 'LookupRuntimeClassName' here, which is kinda similar but returns type names instead
}This works just fine, but we noticed the linker isn't able to remove all branches for types that are not constructed.
Repro steps
- Create a blank .NET 9 project like this:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0-windows10.0.17763.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PublishAot>true</PublishAot>
<InvariantGlobalization>true</InvariantGlobalization>
<CsWinRTAotWarningLevel>2</CsWinRTAotWarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<IlcGenerateMstatFile>true</IlcGenerateMstatFile>
<IlcGenerateDgmlFile>true</IlcGenerateDgmlFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0-preview3" />
</ItemGroup>
</Project>- Paste this code:
using CommunityToolkit.Mvvm.ComponentModel;
Console.WriteLine(new MyViewModel());
public sealed partial class MyViewModel : ObservableObject
{
}- Publish with
dotnet publish -r win-x64 .\ConsoleApp13.csproj
Here's what we see in sizoscope:
That is, sizoscope isn't able to trim branches for types not constructed when checked via the type name.
Note
We cannot do GetType() == typeof() checks, because that would not work with internal types (which we also need to handle).
Proposal
We need a generalized way for this to work in such a way that we can also leverage this for internal types. For instance, either:
- Making ILLink/ILC also trim branches just comparing the fully qualified type name
- Making ILLink/ILC support this via some magic intrinsic (eg.
GetType() == Type.GetType("The.Type.Name") - Something else..?
To clarify, the issue is internal types from other assemblies, ie. such that we can't just do typeof(TheType) in code.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status
