Skip to content

Commit 1c950e5

Browse files
committed
Simplify the try intrinsic by using a callback in the catch block
1 parent 5953c10 commit 1c950e5

File tree

10 files changed

+150
-126
lines changed

10 files changed

+150
-126
lines changed

src/libcore/intrinsics.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,14 +1390,16 @@ extern "rust-intrinsic" {
13901390
/// cast to a `u64`; if `T` has no discriminant, returns 0.
13911391
pub fn discriminant_value<T>(v: &T) -> u64;
13921392

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

14031405
/// Emits a `!nontemporal` store according to LLVM (see their docs).

src/libpanic_abort/lib.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,8 @@
2020

2121
use core::any::Any;
2222

23-
// We need the definition of TryPayload for __rust_panic_cleanup.
24-
include!("../libpanic_unwind/payload.rs");
25-
2623
#[rustc_std_internal_symbol]
27-
pub unsafe extern "C" fn __rust_panic_cleanup(_: TryPayload) -> *mut (dyn Any + Send + 'static) {
24+
pub unsafe extern "C" fn __rust_panic_cleanup(_: *mut u8) -> *mut (dyn Any + Send + 'static) {
2825
unreachable!()
2926
}
3027

src/libpanic_unwind/emcc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ struct Exception {
5252
// This needs to be an Option because the object's lifetime follows C++
5353
// semantics: when catch_unwind moves the Box out of the exception it must
5454
// still leave the exception object in a valid state because its destructor
55-
// is still going to be called by __cxa_end_catch..
55+
// is still going to be called by __cxa_end_catch.
5656
data: Option<Box<dyn Any + Send>>,
5757
}
5858

src/libpanic_unwind/lib.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,6 @@ use alloc::boxed::Box;
3535
use core::any::Any;
3636
use core::panic::BoxMeUp;
3737

38-
// If adding to this list, you should also look at the list of TryPayload types
39-
// defined in payload.rs and likely add to there as well.
4038
cfg_if::cfg_if! {
4139
if #[cfg(target_os = "emscripten")] {
4240
#[path = "emcc.rs"]
@@ -62,8 +60,6 @@ cfg_if::cfg_if! {
6260
}
6361
}
6462

65-
include!("payload.rs");
66-
6763
extern "C" {
6864
/// Handler in libstd called when a panic object is dropped outside of
6965
/// `catch_unwind`.
@@ -73,9 +69,7 @@ extern "C" {
7369
mod dwarf;
7470

7571
#[rustc_std_internal_symbol]
76-
pub unsafe extern "C" fn __rust_panic_cleanup(
77-
payload: TryPayload,
78-
) -> *mut (dyn Any + Send + 'static) {
72+
pub unsafe extern "C" fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static) {
7973
Box::into_raw(imp::cleanup(payload))
8074
}
8175

src/libpanic_unwind/payload.rs

Lines changed: 0 additions & 21 deletions
This file was deleted.

src/libpanic_unwind/seh.rs

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,17 @@
4949

5050
use alloc::boxed::Box;
5151
use core::any::Any;
52-
use core::mem;
53-
use core::raw;
52+
use core::mem::{self, ManuallyDrop};
5453
use libc::{c_int, c_uint, c_void};
5554

55+
struct Exception {
56+
// This needs to be an Option because we catch the exception by reference
57+
// and its destructor is executed by the C++ runtime. When we take the Box
58+
// out of the exception, we need to leave the exception in a valid state
59+
// for its destructor to run without double-dropping the Box.
60+
data: Option<Box<dyn Any + Send>>,
61+
}
62+
5663
// First up, a whole bunch of type definitions. There's a few platform-specific
5764
// oddities here, and a lot that's just blatantly copied from LLVM. The purpose
5865
// of all this is to implement the `panic` function below through a call to
@@ -186,7 +193,7 @@ static mut CATCHABLE_TYPE: _CatchableType = _CatchableType {
186193
properties: 0,
187194
pType: ptr!(0),
188195
thisDisplacement: _PMD { mdisp: 0, pdisp: -1, vdisp: 0 },
189-
sizeOrOffset: mem::size_of::<[u64; 2]>() as c_int,
196+
sizeOrOffset: mem::size_of::<Exception>() as c_int,
190197
copyFunction: ptr!(0),
191198
};
192199

@@ -229,16 +236,16 @@ static mut TYPE_DESCRIPTOR: _TypeDescriptor = _TypeDescriptor {
229236
// because Box<dyn Any> isn't clonable.
230237
macro_rules! define_cleanup {
231238
($abi:tt) => {
232-
unsafe extern $abi fn exception_cleanup(e: *mut [u64; 2]) {
233-
if (*e)[0] != 0 {
234-
cleanup(*e);
239+
unsafe extern $abi fn exception_cleanup(e: *mut Exception) {
240+
if let Some(b) = e.read().data {
241+
drop(b);
235242
super::__rust_drop_panic();
236243
}
237244
}
238245
#[unwind(allowed)]
239-
unsafe extern $abi fn exception_copy(_dest: *mut [u64; 2],
240-
_src: *mut [u64; 2])
241-
-> *mut [u64; 2] {
246+
unsafe extern $abi fn exception_copy(_dest: *mut Exception,
247+
_src: *mut Exception)
248+
-> *mut Exception {
242249
panic!("Rust panics cannot be copied");
243250
}
244251
}
@@ -258,12 +265,11 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
258265
// need to otherwise transfer `data` to the heap. We just pass a stack
259266
// pointer to this function.
260267
//
261-
// The first argument is the payload being thrown (our two pointers), and
262-
// the second argument is the type information object describing the
263-
// exception (constructed above).
264-
let ptrs = mem::transmute::<_, raw::TraitObject>(data);
265-
let mut ptrs = [ptrs.data as u64, ptrs.vtable as u64];
266-
let throw_ptr = ptrs.as_mut_ptr() as *mut _;
268+
// The ManuallyDrop is needed here since we don't want Exception to be
269+
// dropped when unwinding. Instead it will be dropped by exception_cleanup
270+
// which is invoked by the C++ runtime.
271+
let mut exception = ManuallyDrop::new(Exception { data: Some(data) });
272+
let throw_ptr = &mut exception as *mut _ as *mut _;
267273

268274
// This... may seems surprising, and justifiably so. On 32-bit MSVC the
269275
// 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 {
311317
_CxxThrowException(throw_ptr, &mut THROW_INFO as *mut _ as *mut _);
312318
}
313319

314-
pub unsafe fn cleanup(payload: [u64; 2]) -> Box<dyn Any + Send> {
315-
mem::transmute(raw::TraitObject { data: payload[0] as *mut _, vtable: payload[1] as *mut _ })
320+
pub unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send> {
321+
let exception = &mut *(payload as *mut Exception);
322+
exception.data.take().unwrap()
316323
}
317324

318325
// This is required by the compiler to exist (e.g., it's a lang item), but

0 commit comments

Comments
 (0)