Remove BypassReadyToRun attributes from AsyncHelpers#128626
Conversation
Co-authored-by: jakobbotsch <7887810+jakobbotsch@users.noreply.github.com>
|
Tagging subscribers to this area: @dotnet/area-system-runtime-compilerservices |
|
@jtschuster It seems crossgen2 cannot handle these kind of infrastructure async methods: Is it expected? |
|
This isn't expected, I'll investigate. |
|
Looks like we the non-task-returning async methods are seen as CompilerGeneratedIL and that's causing issues. @copilot apply the following patch: diff --git a/src/coreclr/tools/Common/Compiler/AsyncMethodVariant.cs b/src/coreclr/tools/Common/Compiler/AsyncMethodVariant.cs
index 78b0c9c76b1..ad0c94de662 100644
--- a/src/coreclr/tools/Common/Compiler/AsyncMethodVariant.cs
+++ b/src/coreclr/tools/Common/Compiler/AsyncMethodVariant.cs
@@ -152,9 +152,20 @@ public static bool IsReturnDroppingAsyncThunk(this MethodDesc method)
public static bool IsAsyncThunk(this MethodDesc method)
{
+ if (method.IsNonTaskReturningAsyncMethod())
+ return false;
+
return (method.IsAsyncVariant() ^ method.IsAsync) || method.IsReturnDroppingAsyncThunk();
}
+ public static bool IsNonTaskReturningAsyncMethod(this MethodDesc method)
+ {
+ bool isNonTaskReturningAsyncMethod = method.GetTypicalMethodDefinition() is EcmaMethod && method.IsAsync && !method.Signature.ReturnsTaskOrValueTask();
+ // non-task-returning async methods should only be in corelib
+ Debug.Assert(!isNonTaskReturningAsyncMethod || (method.GetTypicalMethodDefinition() is EcmaMethod methodDef && methodDef.Context.SystemModule == methodDef.Module));
+ return isNonTaskReturningAsyncMethod;
+ }
+
public static bool IsCompilerGeneratedILBodyForAsync(this MethodDesc method)
{
return method.IsAsyncThunk() || method is AsyncResumptionStub;
@@ -163,6 +174,7 @@ public static bool IsCompilerGeneratedILBodyForAsync(this MethodDesc method)
public static MethodDesc GetAsyncVariant(this MethodDesc method)
{
Debug.Assert(!method.IsAsyncVariant());
+ Debug.Assert(!method.IsNonTaskReturningAsyncMethod());
return ((CompilerTypeSystemContext)method.Context).GetAsyncVariantMethod(method);
}
diff --git a/src/tests/Interop/UnmanagedCallersOnly/InvalidCSharp.ilproj b/src/tests/Interop/UnmanagedCallersOnly/InvalidCSharp.ilproj
index b7b8b4d7665..8b9ce4121b1 100644
--- a/src/tests/Interop/UnmanagedCallersOnly/InvalidCSharp.ilproj
+++ b/src/tests/Interop/UnmanagedCallersOnly/InvalidCSharp.ilproj
@@ -1,8 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk.IL">
<PropertyGroup>
<OutputType>library</OutputType>
+ <!-- crossgen2 cannot handle non-task-returning runtime-async methods that are not in CoreLib -->
+ <CrossGenTest>false</CrossGenTest>
</PropertyGroup>
<ItemGroup>
<Compile Include="InvalidCallbacks.il" />
</ItemGroup> |
Co-authored-by: jtschuster <36744439+jtschuster@users.noreply.github.com>
Applied the
Applied the |
Removing [BypassReadyToRun] crashed crossgen2 on browser-wasm: REG_ASYNC_CONTINUATION_RET == REG_NA there, so zeroing the continuation register on a synchronous return tripped genIsValidIntOrFakeReg (instr.cpp). Keep the attributes on platforms that don't support runtime-async, and remove them where it is supported. Mirror the RuntimeAsyncSupported predicate (from src/libraries/Directory.Build.targets, which the corelib build does not import) into both corelib csprojs and define RUNTIME_ASYNC_SUPPORTED when it is true. Wrap each [BypassReadyToRun] in #if !RUNTIME_ASYNC_SUPPORTED. Verified by building clr.corelib for browser/wasm (attributes retained) and linux/x64 (attributes removed) and inspecting the emitted metadata. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR updates runtime-async helper handling so supported R2R/AOT targets can compile the MethodImpl.Async helpers while unsupported targets keep [BypassReadyToRun]. It also adjusts crossgen2 async-method classification to avoid treating non-Task-returning runtime-async helpers as compiler-generated async thunks.
Changes:
- Conditionally applies
[BypassReadyToRun]based onRUNTIME_ASYNC_SUPPORTED. - Adds the
RUNTIME_ASYNC_SUPPORTEDdefine to CoreCLR and NativeAOT CoreLib projects. - Excludes non-Task/ValueTask-returning async methods from async-thunk classification.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.cs |
Conditions shared async helper [BypassReadyToRun] attributes on runtime-async support. |
src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs |
Applies the same conditional attribute behavior to CoreCLR-specific helpers. |
src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj |
Defines RUNTIME_ASYNC_SUPPORTED for supported CoreCLR CoreLib builds. |
src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj |
Defines RUNTIME_ASYNC_SUPPORTED for supported NativeAOT CoreLib builds. |
src/coreclr/tools/Common/Compiler/AsyncMethodVariant.cs |
Prevents non-Task-returning runtime-async methods from being treated as async thunks. |
| // "BypassReadyToRun" keeps these MethodImpl.Async helpers out of AOT/R2R images on platforms | ||
| // that don't support runtime-async (RUNTIME_ASYNC_SUPPORTED is not defined there). On those | ||
| // platforms the JIT cannot emit code for runtime-async returns, so the helpers must be JITted. |
| if (method.IsNonTaskReturningAsyncMethod()) | ||
| return false; |
| #if !RUNTIME_ASYNC_SUPPORTED | ||
| [BypassReadyToRun] | ||
| #endif |
| </PropertyGroup> | ||
|
|
||
| <PropertyGroup> | ||
| <DefineConstants Condition="'$(RuntimeAsyncSupported)' == 'true'">$(DefineConstants);RUNTIME_ASYNC_SUPPORTED</DefineConstants> |
There was a problem hiding this comment.
This is misleading. Runtime async should be unconditionally enabled for CoreCLR and NAOT Corelib, including wasm.
If crossgen is crashing on runtime async under wasm, I think it is best to add wasm specific temporary workaround in crossgen or JIT so that it just skips the method without crashing.
There was a problem hiding this comment.
We can probably wait for WASM runtime async support since it is close to be able to crossgen SPC I believe. Is that right @AndyAyersMS?
There was a problem hiding this comment.
Runtime async support in wasm is underway; maybe 1 week away.
Nothing yet depends on codegen handling all of SPC and we have an interim R2R failover for things codegen can't handle, so no reason to wait on Wasm.
There was a problem hiding this comment.
@copilot Remove the RUNTIME_ASYNC_SUPPORTED checks and the msbuild changes that were added
There was a problem hiding this comment.
Addressed in 0d320a2: removed the RUNTIME_ASYNC_SUPPORTED checks and the added CoreLib/NativeAOT CoreLib msbuild property changes, while keeping the crossgen2 fix and disabling CrossGen for InvalidCSharp.ilproj.
Co-authored-by: jakobbotsch <7887810+jakobbotsch@users.noreply.github.com>
Removes
[BypassReadyToRun]from all runtime async helper methods inAsyncHelpers.csandAsyncHelpers.CoreCLR.cs, now that the AOT/R2R typesystem supportsMethodImpl.Async.src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.cs: dropped the attribute from allAwaitAwaiter/UnsafeAwaitAwaiter/Await(Task[/<T>])/Await(ValueTask[/<T>])/Await(ConfiguredTaskAwaitable...)overloads.src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs: dropped the attribute from the CoreCLR-specific awaiter helpers.// "BypassReadyToRun" is until AOT/R2R typesystem has support for MethodImpl.Asynccomment.src/coreclr/tools/Common/Compiler/AsyncMethodVariant.cs: fixed a crossgen2 crash where non-task-returning async methods (e.g. theAsyncHelpersinfrastructure methods) were incorrectly classified as compiler-generated IL bodies. AddedIsNonTaskReturningAsyncMethod()helper and updatedIsAsyncThunk/GetAsyncVariantaccordingly.