From c4c8dba3a54e96dcbf14d855675b4cca093cc5a1 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Fri, 7 Nov 2025 13:33:36 -0800 Subject: [PATCH 1/6] Move StubHelpers.AsyncCallContinuation to AsyncHelpers. --- .../Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs | 4 ++++ .../System.Private.CoreLib/src/System/StubHelpers.cs | 3 --- src/coreclr/jit/gentree.cpp | 2 +- src/coreclr/jit/importercalls.cpp | 10 +++++----- src/coreclr/jit/namedintrinsiclist.h | 2 +- src/coreclr/vm/corelib.h | 6 +++--- 6 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs index 19ea178f6bf1f9..f8aaacc4a49740 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs @@ -150,6 +150,10 @@ public static partial class AsyncHelpers [Intrinsic] private static void AsyncSuspend(Continuation continuation) => throw new UnreachableException(); + [Intrinsic] + [BypassReadyToRun] + internal static Continuation? AsyncCallContinuation() => throw new UnreachableException(); // Unconditionally expanded intrinsic + // Used during suspensions to hold the continuation chain and on what we are waiting. // Methods like FinalizeTaskReturningThunk will unlink the state and wrap into a Task. private struct RuntimeAsyncAwaitState diff --git a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs index acb629e66e3662..6d61edd19ebc4a 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs @@ -1610,9 +1610,6 @@ internal static void MulticastDebuggerTraceHelper(object o, int count) [Intrinsic] internal static IntPtr NextCallReturnAddress() => throw new UnreachableException(); // Unconditionally expanded intrinsic - - [Intrinsic] - internal static Continuation? AsyncCallContinuation() => throw new UnreachableException(); // Unconditionally expanded intrinsic } // class StubHelpers #if FEATURE_COMINTEROP diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index fe620f6f332b87..b9d49d5655f500 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -2265,7 +2265,7 @@ bool GenTreeCall::HasSideEffects(Compiler* compiler, bool ignoreExceptions, bool // those cases the JIT does not know (and does not need to know) which arg is // the async continuation. // -// The VM also uses the StubHelpers.AsyncCallContinuation() intrinsic in the +// The VM also uses the AsyncHelpers.AsyncCallContinuation() intrinsic in the // stubs discussed above. The JIT must take care in those cases to still mark // the preceding call as an async call; this is required for correct LSRA // behavior and GC reporting around the returned async continuation. This is diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 42dbb08ee7043f..f7915a7b98ef61 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -3323,7 +3323,7 @@ GenTree* Compiler::impIntrinsic(CORINFO_CLASS_HANDLE clsHnd, return new (this, GT_LABEL) GenTree(GT_LABEL, TYP_I_IMPL); } - if (ni == NI_System_StubHelpers_AsyncCallContinuation) + if (ni == NI_System_Runtime_CompilerServices_AsyncHelpers_AsyncCallContinuation) { GenTree* node = new (this, GT_ASYNC_CONTINUATION) GenTree(GT_ASYNC_CONTINUATION, TYP_REF); node->SetHasOrderingSideEffect(); @@ -10872,6 +10872,10 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method) { result = NI_System_Runtime_CompilerServices_AsyncHelpers_Await; } + else if (strcmp(methodName, "AsyncCallContinuation") == 0) + { + result = NI_System_Runtime_CompilerServices_AsyncHelpers_AsyncCallContinuation; + } } else if (strcmp(className, "StaticsHelpers") == 0) { @@ -11129,10 +11133,6 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method) { result = NI_System_StubHelpers_NextCallReturnAddress; } - else if (strcmp(methodName, "AsyncCallContinuation") == 0) - { - result = NI_System_StubHelpers_AsyncCallContinuation; - } } } else if (strcmp(namespaceName, "Text") == 0) diff --git a/src/coreclr/jit/namedintrinsiclist.h b/src/coreclr/jit/namedintrinsiclist.h index aa56003f25acc1..e0c346870de084 100644 --- a/src/coreclr/jit/namedintrinsiclist.h +++ b/src/coreclr/jit/namedintrinsiclist.h @@ -107,7 +107,6 @@ enum NamedIntrinsic : unsigned short NI_System_RuntimeType_get_TypeHandle, NI_System_StubHelpers_GetStubContext, NI_System_StubHelpers_NextCallReturnAddress, - NI_System_StubHelpers_AsyncCallContinuation, NI_Array_Address, NI_Array_Get, @@ -126,6 +125,7 @@ enum NamedIntrinsic : unsigned short NI_System_Runtime_CompilerServices_AsyncHelpers_AsyncSuspend, NI_System_Runtime_CompilerServices_AsyncHelpers_Await, + NI_System_Runtime_CompilerServices_AsyncHelpers_AsyncCallContinuation, NI_System_Runtime_CompilerServices_StaticsHelpers_VolatileReadAsByref, diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index e0cde61d373d8e..b2dae8c9ed9e6b 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -747,8 +747,9 @@ DEFINE_METHOD(ASYNC_HELPERS, COMPLETED_TASK, CompletedTask, NoSi DEFINE_METHOD(ASYNC_HELPERS, CAPTURE_EXECUTION_CONTEXT, CaptureExecutionContext, NoSig) DEFINE_METHOD(ASYNC_HELPERS, RESTORE_EXECUTION_CONTEXT, RestoreExecutionContext, NoSig) DEFINE_METHOD(ASYNC_HELPERS, CAPTURE_CONTINUATION_CONTEXT, CaptureContinuationContext, NoSig) -DEFINE_METHOD(ASYNC_HELPERS, CAPTURE_CONTEXTS, CaptureContexts, NoSig) -DEFINE_METHOD(ASYNC_HELPERS, RESTORE_CONTEXTS, RestoreContexts, NoSig) +DEFINE_METHOD(ASYNC_HELPERS, CAPTURE_CONTEXTS, CaptureContexts, NoSig) +DEFINE_METHOD(ASYNC_HELPERS, RESTORE_CONTEXTS, RestoreContexts, NoSig) +DEFINE_METHOD(ASYNC_HELPERS, ASYNC_CALL_CONTINUATION, AsyncCallContinuation, SM_RetContinuation) #ifdef TARGET_BROWSER DEFINE_METHOD(ASYNC_HELPERS, HANDLE_ASYNC_ENTRYPOINT, HandleAsyncEntryPoint, SM_TaskOfInt_RetInt) @@ -1098,7 +1099,6 @@ DEFINE_METHOD(STUBHELPERS, VALIDATE_BYREF, Validate DEFINE_METHOD(STUBHELPERS, GET_STUB_CONTEXT, GetStubContext, SM_RetIntPtr) DEFINE_METHOD(STUBHELPERS, LOG_PINNED_ARGUMENT, LogPinnedArgument, SM_IntPtr_IntPtr_RetVoid) DEFINE_METHOD(STUBHELPERS, NEXT_CALL_RETURN_ADDRESS, NextCallReturnAddress, SM_RetIntPtr) -DEFINE_METHOD(STUBHELPERS, ASYNC_CALL_CONTINUATION, AsyncCallContinuation, SM_RetContinuation) DEFINE_METHOD(STUBHELPERS, SAFE_HANDLE_ADD_REF, SafeHandleAddRef, SM_SafeHandle_RefBool_RetIntPtr) DEFINE_METHOD(STUBHELPERS, SAFE_HANDLE_RELEASE, SafeHandleRelease, SM_SafeHandle_RetVoid) From 3f6297ab4d2f0bb6704b694e2958f38d15ceb03e Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Fri, 7 Nov 2025 15:44:49 -0800 Subject: [PATCH 2/6] Update src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs Co-authored-by: Vladimir Sadov --- .../Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs index f8aaacc4a49740..409f04d8470ba7 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs @@ -150,9 +150,13 @@ public static partial class AsyncHelpers [Intrinsic] private static void AsyncSuspend(Continuation continuation) => throw new UnreachableException(); + // An intrinsic that provides access to continuations produced by Async calls. + // Calling this after an Async method call returns: + // * `null` if the call has completed synchronously, or + // * a continuation object if the call requires suspension. + // In this case the formal result of the call is undefined. [Intrinsic] - [BypassReadyToRun] - internal static Continuation? AsyncCallContinuation() => throw new UnreachableException(); // Unconditionally expanded intrinsic + internal static Continuation? AsyncCallContinuation() => throw new UnreachableException(); // Used during suspensions to hold the continuation chain and on what we are waiting. // Methods like FinalizeTaskReturningThunk will unlink the state and wrap into a Task. From 6bf129d81329a790b4d2a6910f70b3c3a86ff90b Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Fri, 7 Nov 2025 20:11:20 -0800 Subject: [PATCH 3/6] Update src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs --- .../src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs index 409f04d8470ba7..61ec442afd5a70 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs @@ -156,7 +156,7 @@ public static partial class AsyncHelpers // * a continuation object if the call requires suspension. // In this case the formal result of the call is undefined. [Intrinsic] - internal static Continuation? AsyncCallContinuation() => throw new UnreachableException(); + private static Continuation? AsyncCallContinuation() => throw new UnreachableException(); // Used during suspensions to hold the continuation chain and on what we are waiting. // Methods like FinalizeTaskReturningThunk will unlink the state and wrap into a Task. From 5255bc8ca8f36d446fa50532a12092cfe26293ce Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Sun, 9 Nov 2025 21:33:36 -0800 Subject: [PATCH 4/6] Nits --- .../src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs | 2 +- src/coreclr/vm/corelib.h | 2 +- src/coreclr/vm/metasig.h | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs index 61ec442afd5a70..79deaf08a0f6c7 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs @@ -144,7 +144,7 @@ public ref byte GetResultStorageOrNull() public static partial class AsyncHelpers { - // This is the "magic" method on wich other "Await" methods are built. + // This is the "magic" method on which other "Await" methods are built. // Calling this from an Async method returns the continuation to the caller thus // explicitly initiates suspension. [Intrinsic] diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index b2dae8c9ed9e6b..ecc8976103d7e5 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -749,7 +749,7 @@ DEFINE_METHOD(ASYNC_HELPERS, RESTORE_EXECUTION_CONTEXT, RestoreExecutionCon DEFINE_METHOD(ASYNC_HELPERS, CAPTURE_CONTINUATION_CONTEXT, CaptureContinuationContext, NoSig) DEFINE_METHOD(ASYNC_HELPERS, CAPTURE_CONTEXTS, CaptureContexts, NoSig) DEFINE_METHOD(ASYNC_HELPERS, RESTORE_CONTEXTS, RestoreContexts, NoSig) -DEFINE_METHOD(ASYNC_HELPERS, ASYNC_CALL_CONTINUATION, AsyncCallContinuation, SM_RetContinuation) +DEFINE_METHOD(ASYNC_HELPERS, ASYNC_CALL_CONTINUATION, AsyncCallContinuation, NoSig) #ifdef TARGET_BROWSER DEFINE_METHOD(ASYNC_HELPERS, HANDLE_ASYNC_ENTRYPOINT, HandleAsyncEntryPoint, SM_TaskOfInt_RetInt) diff --git a/src/coreclr/vm/metasig.h b/src/coreclr/vm/metasig.h index 412b88665360d0..065690fd812428 100644 --- a/src/coreclr/vm/metasig.h +++ b/src/coreclr/vm/metasig.h @@ -619,7 +619,6 @@ DEFINE_METASIG(SM(PtrByte_RetStr, P(b), s)) DEFINE_METASIG(SM(Str_RetPtrByte, s, P(b))) DEFINE_METASIG(SM(PtrByte_RetVoid, P(b), v)) -DEFINE_METASIG_T(SM(RetContinuation, , C(CONTINUATION))) DEFINE_METASIG(GM(T_RetVoid, IMAGE_CEE_CS_CALLCONV_DEFAULT, 1, M(0), v)) DEFINE_METASIG_T(GM(RetTaskOfT, IMAGE_CEE_CS_CALLCONV_DEFAULT, 1, , GI(C(TASK_1), 1, M(0)))) DEFINE_METASIG_T(GM(RetValueTaskOfT, IMAGE_CEE_CS_CALLCONV_DEFAULT, 1, , GI(g(VALUETASK_1), 1, M(0)))) From b9373e49bd69584886a98738e023fdb1de3b584e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Sun, 9 Nov 2025 22:01:56 -0800 Subject: [PATCH 5/6] Fix build break --- src/coreclr/vm/jitinterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 22707566d309a2..f6902fbc24f91e 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -14763,7 +14763,7 @@ CORINFO_METHOD_HANDLE CEEJitInfo::getAsyncResumptionStub(void** entryPoint) TypeHandle continuationTypeHnd = CoreLibBinder::GetClass(CLASS__CONTINUATION); DWORD newContinuationLoc = pCode->NewLocal(LocalDesc(continuationTypeHnd)); - pCode->EmitCALL(METHOD__STUBHELPERS__ASYNC_CALL_CONTINUATION, 0, 1); + pCode->EmitCALL(METHOD__ASYNC_HELPERS__ASYNC_CALL_CONTINUATION, 0, 1); pCode->EmitSTLOC(newContinuationLoc); if (!msig.IsReturnTypeVoid()) From 3a1efd2aeb22047c38265fb707da368898b7c42f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Sun, 9 Nov 2025 22:40:49 -0800 Subject: [PATCH 6/6] One more build break --- src/coreclr/vm/asyncthunks.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/asyncthunks.cpp b/src/coreclr/vm/asyncthunks.cpp index 519daeefeed193..0f92fe053f734a 100644 --- a/src/coreclr/vm/asyncthunks.cpp +++ b/src/coreclr/vm/asyncthunks.cpp @@ -190,7 +190,7 @@ void MethodDesc::EmitTaskReturningThunk(MethodDesc* pAsyncOtherVariant, MetaSig& if (logicalResultLocal != UINT_MAX) pCode->EmitSTLOC(logicalResultLocal); - pCode->EmitCALL(METHOD__STUBHELPERS__ASYNC_CALL_CONTINUATION, 0, 1); + pCode->EmitCALL(METHOD__ASYNC_HELPERS__ASYNC_CALL_CONTINUATION, 0, 1); pCode->EmitBRFALSE(finishedLabel); pCode->EmitLEAVE(suspendedLabel);