diff --git a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncMethodBuilder.cs b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncMethodBuilder.cs index ef5d609a800..1a640c7d377 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncMethodBuilder.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncMethodBuilder.cs @@ -544,12 +544,16 @@ private class AsyncStateMachineBox : // SOS DumpAsync command dep where TStateMachine : IAsyncStateMachine { /// Delegate used to invoke on an ExecutionContext when passed an instance of this box type. - private static readonly ContextCallback s_callback = s => + 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); // Only used privately to pass directly to EC.Run Unsafe.As>(s).StateMachine.MoveNext(); - }; + } /// A delegate to the method. private Action _moveNextAction; diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Future.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Future.cs index 06eb1186ae2..7a1711b409f 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Future.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Future.cs @@ -67,11 +67,16 @@ public class Task : Task private static readonly TaskFactory s_Factory = new TaskFactory(); - // Delegate used by: - // public static Task> WhenAny(IEnumerable> tasks); - // public static Task> WhenAny(params Task[] tasks); - // Used to "cast" from Task to Task>. - internal static readonly Func, Task> TaskWhenAnyCast = completed => (Task)completed.Result; + // Extract rarely used helper for a static method in a separate type so that the Func, Task> + // generic instantiations don't contribute to all Task instantiations, but only those where WhenAny is used. + internal static class TaskWhenAnyCast + { + // Delegate used by: + // public static Task> WhenAny(IEnumerable> tasks); + // public static Task> WhenAny(params Task[] tasks); + // Used to "cast" from Task to Task>. + internal static readonly Func, Task> Value = completed => (Task)completed.Result; + } // Construct a promise-style task without any options. internal Task() : diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs index a6bc8a5a0ca..2e2c6d61bf7 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs @@ -6156,7 +6156,7 @@ public static Task> WhenAny(params Task[] tasks) Task intermediate = WhenAny((Task[])tasks); // Return a continuation task with the correct result type - return intermediate.ContinueWith(Task.TaskWhenAnyCast, default, + return intermediate.ContinueWith(Task.TaskWhenAnyCast.Value, default, TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.DenyChildAttach, TaskScheduler.Default); } @@ -6185,7 +6185,7 @@ public static Task> WhenAny(IEnumerable> ta Task intermediate = WhenAny((IEnumerable)tasks); // Return a continuation task with the correct result type - return intermediate.ContinueWith(Task.TaskWhenAnyCast, default, + return intermediate.ContinueWith(Task.TaskWhenAnyCast.Value, default, TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.DenyChildAttach, TaskScheduler.Default); } #endregion