Skip to content

Commit 367fe72

Browse files
committed
Separate task finalization helpers for continuation and exception.
1 parent 5a55cbd commit 367fe72

File tree

4 files changed

+114
-80
lines changed

4 files changed

+114
-80
lines changed

src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs

Lines changed: 64 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -591,83 +591,89 @@ private static bool QueueContinuationFollowUpActionIfNecessary<T, TOps>(T task,
591591
#pragma warning disable CA1859
592592
// When a Task-returning thunk gets a continuation result
593593
// it calls here to make a Task that awaits on the current async state.
594-
private static Task<T?> FinalizeTaskReturningThunk<T>(Continuation continuation, Exception ex)
594+
private static Task<T?> FinalizeTaskReturningThunk<T>(Continuation continuation)
595595
{
596-
if (continuation is not null)
597-
{
598-
Continuation finalContinuation = new Continuation();
599-
600-
// Note that the exact location the return value is placed is tied
601-
// into getAsyncResumptionStub in the VM, so do not change this
602-
// without also changing that code (and the JIT).
603-
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
604-
{
605-
finalContinuation.Flags = CorInfoContinuationFlags.CORINFO_CONTINUATION_RESULT_IN_GCDATA | CorInfoContinuationFlags.CORINFO_CONTINUATION_NEEDS_EXCEPTION;
606-
finalContinuation.GCData = new object[1];
607-
}
608-
else
609-
{
610-
finalContinuation.Flags = CorInfoContinuationFlags.CORINFO_CONTINUATION_NEEDS_EXCEPTION;
611-
finalContinuation.Data = new byte[Unsafe.SizeOf<T>()];
612-
}
596+
Continuation finalContinuation = new Continuation();
613597

614-
continuation.Next = finalContinuation;
615-
616-
ThunkTask<T?> result = new();
617-
result.HandleSuspended(continuation);
618-
return result;
598+
// Note that the exact location the return value is placed is tied
599+
// into getAsyncResumptionStub in the VM, so do not change this
600+
// without also changing that code (and the JIT).
601+
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
602+
{
603+
finalContinuation.Flags = CorInfoContinuationFlags.CORINFO_CONTINUATION_RESULT_IN_GCDATA | CorInfoContinuationFlags.CORINFO_CONTINUATION_NEEDS_EXCEPTION;
604+
finalContinuation.GCData = new object[1];
619605
}
620606
else
621607
{
622-
Task<T?> task = new();
623-
// Tail of AsyncTaskMethodBuilderT.SetException
624-
bool successfullySet = ex is OperationCanceledException oce ?
625-
task.TrySetCanceled(oce.CancellationToken, oce) :
626-
task.TrySetException(ex);
627-
628-
Debug.Assert(successfullySet);
629-
return task;
608+
finalContinuation.Flags = CorInfoContinuationFlags.CORINFO_CONTINUATION_NEEDS_EXCEPTION;
609+
finalContinuation.Data = new byte[Unsafe.SizeOf<T>()];
630610
}
611+
612+
continuation.Next = finalContinuation;
613+
614+
ThunkTask<T?> result = new();
615+
result.HandleSuspended(continuation);
616+
return result;
631617
}
632618

633-
private static Task FinalizeTaskReturningThunk(Continuation continuation, Exception ex)
619+
private static Task FinalizeTaskReturningThunk(Continuation continuation)
634620
{
635-
if (continuation is not null)
621+
Continuation finalContinuation = new Continuation
636622
{
637-
Continuation finalContinuation = new Continuation
638-
{
639-
Flags = CorInfoContinuationFlags.CORINFO_CONTINUATION_NEEDS_EXCEPTION,
640-
};
641-
continuation.Next = finalContinuation;
623+
Flags = CorInfoContinuationFlags.CORINFO_CONTINUATION_NEEDS_EXCEPTION,
624+
};
625+
continuation.Next = finalContinuation;
642626

643-
ThunkTask result = new();
644-
result.HandleSuspended(continuation);
645-
return result;
646-
}
647-
else
648-
{
649-
Debug.Assert(ex is not null);
650-
Task task = new();
651-
// Tail of AsyncTaskMethodBuilderT.SetException
652-
bool successfullySet = ex is OperationCanceledException oce ?
653-
task.TrySetCanceled(oce.CancellationToken, oce) :
654-
task.TrySetException(ex);
655-
656-
Debug.Assert(successfullySet);
657-
return task;
658-
}
627+
ThunkTask result = new();
628+
result.HandleSuspended(continuation);
629+
return result;
659630
}
660631

661-
private static ValueTask<T?> FinalizeValueTaskReturningThunk<T>(Continuation continuation, Exception ex)
632+
private static ValueTask<T?> FinalizeValueTaskReturningThunk<T>(Continuation continuation)
662633
{
663634
// We only come to these methods in the expensive case (already
664635
// suspended), so ValueTask optimization here is not relevant.
665-
return new ValueTask<T?>(FinalizeTaskReturningThunk<T>(continuation, ex));
636+
return new ValueTask<T?>(FinalizeTaskReturningThunk<T>(continuation));
637+
}
638+
639+
private static ValueTask FinalizeValueTaskReturningThunk(Continuation continuation)
640+
{
641+
return new ValueTask(FinalizeTaskReturningThunk(continuation));
642+
}
643+
644+
private static Task<T?> TaskFromException<T>(Exception ex)
645+
{
646+
Task<T?> task = new();
647+
bool successfullySet = ex is OperationCanceledException oce ?
648+
task.TrySetCanceled(oce.CancellationToken, oce) :
649+
task.TrySetException(ex);
650+
651+
Debug.Assert(successfullySet);
652+
return task;
653+
}
654+
655+
private static Task TaskFromException(Exception ex)
656+
{
657+
Task task = new();
658+
// Tail of AsyncTaskMethodBuilderT.SetException
659+
bool successfullySet = ex is OperationCanceledException oce ?
660+
task.TrySetCanceled(oce.CancellationToken, oce) :
661+
task.TrySetException(ex);
662+
663+
Debug.Assert(successfullySet);
664+
return task;
665+
}
666+
667+
private static ValueTask ValueTaskFromException(Exception ex)
668+
{
669+
// We only come to these methods in the expensive case (exception),
670+
// so ValueTask optimization here is not relevant.
671+
return new ValueTask(TaskFromException(ex));
666672
}
667673

668-
private static ValueTask FinalizeValueTaskReturningThunk(Continuation continuation, Exception ex)
674+
private static ValueTask<T?> ValueTaskFromException<T>(Exception ex)
669675
{
670-
return new ValueTask(FinalizeTaskReturningThunk(continuation, ex));
676+
return new ValueTask<T?>(TaskFromException<T>(ex));
671677
}
672678

673679
[MethodImpl(MethodImplOptions.AggressiveInlining)]

src/coreclr/vm/asyncthunks.cpp

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -70,21 +70,20 @@ void MethodDesc::EmitTaskReturningThunk(MethodDesc* pAsyncOtherVariant, MetaSig&
7070
// try
7171
// {
7272
// Continuation cont;
73-
// Exception ex;
7473
// try
7574
// {
7675
// T result = Inner(args);
7776
// // call an intrisic to see if the call above produced a continuation
7877
// cont = StubHelpers.AsyncCallContinuation();
7978
// if (cont == null)
8079
// return Task.FromResult(result);
80+
//
81+
// return FinalizeTaskReturningThunk(cont);
8182
// }
82-
// catch (Exception ex1)
83+
// catch (Exception ex)
8384
// {
84-
// ex = ex1;
85+
// return TaskFromException(ex);
8586
// }
86-
//
87-
// return FinalizeTaskReturningThunk(cont, ex);
8887
// }
8988
// finally
9089
// {
@@ -94,7 +93,6 @@ void MethodDesc::EmitTaskReturningThunk(MethodDesc* pAsyncOtherVariant, MetaSig&
9493
ILCodeStream* pCode = pSL->NewCodeStream(ILStubLinker::kDispatch);
9594

9695
unsigned continuationLocal = pCode->NewLocal(LocalDesc(CoreLibBinder::GetClass(CLASS__CONTINUATION)));
97-
unsigned exceptionLocal = pCode->NewLocal(LocalDesc(CoreLibBinder::GetClass(CLASS__EXCEPTION)));
9896

9997
TypeHandle thTaskRet = thunkMsig.GetRetTypeHandleThrowing();
10098

@@ -114,7 +112,7 @@ void MethodDesc::EmitTaskReturningThunk(MethodDesc* pAsyncOtherVariant, MetaSig&
114112
DWORD executionAndSyncBlockStoreLocal = pCode->NewLocal(executionAndSyncBlockStoreLocalDesc);
115113

116114
ILCodeLabel* returnTaskLabel = pCode->NewCodeLabel();
117-
ILCodeLabel* finalizeTaskLabel = pCode->NewCodeLabel();
115+
ILCodeLabel* suspendedLabel = pCode->NewCodeLabel();
118116
ILCodeLabel* finishedLabel = pCode->NewCodeLabel();
119117

120118
pCode->EmitLDLOCA(executionAndSyncBlockStoreLocal);
@@ -201,7 +199,7 @@ void MethodDesc::EmitTaskReturningThunk(MethodDesc* pAsyncOtherVariant, MetaSig&
201199
pCode->EmitLDLOC(continuationLocal);
202200
pCode->EmitBRFALSE(finishedLabel);
203201

204-
pCode->EmitLEAVE(finalizeTaskLabel);
202+
pCode->EmitLEAVE(suspendedLabel);
205203

206204
pCode->EmitLabel(finishedLabel);
207205
if (logicalResultLocal != UINT_MAX)
@@ -232,12 +230,36 @@ void MethodDesc::EmitTaskReturningThunk(MethodDesc* pAsyncOtherVariant, MetaSig&
232230
// Catch
233231
{
234232
pCode->BeginCatchBlock(pCode->GetToken(CoreLibBinder::GetClass(CLASS__EXCEPTION)));
235-
pCode->EmitSTLOC(exceptionLocal);
236-
pCode->EmitLEAVE(finalizeTaskLabel);
233+
234+
int fromExceptionToken;
235+
if (logicalResultLocal != UINT_MAX)
236+
{
237+
MethodDesc* md;
238+
if (isValueTask)
239+
md = CoreLibBinder::GetMethod(METHOD__ASYNC_HELPERS__VALUETASK_FROM_EXCEPTION_1);
240+
else
241+
md = CoreLibBinder::GetMethod(METHOD__ASYNC_HELPERS__TASK_FROM_EXCEPTION_1);
242+
243+
md = FindOrCreateAssociatedMethodDesc(md, md->GetMethodTable(), FALSE, Instantiation(&thLogicalRetType, 1), FALSE);
244+
fromExceptionToken = GetTokenForGenericMethodCallWithAsyncReturnType(pCode, md);
245+
}
246+
else
247+
{
248+
MethodDesc* md;
249+
if (isValueTask)
250+
md = CoreLibBinder::GetMethod(METHOD__ASYNC_HELPERS__VALUETASK_FROM_EXCEPTION);
251+
else
252+
md = CoreLibBinder::GetMethod(METHOD__ASYNC_HELPERS__TASK_FROM_EXCEPTION);
253+
fromExceptionToken = pCode->GetToken(md);
254+
}
255+
256+
pCode->EmitCALL(fromExceptionToken, 1, 1);
257+
pCode->EmitSTLOC(returnTaskLocal);
258+
pCode->EmitLEAVE(returnTaskLabel);
237259
pCode->EndCatchBlock();
238260
}
239261

240-
pCode->EmitLabel(finalizeTaskLabel);
262+
pCode->EmitLabel(suspendedLabel);
241263

242264
int finalizeTaskReturningThunkToken;
243265
if (logicalResultLocal != UINT_MAX)
@@ -260,10 +282,8 @@ void MethodDesc::EmitTaskReturningThunk(MethodDesc* pAsyncOtherVariant, MetaSig&
260282
md = CoreLibBinder::GetMethod(METHOD__ASYNC_HELPERS__FINALIZE_TASK_RETURNING_THUNK);
261283
finalizeTaskReturningThunkToken = pCode->GetToken(md);
262284
}
263-
264285
pCode->EmitLDLOC(continuationLocal);
265-
pCode->EmitLDLOC(exceptionLocal);
266-
pCode->EmitCALL(finalizeTaskReturningThunkToken, 2, 1);
286+
pCode->EmitCALL(finalizeTaskReturningThunkToken, 1, 1);
267287
pCode->EmitSTLOC(returnTaskLocal);
268288
pCode->EmitLEAVE(returnTaskLabel);
269289

src/coreclr/vm/corelib.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -731,10 +731,17 @@ DEFINE_METHOD(ASYNC_HELPERS, ALLOC_CONTINUATION, AllocContinuation,
731731
DEFINE_METHOD(ASYNC_HELPERS, ALLOC_CONTINUATION_METHOD, AllocContinuationMethod, NoSig)
732732
DEFINE_METHOD(ASYNC_HELPERS, ALLOC_CONTINUATION_CLASS, AllocContinuationClass, NoSig)
733733
DEFINE_METHOD(ASYNC_HELPERS, ALLOC_CONTINUATION_RESULT_BOX, AllocContinuationResultBox, SM_VoidPtr_RetObj)
734-
DEFINE_METHOD(ASYNC_HELPERS, FINALIZE_TASK_RETURNING_THUNK, FinalizeTaskReturningThunk, SM_Continuation_Exception_RetTask)
735-
DEFINE_METHOD(ASYNC_HELPERS, FINALIZE_TASK_RETURNING_THUNK_1, FinalizeTaskReturningThunk, GM_Continuation_Exception_RetTaskOfT)
736-
DEFINE_METHOD(ASYNC_HELPERS, FINALIZE_VALUETASK_RETURNING_THUNK, FinalizeValueTaskReturningThunk, SM_Continuation_Exception_RetValueTask)
737-
DEFINE_METHOD(ASYNC_HELPERS, FINALIZE_VALUETASK_RETURNING_THUNK_1, FinalizeValueTaskReturningThunk, GM_Continuation_Exception_RetValueTaskOfT)
734+
735+
DEFINE_METHOD(ASYNC_HELPERS, FINALIZE_TASK_RETURNING_THUNK, FinalizeTaskReturningThunk, SM_Continuation_RetTask)
736+
DEFINE_METHOD(ASYNC_HELPERS, FINALIZE_TASK_RETURNING_THUNK_1, FinalizeTaskReturningThunk, GM_Continuation_RetTaskOfT)
737+
DEFINE_METHOD(ASYNC_HELPERS, FINALIZE_VALUETASK_RETURNING_THUNK, FinalizeValueTaskReturningThunk, SM_Continuation_RetValueTask)
738+
DEFINE_METHOD(ASYNC_HELPERS, FINALIZE_VALUETASK_RETURNING_THUNK_1, FinalizeValueTaskReturningThunk, GM_Continuation_RetValueTaskOfT)
739+
740+
DEFINE_METHOD(ASYNC_HELPERS, TASK_FROM_EXCEPTION, TaskFromException, SM_Exception_RetTask)
741+
DEFINE_METHOD(ASYNC_HELPERS, TASK_FROM_EXCEPTION_1, TaskFromException, GM_Exception_RetTaskOfT)
742+
DEFINE_METHOD(ASYNC_HELPERS, VALUETASK_FROM_EXCEPTION, ValueTaskFromException, SM_Exception_RetValueTask)
743+
DEFINE_METHOD(ASYNC_HELPERS, VALUETASK_FROM_EXCEPTION_1, ValueTaskFromException, GM_Exception_RetValueTaskOfT)
744+
738745
DEFINE_METHOD(ASYNC_HELPERS, UNSAFE_AWAIT_AWAITER_1, UnsafeAwaitAwaiter, GM_T_RetVoid)
739746
DEFINE_METHOD(ASYNC_HELPERS, CAPTURE_EXECUTION_CONTEXT, CaptureExecutionContext, NoSig)
740747
DEFINE_METHOD(ASYNC_HELPERS, RESTORE_EXECUTION_CONTEXT, RestoreExecutionContext, NoSig)

src/coreclr/vm/metasig.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -625,10 +625,11 @@ DEFINE_METASIG(SM(PtrByte_RetVoid, P(b), v))
625625

626626
DEFINE_METASIG_T(SM(RetContinuation, , C(CONTINUATION)))
627627
DEFINE_METASIG(GM(T_RetVoid, IMAGE_CEE_CS_CALLCONV_DEFAULT, 1, M(0), v))
628-
DEFINE_METASIG_T(SM(Continuation_Exception_RetTask, C(CONTINUATION) C(EXCEPTION), C(TASK)))
629-
DEFINE_METASIG_T(GM(Continuation_Exception_RetTaskOfT, IMAGE_CEE_CS_CALLCONV_DEFAULT, 1, C(CONTINUATION) C(EXCEPTION), GI(C(TASK_1), 1, M(0))))
630-
DEFINE_METASIG_T(SM(Continuation_Exception_RetValueTask, C(CONTINUATION) C(EXCEPTION), g(VALUETASK)))
631-
DEFINE_METASIG_T(GM(Continuation_Exception_RetValueTaskOfT, IMAGE_CEE_CS_CALLCONV_DEFAULT, 1, C(CONTINUATION) C(EXCEPTION), GI(g(VALUETASK_1), 1, M(0))))
628+
629+
DEFINE_METASIG_T(SM(Continuation_RetTask, C(CONTINUATION), C(TASK)))
630+
DEFINE_METASIG_T(GM(Continuation_RetTaskOfT, IMAGE_CEE_CS_CALLCONV_DEFAULT, 1, C(CONTINUATION), GI(C(TASK_1), 1, M(0))))
631+
DEFINE_METASIG_T(SM(Continuation_RetValueTask, C(CONTINUATION), g(VALUETASK)))
632+
DEFINE_METASIG_T(GM(Continuation_RetValueTaskOfT, IMAGE_CEE_CS_CALLCONV_DEFAULT, 1, C(CONTINUATION), GI(g(VALUETASK_1), 1, M(0))))
632633

633634
// Undefine macros in case we include the file again in the compilation unit
634635

0 commit comments

Comments
 (0)