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

Fixing COM Aggregation and XAML reference tracking on .NET AOT #90283

Merged
merged 20 commits into from Aug 13, 2023

Conversation

manodasanW
Copy link
Contributor

@manodasanW manodasanW commented Aug 9, 2023

There were blocks put in place in AOT for COM aggregation and XAML reference tracking wasn't implemented. This PR adds support for both of them by porting the CoreCLR native code that existed to C# for AOT support. With these changes, the ComWrappers API tests and weak reference tests all pass.

Fixes #89713
Fixes #85137

@ghost
Copy link

ghost commented Aug 9, 2023

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

Issue Details

There were blocks put in place in AOT for COM aggregation and XAML reference tracking wasn't implemented. This PR adds support for both of them by porting the CoreCLR native code that existed to C# for AOT support. With these changes, the ComWrappers API tests all pass. The weak reference tests currently do fail due to that logic isn't ported yet which I am looking in now but starting the PR with the core changes in the meantime.

Fixes #89713
Fixes #85137

Author: manodasanW
Assignees: -
Labels:

area-NativeAOT-coreclr

Milestone: -

Copy link
Member

@jkoritzinsky jkoritzinsky left a comment

Choose a reason for hiding this comment

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

LGTM, but I'll defer to @AaronRobinsonMSFT for final sign-off.

if (_pHandles == null)
{
_capacity = DefaultCapacity;
_pHandles = (IntPtr*)Interop.Ucrtbase.calloc((nuint)_capacity, (nuint)sizeof(IntPtr));
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes we do, the logic as ported checks if there was a previously allocated dependency handle at the slot by checking if it is not default / zero and if so overrides the target and dependent for it rather than allocating a new one.

@AaronRobinsonMSFT
Copy link
Member

Thanks @manodasanW. So far so good.

/cc @AustinWise

@AaronRobinsonMSFT AaronRobinsonMSFT added this to the 8.0.0 milestone Aug 10, 2023
manodasanW and others added 3 commits August 9, 2023 19:36
Co-authored-by: Aaron Robinson <arobins@microsoft.com>
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
Co-authored-by: Jeremy Koritzinsky <jkoritzinsky@gmail.com>
Copy link
Contributor

@Sergio0694 Sergio0694 left a comment

Choose a reason for hiding this comment

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

Just leaving a few thoughts here. This is all looking amazing!! 🎉

@manodasanW
Copy link
Contributor Author

@jkotas it looks like the build is failing on osx-x64 Release NativeAOT due to the binary size increased. What options do we have here?

  ****************************************************
  * Size test                                        *
  * Size of the executable is   1,780 kB             *
  ****************************************************
  BUG: File size is not in the expected range (1331200 to 1792000 bytes). Did a libraries change regress size of Hello World?

@jkotas
Copy link
Member

jkotas commented Aug 11, 2023

It means that a lot of the ComWrappers code ends up in the final binary even when none of it is actually used.

The problem is most likely caused by the calls from WeakReference/ComAwareWeakReference. We either need to make all these calls from WeakReference to go through indirections that are initialized only after the Com wrappers tracking is initialized (ie replace the bool that you have added with a bunch of delegates or function pointers, and make sure to do all calls from WeakReference/ComAwareWeakReference via these).

If that does not work for some reason, we may need end up introducing a feature switch to enable this feature in WinUI apps only. https://learn.microsoft.com/en-us/dotnet/core/runtime-config/threading#autoreleasepool-for-managed-threads is a good example of prior art.

@Sergio0694
Copy link
Contributor

"If that does not work for some reason, we may need end up introducing a feature switch to enable this feature in WinUI apps only"

Pretty sure that's what you meant, but just to double check: did you just use WinUI as a reference here but the feature switch would just be a general-purpose feature switch like others in .NET, that anyone could use? Because WinUI 3 apps are not the only applications that would use the new stuff added in this PR. For instance, COM aggregation can be needed by any WASDK app (without WinUI 3) that also happens to have some types deriving from WinRT projection types.

@jkotas
Copy link
Member

jkotas commented Aug 11, 2023

the feature switch would just be a general-purpose feature switch like others in .NET, that anyone could use?

Correct.

We should investigate first whether this feature switch is actually needed.

@manodasanW
Copy link
Contributor Author

It means that a lot of the ComWrappers code ends up in the final binary even when none of it is actually used.

The problem is most likely caused by the calls from WeakReference/ComAwareWeakReference. We either need to make all these calls from WeakReference to go through indirections that are initialized only after the Com wrappers tracking is initialized (ie replace the bool that you have added with a bunch of delegates or function pointers, and make sure to do all calls from WeakReference/ComAwareWeakReference via these).

If that does not work for some reason, we may need end up introducing a feature switch to enable this feature in WinUI apps only. https://learn.microsoft.com/en-us/dotnet/core/runtime-config/threading#autoreleasepool-for-managed-threads is a good example of prior art.

Looks like all the tests passed after the callback change. Thanks.

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.

Some remaining nits

@@ -4181,6 +4181,9 @@
<data name="InvalidOperation_ComInteropRequireComWrapperInstance" xml:space="preserve">
<value>COM Interop requires ComWrapper instance registered for marshalling.</value>
</data>
<data name="InvalidOperation_ComInteropRequireComWrapperTrackerInstance" xml:space="preserve">
<value>COM Interop requires ComWrapper instance registered for reference tracker support.</value>
Copy link
Member

Choose a reason for hiding this comment

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

I do not see this message in CoreCLR anywhere. Is the CoreCLR error handling different? Do we want to make it the same?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

CoreCLR doesn't have a message, but following the code path, it does throw an ArgumentException in one case and in the other it seems it would hit a NullPointerException from a null access. Given in CoreCLR they are mixing between C# and the C++ layer for where this logic is and the error happens in a more generic function like CallReleaseObjects, I guess they didn't have a specific error message there. But here we are able to.

Copy link
Member

Choose a reason for hiding this comment

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

@AaronRobinsonMSFT Should we have a test for these paths?

Copy link
Member

Choose a reason for hiding this comment

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

Sure. This code path in CoreCLR is a bit more contrived given the set up, but we can construct a test. Due to how the system is built up it is going to be some effort though.

manodasanW and others added 2 commits August 11, 2023 23:50
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
@AaronRobinsonMSFT AaronRobinsonMSFT merged commit 9a9d110 into dotnet:main Aug 13, 2023
171 checks passed
@manodasanW manodasanW deleted the manodasanw/aotcomwrappers branch August 13, 2023 20:24
@dotnet dotnet locked as resolved and limited conversation to collaborators Sep 13, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
6 participants