From 1c950e5c6f85422283bb23bb4bad07ae6c3d2fe1 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 2 Mar 2020 13:59:20 +0000 Subject: Simplify the try intrinsic by using a callback in the catch block --- src/libstd/panicking.rs | 65 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 13 deletions(-) (limited to 'src/libstd') 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` because the other end of this call does not depend @@ -246,6 +241,7 @@ pub unsafe fn r#try R>(f: F) -> Result> union Data { f: ManuallyDrop, r: ManuallyDrop, + p: ManuallyDrop>, } // We do some sketchy operations with ownership here for the sake of @@ -275,27 +271,57 @@ pub unsafe fn r#try R>(f: F) -> Result> // method of calling a catch panic whilst juggling ownership. let mut data = Data { f: ManuallyDrop::new(f) }; - let mut payload: MaybeUninit = 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::, data_ptr, payload_ptr) == 0 { + return if do_try(do_call::, data_ptr, do_catch::) == 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 = 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 { + unsafe fn cleanup(payload: *mut u8) -> Box { let obj = Box::from_raw(__rust_panic_cleanup(payload)); update_panic_count(-1); obj } + #[inline] fn do_call R, R>(data: *mut u8) { unsafe { let data = data as *mut Data; @@ -304,6 +330,19 @@ pub unsafe fn r#try R>(f: F) -> Result> 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 R, R>(data: *mut u8, payload: *mut u8) { + unsafe { + let data = data as *mut Data; + let data = &mut (*data); + let obj = cleanup(payload); + data.p = ManuallyDrop::new(obj); + } + } } /// Determines whether the current thread is unwinding because of panic. -- cgit 1.4.1-3-g733a5