File: src\runtime\src\coreclr\System.Private.CoreLib\src\System\Runtime\CompilerServices\AsyncProfiler.CoreCLR.cs
Web Access
Project: src\runtime\src\coreclr\nativeaot\System.Private.CoreLib\src\System.Private.CoreLib.csproj (System.Private.CoreLib)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Buffers;
using System.Diagnostics;
using System.Diagnostics.Tracing;
using System.Threading.Tasks;
using Serializer = System.Runtime.CompilerServices.AsyncProfiler.EventBuffer.Serializer;

namespace System.Runtime.CompilerServices
{
    internal static partial class AsyncProfiler
    {
        internal static partial class DispatcherIds
        {
            public static ulong GetDispatcherId(ref AsyncDispatcherInfo info)
            {
                if (info.CurrentTask != null)
                {
                    return (ulong)info.CurrentTask.Id;
                }
                return 0;
            }

            public static unsafe ulong CaptureParentDispatcherId()
            {
                AsyncDispatcherInfo* v2 = AsyncDispatcherInfo.t_current;
                AsyncStateMachineDispatcherInfo* v1 = AsyncStateMachineDispatcherInfo.t_current;

                Task? parent = null;
                if (v2 != null && (v1 == null || (void*)v2 < (void*)v1))
                {
                    parent = v2->CurrentTask;
                }
                else if (v1 != null)
                {
                    parent = v1->Dispatcher;
                }

                return parent != null ? (ulong)parent.Id : 0;
            }
        }

        internal static partial class CreateAsyncContext
        {
            public static void Create(Task dispatcher, Continuation nextContinuation)
            {
                Info info = default;
                AsyncThreadContext context = AsyncThreadContext.Acquire(ref info);

                SyncPoint.Check(context);

                EventKeywords eventKeywords = context.ActiveEventKeywords;
                if (IsEnabled.AnyAsyncEvents(eventKeywords))
                {
                    ulong parentDispatcherId = DispatcherIds.CaptureParentDispatcherId();
                    ulong dispatcherId = DispatcherIds.GetDispatcherId(dispatcher);
                    long currentTimestamp = Stopwatch.GetTimestamp();

                    if (IsEnabled.CreateRuntimeAsyncContextEvent(eventKeywords))
                    {
                        EmitEvent(context, currentTimestamp, parentDispatcherId, dispatcherId, AsyncEventID.CreateRuntimeAsyncContext);
                    }

                    if (IsEnabled.CreateRuntimeAsyncCallstackEvent(eventKeywords) && nextContinuation != null)
                    {
                        AsyncCallstack.EmitCreateEvent(context, currentTimestamp, parentDispatcherId, dispatcherId, nextContinuation);
                    }
                }

                AsyncThreadContext.Release(context);
            }
        }

        internal static partial class ResumeAsyncContext
        {
            public static void Resume(ref AsyncDispatcherInfo info)
            {
                AsyncThreadContext context = AsyncThreadContext.Acquire(ref info.AsyncProfilerInfo);

                Resume(ref info, context, DispatcherIds.GetDispatcherId(ref info), context.ActiveEventKeywords);

                AsyncThreadContext.Release(context);
            }

            public static void Resume(ref AsyncDispatcherInfo info, AsyncThreadContext context, ulong dispatcherId, EventKeywords activeEventKeywords)
            {
                if (SyncPoint.Check(context))
                {
                    return;
                }

                if (IsEnabled.AnyAsyncEvents(activeEventKeywords))
                {
                    long currentTimestamp = Stopwatch.GetTimestamp();
                    if (IsEnabled.ResumeRuntimeAsyncContextEvent(activeEventKeywords))
                    {
                        EmitEvent(context, currentTimestamp, dispatcherId, AsyncEventID.ResumeRuntimeAsyncContext);
                    }

                    if (IsEnabled.ResumeRuntimeAsyncCallstackEvent(activeEventKeywords))
                    {
                        byte wrapperIndex = (byte)(info.AsyncProfilerInfo.ContinuationIndex & ContinuationWrapper.COUNT_MASK);
                        if (info.AsyncProfilerInfo.CurrentContinuation != null)
                        {
                            Debug.Assert(info.AsyncProfilerInfo.CurrentContinuation is Continuation);
                            AsyncCallstack.EmitResumeEvent(context, currentTimestamp, dispatcherId, wrapperIndex, Unsafe.As<Continuation>(info.AsyncProfilerInfo.CurrentContinuation));
                        }
                        else
                        {
                            AsyncCallstack.EmitResumeEvent(context, currentTimestamp, dispatcherId, wrapperIndex, info.NextContinuation);
                        }
                    }
                }
            }
        }

        internal static partial class SuspendAsyncContext
        {
            public static void Suspend(ref AsyncDispatcherInfo info, Continuation nextContinuation)
            {
                AsyncThreadContext context = AsyncThreadContext.Acquire(ref info.AsyncProfilerInfo);

                SyncPoint.Check(context);

                EventKeywords activeEventKeywords = context.ActiveEventKeywords;
                if (IsEnabled.AnyAsyncEvents(activeEventKeywords))
                {
                    long currentTimestamp = Stopwatch.GetTimestamp();

                    if (IsEnabled.SuspendRuntimeAsyncCallstackEvent(activeEventKeywords) && nextContinuation != null)
                    {
                        AsyncCallstack.EmitSuspendEvent(context, currentTimestamp, DispatcherIds.GetDispatcherId(ref info), nextContinuation);
                    }

                    if (IsEnabled.SuspendRuntimeAsyncContextEvent(activeEventKeywords))
                    {
                        EmitEvent(context, currentTimestamp, AsyncEventID.SuspendRuntimeAsyncContext);
                    }
                }

                AsyncThreadContext.Release(context);
            }
        }

        internal static partial class CompleteAsyncContext
        {
            public static void Complete(ref AsyncDispatcherInfo info)
            {
                AsyncThreadContext context = AsyncThreadContext.Acquire(ref info.AsyncProfilerInfo);

                SyncPoint.Check(context);

                if (IsEnabled.CompleteRuntimeAsyncContextEvent(context.ActiveEventKeywords))
                {
                    EmitEvent(context, Stopwatch.GetTimestamp(), AsyncEventID.CompleteRuntimeAsyncContext);
                }

                AsyncThreadContext.Release(context);
            }
        }

        internal static partial class AsyncMethodException
        {
            public static void Unhandled(ref AsyncDispatcherInfo info, uint unwindedFrames)
            {
                AsyncThreadContext context = AsyncThreadContext.Acquire(ref info.AsyncProfilerInfo);

                EventKeywords activeEventKeywords = context.ActiveEventKeywords;
                if (IsEnabled.AnyAsyncEvents(activeEventKeywords))
                {
                    long currentTimestamp = Stopwatch.GetTimestamp();
                    if (IsEnabled.UnwindRuntimeAsyncExceptionEvent(activeEventKeywords))
                    {
                        EmitEvent(context, currentTimestamp, unwindedFrames, AsyncEventID.UnwindRuntimeAsyncException);
                    }

                    if (IsEnabled.CompleteRuntimeAsyncContextEvent(activeEventKeywords))
                    {
                        CompleteAsyncContext.EmitEvent(context, currentTimestamp, AsyncEventID.CompleteRuntimeAsyncContext);
                    }
                }

                AsyncThreadContext.Release(context);
            }

            public static void Handled(ref AsyncDispatcherInfo info, uint unwindedFrames)
            {
                AsyncThreadContext context = AsyncThreadContext.Acquire(ref info.AsyncProfilerInfo);

                if (IsEnabled.UnwindRuntimeAsyncExceptionEvent(context.ActiveEventKeywords))
                {
                    EmitEvent(context, Stopwatch.GetTimestamp(), unwindedFrames, AsyncEventID.UnwindRuntimeAsyncException);
                }

                AsyncThreadContext.Release(context);
            }
        }

        internal static partial class ResumeAsyncMethod
        {
            public static void Resume(ref AsyncDispatcherInfo info)
            {
                AsyncThreadContext context = AsyncThreadContext.Acquire(ref info.AsyncProfilerInfo);

                if (IsEnabled.ResumeRuntimeAsyncMethodEvent(context.ActiveEventKeywords))
                {
                    EmitEvent(context, AsyncEventID.ResumeRuntimeAsyncMethod);
                }

                AsyncThreadContext.Release(context);
            }
        }

        internal static partial class CompleteAsyncMethod
        {
            public static void Complete(ref AsyncDispatcherInfo info)
            {
                AsyncThreadContext context = AsyncThreadContext.Acquire(ref info.AsyncProfilerInfo);

                if (IsEnabled.CompleteRuntimeAsyncMethodEvent(context.ActiveEventKeywords))
                {
                    EmitEvent(context, AsyncEventID.CompleteRuntimeAsyncMethod);
                }

                AsyncThreadContext.Release(context);
            }
        }

        /// <summary>
        /// Provides a table of 32 functionally identical continuation wrapper methods, each with
        /// a unique native IP address. When resuming an async continuation, the profiler dispatches
        /// through the wrapper at index (ContinuationIndex &amp; COUNT_MASK), then increments the index.
        ///
        /// This creates a rotating pattern of unique return addresses on the native callstack. An OS
        /// CPU profiler (e.g., ETW, perf) captures these native IPs in its stack samples. A post-processing
        /// tool uses the wrapper name template and count (defined by the async profiler contract) to
        /// format method names, resolve them via symbol data (rundown events), and correlate
        /// native stack IPs with the async resume callstack events emitted at the same logical point.
        /// This bridges the gap between synchronous native stack samples and the asynchronous
        /// continuation chain.
        ///
        /// Every COUNT (32) continuations, a ResetAsyncContinuationWrapperIndex event is emitted
        /// so the tool knows the index has wrapped around and can correctly map subsequent samples.
        ///
        /// Each wrapper is marked [NoInlining] to guarantee a distinct native IP, and
        /// [AggressiveOptimization] to ensure stable JIT output (skip tiered compilation).
        /// </summary>
        [StackTraceHidden]
        internal static partial class ContinuationWrapper
        {
            /// <summary>
            /// Name template for the continuation wrapper methods, defined by contract.
            /// External tools format this template with the wrapper index (0..COUNT-1) to produce
            /// method names for identifying wrapper frames in stacks.
            /// Must match the actual method names below (e.g., Continuation_Wrapper_0, Continuation_Wrapper_1, ...).
            /// </summary>
            public const string NameTemplate = "Continuation_Wrapper_{0}";

            public static void InitInfo(ref Info info)
            {
                info.ContinuationTable = ref Unsafe.As<ContinuationWrapperTable, nint>(ref s_continuationWrappers);
                info.ContinuationIndex = 0;
            }

            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            public static Continuation? Dispatch(ref AsyncDispatcherInfo info, Continuation curContinuation, ref byte resultLoc)
            {
                nint dispatcher = Unsafe.Add(ref info.AsyncProfilerInfo.ContinuationTable, info.AsyncProfilerInfo.ContinuationIndex & COUNT_MASK);
                unsafe
                {
                    return ((delegate*<Continuation, ref byte, Continuation?>)(dispatcher))(curContinuation, ref resultLoc);
                }
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_0(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_1(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_2(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_3(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_4(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_5(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_6(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_7(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_8(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_9(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_10(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_11(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_12(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_13(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_14(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_15(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_16(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_17(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_18(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_19(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_20(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_21(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_22(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_23(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_24(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_25(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_26(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_27(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_28(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_29(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_30(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
            private static unsafe Continuation? Continuation_Wrapper_31(Continuation continuation, ref byte resultLoc)
            {
                return continuation.ResumeInfo->Resume(continuation, ref resultLoc);
            }

            private static unsafe ContinuationWrapperTable InitContinuationWrappers()
            {
                ContinuationWrapperTable wrappers = default;
                wrappers[0] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_0;
                wrappers[1] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_1;
                wrappers[2] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_2;
                wrappers[3] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_3;
                wrappers[4] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_4;
                wrappers[5] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_5;
                wrappers[6] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_6;
                wrappers[7] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_7;
                wrappers[8] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_8;
                wrappers[9] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_9;
                wrappers[10] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_10;
                wrappers[11] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_11;
                wrappers[12] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_12;
                wrappers[13] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_13;
                wrappers[14] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_14;
                wrappers[15] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_15;
                wrappers[16] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_16;
                wrappers[17] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_17;
                wrappers[18] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_18;
                wrappers[19] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_19;
                wrappers[20] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_20;
                wrappers[21] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_21;
                wrappers[22] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_22;
                wrappers[23] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_23;
                wrappers[24] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_24;
                wrappers[25] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_25;
                wrappers[26] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_26;
                wrappers[27] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_27;
                wrappers[28] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_28;
                wrappers[29] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_29;
                wrappers[30] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_30;
                wrappers[31] = (nint)(delegate*<Continuation, ref byte, Continuation?>)&Continuation_Wrapper_31;
                return wrappers;
            }

            [InlineArray(COUNT)]
            private struct ContinuationWrapperTable
            {
                private nint _element;
            }

            private static ContinuationWrapperTable s_continuationWrappers = InitContinuationWrappers();
        }

        internal static partial class SyncPoint
        {
            private static unsafe void ResumeAsyncCallstacks(AsyncThreadContext context)
            {
                // Replay suspended dispatchers in original execution (push) order. Both TLS chains
                // (V2 AsyncDispatcherInfo and V1 AsyncStateMachineDispatcherInfo) are linked head=most-recent,
                // so head has the smallest stack address (downward-growing stacks). The walker
                // recurses to Next BEFORE emitting, producing oldest-first emission, and merges the
                // two chains by always recursing on the smaller-address node first.
                AsyncDispatcherInfo* runtimeAsyncInfo = AsyncDispatcherInfo.t_current;
                AsyncStateMachineDispatcherInfo* stateMachineAsyncInfo = AsyncStateMachineDispatcherInfo.t_current;

                ResumeAsyncCallstacks(runtimeAsyncInfo, stateMachineAsyncInfo, context);
            }

            private static unsafe void ResumeAsyncCallstacks(AsyncDispatcherInfo* runtimeAsyncInfo, AsyncStateMachineDispatcherInfo* stateMachineAsyncInfo, AsyncThreadContext context)
            {
                if (runtimeAsyncInfo == null && stateMachineAsyncInfo == null)
                {
                    return;
                }

                if (stateMachineAsyncInfo == null || (runtimeAsyncInfo != null && (void*)runtimeAsyncInfo < (void*)stateMachineAsyncInfo))
                {
                    ResumeAsyncCallstacks(runtimeAsyncInfo->Next, stateMachineAsyncInfo, context);
                    ResumeAsyncContext.Resume(ref *runtimeAsyncInfo, context, DispatcherIds.GetDispatcherId(ref *runtimeAsyncInfo), Config.ActiveEventKeywords);
                }
                else
                {
                    ResumeAsyncCallstacks(runtimeAsyncInfo, stateMachineAsyncInfo->Next, context);
                    ResumeAsyncContext.Resume(ref *stateMachineAsyncInfo, context, DispatcherIds.GetDispatcherId(ref *stateMachineAsyncInfo), Config.ActiveEventKeywords);
                }
            }
        }

        private static partial class AsyncCallstack
        {
            private const int MaxRuntimeAsyncMethodFrameSize = Serializer.MaxCompressedUInt64Size;

            private ref struct CaptureRuntimeAsyncCallstackState : ICaptureAsyncCallstack
            {
                public Continuation? Continuation;
                public ulong LastNativeIP;
                public byte Count;

                public bool Capture(byte[] buffer, ref int index, out byte count)
                {
                    bool result = CaptureRuntimeAsyncCallstack(buffer, ref index, ref this);
                    count = Count;
                    return result;
                }

                public static int MaxAsyncMethodFrameSize => MaxRuntimeAsyncMethodFrameSize;
            }

            public static void EmitCreateEvent(AsyncThreadContext context, long currentTimestamp, ulong parentDispatcherId, ulong dispatcherId, Continuation? asyncCallstack)
            {
                CaptureRuntimeAsyncCallstackState state = default;
                state.Continuation = asyncCallstack;
                EmitAsyncCallstack(context, currentTimestamp, currentTimestamp - context.LastEventTimestamp, AsyncEventID.CreateRuntimeAsyncCallstack, parentDispatcherId, dispatcherId, 0, ref state);
            }

            public static void EmitSuspendEvent(AsyncThreadContext context, long currentTimestamp, ulong dispatcherId, Continuation? asyncCallstack)
            {
                CaptureRuntimeAsyncCallstackState state = default;
                state.Continuation = asyncCallstack;
                EmitAsyncCallstack(context, currentTimestamp, currentTimestamp - context.LastEventTimestamp, AsyncEventID.SuspendRuntimeAsyncCallstack, 0, dispatcherId, 0, ref state);
            }

            public static void EmitResumeEvent(AsyncThreadContext context, long currentTimestamp, ulong dispatcherId, byte continuationIndex, Continuation? asyncCallstack)
            {
                CaptureRuntimeAsyncCallstackState state = default;
                state.Continuation = asyncCallstack;
                EmitAsyncCallstack(context, currentTimestamp, currentTimestamp - context.LastEventTimestamp, AsyncEventID.ResumeRuntimeAsyncCallstack, 0, dispatcherId, continuationIndex, ref state);
            }

            private static bool CaptureRuntimeAsyncCallstack(byte[] buffer, ref int index, ref CaptureRuntimeAsyncCallstackState state)
            {
                if (index > buffer.Length)
                {
                    return false;
                }

                if (state.Continuation == null)
                {
                    return true;
                }

                int remainingFrames = (buffer.Length - index) / MaxRuntimeAsyncMethodFrameSize;
                if (remainingFrames == 0)
                {
                    return false;
                }

                byte maxAsyncCallstackFrames = (byte)Math.Min(byte.MaxValue, state.Count + remainingFrames);

                Span<byte> callstackSpan = buffer.AsSpan(index);

                ulong currentNativeIP = 0;
                ulong previousNativeIP = state.LastNativeIP;

                unsafe
                {
                    currentNativeIP = (ulong)state.Continuation.ResumeInfo->DiagnosticIP;
                }

                int callstackSpanIndex = 0;

                // First frame (Count == 0) is written as absolute; subsequent frames
                // (including the first frame of a continuation call after overflow)
                // are written as deltas from the previous frame.
                if (state.Count == 0)
                {
                    callstackSpanIndex += Serializer.WriteCompressedUInt64(callstackSpan.Slice(callstackSpanIndex, Serializer.MaxCompressedUInt64Size), currentNativeIP);
                }
                else
                {
                    callstackSpanIndex += Serializer.WriteCompressedInt64(callstackSpan.Slice(callstackSpanIndex, Serializer.MaxCompressedInt64Size), (long)(currentNativeIP - previousNativeIP));
                }

                state.Count++;

                state.Continuation = state.Continuation.Next;
                while (state.Count < maxAsyncCallstackFrames && state.Continuation != null)
                {
                    previousNativeIP = currentNativeIP;

                    unsafe
                    {
                        currentNativeIP = (ulong)state.Continuation.ResumeInfo->DiagnosticIP;
                    }

                    callstackSpanIndex += Serializer.WriteCompressedInt64(callstackSpan.Slice(callstackSpanIndex, Serializer.MaxCompressedInt64Size), (long)(currentNativeIP - previousNativeIP));

                    state.Count++;
                    state.Continuation = state.Continuation.Next;
                }

                state.LastNativeIP = currentNativeIP;
                index += callstackSpanIndex;

                return state.Continuation == null || state.Count == byte.MaxValue;
            }
        }
    }
}