|
@@ -1,106 +1,70 @@
|
|
use alloc::boxed::Box;
|
|
use alloc::boxed::Box;
|
|
use core::any::Any;
|
|
use core::any::Any;
|
|
-use core::mem::ManuallyDrop;
|
|
|
|
|
|
+use core::mem::MaybeUninit;
|
|
|
|
|
|
use crate::abi::*;
|
|
use crate::abi::*;
|
|
#[cfg(feature = "panic-handler")]
|
|
#[cfg(feature = "panic-handler")]
|
|
-pub use crate::panic_handler::*;
|
|
|
|
|
|
+use crate::panic_handler::*;
|
|
|
|
+use crate::panicking::Exception;
|
|
|
|
|
|
-#[repr(C)]
|
|
|
|
-struct Exception {
|
|
|
|
- exception: UnwindException,
|
|
|
|
- payload: Box<dyn Any + Send>,
|
|
|
|
-}
|
|
|
|
|
|
+#[repr(transparent)]
|
|
|
|
+struct RustPanic(Box<dyn Any + Send>, ForeignGuard);
|
|
|
|
|
|
-const RUST_EXCEPTION_CLASS: u64 = u64::from_be_bytes(*b"MOZ\0RUST");
|
|
|
|
-
|
|
|
|
-pub fn begin_panic(payload: Box<dyn Any + Send>) -> UnwindReasonCode {
|
|
|
|
- unsafe extern "C" fn exception_cleanup(
|
|
|
|
- _unwind_code: UnwindReasonCode,
|
|
|
|
- exception: *mut UnwindException,
|
|
|
|
- ) {
|
|
|
|
- unsafe {
|
|
|
|
- let _ = Box::from_raw(exception as *mut Exception);
|
|
|
|
- }
|
|
|
|
- #[cfg(feature = "panic-handler")]
|
|
|
|
- {
|
|
|
|
- drop_panic();
|
|
|
|
- }
|
|
|
|
- #[cfg(not(feature = "panic-handler"))]
|
|
|
|
- {
|
|
|
|
- core::intrinsics::abort();
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- let mut unwind_ex = UnwindException::new();
|
|
|
|
- unwind_ex.exception_class = RUST_EXCEPTION_CLASS;
|
|
|
|
- unwind_ex.exception_cleanup = Some(exception_cleanup);
|
|
|
|
- let exception = Box::new(Exception {
|
|
|
|
- exception: unwind_ex,
|
|
|
|
- payload,
|
|
|
|
- });
|
|
|
|
- _Unwind_RaiseException(unsafe { &mut *(Box::into_raw(exception) as *mut UnwindException) })
|
|
|
|
-}
|
|
|
|
|
|
+struct ForeignGuard;
|
|
|
|
|
|
-#[cold]
|
|
|
|
-unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send + 'static> {
|
|
|
|
- let exception = payload as *mut UnwindException;
|
|
|
|
- if unsafe { (*exception).exception_class } != RUST_EXCEPTION_CLASS {
|
|
|
|
- unsafe { _Unwind_DeleteException(exception) };
|
|
|
|
|
|
+impl Drop for ForeignGuard {
|
|
|
|
+ fn drop(&mut self) {
|
|
#[cfg(feature = "panic-handler")]
|
|
#[cfg(feature = "panic-handler")]
|
|
{
|
|
{
|
|
foreign_exception();
|
|
foreign_exception();
|
|
}
|
|
}
|
|
- #[cfg(not(feature = "panic-handler"))]
|
|
|
|
- {
|
|
|
|
- core::intrinsics::abort();
|
|
|
|
- }
|
|
|
|
|
|
+ core::intrinsics::abort();
|
|
}
|
|
}
|
|
- #[cfg(feature = "panic-handler")]
|
|
|
|
- {
|
|
|
|
- panic_caught();
|
|
|
|
- }
|
|
|
|
- let unwind_ex = unsafe { Box::from_raw(exception as *mut Exception) };
|
|
|
|
- unwind_ex.payload
|
|
|
|
}
|
|
}
|
|
|
|
|
|
-pub fn catch_unwind<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> {
|
|
|
|
- union Data<F, R> {
|
|
|
|
- f: ManuallyDrop<F>,
|
|
|
|
- r: ManuallyDrop<R>,
|
|
|
|
- p: ManuallyDrop<Box<dyn Any + Send>>,
|
|
|
|
- }
|
|
|
|
|
|
+#[repr(C)]
|
|
|
|
+struct ExceptionWithPayload {
|
|
|
|
+ exception: MaybeUninit<UnwindException>,
|
|
|
|
+ payload: RustPanic,
|
|
|
|
+}
|
|
|
|
|
|
- let mut data = Data {
|
|
|
|
- f: ManuallyDrop::new(f),
|
|
|
|
- };
|
|
|
|
|
|
+unsafe impl Exception for RustPanic {
|
|
|
|
+ const CLASS: [u8; 8] = *b"MOZ\0RUST";
|
|
|
|
|
|
- let data_ptr = &mut data as *mut _ as *mut u8;
|
|
|
|
- unsafe {
|
|
|
|
- return if core::intrinsics::r#try(do_call::<F, R>, data_ptr, do_catch::<F, R>) == 0 {
|
|
|
|
- Ok(ManuallyDrop::into_inner(data.r))
|
|
|
|
- } else {
|
|
|
|
- Err(ManuallyDrop::into_inner(data.p))
|
|
|
|
- };
|
|
|
|
|
|
+ fn wrap(this: Self) -> *mut UnwindException {
|
|
|
|
+ Box::into_raw(Box::new(ExceptionWithPayload {
|
|
|
|
+ exception: MaybeUninit::uninit(),
|
|
|
|
+ payload: this,
|
|
|
|
+ })) as *mut UnwindException
|
|
}
|
|
}
|
|
|
|
|
|
- #[inline]
|
|
|
|
- fn do_call<F: FnOnce() -> R, R>(data: *mut u8) {
|
|
|
|
- unsafe {
|
|
|
|
- let data = data as *mut Data<F, R>;
|
|
|
|
- let data = &mut (*data);
|
|
|
|
- let f = ManuallyDrop::take(&mut data.f);
|
|
|
|
- data.r = ManuallyDrop::new(f());
|
|
|
|
- }
|
|
|
|
|
|
+ unsafe fn unwrap(ex: *mut UnwindException) -> Self {
|
|
|
|
+ let ex = unsafe { Box::from_raw(ex as *mut ExceptionWithPayload) };
|
|
|
|
+ ex.payload
|
|
}
|
|
}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+pub fn begin_panic(payload: Box<dyn Any + Send>) -> UnwindReasonCode {
|
|
|
|
+ crate::panicking::begin_panic(RustPanic(payload, ForeignGuard))
|
|
|
|
+}
|
|
|
|
|
|
- #[inline]
|
|
|
|
- fn do_catch<F: FnOnce() -> R, R>(data: *mut u8, payload: *mut u8) {
|
|
|
|
- unsafe {
|
|
|
|
- let data = data as *mut Data<F, R>;
|
|
|
|
- let data = &mut (*data);
|
|
|
|
- let obj = cleanup(payload);
|
|
|
|
- data.p = ManuallyDrop::new(obj);
|
|
|
|
|
|
+pub fn catch_unwind<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> {
|
|
|
|
+ #[cold]
|
|
|
|
+ fn process_panic(p: Option<RustPanic>) -> Box<dyn Any + Send> {
|
|
|
|
+ match p {
|
|
|
|
+ None => {
|
|
|
|
+ #[cfg(feature = "panic-handler")]
|
|
|
|
+ {
|
|
|
|
+ drop_panic();
|
|
|
|
+ }
|
|
|
|
+ core::intrinsics::abort();
|
|
|
|
+ }
|
|
|
|
+ Some(e) => {
|
|
|
|
+ panic_caught();
|
|
|
|
+ core::mem::forget(e.1);
|
|
|
|
+ e.0
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ crate::panicking::catch_unwind(f).map_err(process_panic)
|
|
}
|
|
}
|