Skip to content

Support inlining runtime async callable thunks#127642

Draft
jakobbotsch wants to merge 2 commits intodotnet:mainfrom
jakobbotsch:async-helper-inlining
Draft

Support inlining runtime async callable thunks#127642
jakobbotsch wants to merge 2 commits intodotnet:mainfrom
jakobbotsch:async-helper-inlining

Conversation

@jakobbotsch
Copy link
Copy Markdown
Member

@jakobbotsch jakobbotsch commented May 1, 2026

This adds supports to the JIT for inlining runtime async callable thunks. We typically see these after GDV kicks in for a virtual async call, and the implementer is not runtime async.
Example:

using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;

namespace AsyncMicro;

public class Program
{
    static async Task Main()
    {
        int sum = 0;
        for (int i = 0; i < 10000; i++)
        {
            sum += await Foo(new Derived());
            Thread.Sleep(1);
        }
        Console.WriteLine(sum);
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    private static async ValueTask<int> Foo(Base b)
    {
        return await b.Foo();
    }

    private abstract class Base
    {
        public abstract ValueTask<int> Foo();
    }

    private class Derived : Base
    {
        public override ValueTask<int> Foo()
        {
            return new ValueTask<int>(42);
        }
    }
}

Before:

G_M32752_IG02:  ;; offset=0x000B
       test     rbx, rbx
       jne      G_M32752_IG11
       mov      rcx, 0x7FFCA6AE49D8      ; AsyncMicro.Program+Derived
       cmp      qword ptr [rax], rcx
       jne      SHORT G_M32752_IG06
                                                ;; size=24 bbWeight=1 PerfScore 4.50
G_M32752_IG03:  ;; offset=0x0023
       mov      rcx, rax
       xor      rdx, rdx
       call     [AsyncMicro.Program+Derived:Foo():int:this]      ; (call to runtime async callable thunk)
       test     rcx, rcx
       jne      SHORT G_M32752_IG07

After:

G_M32752_IG02:  ;; offset=0x000B
       test     rbx, rbx
       jne      G_M32752_IG07
       mov      rdx, 0x7FFCA8633BE8      ; AsyncMicro.Program+Derived
       cmp      qword ptr [rcx], rdx
       jne      SHORT G_M32752_IG05
       mov      eax, 42

Not totally sure this is how I wanna do this, this might look different once we get full general async inlining...

Copilot AI review requested due to automatic review settings May 1, 2026 10:45
@github-actions github-actions Bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label May 1, 2026
@dotnet-policy-service
Copy link
Copy Markdown
Contributor

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

Copy link
Copy Markdown
Contributor

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 updates CoreCLR async infrastructure and the JIT importer to enable inlining of runtime async callable thunks (commonly seen after guarded devirtualization of virtual async calls), including propagating/handling continuation-context behavior so the inlined code can still resume on the appropriate context.

Changes:

  • JIT: allow inlining inlinees that contain async calls in a constrained scenario, and propagate caller async context arguments into inlined async calls when needed.
  • CoreLib: centralize “continue” flag masking via AllContinueFlags and adjust continuation dispatch to handle head continuations that require follow-up scheduling.

Reviewed changes

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

File Description
src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs Adds AllContinueFlags and updates runtime-async continuation dispatch to detect/queue follow-up execution when continuation-context flags are present.
src/coreclr/jit/importercalls.cpp Enables inlining of certain async inlinees (runtime async callable thunks) and adds logic to flow async context args from the inlining call into async calls inside the inlinee.
src/coreclr/jit/compiler.h Declares new importer helpers/state used for async-in-inlinee handling.

Comment thread src/coreclr/jit/importercalls.cpp
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants