-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
[API Proposal]: "*App*" wildcard for [UnsafeAccessor] assembly name #106216
Comments
Tagging subscribers to this area: @dotnet/area-system-runtime-compilerservices |
The #90081 propsal is written in a very narrow way. The input string would simply be passed to The Static version seems okay, but does come with serious costs around manipulating the supplied The Dynamic version is ill-advised because calling the same function would seem to change the content of the method. This would be a redesign of the entire feature. Once an I will need to read over the issues here, but the Dynamic version is a non-starter in my opinion. The Static one seems feasible. |
In my initial thinking, the Dynamic mode would call the resolution callback once per UnsafeAccessor method (when the IL is generated and the target is resolved). It wouldn't call it every time the method is called. |
Why is it not an option to use a fixed assembly name to generate the app specific WinRT interop? |
Okay, so that is the latter case. For me the concern comes down to I can call the function with the same inputs, but its behavior changes if Assembly A calls it vs if Assembly B calls it. That is how I read that feature and I'm not a fan. It creates a very complex scenario. Everytime an |
It wouldn't change based on caller of the UnsafeAccessor method. Assembly A and B would both have their own UnsafeAccessor methods that happen to be described the same but declared in different assemblies. In any case, @jkotas's idea would be significantly more straightforward if it would solve the scenario. |
I don't think I understand this. So let's say assembly A and assembly B both have the following public type: public class Accessor
{
[UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "get_Initialized")]
[UnsafeAccessorType("WinRT.GenericHelpers.IReadOnlyList_System_Collections_IList, *App*")]
public static extern bool IReadOnlyList_System_Collections_IList();
} If I call |
Why won't it? I thought I had proposed this offline a while ago as well. |
Mmh could you elaborate on how would this work? Suppose I have some project B (either an app, or perhaps a WinRT component), where I reference library A.dll, which has that |
Project B would have targets that run after CoreCompile that would generate and compile a sidecar assembly (likely with a temp csproj like how WPF XAML works today) that is only referenced by UnsafeAccessor methods. It would be copied out to the build and publish directories, added to the deps.json, and passed to crossgen2 and ILC as a reference. |
Mmh I see, that's interesting. Just so I understand, any particular reason why this would have to be after CoreCompile and then manually copied and added to deps.json, etc.? Could it not be compiled before CoreCompile and then the assembly added as |
You'd need to do it after CoreCompile if you want to analyze the "app" project easily and have it's generic helpers in this shared sidecar assembly as well. |
I see. Ok this idea is growing on me, and I could see this giving us a way to introduce all kinds of global program view optimizations for CsWinRT in the future. Is there some documented way to do this that we could take a dependency on in CsWinRT? That is, this part slightly worries me:
Are there public docs on what properties we'd need to set, where exactly we'd need to copy that .dll to, etc.? |
This would basically be done with MSBuild targets like how WPF does it. You'd want to hook after There shouldn't be any .NET SDK work necessary here. |
@Sergio0694 Based on the conversation about it doesn't look like this addition to the API is going to be considered. Feel free to re-open if needed, but I'm closing for now. |
Yup, that works for me! We'll be working on an implementation using an extension .dll as suggested 🙂 |
Background
As part of CsWinRT 2.1.1, we introduced AOT support in WinRT scenarios. In order to make this happen, CsWinRT now also generates a fair amount (read: a metric ton) of code to make things such as WinRT generics work. This support comes with several drawbacks though. The first one is that it is viral: we need every single library to reference CsWinRT in order to make types AOT compatible when used for WinRT interop. This doesn't just affect libraries that are specific to Windows, but any library which contains types that will be used in WinRT scenarios. For instance, I've had to add the Windows TFM to the MVVM Toolkit, so that the types in the MVVM Toolkit could get the necessary supporting code generated. This isn't really fixable, it's just the state of things now that WinRT support is lifted.
On top of this however, we have two main problems that we'd like to solve:
For instance, here's just some of these supporting types generated in the MVVM Toolkit:
It's very easy for a large app to have even hundreds of these spread across all your dependencies and projects. And it's not uncommon that a lot of these will just be copies and copies of the same combinations of type arguments (eg.
string
).We'd like improve things and move as much code generation as possible down to the published projects.
API proposal
The proposal is not an API, but an extension on top of #90081. We'd like to add a new "*App*" wildcard that can be used in place of assembly names for
[UnsafeAccessor]
methods. The exact semantics would be controlled via a new feature switch that can be configured via the newUnsafeAccessorOutputAssemblyResolutionType
property. There would be two modes:Example use
Consider the current CsWinRT code generation for some enumerable type, such as
ObservableGroup<TKey, TElement>
:Generated CCW vtable (click to expand):
This, along with all of those
IReadOnlyList_System_Collections_IList
etc. implementations (each of those is and lot of code as well). With this proposed feature, we'd be able to not generate any of that, and simply do this instead:For any generic type instantiation we need. Then, replace those
Initialized
accesses with:And just call those, which would call the shared generated generic type instantiation in the final assembly. This support could technically us to go even further and potentially just have the entire vtable implementation call to some well known generated method in the final assembly, if we found that method to be even better for CsWinRT (either would work).
Essentially, this allows us to:
Additional information
This design includes suggestions from @jkoritzinsky, who pointed out that in several scenarios around ALC, there is no "entry assembly", or you might have a given dependency library being loaded in one ALC and then referenced by some other code in another ALC. In those cases, the "Dynamic" mode would allow eg. CsWinRT to implement an appropriate resolver callback.
cc. @AaronRobinsonMSFT @jkotas @MichalStrehovsky @agocke
The text was updated successfully, but these errors were encountered: