-
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
Add Array.GetMaxLength<T> #43301
Add Array.GetMaxLength<T> #43301
Conversation
Note regarding the This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, to please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change. |
Is |
f237f50
to
b6e9d48
Compare
@stephentoub or @jkotas -- It's unclear to me what the next steps for this PR should be; can you help? |
I think we should:
|
At that point, it also needn't be a method, so presumably just: public static int MaxLength => 0x7FFFFFC7; |
Is the max limit going to be potentially confusing for types where it is larger than the actual max limit? For example, on a 32-bit computer the max limit for Likewise, will a constant and non-generic T be sufficient for other runtimes, such as say |
The practical limit on 32-bit is always a lot smaller due to address space fragmentation. |
1d18fa7
to
15e02a1
Compare
@jkotas, I pushed an update. Can you confirm this is what you had in mind? |
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.
Yes, this looks good. Thanks!
...System.Private.DataContractSerialization/src/System/Runtime/Serialization/ObjectToIdCache.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Collections/tests/Generic/Stack/Stack.Generic.Tests.cs
Outdated
Show resolved
Hide resolved
Co-authored-by: Jan Kotas <[email protected]>
210c785
to
dddee8f
Compare
src/libraries/System.Private.CoreLib/src/System/Collections/HashHelpers.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Collections/tests/Generic/List/List.Generic.Tests.EnsureCapacity.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Collections/tests/Generic/Queue/Queue.Generic.Tests.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Collections/tests/Generic/Stack/Stack.Generic.Tests.cs
Outdated
Show resolved
Hide resolved
Co-authored-by: Jan Kotas <[email protected]>
…eric.Tests.cs Co-authored-by: Jan Kotas <[email protected]>
Could we apply this same maximum length limit (0X7FFFFFC7) to Span/ReadOnlySpan as well as arrays? This might allow the JIT to remove bounds checks in cases where currently we need to assume an iteration variable might overflow, e.g.,
But if we know that a.Length can't exceed 0X7FFFFFC7 then |
It would require a breaking change. We would need to start validating the length and throwing an exception in Span constructors that take unmanaged pointers. Also, the affected Span constructors would become slower because of that. Do you have any data on how often this optimization can kick in if we were to limit the max span length? My gut feeling is that this is not worth. The extra instructions to check the Span length in constructors would cost more what we would save in these loops in typical programs. In addition to that, there is the cost of the breaking change. |
For 64-bit wouldn't it be better to just retype the loop to be over |
Simple retying would change behavior. As written, the loop will crash for We would need to clone the loop and use the retyped clone only when we can check using precondition that the loop does not hit the boundary conditions. |
The only break (I believe) would be in the Span constructor taking a native pointer, which would fail if given a size >= 0X7FFFFFC7. (It's always been limited to be <= 0x7FFFFFFF.) So it's only a very small set of values that would be breaking. Yes, these constructors would need a check and an (uncommon) throw so might impact inlining.
I have a prototype implementation that shows somewhat minimal diffs, across all our SuperPMI collections, but the problem with the implementation, and one of my main motivations for asking the question, is that the JIT likes to treat Span and array bounds checks the same, so I'm worried there are places where we're not optimizing arrays as well as we could because we need to "pessimize" our assumptions to consider that Span has a different maximum length. Possibly the JIT could do a better job distinguishing Span and array bounds checks and that problem would go away, but since Span is so much like an array it would be nice to treat them equivalently here, also. [Edit] I found an implementation in the JIT that I think isolates just the missing optimizations from the Span max length being INT_MAX instead of the same as array, and it's pretty small. Here are the diffs. Asm Diffslibraries.crossgen2.windows.x64.checked.mch:
Detail diffs
libraries.pmi.windows.x64.checked.mch:
Detail diffs
|
|
On 32-bit yes. On 64-bit, since the actual indexing done behind the scenes needs to be Likewise since we know that |
I think we have a few options given that we know valid indices must be positive and the length can never be greater than |
Closes #31366
Not encountering the complexity of dividing with object size under 32bit, because that limit shouldn't be meaningful in real world.
Replaces usages of the magic constant with the new api.