#![allow(unused_macros)]
use crate::stack::StackPointer;
use crate::util::EncodedValue;
cfg_if::cfg_if! {
if #[cfg(feature = "unwind")] {
extern crate std;
use core::any::Any;
use std::boxed::Box;
use std::panic::{self, AssertUnwindSafe};
use crate::CoroutineResult;
}
}
cfg_if::cfg_if! {
if #[cfg(any(not(windows), all(target_arch = "x86", target_env = "gnu")))] {
macro_rules! cfi_reset_args_size {
() => {
".cfi_escape 0x2e, 0x00"
};
}
} else {
macro_rules! cfi_reset_args_size {
() => {
""
};
}
}
}
cfg_if::cfg_if! {
if #[cfg(all(feature = "asm-unwind", not(windows)))] {
macro_rules! asm_may_unwind_root {
($($tt:tt)*) => {
core::arch::asm!($($tt)* options(may_unwind))
};
}
macro_rules! cfi_reset_args_size_root {
() => {
crate::unwind::cfi_reset_args_size!()
}
}
cfg_if::cfg_if! {
if #[cfg(target_arch = "x86_64")] {
pub type InitialFunc<T> = unsafe extern "sysv64-unwind" fn(
arg: EncodedValue,
sp: &mut StackPointer,
obj: *mut T,
) -> !;
pub type TrapHandler<T> = unsafe extern "sysv64-unwind" fn(
val: *mut T,
parent_link: *mut StackPointer,
) -> !;
pub type StackCallFunc = unsafe extern "sysv64-unwind" fn(ptr: *mut u8);
macro_rules! initial_func_abi {
(unsafe fn $($tt:tt)*) => {
unsafe extern "sysv64-unwind" fn $($tt)*
}
}
} else if #[cfg(target_arch = "x86")] {
pub type InitialFunc<T> = unsafe extern "fastcall-unwind" fn(
arg: EncodedValue,
sp: &mut StackPointer,
obj: *mut T,
) -> !;
pub type TrapHandler<T> = unsafe extern "fastcall-unwind" fn(
val: *mut T,
parent_link: *mut StackPointer,
) -> !;
pub type StackCallFunc = unsafe extern "fastcall-unwind" fn(ptr: *mut u8);
macro_rules! initial_func_abi {
(unsafe fn $($tt:tt)*) => {
unsafe extern "fastcall-unwind" fn $($tt)*
}
}
} else {
pub type InitialFunc<T> = unsafe extern "C-unwind" fn(
arg: EncodedValue,
sp: &mut StackPointer,
obj: *mut T,
) -> !;
pub type TrapHandler<T> =
unsafe extern "C-unwind" fn(val: *mut T, parent_link: *mut StackPointer) -> !;
pub type StackCallFunc = unsafe extern "C-unwind" fn(ptr: *mut u8);
macro_rules! initial_func_abi {
(unsafe fn $($tt:tt)*) => {
unsafe extern "C-unwind" fn $($tt)*
}
}
}
}
} else {
macro_rules! asm_may_unwind_root {
($($tt:tt)*) => {
core::arch::asm!($($tt)*)
};
}
macro_rules! cfi_reset_args_size_root {
() => {
""
}
}
cfg_if::cfg_if! {
if #[cfg(target_arch = "x86_64")] {
pub type InitialFunc<T> = unsafe extern "sysv64" fn(
arg: EncodedValue,
sp: &mut StackPointer,
obj: *mut T,
) -> !;
pub type TrapHandler<T> =
unsafe extern "sysv64" fn(val: *mut T, parent_link: *mut StackPointer) -> !;
pub type StackCallFunc = unsafe extern "sysv64" fn(ptr: *mut u8);
macro_rules! initial_func_abi {
(unsafe fn $($tt:tt)*) => {
unsafe extern "sysv64" fn $($tt)*
}
}
} else if #[cfg(target_arch = "x86")] {
pub type InitialFunc<T> = unsafe extern "fastcall" fn(
arg: EncodedValue,
sp: &mut StackPointer,
obj: *mut T,
) -> !;
pub type TrapHandler<T> =
unsafe extern "fastcall" fn(val: *mut T, parent_link: *mut StackPointer) -> !;
pub type StackCallFunc = unsafe extern "fastcall" fn(ptr: *mut u8);
macro_rules! initial_func_abi {
(unsafe fn $($tt:tt)*) => {
unsafe extern "fastcall" fn $($tt)*
}
}
} else {
pub type InitialFunc<T> = unsafe extern "C" fn(
arg: EncodedValue,
sp: &mut StackPointer,
obj: *mut T,
) -> !;
pub type TrapHandler<T> =
unsafe extern "C" fn(val: *mut T, parent_link: *mut StackPointer) -> !;
pub type StackCallFunc = unsafe extern "C" fn(ptr: *mut u8);
macro_rules! initial_func_abi {
(unsafe fn $($tt:tt)*) => {
unsafe extern "C" fn $($tt)*
}
}
}
}
}
}
cfg_if::cfg_if! {
if #[cfg(all(feature = "asm-unwind", not(windows)))] {
pub type CaughtPanic = core::convert::Infallible;
#[inline]
pub fn catch_unwind_at_root<T, F: FnOnce() -> T>(f: F) -> Result<T, CaughtPanic> {
Ok(f())
}
#[inline]
pub fn catch_forced_unwind<Yield, Return>(
f: impl FnOnce() -> CoroutineResult<Yield, Result<Return, CaughtPanic>>
) -> CoroutineResult<Yield, Result<Return, Box<dyn Any+ Send>>> {
match panic::catch_unwind(AssertUnwindSafe(|| f())) {
Ok(CoroutineResult::Yield(x)) => CoroutineResult::Yield(x),
Ok(CoroutineResult::Return(Ok(x))) => CoroutineResult::Return(Ok(x)),
Err(x) => CoroutineResult::Return(Err(x)),
}
}
#[inline]
pub fn maybe_resume_unwind<T>(val: Result<T, CaughtPanic>) -> T {
match val {
Ok(val) => val,
#[allow(unreachable_patterns)]
Err(_) => unreachable!(),
}
}
} else if #[cfg(feature = "unwind")] {
pub type CaughtPanic = Box<dyn Any + Send>;
#[inline]
pub fn catch_unwind_at_root<T, F: FnOnce() -> T>(f: F) -> Result<T, CaughtPanic> {
panic::catch_unwind(AssertUnwindSafe(f))
}
#[inline]
pub fn catch_forced_unwind<Yield, Return>(
f: impl FnOnce() -> CoroutineResult<Yield, Result<Return, CaughtPanic>>
) -> CoroutineResult<Yield, Result<Return, Box<dyn Any+ Send>>> {
f()
}
#[inline]
pub fn maybe_resume_unwind<T>(val: Result<T, CaughtPanic>) -> T {
match val {
Ok(val) => val,
Err(e) => panic::resume_unwind(e),
}
}
} else {
pub type CaughtPanic = core::convert::Infallible;
#[inline]
pub fn catch_unwind_at_root<T, F: FnOnce() -> T>(f: F) -> Result<T, CaughtPanic> {
let guard = scopeguard::guard((), |()| {
panic!("cannot propagate coroutine panic with #![no_std]");
});
let result = f();
core::mem::forget(guard);
Ok(result)
}
#[inline]
pub fn maybe_resume_unwind<T>(val: Result<T, CaughtPanic>) -> T {
match val {
Ok(val) => val,
Err(_) => unreachable!(),
}
}
}
}
cfg_if::cfg_if! {
if #[cfg(feature = "asm-unwind")] {
macro_rules! asm_may_unwind_yield {
($($tt:tt)*) => {
core::arch::asm!($($tt)* options(may_unwind))
};
}
macro_rules! cfi_reset_args_size_yield {
() => {
crate::unwind::cfi_reset_args_size!()
}
}
} else {
macro_rules! asm_may_unwind_yield {
($($tt:tt)*) => {
core::arch::asm!($($tt)*)
};
}
macro_rules! cfi_reset_args_size_yield {
() => {
""
}
}
}
}
cfg_if::cfg_if! {
if #[cfg(feature = "asm-unwind")] {
#[repr(transparent)]
pub struct ForcedUnwind(pub StackPointer);
pub type ForcedUnwindErr = core::convert::Infallible;
#[inline]
pub fn maybe_force_unwind<T>(val: Result<T, ForcedUnwindErr>) -> T {
match val {
Ok(val) => val,
#[allow(unreachable_patterns)]
Err(_) => unreachable!(),
}
}
} else if #[cfg(feature = "unwind")] {
#[repr(transparent)]
pub struct ForcedUnwind(pub StackPointer);
pub type ForcedUnwindErr = ForcedUnwind;
#[inline]
pub fn maybe_force_unwind<T>(val: Result<T, ForcedUnwindErr>) -> T {
match val {
Ok(val) => val,
Err(e) => panic::resume_unwind(Box::new(e)),
}
}
} else {
pub type ForcedUnwindErr = core::convert::Infallible;
#[inline]
pub fn maybe_force_unwind<T>(val: Result<T, ForcedUnwindErr>) -> T {
match val {
Ok(val) => val,
Err(_) => unreachable!(),
}
}
}
}
#[allow(unused_imports)]
pub(crate) use {
asm_may_unwind_root, asm_may_unwind_yield, cfi_reset_args_size, cfi_reset_args_size_root,
cfi_reset_args_size_yield, initial_func_abi,
};