Skip to content

Conversation

VSadov
Copy link
Member

@VSadov VSadov commented Aug 2, 2025

Re: #117266

Adding support for async target methods in unboxing and instantiating stubs.

As far as stubs are concerned, async is a passive participant. The main reason for this change is to make sure that whenever arguments are propagated/shuffled by a stub and the target is using async calling convention, the implicit continuation arguments are not lost or corrupted.
Also need to ensure that returned continuation is handled correctly. Since it is a managed object, if stub is managed code, then it needs to be aware of continuation return, at very least for GC purposes.

  • ASM stubs only need to be sure that continuation argument is not lost in the shuffle. Since all ASM stubs tailcall the target, they do not need to worry about continuation on the return side.
  • on x86 the generic context is the last one, so it can be set/pushed without disturbing or even knowing about other args.
    That seems sufficient for the continuation to be handled correctly.
  • Portable shuffler maps each arg move thus needs to know about continuation arg offset, so that continuation can be moved, if needed. This change adds such knowledge.
  • IL stubs:
    This is a bit more complicated. The IL stubs typically come into play when we cannot tailcall. Even if we immediately return from the stub, a non-async stub method would have two problems: a) ensure that implicit continuation return is not trashed in the epilog, b) ensure that continuation return is GC protected.
    Thus we go with a different solution - we introduce async IL stubs. Since IL stubs are fully normal methods sent through the JIT, we can ask the JIT to treat them as AsyncMethodKind::AsyncExplicitImpl.

One subtle part is that in the async stubs' CALLI we pass the continuation argument explicitly, similar to what we do with generic contexts. The JIT expects this pattern when seeing async CALLI. Since only stubs use async CALLI, this convention is sufficient.

The reason we cannot rely on normal inserting of continuation arg by the JIT is that in stub calls the generic context is passed as an ordinary parameter and JIT would not know how to order continuation argument with respect to that.
(the knowledge that one of the parameter is a generic context stays on stub's side, means the continuation needs to be inserted on the stub's side as well).

Copy link
Contributor

Tagging subscribers to this area: @mangod9
See info in area-owners.md if you want to be subscribed.

@VSadov
Copy link
Member Author

VSadov commented Aug 11, 2025

@jakobbotsch Thanks!!

@VSadov
Copy link
Member Author

VSadov commented Aug 12, 2025

I think this is ready for review.

Copy link
Contributor

@Copilot Copilot AI left a 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 target methods in unboxing and instantiating stubs, ensuring that implicit continuation arguments are properly handled during argument propagation and that returned continuations are managed correctly for GC purposes.

Key changes include:

  • Introduction of async IL stubs that handle continuation arguments explicitly
  • Updates to portable shuffler to handle async continuation argument mapping
  • Configuration changes to enable runtime async support by default

Reviewed Changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/tests/async/inst-unbox-thunks/inst-unbox-thunks.csproj Test project configuration for async unboxing/instantiating stub tests
src/tests/async/inst-unbox-thunks/inst-unbox-thunks.cs Comprehensive test cases covering async unboxing and instantiating stubs
src/tests/async/Directory.Build.targets Enables async testing by uncommenting DisableProjectBuild
src/coreclr/vm/siginfo.cpp Adds PermitUninstDefOrRef flag to type loading
src/coreclr/vm/prestub.cpp Major updates to support async in unboxing and instantiating stubs
src/coreclr/vm/jitinterface.cpp Adds async calling convention translation and removes unnecessary token reset
src/coreclr/vm/ilstubcache.h Extends IL stub cache to support async stubs
src/coreclr/vm/ilstubcache.cpp Implements async stub creation with proper async method data
src/coreclr/vm/comdelegate.cpp Adds async continuation argument handling to portable shuffle array
src/coreclr/vm/callingconvention.h Adds GetAsyncContinuatioLoc method for argument location
src/coreclr/jit/importercalls.cpp Updates async call handling for CALLI instructions
src/coreclr/inc/corhdr.h Defines new IMAGE_CEE_CS_CALLCONV_ASYNC calling convention
src/coreclr/inc/clrconfigvalues.h Enables RuntimeAsync support by default

@VSadov
Copy link
Member Author

VSadov commented Aug 12, 2025

The network timeouts on Android are unlikely related to the changes

@VSadov
Copy link
Member Author

VSadov commented Aug 13, 2025

/ba-g the failures are known - #87783 and #118350

@VSadov VSadov disabled auto-merge August 13, 2025 01:49
@VSadov VSadov merged commit 2fa82a2 into dotnet:main Aug 13, 2025
110 of 113 checks passed
@VSadov VSadov deleted the asyncStubs branch August 13, 2025 01:50
@github-actions github-actions bot locked and limited conversation to collaborators Sep 12, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants