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

Handle scenarios when the transitive closure of types is known. #78

Open
AaronRobinsonMSFT opened this issue Feb 19, 2020 · 12 comments
Open
Labels
enhancement New feature or request performance Related to performance work
Milestone

Comments

@AaronRobinsonMSFT
Copy link
Member

AaronRobinsonMSFT commented Feb 19, 2020

There are scenarios in WinRT where the transitive closure of all types is known. This would imply there are opportunities to optimize the RCW code generation logic and avoid querying the runtime for these types - see

internal static Func<IInspectable, object> CreateTypedRcwFactory(string runtimeClassName)

Reasons for considering this are: AOT and linkability (reduce memory footprint).

@jkotas
Copy link
Member

jkotas commented Feb 19, 2020

The default for the WinRT (store) apps should be the constrained environment, where the transitive closure of all types is known, without reflection fallbacks. Otherwise, the WinRT apps are going to be big and slow by default.

Would it make sense to have an explicit opt-in (e.g. API call) to enable the reflection fallbacks, so that only apps that want to pay for it get it?

@jkoritzinsky
Copy link
Member

Another option would be to expose an API to allow an app to pre-register its factories. Then in cases where the transitive type closure is known, the entire table could be pre-registered at startup before the app runs.

We could make the reflection fallback opt-in if we feel that there are users who would rather have the code throw an exception than go down the reflection path.

@AaronRobinsonMSFT
Copy link
Member Author

@jkoritzinsky Would CsWinRT expose this new API or the runtime for CsWinRT to query? I would prefer the former rather than the latter. I think providing some pseudo code that illustrates how Apps and CsWinRT would interact would be helpful to illustrate the idea.

@jkoritzinsky
Copy link
Member

CsWinRT would expose this API and code generated by some task in the SDK toolchain would call it at startup either in a module initializer or a Main method. I’ll post some possible pseudo code tomorrow.

@jkoritzinsky
Copy link
Member

jkoritzinsky commented Feb 20, 2020

Here's the API I'm thinking of. We can do either or both depending on what we think is better (or what gives better perf).

public partial static class ComWrappersSupport
{
     public static void RegisterObjectFactoryForRuntimeClass(string runtimeClassName, Func<WinRT.IInspectable, object> factory);

     public static void RegisterObjectFactoriesForRuntimeClass(params System.Collections.Generic.KeyValuePair<string, Func<WinRT.IInspectable, object>>[] factories);

}

The usage would be something like as follows:

public static void Main()
{
     WinRT.ComWrappersSupport.RegisterObjectFactoryForRuntimeClass("Windows.Foundation.IReference`1<Int32>", inspectable => new ABI.Windows.Foundation.IReference<int>(inspectable.As<ABI.Windows.Foundation.IReference<int>.Vftbl>()));
// Run the WinUI application here.
}

This would require us to make the types in the ABI namespace public instead of their current internal visibility.

@AaronRobinsonMSFT
Copy link
Member Author

@jkoritzinsky Perhaps it would be better to have the caller provide a ComWrappers instance instead? I would like to limit ways to create external object wrappers and the ComWrappers already exists so it might make sense to reuse that.

@jkoritzinsky
Copy link
Member

We could do that as well if we're ok with this API being available only on the .NET 5 target.

@jkoritzinsky
Copy link
Member

Unless we want to play the type-fowarding game and define a ComWrappers type in CsWinRT in System.Runtime.InteropServices that type-forwards to the runtime-defined one on .NET 5.

@AaronRobinsonMSFT
Copy link
Member Author

We could do that as well if we're ok with this API being available only on the .NET 5 target.

The non .NET 5 approach is already degraded due to the inability to properly interact with a tracker runtime (e.g. Jupiter) and the more expensive object identity and lifetime tracking mechanisms that are implemented in .NET Standard 2.0. I think that would be okay. I am not entirely convinced this API would provide the most optimized/AOT-friendly approach though.

@jkoritzinsky
Copy link
Member

I meant define it in the System.Runtime.InteropServices namespace in a singular location (since some of the CsWinRT code is going to have to be shared across all projections anyway) that multitargets netstandard2.0 and net5 and type-forwards on the net5 target.

I don't particularly like the idea, but we could do it.

@jkotas
Copy link
Member

jkotas commented Feb 20, 2020

Here's the API I'm thinking of

It would be nice if this API allows hydrating the registrations lazily. E.g. If the app has 1000 types but only one of them is actually created at runtime, the app should only pay for that one type.

@stevenbrix
Copy link
Contributor

CsWinRT would expose this API and code generated by some task in the SDK toolchain would call it at startup either in a module initializer or a Main method. I’ll post some possible pseudo code tomorrow.

@jkoritzinsky is there work planned for the sdk toolchain to support this? And I'm guessing you are referring to the Windows SDK?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request performance Related to performance work
Projects
None yet
Development

No branches or pull requests

8 participants