Replace small stackallocs with collection literals#128389
Conversation
There was a problem hiding this comment.
Pull request overview
This PR replaces several very small stackalloc scratch buffers with C# collection expressions targeting Span<T> / ReadOnlySpan<T>, and removes unsafe modifiers that were only present to enable those small stackallocs.
Changes:
- Replaced tiny
stackallocbuffers (e.g., 1–4 elements) with collection expressions (e.g.,[0, 0, 0, 0],['\0', '\0']) across multiple libraries. - Removed
unsafefrom a number of methods / local functions where it was only needed for thosestackallocs. - Kept existing behavior by continuing to use stack-based scratch spans for transient buffers (subject to compiler lowering), while simplifying method signatures.
Reviewed changes
Copilot reviewed 26 out of 26 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs | Removes an unsafe local function and replaces tiny scratch stackalloc spans with collection expressions. |
| src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs | Replaces small stackalloc spans used for category / set-char probing with collection expressions. |
| src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.StringSegment.cs | Removes unsafe from leftover-handling helpers and replaces small combined-buffer stackallocs with collection expressions. |
| src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X500DistinguishedNameBuilder.cs | Removes unsafe from AddCountryOrRegion and uses a 2-char collection expression buffer. |
| src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/LiteHash.Windows.cs | Replaces a 1-byte stackalloc scratch buffer with [0]. |
| src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs | Removes unsafe from the BigInteger(decimal) ctor and uses a 4-int collection expression buffer. |
| src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/DecimalUtilities.cs | Removes unsafe from helpers and uses 4-int collection expression buffers. |
| src/libraries/System.Private.Uri/src/System/UriHelper.cs | Removes unsafe from EscapeStringToBuilder and replaces a 4-byte scratch stackalloc with a collection expression. |
| src/libraries/System.Private.Uri/src/System/IriHelper.cs | Removes unsafe and replaces a 4-byte scratch stackalloc with a collection expression. |
| src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBinaryWriter.cs | Removes unsafe from decimal write paths and replaces 4-int stackalloc with collection expressions. |
| src/libraries/System.Private.CoreLib/src/System/Text/Encoding.Internal.cs | Removes unsafe from a virtual helper and updates a disabled #if false sample to use collection expressions. |
| src/libraries/System.Private.CoreLib/src/System/Text/DecoderNLS.cs | Removes unsafe from leftover-drain helpers and replaces 4-byte combined-buffer stackallocs with collection expressions. |
| src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/Helpers/AhoCorasick.cs | Removes unsafe from a helper and replaces a 2-char destination stackalloc with a collection expression. |
| src/libraries/System.Private.CoreLib/src/System/SearchValues/SearchValues.cs | Replaces a 4-char stackalloc scratch buffer with a collection expression. |
| src/libraries/System.Private.CoreLib/src/System/Resources/ResourceReader.cs | Removes unsafe from _LoadObjectV1 and replaces a 4-int stackalloc with a collection expression. |
| src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyName.cs | Removes unsafe from EscapeStringToBuilder and replaces a 4-byte scratch stackalloc with a collection expression. |
| src/libraries/System.Private.CoreLib/src/System/IO/UnmanagedMemoryAccessor.cs | Replaces a 4-int stackalloc scratch buffer with a collection expression. |
| src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.cs | Removes unsafe from AddTitlecaseLetter and replaces a few 2-char scratch stackallocs with collection expressions. |
| src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/Compiler/ILGen.cs | Removes unsafe from EmitDecimal and replaces a 4-int stackalloc with a collection expression. |
| src/libraries/System.IO.Pipelines/src/System/IO/Pipelines/PipeReaderStream.cs | Removes unsafe from ReadByte and replaces a 1-byte stackalloc with [0]. |
| src/libraries/System.IO.Compression/src/System/IO/Compression/Zstandard/ZstandardStream.Decompress.cs | Removes unsafe from ReadByte and replaces a 1-byte stackalloc with [0]. |
| src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.Tag.cs | Replaces 4-int stackalloc scratch buffers with collection expressions. |
| src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.cs | Removes unsafe from Id-related members / ctor and replaces tiny stackalloc spans with collection expressions. |
| src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLDecimal.cs | Removes unsafe from SqlDecimal(decimal) and replaces a 4-int stackalloc with a collection expression. |
| src/libraries/Common/src/System/Number.Formatting.Common.cs | Replaces a 4-int stackalloc scratch buffer with a collection expression. |
| src/libraries/Common/src/Interop/Windows/BCrypt/Interop.BCryptEncryptDecrypt.RSA.cs | Replaces a 1-byte stackalloc scratch span with a collection expression. |
|
Tagging subscribers to this area: @dotnet/area-meta |
|
Out of my own curiosity, with |
It's actually an improvement according to diffs:
The downside is one instruction (in all these cases) to zero a couple of bytes on stack. But the main motivation was to remove unsafe |
|
PTAL @MihaZupan @tannergooding removes 26 unsafe contexts. Not more than 4 elements to keep it readable. Long terms we need either an opposite of SkipLocalsInit, or Buffer.Allocate (safe variant) API. Or inline arrays, but they need some polishment to work nicely (e.g. |
Replace very small stackallocs with collection literals (since stackallocs require unsafe context).