#![feature(libc)]
#![feature(nll)]
#![feature(panic_unwind)]
-#![feature(raw)]
#![feature(staged_api)]
#![feature(std_internals)]
#![feature(unwind_attributes)]
#![feature(abi_thiscall)]
+#![feature(rustc_attrs)]
+#![feature(raw)]
#![panic_runtime]
#![feature(panic_runtime)]
use alloc::boxed::Box;
-use core::intrinsics;
-use core::mem;
use core::panic::BoxMeUp;
-use core::raw;
+// If adding to this list, you should also look at libstd::panicking's identical
+// list of Payload types and likely add to there as well.
cfg_if::cfg_if! {
if #[cfg(target_os = "emscripten")] {
#[path = "emcc.rs"]
mod dwarf;
-// Entry point for catching an exception, implemented using the `try` intrinsic
-// in the compiler.
-//
-// The interaction between the `payload` function and the compiler is pretty
-// hairy and tightly coupled, for more information see the compiler's
-// implementation of this.
#[no_mangle]
-pub unsafe extern "C" fn __rust_maybe_catch_panic(
- f: fn(*mut u8),
- data: *mut u8,
- data_ptr: *mut usize,
- vtable_ptr: *mut usize,
-) -> u32 {
- let mut payload = imp::payload();
- if intrinsics::r#try(f, data, &mut payload as *mut _ as *mut _) == 0 {
- 0
- } else {
- let obj = mem::transmute::<_, raw::TraitObject>(imp::cleanup(payload));
- *data_ptr = obj.data as usize;
- *vtable_ptr = obj.vtable as usize;
- 1
- }
+pub unsafe extern "C" fn __rust_panic_cleanup(payload: *mut u8) -> core::raw::TraitObject {
+ let payload = payload as *mut imp::Payload;
+ let payload = *(payload);
+ core::mem::transmute(imp::cleanup(payload))
}
// Entry point for raising an exception, just delegates to the platform-specific
use crate::any::Any;
use crate::fmt;
use crate::intrinsics;
-use crate::mem::{self, ManuallyDrop};
+use crate::mem::{self, ManuallyDrop, MaybeUninit};
use crate::process;
-use crate::raw;
use crate::sync::atomic::{AtomicBool, Ordering};
use crate::sys::stdio::panic_output;
use crate::sys_common::backtrace::{self, RustBacktrace};
#[cfg(test)]
use realstd::io::set_panic;
+// This must be kept in sync with the implementations in libpanic_unwind.
+//
+// This is *not* checked in anyway; the compiler does not allow us to use a
+// type/macro/anything from panic_unwind, since we're then linking in the
+// panic_unwind runtime even during -Cpanic=abort.
+//
+// Essentially this must be the type of `imp::Payload` in libpanic_unwind.
+cfg_if::cfg_if! {
+ if #[cfg(not(feature = "panic_unwind"))] {
+ type Payload = ();
+ } else if #[cfg(target_os = "emscripten")] {
+ type Payload = *mut u8;
+ } else if #[cfg(target_arch = "wasm32")] {
+ type Payload = *mut u8;
+ } else if #[cfg(target_os = "hermit")] {
+ type Payload = *mut u8;
+ } else if #[cfg(all(target_env = "msvc", target_arch = "aarch64"))] {
+ type Payload = *mut u8;
+ } else if #[cfg(target_env = "msvc")] {
+ type Payload = [u64; 2];
+ } else {
+ type Payload = *mut u8;
+ }
+}
+
// Binary interface to the panic runtime that the standard library depends on.
//
// The standard library is tagged with `#![needs_panic_runtime]` (introduced in
// hook up these functions, but it is not this day!
#[allow(improper_ctypes)]
extern "C" {
- fn __rust_maybe_catch_panic(
- f: fn(*mut u8),
- data: *mut u8,
- data_ptr: *mut usize,
- vtable_ptr: *mut usize,
- ) -> u32;
+ /// 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: *mut u8) -> core::raw::TraitObject;
/// `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
}
// We do some sketchy operations with ownership here for the sake of
- // performance. We can only pass pointers down to
- // `__rust_maybe_catch_panic` (can't pass objects by value), so we do all
- // the ownership tracking here manually using a union.
+ // performance. We can only pass pointers down to `do_call` (can't pass
+ // objects by value), so we do all the ownership tracking here manually
+ // using a union.
//
// We go through a transition where:
//
// * If the closure successfully returns, we write the return value into the
// data's return slot. Note that `ptr::write` is used as it's overwriting
// uninitialized data.
- // * Finally, when we come back out of the `__rust_maybe_catch_panic` we're
+ // * Finally, when we come back out of the `try` intrinsic we're
// in one of two states:
//
// 1. The closure didn't panic, in which case the return value was
//
// Once we stack all that together we should have the "most efficient'
// method of calling a catch panic whilst juggling ownership.
- let mut any_data = 0;
- let mut any_vtable = 0;
let mut data = Data { f: ManuallyDrop::new(f) };
- let r = __rust_maybe_catch_panic(
- do_call::<F, R>,
- &mut data as *mut _ as *mut u8,
- &mut any_data,
- &mut any_vtable,
- );
+ let mut payload: MaybeUninit<Payload> = MaybeUninit::uninit();
- return if r == 0 {
+ 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 {
Ok(ManuallyDrop::into_inner(data.r))
} else {
- update_panic_count(-1);
- Err(mem::transmute(raw::TraitObject {
- data: any_data as *mut _,
- vtable: any_vtable as *mut _,
- }))
+ Err(cleanup(payload.assume_init()))
};
+ unsafe fn cleanup(mut payload: Payload) -> Box<dyn Any + Send + 'static> {
+ let obj = crate::mem::transmute(__rust_panic_cleanup(&mut payload as *mut _ as *mut u8));
+ update_panic_count(-1);
+ obj
+ }
+
fn do_call<F: FnOnce() -> R, R>(data: *mut u8) {
unsafe {
let data = data as *mut Data<F, R>;