-
Notifications
You must be signed in to change notification settings - Fork 5.2k
First part of async support in native AOT #121295
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
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR implements support for NativeAOT async method compilation by introducing an async calling convention and variant method infrastructure. The key changes enable async methods to be compiled with special handling in NativeAOT, mirroring the CoreCLR VM's AsyncVariantImpl concept.
Key Changes:
- Added NativeAOT-specific implementations for
TaskandTask<T>await methods in AsyncHelpers - Introduced
AsyncVariantImplMethodinfrastructure to represent async methods callable with async calling convention - Added support for unwrapping Task return types and marking methods with
AsyncCallConvflag - Extended JIT interface to handle async token resolution and calling convention flags
Reviewed Changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| AsyncHelpers.cs | Added NativeAOT-specific await implementations for Task/Task that handle completed tasks synchronously |
| ILCompiler.Compiler.csproj | Registered new async variant method source files in the compiler project |
| AsyncThunks.cs | Added IL emitter for generating Task-returning thunks that wrap async methods |
| NativeAotILProvider.cs | Integrated async method detection and thunk generation into IL provider |
| CorInfoTypes.cs | Added CORINFO_CALLCONV_ASYNCCALL and CORINFO_TOKENKIND_Await enum values |
| CorInfoImpl.cs | Implemented async token resolution and propagated AsyncCallConv flag to JIT |
| AsyncMethodDesc.cs | Removed IsTaskReturning extension method (moved to MethodExtensions) |
| MethodExtensions.cs | Added IsTaskReturning helper method for identifying Task-returning methods |
| CompilerTypeSystemContext.Async.cs | Added async variant method hashtable and instantiation support |
| AsyncVariantImplMethod.cs | Core implementation of async variant method with unwrapped signature |
| AsyncVariantImplMethod.Sorting.cs | Added sorting/comparison support for async variant methods |
| AsyncVariantImplMethod.Mangling.cs | Added name mangling with "AsyncCallable" prefix |
src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.cs
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.cs
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.cs
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.cs
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.cs
Show resolved
Hide resolved
|
There are several shovel-ready workitems that can be started in parallel on the native AOT side after this merges (we can discuss on Teams). I did a couple hacks on the crossgen side that makes things mostly compile in MichalStrehovsky@d395c1a (not part of this PR; was just looking around). I think the crossgen side will depend on what we want to compile. If we're fine with only precompiling the Cc @dotnet/ilc-contrib |
src/coreclr/tools/Common/Compiler/CompilerTypeSystemContext.Async.cs
Outdated
Show resolved
Hide resolved
If you got a Teams channel going for this, would you mind adding me to it? I suspect that the questions that I have just asked might have been discussed there. |
It was just an ad hoc video meeting between Jackson, Eduardo, David and me. I'll add you if we have something written. |
b811d06 to
79e8a8d
Compare
|
Rebased this on top of Jackson's PR that added the MethodDesc, so this is now only 130 lines. I validated the repro in top-post still works. This is ready for review now. |
|
/ba-g widespread Apple and Android infra issues |
The same program as in dotnet#121295 still works, but we can newly report async helpers as Intrinsic/Async. This implements things around suspension/resumption. Most of this change is around handling continuation types. Continuation types are synthetic types (created in the compiler) that derive from `Continuation` in the CoreLib. The JIT requests these based on the shape of locals it needs to preserve. What we get from the JIT in CorInfoImpl is size of the type and a pointer map (1011001 - non-zero means "GC pointer is here"). What we need to generate is a `MethodTable` for a type that derives from `Continuation` and has the specified GC layout after fields inherited from `Continuation`. We already have a similar thing in the compiler ("`MethodTable`" we use for GC statics), however because we need to derive from `Continuation` and presumably need to have a working vtable (with Equals/GetHashCode/ToString), we can't use this. So we emit a normal `MethodTable` for a synthetic type. Maybe we could optimize this to the one without vtable in the future. The synthetic type is a `MetadataType` that reports `Continuation` as the base type. It has instance fields of type `object` or `nint`, based on what we need. Because the standard type layout algorithm (the thing that assigns offsets to fields) would attempt to group GC fields together (it's a layout that works better for the GC), we also have a custom layouting algorithm that lays out these fields sequentially. The resumption stub is just a stubbed out TODO for someone else to look into for now.
Following works with runtime async enabled in Roslyn on native AOT:
The implementation strategy is as follows:
EcmaMethodof an asyncv2 method, it means they're holding theRuntimeAsyncflavor of the method in CoreCLR VM parlance. The return value is aTask,MethodDesc.IsAsyncis true,MethodSignature.IsAsyncCallConvis false. The IL is a thunk to theAsyncVariantImplMethodflavor.MethodDescdescendant:AsyncVariantImplMethod. This is the actual method with async calling convention that corresponds to someEcmaMethodwithIsAsync==true. For this one: the return value is unwrapped fromTask,MethodDesc.IsAsyncis true,MethodSignature.IsAsyncCallConvis true. The IL is the actual IL that corresponds to the wrappedEcmaMethodon disk.Cc @dotnet/ilc-contrib