-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Async continuations for native AOT #121398
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
base: main
Are you sure you want to change the base?
Conversation
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.
|
Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas |
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 adds support for async/await functionality in NativeAOT by implementing continuation type handling and async resumption stubs. The changes enable the JIT compiler to properly handle async methods in ahead-of-time compilation scenarios.
- Extends async support from CoreCLR to NativeAOT by unifying the preprocessor directives
- Implements continuation type generation with GC pointer mapping for async state storage
- Adds async resumption stub infrastructure for handling async method suspension/resumption
Reviewed Changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| AsyncHelpers.cs | Extends conditional compilation to include NativeAOT alongside CoreCLR and removes duplicate NATIVEAOT-specific implementations |
| AsyncHelpers.CoreCLR.cs | Adds NativeAOT support for continuation allocation using RuntimeImports.RhNewObject |
| CorInfoImpl.RyuJit.cs | Implements continuation allocation helper and fixed entry point retrieval for async methods |
| CorInfoImpl.ReadyToRun.cs | Adds placeholder for getFunctionFixedEntryPoint in ReadyToRun compilation |
| ILCompiler.Compiler.csproj | Adds new AsyncResumptionStub source files to the build |
| CompilerTypeSystemContext.Aot.cs | Registers continuation type field layout algorithm and hashtable |
| AsyncResumptionStub.cs | Defines async resumption stub method that throws NotSupportedException as placeholder |
| AsyncResumptionStub.Sorting.cs | Implements sorting and comparison for AsyncResumptionStub |
| AsyncResumptionStub.Mangling.cs | Defines name mangling for async resumption stubs |
| CorInfoImpl.cs | Implements getContinuationType and getAsyncResumptionStub for NativeAOT |
| CompilerTypeSystemContext.Async.cs | Implements ContinuationType and ContinuationTypeFieldLayoutAlgorithm for async state storage |
| System.Private.CoreLib.csproj | Includes AsyncHelpers.CoreCLR.cs in NativeAOT build |
src/coreclr/tools/Common/Compiler/CompilerTypeSystemContext.Async.cs
Outdated
Show resolved
Hide resolved
|
Can we add a design doc for this to BotR? (Or, better yet, can copilot add it 😄) |
Nothing in the runtime should depend a working vtable for these. I think it would be fine to start without a working vtable for these in NAOT and see whether we run into problems. For CoreCLR, a working vtable should be only a problem for managed debuggers. cc @rcj1 |
Right. One thing I noticed that before the switch to "flat" continuations the infrastructure code was mostly debuggable in VS. Now VS just crashes. I do not know for sure, but strongly suspect it happens once it sees a continuation instance and digs into its type. I kind of think, perhaps it is good if these are closer to real types where possible, unless it makes good savings. |
|
I wonder if the APIs that debuggers* use could just report that it has the base -- |
src/coreclr/tools/Common/Compiler/CompilerTypeSystemContext.Async.cs
Outdated
Show resolved
Hide resolved
Real types have metadata tokens and metadata. I do not see a reasonable way to create metadata tokens for these. If these types do not have metadata tokens, they are not real types and they will need to be special-cased in the diagnostic tooling.
It may be a good strategy for special-casing in some places, but it will be still problematic for code that expects 1:1 mapping between types and metadata tokens (for non-generic types). |
We should have a general runtime implementation design doc for runtime async (not specific to NAOT). @VSadov Do we have one? |
We have specs for the public surface: BOTR has the ABI spec:
But no general implementation design document. Mostly because the design was changing. We had a document that touches on design highlights in the runtimelab although that could be a bit obsolete vs. the current state. It makes sense to bring that part over as a starting point. (after adjusting for the current state). I will look into that. |
src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj
Outdated
Show resolved
Hide resolved
…e.CoreLib.csproj Co-authored-by: Adeel Mujahid <[email protected]>
src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
Outdated
Show resolved
Hide resolved
|
I've switched this over to use the barebone |
src/coreclr/tools/Common/Compiler/CompilerTypeSystemContext.Async.cs
Outdated
Show resolved
Hide resolved
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.
Thanks
The same program as in #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
Continuationin 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 aMethodTablefor a type that derives fromContinuationand has the specified GC layout after fields inherited fromContinuation.We already have a similar thing in the compiler ("
MethodTable" we use for GC statics), so we're reusing the same approach. TheMethodTableis pretty restricted and not the wholeMethodTableAPI surface on it is available at runtime. However, it implements enough that the GC can operate on it.The two new types are
AsyncContinuationType. This is a type systemMetadataTypethat represents the continuation pointer map. Then we haveAsyncContinuationEETypeNodewhich is the thing that gets emitted into the output file - theMethodTableitself.The resumption stub is just a stubbed out TODO for someone else to look into for now.
Cc @dotnet/ilc-contrib