Skip to content

Commit fb1376c

Browse files
committed
Simplify the try intrinsic by using a callback in the catch block
1 parent a090b93 commit fb1376c

File tree

10 files changed

+129
-108
lines changed

10 files changed

+129
-108
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
@@ -36,8 +36,6 @@ use alloc::boxed::Box;
3636
use core::any::Any;
3737
use core::panic::BoxMeUp;
3838

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

66-
include!("payload.rs");
67-
6864
extern "C" {
6965
/// Handler in libstd called when a panic object is dropped outside of
7066
/// `catch_unwind`.
@@ -74,9 +70,7 @@ extern "C" {
7470
mod dwarf;
7571

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

src/libpanic_unwind/payload.rs

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

src/libpanic_unwind/seh.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,14 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
311311
_CxxThrowException(throw_ptr, &mut THROW_INFO as *mut _ as *mut _);
312312
}
313313

314-
pub unsafe fn cleanup(payload: [u64; 2]) -> Box<dyn Any + Send> {
314+
pub unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send> {
315+
let payload = *&mut (payload as *mut [u64; 2]);
316+
317+
// Clear the first word of the exception so avoid double-dropping it.
318+
// This will be read by the destructor which is implicitly called at the
319+
// end of the catch block by the runtime.
320+
payload[0] = 0;
321+
315322
mem::transmute(raw::TraitObject { data: payload[0] as *mut _, vtable: payload[1] as *mut _ })
316323
}
317324

src/librustc_codegen_llvm/intrinsic.rs

Lines changed: 44 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -851,21 +851,21 @@ fn memset_intrinsic(
851851

852852
fn try_intrinsic(
853853
bx: &mut Builder<'a, 'll, 'tcx>,
854-
func: &'ll Value,
854+
try_func: &'ll Value,
855855
data: &'ll Value,
856-
local_ptr: &'ll Value,
856+
catch_func: &'ll Value,
857857
dest: &'ll Value,
858858
) {
859859
if bx.sess().no_landing_pads() {
860-
bx.call(func, &[data], None);
860+
bx.call(try_func, &[data], None);
861861
// Return 0 unconditionally from the intrinsic call;
862862
// we can never unwind.
863863
let ret_align = bx.tcx().data_layout.i32_align.abi;
864864
bx.store(bx.const_i32(0), dest, ret_align);
865865
} else if wants_msvc_seh(bx.sess()) {
866-
codegen_msvc_try(bx, func, data, local_ptr, dest);
866+
codegen_msvc_try(bx, try_func, data, catch_func, dest);
867867
} else {
868-
codegen_gnu_try(bx, func, data, local_ptr, dest);
868+
codegen_gnu_try(bx, try_func, data, catch_func, dest);
869869
}
870870
}
871871

@@ -878,9 +878,9 @@ fn try_intrinsic(
878878
// as the old ones are still more optimized.
879879
fn codegen_msvc_try(
880880
bx: &mut Builder<'a, 'll, 'tcx>,
881-
func: &'ll Value,
881+
try_func: &'ll Value,
882882
data: &'ll Value,
883-
local_ptr: &'ll Value,
883+
catch_func: &'ll Value,
884884
dest: &'ll Value,
885885
) {
886886
let llfn = get_rust_try_fn(bx, &mut |mut bx| {
@@ -892,15 +892,15 @@ fn codegen_msvc_try(
892892
let mut catchpad = bx.build_sibling_block("catchpad");
893893
let mut caught = bx.build_sibling_block("caught");
894894

895-
let func = llvm::get_param(bx.llfn(), 0);
895+
let try_func = llvm::get_param(bx.llfn(), 0);
896896
let data = llvm::get_param(bx.llfn(), 1);
897-
let local_ptr = llvm::get_param(bx.llfn(), 2);
897+
let catch_func = llvm::get_param(bx.llfn(), 2);
898898

899899
// We're generating an IR snippet that looks like:
900900
//
901-
// declare i32 @rust_try(%func, %data, %ptr) {
902-
// %slot = alloca [2 x i64]
903-
// invoke %func(%data) to label %normal unwind label %catchswitch
901+
// declare i32 @rust_try(%try_func, %data, %catch_func) {
902+
// %slot = alloca u8*
903+
// invoke %try_func(%data) to label %normal unwind label %catchswitch
904904
//
905905
// normal:
906906
// ret i32 0
@@ -928,26 +928,26 @@ fn codegen_msvc_try(
928928
// ~rust_panic();
929929
//
930930
// uint64_t x[2];
931-
// }
931+
// };
932932
//
933-
// int bar(void (*foo)(void), uint64_t *ret) {
933+
// int __rust_try(
934+
// void (*try_func)(void*),
935+
// void *data,
936+
// void (*catch_func)(void*, void*) noexcept
937+
// ) {
934938
// try {
935-
// foo();
939+
// try_func(data);
936940
// return 0;
937941
// } catch(rust_panic& a) {
938-
// ret[0] = a.x[0];
939-
// ret[1] = a.x[1];
940-
// a.x[0] = 0;
942+
// catch_func(data, &a);
941943
// return 1;
942944
// }
943945
// }
944946
//
945947
// More information can be found in libstd's seh.rs implementation.
946-
let i64_2 = bx.type_array(bx.type_i64(), 2);
947-
let i64_2_ptr = bx.type_ptr_to(i64_2);
948948
let ptr_align = bx.tcx().data_layout.pointer_align.abi;
949-
let slot = bx.alloca(i64_2_ptr, ptr_align);
950-
bx.invoke(func, &[data], normal.llbb(), catchswitch.llbb(), None);
949+
let slot = bx.alloca(bx.type_i8p(), ptr_align);
950+
bx.invoke(try_func, &[data], normal.llbb(), catchswitch.llbb(), None);
951951

952952
normal.ret(bx.const_i32(0));
953953

@@ -987,17 +987,8 @@ fn codegen_msvc_try(
987987
// Source: MicrosoftCXXABI::getAddrOfCXXCatchHandlerType in clang
988988
let flags = bx.const_i32(8);
989989
let funclet = catchpad.catch_pad(cs, &[tydesc, flags, slot]);
990-
let i64_align = bx.tcx().data_layout.i64_align.abi;
991-
let payload_ptr = catchpad.load(slot, ptr_align);
992-
let payload = catchpad.load(payload_ptr, i64_align);
993-
let local_ptr = catchpad.bitcast(local_ptr, bx.type_ptr_to(i64_2));
994-
catchpad.store(payload, local_ptr, i64_align);
995-
996-
// Clear the first word of the exception so avoid double-dropping it.
997-
// This will be read by the destructor which is implicitly called at the
998-
// end of the catch block by the runtime.
999-
let payload_0_ptr = catchpad.inbounds_gep(payload_ptr, &[bx.const_i32(0), bx.const_i32(0)]);
1000-
catchpad.store(bx.const_u64(0), payload_0_ptr, i64_align);
990+
let ptr = catchpad.load(slot, ptr_align);
991+
catchpad.call(catch_func, &[data, ptr], Some(&funclet));
1001992

1002993
catchpad.catch_ret(&funclet, caught.llbb());
1003994

@@ -1006,7 +997,7 @@ fn codegen_msvc_try(
1006997

1007998
// Note that no invoke is used here because by definition this function
1008999
// can't panic (that's what it's catching).
1009-
let ret = bx.call(llfn, &[func, data, local_ptr], None);
1000+
let ret = bx.call(llfn, &[try_func, data, catch_func], None);
10101001
let i32_align = bx.tcx().data_layout.i32_align.abi;
10111002
bx.store(ret, dest, i32_align);
10121003
}
@@ -1024,38 +1015,34 @@ fn codegen_msvc_try(
10241015
// the right personality function.
10251016
fn codegen_gnu_try(
10261017
bx: &mut Builder<'a, 'll, 'tcx>,
1027-
func: &'ll Value,
1018+
try_func: &'ll Value,
10281019
data: &'ll Value,
1029-
local_ptr: &'ll Value,
1020+
catch_func: &'ll Value,
10301021
dest: &'ll Value,
10311022
) {
10321023
let llfn = get_rust_try_fn(bx, &mut |mut bx| {
10331024
// Codegens the shims described above:
10341025
//
10351026
// bx:
1036-
// invoke %func(%args...) normal %normal unwind %catch
1027+
// invoke %func(%data) normal %normal unwind %catch
10371028
//
10381029
// normal:
10391030
// ret 0
10401031
//
10411032
// catch:
1042-
// (ptr, _) = landingpad
1043-
// store ptr, %local_ptr
1033+
// (%ptr, _) = landingpad
1034+
// call %catch_func(%data, %ptr)
10441035
// ret 1
1045-
//
1046-
// Note that the `local_ptr` data passed into the `try` intrinsic is
1047-
// expected to be `*mut *mut u8` for this to actually work, but that's
1048-
// managed by the standard library.
10491036

10501037
bx.sideeffect();
10511038

10521039
let mut then = bx.build_sibling_block("then");
10531040
let mut catch = bx.build_sibling_block("catch");
10541041

1055-
let func = llvm::get_param(bx.llfn(), 0);
1042+
let try_func = llvm::get_param(bx.llfn(), 0);
10561043
let data = llvm::get_param(bx.llfn(), 1);
1057-
let local_ptr = llvm::get_param(bx.llfn(), 2);
1058-
bx.invoke(func, &[data], then.llbb(), catch.llbb(), None);
1044+
let catch_func = llvm::get_param(bx.llfn(), 2);
1045+
bx.invoke(try_func, &[data], then.llbb(), catch.llbb(), None);
10591046
then.ret(bx.const_i32(0));
10601047

10611048
// Type indicator for the exception being thrown.
@@ -1075,15 +1062,13 @@ fn codegen_gnu_try(
10751062
};
10761063
catch.add_clause(vals, tydesc);
10771064
let ptr = catch.extract_value(vals, 0);
1078-
let ptr_align = bx.tcx().data_layout.pointer_align.abi;
1079-
let bitcast = catch.bitcast(local_ptr, bx.type_ptr_to(bx.type_i8p()));
1080-
catch.store(ptr, bitcast, ptr_align);
1065+
catch.call(catch_func, &[data, ptr], None);
10811066
catch.ret(bx.const_i32(1));
10821067
});
10831068

10841069
// Note that no invoke is used here because by definition this function
10851070
// can't panic (that's what it's catching).
1086-
let ret = bx.call(llfn, &[func, data, local_ptr], None);
1071+
let ret = bx.call(llfn, &[try_func, data, catch_func], None);
10871072
let i32_align = bx.tcx().data_layout.i32_align.abi;
10881073
bx.store(ret, dest, i32_align);
10891074
}
@@ -1130,15 +1115,22 @@ fn get_rust_try_fn<'ll, 'tcx>(
11301115
// Define the type up front for the signature of the rust_try function.
11311116
let tcx = cx.tcx;
11321117
let i8p = tcx.mk_mut_ptr(tcx.types.i8);
1133-
let fn_ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig(
1118+
let try_fn_ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig(
11341119
iter::once(i8p),
11351120
tcx.mk_unit(),
11361121
false,
11371122
hir::Unsafety::Unsafe,
11381123
Abi::Rust,
11391124
)));
1125+
let catch_fn_ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig(
1126+
[i8p, i8p].iter().cloned(),
1127+
tcx.mk_unit(),
1128+
false,
1129+
hir::Unsafety::Unsafe,
1130+
Abi::Rust,
1131+
)));
11401132
let output = tcx.types.i32;
1141-
let rust_try = gen_fn(cx, "__rust_try", vec![fn_ty, i8p, i8p], output, codegen);
1133+
let rust_try = gen_fn(cx, "__rust_try", vec![try_fn_ty, i8p, catch_fn_ty], output, codegen);
11421134
cx.rust_try_fn.set(Some(rust_try));
11431135
rust_try
11441136
}

src/librustc_typeck/check/intrinsic.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,14 +297,25 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
297297

298298
"try" => {
299299
let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8);
300-
let fn_ty = ty::Binder::bind(tcx.mk_fn_sig(
300+
let try_fn_ty = ty::Binder::bind(tcx.mk_fn_sig(
301301
iter::once(mut_u8),
302302
tcx.mk_unit(),
303303
false,
304304
hir::Unsafety::Normal,
305305
Abi::Rust,
306306
));
307-
(0, vec![tcx.mk_fn_ptr(fn_ty), mut_u8, mut_u8], tcx.types.i32)
307+
let catch_fn_ty = ty::Binder::bind(tcx.mk_fn_sig(
308+
[mut_u8, mut_u8].iter().cloned(),
309+
tcx.mk_unit(),
310+
false,
311+
hir::Unsafety::Normal,
312+
Abi::Rust,
313+
));
314+
(
315+
0,
316+
vec![tcx.mk_fn_ptr(try_fn_ty), mut_u8, tcx.mk_fn_ptr(catch_fn_ty)],
317+
tcx.types.i32,
318+
)
308319
}
309320

310321
"va_start" | "va_end" => match mk_va_list_ty(hir::Mutability::Mut) {

0 commit comments

Comments
 (0)