diff --git a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems index a3dd64c87a3a..d03e79685e79 100644 --- a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems +++ b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems @@ -424,6 +424,7 @@ + diff --git a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncIteratorMethodBuilder.cs b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncIteratorMethodBuilder.cs new file mode 100644 index 000000000000..7605bdd55e16 --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncIteratorMethodBuilder.cs @@ -0,0 +1,77 @@ +// 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; +using System.Threading.Tasks; + +namespace System.Runtime.CompilerServices +{ + /// Represents a builder for asynchronous iterators. + [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 + + /// Creates an instance of the struct. + /// The initialized instance. + public static AsyncIteratorMethodBuilder Create() => +#if CORERT + // corert's AsyncTaskMethodBuilder.Create() currently does additional debugger-related + // work, so we need to delegate to it. + new AsyncIteratorMethodBuilder() { _methodBuilder = AsyncTaskMethodBuilder.Create() }; +#else + default; // coreclr's AsyncTaskMethodBuilder.Create just returns default as well +#endif + + /// Invokes on the state machine while guarding the + /// The type of the state machine. + /// The state machine instance, passed by reference. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void MoveNext(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine => +#if CORERT + _methodBuilder.Start(ref stateMachine); +#else + AsyncMethodBuilderCore.Start(ref stateMachine); +#endif + + /// Schedules the state machine to proceed to the next action when the specified awaiter completes. + /// The type of the awaiter. + /// The type of the state machine. + /// The awaiter. + /// The state machine. + public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : INotifyCompletion + where TStateMachine : IAsyncStateMachine => + _methodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine); + + /// Schedules the state machine to proceed to the next action when the specified awaiter completes. + /// The type of the awaiter. + /// The type of the state machine. + /// The awaiter. + /// The state machine. + public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : ICriticalNotifyCompletion + where TStateMachine : IAsyncStateMachine => + _methodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine); + + /// Marks iteration as being completed, whether successfully or otherwise. + public void Complete() => + _methodBuilder.SetResult(); + + /// Gets an object that may be used to uniquely identify this builder to the debugger. + internal object ObjectIdForDebugger => + _methodBuilder.ObjectIdForDebugger; + } +}