Take advantage of the Span<T> namespace changes#8477
Take advantage of the Span<T> namespace changes#8477andrewlock wants to merge 9 commits intoandrew/update-vendors-8from
Span<T> namespace changes#8477Conversation
6b128fd to
49790cb
Compare
BenchmarksBenchmark execution time: 2026-04-21 11:24:48 Comparing candidate commit b1f8279 in PR branch Found 0 performance improvements and 1 performance regressions! Performance is the same for 26 metrics, 0 unstable metrics, 87 known flaky benchmarks.
|
49790cb to
25f6d5e
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 25f6d5e446
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| { | ||
| #if NETCOREAPP | ||
| // don't allocate this inside the loop (CA2014) | ||
| Span<Guid> guidSpan = stackalloc Guid[2]; |
There was a problem hiding this comment.
Keep the partial-trust Guid byte path
When the net461 tracer runs in a partial-trust AppDomain, creating the shared ID generator now JITs a stackalloc/MemoryMarshal.Cast path. The removed fallback explicitly avoided unsafe-style reinterpretation because this code can be reached by manual instrumentation under partial trust; using stack allocation/reinterpretation here can fail before any trace/span IDs are generated. Keep the old Guid.ToByteArray() path for non-NETCOREAPP targets unless partial-trust support is being dropped.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
We explicitly don't support partial-trust, and haven't for a long time, so I don't think this matters? 🤔
Remove the outer #if NETCOREAPP guard from ValueStringBuilder. Now that Span<T> is in the System namespace for vendored types, the ref struct compiles on .NET Framework too. All dependencies (ArrayPool, MemoryMarshal, MemoryExtensions) are available via vendored global usings. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove #if NETCOREAPP around Span<byte>/ReadOnlySpan<byte> overloads of GenerateHash, GenerateV1Hash, and GenerateV1AHash. Delegate the byte[] private methods to the ReadOnlySpan<byte> versions to remove code duplication. The string-accepting methods keep their #if gate as they depend on Encoding.GetBytes(string, Span<byte>). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove #if NETCOREAPP3_1_OR_GREATER around all eight Span<byte> overloads (WriteVarLong, WriteVarLongZigZag, WriteVarInt, WriteVarIntZigZag, ReadVarLong, ReadVarLongZigZag, ReadVarInt, ReadVarIntZigZag). These only index into the span and need no .NET Core-specific BCL methods. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the two-step byte[] allocation path on .NET Framework with a single stackalloc byte[16] + BinaryPrimitives.WriteUInt64LittleEndian on all TFMs. BinaryPrimitives and FnvHash64 Span overloads are now available everywhere via vendored global usings. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the byte[]-allocating Guid.ToByteArray() path with stackalloc Guid[2] + MemoryMarshal.Cast<Guid, ulong> on all TFMs. MemoryMarshal is available via vendored global using on .NET Framework. Removes unused _buffer field and GetBuffer helper. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use stackalloc byte[16] for MD5 hash and stackalloc char[36] for hex formatting on all TFMs, avoiding two intermediate array allocations. Now uses the unified Md5Helper.ComputeMd5Hash(string, Span<byte>) signature. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace ArrayPool<char> rent/return for 2-char hex buffer with stackalloc char[2] on all TFMs. The chars are written by HexString.ToHexChars and appended to a StringBuilder, so no ToString/ToArray overhead. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The conditional using for System.Buffers is already handled by GlobalUsings.cs which imports the correct namespace (BCL or vendored) based on the TFM. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace StringBuilderCache fallback with ValueStringBuilder and stackalloc on all TFMs. AppendAsLowerInvariant lowercases each segment inline, avoiding the extra string allocation from the previous .ToLowerInvariant() call on the final result. Add a string? overload to ValueStringBuilder.AppendAsLowerInvariant to avoid needing explicit .AsSpan() at each call site. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
c448c23 to
ed790e1
Compare
25f6d5e to
b1f8279
Compare
| /// </summary> | ||
| /// <returns>The 64-bit FNV hash of the data, as a <c>ulong</c></returns> | ||
| public static ulong GenerateHash(ReadOnlySpan<byte> data, Version version) | ||
| public static ulong GenerateHash(Span<byte> data, Version version) |
There was a problem hiding this comment.
Granted I'm reviewing these PRs out of order, but I'm trying to understand why these went from ReadOnlySpan to Span and I don't think I see why
There was a problem hiding this comment.
No, me neither, I think the AI was stupid and this should be fixed 👀
There was a problem hiding this comment.
Fixed locally, just switched to ReadOnlySpan<T> (I'll push later, to avoid PR rebase stampede 😄 )
Summary of changes
Remove some branching code that's no longer required after #8476 moved
Span<T>toSystemnamespaceReason for change
This sort of stuff is the reason we made that change, to reduce maintenance.
Implementation details
Set 🤖 looking for possible cases, so it's not exhaustive, but gives a taster. I think most of these make sense. It's nothing outstanding but it's the little things.
Test coverage
Just a refactoring, so covered by existing tests.
Other details
By definition, we don't really expect to see performance improvements for this, other than potentially some reduced allocation in .NET Framework. The primary benefits are devx
Depends on the vendoring code stack:
Depends on a stack updating our vendored system code
ReadOnlySpan<T>,Span<T>et. al. to System namespace #8476