-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replace confusing new T[] { ... }
optimization with collection expressions
#93125
Conversation
…essions We rely heavily on the compiler rewriting: ```C# ReadOnlySpan<T> span = new T[] { /* const data */ }; ``` into variants that don't actually allocate and instead blit the data into the assembly data section and create a span that points directly to that data. But the syntax is very confusing and looks like it allocates on every use. Now that we have collection expressions and they handle the same optimizations (and more), we can avoid the confusion and simplify the code by switching to use them. This does so for all the uses I could find with some greping around.
Tagging subscribers to this area: @dotnet/area-meta Issue DetailsWe rely heavily on the compiler rewriting: ReadOnlySpan<T> span = new T[] { /* const data */ }; into variants that don't actually allocate and instead blit the data into the assembly data section and create a span that points directly to that data. But the syntax is very confusing and looks like it allocates on every use. Now that we have collection expressions and they handle the same optimizations (and more), we can avoid the confusion and simplify the code by switching to use them. This does so for all the uses I could find with some greping around.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!
src/libraries/Common/src/System/Security/Cryptography/Asn1/OaepParamsAsn.xml.cs
Show resolved
Hide resolved
src/libraries/Common/src/System/Security/Cryptography/Asn1/OaepParamsAsn.xml.cs
Show resolved
Hide resolved
Woohoo. Did you use the analyzer/fixer here? Or do this manually? |
Manual (regex). The analyzer doesn't flag these, or at least it doesn't in the version I'm using (Version 17.9.0 Preview 1.0 [34203.221.main]), e.g. for: internal class Program
{
private static void Main()
{
ReadOnlySpan<int> span = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Console.WriteLine(span[0]);
}
} no suggestion or fix is offered. |
|
||
private static ReadOnlySpan<byte> EightZeros => new byte[8]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that this one was actually allocating on each call :(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that necessarily bad? Often we avoid caching memory that would never leave Gen0 (I don't know this code OC)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that necessarily bad? Often we avoid caching memory that would never leave Gen0 (I don't know this code OC)
If this had instead been:
private static ReadOnlySpan<byte> EightZeros => new byte[8] { 0, 0, 0, 0, 0, 0, 0, 0 };
there wouldn't have been any allocation, not even on first use: it would have simply been eight zero'd bytes in the assembly data, and the span would have pointed directly to that memory.
SharpLab
And, yes, a property that looks like it should be non-allocating but that allocates on every access is bad :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, wow, TIL.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should just fix that in Roslyn. I don't see a good reason for these two to exhibit such a codegen difference. (Though moving forward we'll use that syntax much less and so hopefully won't trip over it again.)
cc: @jcouv
I'll add support for that case. |
We rely heavily on the compiler rewriting:
into variants that don't actually allocate and instead blit the data into the assembly data section and create a span that points directly to that data. But the syntax is very confusing and looks like it allocates on every use.
Now that we have collection expressions and they handle the same optimizations (and more), we can avoid the confusion and simplify the code by switching to use them. This does so for all the uses I could find with some greping around.