From f748d23a90d5563e7961a03863b40cb476c943f3 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Tue, 30 Jan 2018 10:12:52 -0500 Subject: [PATCH 1/4] Remove defunct CreateAsyncMethodBuilder from ValueTask --- .../shared/System/Threading/Tasks/ValueTask.cs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/mscorlib/shared/System/Threading/Tasks/ValueTask.cs b/src/mscorlib/shared/System/Threading/Tasks/ValueTask.cs index de9b016328cb..6b98a5f1007e 100644 --- a/src/mscorlib/shared/System/Threading/Tasks/ValueTask.cs +++ b/src/mscorlib/shared/System/Threading/Tasks/ValueTask.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.ComponentModel; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -77,7 +76,7 @@ public ValueTask(Task task) } _task = task; - _result = default(TResult); + _result = default; } /// Returns the hash code for this instance. @@ -166,13 +165,5 @@ public override string ToString() string.Empty; } } - - // TODO https://github.com/dotnet/corefx/issues/22171: - // Remove CreateAsyncMethodBuilder once the C# compiler relies on the AsyncBuilder attribute. - - /// Creates a method builder for use with an async method. - /// The created builder. - [EditorBrowsable(EditorBrowsableState.Never)] // intended only for compiler consumption - public static AsyncValueTaskMethodBuilder CreateAsyncMethodBuilder() => AsyncValueTaskMethodBuilder.Create(); } } From 1e961391acced7d2fc6fea91c97792a7a05427a0 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Tue, 30 Jan 2018 10:13:52 -0500 Subject: [PATCH 2/4] Make ValueTaskAwaiters readonly structs The _value field wasn't previously readonly, because method calls were made on the ValueTask, resulting in a copy. But now that ValueTask is a readonly struct, the field can be readonly, and these structs can then also be readonly. --- .../Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs | 4 ++-- .../System/Runtime/CompilerServices/ValueTaskAwaiter.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mscorlib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs b/src/mscorlib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs index 4e8ce691bece..e24ce6190574 100644 --- a/src/mscorlib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs +++ b/src/mscorlib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs @@ -35,10 +35,10 @@ public ConfiguredValueTaskAwaiter GetAwaiter() => /// Provides an awaiter for a . [StructLayout(LayoutKind.Auto)] - public struct ConfiguredValueTaskAwaiter : ICriticalNotifyCompletion, IConfiguredValueTaskAwaiter + public readonly struct ConfiguredValueTaskAwaiter : ICriticalNotifyCompletion, IConfiguredValueTaskAwaiter { /// The value being awaited. - private ValueTask _value; // Methods are called on this; avoid making it readonly so as to avoid unnecessary copies + private readonly ValueTask _value; /// The value to pass to ConfigureAwait. internal readonly bool _continueOnCapturedContext; diff --git a/src/mscorlib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs b/src/mscorlib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs index 7bc8b5cc7d34..3f212d8bf9b8 100644 --- a/src/mscorlib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs +++ b/src/mscorlib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs @@ -8,10 +8,10 @@ namespace System.Runtime.CompilerServices { /// Provides an awaiter for a . - public struct ValueTaskAwaiter : ICriticalNotifyCompletion, IValueTaskAwaiter + public readonly struct ValueTaskAwaiter : ICriticalNotifyCompletion, IValueTaskAwaiter { /// The value being awaited. - private ValueTask _value; // Methods are called on this; avoid making it readonly so as to avoid unnecessary copies + private readonly ValueTask _value; /// Initializes the awaiter. /// The value to be awaited. From eb234ae81903a592a51858c0214cbf9c9fe7ab4a Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Tue, 30 Jan 2018 10:14:58 -0500 Subject: [PATCH 3/4] Remove ValueTuple usage from ConfiguredValueTaskAwaitable It was superfluous and made sharing the code with corefx more challenging due to the netstandard1.0 build of System.Threading.Tasks.Extensions in corefx. --- .../CompilerServices/ConfiguredValueTaskAwaitable.cs | 8 ++++++-- .../System/Runtime/CompilerServices/AsyncMethodBuilder.cs | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/mscorlib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs b/src/mscorlib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs index e24ce6190574..f22b9d94bf65 100644 --- a/src/mscorlib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs +++ b/src/mscorlib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs @@ -74,7 +74,11 @@ public void UnsafeOnCompleted(Action continuation) => /// Gets the task underlying the incomplete . /// This method is used when awaiting and IsCompleted returned false; thus we expect the value task to be wrapping a non-null task. - (Task task, bool continueOnCapturedContext) IConfiguredValueTaskAwaiter.GetTask() => (_value.AsTaskExpectNonNull(), _continueOnCapturedContext); + Task IConfiguredValueTaskAwaiter.GetTask(out bool continueOnCapturedContext) + { + continueOnCapturedContext = _continueOnCapturedContext; + return _value.AsTaskExpectNonNull(); + } } } @@ -83,6 +87,6 @@ public void UnsafeOnCompleted(Action continuation) => /// internal interface IConfiguredValueTaskAwaiter { - (Task task, bool continueOnCapturedContext) GetTask(); + Task GetTask(out bool continueOnCapturedContext); } } diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs b/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs index 30734048c554..022f15ab1108 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs @@ -413,8 +413,8 @@ public void AwaitUnsafeOnCompleted( } else if ((null != (object)default(TAwaiter)) && (awaiter is IConfiguredValueTaskAwaiter)) { - (Task task, bool continueOnCapturedContext) t = ((IConfiguredValueTaskAwaiter)awaiter).GetTask(); - TaskAwaiter.UnsafeOnCompletedInternal(t.task, box, t.continueOnCapturedContext); + Task t = ((IConfiguredValueTaskAwaiter)awaiter).GetTask(out bool continueOnCapturedContext); + TaskAwaiter.UnsafeOnCompletedInternal(t, box, continueOnCapturedContext); } // The awaiter isn't specially known. Fall back to doing a normal await. else From de70b09f9a4409d33453a30207b71322f25ceebe Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Tue, 30 Jan 2018 14:28:35 -0500 Subject: [PATCH 4/4] Make ValueTask shareable with corefx --- .../System/Threading/Tasks/ValueTask.cs | 40 +++++++++++++------ 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/mscorlib/shared/System/Threading/Tasks/ValueTask.cs b/src/mscorlib/shared/System/Threading/Tasks/ValueTask.cs index 6b98a5f1007e..5edd8501b0c6 100644 --- a/src/mscorlib/shared/System/Threading/Tasks/ValueTask.cs +++ b/src/mscorlib/shared/System/Threading/Tasks/ValueTask.cs @@ -113,7 +113,12 @@ public Task AsTask() => // Return the task if we were constructed from one, otherwise manufacture one. We don't // cache the generated task into _task as it would end up changing both equality comparison // and the hash code we generate in GetHashCode. - _task ?? AsyncTaskMethodBuilder.GetTaskForResult(_result); + _task ?? +#if netstandard + Task.FromResult(_result); +#else + AsyncTaskMethodBuilder.GetTaskForResult(_result); +#endif internal Task AsTaskExpectNonNull() => // Return the task if we were constructed from one, otherwise manufacture one. @@ -122,13 +127,24 @@ internal Task AsTaskExpectNonNull() => _task ?? GetTaskForResultNoInlining(); [MethodImpl(MethodImplOptions.NoInlining)] - private Task GetTaskForResultNoInlining() => AsyncTaskMethodBuilder.GetTaskForResult(_result); + private Task GetTaskForResultNoInlining() => +#if netstandard + Task.FromResult(_result); +#else + AsyncTaskMethodBuilder.GetTaskForResult(_result); +#endif /// Gets whether the represents a completed operation. public bool IsCompleted => _task == null || _task.IsCompleted; /// Gets whether the represents a successfully completed operation. - public bool IsCompletedSuccessfully => _task == null || _task.IsCompletedSuccessfully; + public bool IsCompletedSuccessfully => + _task == null || +#if netstandard + _task.Status == TaskStatus.RanToCompletion; +#else + _task.IsCompletedSuccessfully; +#endif /// Gets whether the represents a failed operation. public bool IsFaulted => _task != null && _task.IsFaulted; @@ -152,18 +168,16 @@ public ConfiguredValueTaskAwaitable ConfigureAwait(bool continueOnCaptu /// Gets a string-representation of this . public override string ToString() { - if (_task != null) + if (IsCompletedSuccessfully) { - return _task.IsCompletedSuccessfully && _task.Result != null ? - _task.Result.ToString() : - string.Empty; - } - else - { - return _result != null ? - _result.ToString() : - string.Empty; + TResult result = Result; + if (result != null) + { + return result.ToString(); + } } + + return string.Empty; } } }