diff options
Diffstat (limited to 'netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices')
71 files changed, 0 insertions, 5475 deletions
diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AccessedThroughPropertyAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AccessedThroughPropertyAttribute.cs deleted file mode 100644 index 25efcafa3fd..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AccessedThroughPropertyAttribute.cs +++ /dev/null @@ -1,17 +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 -{ - [AttributeUsage(AttributeTargets.Field)] - public sealed class AccessedThroughPropertyAttribute : Attribute - { - public AccessedThroughPropertyAttribute(string propertyName) - { - PropertyName = propertyName; - } - - public string PropertyName { get; } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncIteratorMethodBuilder.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncIteratorMethodBuilder.cs deleted file mode 100644 index 4c4e2ebc05a..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncIteratorMethodBuilder.cs +++ /dev/null @@ -1,66 +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; - -namespace System.Runtime.CompilerServices -{ - /// <summary>Represents a builder for asynchronous iterators.</summary> - [StructLayout(LayoutKind.Auto)] - public struct AsyncIteratorMethodBuilder - { - // AsyncIteratorMethodBuilder is used by the language compiler as part of generating - // async iterators. For now, the implementation just wraps AsyncTaskMethodBuilder, as - // most of the logic is shared. However, in the future this could be changed and - // optimized. For example, we do need to allocate an object (once) to flow state like - // ExecutionContext, which AsyncTaskMethodBuilder handles, but it handles it by - // allocating a Task-derived object. We could optimize this further by removing - // the Task from the hierarchy, but in doing so we'd also lose a variety of optimizations - // related to it, so we'd need to replicate all of those optimizations (e.g. storing - // that box object directly into a Task's continuation field). - - private AsyncTaskMethodBuilder _methodBuilder; // mutable struct; do not make it readonly - - /// <summary>Creates an instance of the <see cref="AsyncIteratorMethodBuilder"/> struct.</summary> - /// <returns>The initialized instance.</returns> - public static AsyncIteratorMethodBuilder Create() => - // _methodBuilder should be initialized to AsyncTaskMethodBuilder.Create(), but on coreclr - // that Create() is a nop, so we can just return the default here. - default; - - /// <summary>Invokes <see cref="IAsyncStateMachine.MoveNext"/> on the state machine while guarding the <see cref="ExecutionContext"/>.</summary> - /// <typeparam name="TStateMachine">The type of the state machine.</typeparam> - /// <param name="stateMachine">The state machine instance, passed by reference.</param> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void MoveNext<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine => - AsyncMethodBuilderCore.Start(ref stateMachine); - - /// <summary>Schedules the state machine to proceed to the next action when the specified awaiter completes.</summary> - /// <typeparam name="TAwaiter">The type of the awaiter.</typeparam> - /// <typeparam name="TStateMachine">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 => - _methodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine); - - /// <summary>Schedules the state machine to proceed to the next action when the specified awaiter completes.</summary> - /// <typeparam name="TAwaiter">The type of the awaiter.</typeparam> - /// <typeparam name="TStateMachine">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 => - _methodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine); - - /// <summary>Marks iteration as being completed, whether successfully or otherwise.</summary> - public void Complete() => _methodBuilder.SetResult(); - - /// <summary>Gets an object that may be used to uniquely identify this builder to the debugger.</summary> - internal object ObjectIdForDebugger => _methodBuilder.ObjectIdForDebugger; - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncIteratorStateMachineAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncIteratorStateMachineAttribute.cs deleted file mode 100644 index 489195569de..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncIteratorStateMachineAttribute.cs +++ /dev/null @@ -1,18 +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 -{ - /// <summary>Indicates whether a method is an asynchronous iterator.</summary> - [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)] - public sealed class AsyncIteratorStateMachineAttribute : StateMachineAttribute - { - /// <summary>Initializes a new instance of the <see cref="AsyncIteratorStateMachineAttribute"/> class.</summary> - /// <param name="stateMachineType">The type object for the underlying state machine type that's used to implement a state machine method.</param> - public AsyncIteratorStateMachineAttribute(Type stateMachineType) - : base(stateMachineType) - { - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncMethodBuilderAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncMethodBuilderAttribute.cs deleted file mode 100644 index 688a3a01ba7..00000000000 --- a/netcore/System.Private.CoreLib/shared/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 -{ - /// <summary> - /// 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. - /// </summary> - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface | AttributeTargets.Delegate | AttributeTargets.Enum, Inherited = false, AllowMultiple = false)] - public sealed class AsyncMethodBuilderAttribute : Attribute - { - /// <summary>Initializes the <see cref="AsyncMethodBuilderAttribute"/>.</summary> - /// <param name="builderType">The <see cref="Type"/> of the associated builder.</param> - public AsyncMethodBuilderAttribute(Type builderType) => BuilderType = builderType; - - /// <summary>Gets the <see cref="Type"/> of the associated builder.</summary> - public Type BuilderType { get; } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncMethodBuilderCore.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncMethodBuilderCore.cs deleted file mode 100644 index f8aad2f0178..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncMethodBuilderCore.cs +++ /dev/null @@ -1,158 +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.Diagnostics; -using System.Diagnostics.Tracing; -using System.Reflection; -using System.Threading; -using System.Threading.Tasks; -using System.Text; - -namespace System.Runtime.CompilerServices -{ - /// <summary>Shared helpers for manipulating state related to async state machines.</summary> - internal static class AsyncMethodBuilderCore // debugger depends on this exact name - { - /// <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> - [DebuggerStepThrough] - public static void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine - { - if (stateMachine == null) // TStateMachines are generally non-nullable value types, so this check will be elided - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.stateMachine); - } - - // enregistrer variables with 0 post-fix so they can be used in registers without EH forcing them to stack - // Capture references to Thread Contexts - Thread currentThread0 = Thread.CurrentThread; - Thread currentThread = currentThread0; - ExecutionContext? previousExecutionCtx0 = currentThread0._executionContext; - - // Store current ExecutionContext and SynchronizationContext as "previousXxx". - // This allows us to restore them and undo any Context changes made in stateMachine.MoveNext - // so that they won't "leak" out of the first await. - ExecutionContext? previousExecutionCtx = previousExecutionCtx0; - SynchronizationContext? previousSyncCtx = currentThread0._synchronizationContext; - - try - { - stateMachine.MoveNext(); - } - finally - { - // Re-enregistrer variables post EH with 1 post-fix so they can be used in registers rather than from stack - SynchronizationContext? previousSyncCtx1 = previousSyncCtx; - Thread currentThread1 = currentThread; - // The common case is that these have not changed, so avoid the cost of a write barrier if not needed. - if (previousSyncCtx1 != currentThread1._synchronizationContext) - { - // Restore changed SynchronizationContext back to previous - currentThread1._synchronizationContext = previousSyncCtx1; - } - - ExecutionContext? previousExecutionCtx1 = previousExecutionCtx; - ExecutionContext? currentExecutionCtx1 = currentThread1._executionContext; - if (previousExecutionCtx1 != currentExecutionCtx1) - { - ExecutionContext.RestoreChangedContextToThread(currentThread1, previousExecutionCtx1, currentExecutionCtx1); - } - } - } - - public static void SetStateMachine(IAsyncStateMachine stateMachine, Task? task) - { - if (stateMachine == null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.stateMachine); - } - - if (task != null) - { - ThrowHelper.ThrowInvalidOperationException(ExceptionResource.AsyncMethodBuilder_InstanceNotInitialized); - } - - // SetStateMachine was originally needed in order to store the boxed state machine reference into - // the boxed copy. Now that a normal box is no longer used, SetStateMachine is also legacy. We need not - // do anything here, and thus assert to ensure we're not calling this from our own implementations. - Debug.Fail("SetStateMachine should not be used."); - } - -#if !CORERT - /// <summary>Gets whether we should be tracking async method completions for eventing.</summary> - internal static bool TrackAsyncMethodCompletion - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => TplEventSource.Log.IsEnabled(EventLevel.Warning, TplEventSource.Keywords.AsyncMethod); - } -#endif - - /// <summary>Gets a description of the state of the state machine object, suitable for debug purposes.</summary> - /// <param name="stateMachine">The state machine object.</param> - /// <returns>A description of the state machine.</returns> - internal static string GetAsyncStateMachineDescription(IAsyncStateMachine stateMachine) - { - Debug.Assert(stateMachine != null); - - Type stateMachineType = stateMachine.GetType(); - FieldInfo[] fields = stateMachineType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); - - var sb = new StringBuilder(); - sb.AppendLine(stateMachineType.FullName); - foreach (FieldInfo fi in fields) - { - sb.Append(" ").Append(fi.Name).Append(": ").Append(fi.GetValue(stateMachine)).AppendLine(); - } - return sb.ToString(); - } - - internal static Action CreateContinuationWrapper(Action continuation, Action<Action, Task> invokeAction, Task innerTask) => - new ContinuationWrapper(continuation, invokeAction, innerTask).Invoke; - - /// <summary>This helper routine is targeted by the debugger. Its purpose is to remove any delegate wrappers introduced by - /// the framework that the debugger doesn't want to see.</summary> - internal static Action TryGetStateMachineForDebugger(Action action) // debugger depends on this exact name/signature - { - object? target = action.Target; - return - target is IAsyncStateMachineBox sm ? sm.GetStateMachineObject().MoveNext : - target is ContinuationWrapper cw ? TryGetStateMachineForDebugger(cw._continuation) : - action; - } - - internal static Task? TryGetContinuationTask(Action continuation) => - (continuation.Target is ContinuationWrapper wrapper) ? - wrapper._innerTask : // A wrapped continuation, created by an awaiter - continuation.Target as Task; // The continuation targets a task directly, such as with AsyncStateMachineBox - - /// <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 sealed class ContinuationWrapper // SOS DumpAsync command depends on this name - { - private readonly Action<Action, Task> _invokeAction; // This wrapper is an action that wraps another action, this is that Action. - internal readonly Action _continuation; // This is continuation which will happen after m_invokeAction (and is probably a ContinuationWrapper). SOS DumpAsync command depends on this name. - internal readonly Task _innerTask; // If the continuation is logically going to invoke a task, this is that task (may be null) - - internal ContinuationWrapper(Action continuation, Action<Action, Task> invokeAction, Task innerTask) - { - Debug.Assert(continuation != null, "Expected non-null continuation"); - Debug.Assert(invokeAction != null, "Expected non-null invokeAction"); - Debug.Assert(innerTask != null, "Expected non-null innerTask"); - - _invokeAction = invokeAction; - _continuation = continuation; - _innerTask = innerTask; - } - - internal void Invoke() => _invokeAction(_continuation, _innerTask); - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncStateMachineAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncStateMachineAttribute.cs deleted file mode 100644 index 66c9175ee75..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncStateMachineAttribute.cs +++ /dev/null @@ -1,15 +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 -{ - [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)] - public sealed class AsyncStateMachineAttribute : StateMachineAttribute - { - public AsyncStateMachineAttribute(Type stateMachineType) - : base(stateMachineType) - { - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncTaskCache.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncTaskCache.cs deleted file mode 100644 index 3f164a02c43..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncTaskCache.cs +++ /dev/null @@ -1,66 +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.Diagnostics; -using System.Threading.Tasks; -using System.Diagnostics.CodeAnalysis; - -namespace System.Runtime.CompilerServices -{ - /// <summary>Provides a cache of closed generic tasks for async methods.</summary> - internal static class AsyncTaskCache - { - /// <summary>A cached Task{Boolean}.Result == true.</summary> - internal static readonly Task<bool> s_trueTask = CreateCacheableTask(result: true); - /// <summary>A cached Task{Boolean}.Result == false.</summary> - internal static readonly Task<bool> s_falseTask = CreateCacheableTask(result: false); - /// <summary>The cache of Task{Int32}.</summary> - internal static readonly Task<int>[] s_int32Tasks = CreateInt32Tasks(); - /// <summary>The minimum value, inclusive, for which we want a cached task.</summary> - internal const int InclusiveInt32Min = -1; - /// <summary>The maximum value, exclusive, for which we want a cached task.</summary> - internal const int ExclusiveInt32Max = 9; - - /// <summary>true if we should use reusable boxes for async completions of ValueTask methods; false if we should use tasks.</summary> - /// <remarks> - /// We rely on tiered compilation turning this into a const and doing dead code elimination to make checks on this efficient. - /// It's also required for safety that this value never changes once observed, as Unsafe.As casts are employed based on its value. - /// </remarks> - internal static readonly bool s_valueTaskPoolingEnabled = GetPoolAsyncValueTasksSwitch(); - /// <summary>Maximum number of boxes that are allowed to be cached per state machine type.</summary> - internal static readonly int s_valueTaskPoolingCacheSize = GetPoolAsyncValueTasksLimitValue(); - - private static bool GetPoolAsyncValueTasksSwitch() - { - string? value = Environment.GetEnvironmentVariable("DOTNET_SYSTEM_THREADING_POOLASYNCVALUETASKS"); - return value != null && (bool.IsTrueStringIgnoreCase(value) || value.Equals("1")); - } - - private static int GetPoolAsyncValueTasksLimitValue() => - int.TryParse(Environment.GetEnvironmentVariable("DOTNET_SYSTEM_THREADING_POOLASYNCVALUETASKSLIMIT"), out int result) && result > 0 ? - result : - Environment.ProcessorCount * 4; // arbitrary default value - - /// <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>([AllowNull] TResult result) => - new Task<TResult>(false, result, (TaskCreationOptions)InternalTaskOptions.DoNotDispose, default); - - /// <summary>Creates an array of cached tasks for the values in the range [INCLUSIVE_MIN,EXCLUSIVE_MAX).</summary> - private static Task<int>[] CreateInt32Tasks() - { - Debug.Assert(ExclusiveInt32Max >= InclusiveInt32Min, "Expected max to be at least min"); - - var tasks = new Task<int>[ExclusiveInt32Max - InclusiveInt32Min]; - for (int i = 0; i < tasks.Length; i++) - { - tasks[i] = CreateCacheableTask(i + InclusiveInt32Min); - } - - return tasks; - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncTaskMethodBuilder.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncTaskMethodBuilder.cs deleted file mode 100644 index a3e7e5fe068..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncTaskMethodBuilder.cs +++ /dev/null @@ -1,144 +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.Diagnostics; -using System.Threading.Tasks; - -namespace System.Runtime.CompilerServices -{ - /// <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> - public struct AsyncTaskMethodBuilder - { - /// <summary>The lazily-initialized built task.</summary> - private Task<VoidTaskResult>? m_task; // Debugger depends on the exact name of this field. - - /// <summary>Initializes a new <see cref="AsyncTaskMethodBuilder"/>.</summary> - /// <returns>The initialized <see cref="AsyncTaskMethodBuilder"/>.</returns> - public static AsyncTaskMethodBuilder Create() => default; - - /// <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> - [DebuggerStepThrough] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine => - AsyncMethodBuilderCore.Start(ref stateMachine); - - /// <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) => - AsyncMethodBuilderCore.SetStateMachine(stateMachine, task: 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> - public void AwaitOnCompleted<TAwaiter, TStateMachine>( - ref TAwaiter awaiter, ref TStateMachine stateMachine) - where TAwaiter : INotifyCompletion - where TStateMachine : IAsyncStateMachine => - AsyncTaskMethodBuilder<VoidTaskResult>.AwaitOnCompleted(ref awaiter, ref stateMachine, ref m_task); - - /// <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> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>( - ref TAwaiter awaiter, ref TStateMachine stateMachine) - where TAwaiter : ICriticalNotifyCompletion - where TStateMachine : IAsyncStateMachine => - AsyncTaskMethodBuilder<VoidTaskResult>.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine, ref m_task); - - /// <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 - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => m_task ?? InitializeTaskAsPromise(); - } - - /// <summary> - /// Initializes the task, which must not yet be initialized. Used only when the Task is being forced into - /// existence when no state machine is needed, e.g. when the builder is being synchronously completed with - /// an exception, when the builder is being used out of the context of an async method, etc. - /// </summary> - [MethodImpl(MethodImplOptions.NoInlining)] - private Task<VoidTaskResult> InitializeTaskAsPromise() - { - Debug.Assert(m_task == null); - return m_task = new Task<VoidTaskResult>(); - } - - /// <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() - { - // 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. - if (m_task is null) - { - m_task = Task.s_cachedCompleted; - } - else - { - // Otherwise, complete the task that's there. - AsyncTaskMethodBuilder<VoidTaskResult>.SetExistingTaskResult(m_task, default!); - } - } - - /// <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) => - AsyncTaskMethodBuilder<VoidTaskResult>.SetException(exception, ref m_task); - - /// <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) => - AsyncTaskMethodBuilder<VoidTaskResult>.SetNotificationForWaitCompletion(enabled, ref 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 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> - internal object ObjectIdForDebugger => - m_task ??= AsyncTaskMethodBuilder<VoidTaskResult>.CreateWeaklyTypedStateMachineBox(); - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncTaskMethodBuilderT.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncTaskMethodBuilderT.cs deleted file mode 100644 index 043a133ab13..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncTaskMethodBuilderT.cs +++ /dev/null @@ -1,607 +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.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Threading; -using System.Threading.Tasks; -using Internal.Runtime.CompilerServices; - -namespace System.Runtime.CompilerServices -{ - /// <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> - public struct AsyncTaskMethodBuilder<TResult> - { - /// <summary>A cached task for default(TResult).</summary> - internal static readonly Task<TResult> s_defaultResultTask = AsyncTaskCache.CreateCacheableTask<TResult>(default); - - /// <summary>The lazily-initialized built task.</summary> - private Task<TResult>? m_task; // Debugger depends on the exact name of this field. - - /// <summary>Initializes a new <see cref="AsyncTaskMethodBuilder"/>.</summary> - /// <returns>The initialized <see cref="AsyncTaskMethodBuilder"/>.</returns> - public static AsyncTaskMethodBuilder<TResult> Create() => default; - - /// <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> - [DebuggerStepThrough] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine => - AsyncMethodBuilderCore.Start(ref stateMachine); - - /// <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) => - AsyncMethodBuilderCore.SetStateMachine(stateMachine, m_task); - - /// <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 => - AwaitOnCompleted(ref awaiter, ref stateMachine, ref m_task); - - internal static void AwaitOnCompleted<TAwaiter, TStateMachine>( - ref TAwaiter awaiter, ref TStateMachine stateMachine, [NotNull] ref Task<TResult>? taskField) - where TAwaiter : INotifyCompletion - where TStateMachine : IAsyncStateMachine - { - try - { - awaiter.OnCompleted(GetStateMachineBox(ref stateMachine, ref taskField).MoveNextAction); - } - catch (Exception e) - { - System.Threading.Tasks.Task.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> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>( - ref TAwaiter awaiter, ref TStateMachine stateMachine) - where TAwaiter : ICriticalNotifyCompletion - where TStateMachine : IAsyncStateMachine => - AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine, ref m_task); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>( - ref TAwaiter awaiter, ref TStateMachine stateMachine, [NotNull] ref Task<TResult>? taskField) - where TAwaiter : ICriticalNotifyCompletion - where TStateMachine : IAsyncStateMachine - { - IAsyncStateMachineBox box = GetStateMachineBox(ref stateMachine, ref taskField); - AwaitUnsafeOnCompleted(ref awaiter, box); - } - - [MethodImpl(MethodImplOptions.AggressiveOptimization)] // workaround boxing allocations in Tier0: https://github.com/dotnet/coreclr/issues/14474 - internal static void AwaitUnsafeOnCompleted<TAwaiter>( - ref TAwaiter awaiter, IAsyncStateMachineBox box) - where TAwaiter : ICriticalNotifyCompletion - { - // The null tests here ensure that the jit can optimize away the interface - // tests when TAwaiter is a ref type. - - if ((null != (object)default(TAwaiter)!) && (awaiter is ITaskAwaiter)) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) - { - ref TaskAwaiter ta = ref Unsafe.As<TAwaiter, TaskAwaiter>(ref awaiter); // relies on TaskAwaiter/TaskAwaiter<T> having the same layout - TaskAwaiter.UnsafeOnCompletedInternal(ta.m_task, box, continueOnCapturedContext: true); - } - else if ((null != (object)default(TAwaiter)!) && (awaiter is IConfiguredTaskAwaiter)) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) - { - ref ConfiguredTaskAwaitable.ConfiguredTaskAwaiter ta = ref Unsafe.As<TAwaiter, ConfiguredTaskAwaitable.ConfiguredTaskAwaiter>(ref awaiter); - TaskAwaiter.UnsafeOnCompletedInternal(ta.m_task, box, ta.m_continueOnCapturedContext); - } - else if ((null != (object)default(TAwaiter)!) && (awaiter is IStateMachineBoxAwareAwaiter)) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) - { - try - { - ((IStateMachineBoxAwareAwaiter)awaiter).AwaitUnsafeOnCompleted(box); - } - catch (Exception e) - { - // Whereas with Task the code that hooks up and invokes the continuation is all local to corelib, - // with ValueTaskAwaiter we may be calling out to an arbitrary implementation of IValueTaskSource - // wrapped in the ValueTask, and as such we protect against errant exceptions that may emerge. - // We don't want such exceptions propagating back into the async method, which can't handle - // exceptions well at that location in the state machine, especially if the exception may occur - // after the ValueTaskAwaiter already successfully hooked up the callback, in which case it's possible - // two different flows of execution could end up happening in the same async method call. - System.Threading.Tasks.Task.ThrowAsync(e, targetContext: null); - } - } - else - { - // The awaiter isn't specially known. Fall back to doing a normal await. - try - { - awaiter.UnsafeOnCompleted(box.MoveNextAction); - } - catch (Exception e) - { - System.Threading.Tasks.Task.ThrowAsync(e, targetContext: null); - } - } - } - - /// <summary>Gets the "boxed" state machine object.</summary> - /// <typeparam name="TStateMachine">Specifies the type of the async state machine.</typeparam> - /// <param name="stateMachine">The state machine.</param> - /// <returns>The "boxed" state machine.</returns> - private static IAsyncStateMachineBox GetStateMachineBox<TStateMachine>( - ref TStateMachine stateMachine, - [NotNull] ref Task<TResult>? taskField) - where TStateMachine : IAsyncStateMachine - { - ExecutionContext? currentContext = ExecutionContext.Capture(); - - // Check first for the most common case: not the first yield in an async method. - // In this case, the first yield will have already "boxed" the state machine in - // a strongly-typed manner into an AsyncStateMachineBox. It will already contain - // the state machine as well as a MoveNextDelegate and a context. The only thing - // we might need to do is update the context if that's changed since it was stored. - if (taskField is AsyncStateMachineBox<TStateMachine> stronglyTypedBox) - { - if (stronglyTypedBox.Context != currentContext) - { - stronglyTypedBox.Context = currentContext; - } - return stronglyTypedBox; - } - - // The least common case: we have a weakly-typed boxed. This results if the debugger - // or some other use of reflection accesses a property like ObjectIdForDebugger or a - // method like SetNotificationForWaitCompletion prior to the first await happening. In - // such situations, we need to get an object to represent the builder, but we don't yet - // know the type of the state machine, and thus can't use TStateMachine. Instead, we - // use the IAsyncStateMachine interface, which all TStateMachines implement. This will - // result in a boxing allocation when storing the TStateMachine if it's a struct, but - // this only happens in active debugging scenarios where such performance impact doesn't - // matter. - if (taskField is AsyncStateMachineBox<IAsyncStateMachine> weaklyTypedBox) - { - // If this is the first await, we won't yet have a state machine, so store it. - if (weaklyTypedBox.StateMachine == null) - { - Debugger.NotifyOfCrossThreadDependency(); // same explanation as with usage below - weaklyTypedBox.StateMachine = stateMachine; - } - - // Update the context. This only happens with a debugger, so no need to spend - // extra IL checking for equality before doing the assignment. - weaklyTypedBox.Context = currentContext; - return weaklyTypedBox; - } - - // 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(); - - // At this point, taskField should really be null, in which case we want to create the box. - // However, in a variety of debugger-related (erroneous) situations, it might be non-null, - // e.g. if the Task property is examined in a Watch window, forcing it to be lazily-intialized - // as a Task<TResult> rather than as an AsyncStateMachineBox. The worst that happens in such - // cases is we lose the ability to properly step in the debugger, as the debugger uses that - // object's identity to track this specific builder/state machine. As such, we proceed to - // overwrite whatever's there anyway, even if it's non-null. -#if CORERT - // DebugFinalizableAsyncStateMachineBox looks like a small type, but it actually is not because - // it will have a copy of all the slots from its parent. It will add another hundred(s) bytes - // per each async method in CoreRT / ProjectN binaries without adding much value. Avoid - // generating this extra code until a better solution is implemented. - var box = new AsyncStateMachineBox<TStateMachine>(); -#else - AsyncStateMachineBox<TStateMachine> box = AsyncMethodBuilderCore.TrackAsyncMethodCompletion ? - CreateDebugFinalizableAsyncStateMachineBox<TStateMachine>() : - new AsyncStateMachineBox<TStateMachine>(); -#endif - taskField = box; // important: this must be done before storing stateMachine into box.StateMachine! - box.StateMachine = stateMachine; - box.Context = currentContext; - - // Log the creation of the state machine box object / task for this async method. - if (AsyncCausalityTracer.LoggingOn) - { - AsyncCausalityTracer.TraceOperationCreation(box, "Async: " + stateMachine.GetType().Name); - } - - // And if async debugging is enabled, track the task. - if (System.Threading.Tasks.Task.s_asyncDebuggingEnabled) - { - System.Threading.Tasks.Task.AddToActiveTasks(box); - } - - return box; - } - -#if !CORERT - // Avoid forcing the JIT to build DebugFinalizableAsyncStateMachineBox<TStateMachine> unless it's actually needed. - [MethodImpl(MethodImplOptions.NoInlining)] - private static AsyncStateMachineBox<TStateMachine> CreateDebugFinalizableAsyncStateMachineBox<TStateMachine>() - where TStateMachine : IAsyncStateMachine => - new DebugFinalizableAsyncStateMachineBox<TStateMachine>(); - - /// <summary> - /// Provides an async state machine box with a finalizer that will fire an EventSource - /// event about the state machine if it's being finalized without having been completed. - /// </summary> - /// <typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam> - private sealed class DebugFinalizableAsyncStateMachineBox<TStateMachine> : // SOS DumpAsync command depends on this name - AsyncStateMachineBox<TStateMachine> - where TStateMachine : IAsyncStateMachine - { - ~DebugFinalizableAsyncStateMachineBox() - { - // If the state machine is being finalized, something went wrong during its processing, - // e.g. it awaited something that got collected without itself having been completed. - // Fire an event with details about the state machine to help with debugging. - if (!IsCompleted) // double-check it's not completed, just to help minimize false positives - { - TplEventSource.Log.IncompleteAsyncMethod(this); - } - } - } -#endif - - /// <summary>A strongly-typed box for Task-based async state machines.</summary> - /// <typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam> - private class AsyncStateMachineBox<TStateMachine> : // SOS DumpAsync command depends on this name - Task<TResult>, IAsyncStateMachineBox - where TStateMachine : IAsyncStateMachine - { - /// <summary>Delegate used to invoke on an ExecutionContext when passed an instance of this box type.</summary> - private static readonly ContextCallback s_callback = ExecutionContextCallback; - - // Used to initialize s_callback above. We don't use a lambda for this on purpose: a lambda would - // introduce a new generic type behind the scenes that comes with a hefty size penalty in AOT builds. - private static void ExecutionContextCallback(object? s) - { - Debug.Assert(s is AsyncStateMachineBox<TStateMachine>); - // Only used privately to pass directly to EC.Run - Unsafe.As<AsyncStateMachineBox<TStateMachine>>(s).StateMachine!.MoveNext(); - } - - /// <summary>A delegate to the <see cref="MoveNext()"/> method.</summary> - private Action? _moveNextAction; - /// <summary>The state machine itself.</summary> - [AllowNull, MaybeNull] - public TStateMachine StateMachine = default; // mutable struct; do not make this readonly. SOS DumpAsync command depends on this name. - /// <summary>Captured ExecutionContext with which to invoke <see cref="MoveNextAction"/>; may be null.</summary> - public ExecutionContext? Context; - - /// <summary>A delegate to the <see cref="MoveNext()"/> method.</summary> - public Action MoveNextAction => _moveNextAction ??= new Action(MoveNext); - - internal sealed override void ExecuteFromThreadPool(Thread threadPoolThread) => MoveNext(threadPoolThread); - - /// <summary>Calls MoveNext on <see cref="StateMachine"/></summary> - public void MoveNext() => MoveNext(threadPoolThread: null); - - private void MoveNext(Thread? threadPoolThread) - { - Debug.Assert(!IsCompleted); - - bool loggingOn = AsyncCausalityTracer.LoggingOn; - if (loggingOn) - { - AsyncCausalityTracer.TraceSynchronousWorkStart(this, CausalitySynchronousWork.Execution); - } - - ExecutionContext? context = Context; - if (context == null) - { - Debug.Assert(StateMachine != null); - StateMachine.MoveNext(); - } - else - { - if (threadPoolThread is null) - { - ExecutionContext.RunInternal(context, s_callback, this); - } - else - { - ExecutionContext.RunFromThreadPoolDispatchLoop(threadPoolThread, context, s_callback, this); - } - } - - if (IsCompleted) - { - // If async debugging is enabled, remove the task from tracking. - if (System.Threading.Tasks.Task.s_asyncDebuggingEnabled) - { - System.Threading.Tasks.Task.RemoveFromActiveTasks(this); - } - - // Clear out state now that the async method has completed. - // This avoids keeping arbitrary state referenced by lifted locals - // if this Task / state machine box is held onto. - StateMachine = default; - Context = default; - -#if !CORERT - // In case this is a state machine box with a finalizer, suppress its finalization - // as it's now complete. We only need the finalizer to run if the box is collected - // without having been completed. - if (AsyncMethodBuilderCore.TrackAsyncMethodCompletion) - { - GC.SuppressFinalize(this); - } -#endif - } - - if (loggingOn) - { - AsyncCausalityTracer.TraceSynchronousWorkCompletion(CausalitySynchronousWork.Execution); - } - } - - /// <summary>Gets the state machine as a boxed object. This should only be used for debugging purposes.</summary> - IAsyncStateMachine IAsyncStateMachineBox.GetStateMachineObject() => StateMachine!; // likely boxes, only use for debugging - } - - /// <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 - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => m_task ?? InitializeTaskAsPromise(); - } - - /// <summary> - /// Initializes the task, which must not yet be initialized. Used only when the Task is being forced into - /// existence when no state machine is needed, e.g. when the builder is being synchronously completed with - /// an exception, when the builder is being used out of the context of an async method, etc. - /// </summary> - [MethodImpl(MethodImplOptions.NoInlining)] - private Task<TResult> InitializeTaskAsPromise() - { - Debug.Assert(m_task == null); - return m_task = new Task<TResult>(); - } - - internal static Task<TResult> CreateWeaklyTypedStateMachineBox() - { -#if CORERT - // DebugFinalizableAsyncStateMachineBox looks like a small type, but it actually is not because - // it will have a copy of all the slots from its parent. It will add another hundred(s) bytes - // per each async method in CoreRT / ProjectN binaries without adding much value. Avoid - // generating this extra code until a better solution is implemented. - return new AsyncStateMachineBox<IAsyncStateMachine>(); -#else - return AsyncMethodBuilderCore.TrackAsyncMethodCompletion ? - CreateDebugFinalizableAsyncStateMachineBox<IAsyncStateMachine>() : - new AsyncStateMachineBox<IAsyncStateMachine>(); -#endif - } - - /// <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. - if (m_task is null) - { - m_task = GetTaskForResult(result); - Debug.Assert(m_task != null, $"{nameof(GetTaskForResult)} should never return null"); - } - else - { - // Slow path: complete the existing task. - SetExistingTaskResult(m_task, result); - } - } - - /// <summary>Completes the already initialized task with the specified result.</summary> - /// <param name="result">The result to use to complete the task.</param> - internal static void SetExistingTaskResult(Task<TResult> taskField, [AllowNull] TResult result) - { - Debug.Assert(taskField != null, "Expected non-null task"); - - if (AsyncCausalityTracer.LoggingOn) - { - AsyncCausalityTracer.TraceOperationCompletion(taskField, AsyncCausalityStatus.Completed); - } - - if (!taskField.TrySetResult(result)) - { - ThrowHelper.ThrowInvalidOperationException(ExceptionResource.TaskT_TransitionToFinal_AlreadyCompleted); - } - } - - /// <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) => SetException(exception, ref m_task); - - internal static void SetException(Exception exception, ref Task<TResult>? taskField) - { - if (exception == null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.exception); - } - - // Get the task, forcing initialization if it hasn't already been initialized. - Task<TResult> task = (taskField ??= new Task<TResult>()); - - // If the exception represents cancellation, cancel the task. Otherwise, fault the task. - bool successfullySet = exception is OperationCanceledException oce ? - task.TrySetCanceled(oce.CancellationToken, oce) : - task.TrySetException(exception); - - // Unlike with TaskCompletionSource, we do not need to spin here until _taskAndStateMachine 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 completes the task first). - if (!successfullySet) - { - ThrowHelper.ThrowInvalidOperationException(ExceptionResource.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) => - SetNotificationForWaitCompletion(enabled, ref m_task); - - internal static void SetNotificationForWaitCompletion(bool enabled, [NotNull] ref Task<TResult>? taskField) - { - // Get the task (forcing initialization if not already initialized), and set debug notification - (taskField ??= CreateWeaklyTypedStateMachineBox()).SetNotificationForWaitCompletion(enabled); - - // NOTE: It's important that the debugger use builder.SetNotificationForWaitCompletion - // rather than builder.Task.SetNotificationForWaitCompletion. Even though the latter will - // lazily-initialize the task as well, it'll initialize it to a Task<T> (which is important - // to minimize size for cases where an ATMB is used directly by user code to avoid the - // allocation overhead of a TaskCompletionSource). If that's done prior to the first await, - // the GetMoveNextDelegate code, which needs an AsyncStateMachineBox, will end up creating - // a new box and overwriting the previously created task. That'll change the object identity - // of the task being used for wait completion notification, and no notification will - // ever arrive, breaking step-out behavior when stepping out before the first yielding await. - } - - /// <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 or other members that lazily initialize the task. - /// </remarks> - internal object ObjectIdForDebugger => m_task ??= CreateWeaklyTypedStateMachineBox(); - - /// <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> - [MethodImpl(MethodImplOptions.AggressiveInlining)] // method looks long, but for a given TResult it results in a relatively small amount of asm - internal static Task<TResult> GetTaskForResult(TResult result) - { - // 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 // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) - { - // Special case simple value types: - // - Boolean - // - Byte, SByte - // - Char - // - 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(bool)) // only the relevant branches are kept for each value-type generic instantiation - { - bool value = (bool)(object)result!; - Task<bool> task = value ? AsyncTaskCache.s_trueTask : AsyncTaskCache.s_falseTask; - return Unsafe.As<Task<TResult>>(task); // UnsafeCast avoids type check we know will succeed - } - // For Int32, we cache a range of common values, e.g. [-1,9). - else if (typeof(TResult) == typeof(int)) - { - // 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. - int value = (int)(object)result!; - if (value < AsyncTaskCache.ExclusiveInt32Max && - value >= AsyncTaskCache.InclusiveInt32Min) - { - Task<int> task = AsyncTaskCache.s_int32Tasks[value - AsyncTaskCache.InclusiveInt32Min]; - return Unsafe.As<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(uint) && default == (uint)(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!) || - (typeof(TResult) == typeof(long) && default == (long)(object)result!) || - (typeof(TResult) == typeof(ulong) && default == (ulong)(object)result!) || - (typeof(TResult) == typeof(short) && default(short) == (short)(object)result!) || - (typeof(TResult) == typeof(ushort) && default(ushort) == (ushort)(object)result!) || - (typeof(TResult) == typeof(IntPtr) && default == (IntPtr)(object)result!) || - (typeof(TResult) == typeof(UIntPtr) && default == (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); - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs deleted file mode 100644 index bb5bd28393c..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs +++ /dev/null @@ -1,175 +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; -using Internal.Runtime.CompilerServices; - -using StateMachineBox = System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder<System.Threading.Tasks.VoidTaskResult>.StateMachineBox; - -namespace System.Runtime.CompilerServices -{ - /// <summary>Represents a builder for asynchronous methods that return a <see cref="ValueTask"/>.</summary> - [StructLayout(LayoutKind.Auto)] - public struct AsyncValueTaskMethodBuilder - { - /// <summary>Sentinel object used to indicate that the builder completed synchronously and successfully.</summary> - private static readonly object s_syncSuccessSentinel = AsyncValueTaskMethodBuilder<VoidTaskResult>.s_syncSuccessSentinel; - - /// <summary>The wrapped state machine box or task, based on the value of <see cref="AsyncTaskCache.s_valueTaskPoolingEnabled"/>.</summary> - /// <remarks> - /// If the operation completed synchronously and successfully, this will be <see cref="s_syncSuccessSentinel"/>. - /// </remarks> - private object? m_task; // Debugger depends on the exact name of this field. - - /// <summary>Creates an instance of the <see cref="AsyncValueTaskMethodBuilder"/> struct.</summary> - /// <returns>The initialized instance.</returns> - public static AsyncValueTaskMethodBuilder Create() => default; - - /// <summary>Begins running the builder with the associated state machine.</summary> - /// <typeparam name="TStateMachine">The type of the state machine.</typeparam> - /// <param name="stateMachine">The state machine instance, passed by reference.</param> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Start<TStateMachine>(ref TStateMachine stateMachine) - where TStateMachine : IAsyncStateMachine => - AsyncMethodBuilderCore.Start(ref stateMachine); - - /// <summary>Associates the builder with the specified state machine.</summary> - /// <param name="stateMachine">The state machine instance to associate with the builder.</param> - public void SetStateMachine(IAsyncStateMachine stateMachine) => - AsyncMethodBuilderCore.SetStateMachine(stateMachine, task: null); - - /// <summary>Marks the task as successfully completed.</summary> - public void SetResult() - { - if (m_task is null) - { - m_task = s_syncSuccessSentinel; - } - else if (AsyncTaskCache.s_valueTaskPoolingEnabled) - { - Unsafe.As<StateMachineBox>(m_task).SetResult(default); - } - else - { - AsyncTaskMethodBuilder<VoidTaskResult>.SetExistingTaskResult(Unsafe.As<Task<VoidTaskResult>>(m_task), default); - } - } - - /// <summary>Marks the task as failed and binds the specified exception to the task.</summary> - /// <param name="exception">The exception to bind to the task.</param> - public void SetException(Exception exception) - { - if (AsyncTaskCache.s_valueTaskPoolingEnabled) - { - AsyncValueTaskMethodBuilder<VoidTaskResult>.SetException(exception, ref Unsafe.As<object?, StateMachineBox?>(ref m_task)); - } - else - { - AsyncTaskMethodBuilder<VoidTaskResult>.SetException(exception, ref Unsafe.As<object?, Task<VoidTaskResult>?>(ref m_task)); - } - } - - /// <summary>Gets the task for this builder.</summary> - public ValueTask Task - { - get - { - if (m_task == s_syncSuccessSentinel) - { - return default; - } - - // With normal access paterns, m_task should always be non-null here: the async method should have - // either completed synchronously, in which case SetResult would have set m_task to a non-null object, - // or it should be completing asynchronously, in which case AwaitUnsafeOnCompleted would have similarly - // initialized m_task to a state machine object. However, if the type is used manually (not via - // compiler-generated code) and accesses Task directly, we force it to be initialized. Things will then - // "work" but in a degraded mode, as we don't know the TStateMachine type here, and thus we use a box around - // the interface instead. - - if (AsyncTaskCache.s_valueTaskPoolingEnabled) - { - var box = Unsafe.As<StateMachineBox?>(m_task); - if (box is null) - { - m_task = box = AsyncValueTaskMethodBuilder<VoidTaskResult>.CreateWeaklyTypedStateMachineBox(); - } - return new ValueTask(box, box.Version); - } - else - { - var task = Unsafe.As<Task<VoidTaskResult>?>(m_task); - if (task is null) - { - m_task = task = new Task<VoidTaskResult>(); // base task used rather than box to minimize size when used as manual promise - } - return new ValueTask(task); - } - } - } - - /// <summary>Schedules the state machine to proceed to the next action when the specified awaiter completes.</summary> - /// <typeparam name="TAwaiter">The type of the awaiter.</typeparam> - /// <typeparam name="TStateMachine">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 - { - if (AsyncTaskCache.s_valueTaskPoolingEnabled) - { - AsyncValueTaskMethodBuilder<VoidTaskResult>.AwaitOnCompleted(ref awaiter, ref stateMachine, ref Unsafe.As<object?, StateMachineBox?>(ref m_task)); - } - else - { - AsyncTaskMethodBuilder<VoidTaskResult>.AwaitOnCompleted(ref awaiter, ref stateMachine, ref Unsafe.As<object?, Task<VoidTaskResult>?>(ref m_task)); - } - } - - /// <summary>Schedules the state machine to proceed to the next action when the specified awaiter completes.</summary> - /// <typeparam name="TAwaiter">The type of the awaiter.</typeparam> - /// <typeparam name="TStateMachine">The type of the state machine.</typeparam> - /// <param name="awaiter">The awaiter.</param> - /// <param name="stateMachine">The state machine.</param> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) - where TAwaiter : ICriticalNotifyCompletion - where TStateMachine : IAsyncStateMachine - { - if (AsyncTaskCache.s_valueTaskPoolingEnabled) - { - AsyncValueTaskMethodBuilder<VoidTaskResult>.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine, ref Unsafe.As<object?, StateMachineBox?>(ref m_task)); - } - else - { - AsyncTaskMethodBuilder<VoidTaskResult>.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine, ref Unsafe.As<object?, Task<VoidTaskResult>?>(ref 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 tracing purposes, and only in a single-threaded manner - /// when no other threads are in the middle of accessing this or other members that lazily initialize the box. - /// </remarks> - internal object ObjectIdForDebugger - { - get - { - if (m_task is null) - { - m_task = AsyncTaskCache.s_valueTaskPoolingEnabled ? (object) - AsyncValueTaskMethodBuilder<VoidTaskResult>.CreateWeaklyTypedStateMachineBox() : - AsyncTaskMethodBuilder<VoidTaskResult>.CreateWeaklyTypedStateMachineBox(); - } - - return m_task; - } - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilderT.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilderT.cs deleted file mode 100644 index d2bd7ec111a..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilderT.cs +++ /dev/null @@ -1,513 +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.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using System.Threading; -using System.Threading.Tasks; -using System.Threading.Tasks.Sources; -using Internal.Runtime.CompilerServices; - -namespace System.Runtime.CompilerServices -{ - /// <summary>Represents a builder for asynchronous methods that returns a <see cref="ValueTask{TResult}"/>.</summary> - /// <typeparam name="TResult">The type of the result.</typeparam> - [StructLayout(LayoutKind.Auto)] - public struct AsyncValueTaskMethodBuilder<TResult> - { - /// <summary>Sentinel object used to indicate that the builder completed synchronously and successfully.</summary> - /// <remarks> - /// To avoid memory safety issues even in the face of invalid race conditions, we ensure that the type of this object - /// is valid for the mode in which we're operating. As such, it's cached on the generic builder per TResult - /// rather than having one sentinel instance for all types. - /// </remarks> - internal static readonly object s_syncSuccessSentinel = AsyncTaskCache.s_valueTaskPoolingEnabled ? (object) - new SyncSuccessSentinelStateMachineBox() : - new Task<TResult>(default(TResult)!); - - /// <summary>The wrapped state machine or task. If the operation completed synchronously and successfully, this will be a sentinel object compared by reference identity.</summary> - private object? m_task; // Debugger depends on the exact name of this field. - /// <summary>The result for this builder if it's completed synchronously, in which case <see cref="m_task"/> will be <see cref="s_syncSuccessSentinel"/>.</summary> - private TResult _result; - - /// <summary>Creates an instance of the <see cref="AsyncValueTaskMethodBuilder{TResult}"/> struct.</summary> - /// <returns>The initialized instance.</returns> - public static AsyncValueTaskMethodBuilder<TResult> Create() => default; - - /// <summary>Begins running the builder with the associated state machine.</summary> - /// <typeparam name="TStateMachine">The type of the state machine.</typeparam> - /// <param name="stateMachine">The state machine instance, passed by reference.</param> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine => - AsyncMethodBuilderCore.Start(ref stateMachine); - - /// <summary>Associates the builder with the specified state machine.</summary> - /// <param name="stateMachine">The state machine instance to associate with the builder.</param> - public void SetStateMachine(IAsyncStateMachine stateMachine) => - AsyncMethodBuilderCore.SetStateMachine(stateMachine, task: null); - - /// <summary>Marks the value task as successfully completed.</summary> - /// <param name="result">The result to use to complete the value task.</param> - public void SetResult(TResult result) - { - if (m_task is null) - { - _result = result; - m_task = s_syncSuccessSentinel; - } - else if (AsyncTaskCache.s_valueTaskPoolingEnabled) - { - Unsafe.As<StateMachineBox>(m_task).SetResult(result); - } - else - { - AsyncTaskMethodBuilder<TResult>.SetExistingTaskResult(Unsafe.As<Task<TResult>>(m_task), result); - } - } - - /// <summary>Marks the value task as failed and binds the specified exception to the value task.</summary> - /// <param name="exception">The exception to bind to the value task.</param> - public void SetException(Exception exception) - { - if (AsyncTaskCache.s_valueTaskPoolingEnabled) - { - SetException(exception, ref Unsafe.As<object?, StateMachineBox?>(ref m_task)); - } - else - { - AsyncTaskMethodBuilder<TResult>.SetException(exception, ref Unsafe.As<object?, Task<TResult>?>(ref m_task)); - } - } - - internal static void SetException(Exception exception, [NotNull] ref StateMachineBox? boxFieldRef) - { - if (exception is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.exception); - } - - (boxFieldRef ??= CreateWeaklyTypedStateMachineBox()).SetException(exception); - } - - /// <summary>Gets the value task for this builder.</summary> - public ValueTask<TResult> Task - { - get - { - if (m_task == s_syncSuccessSentinel) - { - return new ValueTask<TResult>(_result); - } - - // With normal access paterns, m_task should always be non-null here: the async method should have - // either completed synchronously, in which case SetResult would have set m_task to a non-null object, - // or it should be completing asynchronously, in which case AwaitUnsafeOnCompleted would have similarly - // initialized m_task to a state machine object. However, if the type is used manually (not via - // compiler-generated code) and accesses Task directly, we force it to be initialized. Things will then - // "work" but in a degraded mode, as we don't know the TStateMachine type here, and thus we use a box around - // the interface instead. - - if (AsyncTaskCache.s_valueTaskPoolingEnabled) - { - var box = Unsafe.As<StateMachineBox?>(m_task); - if (box is null) - { - m_task = box = CreateWeaklyTypedStateMachineBox(); - } - return new ValueTask<TResult>(box, box.Version); - } - else - { - var task = Unsafe.As<Task<TResult>?>(m_task); - if (task is null) - { - m_task = task = new Task<TResult>(); // base task used rather than box to minimize size when used as manual promise - } - return new ValueTask<TResult>(task); - } - } - } - - /// <summary>Schedules the state machine to proceed to the next action when the specified awaiter completes.</summary> - /// <typeparam name="TAwaiter">The type of the awaiter.</typeparam> - /// <typeparam name="TStateMachine">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 - { - if (AsyncTaskCache.s_valueTaskPoolingEnabled) - { - AwaitOnCompleted(ref awaiter, ref stateMachine, ref Unsafe.As<object?, StateMachineBox?>(ref m_task)); - } - else - { - AsyncTaskMethodBuilder<TResult>.AwaitOnCompleted(ref awaiter, ref stateMachine, ref Unsafe.As<object?, Task<TResult>?>(ref m_task)); - } - } - - internal static void AwaitOnCompleted<TAwaiter, TStateMachine>( - ref TAwaiter awaiter, ref TStateMachine stateMachine, [NotNull] ref StateMachineBox? box) - where TAwaiter : INotifyCompletion - where TStateMachine : IAsyncStateMachine - { - try - { - awaiter.OnCompleted(GetStateMachineBox(ref stateMachine, ref box).MoveNextAction); - } - catch (Exception e) - { - System.Threading.Tasks.Task.ThrowAsync(e, targetContext: null); - } - } - - /// <summary>Schedules the state machine to proceed to the next action when the specified awaiter completes.</summary> - /// <typeparam name="TAwaiter">The type of the awaiter.</typeparam> - /// <typeparam name="TStateMachine">The type of the state machine.</typeparam> - /// <param name="awaiter">the awaiter</param> - /// <param name="stateMachine">The state machine.</param> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) - where TAwaiter : ICriticalNotifyCompletion - where TStateMachine : IAsyncStateMachine - { - if (AsyncTaskCache.s_valueTaskPoolingEnabled) - { - AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine, ref Unsafe.As<object?, StateMachineBox?>(ref m_task)); - } - else - { - AsyncTaskMethodBuilder<TResult>.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine, ref Unsafe.As<object?, Task<TResult>?>(ref m_task)); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>( - ref TAwaiter awaiter, ref TStateMachine stateMachine, [NotNull] ref StateMachineBox? boxRef) - where TAwaiter : ICriticalNotifyCompletion - where TStateMachine : IAsyncStateMachine - { - IAsyncStateMachineBox box = GetStateMachineBox(ref stateMachine, ref boxRef); - AsyncTaskMethodBuilder<VoidTaskResult>.AwaitUnsafeOnCompleted(ref awaiter, box); - } - - /// <summary>Gets the "boxed" state machine object.</summary> - /// <typeparam name="TStateMachine">Specifies the type of the async state machine.</typeparam> - /// <param name="stateMachine">The state machine.</param> - /// <param name="boxFieldRef">A reference to the field containing the initialized state machine box.</param> - /// <returns>The "boxed" state machine.</returns> - private static IAsyncStateMachineBox GetStateMachineBox<TStateMachine>( - ref TStateMachine stateMachine, - [NotNull] ref StateMachineBox? boxFieldRef) - where TStateMachine : IAsyncStateMachine - { - ExecutionContext? currentContext = ExecutionContext.Capture(); - - // Check first for the most common case: not the first yield in an async method. - // In this case, the first yield will have already "boxed" the state machine in - // a strongly-typed manner into an AsyncStateMachineBox. It will already contain - // the state machine as well as a MoveNextDelegate and a context. The only thing - // we might need to do is update the context if that's changed since it was stored. - if (boxFieldRef is StateMachineBox<TStateMachine> stronglyTypedBox) - { - if (stronglyTypedBox.Context != currentContext) - { - stronglyTypedBox.Context = currentContext; - } - - return stronglyTypedBox; - } - - // The least common case: we have a weakly-typed boxed. This results if the debugger - // or some other use of reflection accesses a property like ObjectIdForDebugger. In - // such situations, we need to get an object to represent the builder, but we don't yet - // know the type of the state machine, and thus can't use TStateMachine. Instead, we - // use the IAsyncStateMachine interface, which all TStateMachines implement. This will - // result in a boxing allocation when storing the TStateMachine if it's a struct, but - // this only happens in active debugging scenarios where such performance impact doesn't - // matter. - if (boxFieldRef is StateMachineBox<IAsyncStateMachine> weaklyTypedBox) - { - // If this is the first await, we won't yet have a state machine, so store it. - if (weaklyTypedBox.StateMachine is null) - { - Debugger.NotifyOfCrossThreadDependency(); // same explanation as with usage below - weaklyTypedBox.StateMachine = stateMachine; - } - - // Update the context. This only happens with a debugger, so no need to spend - // extra IL checking for equality before doing the assignment. - weaklyTypedBox.Context = currentContext; - return weaklyTypedBox; - } - - // 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(); - - // At this point, m_task should really be null, in which case we want to create the box. - // However, in a variety of debugger-related (erroneous) situations, it might be non-null, - // e.g. if the Task property is examined in a Watch window, forcing it to be lazily-intialized - // as a Task<TResult> rather than as an ValueTaskStateMachineBox. The worst that happens in such - // cases is we lose the ability to properly step in the debugger, as the debugger uses that - // object's identity to track this specific builder/state machine. As such, we proceed to - // overwrite whatever's there anyway, even if it's non-null. - var box = StateMachineBox<TStateMachine>.GetOrCreateBox(); - boxFieldRef = box; // important: this must be done before storing stateMachine into box.StateMachine! - box.StateMachine = stateMachine; - box.Context = currentContext; - - return box; - } - - /// <summary> - /// Creates a box object for use when a non-standard access pattern is employed, e.g. when Task - /// is evaluated in the debugger prior to the async method yielding for the first time. - /// </summary> - internal static StateMachineBox CreateWeaklyTypedStateMachineBox() => new StateMachineBox<IAsyncStateMachine>(); - - /// <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 or other members that lazily initialize the box. - /// </remarks> - internal object ObjectIdForDebugger - { - get - { - if (m_task is null) - { - m_task = AsyncTaskCache.s_valueTaskPoolingEnabled ? (object) - CreateWeaklyTypedStateMachineBox() : - AsyncTaskMethodBuilder<TResult>.CreateWeaklyTypedStateMachineBox(); - } - - return m_task; - } - } - - /// <summary>The base type for all value task box reusable box objects, regardless of state machine type.</summary> - internal abstract class StateMachineBox : - IValueTaskSource<TResult>, IValueTaskSource - { - /// <summary>A delegate to the MoveNext method.</summary> - protected Action? _moveNextAction; - /// <summary>Captured ExecutionContext with which to invoke MoveNext.</summary> - public ExecutionContext? Context; - /// <summary>Implementation for IValueTaskSource interfaces.</summary> - protected ManualResetValueTaskSourceCore<TResult> _valueTaskSource; - - /// <summary>Completes the box with a result.</summary> - /// <param name="result">The result.</param> - public void SetResult(TResult result) => - _valueTaskSource.SetResult(result); - - /// <summary>Completes the box with an error.</summary> - /// <param name="error">The exception.</param> - public void SetException(Exception error) => - _valueTaskSource.SetException(error); - - /// <summary>Gets the status of the box.</summary> - public ValueTaskSourceStatus GetStatus(short token) => _valueTaskSource.GetStatus(token); - - /// <summary>Schedules the continuation action for this box.</summary> - public void OnCompleted(Action<object?> continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags) => - _valueTaskSource.OnCompleted(continuation, state, token, flags); - - /// <summary>Gets the current version number of the box.</summary> - public short Version => _valueTaskSource.Version; - - /// <summary>Implemented by derived type.</summary> - TResult IValueTaskSource<TResult>.GetResult(short token) => throw NotImplemented.ByDesign; - - /// <summary>Implemented by derived type.</summary> - void IValueTaskSource.GetResult(short token) => throw NotImplemented.ByDesign; - } - - private sealed class SyncSuccessSentinelStateMachineBox : StateMachineBox - { - public SyncSuccessSentinelStateMachineBox() => SetResult(default!); - } - - /// <summary>Provides a strongly-typed box object based on the specific state machine type in use.</summary> - private sealed class StateMachineBox<TStateMachine> : - StateMachineBox, - IValueTaskSource<TResult>, IValueTaskSource, IAsyncStateMachineBox, IThreadPoolWorkItem - where TStateMachine : IAsyncStateMachine - { - /// <summary>Delegate used to invoke on an ExecutionContext when passed an instance of this box type.</summary> - private static readonly ContextCallback s_callback = ExecutionContextCallback; - /// <summary>Lock used to protected the shared cache of boxes.</summary> - /// <remarks>The code that uses this assumes a runtime without thread aborts.</remarks> - private static int s_cacheLock; - /// <summary>Singly-linked list cache of boxes.</summary> - private static StateMachineBox<TStateMachine>? s_cache; - /// <summary>The number of items stored in <see cref="s_cache"/>.</summary> - private static int s_cacheSize; - - // TODO: - // AsyncTaskMethodBuilder logs about the state machine box lifecycle; AsyncValueTaskMethodBuilder currently - // does not when it employs these pooled boxes. That logging is based on Task IDs, which we lack here. - // We could use the box's Version, but that is very likely to conflict with the IDs of other tasks in the system. - // For now, we don't log, but should we choose to we'll probably want to store an int ID on the state machine box, - // and initialize it an ID from Task's generator. - - /// <summary>If this box is stored in the cache, the next box in the cache.</summary> - private StateMachineBox<TStateMachine>? _next; - /// <summary>The state machine itself.</summary> - [AllowNull, MaybeNull] - public TStateMachine StateMachine = default; - - /// <summary>Gets a box object to use for an operation. This may be a reused, pooled object, or it may be new.</summary> - [MethodImpl(MethodImplOptions.AggressiveInlining)] // only one caller - internal static StateMachineBox<TStateMachine> GetOrCreateBox() - { - // Try to acquire the lock to access the cache. If there's any contention, don't use the cache. - if (Interlocked.CompareExchange(ref s_cacheLock, 1, 0) == 0) - { - // If there are any instances cached, take one from the cache stack and use it. - StateMachineBox<TStateMachine>? box = s_cache; - if (!(box is null)) - { - s_cache = box._next; - box._next = null; - s_cacheSize--; - Debug.Assert(s_cacheSize >= 0, "Expected the cache size to be non-negative."); - - // Release the lock and return the box. - Volatile.Write(ref s_cacheLock, 0); - return box; - } - - // No objects were cached. We'll just create a new instance. - Debug.Assert(s_cacheSize == 0, "Expected cache size to be 0."); - - // Release the lock. - Volatile.Write(ref s_cacheLock, 0); - } - - // Couldn't quickly get a cached instance, so create a new instance. - return new StateMachineBox<TStateMachine>(); - } - - private void ReturnOrDropBox() - { - Debug.Assert(_next is null, "Expected box to not be part of cached list."); - - // Clear out the state machine and associated context to avoid keeping arbitrary state referenced by - // lifted locals. We want to do this regardless of whether we end up caching the box or not, in case - // the caller keeps the box alive for an arbitrary period of time. - StateMachine = default; - Context = default; - - // Reset the MRVTSC. We can either do this here, in which case we may be paying the (small) overhead - // to reset the box even if we're going to drop it, or we could do it while holding the lock, in which - // case we'll only reset it if necessary but causing the lock to be held for longer, thereby causing - // more contention. For now at least, we do it outside of the lock. (This must not be done after - // the lock is released, since at that point the instance could already be in use elsewhere.) - // We also want to increment the version number even if we're going to drop it, to maximize the chances - // that incorrectly double-awaiting a ValueTask will produce an error. - _valueTaskSource.Reset(); - - // If reusing the object would result in potentially wrapping around its version number, just throw it away. - // This provides a modicum of additional safety when ValueTasks are misused (helping to avoid the case where - // a ValueTask is illegally re-awaited and happens to do so at exactly 2^16 uses later on this exact same instance), - // at the expense of potentially incurring an additional allocation every 65K uses. - if ((ushort)_valueTaskSource.Version == ushort.MaxValue) - { - return; - } - - // Try to acquire the cache lock. If there's any contention, or if the cache is full, we just throw away the object. - if (Interlocked.CompareExchange(ref s_cacheLock, 1, 0) == 0) - { - if (s_cacheSize < AsyncTaskCache.s_valueTaskPoolingCacheSize) - { - // Push the box onto the cache stack for subsequent reuse. - _next = s_cache; - s_cache = this; - s_cacheSize++; - Debug.Assert(s_cacheSize > 0 && s_cacheSize <= AsyncTaskCache.s_valueTaskPoolingCacheSize, "Expected cache size to be within bounds."); - } - - // Release the lock. - Volatile.Write(ref s_cacheLock, 0); - } - } - - /// <summary> - /// Used to initialize s_callback above. We don't use a lambda for this on purpose: a lambda would - /// introduce a new generic type behind the scenes that comes with a hefty size penalty in AOT builds. - /// </summary> - private static void ExecutionContextCallback(object? s) - { - // Only used privately to pass directly to EC.Run - Debug.Assert(s is StateMachineBox<TStateMachine>); - Unsafe.As<StateMachineBox<TStateMachine>>(s).StateMachine!.MoveNext(); - } - - /// <summary>A delegate to the <see cref="MoveNext()"/> method.</summary> - public Action MoveNextAction => _moveNextAction ??= new Action(MoveNext); - - /// <summary>Invoked to run MoveNext when this instance is executed from the thread pool.</summary> - void IThreadPoolWorkItem.Execute() => MoveNext(); - - /// <summary>Calls MoveNext on <see cref="StateMachine"/></summary> - public void MoveNext() - { - ExecutionContext? context = Context; - - if (context is null) - { - Debug.Assert(!(StateMachine is null)); - StateMachine.MoveNext(); - } - else - { - ExecutionContext.RunInternal(context, s_callback, this); - } - } - - /// <summary>Get the result of the operation.</summary> - TResult IValueTaskSource<TResult>.GetResult(short token) - { - try - { - return _valueTaskSource.GetResult(token); - } - finally - { - // Reuse this instance if possible, otherwise clear and drop it. - ReturnOrDropBox(); - } - } - - /// <summary>Get the result of the operation.</summary> - void IValueTaskSource.GetResult(short token) - { - try - { - _valueTaskSource.GetResult(token); - } - finally - { - // Reuse this instance if possible, otherwise clear and drop it. - ReturnOrDropBox(); - } - } - - /// <summary>Gets the state machine as a boxed object. This should only be used for debugging purposes.</summary> - IAsyncStateMachine IAsyncStateMachineBox.GetStateMachineObject() => StateMachine!; // likely boxes, only use for debugging - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncVoidMethodBuilder.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncVoidMethodBuilder.cs deleted file mode 100644 index 3a0a0a2c630..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncVoidMethodBuilder.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.Diagnostics; -using System.Threading; -using System.Threading.Tasks; - -namespace System.Runtime.CompilerServices -{ - /// <summary> - /// Provides a builder for asynchronous methods that return void. - /// This type is intended for compiler use only. - /// </summary> - public struct AsyncVoidMethodBuilder - { - /// <summary>The synchronization context associated with this operation.</summary> - private SynchronizationContext? _synchronizationContext; - /// <summary>The builder this void builder wraps.</summary> - private AsyncTaskMethodBuilder _builder; // mutable struct: must not be readonly - - /// <summary>Initializes a new <see cref="AsyncVoidMethodBuilder"/>.</summary> - /// <returns>The initialized <see cref="AsyncVoidMethodBuilder"/>.</returns> - public static AsyncVoidMethodBuilder Create() - { - SynchronizationContext? sc = SynchronizationContext.Current; - sc?.OperationStarted(); - - // _builder should be initialized to AsyncTaskMethodBuilder.Create(), but on coreclr - // that Create() is a nop, so we can just return the default here. - return new AsyncVoidMethodBuilder() { _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> - [DebuggerStepThrough] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine => - AsyncMethodBuilderCore.Start(ref stateMachine); - - /// <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) => - _builder.SetStateMachine(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 AwaitOnCompleted<TAwaiter, TStateMachine>( - ref TAwaiter awaiter, ref TStateMachine stateMachine) - where TAwaiter : INotifyCompletion - where TStateMachine : IAsyncStateMachine => - _builder.AwaitOnCompleted(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 => - _builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine); - - /// <summary>Completes the method builder successfully.</summary> - public void SetResult() - { - if (AsyncCausalityTracer.LoggingOn) - { - AsyncCausalityTracer.TraceOperationCompletion(this.Task, AsyncCausalityStatus.Completed); - } - - // Mark the builder as completed. As this is a void-returning method, this mostly - // doesn't matter, but it can affect things like debug events related to finalization. - _builder.SetResult(); - - if (_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) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.exception); - } - - if (AsyncCausalityTracer.LoggingOn) - { - AsyncCausalityTracer.TraceOperationCompletion(this.Task, AsyncCausalityStatus.Error); - } - - if (_synchronizationContext != null) - { - // If we captured a synchronization context, Post the throwing of the exception to it - // and decrement its outstanding operation count. - try - { - System.Threading.Tasks.Task.ThrowAsync(exception, targetContext: _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. - System.Threading.Tasks.Task.ThrowAsync(exception, targetContext: null); - } - - // The exception was propagated already; we don't need or want to fault the builder, just mark it as completed. - _builder.SetResult(); - } - - /// <summary>Notifies the current synchronization context that the operation completed.</summary> - private void NotifySynchronizationContextOfCompletion() - { - Debug.Assert(_synchronizationContext != null, "Must only be used with a non-null context."); - try - { - _synchronizationContext.OperationCompleted(); - } - catch (Exception exc) - { - // If the interaction with the SynchronizationContext goes awry, - // fall back to propagating on the ThreadPool. - Task.ThrowAsync(exc, targetContext: null); - } - } - - /// <summary>Lazily instantiate the Task in a non-thread-safe manner.</summary> - private Task Task => _builder.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> - internal object ObjectIdForDebugger => _builder.ObjectIdForDebugger; - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/CallerArgumentExpressionAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/CallerArgumentExpressionAttribute.cs deleted file mode 100644 index 6e1c4c56cd0..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/CallerArgumentExpressionAttribute.cs +++ /dev/null @@ -1,17 +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 -{ - [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] - public sealed class CallerArgumentExpressionAttribute : Attribute - { - public CallerArgumentExpressionAttribute(string parameterName) - { - ParameterName = parameterName; - } - - public string ParameterName { get; } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/CallerFilePathAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/CallerFilePathAttribute.cs deleted file mode 100644 index 5858634b427..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/CallerFilePathAttribute.cs +++ /dev/null @@ -1,14 +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 -{ - [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] - public sealed class CallerFilePathAttribute : Attribute - { - public CallerFilePathAttribute() - { - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/CallerLineNumberAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/CallerLineNumberAttribute.cs deleted file mode 100644 index 5bd2fcb91b9..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/CallerLineNumberAttribute.cs +++ /dev/null @@ -1,14 +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 -{ - [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] - public sealed class CallerLineNumberAttribute : Attribute - { - public CallerLineNumberAttribute() - { - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/CallerMemberNameAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/CallerMemberNameAttribute.cs deleted file mode 100644 index 8b046335b5a..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/CallerMemberNameAttribute.cs +++ /dev/null @@ -1,14 +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 -{ - [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] - public sealed class CallerMemberNameAttribute : Attribute - { - public CallerMemberNameAttribute() - { - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/CompilationRelaxations.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/CompilationRelaxations.cs deleted file mode 100644 index 2d1763327ac..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/CompilationRelaxations.cs +++ /dev/null @@ -1,15 +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 -{ - /// IMPORTANT: Keep this in sync with corhdr.h - [Flags] - public enum CompilationRelaxations : int - { - NoStringInterning = 0x0008 // Start in 0x0008, we had other non public flags in this enum before, - // so we'll start here just in case somebody used them. This flag is only - // valid when set for Assemblies. - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/CompilationRelaxationsAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/CompilationRelaxationsAttribute.cs deleted file mode 100644 index d6da23fdf2a..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/CompilationRelaxationsAttribute.cs +++ /dev/null @@ -1,22 +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 -{ - [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Method)] - public class CompilationRelaxationsAttribute : Attribute - { - public CompilationRelaxationsAttribute(int relaxations) - { - CompilationRelaxations = relaxations; - } - - public CompilationRelaxationsAttribute(CompilationRelaxations relaxations) - { - CompilationRelaxations = (int)relaxations; - } - - public int CompilationRelaxations { get; } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/CompilerGeneratedAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/CompilerGeneratedAttribute.cs deleted file mode 100644 index 1c05abd1fec..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/CompilerGeneratedAttribute.cs +++ /dev/null @@ -1,12 +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 -{ - [AttributeUsage(AttributeTargets.All, Inherited = true)] - public sealed class CompilerGeneratedAttribute : Attribute - { - public CompilerGeneratedAttribute() { } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/CompilerGlobalScopeAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/CompilerGlobalScopeAttribute.cs deleted file mode 100644 index 542181ce91f..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/CompilerGlobalScopeAttribute.cs +++ /dev/null @@ -1,14 +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 -{ - // Attribute used to communicate to the VS7 debugger that a class should be treated as if it has global scope. - - [AttributeUsage(AttributeTargets.Class)] - public class CompilerGlobalScopeAttribute : Attribute - { - public CompilerGlobalScopeAttribute() { } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConditionalWeakTable.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConditionalWeakTable.cs deleted file mode 100644 index ae749f45b8d..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConditionalWeakTable.cs +++ /dev/null @@ -1,806 +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; -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Threading; -using Internal.Runtime.CompilerServices; - -namespace System.Runtime.CompilerServices -{ - public sealed class ConditionalWeakTable<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>> - where TKey : class - where TValue : class? - { - // Lifetimes of keys and values: - // Inserting a key and value into the dictonary will not - // prevent the key from dying, even if the key is strongly reachable - // from the value. Once the key dies, the dictionary automatically removes - // the key/value entry. - // - // Thread safety guarantees: - // ConditionalWeakTable is fully thread-safe and requires no - // additional locking to be done by callers. - // - // OOM guarantees: - // Will not corrupt unmanaged handle table on OOM. No guarantees - // about managed weak table consistency. Native handles reclamation - // may be delayed until appdomain shutdown. - - private const int InitialCapacity = 8; // Initial length of the table. Must be a power of two. - private readonly object _lock; // This lock protects all mutation of data in the table. Readers do not take this lock. - private volatile Container _container; // The actual storage for the table; swapped out as the table grows. - private int _activeEnumeratorRefCount; // The number of outstanding enumerators on the table - - public ConditionalWeakTable() - { - _lock = new object(); - _container = new Container(this); - } - - /// <summary>Gets the value of the specified key.</summary> - /// <param name="key">key of the value to find. Cannot be null.</param> - /// <param name="value"> - /// If the key is found, contains the value associated with the key upon method return. - /// If the key is not found, contains default(TValue). - /// </param> - /// <returns>Returns "true" if key was found, "false" otherwise.</returns> - /// <remarks> - /// The key may get garbaged collected during the TryGetValue operation. If so, TryGetValue - /// may at its discretion, return "false" and set "value" to the default (as if the key was not present.) - /// </remarks> - public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) - { - if (key is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); - } - - return _container.TryGetValueWorker(key, out value); - } - - /// <summary>Adds a key to the table.</summary> - /// <param name="key">key to add. May not be null.</param> - /// <param name="value">value to associate with key.</param> - /// <remarks> - /// If the key is already entered into the dictionary, this method throws an exception. - /// The key may get garbage collected during the Add() operation. If so, Add() - /// has the right to consider any prior entries successfully removed and add a new entry without - /// throwing an exception. - /// </remarks> - public void Add(TKey key, TValue value) - { - if (key is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); - } - - lock (_lock) - { - int entryIndex = _container.FindEntry(key, out _); - if (entryIndex != -1) - { - ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_AddingDuplicate); - } - - CreateEntry(key, value); - } - } - - /// <summary>Adds the key and value if the key doesn't exist, or updates the existing key's value if it does exist.</summary> - /// <param name="key">key to add or update. May not be null.</param> - /// <param name="value">value to associate with key.</param> - public void AddOrUpdate(TKey key, TValue value) - { - if (key is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); - } - - lock (_lock) - { - int entryIndex = _container.FindEntry(key, out _); - - // if we found a key we should just update, if no we should create a new entry. - if (entryIndex != -1) - { - _container.UpdateValue(entryIndex, value); - } - else - { - CreateEntry(key, value); - } - } - } - - /// <summary>Removes a key and its value from the table.</summary> - /// <param name="key">key to remove. May not be null.</param> - /// <returns>true if the key is found and removed. Returns false if the key was not in the dictionary.</returns> - /// <remarks> - /// The key may get garbage collected during the Remove() operation. If so, - /// Remove() will not fail or throw, however, the return value can be either true or false - /// depending on who wins the race. - /// </remarks> - public bool Remove(TKey key) - { - if (key is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); - } - - lock (_lock) - { - return _container.Remove(key); - } - } - - /// <summary>Clear all the key/value pairs</summary> - public void Clear() - { - lock (_lock) - { - // To clear, we would prefer to simply drop the existing container - // and replace it with an empty one, as that's overall more efficient. - // However, if there are any active enumerators, we don't want to do - // that as it will end up removing all of the existing entries and - // allowing new items to be added at the same indices when the container - // is filled and replaced, and one of the guarantees we try to make with - // enumeration is that new items added after enumeration starts won't be - // included in the enumeration. As such, if there are active enumerators, - // we simply use the container's removal functionality to remove all of the - // keys; then when the table is resized, if there are still active enumerators, - // these empty slots will be maintained. - if (_activeEnumeratorRefCount > 0) - { - _container.RemoveAllKeys(); - } - else - { - _container = new Container(this); - } - } - } - - /// <summary> - /// Atomically searches for a specified key in the table and returns the corresponding value. - /// If the key does not exist in the table, the method invokes a callback method to create a - /// value that is bound to the specified key. - /// </summary> - /// <param name="key">key of the value to find. Cannot be null.</param> - /// <param name="createValueCallback">callback that creates value for key. Cannot be null.</param> - /// <returns></returns> - /// <remarks> - /// If multiple threads try to initialize the same key, the table may invoke createValueCallback - /// multiple times with the same key. Exactly one of these calls will succeed and the returned - /// value of that call will be the one added to the table and returned by all the racing GetValue() calls. - /// This rule permits the table to invoke createValueCallback outside the internal table lock - /// to prevent deadlocks. - /// </remarks> - public TValue GetValue(TKey key, CreateValueCallback createValueCallback) - { - // key is validated by TryGetValue - - if (createValueCallback is null) - { - throw new ArgumentNullException(nameof(createValueCallback)); - } - - return TryGetValue(key, out TValue existingValue) ? - existingValue : - GetValueLocked(key, createValueCallback); - } - - private TValue GetValueLocked(TKey key, CreateValueCallback createValueCallback) - { - // If we got here, the key was not in the table. Invoke the callback (outside the lock) - // to generate the new value for the key. - TValue newValue = createValueCallback(key); - - lock (_lock) - { - // Now that we've taken the lock, must recheck in case we lost a race to add the key. - if (_container.TryGetValueWorker(key, out TValue existingValue)) - { - return existingValue; - } - else - { - // Verified in-lock that we won the race to add the key. Add it now. - CreateEntry(key, newValue); - return newValue; - } - } - } - - /// <summary> - /// Helper method to call GetValue without passing a creation delegate. Uses Activator.CreateInstance - /// to create new instances as needed. If TValue does not have a default constructor, this will throw. - /// </summary> - /// <param name="key">key of the value to find. Cannot be null.</param> - public TValue GetOrCreateValue(TKey key) => GetValue(key, _ => Activator.CreateInstance<TValue>()); - - public delegate TValue CreateValueCallback(TKey key); - - /// <summary>Gets an enumerator for the table.</summary> - /// <remarks> - /// The returned enumerator will not extend the lifetime of - /// any object pairs in the table, other than the one that's Current. It will not return entries - /// that have already been collected, nor will it return entries added after the enumerator was - /// retrieved. It may not return all entries that were present when the enumerat was retrieved, - /// however, such as not returning entries that were collected or removed after the enumerator - /// was retrieved but before they were enumerated. - /// </remarks> - IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator() - { - lock (_lock) - { - Container c = _container; - return c is null || c.FirstFreeEntry == 0 ? - ((IEnumerable<KeyValuePair<TKey, TValue>>)Array.Empty<KeyValuePair<TKey, TValue>>()).GetEnumerator() : - new Enumerator(this); - } - } - - IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable<KeyValuePair<TKey, TValue>>)this).GetEnumerator(); - - /// <summary>Provides an enumerator for the table.</summary> - private sealed class Enumerator : IEnumerator<KeyValuePair<TKey, TValue>> - { - // The enumerator would ideally hold a reference to the Container and the end index within that - // container. However, the safety of the CWT depends on the only reference to the Container being - // from the CWT itself; the Container then employs a two-phase finalization scheme, where the first - // phase nulls out that parent CWT's reference, guaranteeing that the second time it's finalized there - // can be no other existing references to it in use that would allow for concurrent usage of the - // native handles with finalization. We would break that if we allowed this Enumerator to hold a - // reference to the Container. Instead, the Enumerator holds a reference to the CWT rather than to - // the Container, and it maintains the CWT._activeEnumeratorRefCount field to track whether there - // are outstanding enumerators that have yet to be disposed/finalized. If there aren't any, the CWT - // behaves as it normally does. If there are, certain operations are affected, in particular resizes. - // Normally when the CWT is resized, it enumerates the contents of the table looking for indices that - // contain entries which have been collected or removed, and it frees those up, effectively moving - // down all subsequent entries in the container (not in the existing container, but in a replacement). - // This, however, would cause the enumerator's understanding of indices to break. So, as long as - // there is any outstanding enumerator, no compaction is performed. - - private ConditionalWeakTable<TKey, TValue>? _table; // parent table, set to null when disposed - private readonly int _maxIndexInclusive; // last index in the container that should be enumerated - private int _currentIndex; // the current index into the container - private KeyValuePair<TKey, TValue> _current; // the current entry set by MoveNext and returned from Current - - public Enumerator(ConditionalWeakTable<TKey, TValue> table) - { - Debug.Assert(table != null, "Must provide a valid table"); - Debug.Assert(Monitor.IsEntered(table._lock), "Must hold the _lock lock to construct the enumerator"); - Debug.Assert(table._container != null, "Should not be used on a finalized table"); - Debug.Assert(table._container.FirstFreeEntry > 0, "Should have returned an empty enumerator instead"); - - // Store a reference to the parent table and increase its active enumerator count. - _table = table; - Debug.Assert(table._activeEnumeratorRefCount >= 0, "Should never have a negative ref count before incrementing"); - table._activeEnumeratorRefCount++; - - // Store the max index to be enumerated. - _maxIndexInclusive = table._container.FirstFreeEntry - 1; - _currentIndex = -1; - } - - ~Enumerator() - { - Dispose(); - } - - public void Dispose() - { - // Use an interlocked operation to ensure that only one thread can get access to - // the _table for disposal and thus only decrement the ref count once. - ConditionalWeakTable<TKey, TValue>? table = Interlocked.Exchange(ref _table, null); - if (table != null) - { - // Ensure we don't keep the last current alive unnecessarily - _current = default; - - // Decrement the ref count that was incremented when constructed - lock (table._lock) - { - table._activeEnumeratorRefCount--; - Debug.Assert(table._activeEnumeratorRefCount >= 0, "Should never have a negative ref count after decrementing"); - } - - // Finalization is purely to decrement the ref count. We can suppress it now. - GC.SuppressFinalize(this); - } - } - - public bool MoveNext() - { - // Start by getting the current table. If it's already been disposed, it will be null. - ConditionalWeakTable<TKey, TValue>? table = _table; - if (table != null) - { - // Once have the table, we need to lock to synchronize with other operations on - // the table, like adding. - lock (table._lock) - { - // From the table, we have to get the current container. This could have changed - // since we grabbed the enumerator, but the index-to-pair mapping should not have - // due to there being at least one active enumerator. If the table (or rather its - // container at the time) has already been finalized, this will be null. - Container c = table._container; - if (c != null) - { - // We have the container. Find the next entry to return, if there is one. - // We need to loop as we may try to get an entry that's already been removed - // or collected, in which case we try again. - while (_currentIndex < _maxIndexInclusive) - { - _currentIndex++; - if (c.TryGetEntry(_currentIndex, out TKey? key, out TValue value)) - { - _current = new KeyValuePair<TKey, TValue>(key, value); - return true; - } - } - } - } - } - - // Nothing more to enumerate. - return false; - } - - public KeyValuePair<TKey, TValue> Current - { - get - { - if (_currentIndex < 0) - { - ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen(); - } - return _current; - } - } - - object? IEnumerator.Current => Current; - - public void Reset() { } - } - - /// <summary>Worker for adding a new key/value pair. Will resize the container if it is full.</summary> - /// <param name="key"></param> - /// <param name="value"></param> - private void CreateEntry(TKey key, TValue value) - { - Debug.Assert(Monitor.IsEntered(_lock)); - Debug.Assert(key != null); // key already validated as non-null and not already in table. - - Container c = _container; - if (!c.HasCapacity) - { - _container = c = c.Resize(); - } - c.CreateEntryNoResize(key, value); - } - - private static bool IsPowerOfTwo(int value) => (value > 0) && ((value & (value - 1)) == 0); - - //-------------------------------------------------------------------------------------------- - // Entry can be in one of four states: - // - // - Unused (stored with an index _firstFreeEntry and above) - // depHnd.IsAllocated == false - // hashCode == <dontcare> - // next == <dontcare>) - // - // - Used with live key (linked into a bucket list where _buckets[hashCode & (_buckets.Length - 1)] points to first entry) - // depHnd.IsAllocated == true, depHnd.GetPrimary() != null - // hashCode == RuntimeHelpers.GetHashCode(depHnd.GetPrimary()) & int.MaxValue - // next links to next Entry in bucket. - // - // - Used with dead key (linked into a bucket list where _buckets[hashCode & (_buckets.Length - 1)] points to first entry) - // depHnd.IsAllocated == true, depHnd.GetPrimary() is null - // hashCode == <notcare> - // next links to next Entry in bucket. - // - // - Has been removed from the table (by a call to Remove) - // depHnd.IsAllocated == true, depHnd.GetPrimary() == <notcare> - // hashCode == -1 - // next links to next Entry in bucket. - // - // The only difference between "used with live key" and "used with dead key" is that - // depHnd.GetPrimary() returns null. The transition from "used with live key" to "used with dead key" - // happens asynchronously as a result of normal garbage collection. The dictionary itself - // receives no notification when this happens. - // - // When the dictionary grows the _entries table, it scours it for expired keys and does not - // add those to the new container. - //-------------------------------------------------------------------------------------------- - private struct Entry - { - public DependentHandle depHnd; // Holds key and value using a weak reference for the key and a strong reference - // for the value that is traversed only if the key is reachable without going through the value. - public int HashCode; // Cached copy of key's hashcode - public int Next; // Index of next entry, -1 if last - } - - /// <summary> - /// Container holds the actual data for the table. A given instance of Container always has the same capacity. When we need - /// more capacity, we create a new Container, copy the old one into the new one, and discard the old one. This helps enable lock-free - /// reads from the table, as readers never need to deal with motion of entries due to rehashing. - /// </summary> - private sealed class Container - { - private readonly ConditionalWeakTable<TKey, TValue> _parent; // the ConditionalWeakTable with which this container is associated - private int[] _buckets; // _buckets[hashcode & (_buckets.Length - 1)] contains index of the first entry in bucket (-1 if empty) - private Entry[] _entries; // the table entries containing the stored dependency handles - private int _firstFreeEntry; // _firstFreeEntry < _entries.Length => table has capacity, entries grow from the bottom of the table. - private bool _invalid; // flag detects if OOM or other background exception threw us out of the lock. - private bool _finalized; // set to true when initially finalized - private volatile object? _oldKeepAlive; // used to ensure the next allocated container isn't finalized until this one is GC'd - - internal Container(ConditionalWeakTable<TKey, TValue> parent) - { - Debug.Assert(parent != null); - Debug.Assert(IsPowerOfTwo(InitialCapacity)); - - const int Size = InitialCapacity; - _buckets = new int[Size]; - for (int i = 0; i < _buckets.Length; i++) - { - _buckets[i] = -1; - } - _entries = new Entry[Size]; - - // Only store the parent after all of the allocations have happened successfully. - // Otherwise, as part of growing or clearing the container, we could end up allocating - // a new Container that fails (OOMs) part way through construction but that gets finalized - // and ends up clearing out some other container present in the associated CWT. - _parent = parent; - } - - private Container(ConditionalWeakTable<TKey, TValue> parent, int[] buckets, Entry[] entries, int firstFreeEntry) - { - Debug.Assert(parent != null); - Debug.Assert(buckets != null); - Debug.Assert(entries != null); - Debug.Assert(buckets.Length == entries.Length); - Debug.Assert(IsPowerOfTwo(buckets.Length)); - - _parent = parent; - _buckets = buckets; - _entries = entries; - _firstFreeEntry = firstFreeEntry; - } - - internal bool HasCapacity => _firstFreeEntry < _entries.Length; - - internal int FirstFreeEntry => _firstFreeEntry; - - /// <summary>Worker for adding a new key/value pair. Container must NOT be full.</summary> - internal void CreateEntryNoResize(TKey key, TValue value) - { - Debug.Assert(key != null); // key already validated as non-null and not already in table. - Debug.Assert(HasCapacity); - - VerifyIntegrity(); - _invalid = true; - - int hashCode = RuntimeHelpers.GetHashCode(key) & int.MaxValue; - int newEntry = _firstFreeEntry++; - - _entries[newEntry].HashCode = hashCode; - _entries[newEntry].depHnd = new DependentHandle(key, value); - int bucket = hashCode & (_buckets.Length - 1); - _entries[newEntry].Next = _buckets[bucket]; - - // This write must be volatile, as we may be racing with concurrent readers. If they see - // the new entry, they must also see all of the writes earlier in this method. - Volatile.Write(ref _buckets[bucket], newEntry); - - _invalid = false; - } - - /// <summary>Worker for finding a key/value pair. Must hold _lock.</summary> - internal bool TryGetValueWorker(TKey key, [MaybeNullWhen(false)] out TValue value) - { - Debug.Assert(key != null); // Key already validated as non-null - - int entryIndex = FindEntry(key, out object? secondary); - value = Unsafe.As<TValue>(secondary); - return entryIndex != -1; - } - - /// <summary> - /// Returns -1 if not found (if key expires during FindEntry, this can be treated as "not found."). - /// Must hold _lock, or be prepared to retry the search while holding _lock. - /// </summary> - internal int FindEntry(TKey key, out object? value) - { - Debug.Assert(key != null); // Key already validated as non-null. - - int hashCode = RuntimeHelpers.GetHashCode(key) & int.MaxValue; - int bucket = hashCode & (_buckets.Length - 1); - for (int entriesIndex = Volatile.Read(ref _buckets[bucket]); entriesIndex != -1; entriesIndex = _entries[entriesIndex].Next) - { - if (_entries[entriesIndex].HashCode == hashCode && _entries[entriesIndex].depHnd.GetPrimaryAndSecondary(out value) == key) - { - GC.KeepAlive(this); // ensure we don't get finalized while accessing DependentHandles. - return entriesIndex; - } - } - - GC.KeepAlive(this); // ensure we don't get finalized while accessing DependentHandles. - value = null; - return -1; - } - - /// <summary>Gets the entry at the specified entry index.</summary> - internal bool TryGetEntry(int index, [NotNullWhen(true)] out TKey? key, [MaybeNullWhen(false)] out TValue value) - { - if (index < _entries.Length) - { - object? oKey = _entries[index].depHnd.GetPrimaryAndSecondary(out object? oValue); - GC.KeepAlive(this); // ensure we don't get finalized while accessing DependentHandles. - - if (oKey != null) - { - key = Unsafe.As<TKey>(oKey); - value = Unsafe.As<TValue>(oValue); - return true; - } - } - - key = default; - value = default!; - return false; - } - - /// <summary>Removes all of the keys in the table.</summary> - internal void RemoveAllKeys() - { - for (int i = 0; i < _firstFreeEntry; i++) - { - RemoveIndex(i); - } - } - - /// <summary>Removes the specified key from the table, if it exists.</summary> - internal bool Remove(TKey key) - { - VerifyIntegrity(); - - int entryIndex = FindEntry(key, out _); - if (entryIndex != -1) - { - RemoveIndex(entryIndex); - return true; - } - - return false; - } - - private void RemoveIndex(int entryIndex) - { - Debug.Assert(entryIndex >= 0 && entryIndex < _firstFreeEntry); - - ref Entry entry = ref _entries[entryIndex]; - - // We do not free the handle here, as we may be racing with readers who already saw the hash code. - // Instead, we simply overwrite the entry's hash code, so subsequent reads will ignore it. - // The handle will be free'd in Container's finalizer, after the table is resized or discarded. - Volatile.Write(ref entry.HashCode, -1); - - // Also, clear the key to allow GC to collect objects pointed to by the entry - entry.depHnd.SetPrimary(null); - } - - internal void UpdateValue(int entryIndex, TValue newValue) - { - Debug.Assert(entryIndex != -1); - - VerifyIntegrity(); - _invalid = true; - - _entries[entryIndex].depHnd.SetSecondary(newValue); - - _invalid = false; - } - - /// <summary>Resize, and scrub expired keys off bucket lists. Must hold _lock.</summary> - /// <remarks> - /// _firstEntry is less than _entries.Length on exit, that is, the table has at least one free entry. - /// </remarks> - internal Container Resize() - { - Debug.Assert(!HasCapacity); - - bool hasExpiredEntries = false; - int newSize = _buckets.Length; - - if (_parent is null || _parent._activeEnumeratorRefCount == 0) - { - // If any expired or removed keys exist, we won't resize. - // If there any active enumerators, though, we don't want - // to compact and thus have no expired entries. - for (int entriesIndex = 0; entriesIndex < _entries.Length; entriesIndex++) - { - ref Entry entry = ref _entries[entriesIndex]; - - if (entry.HashCode == -1) - { - // the entry was removed - hasExpiredEntries = true; - break; - } - - if (entry.depHnd.IsAllocated && entry.depHnd.GetPrimary() is null) - { - // the entry has expired - hasExpiredEntries = true; - break; - } - } - } - - if (!hasExpiredEntries) - { - // Not necessary to check for overflow here, the attempt to allocate new arrays will throw - newSize = _buckets.Length * 2; - } - - return Resize(newSize); - } - - internal Container Resize(int newSize) - { - Debug.Assert(newSize >= _buckets.Length); - Debug.Assert(IsPowerOfTwo(newSize)); - - // Reallocate both buckets and entries and rebuild the bucket and entries from scratch. - // This serves both to scrub entries with expired keys and to put the new entries in the proper bucket. - int[] newBuckets = new int[newSize]; - for (int bucketIndex = 0; bucketIndex < newBuckets.Length; bucketIndex++) - { - newBuckets[bucketIndex] = -1; - } - Entry[] newEntries = new Entry[newSize]; - int newEntriesIndex = 0; - bool activeEnumerators = _parent != null && _parent._activeEnumeratorRefCount > 0; - - // Migrate existing entries to the new table. - if (activeEnumerators) - { - // There's at least one active enumerator, which means we don't want to - // remove any expired/removed entries, in order to not affect existing - // entries indices. Copy over the entries while rebuilding the buckets list, - // as the buckets are dependent on the buckets list length, which is changing. - for (; newEntriesIndex < _entries.Length; newEntriesIndex++) - { - ref Entry oldEntry = ref _entries[newEntriesIndex]; - ref Entry newEntry = ref newEntries[newEntriesIndex]; - int hashCode = oldEntry.HashCode; - - newEntry.HashCode = hashCode; - newEntry.depHnd = oldEntry.depHnd; - int bucket = hashCode & (newBuckets.Length - 1); - newEntry.Next = newBuckets[bucket]; - newBuckets[bucket] = newEntriesIndex; - } - } - else - { - // There are no active enumerators, which means we want to compact by - // removing expired/removed entries. - for (int entriesIndex = 0; entriesIndex < _entries.Length; entriesIndex++) - { - ref Entry oldEntry = ref _entries[entriesIndex]; - int hashCode = oldEntry.HashCode; - DependentHandle depHnd = oldEntry.depHnd; - if (hashCode != -1 && depHnd.IsAllocated) - { - if (depHnd.GetPrimary() != null) - { - ref Entry newEntry = ref newEntries[newEntriesIndex]; - - // Entry is used and has not expired. Link it into the appropriate bucket list. - newEntry.HashCode = hashCode; - newEntry.depHnd = depHnd; - int bucket = hashCode & (newBuckets.Length - 1); - newEntry.Next = newBuckets[bucket]; - newBuckets[bucket] = newEntriesIndex; - newEntriesIndex++; - } - else - { - // Pretend the item was removed, so that this container's finalizer - // will clean up this dependent handle. - Volatile.Write(ref oldEntry.HashCode, -1); - } - } - } - } - - // Create the new container. We want to transfer the responsibility of freeing the handles from - // the old container to the new container, and also ensure that the new container isn't finalized - // while the old container may still be in use. As such, we store a reference from the old container - // to the new one, which will keep the new container alive as long as the old one is. - var newContainer = new Container(_parent!, newBuckets, newEntries, newEntriesIndex); - if (activeEnumerators) - { - // If there are active enumerators, both the old container and the new container may be storing - // the same entries with -1 hash codes, which the finalizer will clean up even if the container - // is not the active container for the table. To prevent that, we want to stop the old container - // from being finalized, as it no longer has any responsibility for any cleanup. - GC.SuppressFinalize(this); - } - _oldKeepAlive = newContainer; // once this is set, the old container's finalizer will not free transferred dependent handles - - GC.KeepAlive(this); // ensure we don't get finalized while accessing DependentHandles. - - return newContainer; - } - - private void VerifyIntegrity() - { - if (_invalid) - { - throw new InvalidOperationException(SR.InvalidOperation_CollectionCorrupted); - } - } - - ~Container() - { - // Skip doing anything if the container is invalid, including if somehow - // the container object was allocated but its associated table never set. - if (_invalid || _parent is null) - { - return; - } - - // It's possible that the ConditionalWeakTable could have been resurrected, in which case code could - // be accessing this Container as it's being finalized. We don't support usage after finalization, - // but we also don't want to potentially corrupt state by allowing dependency handles to be used as - // or after they've been freed. To avoid that, if it's at all possible that another thread has a - // reference to this container via the CWT, we remove such a reference and then re-register for - // finalization: the next time around, we can be sure that no references remain to this and we can - // clean up the dependency handles without fear of corruption. - if (!_finalized) - { - _finalized = true; - lock (_parent._lock) - { - if (_parent._container == this) - { - _parent._container = null!; - } - } - GC.ReRegisterForFinalize(this); // next time it's finalized, we'll be sure there are no remaining refs - return; - } - - Entry[] entries = _entries; - _invalid = true; - _entries = null!; - _buckets = null!; - - if (entries != null) - { - for (int entriesIndex = 0; entriesIndex < entries.Length; entriesIndex++) - { - // We need to free handles in two cases: - // - If this container still owns the dependency handle (meaning ownership hasn't been transferred - // to another container that replaced this one), then it should be freed. - // - If this container had the entry removed, then even if in general ownership was transferred to - // another container, removed entries are not, therefore this container must free them. - if (_oldKeepAlive is null || entries[entriesIndex].HashCode == -1) - { - entries[entriesIndex].depHnd.Free(); - } - } - } - } - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConfiguredAsyncDisposable.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConfiguredAsyncDisposable.cs deleted file mode 100644 index aa5e882dc65..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConfiguredAsyncDisposable.cs +++ /dev/null @@ -1,27 +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; - -namespace System.Runtime.CompilerServices -{ - /// <summary>Provides a type that can be used to configure how awaits on an <see cref="IAsyncDisposable"/> are performed.</summary> - [StructLayout(LayoutKind.Auto)] - public readonly struct ConfiguredAsyncDisposable - { - private readonly IAsyncDisposable _source; - private readonly bool _continueOnCapturedContext; - - internal ConfiguredAsyncDisposable(IAsyncDisposable source, bool continueOnCapturedContext) - { - _source = source; - _continueOnCapturedContext = continueOnCapturedContext; - } - - public ConfiguredValueTaskAwaitable DisposeAsync() => - // as with other "configured" awaitable-related type in CompilerServices, we don't null check to defend against - // misuse like `default(ConfiguredAsyncDisposable).DisposeAsync()`, which will null ref by design. - _source.DisposeAsync().ConfigureAwait(_continueOnCapturedContext); - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConfiguredCancelableAsyncEnumerable.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConfiguredCancelableAsyncEnumerable.cs deleted file mode 100644 index 4f1bca71695..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConfiguredCancelableAsyncEnumerable.cs +++ /dev/null @@ -1,78 +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.Runtime.InteropServices; -using System.Threading; - -namespace System.Runtime.CompilerServices -{ - /// <summary>Provides an awaitable async enumerable that enables cancelable iteration and configured awaits.</summary> - [StructLayout(LayoutKind.Auto)] - public readonly struct ConfiguredCancelableAsyncEnumerable<T> - { - private readonly IAsyncEnumerable<T> _enumerable; - private readonly CancellationToken _cancellationToken; - private readonly bool _continueOnCapturedContext; - - internal ConfiguredCancelableAsyncEnumerable(IAsyncEnumerable<T> enumerable, bool continueOnCapturedContext, CancellationToken cancellationToken) - { - _enumerable = enumerable; - _continueOnCapturedContext = continueOnCapturedContext; - _cancellationToken = cancellationToken; - } - - /// <summary>Configures how awaits on the tasks returned from an async iteration will be performed.</summary> - /// <param name="continueOnCapturedContext">Whether to capture and marshal back to the current context.</param> - /// <returns>The configured enumerable.</returns> - /// <remarks>This will replace any previous value set by <see cref="ConfigureAwait(bool)"/> for this iteration.</remarks> - public ConfiguredCancelableAsyncEnumerable<T> ConfigureAwait(bool continueOnCapturedContext) => - new ConfiguredCancelableAsyncEnumerable<T>(_enumerable, continueOnCapturedContext, _cancellationToken); - - /// <summary>Sets the <see cref="CancellationToken"/> to be passed to <see cref="IAsyncEnumerable{T}.GetAsyncEnumerator(CancellationToken)"/> when iterating.</summary> - /// <param name="cancellationToken">The <see cref="CancellationToken"/> to use.</param> - /// <returns>The configured enumerable.</returns> - /// <remarks>This will replace any previous <see cref="CancellationToken"/> set by <see cref="WithCancellation(CancellationToken)"/> for this iteration.</remarks> - public ConfiguredCancelableAsyncEnumerable<T> WithCancellation(CancellationToken cancellationToken) => - new ConfiguredCancelableAsyncEnumerable<T>(_enumerable, _continueOnCapturedContext, cancellationToken); - - public Enumerator GetAsyncEnumerator() => - // as with other "configured" awaitable-related type in CompilerServices, we don't null check to defend against - // misuse like `default(ConfiguredCancelableAsyncEnumerable<T>).GetAsyncEnumerator()`, which will null ref by design. - new Enumerator(_enumerable.GetAsyncEnumerator(_cancellationToken), _continueOnCapturedContext); - - /// <summary>Provides an awaitable async enumerator that enables cancelable iteration and configured awaits.</summary> - [StructLayout(LayoutKind.Auto)] - public readonly struct Enumerator - { - private readonly IAsyncEnumerator<T> _enumerator; - private readonly bool _continueOnCapturedContext; - - internal Enumerator(IAsyncEnumerator<T> enumerator, bool continueOnCapturedContext) - { - _enumerator = enumerator; - _continueOnCapturedContext = continueOnCapturedContext; - } - - /// <summary>Advances the enumerator asynchronously to the next element of the collection.</summary> - /// <returns> - /// A <see cref="ConfiguredValueTaskAwaitable{Boolean}"/> that will complete with a result of <c>true</c> - /// if the enumerator was successfully advanced to the next element, or <c>false</c> if the enumerator has - /// passed the end of the collection. - /// </returns> - public ConfiguredValueTaskAwaitable<bool> MoveNextAsync() => - _enumerator.MoveNextAsync().ConfigureAwait(_continueOnCapturedContext); - - /// <summary>Gets the element in the collection at the current position of the enumerator.</summary> - public T Current => _enumerator.Current; - - /// <summary> - /// Performs application-defined tasks associated with freeing, releasing, or - /// resetting unmanaged resources asynchronously. - /// </summary> - public ConfiguredValueTaskAwaitable DisposeAsync() => - _enumerator.DisposeAsync().ConfigureAwait(_continueOnCapturedContext); - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs deleted file mode 100644 index 493269218df..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs +++ /dev/null @@ -1,225 +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.Diagnostics; -using System.Runtime.InteropServices; -using System.Threading; -using System.Threading.Tasks; -using System.Threading.Tasks.Sources; - -#if !NETSTANDARD2_0 -using Internal.Runtime.CompilerServices; -#endif - -namespace System.Runtime.CompilerServices -{ - /// <summary>Provides an awaitable type that enables configured awaits on a <see cref="ValueTask"/>.</summary> - [StructLayout(LayoutKind.Auto)] - public readonly struct ConfiguredValueTaskAwaitable - { - /// <summary>The wrapped <see cref="Task"/>.</summary> - private readonly ValueTask _value; - - /// <summary>Initializes the awaitable.</summary> - /// <param name="value">The wrapped <see cref="ValueTask"/>.</param> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ConfiguredValueTaskAwaitable(in ValueTask value) => _value = value; - - /// <summary>Returns an awaiter for this <see cref="ConfiguredValueTaskAwaitable"/> instance.</summary> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ConfiguredValueTaskAwaiter GetAwaiter() => new ConfiguredValueTaskAwaiter(in _value); - - /// <summary>Provides an awaiter for a <see cref="ConfiguredValueTaskAwaitable"/>.</summary> - [StructLayout(LayoutKind.Auto)] - public readonly struct ConfiguredValueTaskAwaiter : ICriticalNotifyCompletion, IStateMachineBoxAwareAwaiter - { - /// <summary>The value being awaited.</summary> - private readonly ValueTask _value; - - /// <summary>Initializes the awaiter.</summary> - /// <param name="value">The value to be awaited.</param> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ConfiguredValueTaskAwaiter(in ValueTask value) => _value = value; - - /// <summary>Gets whether the <see cref="ConfiguredValueTaskAwaitable"/> has completed.</summary> - public bool IsCompleted - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _value.IsCompleted; - } - - /// <summary>Gets the result of the ValueTask.</summary> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void GetResult() => _value.ThrowIfCompletedUnsuccessfully(); - - /// <summary>Schedules the continuation action for the <see cref="ConfiguredValueTaskAwaitable"/>.</summary> - public void OnCompleted(Action continuation) - { - object? obj = _value._obj; - Debug.Assert(obj == null || obj is Task || obj is IValueTaskSource); - - if (obj is Task t) - { - t.ConfigureAwait(_value._continueOnCapturedContext).GetAwaiter().OnCompleted(continuation); - } - else if (obj != null) - { - Unsafe.As<IValueTaskSource>(obj).OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, - ValueTaskSourceOnCompletedFlags.FlowExecutionContext | - (_value._continueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None)); - } - else - { - ValueTask.CompletedTask.ConfigureAwait(_value._continueOnCapturedContext).GetAwaiter().OnCompleted(continuation); - } - } - - /// <summary>Schedules the continuation action for the <see cref="ConfiguredValueTaskAwaitable"/>.</summary> - public void UnsafeOnCompleted(Action continuation) - { - object? obj = _value._obj; - Debug.Assert(obj == null || obj is Task || obj is IValueTaskSource); - - if (obj is Task t) - { - t.ConfigureAwait(_value._continueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation); - } - else if (obj != null) - { - Unsafe.As<IValueTaskSource>(obj).OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, - _value._continueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None); - } - else - { - ValueTask.CompletedTask.ConfigureAwait(_value._continueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation); - } - } - - void IStateMachineBoxAwareAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox box) - { - object? obj = _value._obj; - Debug.Assert(obj == null || obj is Task || obj is IValueTaskSource); - - if (obj is Task t) - { - TaskAwaiter.UnsafeOnCompletedInternal(t, box, _value._continueOnCapturedContext); - } - else if (obj != null) - { - Unsafe.As<IValueTaskSource>(obj).OnCompleted(ThreadPoolGlobals.s_invokeAsyncStateMachineBox, box, _value._token, - _value._continueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None); - } - else - { - TaskAwaiter.UnsafeOnCompletedInternal(Task.CompletedTask, box, _value._continueOnCapturedContext); - } - } - } - } - - /// <summary>Provides an awaitable type that enables configured awaits on a <see cref="ValueTask{TResult}"/>.</summary> - /// <typeparam name="TResult">The type of the result produced.</typeparam> - [StructLayout(LayoutKind.Auto)] - public readonly struct ConfiguredValueTaskAwaitable<TResult> - { - /// <summary>The wrapped <see cref="ValueTask{TResult}"/>.</summary> - private readonly ValueTask<TResult> _value; - - /// <summary>Initializes the awaitable.</summary> - /// <param name="value">The wrapped <see cref="ValueTask{TResult}"/>.</param> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ConfiguredValueTaskAwaitable(in ValueTask<TResult> value) => _value = value; - - /// <summary>Returns an awaiter for this <see cref="ConfiguredValueTaskAwaitable{TResult}"/> instance.</summary> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ConfiguredValueTaskAwaiter GetAwaiter() => new ConfiguredValueTaskAwaiter(in _value); - - /// <summary>Provides an awaiter for a <see cref="ConfiguredValueTaskAwaitable{TResult}"/>.</summary> - [StructLayout(LayoutKind.Auto)] - public readonly struct ConfiguredValueTaskAwaiter : ICriticalNotifyCompletion, IStateMachineBoxAwareAwaiter - { - /// <summary>The value being awaited.</summary> - private readonly ValueTask<TResult> _value; - - /// <summary>Initializes the awaiter.</summary> - /// <param name="value">The value to be awaited.</param> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ConfiguredValueTaskAwaiter(in ValueTask<TResult> value) => _value = value; - - /// <summary>Gets whether the <see cref="ConfiguredValueTaskAwaitable{TResult}"/> has completed.</summary> - public bool IsCompleted - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _value.IsCompleted; - } - - /// <summary>Gets the result of the ValueTask.</summary> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public TResult GetResult() => _value.Result; - - /// <summary>Schedules the continuation action for the <see cref="ConfiguredValueTaskAwaitable{TResult}"/>.</summary> - public void OnCompleted(Action continuation) - { - object? obj = _value._obj; - Debug.Assert(obj == null || obj is Task<TResult> || obj is IValueTaskSource<TResult>); - - if (obj is Task<TResult> t) - { - t.ConfigureAwait(_value._continueOnCapturedContext).GetAwaiter().OnCompleted(continuation); - } - else if (obj != null) - { - Unsafe.As<IValueTaskSource<TResult>>(obj).OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, - ValueTaskSourceOnCompletedFlags.FlowExecutionContext | - (_value._continueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None)); - } - else - { - ValueTask.CompletedTask.ConfigureAwait(_value._continueOnCapturedContext).GetAwaiter().OnCompleted(continuation); - } - } - - /// <summary>Schedules the continuation action for the <see cref="ConfiguredValueTaskAwaitable{TResult}"/>.</summary> - public void UnsafeOnCompleted(Action continuation) - { - object? obj = _value._obj; - Debug.Assert(obj == null || obj is Task<TResult> || obj is IValueTaskSource<TResult>); - - if (obj is Task<TResult> t) - { - t.ConfigureAwait(_value._continueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation); - } - else if (obj != null) - { - Unsafe.As<IValueTaskSource<TResult>>(obj).OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, - _value._continueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None); - } - else - { - ValueTask.CompletedTask.ConfigureAwait(_value._continueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation); - } - } - - void IStateMachineBoxAwareAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox box) - { - object? obj = _value._obj; - Debug.Assert(obj == null || obj is Task<TResult> || obj is IValueTaskSource<TResult>); - - if (obj is Task<TResult> t) - { - TaskAwaiter.UnsafeOnCompletedInternal(t, box, _value._continueOnCapturedContext); - } - else if (obj != null) - { - Unsafe.As<IValueTaskSource<TResult>>(obj).OnCompleted(ThreadPoolGlobals.s_invokeAsyncStateMachineBox, box, _value._token, - _value._continueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None); - } - else - { - TaskAwaiter.UnsafeOnCompletedInternal(Task.CompletedTask, box, _value._continueOnCapturedContext); - } - } - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ContractHelper.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ContractHelper.cs deleted file mode 100644 index 5adf4471e8f..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ContractHelper.cs +++ /dev/null @@ -1,156 +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. - -#define DEBUG // The behavior of this contract library should be consistent regardless of build type. - -using System.Diagnostics.Contracts; - -namespace System.Runtime.CompilerServices -{ - public static class ContractHelper - { - /// <summary> - /// Allows a managed application environment such as an interactive interpreter (IronPython) or a - /// web browser host (Jolt hosting Silverlight in IE) to be notified of contract failures and - /// potentially "handle" them, either by throwing a particular exception type, etc. If any of the - /// event handlers sets the Cancel flag in the ContractFailedEventArgs, then the Contract class will - /// not pop up an assert dialog box or trigger escalation policy. - /// </summary> - internal static event EventHandler<ContractFailedEventArgs>? InternalContractFailed; - - /// <summary> - /// Rewriter will call this method on a contract failure to allow listeners to be notified. - /// The method should not perform any failure (assert/throw) itself. - /// This method has 3 functions: - /// 1. Call any contract hooks (such as listeners to Contract failed events) - /// 2. Determine if the listeners deem the failure as handled (then resultFailureMessage should be set to null) - /// 3. Produce a localized resultFailureMessage used in advertising the failure subsequently. - /// On exit: null if the event was handled and should not trigger a failure. - /// Otherwise, returns the localized failure message. - /// </summary> - [System.Diagnostics.DebuggerNonUserCode] - public static string? RaiseContractFailedEvent(ContractFailureKind failureKind, string? userMessage, string? conditionText, Exception? innerException) - { - if (failureKind < ContractFailureKind.Precondition || failureKind > ContractFailureKind.Assume) - throw new ArgumentException(SR.Format(SR.Arg_EnumIllegalVal, failureKind), nameof(failureKind)); - - string? returnValue; - string displayMessage = "contract failed."; // Incomplete, but in case of OOM during resource lookup... - ContractFailedEventArgs? eventArgs = null; // In case of OOM. - - try - { - displayMessage = GetDisplayMessage(failureKind, userMessage, conditionText); - EventHandler<ContractFailedEventArgs>? contractFailedEventLocal = InternalContractFailed; - if (contractFailedEventLocal != null) - { - eventArgs = new ContractFailedEventArgs(failureKind, displayMessage, conditionText, innerException); - foreach (EventHandler<ContractFailedEventArgs> handler in contractFailedEventLocal.GetInvocationList()) - { - try - { - handler(null, eventArgs); - } - catch (Exception e) - { - eventArgs.thrownDuringHandler = e; - eventArgs.SetUnwind(); - } - } - if (eventArgs.Unwind) - { - // unwind - innerException ??= eventArgs.thrownDuringHandler; - throw new ContractException(failureKind, displayMessage, userMessage, conditionText, innerException); - } - } - } - finally - { - if (eventArgs != null && eventArgs.Handled) - { - returnValue = null; // handled - } - else - { - returnValue = displayMessage; - } - } - - return returnValue; - } - - /// <summary> - /// Rewriter calls this method to get the default failure behavior. - /// </summary> - [System.Diagnostics.DebuggerNonUserCode] - public static void TriggerFailure(ContractFailureKind kind, string? displayMessage, string? userMessage, string? conditionText, Exception? innerException) - { - if (string.IsNullOrEmpty(displayMessage)) - { - displayMessage = GetDisplayMessage(kind, userMessage, conditionText); - } - - System.Diagnostics.Debug.ContractFailure(displayMessage, string.Empty, GetFailureMessage(kind, null)); - } - - private static string GetFailureMessage(ContractFailureKind failureKind, string? conditionText) - { - bool hasConditionText = !string.IsNullOrEmpty(conditionText); - switch (failureKind) - { - case ContractFailureKind.Assert: - return hasConditionText ? SR.Format(SR.AssertionFailed_Cnd, conditionText) : SR.AssertionFailed; - - case ContractFailureKind.Assume: - return hasConditionText ? SR.Format(SR.AssumptionFailed_Cnd, conditionText) : SR.AssumptionFailed; - - case ContractFailureKind.Precondition: - return hasConditionText ? SR.Format(SR.PreconditionFailed_Cnd, conditionText) : SR.PreconditionFailed; - - case ContractFailureKind.Postcondition: - return hasConditionText ? SR.Format(SR.PostconditionFailed_Cnd, conditionText) : SR.PostconditionFailed; - - case ContractFailureKind.Invariant: - return hasConditionText ? SR.Format(SR.InvariantFailed_Cnd, conditionText) : SR.InvariantFailed; - - case ContractFailureKind.PostconditionOnException: - return hasConditionText ? SR.Format(SR.PostconditionOnExceptionFailed_Cnd, conditionText) : SR.PostconditionOnExceptionFailed; - - default: - Contract.Assume(false, "Unreachable code"); - return SR.AssumptionFailed; - } - } - - private static string GetDisplayMessage(ContractFailureKind failureKind, string? userMessage, string? conditionText) - { - string failureMessage; - // Well-formatted English messages will take one of four forms. A sentence ending in - // either a period or a colon, the condition string, then the message tacked - // on to the end with two spaces in front. - // Note that both the conditionText and userMessage may be null. Also, - // on Silverlight we may not be able to look up a friendly string for the - // error message. Let's leverage Silverlight's default error message there. - if (!string.IsNullOrEmpty(conditionText)) - { - failureMessage = GetFailureMessage(failureKind, conditionText); - } - else - { - failureMessage = ""; - } - - // Now add in the user message, if present. - if (!string.IsNullOrEmpty(userMessage)) - { - return failureMessage + " " + userMessage; - } - else - { - return failureMessage; - } - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/CustomConstantAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/CustomConstantAttribute.cs deleted file mode 100644 index f3db0a276b5..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/CustomConstantAttribute.cs +++ /dev/null @@ -1,12 +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 -{ - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)] - public abstract class CustomConstantAttribute : Attribute - { - public abstract object? Value { get; } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/DateTimeConstantAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/DateTimeConstantAttribute.cs deleted file mode 100644 index 315e9e3b938..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/DateTimeConstantAttribute.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 -{ - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)] - public sealed class DateTimeConstantAttribute : CustomConstantAttribute - { - private readonly DateTime _date; - - public DateTimeConstantAttribute(long ticks) - { - _date = new DateTime(ticks); - } - -#pragma warning disable CS8608 - public override object Value => _date; -#pragma warning restore CS8608 - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/DecimalConstantAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/DecimalConstantAttribute.cs deleted file mode 100644 index 7aea9e6cc78..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/DecimalConstantAttribute.cs +++ /dev/null @@ -1,39 +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. - -// Note: If you add a new ctor overloads you need to update ParameterInfo.RawDefaultValue - -namespace System.Runtime.CompilerServices -{ - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)] - public sealed class DecimalConstantAttribute : Attribute - { - private readonly decimal _dec; - - [CLSCompliant(false)] - public DecimalConstantAttribute( - byte scale, - byte sign, - uint hi, - uint mid, - uint low - ) - { - _dec = new decimal((int)low, (int)mid, (int)hi, sign != 0, scale); - } - - public DecimalConstantAttribute( - byte scale, - byte sign, - int hi, - int mid, - int low - ) - { - _dec = new decimal(low, mid, hi, sign != 0, scale); - } - - public decimal Value => _dec; - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/DefaultDependencyAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/DefaultDependencyAttribute.cs deleted file mode 100644 index 31abdcbb3ec..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/DefaultDependencyAttribute.cs +++ /dev/null @@ -1,17 +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 -{ - [AttributeUsage(AttributeTargets.Assembly)] - public sealed class DefaultDependencyAttribute : Attribute - { - public DefaultDependencyAttribute(LoadHint loadHintArgument) - { - LoadHint = loadHintArgument; - } - - public LoadHint LoadHint { get; } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/DependencyAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/DependencyAttribute.cs deleted file mode 100644 index 5b589fbde82..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/DependencyAttribute.cs +++ /dev/null @@ -1,19 +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 -{ - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] - public sealed class DependencyAttribute : Attribute - { - public DependencyAttribute(string dependentAssemblyArgument, LoadHint loadHintArgument) - { - DependentAssembly = dependentAssemblyArgument; - LoadHint = loadHintArgument; - } - - public string DependentAssembly { get; } - public LoadHint LoadHint { get; } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/DisablePrivateReflectionAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/DisablePrivateReflectionAttribute.cs deleted file mode 100644 index dfe4a98a949..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/DisablePrivateReflectionAttribute.cs +++ /dev/null @@ -1,12 +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 -{ - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false, Inherited = false)] - public sealed class DisablePrivateReflectionAttribute : Attribute - { - public DisablePrivateReflectionAttribute() { } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/DiscardableAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/DiscardableAttribute.cs deleted file mode 100644 index 4a860b15878..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/DiscardableAttribute.cs +++ /dev/null @@ -1,13 +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 -{ - // Custom attribute to indicating a TypeDef is a discardable attribute. - [AttributeUsage(AttributeTargets.All)] - public class DiscardableAttribute : Attribute - { - public DiscardableAttribute() { } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ExtensionAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ExtensionAttribute.cs deleted file mode 100644 index d971d633ef3..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ExtensionAttribute.cs +++ /dev/null @@ -1,12 +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 -{ - /// <summary> - /// Indicates that a method is an extension method, or that a class or assembly contains extension methods. - /// </summary> - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly)] - public sealed class ExtensionAttribute : Attribute { } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/FixedAddressValueTypeAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/FixedAddressValueTypeAttribute.cs deleted file mode 100644 index 1810340f545..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/FixedAddressValueTypeAttribute.cs +++ /dev/null @@ -1,12 +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 -{ - [AttributeUsage(AttributeTargets.Field)] - public sealed class FixedAddressValueTypeAttribute : Attribute - { - public FixedAddressValueTypeAttribute() { } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/FixedBufferAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/FixedBufferAttribute.cs deleted file mode 100644 index 2215606c19d..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/FixedBufferAttribute.cs +++ /dev/null @@ -1,30 +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. - -/*============================================================ -** -** -** Purpose: Used by a compiler for generating value types -** in-place within other value types containing a certain -** number of elements of the given (primitive) type. Somewhat -** similar to P/Invoke's ByValTStr attribute. -** Used by C# with this syntax: "fixed int buffer[10];" -** -===========================================================*/ - -namespace System.Runtime.CompilerServices -{ - [AttributeUsage(AttributeTargets.Field, Inherited = false)] - public sealed class FixedBufferAttribute : Attribute - { - public FixedBufferAttribute(Type elementType, int length) - { - ElementType = elementType; - Length = length; - } - - public Type ElementType { get; } - public int Length { get; } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/FormattableStringFactory.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/FormattableStringFactory.cs deleted file mode 100644 index c08ebaee061..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/FormattableStringFactory.cs +++ /dev/null @@ -1,58 +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. - -/*============================================================ -** -** -** -** Purpose: implementation of the FormattableStringFactory -** class. -** -===========================================================*/ - -namespace System.Runtime.CompilerServices -{ - /// <summary> - /// A factory type used by compilers to create instances of the type <see cref="FormattableString"/>. - /// </summary> - public static class FormattableStringFactory - { - /// <summary> - /// Create a <see cref="FormattableString"/> from a composite format string and object - /// array containing zero or more objects to format. - /// </summary> - public static FormattableString Create(string format, params object?[] arguments) - { - if (format == null) - { - throw new ArgumentNullException(nameof(format)); - } - - if (arguments == null) - { - throw new ArgumentNullException(nameof(arguments)); - } - - return new ConcreteFormattableString(format, arguments); - } - - private sealed class ConcreteFormattableString : FormattableString - { - private readonly string _format; - private readonly object?[] _arguments; - - internal ConcreteFormattableString(string format, object?[] arguments) - { - _format = format; - _arguments = arguments; - } - - public override string Format => _format; - public override object?[] GetArguments() { return _arguments; } - public override int ArgumentCount => _arguments.Length; - public override object? GetArgument(int index) { return _arguments[index]; } - public override string ToString(IFormatProvider? formatProvider) { return string.Format(formatProvider, _format, _arguments); } - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IAsyncStateMachine.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IAsyncStateMachine.cs deleted file mode 100644 index 7fb7ea53952..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IAsyncStateMachine.cs +++ /dev/null @@ -1,27 +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. - -// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -// -// -// -// Represents state machines generated for asynchronous methods. -// -// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - -namespace System.Runtime.CompilerServices -{ - /// <summary> - /// Represents state machines generated for asynchronous methods. - /// This type is intended for compiler use only. - /// </summary> - public interface IAsyncStateMachine - { - /// <summary>Moves the state machine to its next state.</summary> - void MoveNext(); - /// <summary>Configures the state machine with a heap-allocated replica.</summary> - /// <param name="stateMachine">The heap-allocated replica.</param> - void SetStateMachine(IAsyncStateMachine stateMachine); - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IAsyncStateMachineBox.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IAsyncStateMachineBox.cs deleted file mode 100644 index bb09d35dd7d..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IAsyncStateMachineBox.cs +++ /dev/null @@ -1,24 +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 -{ - /// <summary> - /// An interface implemented by all <see cref="AsyncTaskMethodBuilder{TResult}.AsyncStateMachineBox{TStateMachine}"/> instances, regardless of generics. - /// </summary> - internal interface IAsyncStateMachineBox - { - /// <summary>Move the state machine forward.</summary> - void MoveNext(); - - /// <summary> - /// Gets an action for moving forward the contained state machine. - /// This will lazily-allocate the delegate as needed. - /// </summary> - Action MoveNextAction { get; } - - /// <summary>Gets the state machine as a boxed object. This should only be used for debugging purposes.</summary> - IAsyncStateMachine GetStateMachineObject(); - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ICastable.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ICastable.cs deleted file mode 100644 index 7320c2d0840..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ICastable.cs +++ /dev/null @@ -1,61 +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.Diagnostics.CodeAnalysis; - -namespace System.Runtime.CompilerServices -{ - /// <summary> - /// Support for dynamic interface casting. Specifically implementing this interface on a type will allow the - /// type to support interfaces (for the purposes of casting and interface dispatch) that do not appear in its - /// interface map. - /// </summary> - public interface ICastable - { - // This is called if casting this object to the given interface type would otherwise fail. Casting - // here means the IL isinst and castclass instructions in the case where they are given an interface - // type as the target type. - // - // A return value of true indicates the cast is valid. - // - // If false is returned when this is called as part of a castclass then the usual InvalidCastException - // will be thrown unless an alternate exception is assigned to the castError output parameter. This - // parameter is ignored on successful casts or during the evaluation of an isinst (which returns null - // rather than throwing on error). - // - // No exception should be thrown from this method (it will cause unpredictable effects, including the - // possibility of an immediate failfast). - // - // The results of this call are not cached, so it is advisable to provide a performant implementation. - // - // The results of this call should be invariant for the same class, interface type pair. That is - // because this is the only guard placed before an interface invocation at runtime. If a type decides - // it no longer wants to implement a given interface it has no way to synchronize with callers that - // have already cached this relationship and can invoke directly via the interface pointer. - bool IsInstanceOfInterface(RuntimeTypeHandle interfaceType, [NotNullWhen(true)] out Exception? castError); - - // This is called as part of the interface dispatch mechanism when the dispatcher logic cannot find - // the given interface type in the interface map of this object. - // - // It allows the implementor to return an alternate class type which does implement the interface. The - // interface lookup shall be performed again on this type (failure to find the interface this time - // resulting in a fail fast) and the corresponding implemented method on that class called instead. - // - // Naturally, since the call is dispatched to a method on a class which does not match the type of the - // this pointer, extreme care must be taken in the implementation of the interface methods of this - // surrogate type. - // - // No exception should be thrown from this method (it will cause unpredictable effects, including the - // possibility of an immediate failfast). - // - // There is no error path defined here. By construction all interface dispatches will already have - // been verified via the castclass/isinst mechanism (and thus a call to IsInstanceOfInterface above) - // so this method is expected to succeed in all cases. The contract for interface dispatch does not - // include any errors from the infrastructure, of which this is a part. - // - // The results of this lookup are cached so computation of the result is not as perf-sensitive as - // IsInstanceOfInterface. - RuntimeTypeHandle GetImplType(RuntimeTypeHandle interfaceType); - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/INotifyCompletion.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/INotifyCompletion.cs deleted file mode 100644 index 24f4f45cbea..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/INotifyCompletion.cs +++ /dev/null @@ -1,36 +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. - -// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= -// -// -// -// Interfaces used to represent instances that notify listeners of their completion via continuations. -// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - -namespace System.Runtime.CompilerServices -{ - /// <summary> - /// Represents an operation that will schedule continuations when the operation completes. - /// </summary> - public interface INotifyCompletion - { - /// <summary>Schedules the continuation action to be invoked when the instance completes.</summary> - /// <param name="continuation">The action to invoke when the operation completes.</param> - /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception> - void OnCompleted(Action continuation); - } - - /// <summary> - /// Represents an awaiter used to schedule continuations when an await operation completes. - /// </summary> - public interface ICriticalNotifyCompletion : INotifyCompletion - { - /// <summary>Schedules the continuation action to be invoked when the instance completes.</summary> - /// <param name="continuation">The action to invoke when the operation completes.</param> - /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception> - /// <remarks>Unlike OnCompleted, UnsafeOnCompleted need not propagate ExecutionContext information.</remarks> - void UnsafeOnCompleted(Action continuation); - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ITuple.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ITuple.cs deleted file mode 100644 index 55b948b3e37..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ITuple.cs +++ /dev/null @@ -1,22 +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 -{ - /// <summary> - /// This interface is required for types that want to be indexed into by dynamic patterns. - /// </summary> - public interface ITuple - { - /// <summary> - /// The number of positions in this data structure. - /// </summary> - int Length { get; } - - /// <summary> - /// Get the element at position <param name="index"/>. - /// </summary> - object? this[int index] { get; } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IndexerNameAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IndexerNameAttribute.cs deleted file mode 100644 index bc76250adc8..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IndexerNameAttribute.cs +++ /dev/null @@ -1,14 +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 -{ - [AttributeUsage(AttributeTargets.Property, Inherited = true)] - public sealed class IndexerNameAttribute : Attribute - { - public IndexerNameAttribute(string indexerName) - { - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/InternalsVisibleToAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/InternalsVisibleToAttribute.cs deleted file mode 100644 index 0967b96c1b2..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/InternalsVisibleToAttribute.cs +++ /dev/null @@ -1,18 +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 -{ - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true, Inherited = false)] - public sealed class InternalsVisibleToAttribute : Attribute - { - public InternalsVisibleToAttribute(string assemblyName) - { - AssemblyName = assemblyName; - } - - public string AssemblyName { get; } - public bool AllInternalsVisible { get; set; } = true; - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IntrinsicAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IntrinsicAttribute.cs deleted file mode 100644 index 6bdd91d8448..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IntrinsicAttribute.cs +++ /dev/null @@ -1,14 +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 -{ - // Calls to methods or references to fields marked with this attribute may be replaced at - // some call sites with jit intrinsic expansions. - // Types marked with this attribute may be specially treated by the runtime/compiler. - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Field, Inherited = false)] - internal sealed class IntrinsicAttribute : Attribute - { - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IsByRefLikeAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IsByRefLikeAttribute.cs deleted file mode 100644 index 90e49d2a425..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IsByRefLikeAttribute.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. - -using System.ComponentModel; - -namespace System.Runtime.CompilerServices -{ - /// <summary> - /// Reserved to be used by the compiler for tracking metadata. - /// This attribute should not be used by developers in source code. - /// </summary> - [EditorBrowsable(EditorBrowsableState.Never)] - [AttributeUsage(AttributeTargets.Struct)] - public sealed class IsByRefLikeAttribute : Attribute - { - public IsByRefLikeAttribute() - { - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IsConst.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IsConst.cs deleted file mode 100644 index 7f948b608a1..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IsConst.cs +++ /dev/null @@ -1,10 +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 -{ - public static partial class IsConst - { - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IsReadOnlyAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IsReadOnlyAttribute.cs deleted file mode 100644 index 657df43957f..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IsReadOnlyAttribute.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. - -using System.ComponentModel; - -namespace System.Runtime.CompilerServices -{ - /// <summary> - /// Reserved to be used by the compiler for tracking metadata. - /// This attribute should not be used by developers in source code. - /// </summary> - [EditorBrowsable(EditorBrowsableState.Never)] - [AttributeUsage(AttributeTargets.All, Inherited = false)] - public sealed class IsReadOnlyAttribute : Attribute - { - public IsReadOnlyAttribute() - { - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IsVolatile.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IsVolatile.cs deleted file mode 100644 index 58aaebc8d1a..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IsVolatile.cs +++ /dev/null @@ -1,11 +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 -{ - public static class IsVolatile - { - // no instantiation, please! - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IteratorStateMachineAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IteratorStateMachineAttribute.cs deleted file mode 100644 index 53afc956643..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IteratorStateMachineAttribute.cs +++ /dev/null @@ -1,15 +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 -{ - [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)] - public sealed class IteratorStateMachineAttribute : StateMachineAttribute - { - public IteratorStateMachineAttribute(Type stateMachineType) - : base(stateMachineType) - { - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/LoadHint.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/LoadHint.cs deleted file mode 100644 index fa490c2c9bb..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/LoadHint.cs +++ /dev/null @@ -1,13 +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 -{ - public enum LoadHint - { - Default = 0x0000, // No preference specified - Always = 0x0001, // Dependency is always loaded - Sometimes = 0x0002, // Dependency is sometimes loaded - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/MethodCodeType.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/MethodCodeType.cs deleted file mode 100644 index 841b6661989..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/MethodCodeType.cs +++ /dev/null @@ -1,16 +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.Reflection; - -namespace System.Runtime.CompilerServices -{ - public enum MethodCodeType - { - IL = MethodImplAttributes.IL, - Native = MethodImplAttributes.Native, - OPTIL = MethodImplAttributes.OPTIL, - Runtime = MethodImplAttributes.Runtime - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/MethodImplAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/MethodImplAttribute.cs deleted file mode 100644 index 18900b37bea..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/MethodImplAttribute.cs +++ /dev/null @@ -1,29 +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 -{ - // Custom attribute to specify additional method properties. - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor, Inherited = false)] - public sealed class MethodImplAttribute : Attribute - { - public MethodCodeType MethodCodeType; - - public MethodImplAttribute(MethodImplOptions methodImplOptions) - { - Value = methodImplOptions; - } - - public MethodImplAttribute(short value) - { - Value = (MethodImplOptions)value; - } - - public MethodImplAttribute() - { - } - - public MethodImplOptions Value { get; } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/MethodImplOptions.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/MethodImplOptions.cs deleted file mode 100644 index 27757683511..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/MethodImplOptions.cs +++ /dev/null @@ -1,22 +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 -{ - // This Enum matchs the miImpl flags defined in corhdr.h. It is used to specify - // certain method properties. - [Flags] - public enum MethodImplOptions - { - Unmanaged = 0x0004, - NoInlining = 0x0008, - ForwardRef = 0x0010, - Synchronized = 0x0020, - NoOptimization = 0x0040, - PreserveSig = 0x0080, - AggressiveInlining = 0x0100, - AggressiveOptimization = 0x0200, - InternalCall = 0x1000 - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/PreserveDependencyAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/PreserveDependencyAttribute.cs deleted file mode 100644 index de14ff35e04..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/PreserveDependencyAttribute.cs +++ /dev/null @@ -1,62 +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. - -#nullable enable - -// TODO https://github.com/dotnet/corefx/issues/41201: Design and expose this publicly. - -namespace System.Runtime.CompilerServices -{ - /// <summary>States a dependency that one member has on another.</summary> - /// <remarks> - /// This can be used to inform tooling of a dependency that is otherwise not evident purely from - /// metadata and IL, for example a member relied on via reflection. - /// </remarks> - [AttributeUsage( - AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Field /* AttributeTargets.Class | AttributeTargets.Struct */, // TODO: https://github.com/mono/linker/issues/797 - AllowMultiple = true, Inherited = false)] - internal sealed class PreserveDependencyAttribute : Attribute - { - /// <summary>Initializes the attribute.</summary> - /// <param name="memberSignature">The signature of the member depended.</param> - public PreserveDependencyAttribute(string memberSignature) - { - MemberSignature = memberSignature; - } - - /// <summary>Initializes the attribute.</summary> - /// <param name="memberSignature">The signature of the member depended on.</param> - /// <param name="typeName">The full name of the type containing <paramref name="memberSignature"/>.</param> - public PreserveDependencyAttribute(string memberSignature, string typeName) - { - MemberSignature = memberSignature; - TypeName = typeName; - } - - /// <summary>Initializes the attribute.</summary> - /// <param name="memberSignature">The signature of the member depended on.</param> - /// <param name="typeName">The full name of the type containing <paramref name="memberSignature"/>.</param> - /// <param name="assemblyName">The name of the assembly containing <paramref name="typeName"/>.</param> - public PreserveDependencyAttribute(string memberSignature, string typeName, string assemblyName) - { - MemberSignature = memberSignature; - TypeName = typeName; - AssemblyName = assemblyName; - } - - /// <summary>Gets the signature of the member depended on.</summary> - public string MemberSignature { get; } - - /// <summary>Gets the full name of the type containing the specified member.</summary> - /// <remarks>If no type name is specified, the type of the consumer is assumed.</remarks> - public string? TypeName { get; } - - /// <summary>Gets the assembly name of the specified type.</summary> - /// <remarks>If no assembly name is specified, the assembly of the consumer is assumed.</remarks> - public string? AssemblyName { get; } - - /// <summary>Gets or sets the condition in which the dependency is applicable, e.g. "DEBUG".</summary> - public string? Condition { get; set; } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ReferenceAssemblyAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ReferenceAssemblyAttribute.cs deleted file mode 100644 index e2c7cb47b4f..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ReferenceAssemblyAttribute.cs +++ /dev/null @@ -1,32 +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. - -/*============================================================ -** -** Attribute: ReferenceAssemblyAttribute -** -** Purpose: Identifies an assembly as being a "reference -** assembly", meaning it contains public surface area but -** no usable implementation. Reference assemblies -** should be loadable for introspection, but not execution. -** -============================================================*/ - -namespace System.Runtime.CompilerServices -{ - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)] - public sealed class ReferenceAssemblyAttribute : Attribute - { - public ReferenceAssemblyAttribute() - { - } - - public ReferenceAssemblyAttribute(string? description) - { - Description = description; - } - - public string? Description { get; } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/RuntimeCompatibilityAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/RuntimeCompatibilityAttribute.cs deleted file mode 100644 index 609c5603300..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/RuntimeCompatibilityAttribute.cs +++ /dev/null @@ -1,30 +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. - -/*============================================================================= -** -** -** -** Purpose: Mark up the program to indicate various legacy or new opt-in behaviors. -** -** -=============================================================================*/ - -namespace System.Runtime.CompilerServices -{ - [AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)] - public sealed class RuntimeCompatibilityAttribute : Attribute - { - public RuntimeCompatibilityAttribute() - { - // legacy behavior is the default, and WrapNonExceptionThrows is implicitly - // false thanks to the CLR's guarantee of zeroed memory. - } - - // If a non-CLSCompliant exception (i.e. one that doesn't derive from System.Exception) is - // thrown, should it be wrapped up in a System.Runtime.CompilerServices.RuntimeWrappedException - // instance when presented to catch handlers? - public bool WrapNonExceptionThrows { get; set; } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/RuntimeFeature.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/RuntimeFeature.cs deleted file mode 100644 index b0cd9ddce26..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/RuntimeFeature.cs +++ /dev/null @@ -1,42 +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 -{ - public static partial class RuntimeFeature - { - /// <summary> - /// Name of the Portable PDB feature. - /// </summary> - public const string PortablePdb = nameof(PortablePdb); - -#if FEATURE_DEFAULT_INTERFACES - /// <summary> - /// Indicates that this version of runtime supports default interface method implementations. - /// </summary> - public const string DefaultImplementationsOfInterfaces = nameof(DefaultImplementationsOfInterfaces); -#endif - - /// <summary> - /// Checks whether a certain feature is supported by the Runtime. - /// </summary> - public static bool IsSupported(string feature) - { - switch (feature) - { - case PortablePdb: -#if FEATURE_DEFAULT_INTERFACES - case DefaultImplementationsOfInterfaces: -#endif - return true; - case nameof(IsDynamicCodeSupported): - return IsDynamicCodeSupported; - case nameof(IsDynamicCodeCompiled): - return IsDynamicCodeCompiled; - } - - return false; - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/RuntimeHelpers.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/RuntimeHelpers.cs deleted file mode 100644 index cd2971f0350..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/RuntimeHelpers.cs +++ /dev/null @@ -1,109 +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.Serialization; -using System.Reflection; -using Internal.Runtime.CompilerServices; - -namespace System.Runtime.CompilerServices -{ - public static partial class RuntimeHelpers - { - public delegate void TryCode(object? userData); - - public delegate void CleanupCode(object? userData, bool exceptionThrown); - - /// <summary> - /// Slices the specified array using the specified range. - /// </summary> - public static T[] GetSubArray<T>(T[] array, Range range) - { - if (array == null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - } - - (int offset, int length) = range.GetOffsetAndLength(array.Length); - - if (default(T)! != null || typeof(T[]) == array.GetType()) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) - { - // We know the type of the array to be exactly T[]. - - if (length == 0) - { - return Array.Empty<T>(); - } - - var dest = new T[length]; - Buffer.Memmove( - ref Unsafe.As<byte, T>(ref dest.GetRawSzArrayData()), - ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), offset), - (uint)length); - return dest; - } - else - { - // The array is actually a U[] where U:T. - T[] dest = (T[])Array.CreateInstance(array.GetType().GetElementType()!, length); - Array.Copy(array, offset, dest, 0, length); - return dest; - } - } - - public static object GetUninitializedObject(Type type) - { - if (type is null) - { - throw new ArgumentNullException(nameof(type), SR.ArgumentNull_Type); - } - - if (!type.IsRuntimeImplemented()) - { - throw new SerializationException(SR.Format(SR.Serialization_InvalidType, type.ToString())); - } - - return GetUninitializedObjectInternal(type); - } - - public static void ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, object? userData) - { - if (code == null) - throw new ArgumentNullException(nameof(code)); - if (backoutCode == null) - throw new ArgumentNullException(nameof(backoutCode)); - - bool exceptionThrown = true; - - try - { - code(userData); - exceptionThrown = false; - } - finally - { - backoutCode(userData, exceptionThrown); - } - } - - public static void PrepareContractedDelegate(Delegate d) - { - } - - public static void ProbeForSufficientStack() - { - } - - public static void PrepareConstrainedRegions() - { - } - - public static void PrepareConstrainedRegionsNoOP() - { - } - - internal static bool IsPrimitiveType(this CorElementType et) - // COR_ELEMENT_TYPE_I1,I2,I4,I8,U1,U2,U4,U8,R4,R8,I,U,CHAR,BOOLEAN - => ((1 << (int)et) & 0b_0011_0000_0000_0011_1111_1111_1100) != 0; - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/RuntimeWrappedException.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/RuntimeWrappedException.cs deleted file mode 100644 index 65fd6d24e64..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/RuntimeWrappedException.cs +++ /dev/null @@ -1,41 +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.Serialization; - -namespace System.Runtime.CompilerServices -{ - /// <summary> - /// Exception used to wrap all non-CLS compliant exceptions. - /// </summary> - [Serializable] - [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - public sealed class RuntimeWrappedException : Exception - { - private object _wrappedException; // EE expects this name - - // Not an api but has to be public as System.Linq.Expression invokes this through Reflection when an expression - // throws an object that doesn't derive from Exception. - public RuntimeWrappedException(object thrownObject) - : base(SR.RuntimeWrappedException) - { - HResult = HResults.COR_E_RUNTIMEWRAPPED; - _wrappedException = thrownObject; - } - - private RuntimeWrappedException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - _wrappedException = info.GetValue("WrappedException", typeof(object))!; - } - - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - info.AddValue("WrappedException", _wrappedException, typeof(object)); - } - - public object WrappedException => _wrappedException; - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/SpecialNameAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/SpecialNameAttribute.cs deleted file mode 100644 index 4cd78621cb5..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/SpecialNameAttribute.cs +++ /dev/null @@ -1,12 +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 -{ - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Struct)] - public sealed class SpecialNameAttribute : Attribute - { - public SpecialNameAttribute() { } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/StateMachineAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/StateMachineAttribute.cs deleted file mode 100644 index d3522f5c470..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/StateMachineAttribute.cs +++ /dev/null @@ -1,17 +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 -{ - [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)] - public class StateMachineAttribute : Attribute - { - public StateMachineAttribute(Type stateMachineType) - { - StateMachineType = stateMachineType; - } - - public Type StateMachineType { get; } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/StringFreezingAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/StringFreezingAttribute.cs deleted file mode 100644 index 9d73197de42..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/StringFreezingAttribute.cs +++ /dev/null @@ -1,14 +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 -{ - // Custom attribute to indicate that strings should be frozen. - - [AttributeUsage(AttributeTargets.Assembly, Inherited = false)] - public sealed class StringFreezingAttribute : Attribute - { - public StringFreezingAttribute() { } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/StrongBox.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/StrongBox.cs deleted file mode 100644 index bdee5189b3c..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/StrongBox.cs +++ /dev/null @@ -1,54 +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.Diagnostics.CodeAnalysis; - -namespace System.Runtime.CompilerServices -{ - /// <summary> - /// Holds a reference to a value. - /// </summary> - /// <typeparam name="T">The type of the value that the <see cref = "StrongBox{T}"></see> references.</typeparam> - public class StrongBox<T> : IStrongBox - { - /// <summary> - /// Gets the strongly typed value associated with the <see cref = "StrongBox{T}"></see> - /// <remarks>This is explicitly exposed as a field instead of a property to enable loading the address of the field.</remarks> - /// </summary> - [MaybeNull] public T Value = default!; - - /// <summary> - /// Initializes a new StrongBox which can receive a value when used in a reference call. - /// </summary> - public StrongBox() - { - } - - /// <summary> - /// Initializes a new <see cref = "StrongBox{T}"></see> with the specified value. - /// </summary> - /// <param name="value">A value that the <see cref = "StrongBox{T}"></see> will reference.</param> - public StrongBox(T value) - { - Value = value; - } - - object? IStrongBox.Value - { - get => Value; - set => Value = (T)value!; - } - } - - /// <summary> - /// Defines a property for accessing the value that an object references. - /// </summary> - public interface IStrongBox - { - /// <summary> - /// Gets or sets the value the object references. - /// </summary> - object? Value { get; set; } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/SuppressIldasmAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/SuppressIldasmAttribute.cs deleted file mode 100644 index e9abf134be9..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/SuppressIldasmAttribute.cs +++ /dev/null @@ -1,12 +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 -{ - [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module)] - public sealed class SuppressIldasmAttribute : Attribute - { - public SuppressIldasmAttribute() { } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/TaskAwaiter.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/TaskAwaiter.cs deleted file mode 100644 index f1c5b07071a..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/TaskAwaiter.cs +++ /dev/null @@ -1,556 +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. - -// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -// -// -// -// Types for awaiting Task and Task<T>. These types are emitted from Task{<T>}.GetAwaiter -// and Task{<T>}.ConfigureAwait. They are meant to be used only by the compiler, e.g. -// -// await nonGenericTask; -// ===================== -// var $awaiter = nonGenericTask.GetAwaiter(); -// if (!$awaiter.IsCompleted) -// { -// SPILL: -// $builder.AwaitUnsafeOnCompleted(ref $awaiter, ref this); -// return; -// Label: -// UNSPILL; -// } -// $awaiter.GetResult(); -// -// result += await genericTask.ConfigureAwait(false); -// =================================================================================== -// var $awaiter = genericTask.ConfigureAwait(false).GetAwaiter(); -// if (!$awaiter.IsCompleted) -// { -// SPILL; -// $builder.AwaitUnsafeOnCompleted(ref $awaiter, ref this); -// return; -// Label: -// UNSPILL; -// } -// result += $awaiter.GetResult(); -// -// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - -using System.Collections.ObjectModel; -using System.Diagnostics; -using System.Diagnostics.Tracing; -using System.Runtime.ExceptionServices; -using System.Threading; -using System.Threading.Tasks; - -// NOTE: For performance reasons, initialization is not verified. If a developer -// incorrectly initializes a task awaiter, which should only be done by the compiler, -// NullReferenceExceptions may be generated (the alternative would be for us to detect -// this case and then throw a different exception instead). This is the same tradeoff -// that's made with other compiler-focused value types like List<T>.Enumerator. - -namespace System.Runtime.CompilerServices -{ - /// <summary>Provides an awaiter for awaiting a <see cref="System.Threading.Tasks.Task"/>.</summary> - /// <remarks>This type is intended for compiler use only.</remarks> - public readonly struct TaskAwaiter : ICriticalNotifyCompletion, ITaskAwaiter - { - // WARNING: Unsafe.As is used to access the generic TaskAwaiter<> as TaskAwaiter. - // Its layout must remain the same. - - /// <summary>The task being awaited.</summary> - internal readonly Task m_task; - - /// <summary>Initializes the <see cref="TaskAwaiter"/>.</summary> - /// <param name="task">The <see cref="System.Threading.Tasks.Task"/> to be awaited.</param> - internal TaskAwaiter(Task task) - { - Debug.Assert(task != null, "Constructing an awaiter requires a task to await."); - m_task = task; - } - - /// <summary>Gets whether the task being awaited is completed.</summary> - /// <remarks>This property is intended for compiler user rather than use directly in code.</remarks> - /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception> - public bool IsCompleted => m_task.IsCompleted; - - /// <summary>Schedules the continuation onto the <see cref="System.Threading.Tasks.Task"/> associated with this <see cref="TaskAwaiter"/>.</summary> - /// <param name="continuation">The action to invoke when the await operation completes.</param> - /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception> - /// <exception cref="System.InvalidOperationException">The awaiter was not properly initialized.</exception> - /// <remarks>This method is intended for compiler user rather than use directly in code.</remarks> - public void OnCompleted(Action continuation) - { - OnCompletedInternal(m_task, continuation, continueOnCapturedContext: true, flowExecutionContext: true); - } - - /// <summary>Schedules the continuation onto the <see cref="System.Threading.Tasks.Task"/> associated with this <see cref="TaskAwaiter"/>.</summary> - /// <param name="continuation">The action to invoke when the await operation completes.</param> - /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception> - /// <exception cref="System.InvalidOperationException">The awaiter was not properly initialized.</exception> - /// <remarks>This method is intended for compiler user rather than use directly in code.</remarks> - public void UnsafeOnCompleted(Action continuation) - { - OnCompletedInternal(m_task, continuation, continueOnCapturedContext: true, flowExecutionContext: false); - } - - /// <summary>Ends the await on the completed <see cref="System.Threading.Tasks.Task"/>.</summary> - /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception> - /// <exception cref="System.Threading.Tasks.TaskCanceledException">The task was canceled.</exception> - /// <exception cref="System.Exception">The task completed in a Faulted state.</exception> - [StackTraceHidden] - public void GetResult() - { - ValidateEnd(m_task); - } - - /// <summary> - /// Fast checks for the end of an await operation to determine whether more needs to be done - /// prior to completing the await. - /// </summary> - /// <param name="task">The awaited task.</param> - [StackTraceHidden] - internal static void ValidateEnd(Task task) - { - // Fast checks that can be inlined. - if (task.IsWaitNotificationEnabledOrNotRanToCompletion) - { - // If either the end await bit is set or we're not completed successfully, - // fall back to the slower path. - HandleNonSuccessAndDebuggerNotification(task); - } - } - - /// <summary> - /// Ensures the task is completed, triggers any necessary debugger breakpoints for completing - /// the await on the task, and throws an exception if the task did not complete successfully. - /// </summary> - /// <param name="task">The awaited task.</param> - [StackTraceHidden] - private static void HandleNonSuccessAndDebuggerNotification(Task task) - { - // NOTE: The JIT refuses to inline ValidateEnd when it contains the contents - // of HandleNonSuccessAndDebuggerNotification, hence the separation. - - // Synchronously wait for the task to complete. When used by the compiler, - // the task will already be complete. This code exists only for direct GetResult use, - // for cases where the same exception propagation semantics used by "await" are desired, - // but where for one reason or another synchronous rather than asynchronous waiting is needed. - if (!task.IsCompleted) - { - bool taskCompleted = task.InternalWait(Timeout.Infinite, default); - Debug.Assert(taskCompleted, "With an infinite timeout, the task should have always completed."); - } - - // Now that we're done, alert the debugger if so requested - task.NotifyDebuggerOfWaitCompletionIfNecessary(); - - // And throw an exception if the task is faulted or canceled. - if (!task.IsCompletedSuccessfully) ThrowForNonSuccess(task); - } - - /// <summary>Throws an exception to handle a task that completed in a state other than RanToCompletion.</summary> - [StackTraceHidden] - private static void ThrowForNonSuccess(Task task) - { - Debug.Assert(task.IsCompleted, "Task must have been completed by now."); - Debug.Assert(task.Status != TaskStatus.RanToCompletion, "Task should not be completed successfully."); - - // Handle whether the task has been canceled or faulted - switch (task.Status) - { - // If the task completed in a canceled state, throw an OperationCanceledException. - // This will either be the OCE that actually caused the task to cancel, or it will be a new - // TaskCanceledException. TCE derives from OCE, and by throwing it we automatically pick up the - // completed task's CancellationToken if it has one, including that CT in the OCE. - case TaskStatus.Canceled: - ExceptionDispatchInfo? oceEdi = task.GetCancellationExceptionDispatchInfo(); - if (oceEdi != null) - { - oceEdi.Throw(); - Debug.Fail("Throw() should have thrown"); - } - throw new TaskCanceledException(task); - - // If the task faulted, throw its first exception, - // even if it contained more than one. - case TaskStatus.Faulted: - ReadOnlyCollection<ExceptionDispatchInfo> edis = task.GetExceptionDispatchInfos(); - if (edis.Count > 0) - { - edis[0].Throw(); - Debug.Fail("Throw() should have thrown"); - break; // Necessary to compile: non-reachable, but compiler can't determine that - } - else - { - Debug.Fail("There should be exceptions if we're Faulted."); - throw task.Exception!; - } - } - } - - /// <summary>Schedules the continuation onto the <see cref="System.Threading.Tasks.Task"/> associated with this <see cref="TaskAwaiter"/>.</summary> - /// <param name="task">The task being awaited.</param> - /// <param name="continuation">The action to invoke when the await operation completes.</param> - /// <param name="continueOnCapturedContext">Whether to capture and marshal back to the current context.</param> - /// <param name="flowExecutionContext">Whether to flow ExecutionContext across the await.</param> - /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception> - /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception> - /// <remarks>This method is intended for compiler user rather than use directly in code.</remarks> - internal static void OnCompletedInternal(Task task, Action continuation, bool continueOnCapturedContext, bool flowExecutionContext) - { - if (continuation == null) throw new ArgumentNullException(nameof(continuation)); - - // If TaskWait* ETW events are enabled, trace a beginning event for this await - // and set up an ending event to be traced when the asynchronous await completes. - if (TplEventSource.Log.IsEnabled() || Task.s_asyncDebuggingEnabled) - { - continuation = OutputWaitEtwEvents(task, continuation); - } - - // Set the continuation onto the awaited task. - task.SetContinuationForAwait(continuation, continueOnCapturedContext, flowExecutionContext); - } - - /// <summary>Schedules the continuation onto the <see cref="System.Threading.Tasks.Task"/> associated with this <see cref="TaskAwaiter"/>.</summary> - /// <param name="task">The task being awaited.</param> - /// <param name="stateMachineBox">The box to invoke when the await operation completes.</param> - /// <param name="continueOnCapturedContext">Whether to capture and marshal back to the current context.</param> - internal static void UnsafeOnCompletedInternal(Task task, IAsyncStateMachineBox stateMachineBox, bool continueOnCapturedContext) - { - Debug.Assert(stateMachineBox != null); - - // If TaskWait* ETW events are enabled, trace a beginning event for this await - // and set up an ending event to be traced when the asynchronous await completes. - if (TplEventSource.Log.IsEnabled() || Task.s_asyncDebuggingEnabled) - { - task.SetContinuationForAwait(OutputWaitEtwEvents(task, stateMachineBox.MoveNextAction), continueOnCapturedContext, flowExecutionContext: false); - } - else - { - task.UnsafeSetContinuationForAwait(stateMachineBox, continueOnCapturedContext); - } - } - - /// <summary> - /// Outputs a WaitBegin ETW event, and augments the continuation action to output a WaitEnd ETW event. - /// </summary> - /// <param name="task">The task being awaited.</param> - /// <param name="continuation">The action to invoke when the await operation completes.</param> - /// <returns>The action to use as the actual continuation.</returns> - private static Action OutputWaitEtwEvents(Task task, Action continuation) - { - Debug.Assert(task != null, "Need a task to wait on"); - Debug.Assert(continuation != null, "Need a continuation to invoke when the wait completes"); - - if (Task.s_asyncDebuggingEnabled) - { - Task.AddToActiveTasks(task); - } - - TplEventSource log = TplEventSource.Log; - - if (log.IsEnabled()) - { - // ETW event for Task Wait Begin - Task? currentTaskAtBegin = Task.InternalCurrent; - - // If this task's continuation is another task, get it. - Task? continuationTask = AsyncMethodBuilderCore.TryGetContinuationTask(continuation); - log.TaskWaitBegin( - currentTaskAtBegin != null ? currentTaskAtBegin.m_taskScheduler!.Id : TaskScheduler.Default.Id, - currentTaskAtBegin != null ? currentTaskAtBegin.Id : 0, - task.Id, TplEventSource.TaskWaitBehavior.Asynchronous, - continuationTask != null ? continuationTask.Id : 0); - } - - // Create a continuation action that outputs the end event and then invokes the user - // provided delegate. This incurs the allocations for the closure/delegate, but only if the event - // is enabled, and in doing so it allows us to pass the awaited task's information into the end event - // in a purely pay-for-play manner (the alternatively would be to increase the size of TaskAwaiter - // just for this ETW purpose, not pay-for-play, since GetResult would need to know whether a real yield occurred). - return AsyncMethodBuilderCore.CreateContinuationWrapper(continuation, (innerContinuation, innerTask) => - { - if (Task.s_asyncDebuggingEnabled) - { - Task.RemoveFromActiveTasks(innerTask); - } - - TplEventSource innerEtwLog = TplEventSource.Log; - - // ETW event for Task Wait End. - Guid prevActivityId = default; - bool bEtwLogEnabled = innerEtwLog.IsEnabled(); - if (bEtwLogEnabled) - { - Task? currentTaskAtEnd = Task.InternalCurrent; - innerEtwLog.TaskWaitEnd( - currentTaskAtEnd != null ? currentTaskAtEnd.m_taskScheduler!.Id : TaskScheduler.Default.Id, - currentTaskAtEnd != null ? currentTaskAtEnd.Id : 0, - innerTask.Id); - - // Ensure the continuation runs under the activity ID of the task that completed for the - // case the antecedent is a promise (in the other cases this is already the case). - if (innerEtwLog.TasksSetActivityIds && (innerTask.Options & (TaskCreationOptions)InternalTaskOptions.PromiseTask) != 0) - EventSource.SetCurrentThreadActivityId(TplEventSource.CreateGuidForTaskID(innerTask.Id), out prevActivityId); - } - - // Invoke the original continuation provided to OnCompleted. - innerContinuation(); - - if (bEtwLogEnabled) - { - innerEtwLog.TaskWaitContinuationComplete(innerTask.Id); - if (innerEtwLog.TasksSetActivityIds && (innerTask.Options & (TaskCreationOptions)InternalTaskOptions.PromiseTask) != 0) - EventSource.SetCurrentThreadActivityId(prevActivityId); - } - }, task); - } - } - - /// <summary>Provides an awaiter for awaiting a <see cref="System.Threading.Tasks.Task{TResult}"/>.</summary> - /// <remarks>This type is intended for compiler use only.</remarks> - public readonly struct TaskAwaiter<TResult> : ICriticalNotifyCompletion, ITaskAwaiter - { - // WARNING: Unsafe.As is used to access TaskAwaiter<> as the non-generic TaskAwaiter. - // Its layout must remain the same. - - /// <summary>The task being awaited.</summary> - private readonly Task<TResult> m_task; - - /// <summary>Initializes the <see cref="TaskAwaiter{TResult}"/>.</summary> - /// <param name="task">The <see cref="System.Threading.Tasks.Task{TResult}"/> to be awaited.</param> - internal TaskAwaiter(Task<TResult> task) - { - Debug.Assert(task != null, "Constructing an awaiter requires a task to await."); - m_task = task; - } - - /// <summary>Gets whether the task being awaited is completed.</summary> - /// <remarks>This property is intended for compiler user rather than use directly in code.</remarks> - /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception> - public bool IsCompleted => m_task.IsCompleted; - - /// <summary>Schedules the continuation onto the <see cref="System.Threading.Tasks.Task"/> associated with this <see cref="TaskAwaiter"/>.</summary> - /// <param name="continuation">The action to invoke when the await operation completes.</param> - /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception> - /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception> - /// <remarks>This method is intended for compiler user rather than use directly in code.</remarks> - public void OnCompleted(Action continuation) - { - TaskAwaiter.OnCompletedInternal(m_task, continuation, continueOnCapturedContext: true, flowExecutionContext: true); - } - - /// <summary>Schedules the continuation onto the <see cref="System.Threading.Tasks.Task"/> associated with this <see cref="TaskAwaiter"/>.</summary> - /// <param name="continuation">The action to invoke when the await operation completes.</param> - /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception> - /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception> - /// <remarks>This method is intended for compiler user rather than use directly in code.</remarks> - public void UnsafeOnCompleted(Action continuation) - { - TaskAwaiter.OnCompletedInternal(m_task, continuation, continueOnCapturedContext: true, flowExecutionContext: false); - } - - /// <summary>Ends the await on the completed <see cref="System.Threading.Tasks.Task{TResult}"/>.</summary> - /// <returns>The result of the completed <see cref="System.Threading.Tasks.Task{TResult}"/>.</returns> - /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception> - /// <exception cref="System.Threading.Tasks.TaskCanceledException">The task was canceled.</exception> - /// <exception cref="System.Exception">The task completed in a Faulted state.</exception> - [StackTraceHidden] - public TResult GetResult() - { - TaskAwaiter.ValidateEnd(m_task); - return m_task.ResultOnSuccess; - } - } - - /// <summary> - /// Marker interface used to know whether a particular awaiter is either a - /// TaskAwaiter or a TaskAwaiter`1. It must not be implemented by any other - /// awaiters. - /// </summary> - internal interface ITaskAwaiter { } - - /// <summary> - /// Marker interface used to know whether a particular awaiter is either a - /// CTA.ConfiguredTaskAwaiter or a CTA`1.ConfiguredTaskAwaiter. It must not - /// be implemented by any other awaiters. - /// </summary> - internal interface IConfiguredTaskAwaiter { } - - /// <summary>Provides an awaitable object that allows for configured awaits on <see cref="System.Threading.Tasks.Task"/>.</summary> - /// <remarks>This type is intended for compiler use only.</remarks> - public readonly struct ConfiguredTaskAwaitable - { - /// <summary>The task being awaited.</summary> - private readonly ConfiguredTaskAwaitable.ConfiguredTaskAwaiter m_configuredTaskAwaiter; - - /// <summary>Initializes the <see cref="ConfiguredTaskAwaitable"/>.</summary> - /// <param name="task">The awaitable <see cref="System.Threading.Tasks.Task"/>.</param> - /// <param name="continueOnCapturedContext"> - /// true to attempt to marshal the continuation back to the original context captured; otherwise, false. - /// </param> - internal ConfiguredTaskAwaitable(Task task, bool continueOnCapturedContext) - { - Debug.Assert(task != null, "Constructing an awaitable requires a task to await."); - m_configuredTaskAwaiter = new ConfiguredTaskAwaitable.ConfiguredTaskAwaiter(task, continueOnCapturedContext); - } - - /// <summary>Gets an awaiter for this awaitable.</summary> - /// <returns>The awaiter.</returns> - public ConfiguredTaskAwaitable.ConfiguredTaskAwaiter GetAwaiter() - { - return m_configuredTaskAwaiter; - } - - /// <summary>Provides an awaiter for a <see cref="ConfiguredTaskAwaitable"/>.</summary> - /// <remarks>This type is intended for compiler use only.</remarks> - public readonly struct ConfiguredTaskAwaiter : ICriticalNotifyCompletion, IConfiguredTaskAwaiter - { - // WARNING: Unsafe.As is used to access the generic ConfiguredTaskAwaiter as this. - // Its layout must remain the same. - - /// <summary>The task being awaited.</summary> - internal readonly Task m_task; - /// <summary>Whether to attempt marshaling back to the original context.</summary> - internal readonly bool m_continueOnCapturedContext; - - /// <summary>Initializes the <see cref="ConfiguredTaskAwaiter"/>.</summary> - /// <param name="task">The <see cref="System.Threading.Tasks.Task"/> to await.</param> - /// <param name="continueOnCapturedContext"> - /// true to attempt to marshal the continuation back to the original context captured - /// when BeginAwait is called; otherwise, false. - /// </param> - internal ConfiguredTaskAwaiter(Task task, bool continueOnCapturedContext) - { - Debug.Assert(task != null, "Constructing an awaiter requires a task to await."); - m_task = task; - m_continueOnCapturedContext = continueOnCapturedContext; - } - - /// <summary>Gets whether the task being awaited is completed.</summary> - /// <remarks>This property is intended for compiler user rather than use directly in code.</remarks> - /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception> - public bool IsCompleted => m_task.IsCompleted; - - /// <summary>Schedules the continuation onto the <see cref="System.Threading.Tasks.Task"/> associated with this <see cref="TaskAwaiter"/>.</summary> - /// <param name="continuation">The action to invoke when the await operation completes.</param> - /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception> - /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception> - /// <remarks>This method is intended for compiler user rather than use directly in code.</remarks> - public void OnCompleted(Action continuation) - { - TaskAwaiter.OnCompletedInternal(m_task, continuation, m_continueOnCapturedContext, flowExecutionContext: true); - } - - /// <summary>Schedules the continuation onto the <see cref="System.Threading.Tasks.Task"/> associated with this <see cref="TaskAwaiter"/>.</summary> - /// <param name="continuation">The action to invoke when the await operation completes.</param> - /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception> - /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception> - /// <remarks>This method is intended for compiler user rather than use directly in code.</remarks> - public void UnsafeOnCompleted(Action continuation) - { - TaskAwaiter.OnCompletedInternal(m_task, continuation, m_continueOnCapturedContext, flowExecutionContext: false); - } - - /// <summary>Ends the await on the completed <see cref="System.Threading.Tasks.Task"/>.</summary> - /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception> - /// <exception cref="System.Threading.Tasks.TaskCanceledException">The task was canceled.</exception> - /// <exception cref="System.Exception">The task completed in a Faulted state.</exception> - [StackTraceHidden] - public void GetResult() - { - TaskAwaiter.ValidateEnd(m_task); - } - } - } - - /// <summary>Provides an awaitable object that allows for configured awaits on <see cref="System.Threading.Tasks.Task{TResult}"/>.</summary> - /// <remarks>This type is intended for compiler use only.</remarks> - public readonly struct ConfiguredTaskAwaitable<TResult> - { - /// <summary>The underlying awaitable on whose logic this awaitable relies.</summary> - private readonly ConfiguredTaskAwaitable<TResult>.ConfiguredTaskAwaiter m_configuredTaskAwaiter; - - /// <summary>Initializes the <see cref="ConfiguredTaskAwaitable{TResult}"/>.</summary> - /// <param name="task">The awaitable <see cref="System.Threading.Tasks.Task{TResult}"/>.</param> - /// <param name="continueOnCapturedContext"> - /// true to attempt to marshal the continuation back to the original context captured; otherwise, false. - /// </param> - internal ConfiguredTaskAwaitable(Task<TResult> task, bool continueOnCapturedContext) - { - m_configuredTaskAwaiter = new ConfiguredTaskAwaitable<TResult>.ConfiguredTaskAwaiter(task, continueOnCapturedContext); - } - - /// <summary>Gets an awaiter for this awaitable.</summary> - /// <returns>The awaiter.</returns> - public ConfiguredTaskAwaitable<TResult>.ConfiguredTaskAwaiter GetAwaiter() - { - return m_configuredTaskAwaiter; - } - - /// <summary>Provides an awaiter for a <see cref="ConfiguredTaskAwaitable{TResult}"/>.</summary> - /// <remarks>This type is intended for compiler use only.</remarks> - public readonly struct ConfiguredTaskAwaiter : ICriticalNotifyCompletion, IConfiguredTaskAwaiter - { - // WARNING: Unsafe.As is used to access this as the non-generic ConfiguredTaskAwaiter. - // Its layout must remain the same. - - /// <summary>The task being awaited.</summary> - private readonly Task<TResult> m_task; - /// <summary>Whether to attempt marshaling back to the original context.</summary> - private readonly bool m_continueOnCapturedContext; - - /// <summary>Initializes the <see cref="ConfiguredTaskAwaiter"/>.</summary> - /// <param name="task">The awaitable <see cref="System.Threading.Tasks.Task{TResult}"/>.</param> - /// <param name="continueOnCapturedContext"> - /// true to attempt to marshal the continuation back to the original context captured; otherwise, false. - /// </param> - internal ConfiguredTaskAwaiter(Task<TResult> task, bool continueOnCapturedContext) - { - Debug.Assert(task != null, "Constructing an awaiter requires a task to await."); - m_task = task; - m_continueOnCapturedContext = continueOnCapturedContext; - } - - /// <summary>Gets whether the task being awaited is completed.</summary> - /// <remarks>This property is intended for compiler user rather than use directly in code.</remarks> - /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception> - public bool IsCompleted => m_task.IsCompleted; - - /// <summary>Schedules the continuation onto the <see cref="System.Threading.Tasks.Task"/> associated with this <see cref="TaskAwaiter"/>.</summary> - /// <param name="continuation">The action to invoke when the await operation completes.</param> - /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception> - /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception> - /// <remarks>This method is intended for compiler user rather than use directly in code.</remarks> - public void OnCompleted(Action continuation) - { - TaskAwaiter.OnCompletedInternal(m_task, continuation, m_continueOnCapturedContext, flowExecutionContext: true); - } - - /// <summary>Schedules the continuation onto the <see cref="System.Threading.Tasks.Task"/> associated with this <see cref="TaskAwaiter"/>.</summary> - /// <param name="continuation">The action to invoke when the await operation completes.</param> - /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception> - /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception> - /// <remarks>This method is intended for compiler user rather than use directly in code.</remarks> - public void UnsafeOnCompleted(Action continuation) - { - TaskAwaiter.OnCompletedInternal(m_task, continuation, m_continueOnCapturedContext, flowExecutionContext: false); - } - - /// <summary>Ends the await on the completed <see cref="System.Threading.Tasks.Task{TResult}"/>.</summary> - /// <returns>The result of the completed <see cref="System.Threading.Tasks.Task{TResult}"/>.</returns> - /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception> - /// <exception cref="System.Threading.Tasks.TaskCanceledException">The task was canceled.</exception> - /// <exception cref="System.Exception">The task completed in a Faulted state.</exception> - [StackTraceHidden] - public TResult GetResult() - { - TaskAwaiter.ValidateEnd(m_task); - return m_task.ResultOnSuccess; - } - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/TupleElementNamesAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/TupleElementNamesAttribute.cs deleted file mode 100644 index d4bdcd1fa7f..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/TupleElementNamesAttribute.cs +++ /dev/null @@ -1,57 +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; - -namespace System.Runtime.CompilerServices -{ - /// <summary> - /// Indicates that the use of <see cref="System.ValueTuple"/> on a member is meant to be treated as a tuple with element names. - /// </summary> - [CLSCompliant(false)] - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Event)] - public sealed class TupleElementNamesAttribute : Attribute - { - private readonly string?[] _transformNames; - - /// <summary> - /// Initializes a new instance of the <see - /// cref="TupleElementNamesAttribute"/> class. - /// </summary> - /// <param name="transformNames"> - /// Specifies, in a pre-order depth-first traversal of a type's - /// construction, which <see cref="System.ValueType"/> occurrences are - /// meant to carry element names. - /// </param> - /// <remarks> - /// This constructor is meant to be used on types that contain an - /// instantiation of <see cref="System.ValueType"/> that contains - /// element names. For instance, if <c>C</c> is a generic type with - /// two type parameters, then a use of the constructed type <c>C{<see - /// cref="System.ValueTuple{T1, T2}"/>, <see - /// cref="System.ValueTuple{T1, T2, T3}"/></c> might be intended to - /// treat the first type argument as a tuple with element names and the - /// second as a tuple without element names. In which case, the - /// appropriate attribute specification should use a - /// <c>transformNames</c> value of <c>{ "name1", "name2", null, null, - /// null }</c>. - /// </remarks> - public TupleElementNamesAttribute(string?[] transformNames) - { - if (transformNames == null) - { - throw new ArgumentNullException(nameof(transformNames)); - } - - _transformNames = transformNames; - } - - /// <summary> - /// Specifies, in a pre-order depth-first traversal of a type's - /// construction, which <see cref="System.ValueTuple"/> elements are - /// meant to carry element names. - /// </summary> - public IList<string?> TransformNames => _transformNames; - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/TypeForwardedFromAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/TypeForwardedFromAttribute.cs deleted file mode 100644 index 27dd6457557..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/TypeForwardedFromAttribute.cs +++ /dev/null @@ -1,20 +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 -{ - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false, AllowMultiple = false)] - public sealed class TypeForwardedFromAttribute : Attribute - { - public TypeForwardedFromAttribute(string assemblyFullName) - { - if (string.IsNullOrEmpty(assemblyFullName)) - throw new ArgumentNullException(nameof(assemblyFullName)); - - AssemblyFullName = assemblyFullName; - } - - public string AssemblyFullName { get; } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/TypeForwardedToAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/TypeForwardedToAttribute.cs deleted file mode 100644 index 85d5c030c19..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/TypeForwardedToAttribute.cs +++ /dev/null @@ -1,17 +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 -{ - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true, Inherited = false)] - public sealed class TypeForwardedToAttribute : Attribute - { - public TypeForwardedToAttribute(Type destination) - { - Destination = destination; - } - - public Type Destination { get; } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/UnsafeValueTypeAttribute.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/UnsafeValueTypeAttribute.cs deleted file mode 100644 index b1f274367e8..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/UnsafeValueTypeAttribute.cs +++ /dev/null @@ -1,11 +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 -{ - [AttributeUsage(AttributeTargets.Struct)] - public sealed class UnsafeValueTypeAttribute : Attribute - { - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs deleted file mode 100644 index b3817d33904..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs +++ /dev/null @@ -1,198 +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.Diagnostics; -using System.Threading; -using System.Threading.Tasks; -using System.Threading.Tasks.Sources; - -#if !NETSTANDARD2_0 -using Internal.Runtime.CompilerServices; -#endif - -namespace System.Runtime.CompilerServices -{ - /// <summary>Provides an awaiter for a <see cref="ValueTask"/>.</summary> - public readonly struct ValueTaskAwaiter : ICriticalNotifyCompletion, IStateMachineBoxAwareAwaiter - { - /// <summary>Shim used to invoke an <see cref="Action"/> passed as the state argument to a <see cref="Action{Object}"/>.</summary> - internal static readonly Action<object?> s_invokeActionDelegate = state => - { - if (!(state is Action action)) - { - ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.state); - return; - } - - action(); - }; - /// <summary>The value being awaited.</summary> - private readonly ValueTask _value; - - /// <summary>Initializes the awaiter.</summary> - /// <param name="value">The value to be awaited.</param> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ValueTaskAwaiter(in ValueTask value) => _value = value; - - /// <summary>Gets whether the <see cref="ValueTask"/> has completed.</summary> - public bool IsCompleted - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _value.IsCompleted; - } - - /// <summary>Gets the result of the ValueTask.</summary> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void GetResult() => _value.ThrowIfCompletedUnsuccessfully(); - - /// <summary>Schedules the continuation action for this ValueTask.</summary> - public void OnCompleted(Action continuation) - { - object? obj = _value._obj; - Debug.Assert(obj == null || obj is Task || obj is IValueTaskSource); - - if (obj is Task t) - { - t.GetAwaiter().OnCompleted(continuation); - } - else if (obj != null) - { - Unsafe.As<IValueTaskSource>(obj).OnCompleted(s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext | ValueTaskSourceOnCompletedFlags.FlowExecutionContext); - } - else - { - ValueTask.CompletedTask.GetAwaiter().OnCompleted(continuation); - } - } - - /// <summary>Schedules the continuation action for this ValueTask.</summary> - public void UnsafeOnCompleted(Action continuation) - { - object? obj = _value._obj; - Debug.Assert(obj == null || obj is Task || obj is IValueTaskSource); - - if (obj is Task t) - { - t.GetAwaiter().UnsafeOnCompleted(continuation); - } - else if (obj != null) - { - Unsafe.As<IValueTaskSource>(obj).OnCompleted(s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); - } - else - { - ValueTask.CompletedTask.GetAwaiter().UnsafeOnCompleted(continuation); - } - } - - void IStateMachineBoxAwareAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox box) - { - object? obj = _value._obj; - Debug.Assert(obj == null || obj is Task || obj is IValueTaskSource); - - if (obj is Task t) - { - TaskAwaiter.UnsafeOnCompletedInternal(t, box, continueOnCapturedContext: true); - } - else if (obj != null) - { - Unsafe.As<IValueTaskSource>(obj).OnCompleted(ThreadPoolGlobals.s_invokeAsyncStateMachineBox, box, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); - } - else - { - TaskAwaiter.UnsafeOnCompletedInternal(Task.CompletedTask, box, continueOnCapturedContext: true); - } - } - } - - /// <summary>Provides an awaiter for a <see cref="ValueTask{TResult}"/>.</summary> - public readonly struct ValueTaskAwaiter<TResult> : ICriticalNotifyCompletion, IStateMachineBoxAwareAwaiter - { - /// <summary>The value being awaited.</summary> - private readonly ValueTask<TResult> _value; - - /// <summary>Initializes the awaiter.</summary> - /// <param name="value">The value to be awaited.</param> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ValueTaskAwaiter(in ValueTask<TResult> value) => _value = value; - - /// <summary>Gets whether the <see cref="ValueTask{TResult}"/> has completed.</summary> - public bool IsCompleted - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _value.IsCompleted; - } - - /// <summary>Gets the result of the ValueTask.</summary> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public TResult GetResult() => _value.Result; - - /// <summary>Schedules the continuation action for this ValueTask.</summary> - public void OnCompleted(Action continuation) - { - object? obj = _value._obj; - Debug.Assert(obj == null || obj is Task<TResult> || obj is IValueTaskSource<TResult>); - - if (obj is Task<TResult> t) - { - t.GetAwaiter().OnCompleted(continuation); - } - else if (obj != null) - { - Unsafe.As<IValueTaskSource<TResult>>(obj).OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext | ValueTaskSourceOnCompletedFlags.FlowExecutionContext); - } - else - { - ValueTask.CompletedTask.GetAwaiter().OnCompleted(continuation); - } - } - - /// <summary>Schedules the continuation action for this ValueTask.</summary> - public void UnsafeOnCompleted(Action continuation) - { - object? obj = _value._obj; - Debug.Assert(obj == null || obj is Task<TResult> || obj is IValueTaskSource<TResult>); - - if (obj is Task<TResult> t) - { - t.GetAwaiter().UnsafeOnCompleted(continuation); - } - else if (obj != null) - { - Unsafe.As<IValueTaskSource<TResult>>(obj).OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); - } - else - { - ValueTask.CompletedTask.GetAwaiter().UnsafeOnCompleted(continuation); - } - } - - void IStateMachineBoxAwareAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox box) - { - object? obj = _value._obj; - Debug.Assert(obj == null || obj is Task<TResult> || obj is IValueTaskSource<TResult>); - - if (obj is Task<TResult> t) - { - TaskAwaiter.UnsafeOnCompletedInternal(t, box, continueOnCapturedContext: true); - } - else if (obj != null) - { - Unsafe.As<IValueTaskSource<TResult>>(obj).OnCompleted(ThreadPoolGlobals.s_invokeAsyncStateMachineBox, box, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); - } - else - { - TaskAwaiter.UnsafeOnCompletedInternal(Task.CompletedTask, box, continueOnCapturedContext: true); - } - } - } - - /// <summary>Internal interface used to enable optimizations from <see cref="AsyncTaskMethodBuilder"/>.</summary>> - internal interface IStateMachineBoxAwareAwaiter - { - /// <summary>Invoked to set <see cref="ITaskCompletionAction.Invoke"/> of the <paramref name="box"/> as the awaiter's continuation.</summary> - /// <param name="box">The box object.</param> - void AwaitUnsafeOnCompleted(IAsyncStateMachineBox box); - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/YieldAwaitable.cs b/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/YieldAwaitable.cs deleted file mode 100644 index cda89738f3e..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Runtime/CompilerServices/YieldAwaitable.cs +++ /dev/null @@ -1,195 +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. - -// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -// -// -// -// Compiler-targeted type for switching back into the current execution context, e.g. -// -// await Task.Yield(); -// ===================== -// var $awaiter = Task.Yield().GetAwaiter(); -// if (!$awaiter.IsCompleted) -// { -// $builder.AwaitUnsafeOnCompleted(ref $awaiter, ref this); -// return; -// Label: -// } -// $awaiter.GetResult(); -// -// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - -using System.Diagnostics; -using System.Diagnostics.Tracing; -using System.Threading; -using System.Threading.Tasks; - -namespace System.Runtime.CompilerServices -{ - // NOTE: YieldAwaitable currently has no state; while developers are encouraged to use Task.Yield() to produce one, - // no validation is performed to ensure that the developer isn't doing "await new YieldAwaitable()". Such validation - // would require additional, useless state to be stored, and as this is a type in the CompilerServices namespace, and - // as the above example isn't harmful, we take the cheaper approach of not validating anything. - - /// <summary>Provides an awaitable context for switching into a target environment.</summary> - /// <remarks>This type is intended for compiler use only.</remarks> - public readonly struct YieldAwaitable - { - /// <summary>Gets an awaiter for this <see cref="YieldAwaitable"/>.</summary> - /// <returns>An awaiter for this awaitable.</returns> - /// <remarks>This method is intended for compiler user rather than use directly in code.</remarks> - public YieldAwaiter GetAwaiter() { return default; } - - /// <summary>Provides an awaiter that switches into a target environment.</summary> - /// <remarks>This type is intended for compiler use only.</remarks> - public readonly struct YieldAwaiter : ICriticalNotifyCompletion, IStateMachineBoxAwareAwaiter - { - /// <summary>Gets whether a yield is not required.</summary> - /// <remarks>This property is intended for compiler user rather than use directly in code.</remarks> - public bool IsCompleted => false; // yielding is always required for YieldAwaiter, hence false - - /// <summary>Posts the <paramref name="continuation"/> back to the current context.</summary> - /// <param name="continuation">The action to invoke asynchronously.</param> - /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception> - public void OnCompleted(Action continuation) - { - QueueContinuation(continuation, flowContext: true); - } - - /// <summary>Posts the <paramref name="continuation"/> back to the current context.</summary> - /// <param name="continuation">The action to invoke asynchronously.</param> - /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception> - public void UnsafeOnCompleted(Action continuation) - { - QueueContinuation(continuation, flowContext: false); - } - - /// <summary>Posts the <paramref name="continuation"/> back to the current context.</summary> - /// <param name="continuation">The action to invoke asynchronously.</param> - /// <param name="flowContext">true to flow ExecutionContext; false if flowing is not required.</param> - /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception> - private static void QueueContinuation(Action continuation, bool flowContext) - { - // Validate arguments - if (continuation == null) throw new ArgumentNullException(nameof(continuation)); - - if (TplEventSource.Log.IsEnabled()) - { - continuation = OutputCorrelationEtwEvent(continuation); - } - // Get the current SynchronizationContext, and if there is one, - // post the continuation to it. However, treat the base type - // as if there wasn't a SynchronizationContext, since that's what it - // logically represents. - SynchronizationContext? syncCtx = SynchronizationContext.Current; - if (syncCtx != null && syncCtx.GetType() != typeof(SynchronizationContext)) - { - syncCtx.Post(s_sendOrPostCallbackRunAction, continuation); - } - else - { - // If we're targeting the default scheduler, queue to the thread pool, so that we go into the global - // queue. As we're going into the global queue, we might as well use QUWI, which for the global queue is - // just a tad faster than task, due to a smaller object getting allocated and less work on the execution path. - TaskScheduler scheduler = TaskScheduler.Current; - if (scheduler == TaskScheduler.Default) - { - if (flowContext) - { - ThreadPool.QueueUserWorkItem(s_waitCallbackRunAction, continuation); - } - else - { - ThreadPool.UnsafeQueueUserWorkItem(s_waitCallbackRunAction, continuation); - } - } - // We're targeting a custom scheduler, so queue a task. - else - { - Task.Factory.StartNew(continuation, default, TaskCreationOptions.PreferFairness, scheduler); - } - } - } - - void IStateMachineBoxAwareAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox box) - { - Debug.Assert(box != null); - - // If tracing is enabled, delegate the Action-based implementation. - if (TplEventSource.Log.IsEnabled()) - { - QueueContinuation(box.MoveNextAction, flowContext: false); - return; - } - - // Otherwise, this is the same logic as in QueueContinuation, except using - // an IAsyncStateMachineBox instead of an Action, and only for flowContext:false. - - SynchronizationContext? syncCtx = SynchronizationContext.Current; - if (syncCtx != null && syncCtx.GetType() != typeof(SynchronizationContext)) - { - syncCtx.Post(s => ((IAsyncStateMachineBox)s!).MoveNext(), box); - } - else - { - TaskScheduler scheduler = TaskScheduler.Current; - if (scheduler == TaskScheduler.Default) - { - ThreadPool.UnsafeQueueUserWorkItemInternal(box, preferLocal: false); - } - else - { - Task.Factory.StartNew(s => ((IAsyncStateMachineBox)s!).MoveNext(), box, default, TaskCreationOptions.PreferFairness, scheduler); - } - } - } - - private static Action OutputCorrelationEtwEvent(Action continuation) - { -#if CORERT - // TODO - return continuation; -#else - int continuationId = Task.NewId(); - Task? currentTask = Task.InternalCurrent; - // fire the correlation ETW event - TplEventSource.Log.AwaitTaskContinuationScheduled(TaskScheduler.Current.Id, (currentTask != null) ? currentTask.Id : 0, continuationId); - - return AsyncMethodBuilderCore.CreateContinuationWrapper(continuation, (innerContinuation, continuationIdTask) => - { - TplEventSource log = TplEventSource.Log; - log.TaskWaitContinuationStarted(((Task<int>)continuationIdTask).Result); - - // ETW event for Task Wait End. - Guid prevActivityId = default; - // Ensure the continuation runs under the correlated activity ID generated above - if (log.TasksSetActivityIds) - EventSource.SetCurrentThreadActivityId(TplEventSource.CreateGuidForTaskID(((Task<int>)continuationIdTask).Result), out prevActivityId); - - // Invoke the original continuation provided to OnCompleted. - innerContinuation(); - // Restore activity ID - - if (log.TasksSetActivityIds) - EventSource.SetCurrentThreadActivityId(prevActivityId); - - log.TaskWaitContinuationComplete(((Task<int>)continuationIdTask).Result); - }, Task.FromResult(continuationId)); // pass the ID in a task to avoid a closure\ -#endif - } - - /// <summary>WaitCallback that invokes the Action supplied as object state.</summary> - private static readonly WaitCallback s_waitCallbackRunAction = RunAction; - /// <summary>SendOrPostCallback that invokes the Action supplied as object state.</summary> - private static readonly SendOrPostCallback s_sendOrPostCallbackRunAction = RunAction; - /// <summary>Runs an Action delegate provided as state.</summary> - /// <param name="state">The Action delegate to invoke.</param> - private static void RunAction(object? state) { ((Action)state!)(); } - - /// <summary>Ends the await operation.</summary> - public void GetResult() { } // Nop. It exists purely because the compiler pattern demands it. - } - } -} |