summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs')
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs112
1 files changed, 63 insertions, 49 deletions
diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs b/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs
index afb0c22778..fc7a7f01a3 100644
--- a/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs
+++ b/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs
@@ -63,7 +63,7 @@ namespace System.Runtime.CompilerServices
// See comment on AsyncMethodBuilderCore.Start
// AsyncMethodBuilderCore.Start(ref stateMachine);
- if (stateMachine == null) throw new ArgumentNullException(nameof(stateMachine));
+ if (stateMachine == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.stateMachine);
Contract.EndContractBlock();
// Run the MoveNext method within a copy-on-write ExecutionContext scope.
@@ -72,7 +72,6 @@ namespace System.Runtime.CompilerServices
Thread currentThread = Thread.CurrentThread;
ExecutionContextSwitcher ecs = default(ExecutionContextSwitcher);
- RuntimeHelpers.PrepareConstrainedRegions();
try
{
ExecutionContext.EstablishCopyOnWriteScope(currentThread, ref ecs);
@@ -240,15 +239,8 @@ namespace System.Runtime.CompilerServices
}
}
- // This property lazily instantiates the Task in a non-thread-safe manner.
- private Task Task
- {
- get
- {
- if (m_task == null) m_task = new Task();
- return m_task;
- }
- }
+ /// <summary>Lazily instantiate the Task in a non-thread-safe manner.</summary>
+ private Task Task => m_task ?? (m_task = new Task());
/// <summary>
/// Gets an object that may be used to uniquely identify this builder to the debugger.
@@ -295,7 +287,7 @@ namespace System.Runtime.CompilerServices
// See comment on AsyncMethodBuilderCore.Start
// AsyncMethodBuilderCore.Start(ref stateMachine);
- if (stateMachine == null) throw new ArgumentNullException(nameof(stateMachine));
+ if (stateMachine == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.stateMachine);
Contract.EndContractBlock();
// Run the MoveNext method within a copy-on-write ExecutionContext scope.
@@ -304,7 +296,6 @@ namespace System.Runtime.CompilerServices
Thread currentThread = Thread.CurrentThread;
ExecutionContextSwitcher ecs = default(ExecutionContextSwitcher);
- RuntimeHelpers.PrepareConstrainedRegions();
try
{
ExecutionContext.EstablishCopyOnWriteScope(currentThread, ref ecs);
@@ -358,7 +349,11 @@ namespace System.Runtime.CompilerServices
/// <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; } }
+ public Task Task
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get { return m_builder.Task; }
+ }
/// <summary>
/// Completes the <see cref="System.Threading.Tasks.Task"/> in the
@@ -449,7 +444,7 @@ namespace System.Runtime.CompilerServices
// See comment on AsyncMethodBuilderCore.Start
// AsyncMethodBuilderCore.Start(ref stateMachine);
- if (stateMachine == null) throw new ArgumentNullException(nameof(stateMachine));
+ if (stateMachine == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.stateMachine);
Contract.EndContractBlock();
// Run the MoveNext method within a copy-on-write ExecutionContext scope.
@@ -458,7 +453,6 @@ namespace System.Runtime.CompilerServices
Thread currentThread = Thread.CurrentThread;
ExecutionContextSwitcher ecs = default(ExecutionContextSwitcher);
- RuntimeHelpers.PrepareConstrainedRegions();
try
{
ExecutionContext.EstablishCopyOnWriteScope(currentThread, ref ecs);
@@ -502,7 +496,7 @@ namespace System.Runtime.CompilerServices
{
// 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;
+ Task 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. NOTE: The language compiler may choose to use
@@ -542,7 +536,7 @@ namespace System.Runtime.CompilerServices
{
// 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;
+ Task<TResult> 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. NOTE: The language compiler may choose to use
@@ -563,15 +557,14 @@ namespace System.Runtime.CompilerServices
/// <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;
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get { return m_task ?? InitializeTask(); }
}
+ /// <summary>Initializes the task, which must not yet be initialized.</summary>
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private Task<TResult> InitializeTask() => (m_task = new Task<TResult>());
+
/// <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.
@@ -582,28 +575,49 @@ namespace System.Runtime.CompilerServices
{
// 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)
+ if (m_task == null)
{
m_task = GetTaskForResult(result);
Debug.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);
+ // Slow path: complete the existing task.
+ SetExistingTaskResult(result);
+ }
+ }
- //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);
- }
+ /// <summary>Completes the already initialized task with the specified result.</summary>
+ /// <param name="result">The result to use to complete the task.</param>
+ private void SetExistingTaskResult(TResult result)
+ {
+ Debug.Assert(m_task != null, "Expected non-null task");
- if (!task.TrySetResult(result))
- {
- throw new InvalidOperationException(Environment.GetResourceString("TaskT_TransitionToFinal_AlreadyCompleted"));
- }
+ if (AsyncCausalityTracer.LoggingOn || System.Threading.Tasks.Task.s_asyncDebuggingEnabled)
+ {
+ LogExistingTaskCompletion();
+ }
+
+ if (!m_task.TrySetResult(result))
+ {
+ ThrowHelper.ThrowInvalidOperationException(ExceptionResource.TaskT_TransitionToFinal_AlreadyCompleted);
+ }
+ }
+
+ /// <summary>Handles logging for the successful completion of an operation.</summary>
+ private void LogExistingTaskCompletion()
+ {
+ Debug.Assert(m_task != null);
+
+ if (AsyncCausalityTracer.LoggingOn)
+ {
+ AsyncCausalityTracer.TraceOperationCompletion(CausalityTraceLevel.Required, m_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(m_task.Id);
}
}
@@ -620,15 +634,14 @@ namespace System.Runtime.CompilerServices
// 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)
+ if (m_task == null)
{
m_task = completedTask;
}
else
{
// Otherwise, complete the task that's there.
- SetResult(default(TResult));
+ SetExistingTaskResult(default(TResult));
}
}
@@ -667,7 +680,7 @@ namespace System.Runtime.CompilerServices
if (!successfullySet)
{
- throw new InvalidOperationException(Environment.GetResourceString("TaskT_TransitionToFinal_AlreadyCompleted"));
+ ThrowHelper.ThrowInvalidOperationException(ExceptionResource.TaskT_TransitionToFinal_AlreadyCompleted);
}
}
@@ -704,6 +717,7 @@ namespace System.Runtime.CompilerServices
/// </summary>
/// <param name="result">The result for which we need a task.</param>
/// <returns>The completed task containing the result.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)] // method looks long, but for a given TResult it results in a relatively small amount of asm
private Task<TResult> GetTaskForResult(TResult result)
{
Contract.Ensures(
@@ -846,9 +860,9 @@ namespace System.Runtime.CompilerServices
/// <exception cref="System.InvalidOperationException">The builder is incorrectly initialized.</exception>
public void SetStateMachine(IAsyncStateMachine stateMachine)
{
- if (stateMachine == null) throw new ArgumentNullException(nameof(stateMachine));
+ if (stateMachine == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.stateMachine);
Contract.EndContractBlock();
- if (m_stateMachine != null) throw new InvalidOperationException(Environment.GetResourceString("AsyncMethodBuilder_InstanceNotInitialized"));
+ if (m_stateMachine != null) ThrowHelper.ThrowInvalidOperationException(ExceptionResource.AsyncMethodBuilder_InstanceNotInitialized);
m_stateMachine = stateMachine;
}
@@ -1104,12 +1118,12 @@ namespace System.Runtime.CompilerServices
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>
+ ///<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)
+ if (action != null)
{
var asWrapper = action.Target as ContinuationWrapper;
if (asWrapper != null)