-
Notifications
You must be signed in to change notification settings - Fork 13.7k
Refactor vtable encoding and optimize it for the case of multiple marker traits #113856
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
Conversation
I always forget what the `bool` means :/
Reasoning: if the stack is empty, the loop will be infinite, so the assumption is that the stack can't be non empty. Unwrap makes the assumption more clear (and removes an indentation level)
Less explicit loops -- easier to read.
1. Hide the option as an iterator, so it's nicer to work with 2. Replace a loop with `find`
r? @oli-obk (rustbot has picked a reviewer for you, use r? to override) |
That was a pleasure to review. I had several comments, and subsequent commits resolved them, so now I got nothing. @bors r+ rollup=never (theoretical perf impact and changing vtable layout could be desirable to get bisected in the future) |
☀️ Test successful - checks-actions |
Finished benchmarking commit (399b068): comparison URL. Overall result: ❌✅ regressions and improvements - no action needed@rustbot label: -perf-regression Instruction countThis is a highly reliable metric that was used to determine the overall result at the top of this comment.
Max RSS (memory usage)ResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
CyclesResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
Binary sizeResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
Bootstrap: 648.763s -> 650.713s (0.30%) |
Method(<S as T>::method), | ||
TraitVPtr(<S as T>), | ||
TraitVPtr(<S as M2>), |
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.
Why is TraitVPtr needed for M2?
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.
The short answer: it is not needed. The longer answer is that we currently keep the order of all things from the traits, so since M2
comes after T
, it can't be inlined there. I've filled #114942 to track this.
…mpiler-errors When determining if a trait has no entries for the purposes of omitting vptrs from subtrait vtables, consider its transitive supertraits' entries, instead of just its own entries. When determining if a non-first supertrait vptr can be omitted from a subtrait vtable, check if the supertrait or any of its (transitive) supertraits have methods, instead of only checking if the supertrait itself has methods. This fixes the soundness issue where a vptr would be omitted for a supertrait with no methods but that itself had a supertrait with methods, while still optimizing the case where the supertrait is "truly" empty (it has no own vtable entries, and none of its (transitive) supertraits have any own vtable entries). Fixes <#145752> ----- Old description: ~~Treat all non-auto traits as non-empty (possibly having methods) for purposes of determining if we need to emit a vptr for a non-direct supertrait (and for new "sibling" entries after a direct or non-direct supertrait).~~ This fixes (I believe) the soundness issue, ~~but regresses vtable sizes and possibly upcasting perf in some cases when using trait hierarchies with empty non-auto traits (see `tests/ui/traits/vtable/multiple-markers.stderr`) since we use vptrs in some cases where we could re-use the vtable.~~ Fixes <#145752> Re-opens (not anymore) <#114942> Should not affect <#131813> (i.e. the soundness issue is still fixed, ~~though the relevant vtables in the `trait Evil` example will be larger now~~) cc implementation history <#131864> <#113856> ----- ~~It should be possible to check if a trait has any methods from itself *or* supertraits (instead of just from itself), but to fix the immediate soundness issue, just assume any non-auto trait could have methods. A more optimistic check can be implemented later (or if someone does it soon it could just supercede this PR 😄).~~ Done in latest push `@rustbot` label A-dyn-trait F-trait_upcasting
…mpiler-errors When determining if a trait has no entries for the purposes of omitting vptrs from subtrait vtables, consider its transitive supertraits' entries, instead of just its own entries. When determining if a non-first supertrait vptr can be omitted from a subtrait vtable, check if the supertrait or any of its (transitive) supertraits have methods, instead of only checking if the supertrait itself has methods. This fixes the soundness issue where a vptr would be omitted for a supertrait with no methods but that itself had a supertrait with methods, while still optimizing the case where the supertrait is "truly" empty (it has no own vtable entries, and none of its (transitive) supertraits have any own vtable entries). Fixes <rust-lang/rust#145752> ----- Old description: ~~Treat all non-auto traits as non-empty (possibly having methods) for purposes of determining if we need to emit a vptr for a non-direct supertrait (and for new "sibling" entries after a direct or non-direct supertrait).~~ This fixes (I believe) the soundness issue, ~~but regresses vtable sizes and possibly upcasting perf in some cases when using trait hierarchies with empty non-auto traits (see `tests/ui/traits/vtable/multiple-markers.stderr`) since we use vptrs in some cases where we could re-use the vtable.~~ Fixes <rust-lang/rust#145752> Re-opens (not anymore) <rust-lang/rust#114942> Should not affect <rust-lang/rust#131813> (i.e. the soundness issue is still fixed, ~~though the relevant vtables in the `trait Evil` example will be larger now~~) cc implementation history <rust-lang/rust#131864> <rust-lang/rust#113856> ----- ~~It should be possible to check if a trait has any methods from itself *or* supertraits (instead of just from itself), but to fix the immediate soundness issue, just assume any non-auto trait could have methods. A more optimistic check can be implemented later (or if someone does it soon it could just supercede this PR 😄).~~ Done in latest push `@rustbot` label A-dyn-trait F-trait_upcasting
…mpiler-errors When determining if a trait has no entries for the purposes of omitting vptrs from subtrait vtables, consider its transitive supertraits' entries, instead of just its own entries. When determining if a non-first supertrait vptr can be omitted from a subtrait vtable, check if the supertrait or any of its (transitive) supertraits have methods, instead of only checking if the supertrait itself has methods. This fixes the soundness issue where a vptr would be omitted for a supertrait with no methods but that itself had a supertrait with methods, while still optimizing the case where the supertrait is "truly" empty (it has no own vtable entries, and none of its (transitive) supertraits have any own vtable entries). Fixes <rust-lang/rust#145752> ----- Old description: ~~Treat all non-auto traits as non-empty (possibly having methods) for purposes of determining if we need to emit a vptr for a non-direct supertrait (and for new "sibling" entries after a direct or non-direct supertrait).~~ This fixes (I believe) the soundness issue, ~~but regresses vtable sizes and possibly upcasting perf in some cases when using trait hierarchies with empty non-auto traits (see `tests/ui/traits/vtable/multiple-markers.stderr`) since we use vptrs in some cases where we could re-use the vtable.~~ Fixes <rust-lang/rust#145752> Re-opens (not anymore) <rust-lang/rust#114942> Should not affect <rust-lang/rust#131813> (i.e. the soundness issue is still fixed, ~~though the relevant vtables in the `trait Evil` example will be larger now~~) cc implementation history <rust-lang/rust#131864> <rust-lang/rust#113856> ----- ~~It should be possible to check if a trait has any methods from itself *or* supertraits (instead of just from itself), but to fix the immediate soundness issue, just assume any non-auto trait could have methods. A more optimistic check can be implemented later (or if someone does it soon it could just supercede this PR 😄).~~ Done in latest push `@rustbot` label A-dyn-trait F-trait_upcasting
…mpiler-errors When determining if a trait has no entries for the purposes of omitting vptrs from subtrait vtables, consider its transitive supertraits' entries, instead of just its own entries. When determining if a non-first supertrait vptr can be omitted from a subtrait vtable, check if the supertrait or any of its (transitive) supertraits have methods, instead of only checking if the supertrait itself has methods. This fixes the soundness issue where a vptr would be omitted for a supertrait with no methods but that itself had a supertrait with methods, while still optimizing the case where the supertrait is "truly" empty (it has no own vtable entries, and none of its (transitive) supertraits have any own vtable entries). Fixes <rust-lang/rust#145752> ----- Old description: ~~Treat all non-auto traits as non-empty (possibly having methods) for purposes of determining if we need to emit a vptr for a non-direct supertrait (and for new "sibling" entries after a direct or non-direct supertrait).~~ This fixes (I believe) the soundness issue, ~~but regresses vtable sizes and possibly upcasting perf in some cases when using trait hierarchies with empty non-auto traits (see `tests/ui/traits/vtable/multiple-markers.stderr`) since we use vptrs in some cases where we could re-use the vtable.~~ Fixes <rust-lang/rust#145752> Re-opens (not anymore) <rust-lang/rust#114942> Should not affect <rust-lang/rust#131813> (i.e. the soundness issue is still fixed, ~~though the relevant vtables in the `trait Evil` example will be larger now~~) cc implementation history <rust-lang/rust#131864> <rust-lang/rust#113856> ----- ~~It should be possible to check if a trait has any methods from itself *or* supertraits (instead of just from itself), but to fix the immediate soundness issue, just assume any non-auto trait could have methods. A more optimistic check can be implemented later (or if someone does it soon it could just supercede this PR 😄).~~ Done in latest push `@rustbot` label A-dyn-trait F-trait_upcasting
This PR does two things
prepare_vtable_segments
(this was motivated by the other change,prepare_vtable_segments
was quite hard to understand and while trying to edit it I've refactored it)loop
s labeledbreak
s/continue
s whenever there is a simpler solution?
Fixes #113840
cc @crlf0710
Review wise it's probably best to review each commit individually, as then it's more clear why the refactoring is correct.
I can split the last two commits (which change behavior) into a separate PR if it makes reviewing easier