Optimize catch_unwind to match C++ try/catch#67502
Conversation
|
r? @shepmaster (rust_highfive has picked a reviewer for you, use r? to override) |
|
I suspect that the best reviewer here is r? @alexcrichton. I am not sure whether we want to accept this. I created this patch while trying to investigate #64224; it is a slight simplification of the generated assembly, but not really anything too major (as might be expected). |
This comment has been minimized.
This comment has been minimized.
afcbceb to
5de0856
Compare
7da6a5a to
8ff0922
Compare
This comment has been minimized.
This comment has been minimized.
8bb8bfe to
ba58f64
Compare
This comment has been minimized.
This comment has been minimized.
|
I believe the test failure here is because we treat I'm not actually sure if there's much use to That would mean that the test in question would also be deleted; we do not expect that a crate with |
|
@bors try for easier testing |
|
⌛ Trying commit ba58f6421d4c5598f16479b0b2e5a1357917bac0 with merge d19982ed64d76225c52b773a53d593e6e96282e8... |
|
☀️ Try build successful - checks-azure |
|
Should be good to merge at this point. I moved some unrelated commits fixing some memory leaks to a separate PR (#67711). |
alexcrichton
left a comment
There was a problem hiding this comment.
One thing I'm worried about here is that this PR changes the standard library to unconditionally use the try intrinsic no matter what panic mode is selected. Previously the try intrinsic was only codegen'd into the panic_unwind crate, but now it'll also be codegen'd when using panic=abort.
I don't think that this is a huge huge problem but I do think that we very much want to avoid any invoke instructions at all in panic=abort mode. Some targets in LLVM die really quickly on the invoke instruction I think. Could you double check the raw IR output in debug mode in panic=abort mode to make sure no invoke instruction exists?
This may require updating the codegen of the try intrinsic to just be call in panic=abort mode which I suspect would be a relatively simple change. It may also already be done, I'm not sure!
src/libstd/panicking.rs
Outdated
|
|
||
| // This must be kept in sync with the implementations in libpanic_unwind. | ||
| // | ||
| // This is *not* checked in anyway; the compiler does not allow us to use a |
src/libstd/panicking.rs
Outdated
| // type/macro/anything from panic_unwind, since we're then linking in the | ||
| // panic_unwind runtime even during -Cpanic=abort. | ||
| // | ||
| // Essentially this must be the type of `imp::Payload` in libpanic_unwind. |
There was a problem hiding this comment.
Would it be possible to extract the definition of Payload to a foo.rs file which we could include with #[path] here?
This is already the case: |
|
Great! That's perfect |
|
The job Click to expand the log.I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact |
src/libpanic_unwind/seh.rs
Outdated
| if (*e)[0] != 0 { | ||
| cleanup(*e); | ||
| unsafe extern $abi fn exception_cleanup(e: *mut Exception) { | ||
| if let Some(b) = e.read().data { |
There was a problem hiding this comment.
Nit: this is prone to diverging if anybody adds fields to Exception. Consider pattern matching the field out instead.
| // | ||
| // bx: | ||
| // invoke %func(%args...) normal %normal unwind %catch | ||
| // invoke %func(%data) normal %normal unwind %catch |
|
Beta has been branched, so... @bors r=Mark-Simulacrum |
|
📌 Commit 9f3679f has been approved by |
|
@bors rollup=never |
|
⌛ Testing commit 9f3679f with merge 40f1118e156cefac66e96f41ac5be86adfb183ff... |
|
💥 Test timed out |
|
@bors retry |
|
@bors p=1 |
|
☀️ Test successful - checks-azure |
| @@ -274,27 +269,59 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> | |||
| // | |||
There was a problem hiding this comment.
Looks like the "2." comment above is no longer accurate? The code now does ManuallyDrop::into_inner(data.p) in the "panicked" case, which looks very symmetric to the "didn't panic case": in both cases we move "it out of data and return it", it's just a different thing we move out.
Now Mark is both author and reviewer of this PR. ;) EDIT: Ah, most commits are authored by @Amanieu, looks like Mark just submitted it. I see. |
| #[rustc_std_internal_symbol] | ||
| #[cfg(all(bootstrap, target_os = "windows", target_env = "gnu"))] | ||
| pub extern "C" fn rust_eh_unwind_resume() {} | ||
|
|
There was a problem hiding this comment.
This additional requirement on #cfg(bootstrap)] looks as though it may be responsible for #79609 ... not sure I understand why it was required, however ?
There was a problem hiding this comment.
The compiler used to emit references to rust_eh_unwind_resume from codegen. But it doesn't do that any more and rust_eh_unwind_resume doesn't exist any more.
This refactors the implementation of catching unwinds to allow LLVM to inline the "try" closure directly into the happy path, avoiding indirection. This means that the catch_unwind implementation is (after this PR) zero-cost unless a panic is thrown.
https://rust.godbolt.org/z/cZcUSB is an example of the current codegen in a simple case. Notably, the codegen is exactly the same if
-Cpanic=abortis passed, which is clearly not great.This PR, on the other hand, generates the following assembly:
Fixes #64224, and resolves #64222.