diff --git a/src/Common/src/CoreLib/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs b/src/Common/src/CoreLib/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs index 23da48eacbc4..ac9886a4e3a4 100644 --- a/src/Common/src/CoreLib/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs +++ b/src/Common/src/CoreLib/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs @@ -40,7 +40,12 @@ public static AsyncValueTaskMethodBuilder Create() => /// The state machine instance, passed by reference. [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine => + // will provide the right ExecutionContext semantics +#if netstandard + _methodBuilder.Start(ref stateMachine); +#else AsyncMethodBuilder.Start(ref stateMachine); // will provide the right ExecutionContext semantics +#endif /// Associates the builder with the specified state machine. /// The state machine instance to associate with the builder. diff --git a/src/System.Threading.Tasks.Extensions/ref/System.Threading.Tasks.Extensions.cs b/src/System.Threading.Tasks.Extensions/ref/System.Threading.Tasks.Extensions.cs index f5787932d27f..577fb2ed3c85 100644 --- a/src/System.Threading.Tasks.Extensions/ref/System.Threading.Tasks.Extensions.cs +++ b/src/System.Threading.Tasks.Extensions/ref/System.Threading.Tasks.Extensions.cs @@ -29,18 +29,18 @@ public readonly partial struct ConfiguredValueTaskAwaitable { private readonly object _dummy; public System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable.ConfiguredValueTaskAwaiter GetAwaiter() { throw null; } - public partial struct ConfiguredValueTaskAwaiter : System.Runtime.CompilerServices.ICriticalNotifyCompletion, System.Runtime.CompilerServices.INotifyCompletion + public readonly partial struct ConfiguredValueTaskAwaiter : System.Runtime.CompilerServices.ICriticalNotifyCompletion, System.Runtime.CompilerServices.INotifyCompletion { - private object _dummy; + private readonly object _dummy; public bool IsCompleted { get { throw null; } } public TResult GetResult() { throw null; } public void OnCompleted(System.Action continuation) { } public void UnsafeOnCompleted(System.Action continuation) { } } } - public partial struct ValueTaskAwaiter : System.Runtime.CompilerServices.ICriticalNotifyCompletion, System.Runtime.CompilerServices.INotifyCompletion + public readonly partial struct ValueTaskAwaiter : System.Runtime.CompilerServices.ICriticalNotifyCompletion, System.Runtime.CompilerServices.INotifyCompletion { - private object _dummy; + private readonly object _dummy; public bool IsCompleted { get { throw null; } } public TResult GetResult() { throw null; } public void OnCompleted(System.Action continuation) { } diff --git a/src/System.Threading.Tasks.Extensions/src/System.Threading.Tasks.Extensions.csproj b/src/System.Threading.Tasks.Extensions/src/System.Threading.Tasks.Extensions.csproj index 0bc93927d557..dc43433c90f3 100644 --- a/src/System.Threading.Tasks.Extensions/src/System.Threading.Tasks.Extensions.csproj +++ b/src/System.Threading.Tasks.Extensions/src/System.Threading.Tasks.Extensions.csproj @@ -6,6 +6,7 @@ $(OutputPath)$(MSBuildProjectName).xml netstandard1.0;portable-net45+win8+wp8+wpa81 true + $(DefineConstants);netstandard true 4.1.1.0 @@ -23,15 +24,30 @@ - - - - - + + + Common\CoreLib\System\Diagnostics\StackTraceHiddenAttribute.cs + + + Common\CoreLib\System\Runtime\CompilerServices\AsyncMethodBuilderAttribute.cs + + + Common\CoreLib\System\Runtime\CompilerServices\AsyncValueTaskMethodBuilder.cs + + + Common\CoreLib\System\Runtime\CompilerServices\ConfiguredValueTaskAwaitable.cs + + + Common\CoreLib\System\Runtime\CompilerServices\ValueTaskAwaiter.cs + + + Common\CoreLib\System\Threading\Tasks\ValueTask.cs + + - \ No newline at end of file + diff --git a/src/System.Threading.Tasks.Extensions/src/System/Runtime/CompilerServices/AsyncMethodBuilderAttribute.cs b/src/System.Threading.Tasks.Extensions/src/System/Runtime/CompilerServices/AsyncMethodBuilderAttribute.cs deleted file mode 100644 index 688a3a01ba72..000000000000 --- a/src/System.Threading.Tasks.Extensions/src/System/Runtime/CompilerServices/AsyncMethodBuilderAttribute.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace System.Runtime.CompilerServices -{ - /// - /// Indicates the type of the async method builder that should be used by a language compiler to - /// build the attributed type when used as the return type of an async method. - /// - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface | AttributeTargets.Delegate | AttributeTargets.Enum, Inherited = false, AllowMultiple = false)] - public sealed class AsyncMethodBuilderAttribute : Attribute - { - /// Initializes the . - /// The of the associated builder. - public AsyncMethodBuilderAttribute(Type builderType) => BuilderType = builderType; - - /// Gets the of the associated builder. - public Type BuilderType { get; } - } -} diff --git a/src/System.Threading.Tasks.Extensions/src/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs b/src/System.Threading.Tasks.Extensions/src/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs deleted file mode 100644 index 8cbcdc562fec..000000000000 --- a/src/System.Threading.Tasks.Extensions/src/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs +++ /dev/null @@ -1,102 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Runtime.InteropServices; -using System.Security; -using System.Threading.Tasks; - -namespace System.Runtime.CompilerServices -{ - /// Represents a builder for asynchronous methods that returns a . - /// The type of the result. - [StructLayout(LayoutKind.Auto)] - public struct AsyncValueTaskMethodBuilder - { - /// The to which most operations are delegated. - private AsyncTaskMethodBuilder _methodBuilder; - /// The result for this builder, if it's completed before any awaits occur. - private TResult _result; - /// true if contains the synchronous result for the async method; otherwise, false. - private bool _haveResult; - /// true if the builder should be used for setting/getting the result; otherwise, false. - private bool _useBuilder; - - /// Creates an instance of the struct. - /// The initialized instance. - public static AsyncValueTaskMethodBuilder Create() => - new AsyncValueTaskMethodBuilder() { _methodBuilder = AsyncTaskMethodBuilder.Create() }; - - /// Begins running the builder with the associated state machine. - /// The type of the state machine. - /// The state machine instance, passed by reference. - public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine => - _methodBuilder.Start(ref stateMachine); // will provide the right ExecutionContext semantics - - /// Associates the builder with the specified state machine. - /// The state machine instance to associate with the builder. - public void SetStateMachine(IAsyncStateMachine stateMachine) => _methodBuilder.SetStateMachine(stateMachine); - - /// Marks the task as successfully completed. - /// The result to use to complete the task. - public void SetResult(TResult result) - { - if (_useBuilder) - { - _methodBuilder.SetResult(result); - } - else - { - _result = result; - _haveResult = true; - } - } - - /// Marks the task as failed and binds the specified exception to the task. - /// The exception to bind to the task. - public void SetException(Exception exception) => _methodBuilder.SetException(exception); - - /// Gets the task for this builder. - public ValueTask Task - { - get - { - if (_haveResult) - { - return new ValueTask(_result); - } - else - { - _useBuilder = true; - return new ValueTask(_methodBuilder.Task); - } - } - } - - /// Schedules the state machine to proceed to the next action when the specified awaiter completes. - /// The type of the awaiter. - /// The type of the state machine. - /// the awaiter - /// The state machine. - public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) - where TAwaiter : INotifyCompletion - where TStateMachine : IAsyncStateMachine - { - _useBuilder = true; - _methodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine); - } - - /// Schedules the state machine to proceed to the next action when the specified awaiter completes. - /// The type of the awaiter. - /// The type of the state machine. - /// the awaiter - /// The state machine. - public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) - where TAwaiter : ICriticalNotifyCompletion - where TStateMachine : IAsyncStateMachine - { - _useBuilder = true; - _methodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine); - } - } -} diff --git a/src/System.Threading.Tasks.Extensions/src/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs b/src/System.Threading.Tasks.Extensions/src/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs deleted file mode 100644 index e0b92e5de185..000000000000 --- a/src/System.Threading.Tasks.Extensions/src/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs +++ /dev/null @@ -1,71 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Runtime.InteropServices; -using System.Threading.Tasks; - -namespace System.Runtime.CompilerServices -{ - /// Provides an awaitable type that enables configured awaits on a . - /// The type of the result produced. - [StructLayout(LayoutKind.Auto)] - public readonly struct ConfiguredValueTaskAwaitable - { - /// The wrapped . - private readonly ValueTask _value; - /// true to attempt to marshal the continuation back to the original context captured; otherwise, false. - private readonly bool _continueOnCapturedContext; - - /// Initializes the awaitable. - /// The wrapped . - /// - /// true to attempt to marshal the continuation back to the original synchronization context captured; otherwise, false. - /// - internal ConfiguredValueTaskAwaitable(ValueTask value, bool continueOnCapturedContext) - { - _value = value; - _continueOnCapturedContext = continueOnCapturedContext; - } - - /// Returns an awaiter for this instance. - public ConfiguredValueTaskAwaiter GetAwaiter() => - new ConfiguredValueTaskAwaiter(_value, _continueOnCapturedContext); - - /// Provides an awaiter for a . - [StructLayout(LayoutKind.Auto)] - public readonly struct ConfiguredValueTaskAwaiter : ICriticalNotifyCompletion - { - /// The value being awaited. - private readonly ValueTask _value; - /// The value to pass to ConfigureAwait. - private readonly bool _continueOnCapturedContext; - - /// Initializes the awaiter. - /// The value to be awaited. - /// The value to pass to ConfigureAwait. - internal ConfiguredValueTaskAwaiter(ValueTask value, bool continueOnCapturedContext) - { - _value = value; - _continueOnCapturedContext = continueOnCapturedContext; - } - - /// Gets whether the has completed. - public bool IsCompleted => _value.IsCompleted; - - /// Gets the result of the ValueTask. - public TResult GetResult() => - _value._task == null ? - _value._result : - _value._task.GetAwaiter().GetResult(); - - /// Schedules the continuation action for the . - public void OnCompleted(Action continuation) => - _value.AsTask().ConfigureAwait(_continueOnCapturedContext).GetAwaiter().OnCompleted(continuation); - - /// Schedules the continuation action for the . - public void UnsafeOnCompleted(Action continuation) => - _value.AsTask().ConfigureAwait(_continueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation); - } - } -} diff --git a/src/System.Threading.Tasks.Extensions/src/System/Runtime/CompilerServices/ValueTaskAwaiter.cs b/src/System.Threading.Tasks.Extensions/src/System/Runtime/CompilerServices/ValueTaskAwaiter.cs deleted file mode 100644 index 2774ba6ad354..000000000000 --- a/src/System.Threading.Tasks.Extensions/src/System/Runtime/CompilerServices/ValueTaskAwaiter.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Runtime.InteropServices; -using System.Threading.Tasks; - -namespace System.Runtime.CompilerServices -{ - /// Provides an awaiter for a . - public readonly struct ValueTaskAwaiter : ICriticalNotifyCompletion - { - /// The value being awaited. - private readonly ValueTask _value; - - /// Initializes the awaiter. - /// The value to be awaited. - internal ValueTaskAwaiter(ValueTask value) => _value = value; - - /// Gets whether the has completed. - public bool IsCompleted => _value.IsCompleted; - - /// Gets the result of the ValueTask. - public TResult GetResult() => - _value._task == null ? - _value._result : - _value._task.GetAwaiter().GetResult(); - - /// Schedules the continuation action for this ValueTask. - public void OnCompleted(Action continuation) => - _value.AsTask().ConfigureAwait(continueOnCapturedContext: true).GetAwaiter().OnCompleted(continuation); - - /// Schedules the continuation action for this ValueTask. - public void UnsafeOnCompleted(Action continuation) => - _value.AsTask().ConfigureAwait(continueOnCapturedContext: true).GetAwaiter().UnsafeOnCompleted(continuation); - } -} diff --git a/src/System.Threading.Tasks.Extensions/src/System/Threading/Tasks/ValueTask.cs b/src/System.Threading.Tasks.Extensions/src/System/Threading/Tasks/ValueTask.cs deleted file mode 100644 index f1f7227c1713..000000000000 --- a/src/System.Threading.Tasks.Extensions/src/System/Threading/Tasks/ValueTask.cs +++ /dev/null @@ -1,163 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// 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; - -namespace System.Threading.Tasks -{ - /// - /// Provides a value type that wraps a and a , - /// only one of which is used. - /// - /// The type of the result. - /// - /// - /// Methods may return an instance of this value type when it's likely that the result of their - /// operations will be available synchronously and when the method is expected to be invoked so - /// frequently that the cost of allocating a new for each call will - /// be prohibitive. - /// - /// - /// There are tradeoffs to using a instead of a . - /// For example, while a can help avoid an allocation in the case where the - /// successful result is available synchronously, it also contains two fields whereas a - /// as a reference type is a single field. This means that a method call ends up returning two fields worth of - /// data instead of one, which is more data to copy. It also means that if a method that returns one of these - /// is awaited within an async method, the state machine for that async method will be larger due to needing - /// to store the struct that's two fields instead of a single reference. - /// - /// - /// Further, for uses other than consuming the result of an asynchronous operation via await, - /// can lead to a more convoluted programming model, which can in turn actually - /// lead to more allocations. For example, consider a method that could return either a - /// with a cached task as a common result or a . If the consumer of the result - /// wants to use it as a , such as to use with in methods like Task.WhenAll and Task.WhenAny, - /// the would first need to be converted into a using - /// , which leads to an allocation that would have been avoided if a cached - /// had been used in the first place. - /// - /// - /// As such, the default choice for any asynchronous method should be to return a or - /// . Only if performance analysis proves it worthwhile should a - /// be used instead of . There is no non-generic version of - /// as the Task.CompletedTask property may be used to hand back a successfully completed singleton in the case where - /// a -returning method completes synchronously and successfully. - /// - /// - [AsyncMethodBuilder(typeof(AsyncValueTaskMethodBuilder<>))] - [StructLayout(LayoutKind.Auto)] - public readonly struct ValueTask : IEquatable> - { - /// The task to be used if the operation completed asynchronously or if it completed synchronously but non-successfully. - internal readonly Task _task; - /// The result to be used if the operation completed successfully synchronously. - internal readonly TResult _result; - - /// Initialize the with the result of the successful operation. - /// The result. - public ValueTask(TResult result) - { - _task = null; - _result = result; - } - - /// - /// Initialize the with a that represents the operation. - /// - /// The task. - public ValueTask(Task task) - { - _task = task ?? throw new ArgumentNullException(nameof(task)); - _result = default(TResult); - } - - /// Returns the hash code for this instance. - public override int GetHashCode() => - _task != null ? _task.GetHashCode() : - _result != null ? _result.GetHashCode() : - 0; - - /// Returns a value indicating whether this value is equal to a specified . - public override bool Equals(object obj) => - obj is ValueTask && - Equals((ValueTask)obj); - - /// Returns a value indicating whether this value is equal to a specified value. - public bool Equals(ValueTask other) => - _task != null || other._task != null ? - _task == other._task : - EqualityComparer.Default.Equals(_result, other._result); - - /// Returns a value indicating whether two values are equal. - public static bool operator==(ValueTask left, ValueTask right) => - left.Equals(right); - - /// Returns a value indicating whether two values are not equal. - public static bool operator!=(ValueTask left, ValueTask right) => - !left.Equals(right); - - /// - /// Gets a object to represent this ValueTask. It will - /// either return the wrapped task object if one exists, or it'll manufacture a new - /// task object to represent the result. - /// - 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 ?? Task.FromResult(_result); - - /// 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.Status == TaskStatus.RanToCompletion; - - /// Gets whether the represents a failed operation. - public bool IsFaulted => _task != null && _task.IsFaulted; - - /// Gets whether the represents a canceled operation. - public bool IsCanceled => _task != null && _task.IsCanceled; - - /// Gets the result. - public TResult Result => _task == null ? _result : _task.GetAwaiter().GetResult(); - - /// Gets an awaiter for this value. - public ValueTaskAwaiter GetAwaiter() => new ValueTaskAwaiter(this); - - /// Configures an awaiter for this value. - /// - /// true to attempt to marshal the continuation back to the captured context; otherwise, false. - /// - public ConfiguredValueTaskAwaitable ConfigureAwait(bool continueOnCapturedContext) => - new ConfiguredValueTaskAwaitable(this, continueOnCapturedContext: continueOnCapturedContext); - - /// Gets a string-representation of this . - public override string ToString() - { - if (_task != null) - { - return _task.Status == TaskStatus.RanToCompletion && _task.Result != null ? - _task.Result.ToString() : - string.Empty; - } - else - { - return _result != null ? - _result.ToString() : - string.Empty; - } - } - - // TODO: 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(); - } -} diff --git a/src/System.Threading.Tasks.Extensions/src/System/ThrowHelper.cs b/src/System.Threading.Tasks.Extensions/src/System/ThrowHelper.cs new file mode 100644 index 000000000000..0757c616bb01 --- /dev/null +++ b/src/System.Threading.Tasks.Extensions/src/System/ThrowHelper.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; +using System.Runtime.CompilerServices; + +namespace System +{ + internal static class ThrowHelper + { + internal static void ThrowArgumentNullException(ExceptionArgument argument) => + throw GetArgumentNullException(argument); + + private static ArgumentNullException GetArgumentNullException(ExceptionArgument argument) => + new ArgumentNullException(GetArgumentName(argument)); + + [MethodImpl(MethodImplOptions.NoInlining)] + private static string GetArgumentName(ExceptionArgument argument) + { + Debug.Assert(Enum.IsDefined(typeof(ExceptionArgument), argument), + $"The enum value is not defined, please check the {nameof(ExceptionArgument)} enum."); + + return argument.ToString(); + } + } + + internal enum ExceptionArgument + { + task + } +} diff --git a/src/System.Threading.Tasks.Extensions/tests/System.Threading.Tasks.Extensions.Tests.csproj b/src/System.Threading.Tasks.Extensions/tests/System.Threading.Tasks.Extensions.Tests.csproj index ab5b04af668f..9d8135bccc40 100644 --- a/src/System.Threading.Tasks.Extensions/tests/System.Threading.Tasks.Extensions.Tests.csproj +++ b/src/System.Threading.Tasks.Extensions/tests/System.Threading.Tasks.Extensions.Tests.csproj @@ -13,5 +13,8 @@ + + + \ No newline at end of file