From 0ade4ac94a879d892f8ebbf95ce703dc9f4d272d Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Fri, 9 Jan 2026 13:38:24 -0800 Subject: [PATCH 1/4] [clr-interp] Async Resume stubs are exclusive to the JIT as they use a set of intrinsics that are JIT specific - Disable running the interpreter compiler for these. In real scenarios we will either have a JIT to generate them, or they will be produced by the R2R compiler, so this should be a good long term solution --- src/coreclr/vm/jitinterface.cpp | 2 +- src/coreclr/vm/method.hpp | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 84c5fe782bed2a..0734fc6caac3b7 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -13467,7 +13467,7 @@ PCODE UnsafeJitFunction(PrepareCodeConfig* config, } // If the interpreter was loaded, use it. - if (interpreterMgr->IsInterpreterLoaded()) + if (interpreterMgr->IsInterpreterLoaded() && (!ftn->IsILStub() || !ftn->AsDynamicMethodDesc()->IsAsyncResumeStub())) // Async resumt stubs cannot be generated by the interpreter { CInterpreterJitInfo interpreterJitInfo{ config, ftn, ILHeader, interpreterMgr }; ret = UnsafeJitFunctionWorker(interpreterMgr, &interpreterJitInfo, nativeCodeVersion, pSizeOfCode); diff --git a/src/coreclr/vm/method.hpp b/src/coreclr/vm/method.hpp index c63f9e344d87d0..d84d8dd8eb4a22 100644 --- a/src/coreclr/vm/method.hpp +++ b/src/coreclr/vm/method.hpp @@ -2992,6 +2992,12 @@ class DynamicMethodDesc : public StoredSigMethodDesc _ASSERTE(IsILStub()); return GetILStubType() == DynamicMethodDesc::StubDelegateShuffleThunk; } + bool IsAsyncResumeStub() const + { + LIMITED_METHOD_DAC_CONTRACT; + _ASSERTE(IsILStub()); + return GetILStubType() == DynamicMethodDesc::StubAsyncResume; + } // Whether the stub takes a context argument that is an interop MethodDesc. // See RequiresMDContextArg() for the non-stub version. From 4d4e0a4c93129322564873cd4be03174cd085e13 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Fri, 9 Jan 2026 16:03:26 -0800 Subject: [PATCH 2/4] Update src/coreclr/vm/jitinterface.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- 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 0734fc6caac3b7..255de8582189b9 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -13467,7 +13467,7 @@ PCODE UnsafeJitFunction(PrepareCodeConfig* config, } // If the interpreter was loaded, use it. - if (interpreterMgr->IsInterpreterLoaded() && (!ftn->IsILStub() || !ftn->AsDynamicMethodDesc()->IsAsyncResumeStub())) // Async resumt stubs cannot be generated by the interpreter + if (interpreterMgr->IsInterpreterLoaded() && (!ftn->IsILStub() || !ftn->AsDynamicMethodDesc()->IsAsyncResumeStub())) // Async resume stubs cannot be generated by the interpreter { CInterpreterJitInfo interpreterJitInfo{ config, ftn, ILHeader, interpreterMgr }; ret = UnsafeJitFunctionWorker(interpreterMgr, &interpreterJitInfo, nativeCodeVersion, pSizeOfCode); From c0a922e8e5a509af1998e2164b2d412eae4d1626 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Mon, 12 Jan 2026 12:47:56 -0800 Subject: [PATCH 3/4] Revert last 2 commits --- src/coreclr/vm/jitinterface.cpp | 2 +- src/coreclr/vm/method.hpp | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 255de8582189b9..84c5fe782bed2a 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -13467,7 +13467,7 @@ PCODE UnsafeJitFunction(PrepareCodeConfig* config, } // If the interpreter was loaded, use it. - if (interpreterMgr->IsInterpreterLoaded() && (!ftn->IsILStub() || !ftn->AsDynamicMethodDesc()->IsAsyncResumeStub())) // Async resume stubs cannot be generated by the interpreter + if (interpreterMgr->IsInterpreterLoaded()) { CInterpreterJitInfo interpreterJitInfo{ config, ftn, ILHeader, interpreterMgr }; ret = UnsafeJitFunctionWorker(interpreterMgr, &interpreterJitInfo, nativeCodeVersion, pSizeOfCode); diff --git a/src/coreclr/vm/method.hpp b/src/coreclr/vm/method.hpp index d84d8dd8eb4a22..c63f9e344d87d0 100644 --- a/src/coreclr/vm/method.hpp +++ b/src/coreclr/vm/method.hpp @@ -2992,12 +2992,6 @@ class DynamicMethodDesc : public StoredSigMethodDesc _ASSERTE(IsILStub()); return GetILStubType() == DynamicMethodDesc::StubDelegateShuffleThunk; } - bool IsAsyncResumeStub() const - { - LIMITED_METHOD_DAC_CONTRACT; - _ASSERTE(IsILStub()); - return GetILStubType() == DynamicMethodDesc::StubAsyncResume; - } // Whether the stub takes a context argument that is an interop MethodDesc. // See RequiresMDContextArg() for the non-stub version. From e90e7657167393b44728dad59bc8a9f298a69069 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Mon, 12 Jan 2026 13:56:32 -0800 Subject: [PATCH 4/4] Fix the partially implemented SetNextCallAsyncContinuation intrinsic --- src/coreclr/interpreter/compiler.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/coreclr/interpreter/compiler.cpp b/src/coreclr/interpreter/compiler.cpp index d04b313f8ca6ac..52605e9473c6a3 100644 --- a/src/coreclr/interpreter/compiler.cpp +++ b/src/coreclr/interpreter/compiler.cpp @@ -4946,8 +4946,18 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re m_pStackPointer--; int32_t continuationArg = m_pStackPointer[0].var; - AddIns(INTOP_LDNULL); - m_pLastNewIns->SetDVar(continuationArg); + if (m_nextCallAsyncContinuationVar == -1) + { + AddIns(INTOP_LDNULL); + m_pLastNewIns->SetDVar(continuationArg); + } + else + { + AddIns(INTOP_MOV_P); + m_pLastNewIns->SetSVar(m_nextCallAsyncContinuationVar); + m_pLastNewIns->SetDVar(continuationArg); + m_nextCallAsyncContinuationVar = -1; + } callArgs[continuationArgLocation] = continuationArg; }