diff --git a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs
index 66ad43e14567..6cfe8ef11db9 100644
--- a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs
+++ b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs
@@ -28,7 +28,15 @@ public readonly struct ConfiguredValueTaskAwaitable
/// Returns an awaiter for this instance.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ConfiguredValueTaskAwaiter GetAwaiter() => new ConfiguredValueTaskAwaiter(_value);
+ public ConfiguredValueTaskAwaiter GetAwaiter()
+ {
+ // Unsafe casting to work around https://github.com/dotnet/coreclr/issues/18542
+
+ // NOTE: This only works because ConfiguredValueTaskAwaiter and ConfiguredValueTaskAwaitable are structs,
+ // exactly the same data layout and ConfiguredValueTaskAwaitable.ctor does no real initalization.
+
+ return Unsafe.As(ref Unsafe.AsRef(in this));
+ }
/// Provides an awaiter for a .
[StructLayout(LayoutKind.Auto)]
@@ -134,7 +142,15 @@ public readonly struct ConfiguredValueTaskAwaitable
/// Returns an awaiter for this instance.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ConfiguredValueTaskAwaiter GetAwaiter() => new ConfiguredValueTaskAwaiter(_value);
+ public ConfiguredValueTaskAwaiter GetAwaiter()
+ {
+ // Unsafe casting to work around https://github.com/dotnet/coreclr/issues/18542
+
+ // NOTE: This only works because ConfiguredValueTaskAwaiter and ConfiguredValueTaskAwaitable are structs,
+ // exactly the same data layout and ConfiguredValueTaskAwaitable.ctor does no real initalization.
+
+ return Unsafe.As, ConfiguredValueTaskAwaiter>(ref Unsafe.AsRef(in this));
+ }
/// Provides an awaiter for a .
[StructLayout(LayoutKind.Auto)]
diff --git a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs
index 56d8bca99d43..c851222defee 100644
--- a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs
+++ b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs
@@ -30,10 +30,18 @@ namespace System.Runtime.CompilerServices
/// The value being awaited.
private readonly ValueTask _value;
+ // NOTE: If any extra fields are added ValueTask.GetAwaiter
+ // must be updated to call the constructor.
+
/// Initializes the awaiter.
/// The value to be awaited.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal ValueTaskAwaiter(ValueTask value) => _value = value;
+ internal ValueTaskAwaiter(ValueTask value)
+ {
+ // NOTE: If this method is ever updated to perform more initialization,
+ // ValueTask.GetAwaiter must be updated to call this.
+ _value = value;
+ }
/// Gets whether the has completed.
public bool IsCompleted
@@ -113,10 +121,18 @@ void IStateMachineBoxAwareAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox b
/// The value being awaited.
private readonly ValueTask _value;
+ // NOTE: If any extra fields are added ValueTask.GetAwaiter
+ // must be updated to call the constructor.
+
/// Initializes the awaiter.
/// The value to be awaited.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal ValueTaskAwaiter(ValueTask value) => _value = value;
+ internal ValueTaskAwaiter(ValueTask value)
+ {
+ // NOTE: If this method is ever updated to perform more initialization,
+ // ValueTask.GetAwaiter must be updated to call this.
+ _value = value;
+ }
/// Gets whether the has completed.
public bool IsCompleted
diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/ValueTask.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/ValueTask.cs
index 256d4d71a2c3..f4655177f936 100644
--- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/ValueTask.cs
+++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/ValueTask.cs
@@ -369,7 +369,16 @@ internal void ThrowIfCompletedUnsuccessfully()
}
/// Gets an awaiter for this .
- public ValueTaskAwaiter GetAwaiter() => new ValueTaskAwaiter(this);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ValueTaskAwaiter GetAwaiter()
+ {
+ // Unsafe casting to work around https://github.com/dotnet/coreclr/issues/18542
+
+ // NOTE: This only works because ValueTaskAwaiter and ValueTask are structs,
+ // exactly the same data layout and ValueTaskAwaiter does no real initalization.
+
+ return Unsafe.As(ref Unsafe.AsRef(in this));
+ }
/// Configures an awaiter for this .
///
@@ -377,7 +386,18 @@ internal void ThrowIfCompletedUnsuccessfully()
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ConfiguredValueTaskAwaitable ConfigureAwait(bool continueOnCapturedContext) =>
- new ConfiguredValueTaskAwaitable(new ValueTask(_obj, _token, continueOnCapturedContext));
+ ConfigureTask(new ValueTask(_obj, _token, continueOnCapturedContext));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static ref readonly ConfiguredValueTaskAwaitable ConfigureTask(in ValueTask vt)
+ {
+ // Unsafe casting to work around https://github.com/dotnet/coreclr/issues/18542
+
+ // NOTE: This only works because ConfiguredValueTaskAwaitable and ValueTask are structs,
+ // exactly the same data layout and ConfiguredValueTaskAwaitable.ctor does no real initalization.
+
+ return ref Unsafe.As(ref Unsafe.AsRef(in vt));
+ }
}
/// Provides a value type that can represent a synchronously available value or a task object.
@@ -765,15 +785,34 @@ public TResult Result
/// Gets an awaiter for this .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ValueTaskAwaiter GetAwaiter() => new ValueTaskAwaiter(this);
+ public ValueTaskAwaiter GetAwaiter()
+ {
+ // Unsafe casting to work around https://github.com/dotnet/coreclr/issues/18542
+
+ // NOTE: This only works because ValueTaskAwaiter and ValueTask are structs,
+ // exactly the same data layout and ValueTaskAwaiter.ctor does no real initalization.
+
+ return Unsafe.As, ValueTaskAwaiter>(ref Unsafe.AsRef(in this));
+ }
/// Configures an awaiter for this .
///
/// true to attempt to marshal the continuation back to the captured context; otherwise, false.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ConfiguredValueTaskAwaitable ConfigureAwait(bool continueOnCapturedContext) =>
- new ConfiguredValueTaskAwaitable(new ValueTask(_obj, _result, _token, continueOnCapturedContext));
+ public ConfiguredValueTaskAwaitable ConfigureAwait(bool continueOnCapturedContext)
+ => ConfigureTask(new ValueTask(_obj, _result, _token, continueOnCapturedContext));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static ref readonly ConfiguredValueTaskAwaitable ConfigureTask(in ValueTask vt)
+ {
+ // Unsafe casting to work around https://github.com/dotnet/coreclr/issues/18542
+
+ // NOTE: This only works because ConfiguredValueTaskAwaitable and ValueTask are structs,
+ // exactly the same data layout and ConfiguredValueTaskAwaitable.ctor does no real initalization.
+
+ return ref Unsafe.As, ConfiguredValueTaskAwaitable>(ref Unsafe.AsRef(in vt));
+ }
/// Gets a string-representation of this .
public override string ToString()