Remove GetWaiterTask allocation for display class (dotnet/corefx#39411)
authorStephen Toub <stoub@microsoft.com>
Fri, 12 Jul 2019 00:28:47 +0000 (20:28 -0400)
committerGitHub <noreply@github.com>
Fri, 12 Jul 2019 00:28:47 +0000 (20:28 -0400)
Using an async local function here that accesses its outer function's state is resulting in the compiler allocating a display class at the beginning of GetWaiterTask.

Commit migrated from https://github.com/dotnet/corefx/commit/59b60a232ecf3df2319fadd0193f5dcb42948e29

src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs

index 052ebe4..6be326d 100644 (file)
@@ -747,34 +747,34 @@ namespace System.Net.Http
                 // if it is cancelable, then register for the cancellation callback, allocate a task for the asynchronously
                 // completing case, etc.
                 return cancellationToken.CanBeCanceled ?
-                    new ValueTask(GetWaiterTaskCore()) :
+                    new ValueTask(GetCancelableWaiterTask(cancellationToken)) :
                     new ValueTask(this, _waitSource.Version);
+            }
 
-                async Task GetWaiterTaskCore()
+            private async Task GetCancelableWaiterTask(CancellationToken cancellationToken)
+            {
+                using (cancellationToken.UnsafeRegister(s =>
                 {
-                    using (cancellationToken.UnsafeRegister(s =>
-                    {
-                        var thisRef = (Http2Stream)s;
-
-                        bool signalWaiter;
-                        lock (thisRef.SyncObject)
-                        {
-                            signalWaiter = thisRef._hasWaiter;
-                            thisRef._hasWaiter = false;
-                        }
+                    var thisRef = (Http2Stream)s;
 
-                        if (signalWaiter)
-                        {
-                            // Wake up the wait.  It will then immediately check whether cancellation was requested and throw if it was.
-                            thisRef._waitSource.SetResult(true);
-                        }
-                    }, this))
+                    bool signalWaiter;
+                    lock (thisRef.SyncObject)
                     {
-                        await new ValueTask(this, _waitSource.Version).ConfigureAwait(false);
+                        signalWaiter = thisRef._hasWaiter;
+                        thisRef._hasWaiter = false;
                     }
 
-                    CancellationHelper.ThrowIfCancellationRequested(cancellationToken);
+                    if (signalWaiter)
+                    {
+                        // Wake up the wait.  It will then immediately check whether cancellation was requested and throw if it was.
+                        thisRef._waitSource.SetResult(true);
+                    }
+                }, this))
+                {
+                    await new ValueTask(this, _waitSource.Version).ConfigureAwait(false);
                 }
+
+                CancellationHelper.ThrowIfCancellationRequested(cancellationToken);
             }
 
             public void Trace(string message, [CallerMemberName] string memberName = null) =>