-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Partial future-proofing for Box<T, A> #50097
Conversation
Currently, MIR just passes the raw Box to box_free(), which happens to work because practically, it's the same thing. But that might not be true in the future, with Box<T, A: Alloc>. The MIR inline pass actually fixes up the argument while inlining box_free, but this is not enabled by default and doesn't necessarily happen (the inline threshold needs to be passed). This change effectively moves what the MIR inline pass does to the elaborate_drops pass, so that box_free() is passed the raw pointer instead of the Box.
Because box_free is now passed a pointer instead of a Box, we can stop relying on TypeChecked::check_box_free_inputs, because TypeChecker::check_call_inputs should be enough, like for all other function calls. It seems it was not actually reached anyways in cases where it would have made a difference. (issue rust-lang#50071)
box_free currently takes a pointer. With the prospect of the Box type definition changing in the future to include an allocator, box_free will also need to be aware of this. In order to prepare for that future, we allow box_free to take a form where its argument are the fields of the Box. e.g. if Box is defined as `Box(A, B, C)`, then box_free signature becomes `box_free(a: A, b: B, c: C)`. We however still allow the current form (taking a pointer), so that the same compiler can handle both forms, which helps with bootstrap.
…meters A Box type with associated allocator would, on its own, be a backwards incompatible change, because of the additional parameter, but if that additional parameter has a default, then backwards compatibility with the current definition of the type is preserved. But the owned_box lang item currently doesn't allow such extra parameters, so add support for this.
@bors try |
@glandium: 🔑 Insufficient privileges: not in try users |
@bors try |
⌛ Trying commit 64f5233 with merge 349c1c0fa7d4522250306a50b4828a911650a414... |
☀️ Test successful - status-travis |
Thanks for the PR! Highfive is currently not working, so I'm assigning a reviewer from the compiler team randomly. |
FWIW, with these patches, it's also possible to use |
Ping from triage @eddyb ! This PR needs your review. |
let free_inputs = free_sig.inputs(); | ||
// If the box_free function takes a *mut T, transform the Box into | ||
// such a pointer before calling box_free. Otherwise, pass it all | ||
// the fields in the Box as individual arguments. |
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.
I think supporting the *mut T
form adds unnecessary clutter to the compiler.
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.
This is only temporary clutter, and really makes the transition easier. For example, this could land now in 1.27, and the liballoc changes could be done in 1.28 without having a cfg(stage0)-specific Box implementation. /That/ would be clutter.
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.
#[cfg(stage0)]
box_free
is tiny compared to this, since all it needs to do is call the real implementation, which it can do in much less code. (See my patch for more details)
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 other problem is that a #[cfg(stage0)]
box_free with the old signature can't be compiled by the new code, which means if, say, version 1.27 has the new code, you can't bootstrap 1.27.1 (if there ends up being one) with 1.27, which, typically, linux distros would be doing.
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.
Ehm, we don't support that - or rather, you set a flag in config.toml that turns off stage0. cc @alexcrichton
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 pretty much always use #[cfg(stage0)]
like this)
As of now, Box only contains a Unique pointer, so this is the sole argument to box_free. Consequently, we remove the code supporting the previous box_free signature. We however keep the old definition for bootstrapping purpose.
@glandium Please update the PR description as well. |
@glandium Are we supposed to crater this? |
@kennytm there is no change of exposed APIs backwards compatible or otherwise, so I don't think this needs one. |
@bors r+ |
📌 Commit bd8c177 has been approved by |
Partial future-proofing for Box<T, A> In some ways, this is similar to @eddyb's PR #47043 that went stale, but doesn't cover everything. Notably, this still leaves Box internalized as a pointer in places, so practically speaking, only ZSTs can be practically added to the Box type with the changes here (the compiler ICEs otherwise). The Box type is not changed here, that's left for the future because I want to test that further first, but this puts things in place in a way that hopefully will make things easier.
☀️ Test successful - status-appveyor, status-travis |
This pr had an up to 10% negative effect on wall time of some benchmarks, has that been looked into or is it known what's going on there? |
Looking at the worst offender, issue-46449, a profile shows that the time spent in llvm is larger (which makes sense considering how essentially only --release builds have been affected). I isolated the regression to the very last commit in the series, and here's the catch: the MIR is strictly identical between with and without that commit. So, somehow, changing the argument to before:
after:
and in callers, before:
after:
(that's from the output of --emit llvm-ir, which is not what rustc generates for llvm, that's after at least some llvm passes) @eddyb what do you think? do you need more information? |
@glandium What happens if this use of rust/src/librustc/ty/layout.rs Line 1590 in 41707d8
|
@eddyb the ir changed, but perf didn't, it's still slower to compile. |
@glandium Wait, what's the difference on the IR then? It should be almost identical. |
|
@glandium No, I mean, the differences you listed in #50097 (comment). |
@eddyp unfortunately, they're not. |
@eddyb (per irc request) https://gist.github.com/glandium/9baea047c63642fe8649d4d7ab690d13 |
In some ways, this is similar to @eddyb's PR #47043 that went stale, but doesn't cover everything. Notably, this still leaves Box internalized as a pointer in places, so practically speaking, only ZSTs can be practically added to the Box type with the changes here (the compiler ICEs otherwise).
The Box type is not changed here, that's left for the future because I want to test that further first, but this puts things in place in a way that hopefully will make things easier.