From 993f99611a39c2cd337e1ea62b0a9d05c5a1a067 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 12 Jun 2026 19:39:35 +0000 Subject: [PATCH 1/3] Initial plan From 81263b6a2c5d6692e766c83c55d575003cdbe2e8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 12 Jun 2026 19:45:56 +0000 Subject: [PATCH 2/3] Optimize netfx websocket read buffer path Co-authored-by: AArnott <3548+AArnott@users.noreply.github.com> --- src/StreamJsonRpc/WebSocketMessageHandler.cs | 24 ++++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/StreamJsonRpc/WebSocketMessageHandler.cs b/src/StreamJsonRpc/WebSocketMessageHandler.cs index e2671802e..86e1f778f 100644 --- a/src/StreamJsonRpc/WebSocketMessageHandler.cs +++ b/src/StreamJsonRpc/WebSocketMessageHandler.cs @@ -96,17 +96,27 @@ void IJsonRpcMessageBufferManager.DeserializationComplete(JsonRpcMessage message result = await this.WebSocket.ReceiveAsync(memory, cancellationToken).ConfigureAwait(false); this.contentSequenceBuilder.Advance(result.Count); #else - ArrayPool pool = ArrayPool.Shared; - byte[] segment = pool.Rent(this.sizeHint); - try + Memory memory = this.contentSequenceBuilder.GetMemory(this.sizeHint); + if (MemoryMarshal.TryGetArray(memory, out ArraySegment segment)) { - result = await this.WebSocket.ReceiveAsync(new ArraySegment(segment), cancellationToken).ConfigureAwait(false); - this.contentSequenceBuilder.Write(segment.AsSpan(0, result.Count)); + result = await this.WebSocket.ReceiveAsync(segment, cancellationToken).ConfigureAwait(false); } - finally + else { - pool.Return(segment); + ArrayPool pool = ArrayPool.Shared; + byte[] rented = pool.Rent(memory.Length); + try + { + result = await this.WebSocket.ReceiveAsync(new ArraySegment(rented), cancellationToken).ConfigureAwait(false); + rented.AsSpan(0, result.Count).CopyTo(memory.Span); + } + finally + { + pool.Return(rented); + } } + + this.contentSequenceBuilder.Advance(result.Count); #endif if (result.MessageType == WebSocketMessageType.Close) { From 3b4a2f9d146df296ff3fdb9f3a15386089895394 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 12 Jun 2026 19:51:04 +0000 Subject: [PATCH 3/3] Limit pooled receive segment to destination memory length Co-authored-by: AArnott <3548+AArnott@users.noreply.github.com> --- src/StreamJsonRpc/WebSocketMessageHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/StreamJsonRpc/WebSocketMessageHandler.cs b/src/StreamJsonRpc/WebSocketMessageHandler.cs index 86e1f778f..6b80e53a1 100644 --- a/src/StreamJsonRpc/WebSocketMessageHandler.cs +++ b/src/StreamJsonRpc/WebSocketMessageHandler.cs @@ -107,7 +107,7 @@ void IJsonRpcMessageBufferManager.DeserializationComplete(JsonRpcMessage message byte[] rented = pool.Rent(memory.Length); try { - result = await this.WebSocket.ReceiveAsync(new ArraySegment(rented), cancellationToken).ConfigureAwait(false); + result = await this.WebSocket.ReceiveAsync(new ArraySegment(rented, 0, memory.Length), cancellationToken).ConfigureAwait(false); rented.AsSpan(0, result.Count).CopyTo(memory.Span); } finally