panicking.rs 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. use core::mem::ManuallyDrop;
  2. use crate::abi::*;
  3. pub unsafe trait Exception {
  4. const CLASS: [u8; 8];
  5. fn wrap(this: Self) -> *mut UnwindException;
  6. unsafe fn unwrap(ex: *mut UnwindException) -> Self;
  7. }
  8. pub fn begin_panic<E: Exception>(exception: E) -> UnwindReasonCode {
  9. unsafe extern "C" fn exception_cleanup<E: Exception>(
  10. _unwind_code: UnwindReasonCode,
  11. exception: *mut UnwindException,
  12. ) {
  13. unsafe { E::unwrap(exception) };
  14. }
  15. let ex = E::wrap(exception);
  16. unsafe {
  17. (*ex).exception_class = u64::from_be_bytes(E::CLASS);
  18. (*ex).exception_cleanup = Some(exception_cleanup::<E>);
  19. _Unwind_RaiseException(ex)
  20. }
  21. }
  22. pub fn catch_unwind<E: Exception, R, F: FnOnce() -> R>(f: F) -> Result<R, Option<E>> {
  23. #[repr(C)]
  24. union Data<F, R, E> {
  25. f: ManuallyDrop<F>,
  26. r: ManuallyDrop<R>,
  27. p: ManuallyDrop<Option<E>>,
  28. }
  29. let mut data = Data {
  30. f: ManuallyDrop::new(f),
  31. };
  32. let data_ptr = &mut data as *mut _ as *mut u8;
  33. unsafe {
  34. return if core::intrinsics::catch_unwind(do_call::<F, R>, data_ptr, do_catch::<E>) == 0 {
  35. Ok(ManuallyDrop::into_inner(data.r))
  36. } else {
  37. Err(ManuallyDrop::into_inner(data.p))
  38. };
  39. }
  40. #[inline]
  41. fn do_call<F: FnOnce() -> R, R>(data: *mut u8) {
  42. unsafe {
  43. let data = &mut *(data as *mut Data<F, R, ()>);
  44. let f = ManuallyDrop::take(&mut data.f);
  45. data.r = ManuallyDrop::new(f());
  46. }
  47. }
  48. #[cold]
  49. fn do_catch<E: Exception>(data: *mut u8, exception: *mut u8) {
  50. unsafe {
  51. let data = &mut *(data as *mut ManuallyDrop<Option<E>>);
  52. let exception = exception as *mut UnwindException;
  53. if (*exception).exception_class != u64::from_be_bytes(E::CLASS) {
  54. _Unwind_DeleteException(exception);
  55. *data = ManuallyDrop::new(None);
  56. return;
  57. }
  58. *data = ManuallyDrop::new(Some(E::unwrap(exception)));
  59. }
  60. }
  61. }