-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Removed unsafe indexing from StrongReferenceMessenger #3513
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
Removed unsafe indexing from StrongReferenceMessenger #3513
Conversation
Thanks Sergio0694 for opening a Pull Request! The reviewers will test the PR and highlight if there is any conflict or changes required. If the PR is approved we will proceed to merge the pull request 🙌 |
I meant something like this:
...
...
...
|
Oh I see now, thanks! I had read your previous comment backwards, now it makes perfect sense 😄 I've re-run the benchmarks and despite the additional bounds checks the performance seems to go from 5-6% faster to 4-5% slower than the original implementation, so on average I'd say we should basically be very close to that, which is perfectly fine! |
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.
LGTM!
Awesome! Thank you for your help Jan, really appreciate it! 😄 |
Hello @michael-hawker! Because this pull request has the p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (
|
Follow up to #3424
PR Type
What kind of change does this PR introduce?
What is the current behavior?
There were a couple of
Unsafe.Add
usages in theStrongReferenceClass
, in particular:https://github.com/windows-toolkit/WindowsCommunityToolkit/blob/79127cf6a76ea1b0673c0376e43d41f91b2df509/Microsoft.Toolkit.Mvvm/Messaging/StrongReferenceMessenger.cs#L384-L385
While these two were working just fine, following the conversation here it was suggested by @jkotas to refactor this to avoid those unsafe indexing operations, to ensure an out of bounds write could never be performed even in case a bug popped up in the previous logic, or in case a future refactor/change introduced one. This would've also made the code a bit less error prone in general. He also offered some suggestions and ideas that I started from to do this refactoring, so thanks! 😄
Changes in this PR
Added a new internalObject2
type. This is a value type that stores a pair of handler and recipient for a messageobject
array of twice the size, and interleaving the local handler and recipients at even and off indices.Span<object>
for all the indexing operations to avoid the array covariance checks.Send
methods for both messenger types. Benefits of this change:using a value typeindexing aSpan<object>
.We have bounds checks now, but only 1 and not 2, since each item holds a pair of values.The broadcast part only has a single array to go through now, so we can replace thefor
with unsafe offsetting with just aref foreach
and still get bounds checks being removed, while having code that's easier to read and to verify.Final result
Benchmarks
Here's the cherry on top - removing those
Unsafe.Add
calls while adding this new type and refactoring made it so that instead of that previous ~10% performance hit I saw in my benchmarks, performance now are virtually identical. I run my benchmark a few times and the new version with the changes in this PR ranged from being up to 2% slower, to being 4% faster (!).If we just say that on average the performance is virtually identical, we still have the advantage of safer code now though 🎉
PR Checklist
Please check if your PR fulfills the following requirements:
Pull Request has been submitted to the documentation repository instructions. Link:Sample in sample app has been added / updated (for bug fixes / features)Icon has been created (if new sample) following the Thumbnail Style Guide and templates