@@ -58,13 +58,43 @@ bool MethodDesc::TryGenerateAsyncThunk(DynamicResolver** resolver, COR_ILMETHOD_
58
58
return true ;
59
59
}
60
60
61
+ // provided an async method, emits a Task-returning wrapper.
61
62
void MethodDesc::EmitTaskReturningThunk (MethodDesc* pAsyncOtherVariant, MetaSig& thunkMsig, ILStubLinker* pSL)
62
63
{
63
64
_ASSERTE (!pAsyncOtherVariant->IsAsyncThunkMethod ());
64
65
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
+
65
94
ILCodeStream* pCode = pSL->NewCodeStream (ILStubLinker::kDispatch );
66
95
67
96
unsigned continuationLocal = pCode->NewLocal (LocalDesc (CoreLibBinder::GetClass (CLASS__CONTINUATION)));
97
+ unsigned exceptionLocal = pCode->NewLocal (LocalDesc (CoreLibBinder::GetClass (CLASS__EXCEPTION)));
68
98
69
99
TypeHandle thTaskRet = thunkMsig.GetRetTypeHandleThrowing ();
70
100
@@ -84,7 +114,7 @@ void MethodDesc::EmitTaskReturningThunk(MethodDesc* pAsyncOtherVariant, MetaSig&
84
114
DWORD executionAndSyncBlockStoreLocal = pCode->NewLocal (executionAndSyncBlockStoreLocalDesc);
85
115
86
116
ILCodeLabel* returnTaskLabel = pCode->NewCodeLabel ();
87
- ILCodeLabel* suspendedLabel = pCode->NewCodeLabel ();
117
+ ILCodeLabel* finalizeTaskLabel = pCode->NewCodeLabel ();
88
118
ILCodeLabel* finishedLabel = pCode->NewCodeLabel ();
89
119
90
120
pCode->EmitLDLOCA (executionAndSyncBlockStoreLocal);
@@ -171,7 +201,7 @@ void MethodDesc::EmitTaskReturningThunk(MethodDesc* pAsyncOtherVariant, MetaSig&
171
201
pCode->EmitLDLOC (continuationLocal);
172
202
pCode->EmitBRFALSE (finishedLabel);
173
203
174
- pCode->EmitLEAVE (suspendedLabel );
204
+ pCode->EmitLEAVE (finalizeTaskLabel );
175
205
176
206
pCode->EmitLabel (finishedLabel);
177
207
if (logicalResultLocal != UINT_MAX)
@@ -202,37 +232,12 @@ void MethodDesc::EmitTaskReturningThunk(MethodDesc* pAsyncOtherVariant, MetaSig&
202
232
// Catch
203
233
{
204
234
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);
232
237
pCode->EndCatchBlock ();
233
238
}
234
239
235
- pCode->EmitLabel (suspendedLabel );
240
+ pCode->EmitLabel (finalizeTaskLabel );
236
241
237
242
int finalizeTaskReturningThunkToken;
238
243
if (logicalResultLocal != UINT_MAX)
@@ -255,8 +260,10 @@ void MethodDesc::EmitTaskReturningThunk(MethodDesc* pAsyncOtherVariant, MetaSig&
255
260
md = CoreLibBinder::GetMethod (METHOD__ASYNC_HELPERS__FINALIZE_TASK_RETURNING_THUNK);
256
261
finalizeTaskReturningThunkToken = pCode->GetToken (md);
257
262
}
263
+
258
264
pCode->EmitLDLOC (continuationLocal);
259
- pCode->EmitCALL (finalizeTaskReturningThunkToken, 1 , 1 );
265
+ pCode->EmitLDLOC (exceptionLocal);
266
+ pCode->EmitCALL (finalizeTaskReturningThunkToken, 2 , 1 );
260
267
pCode->EmitSTLOC (returnTaskLocal);
261
268
pCode->EmitLEAVE (returnTaskLabel);
262
269
@@ -447,15 +454,17 @@ int MethodDesc::GetTokenForGenericTypeMethodCallWithAsyncReturnType(ILCodeStream
447
454
return pCode->GetToken (md, typeSigToken);
448
455
}
449
456
457
+ // provided a Task-returning method, emits an async wrapper.
450
458
void MethodDesc::EmitAsyncMethodThunk (MethodDesc* pAsyncOtherVariant, MetaSig& msig, ILStubLinker* pSL)
451
459
{
452
460
_ASSERTE (!pAsyncOtherVariant->IsAsyncThunkMethod ());
453
461
_ASSERTE (!pAsyncOtherVariant->IsVoid ());
454
462
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:
459
468
/*
460
469
{
461
470
TaskAwaiter<RetType> awaiter = other(arg).GetAwaiter();
0 commit comments