diff options
| author | Amanieu d'Antras <amanieu@gmail.com> | 2020-03-02 13:59:20 +0000 |
|---|---|---|
| committer | Amanieu d'Antras <amanieu@gmail.com> | 2020-03-05 17:36:50 +0000 |
| commit | 1c950e5c6f85422283bb23bb4bad07ae6c3d2fe1 (patch) | |
| tree | 01318bda757bf28d59cdd218b456b99736c613a8 /src/libstd | |
| parent | 5953c100d1e9eea5ca70f185e905ea0773a34eb5 (diff) | |
| download | rust-1c950e5c6f85422283bb23bb4bad07ae6c3d2fe1.tar.gz rust-1c950e5c6f85422283bb23bb4bad07ae6c3d2fe1.zip | |
Simplify the try intrinsic by using a callback in the catch block
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/panicking.rs | 65 |
1 files changed, 52 insertions, 13 deletions
diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 38cb4418dd0..0be71b52d9e 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -12,7 +12,7 @@ use core::panic::{BoxMeUp, Location, PanicInfo}; use crate::any::Any; use crate::fmt; use crate::intrinsics; -use crate::mem::{self, ManuallyDrop, MaybeUninit}; +use crate::mem::{self, ManuallyDrop}; use crate::process; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sys::stdio::panic_output; @@ -28,9 +28,6 @@ use crate::io::set_panic; #[cfg(test)] use realstd::io::set_panic; -// Include the definition of UnwindPayload from libpanic_unwind. -include!("../libpanic_unwind/payload.rs"); - // Binary interface to the panic runtime that the standard library depends on. // // The standard library is tagged with `#![needs_panic_runtime]` (introduced in @@ -43,9 +40,7 @@ include!("../libpanic_unwind/payload.rs"); // hook up these functions, but it is not this day! #[allow(improper_ctypes)] extern "C" { - /// The payload ptr here is actually the same as the payload ptr for the try - /// intrinsic (i.e., is really `*mut [u64; 2]` or `*mut *mut u8`). - fn __rust_panic_cleanup(payload: TryPayload) -> *mut (dyn Any + Send + 'static); + fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static); /// `payload` is actually a `*mut &mut dyn BoxMeUp` but that would cause FFI warnings. /// It cannot be `Box<dyn BoxMeUp>` because the other end of this call does not depend @@ -246,6 +241,7 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> union Data<F, R> { f: ManuallyDrop<F>, r: ManuallyDrop<R>, + p: ManuallyDrop<Box<dyn Any + Send>>, } // We do some sketchy operations with ownership here for the sake of @@ -275,27 +271,57 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> // method of calling a catch panic whilst juggling ownership. let mut data = Data { f: ManuallyDrop::new(f) }; - let mut payload: MaybeUninit<TryPayload> = MaybeUninit::uninit(); - let data_ptr = &mut data as *mut _ as *mut u8; - let payload_ptr = payload.as_mut_ptr() as *mut _; - return if intrinsics::r#try(do_call::<F, R>, data_ptr, payload_ptr) == 0 { + return if do_try(do_call::<F, R>, data_ptr, do_catch::<F, R>) == 0 { Ok(ManuallyDrop::into_inner(data.r)) } else { - Err(cleanup(payload.assume_init())) + Err(ManuallyDrop::into_inner(data.p)) }; + // Compatibility wrapper around the try intrinsic for bootstrap + #[inline] + unsafe fn do_try(try_fn: fn(*mut u8), data: *mut u8, catch_fn: fn(*mut u8, *mut u8)) -> i32 { + #[cfg(not(bootstrap))] + { + intrinsics::r#try(try_fn, data, catch_fn) + } + #[cfg(bootstrap)] + { + use crate::mem::MaybeUninit; + #[cfg(target_env = "msvc")] + type TryPayload = [u64; 2]; + #[cfg(not(target_env = "msvc"))] + type TryPayload = *mut u8; + + let mut payload: MaybeUninit<TryPayload> = MaybeUninit::uninit(); + let payload_ptr = payload.as_mut_ptr() as *mut u8; + let r = intrinsics::r#try(try_fn, data, payload_ptr); + if r != 0 { + #[cfg(target_env = "msvc")] + { + catch_fn(data, payload_ptr) + } + #[cfg(not(target_env = "msvc"))] + { + catch_fn(data, payload.assume_init()) + } + } + r + } + } + // We consider unwinding to be rare, so mark this function as cold. However, // do not mark it no-inline -- that decision is best to leave to the // optimizer (in most cases this function is not inlined even as a normal, // non-cold function, though, as of the writing of this comment). #[cold] - unsafe fn cleanup(payload: TryPayload) -> Box<dyn Any + Send + 'static> { + unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send + 'static> { let obj = Box::from_raw(__rust_panic_cleanup(payload)); update_panic_count(-1); obj } + #[inline] fn do_call<F: FnOnce() -> R, R>(data: *mut u8) { unsafe { let data = data as *mut Data<F, R>; @@ -304,6 +330,19 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> data.r = ManuallyDrop::new(f()); } } + + // We *do* want this part of the catch to be inlined: this allows the + // compiler to properly track accesses to the Data union and optimize it + // away most of the time. + #[inline] + fn do_catch<F: FnOnce() -> R, R>(data: *mut u8, payload: *mut u8) { + unsafe { + let data = data as *mut Data<F, R>; + let data = &mut (*data); + let obj = cleanup(payload); + data.p = ManuallyDrop::new(obj); + } + } } /// Determines whether the current thread is unwinding because of panic. |
