AsyncIteratorMethodBuilder.cs 5.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. #if !BCL_HAS_CONFIGUREAWAIT
  2. // Licensed to the .NET Foundation under one or more agreements.
  3. // The .NET Foundation licenses this file to you under the MIT license.
  4. // See the LICENSE file in the project root for more information.
  5. using System.Diagnostics;
  6. using System.Reflection;
  7. using System.Runtime.InteropServices;
  8. using System.Text;
  9. using System.Threading;
  10. using System.Threading.Tasks;
  11. namespace System.Runtime.CompilerServices
  12. {
  13. /// <summary>Represents a builder for asynchronous iterators.</summary>
  14. [StructLayout(LayoutKind.Auto)]
  15. public struct AsyncIteratorMethodBuilder
  16. {
  17. // AsyncIteratorMethodBuilder is used by the language compiler as part of generating
  18. // async iterators. For now, the implementation just wraps AsyncTaskMethodBuilder, as
  19. // most of the logic is shared. However, in the future this could be changed and
  20. // optimized. For example, we do need to allocate an object (once) to flow state like
  21. // ExecutionContext, which AsyncTaskMethodBuilder handles, but it handles it by
  22. // allocating a Task-derived object. We could optimize this further by removing
  23. // the Task from the hierarchy, but in doing so we'd also lose a variety of optimizations
  24. // related to it, so we'd need to replicate all of those optimizations (e.g. storing
  25. // that box object directly into a Task's continuation field).
  26. #pragma warning disable IDE0044 // Add readonly modifier
  27. private AsyncTaskMethodBuilder _methodBuilder; // mutable struct; do not make it readonly
  28. #pragma warning restore IDE0044 // Add readonly modifier
  29. /// <summary>Creates an instance of the <see cref="AsyncIteratorMethodBuilder"/> struct.</summary>
  30. /// <returns>The initialized instance.</returns>
  31. public static AsyncIteratorMethodBuilder Create() =>
  32. #if PROJECTN
  33. // ProjectN's AsyncTaskMethodBuilder.Create() currently does additional debugger-related
  34. // work, so we need to delegate to it.
  35. new AsyncIteratorMethodBuilder() { _methodBuilder = AsyncTaskMethodBuilder.Create() };
  36. #else
  37. // _methodBuilder should be initialized to AsyncTaskMethodBuilder.Create(), but on coreclr
  38. // that Create() is a nop, so we can just return the default here.
  39. default;
  40. #endif
  41. /// <summary>Invokes <see cref="IAsyncStateMachine.MoveNext"/> on the state machine while guarding the <see cref="ExecutionContext"/>.</summary>
  42. /// <typeparam name="TStateMachine">The type of the state machine.</typeparam>
  43. /// <param name="stateMachine">The state machine instance, passed by reference.</param>
  44. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  45. public void MoveNext<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine =>
  46. #if CORERT || !BCL_HAS_CONFIGUREAWAIT
  47. _methodBuilder.Start(ref stateMachine);
  48. #else
  49. AsyncMethodBuilderCore.Start(ref stateMachine);
  50. #endif
  51. /// <summary>Schedules the state machine to proceed to the next action when the specified awaiter completes.</summary>
  52. /// <typeparam name="TAwaiter">The type of the awaiter.</typeparam>
  53. /// <typeparam name="TStateMachine">The type of the state machine.</typeparam>
  54. /// <param name="awaiter">The awaiter.</param>
  55. /// <param name="stateMachine">The state machine.</param>
  56. public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
  57. where TAwaiter : INotifyCompletion
  58. where TStateMachine : IAsyncStateMachine =>
  59. _methodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine);
  60. /// <summary>Schedules the state machine to proceed to the next action when the specified awaiter completes.</summary>
  61. /// <typeparam name="TAwaiter">The type of the awaiter.</typeparam>
  62. /// <typeparam name="TStateMachine">The type of the state machine.</typeparam>
  63. /// <param name="awaiter">The awaiter.</param>
  64. /// <param name="stateMachine">The state machine.</param>
  65. public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
  66. where TAwaiter : ICriticalNotifyCompletion
  67. where TStateMachine : IAsyncStateMachine =>
  68. _methodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
  69. /// <summary>Marks iteration as being completed, whether successfully or otherwise.</summary>
  70. public void Complete() => _methodBuilder.SetResult();
  71. /// <summary>Gets an object that may be used to uniquely identify this builder to the debugger.</summary>
  72. internal object ObjectIdForDebugger => typeof(AsyncTaskMethodBuilder)
  73. .GetProperty("ObjectIdForDebugger", BindingFlags.Instance | BindingFlags.NonPublic)
  74. .GetMethod.Invoke(_methodBuilder, null);
  75. }
  76. }
  77. #else
  78. using System.Runtime.CompilerServices;
  79. [assembly: TypeForwardedTo(typeof(AsyncIteratorMethodBuilder))]
  80. #endif