Skip to content

Enable runtime-async for shared framework source projects in net11.0+ and remove RuntimeAsync config knob#125406

Merged
agocke merged 12 commits intomainfrom
copilot/enable-runtime-async-netcoreapp
Mar 28, 2026
Merged

Enable runtime-async for shared framework source projects in net11.0+ and remove RuntimeAsync config knob#125406
agocke merged 12 commits intomainfrom
copilot/enable-runtime-async-netcoreapp

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 10, 2026

Description

Auto-enables runtime-async for shared framework (IsNETCoreAppSrc) source projects targeting net11.0+, with exclusions for platforms where it's not yet working and for assemblies that ship as OOB NuGet packages. Also fully removes the UNSUPPORTED_RuntimeAsync / DOTNET_RuntimeAsync config knob and the runtimeAsync field/accessor from the runtime, since runtime-async is now unconditionally enabled. Additionally fixes PEObjectWriter relocation handling for RISC-V and LoongArch to properly support non-zero addends.

Conditions for enablement:

  • IsNETCoreAppSrc — scoped to shared framework only
  • IsPackable != true — excludes OOB NuGet packages (e.g., System.Text.Json, System.Collections.Immutable) to avoid Mono compatibility issues when those packages are referenced in non-CoreCLR environments
  • IsTargetFrameworkCompatible(TFM, 'net11.0') — no pre-net11 TFMs
  • RuntimeAsyncSupported shared property — consolidates platform exclusions (browser, wasi, android, Apple mobile, Mono) into a single predicate used by both library source and test builds
  • Per-project opt-out via UseRuntimeAsync=false

Changes:

  • src/libraries/Directory.Build.targets — Defines RuntimeAsyncSupported shared property with platform exclusions. Auto-enables runtime-async for IsNETCoreAppSrc source projects on net11.0+ supported platforms, excluding OOB packages (IsPackable=true). Replaces the previous explicit UseRuntimeAsync=true opt-in gate.
  • eng/testing/tests.targets — Defines matching RuntimeAsyncSupported property (guarded against redefinition). Removes the TestReadyToRun special-case condition since libraries now ship with runtime-async. Simplifies test enablement to use the shared RuntimeAsyncSupported property.
  • src/coreclr/inc/clrconfigvalues.h — Removes the UNSUPPORTED_RuntimeAsync config definition (which mapped to DOTNET_RuntimeAsync env var).
  • src/coreclr/vm/eeconfig.h — Removes the runtimeAsync field and the RuntimeAsync() accessor method entirely, since the feature is now unconditionally enabled.
  • src/coreclr/vm/eeconfig.cpp — Removes config value read and the runtimeAsync field initialization.
  • src/coreclr/vm/method.cpp — Removes the dead g_pConfig->RuntimeAsync() early-return guard in ClassifyMethodReturnKind, since runtime-async is always on.
  • src/tests/Interop/COM/RuntimeAsync/RuntimeAsync.csproj — Removes DOTNET_RuntimeAsync env variable and the RequiresProcessIsolation property that was only needed for it.
  • EnablePreviewFeatures removed — Removed EnablePreviewFeatures=true from both eng/testing/tests.targets and src/libraries/Directory.Build.targets since runtime-async is no longer a preview feature.
  • src/coreclr/tools/Common/Compiler/ObjectWriter/PEObjectWriter.cs — Fixes RISC-V and LoongArch relocation handling in ResolveRelocations: removes the if (addend != 0) { throw new NotSupportedException(); } guards and replaces symbolImageOffset with long targetAddress = symbolImageOffset + addend to properly incorporate addends, consistent with all other relocation types in the method.

🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

Copilot AI and others added 2 commits March 10, 2026 20:18
…e-net11, browser/wasm, and mobile

Co-authored-by: agocke <515774+agocke@users.noreply.github.com>
@agocke agocke marked this pull request as ready for review March 10, 2026 21:38
Copilot AI review requested due to automatic review settings March 10, 2026 21:38
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 the libraries build infrastructure to automatically enable the runtime-async compiler feature for shared-framework source projects targeting net11.0+, while excluding platforms where the feature isn’t supported and allowing per-project opt-out via UseRuntimeAsync=false.

Changes:

  • Replace the explicit UseRuntimeAsync=true opt-in gate with an auto-enable condition scoped to IsNETCoreAppSrc and net11.0+.
  • Add platform/runtime exclusions (browser, wasi, android, Apple mobile, Mono) to match existing test gating logic.

@jtschuster
Copy link
Copy Markdown
Member

We should probably also remove the '$(TestReadyToRun)' != 'true' case here:

<PropertyGroup Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net11.0'))
and '$(TestNativeAot)' != 'true'
and ('$(TestReadyToRun)' != 'true' or '$(UseRuntimeAsync)' == 'true')
and '$(UseNativeAOTRuntime)' != 'true'
and '$(TargetOS)' != 'browser'
and '$(TargetOS)' != 'wasi'
and '$(TargetOS)' != 'android'
and '$(TargetsAppleMobile)' != 'true'
and '$(RuntimeFlavor)' != 'Mono'
and '$(UseRuntimeAsync)' != 'false'">
<EnablePreviewFeatures>true</EnablePreviewFeatures>
<Features>$(Features);runtime-async=on</Features>
</PropertyGroup>

Also, we should follow up to remove the RuntimeAsync jobs in the runtime-coreclr crossgen2 pipeline.

@jtschuster
Copy link
Copy Markdown
Member

/azp run runtime-coreclr crossgen2

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

@jkotas
Copy link
Copy Markdown
Member

jkotas commented Mar 11, 2026

You may want to submit a test-only job to dotnet/dotnet with this change and trigger full CI run /azp run dotnet-unified-build-full. This is the kind of change that is likely to fail in VMR.

@jkotas
Copy link
Copy Markdown
Member

jkotas commented Mar 11, 2026

@copilot Delete UNSUPPORTED_RuntimeAsync config and DOTNET_RuntimeAsync env variable as part of this change. Nothing is going to work when this config is to set false after this change, so it can only break folks that happen to have it set in the environment.

…PPORTED_RuntimeAsync config and DOTNET_RuntimeAsync env var

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 11, 2026

We should probably also remove the '$(TestReadyToRun)' != 'true' case here:

<PropertyGroup Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net11.0'))
and '$(TestNativeAot)' != 'true'
and ('$(TestReadyToRun)' != 'true' or '$(UseRuntimeAsync)' == 'true')
and '$(UseNativeAOTRuntime)' != 'true'
and '$(TargetOS)' != 'browser'
and '$(TargetOS)' != 'wasi'
and '$(TargetOS)' != 'android'
and '$(TargetsAppleMobile)' != 'true'
and '$(RuntimeFlavor)' != 'Mono'
and '$(UseRuntimeAsync)' != 'false'">
<EnablePreviewFeatures>true</EnablePreviewFeatures>
<Features>$(Features);runtime-async=on</Features>
</PropertyGroup>

...

Removed the TestReadyToRun condition in 6ffe3ab. Since libraries are now compiled with runtime-async, crossgen2/R2R tests should use it by default too. The UseRuntimeAsync=true override from the crossgen2 pipeline (crossgen2.yml line 119) is now a no-op but harmless — removing the crossgen2 RuntimeAsync pipeline jobs can be done as a follow-up.

@copilot Delete UNSUPPORTED_RuntimeAsync config and DOTNET_RuntimeAsync env variable as part of this change. Nothing is going to work when this config is to set false after this change, so it can ...

Done in 6ffe3ab — removed the UNSUPPORTED_RuntimeAsync config definition from clrconfigvalues.h, removed the config read from eeconfig.cpp (initialization now hardcodes true), and removed the DOTNET_RuntimeAsync env variable from the COM RuntimeAsync test csproj.

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
@agocke
Copy link
Copy Markdown
Member

agocke commented Mar 27, 2026

FYI @DrewScoggins

@agocke
Copy link
Copy Markdown
Member

agocke commented Mar 27, 2026

@copilot Can you please remove the if (addend !=0 0) { throw new NotSupportedException(); } from the riscv and loongarch cases in PEObjectWriter.ResolveRelocations method? Also change the code in those cases to replace the symbolImageOffset with a new long targetAddress = symbolImageOffset + addend; variable.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 27, 2026

@copilot Can you please remove the if (addend !=0 0) { throw new NotSupportedException(); } from the riscv and loongarch cases in PEObjectWriter.ResolveRelocations method? Also chang...

Done in 0ca2899 — removed the NotSupportedException throws for both the loongarch and riscv cases, and replaced symbolImageOffset with long targetAddress = symbolImageOffset + addend in both case blocks.

@jtschuster
Copy link
Copy Markdown
Member

jtschuster commented Mar 28, 2026

Created #126233 against this branch to disable runtime-async crossgen generation on untested architectures until we can fully sort out the issues. Filed #126234 to track as well.

The two Debug.Assert calls in PutRiscV64AuipcCombo fire during
crossgen2 R2R compilation for RISC-V because the target memory
already contains nonzero relocation bits.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

🤖 Copilot Code Review — PR #125406

Note

This review was generated by Copilot and should be treated as an automated analysis, not a definitive assessment.

Holistic Assessment

Motivation: Enabling runtime-async by default for shared framework source projects and removing the config knob is well-justified — the feature has matured beyond the preview stage and the prior opt-in UseRuntimeAsync=true gate is no longer necessary.

Approach: The RuntimeAsyncSupported shared property with platform exclusions and OOB filtering is well-structured. The config knob removal is thorough. The PEObjectWriter relocation changes are correct in pattern but unrelated to the PR's primary purpose.

Summary: ⚠️ Needs Human Review. The runtime-async enablement and config knob removal are correct. However, the commented-out Debug.Assert calls in PutRiscV64AuipcCombo (Relocation.cs) warrant verification by someone familiar with RISC-V relocations — the method uses |= to write offset bits, and the assert validates a zero-initial-state precondition that is essential for correctness. A human reviewer should confirm whether the assert failures represent a genuine data corruption risk or a benign condition specific to the crossgen2 PEObjectWriter context.


Detailed Findings

✅ Runtime-Async MSBuild Enablement — Correct and well-structured

The changes to eng/testing/tests.targets and src/libraries/Directory.Build.targets are well-designed:

  • RuntimeAsyncSupported shared property consolidates platform exclusions (browser, wasi, android, Apple mobile, Mono) with a Condition="'$(RuntimeAsyncSupported)' == ''" guard that correctly prevents redefinition and allows per-project overrides.
  • IsPackable != 'true' excludes OOB packages (e.g., System.Text.Json) from runtime-async, addressing the Mono compatibility concern raised by jkotas.
  • net11.0+ TFM check and UseRuntimeAsync=false opt-out are proper safeguards.
  • EnablePreviewFeatures=true removal aligns with runtime-async graduating from preview.
  • Removal of TestNativeAot/UseNativeAOTRuntime exclusions in the test targets is consistent with crossgen2/ILC now supporting runtime-async methods (via PR Emit Async Methods in crossgen2 #124203's infrastructure).

✅ Config Knob Removal — Clean and complete

The removal spans all relevant files and is thorough:

File Change
clrconfigvalues.h UNSUPPORTED_RuntimeAsync config definition removed
eeconfig.h runtimeAsync field and RuntimeAsync() accessor removed
eeconfig.cpp Field initialization and config value read removed
method.cpp Dead g_pConfig->RuntimeAsync() early-return guard in ClassifyMethodReturnKind removed
RuntimeAsync.csproj DOTNET_RuntimeAsync env var and RequiresProcessIsolation removed

Verified: no remaining references to the removed config in the codebase via the commit chain.

✅ PEObjectWriter Relocation Fixes — Correct pattern

The RISC-V and LoongArch64 relocation changes in PEObjectWriter.cs correctly incorporate addends via long targetAddress = symbolImageOffset + addend, replacing the overly restrictive if (addend != 0) throw new NotSupportedException() guards. The pattern matches how other relocation types (e.g., IMAGE_REL_BASED_REL32) in the same method handle addends. For LoongArch64, the page-offset calculation correctly uses targetAddress instead of symbolImageOffset for the & 0x800 sign-extension adjustment.

⚠️ Commented-out RISC-V Debug.Assert — Needs verification

src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs:572,577

Two Debug.Assert calls in PutRiscV64AuipcCombo are commented out rather than properly fixed:

// Debug.Assert(GetRiscV64AuipcCombo(pCode, isStype) == 0);   // precondition
pCode[0] |= (uint)hi20;
// ...
// Debug.Assert(GetRiscV64AuipcCombo(pCode, isStype) == offset); // postcondition

PutRiscV64AuipcCombo writes offset bits using |= (bitwise OR into existing instruction encoding). The first assert validates that the offset slots are zero before writing — a necessary precondition for |= to produce correct results. If the precondition fails, |= produces a corrupted offset (OR of old and new bits).

The C++ equivalents in util.cpp and spmiutil.cpp retain their full _ASSERTE assertions. Recommended actions:

  1. Investigate why the crossgen2 codepath has non-zero initial offset bits — this could indicate double relocation resolution or pre-populated instruction data.
  2. If the precondition cannot hold in the PEObjectWriter context, change the write logic to clear the offset bits before OR-ing (using a mask), rather than suppressing the assert.
  3. At minimum, add a // TODO: comment with a tracking issue link explaining the known failure and planned fix.

This is flagged as advisory rather than blocking, since the assert only fires in debug builds and CI is presumably passing. However, the underlying concern affects correctness in all build configurations.

💡 PR Scope — Consider separating unrelated changes

The PEObjectWriter relocation fixes and RISC-V assert changes are unrelated to runtime-async enablement. Per dotnet/runtime conventions, keeping PRs focused on a single concern helps review and git history. These could be split into a separate PR. (The PR description does document these changes, so this is not a blocking concern.)

Additionally, the branch has diverged from current main — several commits in the two-dot diff (WASM JIT, AsyncResumptionStub caching, COSE, ML-DSA, ETW listener changes) are actually main-side changes resolved cleanly by the three-way merge. A rebase before merge would produce a much cleaner diff for final review.

Generated by Code Review for issue #125406 ·

@agocke
Copy link
Copy Markdown
Member

agocke commented Mar 28, 2026

/ba-g browser failures are known and musl/x86 failures are numerics timeouts

@agocke agocke merged commit 874cab5 into main Mar 28, 2026
161 of 168 checks passed
@agocke agocke deleted the copilot/enable-runtime-async-netcoreapp branch March 28, 2026 17:46
@github-project-automation github-project-automation bot moved this to Done in AppModel Mar 28, 2026
@agocke
Copy link
Copy Markdown
Member

agocke commented Mar 28, 2026

/backport to release/11.0-preview3

@github-actions
Copy link
Copy Markdown
Contributor

Started backporting to release/11.0-preview3 (link to workflow run)

@github-actions
Copy link
Copy Markdown
Contributor

@agocke an error occurred while backporting to release/11.0-preview3. See the workflow output for details.

<EnablePreviewFeatures>true</EnablePreviewFeatures>
<!-- Define a shared predicate for platforms that support runtime async. -->
<PropertyGroup Condition="'$(RuntimeAsyncSupported)' == ''">
<RuntimeAsyncSupported Condition="'$(TargetOS)' != 'browser'
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can enable asyncV2 for browser+coreCLR ?

cc @radekdoulik

@agocke
Copy link
Copy Markdown
Member

agocke commented Mar 30, 2026

/backport to release/11.0-preview3

@github-actions
Copy link
Copy Markdown
Contributor

Started backporting to release/11.0-preview3 (link to workflow run)

@github-actions
Copy link
Copy Markdown
Contributor

@agocke backporting to release/11.0-preview3 failed, the patch most likely resulted in conflicts. Please backport manually!

git am output
$ git am --3way --empty=keep --ignore-whitespace --keep-non-patch changes.patch

Creating an empty commit: Initial plan
Applying: Enable runtime-async for netcoreapp source projects excluding OOB, pre-net11, browser/wasm, and mobile
Applying: Factor RuntimeAsyncSupported, remove TestReadyToRun gate, delete UNSUPPORTED_RuntimeAsync config and DOTNET_RuntimeAsync env var
Using index info to reconstruct a base tree...
M	eng/testing/tests.targets
Falling back to patching base and 3-way merge...
Auto-merging eng/testing/tests.targets
CONFLICT (content): Merge conflict in eng/testing/tests.targets
error: Failed to merge in the changes.
hint: Use 'git am --show-current-patch=diff' to see the failed patch
hint: When you have resolved this problem, run "git am --continue".
hint: If you prefer to skip this patch, run "git am --skip" instead.
hint: To restore the original branch and stop patching, run "git am --abort".
hint: Disable this message with "git config set advice.mergeConflict false"
Patch failed at 0003 Factor RuntimeAsyncSupported, remove TestReadyToRun gate, delete UNSUPPORTED_RuntimeAsync config and DOTNET_RuntimeAsync env var
Error: The process '/usr/bin/git' failed with exit code 128

Link to workflow output

agocke added a commit to agocke/runtime that referenced this pull request Mar 31, 2026
… and remove RuntimeAsync config knob (dotnet#125406)

## Description

Auto-enables `runtime-async` for shared framework (`IsNETCoreAppSrc`)
source projects targeting net11.0+, with exclusions for platforms where
it's not yet working and for assemblies that ship as OOB NuGet packages.
Also fully removes the `UNSUPPORTED_RuntimeAsync` /
`DOTNET_RuntimeAsync` config knob and the `runtimeAsync` field/accessor
from the runtime, since runtime-async is now unconditionally enabled.
Additionally fixes PEObjectWriter relocation handling for RISC-V and
LoongArch to properly support non-zero addends.

**Conditions for enablement:**
- `IsNETCoreAppSrc` — scoped to shared framework only
- `IsPackable != true` — excludes OOB NuGet packages (e.g.,
System.Text.Json, System.Collections.Immutable) to avoid Mono
compatibility issues when those packages are referenced in non-CoreCLR
environments
- `IsTargetFrameworkCompatible(TFM, 'net11.0')` — no pre-net11 TFMs
- `RuntimeAsyncSupported` shared property — consolidates platform
exclusions (browser, wasi, android, Apple mobile, Mono) into a single
predicate used by both library source and test builds
- Per-project opt-out via `UseRuntimeAsync=false`

**Changes:**

- **`src/libraries/Directory.Build.targets`** — Defines
`RuntimeAsyncSupported` shared property with platform exclusions.
Auto-enables runtime-async for `IsNETCoreAppSrc` source projects on
net11.0+ supported platforms, excluding OOB packages
(`IsPackable=true`). Replaces the previous explicit
`UseRuntimeAsync=true` opt-in gate.
- **`eng/testing/tests.targets`** — Defines matching
`RuntimeAsyncSupported` property (guarded against redefinition). Removes
the `TestReadyToRun` special-case condition since libraries now ship
with runtime-async. Simplifies test enablement to use the shared
`RuntimeAsyncSupported` property.
- **`src/coreclr/inc/clrconfigvalues.h`** — Removes the
`UNSUPPORTED_RuntimeAsync` config definition (which mapped to
`DOTNET_RuntimeAsync` env var).
- **`src/coreclr/vm/eeconfig.h`** — Removes the `runtimeAsync` field and
the `RuntimeAsync()` accessor method entirely, since the feature is now
unconditionally enabled.
- **`src/coreclr/vm/eeconfig.cpp`** — Removes config value read and the
`runtimeAsync` field initialization.
- **`src/coreclr/vm/method.cpp`** — Removes the dead
`g_pConfig->RuntimeAsync()` early-return guard in
`ClassifyMethodReturnKind`, since runtime-async is always on.
- **`src/tests/Interop/COM/RuntimeAsync/RuntimeAsync.csproj`** — Removes
`DOTNET_RuntimeAsync` env variable and the `RequiresProcessIsolation`
property that was only needed for it.
- **`EnablePreviewFeatures` removed** — Removed
`EnablePreviewFeatures=true` from both `eng/testing/tests.targets` and
`src/libraries/Directory.Build.targets` since runtime-async is no longer
a preview feature.
- **`src/coreclr/tools/Common/Compiler/ObjectWriter/PEObjectWriter.cs`**
— Fixes RISC-V and LoongArch relocation handling in
`ResolveRelocations`: removes the `if (addend != 0) { throw new
NotSupportedException(); }` guards and replaces `symbolImageOffset` with
`long targetAddress = symbolImageOffset + addend` to properly
incorporate addends, consistent with all other relocation types in the
method.

<!-- START COPILOT CODING AGENT TIPS -->
---

🔒 GitHub Advanced Security automatically protects Copilot coding agent
pull requests. You can protect all pull requests by enabling Advanced
Security for your repositories. [Learn more about Advanced
Security.](https://gh.io/cca-advanced-security)

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: agocke <515774+agocke@users.noreply.github.com>
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
Co-authored-by: Andy Gocke <angocke@microsoft.com>
Co-authored-by: Andy Gocke <andy@commentout.net>
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

Labels

area-Infrastructure-libraries linkable-framework Issues associated with delivering a linker friendly framework

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

6 participants