From 395b673ffb605e7c5b701f51b74eb053d05ca33f Mon Sep 17 00:00:00 2001 From: Tom McDonald Date: Sat, 1 Aug 2026 12:34:27 -0400 Subject: [PATCH 1/2] Fix runtime async context restore after EnC remap Use the continuation argument for root-method context restoration so Edit-and-Continue remaps do not depend on a synthesized resumed indicator that is not preserved in the remapped frame. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/coreclr/jit/async.cpp | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/coreclr/jit/async.cpp b/src/coreclr/jit/async.cpp index 6a47dcacc6a77b..99d68f080552a4 100644 --- a/src/coreclr/jit/async.cpp +++ b/src/coreclr/jit/async.cpp @@ -220,9 +220,19 @@ PhaseStatus Compiler::SaveAsyncContexts() } } - // Insert RestoreContexts call in fault (exceptional case) - // First argument: resumed = (continuation != null) - GenTree* resumed = gtNewLclvNode(lvaResumedIndicator, TYP_INT); + // Inlinees need an explicit indicator because they do not have a continuation + // argument. Root methods can use the continuation argument directly, which also + // remains correct when EnC remaps directly into a resumed method body. + GenTree* resumed; + if (compIsForInlining()) + { + resumed = gtNewLclvNode(lvaResumedIndicator, TYP_INT); + } + else + { + GenTree* continuation = gtNewLclVarNode(lvaAsyncContinuationArg, TYP_REF); + resumed = gtNewOperNode(GT_NE, TYP_INT, continuation, gtNewNull()); + } GenTreeCall* restoreCall = gtNewUserCallNode(asyncInfo->restoreContextsMethHnd, TYP_VOID); restoreCall->gtArgs.PushFront(this, @@ -387,7 +397,16 @@ BasicBlock* Compiler::CreateReturnBB(unsigned* mergedReturnLcl) // Insert "restore" call CORINFO_ASYNC_INFO* asyncInfo = eeGetAsyncInfo(); - GenTree* resumed = gtNewLclvNode(lvaResumedIndicator, TYP_INT); + GenTree* resumed; + if (compIsForInlining()) + { + resumed = gtNewLclvNode(lvaResumedIndicator, TYP_INT); + } + else + { + GenTree* continuation = gtNewLclVarNode(lvaAsyncContinuationArg, TYP_REF); + resumed = gtNewOperNode(GT_NE, TYP_INT, continuation, gtNewNull()); + } GenTreeCall* restoreCall = gtNewUserCallNode(asyncInfo->restoreContextsMethHnd, TYP_VOID); restoreCall->gtArgs.PushFront(this, From e50e2f6f57960c788f2340091bf5940da30e21f1 Mon Sep 17 00:00:00 2001 From: Tom McDonald Date: Sun, 2 Aug 2026 23:16:50 -0400 Subject: [PATCH 2/2] Fix JIT formatting Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/coreclr/jit/async.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/async.cpp b/src/coreclr/jit/async.cpp index 99d68f080552a4..3665d7010d0965 100644 --- a/src/coreclr/jit/async.cpp +++ b/src/coreclr/jit/async.cpp @@ -231,7 +231,7 @@ PhaseStatus Compiler::SaveAsyncContexts() else { GenTree* continuation = gtNewLclVarNode(lvaAsyncContinuationArg, TYP_REF); - resumed = gtNewOperNode(GT_NE, TYP_INT, continuation, gtNewNull()); + resumed = gtNewOperNode(GT_NE, TYP_INT, continuation, gtNewNull()); } GenTreeCall* restoreCall = gtNewUserCallNode(asyncInfo->restoreContextsMethHnd, TYP_VOID); @@ -405,7 +405,7 @@ BasicBlock* Compiler::CreateReturnBB(unsigned* mergedReturnLcl) else { GenTree* continuation = gtNewLclVarNode(lvaAsyncContinuationArg, TYP_REF); - resumed = gtNewOperNode(GT_NE, TYP_INT, continuation, gtNewNull()); + resumed = gtNewOperNode(GT_NE, TYP_INT, continuation, gtNewNull()); } GenTreeCall* restoreCall = gtNewUserCallNode(asyncInfo->restoreContextsMethHnd, TYP_VOID);