summaryrefslogtreecommitdiffstats
path: root/vendor/unwinding/src/panicking.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/unwinding/src/panicking.rs')
-rw-r--r--vendor/unwinding/src/panicking.rs71
1 files changed, 71 insertions, 0 deletions
diff --git a/vendor/unwinding/src/panicking.rs b/vendor/unwinding/src/panicking.rs
new file mode 100644
index 000000000..9c83bfe4a
--- /dev/null
+++ b/vendor/unwinding/src/panicking.rs
@@ -0,0 +1,71 @@
+use core::mem::ManuallyDrop;
+
+use crate::abi::*;
+
+pub unsafe trait Exception {
+ const CLASS: [u8; 8];
+
+ fn wrap(this: Self) -> *mut UnwindException;
+ unsafe fn unwrap(ex: *mut UnwindException) -> Self;
+}
+
+pub fn begin_panic<E: Exception>(exception: E) -> UnwindReasonCode {
+ unsafe extern "C" fn exception_cleanup<E: Exception>(
+ _unwind_code: UnwindReasonCode,
+ exception: *mut UnwindException,
+ ) {
+ unsafe { E::unwrap(exception) };
+ }
+
+ let ex = E::wrap(exception);
+ unsafe {
+ (*ex).exception_class = u64::from_be_bytes(E::CLASS);
+ (*ex).exception_cleanup = Some(exception_cleanup::<E>);
+ _Unwind_RaiseException(ex)
+ }
+}
+
+pub fn catch_unwind<E: Exception, R, F: FnOnce() -> R>(f: F) -> Result<R, Option<E>> {
+ #[repr(C)]
+ union Data<F, R, E> {
+ f: ManuallyDrop<F>,
+ r: ManuallyDrop<R>,
+ p: ManuallyDrop<Option<E>>,
+ }
+
+ let mut data = Data {
+ f: ManuallyDrop::new(f),
+ };
+
+ 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::<E>) == 0 {
+ Ok(ManuallyDrop::into_inner(data.r))
+ } else {
+ Err(ManuallyDrop::into_inner(data.p))
+ };
+ }
+
+ #[inline]
+ fn do_call<F: FnOnce() -> R, R>(data: *mut u8) {
+ unsafe {
+ let data = &mut *(data as *mut Data<F, R, ()>);
+ let f = ManuallyDrop::take(&mut data.f);
+ data.r = ManuallyDrop::new(f());
+ }
+ }
+
+ #[cold]
+ fn do_catch<E: Exception>(data: *mut u8, exception: *mut u8) {
+ unsafe {
+ let data = &mut *(data as *mut ManuallyDrop<Option<E>>);
+ let exception = exception as *mut UnwindException;
+ if (*exception).exception_class != u64::from_be_bytes(E::CLASS) {
+ _Unwind_DeleteException(exception);
+ *data = ManuallyDrop::new(None);
+ return;
+ }
+ *data = ManuallyDrop::new(Some(E::unwrap(exception)));
+ }
+ }
+}