@@ -78,11 +78,27 @@ internal enum ContinuationFlags
7878 ContinueOnCapturedTaskScheduler = 64 ,
7979 }
8080
81+ // Keep in sync with dataAsyncResumeInfo in the JIT
82+ internal unsafe struct ResumeInfo
83+ {
84+ public delegate * < Continuation , ref byte , Continuation ? > Resume ;
85+ // IP to use for diagnostics. Points into the jitted suspension code.
86+ // For debug codegen the IP resolves via an ASYNC native->IL mapping to
87+ // the IL AsyncHelpers.Await (or other async function) call which
88+ // caused the suspension.
89+ // For optimized codegen the mapping into the root method may be more
90+ // approximate (e.g. because of inlining).
91+ // For all codegens the offset of DiagnosticsIP matches
92+ // DiagnosticNativeOffset for the corresponding AsyncSuspensionPoint in
93+ // the debug info.
94+ public void * DiagnosticIP ;
95+ }
96+
8197#pragma warning disable CA1852 // "Type can be sealed" -- no it cannot because the runtime constructs subtypes dynamically
8298 internal unsafe class Continuation
8399 {
84100 public Continuation ? Next ;
85- public delegate * < Continuation , ref byte , Continuation ? > Resume ;
101+ public ResumeInfo * ResumeInfo ;
86102 public ContinuationFlags Flags ;
87103 public int State ;
88104
@@ -195,9 +211,8 @@ private interface IRuntimeAsyncTaskOps<T>
195211 static abstract ref byte GetResultStorage ( T task ) ;
196212 }
197213
198- /// <summary>
199- /// Represents a wrapped runtime async operation.
200- /// </summary>
214+ // Represents execution of a chain of suspended and resuming runtime
215+ // async functions.
201216 private sealed class RuntimeAsyncTask < T > : Task < T > , ITaskCompletionAction
202217 {
203218 public RuntimeAsyncTask ( )
@@ -261,9 +276,8 @@ public static void PostToSyncContext(RuntimeAsyncTask<T> task, SynchronizationCo
261276 }
262277 }
263278
264- /// <summary>
265- /// Represents a wrapped runtime async operation.
266- /// </summary>
279+ // Represents execution of a chain of suspended and resuming runtime
280+ // async functions.
267281 private sealed class RuntimeAsyncTask : Task , ITaskCompletionAction
268282 {
269283 public RuntimeAsyncTask ( )
@@ -329,35 +343,63 @@ public static void PostToSyncContext(RuntimeAsyncTask task, SynchronizationConte
329343
330344 private static class RuntimeAsyncTaskCore
331345 {
346+ [ StructLayout ( LayoutKind . Explicit ) ]
347+ private unsafe ref struct DispatcherInfo
348+ {
349+ // Dispatcher info for next dispatcher present on stack, or
350+ // null if none.
351+ [ FieldOffset ( 0 ) ]
352+ public DispatcherInfo * Next ;
353+
354+ // Next continuation the dispatcher will process.
355+ #if TARGET_64BIT
356+ [ FieldOffset ( 8 ) ]
357+ #else
358+ [ FieldOffset ( 4 ) ]
359+ #endif
360+ public Continuation ? NextContinuation ;
361+ }
362+
363+ // Information about current task dispatching, to be used for async
364+ // stackwalking.
365+ [ ThreadStatic ]
366+ private static unsafe DispatcherInfo * t_dispatcherInfo ;
367+
332368 public static unsafe void DispatchContinuations < T , TOps > ( T task ) where T : Task , ITaskCompletionAction where TOps : IRuntimeAsyncTaskOps < T >
333369 {
334370 ExecutionAndSyncBlockStore contexts = default ;
335371 contexts . Push ( ) ;
336- Continuation ? continuation = TOps . GetContinuationState ( task ) ;
372+
373+ DispatcherInfo dispatcherInfo ;
374+ dispatcherInfo . Next = t_dispatcherInfo ;
375+ dispatcherInfo . NextContinuation = TOps . GetContinuationState ( task ) ;
376+ t_dispatcherInfo = & dispatcherInfo ;
337377
338378 while ( true )
339379 {
340- Debug . Assert ( continuation != null ) ;
380+ Debug . Assert ( dispatcherInfo . NextContinuation != null ) ;
341381 try
342382 {
343- ref byte resultLoc = ref continuation . Next != null ? ref continuation . Next . GetResultStorageOrNull ( ) : ref TOps . GetResultStorage ( task ) ;
344- Continuation ? newContinuation = continuation . Resume ( continuation , ref resultLoc ) ;
383+ Continuation curContinuation = dispatcherInfo . NextContinuation ;
384+ Continuation ? nextContinuation = curContinuation . Next ;
385+ dispatcherInfo . NextContinuation = nextContinuation ;
386+
387+ ref byte resultLoc = ref nextContinuation != null ? ref nextContinuation . GetResultStorageOrNull ( ) : ref TOps . GetResultStorage ( task ) ;
388+ Continuation ? newContinuation = curContinuation . ResumeInfo ->Resume ( curContinuation , ref resultLoc ) ;
345389
346390 if ( newContinuation != null )
347391 {
348- newContinuation . Next = continuation . Next ;
392+ newContinuation . Next = nextContinuation ;
349393 HandleSuspended < T , TOps > ( task ) ;
350394 contexts . Pop ( ) ;
395+ t_dispatcherInfo = dispatcherInfo . Next ;
351396 return ;
352397 }
353-
354- continuation = continuation . Next ;
355398 }
356399 catch ( Exception ex )
357400 {
358- Debug . Assert ( continuation != null ) ;
359- Continuation ? nextContinuation = UnwindToPossibleHandler ( continuation ) ;
360- if ( nextContinuation == null )
401+ Continuation ? handlerContinuation = UnwindToPossibleHandler ( dispatcherInfo . NextContinuation ) ;
402+ if ( handlerContinuation == null )
361403 {
362404 // Tail of AsyncTaskMethodBuilderT.SetException
363405 bool successfullySet = ex is OperationCanceledException oce ?
@@ -366,6 +408,8 @@ public static unsafe void DispatchContinuations<T, TOps>(T task) where T : Task,
366408
367409 contexts . Pop ( ) ;
368410
411+ t_dispatcherInfo = dispatcherInfo . Next ;
412+
369413 if ( ! successfullySet )
370414 {
371415 ThrowHelper . ThrowInvalidOperationException ( ExceptionResource . TaskT_TransitionToFinal_AlreadyCompleted ) ;
@@ -374,17 +418,18 @@ public static unsafe void DispatchContinuations<T, TOps>(T task) where T : Task,
374418 return ;
375419 }
376420
377- nextContinuation . SetException ( ex ) ;
378-
379- continuation = nextContinuation ;
421+ handlerContinuation . SetException ( ex ) ;
422+ dispatcherInfo . NextContinuation = handlerContinuation ;
380423 }
381424
382- if ( continuation == null )
425+ if ( dispatcherInfo . NextContinuation == null )
383426 {
384427 bool successfullySet = TOps . SetCompleted ( task ) ;
385428
386429 contexts . Pop ( ) ;
387430
431+ t_dispatcherInfo = dispatcherInfo . Next ;
432+
388433 if ( ! successfullySet )
389434 {
390435 ThrowHelper . ThrowInvalidOperationException ( ExceptionResource . TaskT_TransitionToFinal_AlreadyCompleted ) ;
@@ -393,26 +438,23 @@ public static unsafe void DispatchContinuations<T, TOps>(T task) where T : Task,
393438 return ;
394439 }
395440
396- if ( QueueContinuationFollowUpActionIfNecessary < T , TOps > ( task , continuation ) )
441+ if ( QueueContinuationFollowUpActionIfNecessary < T , TOps > ( task , dispatcherInfo . NextContinuation ) )
397442 {
398443 contexts . Pop ( ) ;
444+ t_dispatcherInfo = dispatcherInfo . Next ;
399445 return ;
400446 }
401447 }
402448 }
403449
404- private static Continuation ? UnwindToPossibleHandler ( Continuation continuation )
450+ private static Continuation ? UnwindToPossibleHandler ( Continuation ? continuation )
405451 {
406452 while ( true )
407453 {
408- Continuation ? nextContinuation = continuation . Next ;
409- if ( nextContinuation == null )
410- return null ;
411-
412- if ( ( nextContinuation . Flags & ContinuationFlags . HasException ) != 0 )
413- return nextContinuation ;
454+ if ( continuation == null || ( continuation . Flags & ContinuationFlags . HasException ) != 0 )
455+ return continuation ;
414456
415- continuation = nextContinuation ;
457+ continuation = continuation . Next ;
416458 }
417459 }
418460
0 commit comments