Skip to content

Remove async method inlining restrictions in crossgen2#125472

Merged
jtschuster merged 23 commits intodotnet:mainfrom
jtschuster:InlineAsync
Apr 6, 2026
Merged

Remove async method inlining restrictions in crossgen2#125472
jtschuster merged 23 commits intodotnet:mainfrom
jtschuster:InlineAsync

Conversation

@jtschuster
Copy link
Copy Markdown
Member

Remove restrictions that prevented async methods from being inlined during ReadyToRun compilation.

All 69 async tests pass with both crossgen2 and composite R2R.

Output of the src/tests/async/execution-context/execution-context.cs was validated manually to ensure inlining is happening for async calls to methods without awaits. In Test(), these two calls were inlined as expected.

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static async Task ChangeThenThrowInlined()
{
s_local.Value = 123;
throw new Exception();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static async Task ChangeThenReturnInlined()
{
s_local.Value = 123;
}

Fixes #124665

Remove four restrictions that prevented async methods from being inlined
during ReadyToRun compilation:

1. CanInline() rejected IsAsyncThunk()/IsAsyncCall() callees
2. CrossModuleInlineableUncached() rejected async variants/thunks
3. reportInlining() threw when async methods were cross-module inlined
4. InliningInfoNode skipped recording inlining info for async thunks

All 69 async tests pass with both crossgen2 and composite R2R modes.

Fixes dotnet#124665

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 12, 2026 01:43
@jtschuster
Copy link
Copy Markdown
Member Author

/azp run runtime-coreclr crossgen2

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

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

Removes restrictions that prevented async methods from being inlined during ReadyToRun (crossgen2) compilation, fixing #124665.

Changes:

  • Removed four separate guards that blocked inlining of async methods (thunks, variants, calls) in R2R compilation.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
CorInfoImpl.ReadyToRun.cs Removed exception throw for async method inlining
ReadyToRunCompilationModuleGroupBase.cs Removed cross-module inlining restriction for async methods
ReadyToRunCodegenCompilation.cs Removed CanInline restriction for async thunks/calls
InliningInfoNode.cs Removed skip of async thunks in inlining info emission

Copilot AI review requested due to automatic review settings March 16, 2026 20:06
@jtschuster
Copy link
Copy Markdown
Member Author

/azp run runtime-coreclr crossgen2

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

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

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.

@jtschuster
Copy link
Copy Markdown
Member Author

/azp run runtime-coreclr crossgen2

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

jtschuster and others added 7 commits March 26, 2026 17:21
When crossgen2 emits CHECK_IL_BODY fixups for cross-module inlined async
methods (miAsync), the runtime crashes with a MayHaveILHeader() precondition
failure. This happens because the runtime marks the original MethodDesc as an
async thunk, and MayHaveILHeader() returns false for thunks. However, the IL
bytes are still present at the method's RVA in the PE.

Runtime fix: Add GetILHeaderForStandaloneMetadata() helper that bypasses
MayHaveILHeader() for async thunk methods by accessing the IL directly via
Module::GetIL(GetRVA()).

Crossgen2 fix: Separate ILBodyFixupSignature into _ilMethod (EcmaMethod for
IL body hash computation) and _signatureMethod (MethodDesc for method
identity encoding), making the different roles explicit.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Split GetModuleToken into GetILModuleToken (for IL hash and fixup module
context) and GetSignatureModuleToken (for method identity encoding). Use
_signatureMethod.GetTypicalMethodDefinition() for EmitMethodSignature so
the correct method identity is encoded when IL source and signature method
differ (e.g. runtime-async inlinees).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The IL and signature methods always resolve to the same module token,
so a single GetModuleToken suffices. Add Debug.Assert that
signatureMethod.GetPrimaryMethodDesc() == ilMethod to enforce the
invariant that both refer to the same underlying EcmaMethod.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 27, 2026 21:28
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

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

In order to resolve the async method (which has a non-thunk
IL body) from the CheckILBody fixup, separate out the
signature MethodDesc from the IL providing MethodDesc
inf ILBodyFixupSignature. The IL is retrieved for the EcmaMethod
resolved from the _signatureMethod.GetPrimaryMethodDesc(),
which is always an EcmaMethod for the TypicalMethodDefinitions
allowed. At runtime, the correct method is resolved and the IL
body is properly validated.
Copilot AI review requested due to automatic review settings March 31, 2026 05:25
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

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

@jtschuster
Copy link
Copy Markdown
Member Author

/azp run runtime-coreclr crossgen2

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

@jtschuster jtschuster requested a review from davidwrighton April 2, 2026 18:03
@jtschuster jtschuster merged commit 10075f0 into dotnet:main Apr 6, 2026
127 of 146 checks passed
@github-project-automation github-project-automation bot moved this to Done in AppModel Apr 6, 2026
radekdoulik pushed a commit to radekdoulik/runtime that referenced this pull request Apr 9, 2026
Remove restrictions that prevented async methods from being inlined
during ReadyToRun compilation.

All 69 async tests pass with both crossgen2 and composite R2R.

Output of the src/tests/async/execution-context/execution-context.cs was
validated manually to ensure inlining is happening for async calls to
methods without awaits. In `Test()`, these two calls were inlined as
expected.

https://github.com/dotnet/runtime/blob/b7973489277b74bc5da9d36a0a2883eaa987328f/src/tests/async/execution-context/execution-context.cs#L110-L121

Fixes dotnet#124665

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Runtime-async methods are not inlined in crossgen2

3 participants