// ==++==
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//
// AsyncMethodBuilder.cs
//
// <OWNER>Microsoft</OWNER>
//
// Compiler-targeted types that build tasks for use as the return types of asynchronous methods.
//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
using System.Runtime.ExceptionServices;
using System.Security;
using System.Security.Permissions;
using System.Threading;
using System.Threading.Tasks;

#if FEATURE_COMINTEROP
using System.Runtime.InteropServices.WindowsRuntime;
#endif // FEATURE_COMINTEROP

namespace System.Runtime.CompilerServices
{
    /// <summary>
    /// Provides a builder for asynchronous methods that return void.
    /// This type is intended for compiler use only.
    /// </summary>
    [HostProtection(Synchronization = true, ExternalThreading = true)]
    public struct AsyncVoidMethodBuilder
    {
        /// <summary>The synchronization context associated with this operation.</summary>
        private SynchronizationContext m_synchronizationContext;
        /// <summary>State related to the IAsyncStateMachine.</summary>
        private AsyncMethodBuilderCore m_coreState; // mutable struct: must not be readonly
        /// <summary>Task used for debugging and logging purposes only.  Lazily initialized.</summary>
        private Task m_task;

        /// <summary>Initializes a new <see cref="AsyncVoidMethodBuilder"/>.</summary>
        /// <returns>The initialized <see cref="AsyncVoidMethodBuilder"/>.</returns>
        public static AsyncVoidMethodBuilder Create()
        {
            // Capture the current sync context.  If there isn't one, use the dummy s_noContextCaptured
            // instance; this allows us to tell the state of no captured context apart from the state
            // of an improperly constructed builder instance.
            SynchronizationContext sc = SynchronizationContext.CurrentNoFlow;
            if (sc != null)
                sc.OperationStarted();
            return new AsyncVoidMethodBuilder() { m_synchronizationContext = sc };
        }

        /// <summary>Initiates the builder's execution with the associated state machine.</summary>
        /// <typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
        /// <param name="stateMachine">The state machine instance, passed by reference.</param>
        /// <exception cref="System.ArgumentNullException">The <paramref name="stateMachine"/> argument was null (Nothing in Visual Basic).</exception>
        [SecuritySafeCritical]
        [DebuggerStepThrough]
        public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
        {
            // See comment on AsyncMethodBuilderCore.Start
            // AsyncMethodBuilderCore.Start(ref stateMachine);

            if (stateMachine == null) throw new ArgumentNullException("stateMachine");
            Contract.EndContractBlock();

            // Run the MoveNext method within a copy-on-write ExecutionContext scope.
            // This allows us to undo any ExecutionContext changes made in MoveNext,
            // so that they won't "leak" out of the first await.

            ExecutionContextSwitcher ecs = default(ExecutionContextSwitcher);
            RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                ExecutionContext.EstablishCopyOnWriteScope(ref ecs);
                stateMachine.MoveNext();
            }
            finally
            {
                ecs.Undo();
            }
        }

        /// <summary>Associates the builder with the state machine it represents.</summary>
        /// <param name="stateMachine">The heap-allocated state machine object.</param>
        /// <exception cref="System.ArgumentNullException">The <paramref name="stateMachine"/> argument was null (Nothing in Visual Basic).</exception>
        /// <exception cref="System.InvalidOperationException">The builder is incorrectly initialized.</exception>
        public void SetStateMachine(IAsyncStateMachine stateMachine)
        {
            m_coreState.SetStateMachine(stateMachine); // argument validation handled by AsyncMethodBuilderCore
        }

        /// <summary>
        /// Schedules the specified state machine to be pushed forward when the specified awaiter completes.
        /// </summary>
        /// <typeparam name="TAwaiter">Specifies the type of the awaiter.</typeparam>
        /// <typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
        /// <param name="awaiter">The awaiter.</param>
        /// <param name="stateMachine">The state machine.</param>
        public void AwaitOnCompleted<TAwaiter, TStateMachine>(
            ref TAwaiter awaiter, ref TStateMachine stateMachine)
            where TAwaiter : INotifyCompletion
            where TStateMachine : IAsyncStateMachine
        {
            try
            {
                AsyncMethodBuilderCore.MoveNextRunner runnerToInitialize = null;
                var continuation = m_coreState.GetCompletionAction(AsyncCausalityTracer.LoggingOn ? this.Task : null, ref runnerToInitialize);
                Contract.Assert(continuation != null, "GetCompletionAction should always return a valid action.");

                // If this is our first await, such that we've not yet boxed the state machine, do so now.
                if (m_coreState.m_stateMachine == null)
                {
                    if (AsyncCausalityTracer.LoggingOn)
                        AsyncCausalityTracer.TraceOperationCreation(CausalityTraceLevel.Required, this.Task.Id, "Async: " + stateMachine.GetType().Name, 0);

                    // Box the state machine, then tell the boxed instance to call back into its own builder,
                    // so we can cache the boxed reference.
                    Contract.Assert(!Object.ReferenceEquals((object)stateMachine, (object)stateMachine), "Expected an unboxed state machine reference");
                    m_coreState.PostBoxInitialization(stateMachine, runnerToInitialize, null);
                }

                awaiter.OnCompleted(continuation);
            }
            catch (Exception exc)
            {
                // Prevent exceptions from leaking to the call site, which could
                // then allow multiple flows of execution through the same async method
                // if the awaiter had already scheduled the continuation by the time
                // the exception was thrown.  We propagate the exception on the
                // ThreadPool because we can trust it to not throw, unlike
                // if we were to go to a user-supplied SynchronizationContext,
                // whose Post method could easily throw.
                AsyncMethodBuilderCore.ThrowAsync(exc, targetContext: null);
            }
        }

        /// <summary>
        /// Schedules the specified state machine to be pushed forward when the specified awaiter completes.
        /// </summary>
        /// <typeparam name="TAwaiter">Specifies the type of the awaiter.</typeparam>
        /// <typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
        /// <param name="awaiter">The awaiter.</param>
        /// <param name="stateMachine">The state machine.</param>
        [SecuritySafeCritical]
        public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
            ref TAwaiter awaiter, ref TStateMachine stateMachine)
            where TAwaiter : ICriticalNotifyCompletion
            where TStateMachine : IAsyncStateMachine
        {
            try
            {
                AsyncMethodBuilderCore.MoveNextRunner runnerToInitialize = null;
                var continuation = m_coreState.GetCompletionAction(AsyncCausalityTracer.LoggingOn ? this.Task : null, ref runnerToInitialize);
                Contract.Assert(continuation != null, "GetCompletionAction should always return a valid action.");

                // If this is our first await, such that we've not yet boxed the state machine, do so now.
                if (m_coreState.m_stateMachine == null)
                {
                    if (AsyncCausalityTracer.LoggingOn)
                        AsyncCausalityTracer.TraceOperationCreation(CausalityTraceLevel.Required, this.Task.Id, "Async: " + stateMachine.GetType().Name, 0);

                    // Box the state machine, then tell the boxed instance to call back into its own builder,
                    // so we can cache the boxed reference.
                    Contract.Assert(!Object.ReferenceEquals((object)stateMachine, (object)stateMachine), "Expected an unboxed state machine reference");
                    m_coreState.PostBoxInitialization(stateMachine, runnerToInitialize, null);
                }

                awaiter.UnsafeOnCompleted(continuation);
            }
            catch (Exception e)
            {
                AsyncMethodBuilderCore.ThrowAsync(e, targetContext: null);
            }
        }

        /// <summary>Completes the method builder successfully.</summary>
        public void SetResult()
        {
            if (AsyncCausalityTracer.LoggingOn)
                AsyncCausalityTracer.TraceOperationCompletion(CausalityTraceLevel.Required, this.Task.Id, AsyncCausalityStatus.Completed);

            if (m_synchronizationContext != null)
            {
                NotifySynchronizationContextOfCompletion();
            }
        }

        /// <summary>Faults the method builder with an exception.</summary>
        /// <param name="exception">The exception that is the cause of this fault.</param>
        /// <exception cref="System.ArgumentNullException">The <paramref name="exception"/> argument is null (Nothing in Visual Basic).</exception>
        /// <exception cref="System.InvalidOperationException">The builder is not initialized.</exception>
        public void SetException(Exception exception)
        {
            if (exception == null) throw new ArgumentNullException("exception");
            Contract.EndContractBlock();

            if (AsyncCausalityTracer.LoggingOn)
                AsyncCausalityTracer.TraceOperationCompletion(CausalityTraceLevel.Required, this.Task.Id, AsyncCausalityStatus.Error);

            if (m_synchronizationContext != null)
            {
                // If we captured a synchronization context, Post the throwing of the exception to it 
                // and decrement its outstanding operation count.
                try
                {
                    AsyncMethodBuilderCore.ThrowAsync(exception, targetContext: m_synchronizationContext);
                }
                finally
                {
                    NotifySynchronizationContextOfCompletion();
                }
            }
            else
            {
                // Otherwise, queue the exception to be thrown on the ThreadPool.  This will
                // result in a crash unless legacy exception behavior is enabled by a config
                // file or a CLR host.
                AsyncMethodBuilderCore.ThrowAsync(exception, targetContext: null);
            }
        }

        /// <summary>Notifies the current synchronization context that the operation completed.</summary>
        private void NotifySynchronizationContextOfCompletion()
        {
            Contract.Assert(m_synchronizationContext != null, "Must only be used with a non-null context.");
            try
            {
                m_synchronizationContext.OperationCompleted();
            }
            catch (Exception exc)
            {
                // If the interaction with the SynchronizationContext goes awry,
                // fall back to propagating on the ThreadPool.
                AsyncMethodBuilderCore.ThrowAsync(exc, targetContext: null);
            }
        }

        // This property lazily instantiates the Task in a non-thread-safe manner.  
        internal Task Task 
        {
            get
            {
                if (m_task == null) m_task = new Task();
                return m_task;
            }
        }

        /// <summary>
        /// Gets an object that may be used to uniquely identify this builder to the debugger.
        /// </summary>
        /// <remarks>
        /// This property lazily instantiates the ID in a non-thread-safe manner.  
        /// It must only be used by the debugger and AsyncCausalityTracer in a single-threaded manner.
        /// </remarks>
        private object ObjectIdForDebugger { get { return this.Task; } }
    }

    /// <summary>
    /// Provides a builder for asynchronous methods that return <see cref="System.Threading.Tasks.Task"/>.
    /// This type is intended for compiler use only.
    /// </summary>
    /// <remarks>
    /// AsyncTaskMethodBuilder is a value type, and thus it is copied by value.
    /// Prior to being copied, one of its Task, SetResult, or SetException members must be accessed,
    /// or else the copies may end up building distinct Task instances.
    /// </remarks>
    [HostProtection(Synchronization = true, ExternalThreading = true)]
    public struct AsyncTaskMethodBuilder
    {
        /// <summary>A cached VoidTaskResult task used for builders that complete synchronously.</summary>
        private readonly static Task<VoidTaskResult> s_cachedCompleted = AsyncTaskMethodBuilder<VoidTaskResult>.s_defaultResultTask;

        /// <summary>The generic builder object to which this non-generic instance delegates.</summary>
        private AsyncTaskMethodBuilder<VoidTaskResult> m_builder; // mutable struct: must not be readonly

        /// <summary>Initializes a new <see cref="AsyncTaskMethodBuilder"/>.</summary>
        /// <returns>The initialized <see cref="AsyncTaskMethodBuilder"/>.</returns>
        public static AsyncTaskMethodBuilder Create()
        {
            return default(AsyncTaskMethodBuilder);
            // Note: If ATMB<T>.Create is modified to do any initialization, this
            //       method needs to be updated to do m_builder = ATMB<T>.Create().
        }

        /// <summary>Initiates the builder's execution with the associated state machine.</summary>
        /// <typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
        /// <param name="stateMachine">The state machine instance, passed by reference.</param>
        [SecuritySafeCritical]
        [DebuggerStepThrough]
        public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
        {
            // See comment on AsyncMethodBuilderCore.Start
            // AsyncMethodBuilderCore.Start(ref stateMachine);

            if (stateMachine == null) throw new ArgumentNullException("stateMachine");
            Contract.EndContractBlock();

            // Run the MoveNext method within a copy-on-write ExecutionContext scope.
            // This allows us to undo any ExecutionContext changes made in MoveNext,
            // so that they won't "leak" out of the first await.

            ExecutionContextSwitcher ecs = default(ExecutionContextSwitcher);
            RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                ExecutionContext.EstablishCopyOnWriteScope(ref ecs);
                stateMachine.MoveNext();
            }
            finally
            {
                ecs.Undo();
            }
        }

        /// <summary>Associates the builder with the state machine it represents.</summary>
        /// <param name="stateMachine">The heap-allocated state machine object.</param>
        /// <exception cref="System.ArgumentNullException">The <paramref name="stateMachine"/> argument was null (Nothing in Visual Basic).</exception>
        /// <exception cref="System.InvalidOperationException">The builder is incorrectly initialized.</exception>
        public void SetStateMachine(IAsyncStateMachine stateMachine)
        {
            m_builder.SetStateMachine(stateMachine); // argument validation handled by AsyncMethodBuilderCore
        }

        /// <summary>
        /// Schedules the specified state machine to be pushed forward when the specified awaiter completes.
        /// </summary>
        /// <typeparam name="TAwaiter">Specifies the type of the awaiter.</typeparam>
        /// <typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
        /// <param name="awaiter">The awaiter.</param>
        /// <param name="stateMachine">The state machine.</param>
        public void AwaitOnCompleted<TAwaiter, TStateMachine>(
            ref TAwaiter awaiter, ref TStateMachine stateMachine)
            where TAwaiter : INotifyCompletion
            where TStateMachine : IAsyncStateMachine
        {
            m_builder.AwaitOnCompleted<TAwaiter, TStateMachine>(ref awaiter, ref stateMachine);
        }

        /// <summary>
        /// Schedules the specified state machine to be pushed forward when the specified awaiter completes.
        /// </summary>
        /// <typeparam name="TAwaiter">Specifies the type of the awaiter.</typeparam>
        /// <typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
        /// <param name="awaiter">The awaiter.</param>
        /// <param name="stateMachine">The state machine.</param>
        public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
            ref TAwaiter awaiter, ref TStateMachine stateMachine)
            where TAwaiter : ICriticalNotifyCompletion
            where TStateMachine : IAsyncStateMachine
        {
            m_builder.AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref awaiter, ref stateMachine);
        }

        /// <summary>Gets the <see cref="System.Threading.Tasks.Task"/> for this builder.</summary>
        /// <returns>The <see cref="System.Threading.Tasks.Task"/> representing the builder's asynchronous operation.</returns>
        /// <exception cref="System.InvalidOperationException">The builder is not initialized.</exception>
        public Task Task { get { return m_builder.Task; } }

        /// <summary>
        /// Completes the <see cref="System.Threading.Tasks.Task"/> in the 
        /// <see cref="System.Threading.Tasks.TaskStatus">RanToCompletion</see> state.
        /// </summary>
        /// <exception cref="System.InvalidOperationException">The builder is not initialized.</exception>
        /// <exception cref="System.InvalidOperationException">The task has already completed.</exception>
        public void SetResult()
        {
            // Accessing AsyncTaskMethodBuilder.s_cachedCompleted is faster than
            // accessing AsyncTaskMethodBuilder<T>.s_defaultResultTask.
            m_builder.SetResult(s_cachedCompleted);
        }

        /// <summary>
        /// Completes the <see cref="System.Threading.Tasks.Task"/> in the 
        /// <see cref="System.Threading.Tasks.TaskStatus">Faulted</see> state with the specified exception.
        /// </summary>
        /// <param name="exception">The <see cref="System.Exception"/> to use to fault the task.</param>
        /// <exception cref="System.ArgumentNullException">The <paramref name="exception"/> argument is null (Nothing in Visual Basic).</exception>
        /// <exception cref="System.InvalidOperationException">The builder is not initialized.</exception>
        /// <exception cref="System.InvalidOperationException">The task has already completed.</exception>
        public void SetException(Exception exception) { m_builder.SetException(exception); }

        /// <summary>
        /// Called by the debugger to request notification when the first wait operation
        /// (await, Wait, Result, etc.) on this builder's task completes.
        /// </summary>
        /// <param name="enabled">
        /// true to enable notification; false to disable a previously set notification.
        /// </param>
        internal void SetNotificationForWaitCompletion(bool enabled)
        {
            m_builder.SetNotificationForWaitCompletion(enabled);
        }

        /// <summary>
        /// Gets an object that may be used to uniquely identify this builder to the debugger.
        /// </summary>
        /// <remarks>
        /// This property lazily instantiates the ID in a non-thread-safe manner.  
        /// It must only be used by the debugger and tracing pruposes, and only in a single-threaded manner
        /// when no other threads are in the middle of accessing this property or this.Task.
        /// </remarks>
        internal object ObjectIdForDebugger { get { return this.Task; } }
    }

    /// <summary>
    /// Provides a builder for asynchronous methods that return <see cref="System.Threading.Tasks.Task{TResult}"/>.
    /// This type is intended for compiler use only.
    /// </summary>
    /// <remarks>
    /// AsyncTaskMethodBuilder{TResult} is a value type, and thus it is copied by value.
    /// Prior to being copied, one of its Task, SetResult, or SetException members must be accessed,
    /// or else the copies may end up building distinct Task instances.
    /// </remarks>
    [HostProtection(Synchronization = true, ExternalThreading = true)]
    public struct AsyncTaskMethodBuilder<TResult>
    {
        /// <summary>A cached task for default(TResult).</summary>
        internal readonly static Task<TResult> s_defaultResultTask = AsyncTaskCache.CreateCacheableTask(default(TResult));

        // WARNING: For performance reasons, the m_task field is lazily initialized.
        //          For correct results, the struct AsyncTaskMethodBuilder<TResult> must 
        //          always be used from the same location/copy, at least until m_task is 
        //          initialized.  If that guarantee is broken, the field could end up being 
        //          initialized on the wrong copy.

        /// <summary>State related to the IAsyncStateMachine.</summary>
        private AsyncMethodBuilderCore m_coreState; // mutable struct: must not be readonly
        /// <summary>The lazily-initialized built task.</summary>
        private Task<TResult> m_task; // lazily-initialized: must not be readonly

        /// <summary>Initializes a new <see cref="AsyncTaskMethodBuilder"/>.</summary>
        /// <returns>The initialized <see cref="AsyncTaskMethodBuilder"/>.</returns>
        public static AsyncTaskMethodBuilder<TResult> Create()
        {
            return default(AsyncTaskMethodBuilder<TResult>);
            // NOTE:  If this method is ever updated to perform more initialization,
            //        ATMB.Create must also be updated to call this Create method.
        }

        /// <summary>Initiates the builder's execution with the associated state machine.</summary>
        /// <typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
        /// <param name="stateMachine">The state machine instance, passed by reference.</param>
        [SecuritySafeCritical]
        [DebuggerStepThrough]
        public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
        {
            // See comment on AsyncMethodBuilderCore.Start
            // AsyncMethodBuilderCore.Start(ref stateMachine);

            if (stateMachine == null) throw new ArgumentNullException("stateMachine");
            Contract.EndContractBlock();

            // Run the MoveNext method within a copy-on-write ExecutionContext scope.
            // This allows us to undo any ExecutionContext changes made in MoveNext,
            // so that they won't "leak" out of the first await.

            ExecutionContextSwitcher ecs = default(ExecutionContextSwitcher);
            RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                ExecutionContext.EstablishCopyOnWriteScope(ref ecs);
                stateMachine.MoveNext();
            }
            finally
            {
                ecs.Undo();
            }
        }

        /// <summary>Associates the builder with the state machine it represents.</summary>
        /// <param name="stateMachine">The heap-allocated state machine object.</param>
        /// <exception cref="System.ArgumentNullException">The <paramref name="stateMachine"/> argument was null (Nothing in Visual Basic).</exception>
        /// <exception cref="System.InvalidOperationException">The builder is incorrectly initialized.</exception>
        public void SetStateMachine(IAsyncStateMachine stateMachine)
        {
            m_coreState.SetStateMachine(stateMachine); // argument validation handled by AsyncMethodBuilderCore
        }

        /// <summary>
        /// Schedules the specified state machine to be pushed forward when the specified awaiter completes.
        /// </summary>
        /// <typeparam name="TAwaiter">Specifies the type of the awaiter.</typeparam>
        /// <typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
        /// <param name="awaiter">The awaiter.</param>
        /// <param name="stateMachine">The state machine.</param>
        public void AwaitOnCompleted<TAwaiter, TStateMachine>(
            ref TAwaiter awaiter, ref TStateMachine stateMachine)
            where TAwaiter : INotifyCompletion
            where TStateMachine : IAsyncStateMachine
        {
            try
            {
                AsyncMethodBuilderCore.MoveNextRunner runnerToInitialize = null;
                var continuation = m_coreState.GetCompletionAction(AsyncCausalityTracer.LoggingOn ? this.Task : null, ref runnerToInitialize);
                Contract.Assert(continuation != null, "GetCompletionAction should always return a valid action.");

                // If this is our first await, such that we've not yet boxed the state machine, do so now.
                if (m_coreState.m_stateMachine == null)
                {
                    // Force the Task to be initialized prior to the first suspending await so 
                    // that the original stack-based builder has a reference to the right Task.
                    var builtTask = this.Task;

                    // Box the state machine, then tell the boxed instance to call back into its own builder,
                    // so we can cache the boxed reference.
                    Contract.Assert(!Object.ReferenceEquals((object)stateMachine, (object)stateMachine), "Expected an unboxed state machine reference");
                    m_coreState.PostBoxInitialization(stateMachine, runnerToInitialize, builtTask);
                }

                awaiter.OnCompleted(continuation);
            }
            catch (Exception e)
            {
                AsyncMethodBuilderCore.ThrowAsync(e, targetContext: null);
            }
        }

        /// <summary>
        /// Schedules the specified state machine to be pushed forward when the specified awaiter completes.
        /// </summary>
        /// <typeparam name="TAwaiter">Specifies the type of the awaiter.</typeparam>
        /// <typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
        /// <param name="awaiter">The awaiter.</param>
        /// <param name="stateMachine">The state machine.</param>
        [SecuritySafeCritical]
        public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
            ref TAwaiter awaiter, ref TStateMachine stateMachine)
            where TAwaiter : ICriticalNotifyCompletion
            where TStateMachine : IAsyncStateMachine
        {
            try
            {
                AsyncMethodBuilderCore.MoveNextRunner runnerToInitialize = null;
                var continuation = m_coreState.GetCompletionAction(AsyncCausalityTracer.LoggingOn ? this.Task : null, ref runnerToInitialize);
                Contract.Assert(continuation != null, "GetCompletionAction should always return a valid action.");

                // If this is our first await, such that we've not yet boxed the state machine, do so now.
                if (m_coreState.m_stateMachine == null)
                {
                    // Force the Task to be initialized prior to the first suspending await so 
                    // that the original stack-based builder has a reference to the right Task.
                    var builtTask = this.Task;

                    // Box the state machine, then tell the boxed instance to call back into its own builder,
                    // so we can cache the boxed reference.
                    Contract.Assert(!Object.ReferenceEquals((object)stateMachine, (object)stateMachine), "Expected an unboxed state machine reference");
                    m_coreState.PostBoxInitialization(stateMachine, runnerToInitialize, builtTask);
                }

                awaiter.UnsafeOnCompleted(continuation);
            }
            catch (Exception e)
            {
                AsyncMethodBuilderCore.ThrowAsync(e, targetContext: null);
            }
        }

        /// <summary>Gets the <see cref="System.Threading.Tasks.Task{TResult}"/> for this builder.</summary>
        /// <returns>The <see cref="System.Threading.Tasks.Task{TResult}"/> representing the builder's asynchronous operation.</returns>
        public Task<TResult> Task
        {
            get
            {
                // Get and return the task. If there isn't one, first create one and store it.
                var task = m_task;
                if (task == null) { m_task = task = new Task<TResult>(); }
                return task;
            }
        }

        /// <summary>
        /// Completes the <see cref="System.Threading.Tasks.Task{TResult}"/> in the 
        /// <see cref="System.Threading.Tasks.TaskStatus">RanToCompletion</see> state with the specified result.
        /// </summary>
        /// <param name="result">The result to use to complete the task.</param>
        /// <exception cref="System.InvalidOperationException">The task has already completed.</exception>
        public void SetResult(TResult result)
        {
            // Get the currently stored task, which will be non-null if get_Task has already been accessed.
            // If there isn't one, get a task and store it.
            var task = m_task;
            if (task == null)
            {
                m_task = GetTaskForResult(result);
                Contract.Assert(m_task != null, "GetTaskForResult should never return null");
            }
            // Slow path: complete the existing task.
            else
            {
                if (AsyncCausalityTracer.LoggingOn)
                    AsyncCausalityTracer.TraceOperationCompletion(CausalityTraceLevel.Required, task.Id, AsyncCausalityStatus.Completed);

                //only log if we have a real task that was previously created
                if (System.Threading.Tasks.Task.s_asyncDebuggingEnabled)
                {
                    System.Threading.Tasks.Task.RemoveFromActiveTasks(task.Id);
                }

                if (!task.TrySetResult(result))
                {
                    throw new InvalidOperationException(Environment.GetResourceString("TaskT_TransitionToFinal_AlreadyCompleted"));
                }
            }
        }

        /// <summary>
        /// Completes the builder by using either the supplied completed task, or by completing
        /// the builder's previously accessed task using default(TResult).
        /// </summary>
        /// <param name="completedTask">A task already completed with the value default(TResult).</param>
        /// <exception cref="System.InvalidOperationException">The task has already completed.</exception>
        internal void SetResult(Task<TResult> completedTask)
        {
            Contract.Requires(completedTask != null, "Expected non-null task");
            Contract.Requires(completedTask.Status == TaskStatus.RanToCompletion, "Expected a successfully completed task");

            // Get the currently stored task, which will be non-null if get_Task has already been accessed.
            // If there isn't one, store the supplied completed task.
            var task = m_task;
            if (task == null)
            {
                m_task = completedTask;
            }
            else
            {
                // Otherwise, complete the task that's there.
                SetResult(default(TResult));
            }
        }

        /// <summary>
        /// Completes the <see cref="System.Threading.Tasks.Task{TResult}"/> in the 
        /// <see cref="System.Threading.Tasks.TaskStatus">Faulted</see> state with the specified exception.
        /// </summary>
        /// <param name="exception">The <see cref="System.Exception"/> to use to fault the task.</param>
        /// <exception cref="System.ArgumentNullException">The <paramref name="exception"/> argument is null (Nothing in Visual Basic).</exception>
        /// <exception cref="System.InvalidOperationException">The task has already completed.</exception>
        public void SetException(Exception exception)
        {
            if (exception == null) throw new ArgumentNullException("exception");
            Contract.EndContractBlock();


            var task = m_task;
            if (task == null)
            {
                // Get the task, forcing initialization if it hasn't already been initialized.
                task = this.Task;
            }

            // If the exception represents cancellation, cancel the task.  Otherwise, fault the task.
            var oce = exception as OperationCanceledException;
            bool successfullySet = oce != null ?
                task.TrySetCanceled(oce.CancellationToken, oce) :
                task.TrySetException(exception);

            // Unlike with TaskCompletionSource, we do not need to spin here until m_task is completed,
            // since AsyncTaskMethodBuilder.SetException should not be immediately followed by any code
            // that depends on the task having completely completed.  Moreover, with correct usage, 
            // SetResult or SetException should only be called once, so the Try* methods should always
            // return true, so no spinning would be necessary anyway (the spinning in TCS is only relevant
            // if another thread won the ---- to complete the task).

            if (!successfullySet)
            {
                throw new InvalidOperationException(Environment.GetResourceString("TaskT_TransitionToFinal_AlreadyCompleted"));
            }
        }

        /// <summary>
        /// Called by the debugger to request notification when the first wait operation
        /// (await, Wait, Result, etc.) on this builder's task completes.
        /// </summary>
        /// <param name="enabled">
        /// true to enable notification; false to disable a previously set notification.
        /// </param>
        /// <remarks>
        /// This should only be invoked from within an asynchronous method,
        /// and only by the debugger.
        /// </remarks>
        internal void SetNotificationForWaitCompletion(bool enabled)
        {
            // Get the task (forcing initialization if not already initialized), and set debug notification
            this.Task.SetNotificationForWaitCompletion(enabled);
        }

        /// <summary>
        /// Gets an object that may be used to uniquely identify this builder to the debugger.
        /// </summary>
        /// <remarks>
        /// This property lazily instantiates the ID in a non-thread-safe manner.  
        /// It must only be used by the debugger and tracing purposes, and only in a single-threaded manner
        /// when no other threads are in the middle of accessing this property or this.Task.
        /// </remarks>
        private object ObjectIdForDebugger { get { return this.Task; } }

        /// <summary>
        /// Gets a task for the specified result.  This will either
        /// be a cached or new task, never null.
        /// </summary>
        /// <param name="result">The result for which we need a task.</param>
        /// <returns>The completed task containing the result.</returns>
        [SecuritySafeCritical] // for JitHelpers.UnsafeCast
#if MONO
        internal static
#endif
        Task<TResult> GetTaskForResult(TResult result)
        {
            Contract.Ensures(
                EqualityComparer<TResult>.Default.Equals(result, Contract.Result<Task<TResult>>().Result),
                "The returned task's Result must return the same value as the specified result value.");

            // The goal of this function is to be give back a cached task if possible,
            // or to otherwise give back a new task.  To give back a cached task,
            // we need to be able to evaluate the incoming result value, and we need
            // to avoid as much overhead as possible when doing so, as this function
            // is invoked as part of the return path from every async method.
            // Most tasks won't be cached, and thus we need the checks for those that are 
            // to be as close to free as possible. This requires some trickiness given the 
            // lack of generic specialization in .NET.
            //
            // Be very careful when modifying this code.  It has been tuned
            // to comply with patterns recognized by both 32-bit and 64-bit JITs.
            // If changes are made here, be sure to look at the generated assembly, as
            // small tweaks can have big consequences for what does and doesn't get optimized away.
            //
            // Note that this code only ever accesses a static field when it knows it'll
            // find a cached value, since static fields (even if readonly and integral types) 
            // require special access helpers in this NGEN'd and domain-neutral.

            if (null != (object)default(TResult)) // help the JIT avoid the value type branches for ref types
            {
                // Special case simple value types:
                // - Boolean
                // - Byte, SByte
                // - Char
                // - Decimal
                // - Int32, UInt32
                // - Int64, UInt64
                // - Int16, UInt16
                // - IntPtr, UIntPtr
                // As of .NET 4.5, the (Type)(object)result pattern used below
                // is recognized and optimized by both 32-bit and 64-bit JITs.

                // For Boolean, we cache all possible values.
                if (typeof(TResult) == typeof(Boolean)) // only the relevant branches are kept for each value-type generic instantiation
                {
                    Boolean value = (Boolean)(object)result;
                    Task<Boolean> task = value ? AsyncTaskCache.TrueTask : AsyncTaskCache.FalseTask;
                    return JitHelpers.UnsafeCast<Task<TResult>>(task); // UnsafeCast avoids type check we know will succeed
                }
                // For Int32, we cache a range of common values, e.g. [-1,4).
                else if (typeof(TResult) == typeof(Int32))
                {
                    // Compare to constants to avoid static field access if outside of cached range.
                    // We compare to the upper bound first, as we're more likely to cache miss on the upper side than on the 
                    // lower side, due to positive values being more common than negative as return values.
                    Int32 value = (Int32)(object)result;
                    if (value < AsyncTaskCache.EXCLUSIVE_INT32_MAX &&
                        value >= AsyncTaskCache.INCLUSIVE_INT32_MIN)
                    {
                        Task<Int32> task = AsyncTaskCache.Int32Tasks[value - AsyncTaskCache.INCLUSIVE_INT32_MIN];
                        return JitHelpers.UnsafeCast<Task<TResult>>(task); // UnsafeCast avoids a type check we know will succeed
                    }
                }
                // For other known value types, we only special-case 0 / default(TResult).
                else if (
                    (typeof(TResult) == typeof(UInt32) && default(UInt32) == (UInt32)(object)result) ||
                    (typeof(TResult) == typeof(Byte) && default(Byte) == (Byte)(object)result) ||
                    (typeof(TResult) == typeof(SByte) && default(SByte) == (SByte)(object)result) ||
                    (typeof(TResult) == typeof(Char) && default(Char) == (Char)(object)result) ||
#if !MONO
                    (typeof(TResult) == typeof(Decimal) && default(Decimal) == (Decimal)(object)result) ||
#endif
                    (typeof(TResult) == typeof(Int64) && default(Int64) == (Int64)(object)result) ||
                    (typeof(TResult) == typeof(UInt64) && default(UInt64) == (UInt64)(object)result) ||
                    (typeof(TResult) == typeof(Int16) && default(Int16) == (Int16)(object)result) ||
                    (typeof(TResult) == typeof(UInt16) && default(UInt16) == (UInt16)(object)result) ||
                    (typeof(TResult) == typeof(IntPtr) && default(IntPtr) == (IntPtr)(object)result) ||
                    (typeof(TResult) == typeof(UIntPtr) && default(UIntPtr) == (UIntPtr)(object)result))
                {
                    return s_defaultResultTask;
                }
            }
            else if (result == null) // optimized away for value types
            {
                return s_defaultResultTask;
            }

            // No cached task is available.  Manufacture a new one for this result.
            return new Task<TResult>(result);
        }
    }

    /// <summary>Provides a cache of closed generic tasks for async methods.</summary>
    internal static class AsyncTaskCache
    {
        // All static members are initialized inline to ensure type is beforefieldinit

        /// <summary>A cached Task{Boolean}.Result == true.</summary>
        internal readonly static Task<Boolean> TrueTask = CreateCacheableTask(true);
        /// <summary>A cached Task{Boolean}.Result == false.</summary>
        internal readonly static Task<Boolean> FalseTask = CreateCacheableTask(false);

        /// <summary>The cache of Task{Int32}.</summary>
        internal readonly static Task<Int32>[] Int32Tasks = CreateInt32Tasks();
        /// <summary>The minimum value, inclusive, for which we want a cached task.</summary>
        internal const Int32 INCLUSIVE_INT32_MIN = -1;
        /// <summary>The maximum value, exclusive, for which we want a cached task.</summary>
        internal const Int32 EXCLUSIVE_INT32_MAX = 9;
        /// <summary>Creates an array of cached tasks for the values in the range [INCLUSIVE_MIN,EXCLUSIVE_MAX).</summary>
        private static Task<Int32>[] CreateInt32Tasks()
        {
            Contract.Assert(EXCLUSIVE_INT32_MAX >= INCLUSIVE_INT32_MIN, "Expected max to be at least min");
            var tasks = new Task<Int32>[EXCLUSIVE_INT32_MAX - INCLUSIVE_INT32_MIN];
            for (int i = 0; i < tasks.Length; i++)
            {
                tasks[i] = CreateCacheableTask(i + INCLUSIVE_INT32_MIN);
            }
            return tasks;
        }

        /// <summary>Creates a non-disposable task.</summary>
        /// <typeparam name="TResult">Specifies the result type.</typeparam>
        /// <param name="result">The result for the task.</param>
        /// <returns>The cacheable task.</returns>
        internal static Task<TResult> CreateCacheableTask<TResult>(TResult result)
        {
            return new Task<TResult>(false, result, (TaskCreationOptions)InternalTaskOptions.DoNotDispose, default(CancellationToken));
        }
    }

    /// <summary>Holds state related to the builder's IAsyncStateMachine.</summary>
    /// <remarks>This is a mutable struct.  Be very delicate with it.</remarks>
    internal struct AsyncMethodBuilderCore
    {
        /// <summary>A reference to the heap-allocated state machine object associated with this builder.</summary>
        internal IAsyncStateMachine m_stateMachine;
        /// <summary>A cached Action delegate used when dealing with a default ExecutionContext.</summary>
        internal Action m_defaultContextAction;

        // This method is copy&pasted into the public Start methods to avoid size overhead of valuetype generic instantiations.
        // Ideally, we would build intrinsics to get the raw ref address and raw code address of MoveNext, and just use the shared implementation.
        /// <summary>Initiates the builder's execution with the associated state machine.</summary>
        /// <typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
        /// <param name="stateMachine">The state machine instance, passed by reference.</param>
        /// <exception cref="System.ArgumentNullException">The <paramref name="stateMachine"/> argument is null (Nothing in Visual Basic).</exception>
        [SecuritySafeCritical]
        [DebuggerStepThrough]
        internal static void Start<TStateMachine>(ref TStateMachine stateMachine)
            where TStateMachine : IAsyncStateMachine
        {
            if (stateMachine == null) throw new ArgumentNullException("stateMachine");
            Contract.EndContractBlock();

            // Run the MoveNext method within a copy-on-write ExecutionContext scope.
            // This allows us to undo any ExecutionContext changes made in MoveNext,
            // so that they won't "leak" out of the first await.

            Thread currentThread = Thread.CurrentThread;
            ExecutionContextSwitcher ecs = default(ExecutionContextSwitcher);
            RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                ExecutionContext.EstablishCopyOnWriteScope(ref ecs);
                stateMachine.MoveNext();
            }
            finally
            {
                ecs.Undo();
            }
        }

        /// <summary>Associates the builder with the state machine it represents.</summary>
        /// <param name="stateMachine">The heap-allocated state machine object.</param>
        /// <exception cref="System.ArgumentNullException">The <paramref name="stateMachine"/> argument was null (Nothing in Visual Basic).</exception>
        /// <exception cref="System.InvalidOperationException">The builder is incorrectly initialized.</exception>
        public void SetStateMachine(IAsyncStateMachine stateMachine)
        {
            if (stateMachine == null) throw new ArgumentNullException("stateMachine");
            Contract.EndContractBlock();
            if (m_stateMachine != null) throw new InvalidOperationException(Environment.GetResourceString("AsyncMethodBuilder_InstanceNotInitialized"));
            m_stateMachine = stateMachine;
        }

        /// <summary>
        /// Gets the Action to use with an awaiter's OnCompleted or UnsafeOnCompleted method.
        /// On first invocation, the supplied state machine will be boxed.
        /// </summary>
        /// <typeparam name="TMethodBuilder">Specifies the type of the method builder used.</typeparam>
        /// <typeparam name="TStateMachine">Specifies the type of the state machine used.</typeparam>
        /// <param name="builder">The builder.</param>
        /// <param name="stateMachine">The state machine.</param>
        /// <returns>An Action to provide to the awaiter.</returns>
        [SecuritySafeCritical]
        internal Action GetCompletionAction(Task taskForTracing, ref MoveNextRunner runnerToInitialize)
        {
            Contract.Assert(m_defaultContextAction == null || m_stateMachine != null,
                "Expected non-null m_stateMachine on non-null m_defaultContextAction");

            // Alert a listening debugger that we can't make forward progress unless it slips threads.
            // If we don't do this, and a method that uses "await foo;" is invoked through funceval,
            // we could end up hooking up a callback to push forward the async method's state machine,
            // the debugger would then abort the funceval after it takes too long, and then continuing
            // execution could result in another callback being hooked up.  At that point we have
            // multiple callbacks registered to push the state machine, which could result in bad behavior.
            Debugger.NotifyOfCrossThreadDependency();

            // The builder needs to flow ExecutionContext, so capture it.
            var capturedContext = ExecutionContext.FastCapture(); // ok to use FastCapture as we haven't made any permission demands/asserts

            // If the ExecutionContext is the default context, try to use a cached delegate, creating one if necessary.
            Action action;
            MoveNextRunner runner;
            if (capturedContext != null && capturedContext.IsPreAllocatedDefault)
            {
                // Get the cached delegate, and if it's non-null, return it.
                action = m_defaultContextAction;
                if (action != null)
                {
                    Contract.Assert(m_stateMachine != null, "If the delegate was set, the state machine should have been as well.");
                    return action;
                }

                // There wasn't a cached delegate, so create one and cache it.
                // The delegate won't be usable until we set the MoveNextRunner's target state machine.
                runner = new MoveNextRunner(capturedContext, m_stateMachine);

                action = new Action(runner.Run);
                if (taskForTracing != null)
                {
                    m_defaultContextAction = action = OutputAsyncCausalityEvents(taskForTracing, action);
                }
                else
                {
                    m_defaultContextAction = action;
                }
            }
            // Otherwise, create an Action that flows this context.  The context may be null.
            // The delegate won't be usable until we set the MoveNextRunner's target state machine.
            else
            {
                runner = new MoveNextRunner(capturedContext, m_stateMachine);
                action = new Action(runner.Run);

                if (taskForTracing != null)
                {
                    action = OutputAsyncCausalityEvents(taskForTracing, action);
                }

                // NOTE: If capturedContext is null, we could create the Action to point directly
                // to m_stateMachine.MoveNext.  However, that follows a much more expensive
                // delegate creation path.
            }

            if (m_stateMachine == null)
                runnerToInitialize = runner;

            return action;
        }

        private Action OutputAsyncCausalityEvents(Task innerTask, Action continuation)
        {
            return CreateContinuationWrapper(continuation, () =>
            {
                AsyncCausalityTracer.TraceSynchronousWorkStart(CausalityTraceLevel.Required, innerTask.Id, CausalitySynchronousWork.Execution);

                // Invoke the original continuation
                continuation.Invoke();

                AsyncCausalityTracer.TraceSynchronousWorkCompletion(CausalityTraceLevel.Required, CausalitySynchronousWork.Execution);
            }, innerTask);
        }

        internal void PostBoxInitialization(IAsyncStateMachine stateMachine, MoveNextRunner runner, Task builtTask)
        {
            if (builtTask != null)
            {
                if (AsyncCausalityTracer.LoggingOn)
                    AsyncCausalityTracer.TraceOperationCreation(CausalityTraceLevel.Required, builtTask.Id, "Async: " + stateMachine.GetType().Name, 0);

                if (System.Threading.Tasks.Task.s_asyncDebuggingEnabled)
                    System.Threading.Tasks.Task.AddToActiveTasks(builtTask);
            }

            m_stateMachine = stateMachine;
            m_stateMachine.SetStateMachine(m_stateMachine);

            Contract.Assert(runner.m_stateMachine == null, "The runner's state machine should not yet have been populated.");
            Contract.Assert(m_stateMachine != null, "The builder's state machine field should have been initialized.");

            // Now that we have the state machine, store it into the runner that the action delegate points to.
            // And return the action.
            runner.m_stateMachine = m_stateMachine; // only after this line is the Action delegate usable
        }

        /// <summary>Throws the exception on the ThreadPool.</summary>
        /// <param name="exception">The exception to propagate.</param>
        /// <param name="targetContext">The target context on which to propagate the exception.  Null to use the ThreadPool.</param>
        internal static void ThrowAsync(Exception exception, SynchronizationContext targetContext)
        {
            // Capture the exception into an ExceptionDispatchInfo so that its 
            // stack trace and Watson bucket info will be preserved
            var edi = ExceptionDispatchInfo.Capture(exception);

            // If the user supplied a SynchronizationContext...
            if (targetContext != null)
            {
                try
                {
                    // Post the throwing of the exception to that context, and return.
                    targetContext.Post(state => ((ExceptionDispatchInfo)state).Throw(), edi);
                    return;
                }
                catch (Exception postException)
                {
                    // If something goes horribly wrong in the Post, we'll 
                    // propagate both exceptions on the ThreadPool
                    edi = ExceptionDispatchInfo.Capture(new AggregateException(exception, postException));
                }
            }

            // If we have the new error reporting APIs, report this error.  Otherwise, Propagate the exception(s) on the ThreadPool
#if FEATURE_COMINTEROP
            if (!WindowsRuntimeMarshal.ReportUnhandledError(edi.SourceException))
#endif // FEATURE_COMINTEROP
            {
                ThreadPool.QueueUserWorkItem(state => ((ExceptionDispatchInfo)state).Throw(), edi);
            }
        }

        /// <summary>Provides the ability to invoke a state machine's MoveNext method under a supplied ExecutionContext.</summary>
        internal sealed class MoveNextRunner
        {
            /// <summary>The context with which to run MoveNext.</summary>
            private readonly ExecutionContext m_context;
            /// <summary>The state machine whose MoveNext method should be invoked.</summary>
            internal IAsyncStateMachine m_stateMachine;

            /// <summary>Initializes the runner.</summary>
            /// <param name="context">The context with which to run MoveNext.</param>
            [SecurityCritical] // Run needs to be SSC to map to Action delegate, so to prevent misuse, we only allow construction through SC
            internal MoveNextRunner(ExecutionContext context, IAsyncStateMachine stateMachine)
            {
                m_context = context;
                m_stateMachine = stateMachine;
            }

            /// <summary>Invokes MoveNext under the provided context.</summary>
            [SecuritySafeCritical]
            internal void Run()
            {
                Contract.Assert(m_stateMachine != null, "The state machine must have been set before calling Run.");

                if (m_context != null)
                {
                    try
                    {
                        // Get the callback, lazily initializing it as necessary
                        ContextCallback callback = s_invokeMoveNext;
                        if (callback == null) { s_invokeMoveNext = callback = InvokeMoveNext; }

                        // Use the context and callback to invoke m_stateMachine.MoveNext.
                        ExecutionContext.Run(m_context, callback, m_stateMachine, preserveSyncCtx: true);
                    }
                    finally { m_context.Dispose(); }
                }
                else
                {
                    m_stateMachine.MoveNext();
                }
            }

            /// <summary>Cached delegate used with ExecutionContext.Run.</summary>
            [SecurityCritical]
            private static ContextCallback s_invokeMoveNext; // lazily-initialized due to SecurityCritical attribution

            /// <summary>Invokes the MoveNext method on the supplied IAsyncStateMachine.</summary>
            /// <param name="stateMachine">The IAsyncStateMachine machine instance.</param>
            [SecurityCritical] // necessary for ContextCallback in CoreCLR
            private static void InvokeMoveNext(object stateMachine)
            {
                ((IAsyncStateMachine)stateMachine).MoveNext();
            }
        }

        /// <summary>
        /// Logically we pass just an Action (delegate) to a task for its action to 'ContinueWith' when it completes.
        /// However debuggers and profilers need more information about what that action is. (In particular what 
        /// the action after that is and after that.   To solve this problem we create a 'ContinuationWrapper 
        /// which when invoked just does the original action (the invoke action), but also remembers other information
        /// (like the action after that (which is also a ContinuationWrapper and thus form a linked list).  
        //  We also store that task if the action is associate with at task.  
        /// </summary>
        private class ContinuationWrapper
        {
            internal readonly Action m_continuation;        // This is continuation which will happen after m_invokeAction  (and is probably a ContinuationWrapper)
            private readonly Action m_invokeAction;         // This wrapper is an action that wraps another action, this is that Action.  
            internal readonly Task m_innerTask;             // If the continuation is logically going to invoke a task, this is that task (may be null)

            internal ContinuationWrapper(Action continuation, Action invokeAction, Task innerTask)
            {
                Contract.Requires(continuation != null, "Expected non-null continuation");

                // If we don't have a task, see if our continuation is a wrapper and use that. 
                if (innerTask == null)
                    innerTask = TryGetContinuationTask(continuation);

                m_continuation = continuation;
                m_innerTask = innerTask;
                m_invokeAction = invokeAction;
            }

            internal void Invoke()
            {
                m_invokeAction();
            }
        }

        internal static Action CreateContinuationWrapper(Action continuation, Action invokeAction, Task innerTask = null)
        {
            return new ContinuationWrapper(continuation, invokeAction, innerTask).Invoke;
        }

        internal static Action TryGetStateMachineForDebugger(Action action)
        {
            object target = action.Target;
            var runner = target as AsyncMethodBuilderCore.MoveNextRunner;
            if (runner != null)
            {
                return new Action(runner.m_stateMachine.MoveNext);
            }

            var continuationWrapper = target as ContinuationWrapper;
            if (continuationWrapper != null)
            {
                return TryGetStateMachineForDebugger(continuationWrapper.m_continuation);
            }

            return action;
        }

    ///<summary>
    /// Given an action, see if it is a contiunation wrapper and has a Task associated with it.  If so return it (null otherwise)
    ///</summary>
        internal static Task TryGetContinuationTask(Action action)
        {
            if (action != null) 
            {
                var asWrapper = action.Target as ContinuationWrapper;
                if (asWrapper != null)
                    return asWrapper.m_innerTask;
            }
            return null;
        }
    }
}
