-
-
Notifications
You must be signed in to change notification settings - Fork 525
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
perf(allocator): remove overflow checks from String::from_strs_array_in
#9650
perf(allocator): remove overflow checks from String::from_strs_array_in
#9650
Conversation
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. This stack of pull requests is managed by Graphite. Learn more about stacking. |
CodSpeed Performance ReportMerging #9650 will not alter performanceComparing Summary
|
1868d1a
to
94d3284
Compare
It looks like we don't even need to add any checks? |
Merge activity
|
…_in` (#9650) Optimize `String::from_strs_array_in` to remove overflow checks in common cases. `&str` has a maximum length of `isize::MAX`, so in many cases, if we communicate this constraint to the compiler, it can remove the overflow checks, as it can see that overflowing `usize` is impossible. I was unsure if max length of `&str` was guaranteed, but wiser minds confirm it is: https://users.rust-lang.org/t/does-str-reliably-have-length-isize-max/126777
94d3284
to
89b6e4c
Compare
Yes I think we still do. We have to deal correctly with any possible input to the function. Without overflow checks, this example would cause incorrect let s1 = "$_";
let s2 = get_long_string();
let s3 = get_long_string();
assert_eq!(s1.len(), 2);
assert_eq!(s2.len(), isize::MAX as usize);
assert_eq!(s3.len(), isize::MAX as usize);
// This does not panic in release mode without `checked_add`
let total_len = [s1, s2, s3].iter().fold(0usize, |total_len, s| total_len + s.len());
// Oh no!
assert_eq!(total_len, 0); But... at least this change means that in our actual use cases, the compiler has enough information to prove that the checks aren't needed, and to remove them. So we get complete safety no matter what the input is, but we don't have to pay for it - as long as only 1 of the input strings is dynamic, and the rest are static (so compiler knows their length). |
Yes, I agree!
The example case seems like it would not happen, as https://users.rust-lang.org/t/does-str-reliably-have-length-isize-max/126777/2 explained, the maximum allocatable allocation object cannot exceed |
Yes, it's true that attempting to allocate more than But the potential problem here is before we allocate the If we calculate So, if But we are assuming that we have allocated enough memory for all the strings, and we get the pointer to the In safe code, Rust will prevent you from doing this - it checks these things and panics if you try to do anything illegal, and it's extremely good at covering every conceivable edge case. But in "unsafe land", we we have told Rust "don't check anything, we already checked". So the responsibility for covering every possible case is on us. I'm not sure if this makes any more sense? |
Thank you for explaining this again, that makes sense, I misunderstood that the allocated object can't be more than one https://doc.rust-lang.org/std/ptr/index.html#allocated-object |
Optimize
String::from_strs_array_in
to remove overflow checks in common cases.&str
has a maximum length ofisize::MAX
, so in many cases, if we communicate this constraint to the compiler, it can remove the overflow checks, as it can see that overflowingusize
is impossible.I was unsure if max length of
&str
was guaranteed, but wiser minds confirm it is: https://users.rust-lang.org/t/does-str-reliably-have-length-isize-max/126777