Repository: dotnet/runtime
File: src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs (C#)

Code before:
            {
                ExecutionAndSyncBlockStore contexts = default;
                contexts.Push();

                AsyncDispatcherInfo asyncDispatcherInfo;
                asyncDispatcherInfo.Next = AsyncDispatcherInfo.t_current;
                asyncDispatcherInfo.NextContinuation = MoveContinuationState();
                asyncDispatcherInfo.CurrentTask = this;
                AsyncDispatcherInfo.t_current = &asyncDispatcherInfo;
                bool isTplEnabled = TplEventSource.Log.IsEnabled();

                if (isTplEnabled)
                {
                    TplEventSource.Log.TraceSynchronousWorkBegin(this.Id, CausalitySynchronousWork.Execution);
                }

                while (true)
                {
                    Debug.Assert(asyncDispatcherInfo.NextContinuation != null);
                    Continuation curContinuation = asyncDispatcherInfo.NextContinuation;
                    try
                    {
                        Continuation? nextContinuation = curContinuation.Next;
                        asyncDispatcherInfo.NextContinuation = nextContinuation;

                        ref byte resultLoc = ref nextContinuation != null ? ref nextContinuation.GetResultStorageOrNull() : ref GetResultStorage();
                        long timestamp = 0;
                        if (Task.s_asyncDebuggingEnabled)
                        {
                            timestamp = Task.GetRuntimeAsyncContinuationTimestamp(curContinuation, out long timestampVal) ? timestampVal : Stopwatch.GetTimestamp();
                            // we have dequeued curContinuation; update task tick info so that we can track its start time from a debugger
                            Task.UpdateRuntimeAsyncTaskTimestamp(this, timestamp);
                        }
                        Continuation? newContinuation = curContinuation.ResumeInfo->Resume(curContinuation, ref resultLoc);

                        if (Task.s_asyncDebuggingEnabled)
                        {
                            Task.RemoveRuntimeAsyncContinuationTimestamp(curContinuation);
                        }

                        if (newContinuation != null)
                        {
                            // we have a new Continuation that belongs to the same logical invocation as the previous; propagate debug info from previous continuation
                            if (Task.s_asyncDebuggingEnabled)
                            {
                                Task.SetRuntimeAsyncContinuationTimestamp(newContinuation, timestamp);
                            }
                            newContinuation.Next = nextContinuation;
                            HandleSuspended();
                            contexts.Pop();
                            AsyncDispatcherInfo.t_current = asyncDispatcherInfo.Next;

Review comment (bug):
What's the point of moving this out of the try block?

I think it would make more sense to move the `Debug.Assert` into the try block, and maybe change it to `Debug.Assert(curContinuation != null);`.

Code after:
            {
            }
#pragma warning restore CA1822

            [StackTraceHidden]
            private unsafe void DispatchContinuations()
            {
                ExecutionAndSyncBlockStore contexts = default;
                contexts.Push();

                AsyncDispatcherInfo asyncDispatcherInfo;
                asyncDispatcherInfo.Next = AsyncDispatcherInfo.t_current;
                asyncDispatcherInfo.NextContinuation = MoveContinuationState();
                asyncDispatcherInfo.CurrentTask = this;
                AsyncDispatcherInfo.t_current = &asyncDispatcherInfo;
                bool isTplEnabled = TplEventSource.Log.IsEnabled();

                if (isTplEnabled)
                {
                    TplEventSource.Log.TraceSynchronousWorkBegin(this.Id, CausalitySynchronousWork.Execution);
                }

                while (true)
                {
                    Debug.Assert(asyncDispatcherInfo.NextContinuation != null);
                    Continuation curContinuation = asyncDispatcherInfo.NextContinuation;
                    try
                    {
                        Continuation? nextContinuation = curContinuation.Next;
                        asyncDispatcherInfo.NextContinuation = nextContinuation;

                        ref byte resultLoc = ref nextContinuation != null ? ref nextContinuation.GetResultStorageOrNull() : ref GetResultStorage();
                        long timestamp = 0;
                        if (Task.s_asyncDebuggingEnabled)
                        {
                            timestamp = Task.GetRuntimeAsyncContinuationTimestamp(curContinuation, out long timestampVal) ? timestampVal : Stopwatch.GetTimestamp();
                            // we have dequeued curContinuation; update task tick info so that we can track its start time from a debugger
                            Task.UpdateRuntimeAsyncTaskTimestamp(this, timestamp);
                        }
                        Continuation? newContinuation = curContinuation.ResumeInfo->Resume(curContinuation, ref resultLoc);

                        if (Task.s_asyncDebuggingEnabled)
                        {
                            Task.RemoveRuntimeAsyncContinuationTimestamp(curContinuation);
                        }

                        if (newContinuation != null)
                        {
                            // we have a new Continuation that belongs to the same logical invocation as the previous; propagate debug info from previous continuation
                            if (Task.s_asyncDebuggingEnabled)
                            {