about summary refs log tree commit diff
path: root/src/libpanic_unwind
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/libpanic_unwind
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/libpanic_unwind')
-rw-r--r--src/libpanic_unwind/emcc.rs2
-rw-r--r--src/libpanic_unwind/lib.rs8
-rw-r--r--src/libpanic_unwind/payload.rs21
-rw-r--r--src/libpanic_unwind/seh.rs41
4 files changed, 26 insertions, 46 deletions
diff --git a/src/libpanic_unwind/emcc.rs b/src/libpanic_unwind/emcc.rs
index 117246aa6c9..c7144fe16cd 100644
--- a/src/libpanic_unwind/emcc.rs
+++ b/src/libpanic_unwind/emcc.rs
@@ -52,7 +52,7 @@ struct Exception {
     // This needs to be an Option because the object's lifetime follows C++
     // semantics: when catch_unwind moves the Box out of the exception it must
     // still leave the exception object in a valid state because its destructor
-    // is still going to be called by __cxa_end_catch..
+    // is still going to be called by __cxa_end_catch.
     data: Option<Box<dyn Any + Send>>,
 }
 
diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs
index 20331e8808c..d6c33666938 100644
--- a/src/libpanic_unwind/lib.rs
+++ b/src/libpanic_unwind/lib.rs
@@ -35,8 +35,6 @@ use alloc::boxed::Box;
 use core::any::Any;
 use core::panic::BoxMeUp;
 
-// If adding to this list, you should also look at the list of TryPayload types
-// defined in payload.rs and likely add to there as well.
 cfg_if::cfg_if! {
     if #[cfg(target_os = "emscripten")] {
         #[path = "emcc.rs"]
@@ -62,8 +60,6 @@ cfg_if::cfg_if! {
     }
 }
 
-include!("payload.rs");
-
 extern "C" {
     /// Handler in libstd called when a panic object is dropped outside of
     /// `catch_unwind`.
@@ -73,9 +69,7 @@ extern "C" {
 mod dwarf;
 
 #[rustc_std_internal_symbol]
-pub unsafe extern "C" fn __rust_panic_cleanup(
-    payload: TryPayload,
-) -> *mut (dyn Any + Send + 'static) {
+pub unsafe extern "C" fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static) {
     Box::into_raw(imp::cleanup(payload))
 }
 
diff --git a/src/libpanic_unwind/payload.rs b/src/libpanic_unwind/payload.rs
deleted file mode 100644
index 1234db7da0f..00000000000
--- a/src/libpanic_unwind/payload.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-// Type definition for the payload argument of the try intrinsic.
-//
-// This must be kept in sync with the implementations of the try intrinsic.
-//
-// This file is included by both panic runtimes and libstd. It is part of the
-// panic runtime ABI.
-cfg_if::cfg_if! {
-    if #[cfg(target_os = "emscripten")] {
-        type TryPayload = *mut u8;
-    } else if #[cfg(target_arch = "wasm32")] {
-        type TryPayload = *mut u8;
-    } else if #[cfg(target_os = "hermit")] {
-        type TryPayload = *mut u8;
-    } else if #[cfg(all(target_env = "msvc", target_arch = "aarch64"))] {
-        type TryPayload = *mut u8;
-    } else if #[cfg(target_env = "msvc")] {
-        type TryPayload = [u64; 2];
-    } else {
-        type TryPayload = *mut u8;
-    }
-}
diff --git a/src/libpanic_unwind/seh.rs b/src/libpanic_unwind/seh.rs
index f599f9815a6..c1656023b60 100644
--- a/src/libpanic_unwind/seh.rs
+++ b/src/libpanic_unwind/seh.rs
@@ -49,10 +49,17 @@
 
 use alloc::boxed::Box;
 use core::any::Any;
-use core::mem;
-use core::raw;
+use core::mem::{self, ManuallyDrop};
 use libc::{c_int, c_uint, c_void};
 
+struct Exception {
+    // This needs to be an Option because we catch the exception by reference
+    // and its destructor is executed by the C++ runtime. When we take the Box
+    // out of the exception, we need to leave the exception in a valid state
+    // for its destructor to run without double-dropping the Box.
+    data: Option<Box<dyn Any + Send>>,
+}
+
 // First up, a whole bunch of type definitions. There's a few platform-specific
 // oddities here, and a lot that's just blatantly copied from LLVM. The purpose
 // of all this is to implement the `panic` function below through a call to
@@ -186,7 +193,7 @@ static mut CATCHABLE_TYPE: _CatchableType = _CatchableType {
     properties: 0,
     pType: ptr!(0),
     thisDisplacement: _PMD { mdisp: 0, pdisp: -1, vdisp: 0 },
-    sizeOrOffset: mem::size_of::<[u64; 2]>() as c_int,
+    sizeOrOffset: mem::size_of::<Exception>() as c_int,
     copyFunction: ptr!(0),
 };
 
@@ -229,16 +236,16 @@ static mut TYPE_DESCRIPTOR: _TypeDescriptor = _TypeDescriptor {
 // because Box<dyn Any> isn't clonable.
 macro_rules! define_cleanup {
     ($abi:tt) => {
-        unsafe extern $abi fn exception_cleanup(e: *mut [u64; 2]) {
-            if (*e)[0] != 0 {
-                cleanup(*e);
+        unsafe extern $abi fn exception_cleanup(e: *mut Exception) {
+            if let Some(b) = e.read().data {
+                drop(b);
                 super::__rust_drop_panic();
             }
         }
         #[unwind(allowed)]
-        unsafe extern $abi fn exception_copy(_dest: *mut [u64; 2],
-                                             _src: *mut [u64; 2])
-                                             -> *mut [u64; 2] {
+        unsafe extern $abi fn exception_copy(_dest: *mut Exception,
+                                             _src: *mut Exception)
+                                             -> *mut Exception {
             panic!("Rust panics cannot be copied");
         }
     }
@@ -258,12 +265,11 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
     // need to otherwise transfer `data` to the heap. We just pass a stack
     // pointer to this function.
     //
-    // The first argument is the payload being thrown (our two pointers), and
-    // the second argument is the type information object describing the
-    // exception (constructed above).
-    let ptrs = mem::transmute::<_, raw::TraitObject>(data);
-    let mut ptrs = [ptrs.data as u64, ptrs.vtable as u64];
-    let throw_ptr = ptrs.as_mut_ptr() as *mut _;
+    // The ManuallyDrop is needed here since we don't want Exception to be
+    // dropped when unwinding. Instead it will be dropped by exception_cleanup
+    // which is invoked by the C++ runtime.
+    let mut exception = ManuallyDrop::new(Exception { data: Some(data) });
+    let throw_ptr = &mut exception as *mut _ as *mut _;
 
     // This... may seems surprising, and justifiably so. On 32-bit MSVC the
     // pointers between these structure are just that, pointers. On 64-bit MSVC,
@@ -311,8 +317,9 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
     _CxxThrowException(throw_ptr, &mut THROW_INFO as *mut _ as *mut _);
 }
 
-pub unsafe fn cleanup(payload: [u64; 2]) -> Box<dyn Any + Send> {
-    mem::transmute(raw::TraitObject { data: payload[0] as *mut _, vtable: payload[1] as *mut _ })
+pub unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send> {
+    let exception = &mut *(payload as *mut Exception);
+    exception.data.take().unwrap()
 }
 
 // This is required by the compiler to exist (e.g., it's a lang item), but