Skip to content

Commit

Permalink
Simplify the try intrinsic by using a callback in the catch block
Browse files Browse the repository at this point in the history
  • Loading branch information
Amanieu committed Mar 5, 2020
1 parent 5953c10 commit 1c950e5
Show file tree
Hide file tree
Showing 10 changed files with 150 additions and 126 deletions.
14 changes: 8 additions & 6 deletions src/libcore/intrinsics.rs
Expand Up @@ -1390,14 +1390,16 @@ extern "rust-intrinsic" {
/// cast to a `u64`; if `T` has no discriminant, returns 0.
pub fn discriminant_value<T>(v: &T) -> u64;

/// Rust's "try catch" construct which invokes the function pointer `f` with
/// the data pointer `data`.
/// Rust's "try catch" construct which invokes the function pointer `try_fn`
/// with the data pointer `data`.
///
/// The third pointer is a target-specific data pointer which is filled in
/// with the specifics of the exception that occurred. For examples on Unix
/// platforms this is a `*mut *mut T` which is filled in by the compiler and
/// on MSVC it's `*mut [usize; 2]`. For more information see the compiler's
/// The third argument is a function called if a panic occurs. This function
/// takes the data pointer and a pointer to the target-specific exception
/// object that was caught. For more information see the compiler's
/// source as well as std's catch implementation.
#[cfg(not(bootstrap))]
pub fn r#try(try_fn: fn(*mut u8), data: *mut u8, catch_fn: fn(*mut u8, *mut u8)) -> i32;
#[cfg(bootstrap)]
pub fn r#try(f: fn(*mut u8), data: *mut u8, local_ptr: *mut u8) -> i32;

/// Emits a `!nontemporal` store according to LLVM (see their docs).
Expand Down
5 changes: 1 addition & 4 deletions src/libpanic_abort/lib.rs
Expand Up @@ -20,11 +20,8 @@

use core::any::Any;

// We need the definition of TryPayload for __rust_panic_cleanup.
include!("../libpanic_unwind/payload.rs");

#[rustc_std_internal_symbol]
pub unsafe extern "C" fn __rust_panic_cleanup(_: TryPayload) -> *mut (dyn Any + Send + 'static) {
pub unsafe extern "C" fn __rust_panic_cleanup(_: *mut u8) -> *mut (dyn Any + Send + 'static) {
unreachable!()
}

Expand Down
2 changes: 1 addition & 1 deletion src/libpanic_unwind/emcc.rs
Expand Up @@ -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>>,
}

Expand Down
8 changes: 1 addition & 7 deletions src/libpanic_unwind/lib.rs
Expand Up @@ -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"]
Expand All @@ -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`.
Expand All @@ -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))
}

Expand Down
21 changes: 0 additions & 21 deletions src/libpanic_unwind/payload.rs

This file was deleted.

41 changes: 24 additions & 17 deletions src/libpanic_unwind/seh.rs
Expand Up @@ -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
Expand Down Expand Up @@ -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),
};

Expand Down Expand Up @@ -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");
}
}
Expand All @@ -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,
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 1c950e5

Please sign in to comment.