@@ -58,13 +58,43 @@ bool MethodDesc::TryGenerateAsyncThunk(DynamicResolver** resolver, COR_ILMETHOD_
5858 return true ;
5959}
6060
61+ // provided an async method, emits a Task-returning wrapper.
6162void MethodDesc::EmitTaskReturningThunk (MethodDesc* pAsyncOtherVariant, MetaSig& thunkMsig, ILStubLinker* pSL)
6263{
6364 _ASSERTE (!pAsyncOtherVariant->IsAsyncThunkMethod ());
6465
66+ // Emits roughly the following code:
67+ //
68+ // ExecutionAndSyncBlockStore store = default;
69+ // store.Push();
70+ // try
71+ // {
72+ // Continuation cont;
73+ // Exception ex;
74+ // try
75+ // {
76+ // T result = Inner(args);
77+ // // call an intrisic to see if the call above produced a continuation
78+ // cont = StubHelpers.AsyncCallContinuation();
79+ // if (cont == null)
80+ // return Task.FromResult(result);
81+ // }
82+ // catch (Exception ex1)
83+ // {
84+ // ex = ex1;
85+ // }
86+ //
87+ // return FinalizeTaskReturningThunk(cont, ex);
88+ // }
89+ // finally
90+ // {
91+ // store.Pop();
92+ // }
93+
6594 ILCodeStream* pCode = pSL->NewCodeStream (ILStubLinker::kDispatch );
6695
6796 unsigned continuationLocal = pCode->NewLocal (LocalDesc (CoreLibBinder::GetClass (CLASS__CONTINUATION)));
97+ unsigned exceptionLocal = pCode->NewLocal (LocalDesc (CoreLibBinder::GetClass (CLASS__EXCEPTION)));
6898
6999 TypeHandle thTaskRet = thunkMsig.GetRetTypeHandleThrowing ();
70100
@@ -84,7 +114,7 @@ void MethodDesc::EmitTaskReturningThunk(MethodDesc* pAsyncOtherVariant, MetaSig&
84114 DWORD executionAndSyncBlockStoreLocal = pCode->NewLocal (executionAndSyncBlockStoreLocalDesc);
85115
86116 ILCodeLabel* returnTaskLabel = pCode->NewCodeLabel ();
87- ILCodeLabel* suspendedLabel = pCode->NewCodeLabel ();
117+ ILCodeLabel* finalizeTaskLabel = pCode->NewCodeLabel ();
88118 ILCodeLabel* finishedLabel = pCode->NewCodeLabel ();
89119
90120 pCode->EmitLDLOCA (executionAndSyncBlockStoreLocal);
@@ -171,7 +201,7 @@ void MethodDesc::EmitTaskReturningThunk(MethodDesc* pAsyncOtherVariant, MetaSig&
171201 pCode->EmitLDLOC (continuationLocal);
172202 pCode->EmitBRFALSE (finishedLabel);
173203
174- pCode->EmitLEAVE (suspendedLabel );
204+ pCode->EmitLEAVE (finalizeTaskLabel );
175205
176206 pCode->EmitLabel (finishedLabel);
177207 if (logicalResultLocal != UINT_MAX)
@@ -202,37 +232,12 @@ void MethodDesc::EmitTaskReturningThunk(MethodDesc* pAsyncOtherVariant, MetaSig&
202232 // Catch
203233 {
204234 pCode->BeginCatchBlock (pCode->GetToken (CoreLibBinder::GetClass (CLASS__EXCEPTION)));
205-
206- int fromExceptionToken;
207- if (logicalResultLocal != UINT_MAX)
208- {
209- MethodDesc* fromExceptionMD;
210- if (isValueTask)
211- fromExceptionMD = CoreLibBinder::GetMethod (METHOD__VALUETASK__FROM_EXCEPTION_1);
212- else
213- fromExceptionMD = CoreLibBinder::GetMethod (METHOD__TASK__FROM_EXCEPTION_1);
214-
215- fromExceptionMD = FindOrCreateAssociatedMethodDesc (fromExceptionMD, fromExceptionMD->GetMethodTable (), FALSE , Instantiation (&thLogicalRetType, 1 ), FALSE );
216-
217- fromExceptionToken = GetTokenForGenericMethodCallWithAsyncReturnType (pCode, fromExceptionMD);
218- }
219- else
220- {
221- MethodDesc* fromExceptionMD;
222- if (isValueTask)
223- fromExceptionMD = CoreLibBinder::GetMethod (METHOD__VALUETASK__FROM_EXCEPTION);
224- else
225- fromExceptionMD = CoreLibBinder::GetMethod (METHOD__TASK__FROM_EXCEPTION);
226-
227- fromExceptionToken = pCode->GetToken (fromExceptionMD);
228- }
229- pCode->EmitCALL (fromExceptionToken, 1 , 1 );
230- pCode->EmitSTLOC (returnTaskLocal);
231- pCode->EmitLEAVE (returnTaskLabel);
235+ pCode->EmitSTLOC (exceptionLocal);
236+ pCode->EmitLEAVE (finalizeTaskLabel);
232237 pCode->EndCatchBlock ();
233238 }
234239
235- pCode->EmitLabel (suspendedLabel );
240+ pCode->EmitLabel (finalizeTaskLabel );
236241
237242 int finalizeTaskReturningThunkToken;
238243 if (logicalResultLocal != UINT_MAX)
@@ -255,8 +260,10 @@ void MethodDesc::EmitTaskReturningThunk(MethodDesc* pAsyncOtherVariant, MetaSig&
255260 md = CoreLibBinder::GetMethod (METHOD__ASYNC_HELPERS__FINALIZE_TASK_RETURNING_THUNK);
256261 finalizeTaskReturningThunkToken = pCode->GetToken (md);
257262 }
263+
258264 pCode->EmitLDLOC (continuationLocal);
259- pCode->EmitCALL (finalizeTaskReturningThunkToken, 1 , 1 );
265+ pCode->EmitLDLOC (exceptionLocal);
266+ pCode->EmitCALL (finalizeTaskReturningThunkToken, 2 , 1 );
260267 pCode->EmitSTLOC (returnTaskLocal);
261268 pCode->EmitLEAVE (returnTaskLabel);
262269
@@ -447,15 +454,17 @@ int MethodDesc::GetTokenForGenericTypeMethodCallWithAsyncReturnType(ILCodeStream
447454 return pCode->GetToken (md, typeSigToken);
448455}
449456
457+ // provided a Task-returning method, emits an async wrapper.
450458void MethodDesc::EmitAsyncMethodThunk (MethodDesc* pAsyncOtherVariant, MetaSig& msig, ILStubLinker* pSL)
451459{
452460 _ASSERTE (!pAsyncOtherVariant->IsAsyncThunkMethod ());
453461 _ASSERTE (!pAsyncOtherVariant->IsVoid ());
454462
455- // TODO: (async) we may now be able to just do "AsyncHelpers.Await(other(arg))",
456- // but would need to make sure it is not "optimized" back to calling this same thunk.
457-
458- // Implement IL that is effectively the following
463+ // The thunk is roughly the same as "AsyncHelpers.Await(other(arg))", but without any
464+ // synchronization preferences. In a case of resumption the thunk will run on whatever the
465+ // thread/context was used by the awaiter to call us on completion.
466+ //
467+ // Implement IL that is effectively the following:
459468 /*
460469 {
461470 TaskAwaiter<RetType> awaiter = other(arg).GetAwaiter();
0 commit comments