Avoid async method delegate allocation
authorStephen Toub <stoub@microsoft.com>
Mon, 25 Sep 2017 16:02:10 +0000 (12:02 -0400)
committerStephen Toub <stoub@microsoft.com>
Tue, 26 Sep 2017 01:53:46 +0000 (21:53 -0400)
commit9a0630152c4339324ba9ac0fa886f9fb4916e759
tree4332ca6637f583698cc7a0ec1c947328cebb3ee9
parent522c30957ac8b45e692420974bf9732d49503a36
Avoid async method delegate allocation

Previously when a task-returning async method would yield for the first time, there would be four allocations: the task, the state machine object boxed to the heap, a context "runner" object, and a delegate that points to the boxed state machine's MoveNext method.  A recent PR changed this to avoid the separate box object and the runner, but that still left the task and the delegate.

This PR avoids the delegate as well in a common case.  For async methods that only ever await Task/Task`1, that aren't using a custom sync context/scheduler, and for which tracing isn't enabled, we know the inner workings of both the builder and the awaiter and can thus bypass the awaiter's pattern APIs; instead of creating the delegate that gets passed to the awaiter and then stored in the wrapped task's continuation slot/list, we can instead just store the boxed state machine directly in the slot/list.
src/mscorlib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs
src/mscorlib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs
src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs
src/mscorlib/src/System/Runtime/CompilerServices/TaskAwaiter.cs
src/mscorlib/src/System/Threading/Tasks/Task.cs