about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorAmanieu d'Antras <amanieu@gmail.com>2020-03-02 13:59:20 +0000
committerAmanieu d'Antras <amanieu@gmail.com>2020-03-05 17:36:50 +0000
commit1c950e5c6f85422283bb23bb4bad07ae6c3d2fe1 (patch)
tree01318bda757bf28d59cdd218b456b99736c613a8 /src/libstd
parent5953c100d1e9eea5ca70f185e905ea0773a34eb5 (diff)
downloadrust-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.rs65
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.