Skip to main content

wasmtime/runtime/vm/
traphandlers.rs

1//! WebAssembly trap handling, which is built on top of the lower-level
2//! signalhandling mechanisms.
3
4mod backtrace;
5
6#[cfg(feature = "coredump")]
7#[path = "traphandlers/coredump_enabled.rs"]
8mod coredump;
9#[cfg(not(feature = "coredump"))]
10#[path = "traphandlers/coredump_disabled.rs"]
11mod coredump;
12
13#[cfg(all(has_native_signals))]
14mod signals;
15#[cfg(all(has_native_signals))]
16pub use self::signals::*;
17
18#[cfg(feature = "gc")]
19use crate::ThrownException;
20use crate::runtime::module::lookup_code;
21use crate::runtime::store::{ExecutorRef, StoreOpaque};
22use crate::runtime::vm::sys::traphandlers;
23use crate::runtime::vm::{InterpreterRef, VMContext, VMStore, VMStoreContext, f32x4, f64x2, i8x16};
24use crate::{EntryStoreContext, prelude::*};
25use crate::{StoreContextMut, WasmBacktrace};
26use core::cell::Cell;
27use core::num::NonZeroU32;
28use core::ptr::{self, NonNull};
29use wasmtime_unwinder::Handler;
30
31#[cfg(feature = "debug")]
32pub(crate) use self::backtrace::Activation;
33pub use self::backtrace::Backtrace;
34#[cfg(feature = "gc")]
35pub use wasmtime_unwinder::Frame;
36
37pub use self::coredump::CoreDumpStack;
38pub use self::tls::tls_eager_initialize;
39#[cfg(feature = "async")]
40pub use self::tls::{AsyncWasmCallState, PreviousAsyncWasmCallState};
41
42pub use traphandlers::SignalHandler;
43
44pub(crate) struct TrapRegisters {
45    pub pc: usize,
46    pub fp: usize,
47}
48
49/// Return value from `test_if_trap`.
50pub(crate) enum TrapTest {
51    /// Not a wasm trap, need to delegate to whatever process handler is next.
52    NotWasm,
53    /// This trap was handled by the embedder via custom embedding APIs.
54    #[cfg(has_host_compiler_backend)]
55    #[cfg_attr(miri, expect(dead_code, reason = "using #[cfg] too unergonomic"))]
56    HandledByEmbedder,
57    /// This is a wasm trap, it needs to be handled.
58    Trap(Handler),
59}
60
61fn lazy_per_thread_init() {
62    traphandlers::lazy_per_thread_init();
63}
64
65/// Raises a preexisting trap or exception and unwinds.
66///
67/// If the preexisting state has registered a trap, this function will execute
68/// the `Handler::resume` to make its way back to the original exception
69/// handler created when Wasm was entered. If the state has registered an
70/// exception, this function will perform the unwind action registered: either
71/// resetting PC, FP, and SP to the handler in the middle of the Wasm
72/// activation on the stack, or the entry trampoline back to the the host, if
73/// the exception is uncaught.
74///
75/// This is currently only called from the `raise` builtin of
76/// Wasmtime. This builtin is only used when the host returns back to
77/// wasm and indicates that a trap or exception should be raised. In
78/// this situation the host has already stored trap or exception
79/// information within the `CallThreadState` and this is the low-level
80/// operation to actually perform an unwind.
81///
82/// Note that this function is used both for Pulley and for native execution.
83/// For Pulley this function will return and the interpreter will be
84/// responsible for handling the control-flow transfer. For native this
85/// function will not return as the control flow transfer will be handled
86/// internally.
87///
88/// # Safety
89///
90/// Only safe to call when wasm code is on the stack, aka `catch_traps` must
91/// have been previously called. Additionally no Rust destructors can be on the
92/// stack. They will be skipped and not executed.
93pub(super) unsafe fn raise_preexisting_trap(store: &mut dyn VMStore) {
94    tls::with(|info| unsafe { info.unwrap().unwind(store) })
95}
96
97/// Invokes the closure `f` and handles any error/panic/trap that happens
98/// within.
99///
100/// This will invoke the closure `f` with the provided `store` and the closure
101/// will return a value that implements `HostResult`. This trait abstracts over
102/// how host values are translated to ABI values when going back into wasm.
103/// Some examples are:
104///
105/// * `T` - bare return types (not results) are simply returned as-is. No
106///   `catch_unwind` happens as if a trap can't happen then the host shouldn't
107///   be panicking or invoking user code.
108///
109/// * `Result<(), E>` - this represents an ABI return value of `bool` which
110///   indicates whether the call succeeded. This return value will catch panics
111///   and record trap information as `E`.
112///
113/// * `Result<u32, E>` - the ABI return value here is `u64` where on success
114///   the 32-bit result is zero-extended and `u64::MAX` as a return value
115///   indicates that a trap or panic happened.
116///
117/// This is primarily used in conjunction with the Cranelift-and-host boundary.
118/// This function acts as a bridge between the two to appropriately handle
119/// encoding host values to Cranelift-understood ABIs via the `HostResult`
120/// trait.
121pub fn catch_unwind_and_record_trap<R>(
122    store: &mut dyn VMStore,
123    f: impl FnOnce(&mut dyn VMStore) -> R,
124) -> R::Abi
125where
126    R: HostResult,
127{
128    // Invoke the closure `f`, optionally catching unwinds depending on `R`. The
129    // return value is always provided and if unwind information is provided
130    // (e.g. `ret` is a "false"-y value) then it's recorded in TLS for the
131    // unwind operation that's about to happen from Cranelift-generated code.
132    let (ret, unwind) = R::maybe_catch_unwind(store, |store| f(store));
133    if let Some(unwind) = unwind {
134        tls::with(|info| info.unwrap().record_unwind(unwind));
135    }
136    ret
137}
138
139/// A trait used in conjunction with `catch_unwind_and_record_trap` to convert a
140/// Rust-based type to a specific ABI while handling traps/unwinds.
141///
142/// This type is implemented for return values from host function calls and
143/// libcalls. The `Abi` value of this trait represents either a successful
144/// execution with some payload state or that a failed execution happened. In
145/// the event of a failed execution the state of the failure itself is stored
146/// within `CallThreadState::unwind`. Cranelift-compiled code is expected to
147/// test for this failure sentinel and process it accordingly.
148///
149/// See `catch_unwind_and_record_trap` for some more information as well.
150pub trait HostResult {
151    /// The type of the value that's returned to Cranelift-compiled code. Needs
152    /// to be ABI-safe to pass through an `extern "C"` return value.
153    type Abi: Copy;
154
155    /// Executes `f` and returns the ABI/unwind information as a result.
156    ///
157    /// This may optionally catch unwinds during execution depending on this
158    /// implementation. The ABI return value is unconditionally provided. If an
159    /// unwind was detected (e.g. a host panic or a wasm trap) then that's
160    /// additionally returned as well.
161    ///
162    /// If an unwind is returned then it's expected that when the host returns
163    /// back to wasm (which should be soon after calling this through
164    /// `catch_unwind_and_record_trap`) then wasm will very quickly turn around
165    /// and initiate an unwind (currently through `raise_preexisting_trap`).
166    fn maybe_catch_unwind(
167        store: &mut dyn VMStore,
168        f: impl FnOnce(&mut dyn VMStore) -> Self,
169    ) -> (Self::Abi, Option<UnwindReason>);
170}
171
172// Base case implementations that do not catch unwinds. These are for libcalls
173// that neither trap nor execute user code. The raw value is the ABI itself.
174//
175// Panics in these libcalls will result in a process abort as unwinding is not
176// allowed via Rust through `extern "C"` function boundaries.
177macro_rules! host_result_no_catch {
178    ($($t:ty,)*) => {
179        $(
180            impl HostResult for $t {
181                type Abi = $t;
182                #[allow(unreachable_code, reason = "some types uninhabited on some platforms")]
183                fn maybe_catch_unwind(
184                    store: &mut dyn VMStore,
185                    f: impl FnOnce(&mut dyn VMStore) -> $t,
186                ) -> ($t, Option<UnwindReason>) {
187                    (f(store), None)
188                }
189            }
190        )*
191    }
192}
193
194host_result_no_catch! {
195    (),
196    bool,
197    u32,
198    *mut u8,
199    u64,
200    f32,
201    f64,
202    usize,
203    i8x16,
204    f32x4,
205    f64x2,
206}
207
208impl HostResult for NonNull<u8> {
209    type Abi = *mut u8;
210    fn maybe_catch_unwind(
211        store: &mut dyn VMStore,
212        f: impl FnOnce(&mut dyn VMStore) -> Self,
213    ) -> (*mut u8, Option<UnwindReason>) {
214        (f(store).as_ptr(), None)
215    }
216}
217
218/// Implementation of `HostResult` for `Result<T, E>`.
219///
220/// This is where things get interesting for `HostResult`. This is generically
221/// defined to allow many shapes of the `Result` type to be returned from host
222/// calls or libcalls. To do this an extra trait requirement is placed on the
223/// successful result `T`: `HostResultHasUnwindSentinel`.
224///
225/// The general requirement is that `T` says what ABI it has, and the ABI must
226/// have a sentinel value which indicates that an unwind in wasm should happen.
227/// For example if `T = ()` then `true` means that the call succeeded and
228/// `false` means that an unwind happened. Here the sentinel is `false` and the
229/// ABI is `bool`.
230///
231/// This is the only implementation of `HostResult` which actually catches
232/// unwinds as there's a sentinel to encode.
233impl<T, E> HostResult for Result<T, E>
234where
235    T: HostResultHasUnwindSentinel,
236    E: Into<TrapReason>,
237{
238    type Abi = T::Abi;
239
240    fn maybe_catch_unwind(
241        store: &mut dyn VMStore,
242        f: impl FnOnce(&mut dyn VMStore) -> Result<T, E>,
243    ) -> (T::Abi, Option<UnwindReason>) {
244        // First prepare the closure `f` as something that'll be invoked to
245        // generate the return value of this function. This is the
246        // conditionally, below, passed to `catch_unwind`.
247        let f = move || match f(store) {
248            Ok(ret) => {
249                let abi = ret.into_abi();
250                debug_assert!(abi != T::SENTINEL);
251                (abi, None)
252            }
253            Err(reason) => (T::SENTINEL, Some(UnwindReason::from(reason))),
254        };
255
256        // With `panic=unwind` use `std::panic::catch_unwind` to catch possible
257        // panics to rethrow.
258        #[cfg(all(feature = "std", panic = "unwind"))]
259        {
260            match std::panic::catch_unwind(std::panic::AssertUnwindSafe(f)) {
261                Ok(result) => result,
262                Err(err) => (T::SENTINEL, Some(UnwindReason::Panic(err))),
263            }
264        }
265
266        // With `panic=abort` there's no use in using `std::panic::catch_unwind`
267        // since it won't actually catch anything. Note that
268        // `std::panic::catch_unwind` will technically optimize to this but having
269        // this branch avoids using the `std::panic` module entirely.
270        #[cfg(not(all(feature = "std", panic = "unwind")))]
271        {
272            f()
273        }
274    }
275}
276
277/// Trait used in conjunction with `HostResult for Result<T, E>` where this is
278/// the trait bound on `T`.
279///
280/// This is for values in the "ok" position of a `Result` return value. Each
281/// value can have a separate ABI from itself (e.g. `type Abi`) and must be
282/// convertible to the ABI. Additionally all implementations of this trait have
283/// a "sentinel value" which indicates that an unwind happened. This means that
284/// no valid instance of `Self` should generate the `SENTINEL` via the
285/// `into_abi` function.
286pub unsafe trait HostResultHasUnwindSentinel {
287    /// The Cranelift-understood ABI of this value (should not be `Self`).
288    type Abi: Copy + PartialEq;
289
290    /// A value that indicates that an unwind should happen and is tested for in
291    /// Cranelift-generated code.
292    const SENTINEL: Self::Abi;
293
294    /// Converts this value into the ABI representation. Should never returned
295    /// the `SENTINEL` value.
296    fn into_abi(self) -> Self::Abi;
297}
298
299/// No return value from the host is represented as a `bool` in the ABI. Here
300/// `true` means that execution succeeded while `false` is the sentinel used to
301/// indicate an unwind.
302unsafe impl HostResultHasUnwindSentinel for () {
303    type Abi = bool;
304    const SENTINEL: bool = false;
305    fn into_abi(self) -> bool {
306        true
307    }
308}
309
310unsafe impl HostResultHasUnwindSentinel for NonZeroU32 {
311    type Abi = u32;
312    const SENTINEL: Self::Abi = 0;
313    fn into_abi(self) -> Self::Abi {
314        self.get()
315    }
316}
317
318/// A 32-bit return value can be inflated to a 64-bit return value in the ABI.
319/// In this manner a successful result is a zero-extended 32-bit value and the
320/// failure sentinel is `u64::MAX` or -1 as a signed integer.
321unsafe impl HostResultHasUnwindSentinel for u32 {
322    type Abi = u64;
323    const SENTINEL: u64 = u64::MAX;
324    fn into_abi(self) -> u64 {
325        self.into()
326    }
327}
328
329/// If there is not actual successful result (e.g. an empty enum) then the ABI
330/// can be `()`, or nothing, because there's no successful result and it's
331/// always a failure.
332unsafe impl HostResultHasUnwindSentinel for core::convert::Infallible {
333    type Abi = ();
334    const SENTINEL: () = ();
335    fn into_abi(self) {
336        match self {}
337    }
338}
339
340unsafe impl HostResultHasUnwindSentinel for bool {
341    type Abi = u32;
342    const SENTINEL: Self::Abi = u32::MAX;
343    fn into_abi(self) -> Self::Abi {
344        u32::from(self)
345    }
346}
347
348unsafe impl HostResultHasUnwindSentinel for *mut u8 {
349    type Abi = *mut u8;
350    const SENTINEL: Self::Abi = ptr::without_provenance_mut(usize::MAX);
351    fn into_abi(self) -> Self::Abi {
352        self
353    }
354}
355
356/// A helper structure to schlep from this module to the
357/// `crate::trap::from_runtime_box` function.
358///
359/// This is boxed up on the heap to keep movement around optimized. This is
360/// mutated after creation to fill in `backtrace` in some situations as well.
361#[derive(Debug)]
362pub struct Trap {
363    /// Original reason from where this trap originated.
364    pub reason: TrapReason,
365    /// Wasm backtrace of the trap, if any.
366    pub backtrace: Option<Backtrace>,
367    /// The Wasm Coredump, if any.
368    pub coredumpstack: Option<CoreDumpStack>,
369}
370
371/// Enumeration of different methods of raising a trap (or a sentinel
372/// for an exception).
373#[derive(Debug)]
374pub enum TrapReason {
375    /// A user-defined error has been raised, such as through a host function
376    /// call.
377    ///
378    /// This is constructed naturally through various `From` conversions leading
379    /// into a `TrapReason`. For example host functions returning `Result<()>`
380    /// will have any errors put here.
381    ///
382    /// Note that this variant can also represent an embedder-thrown exception.
383    /// Embedder-thrown exceptions are encoded as `ThrownException.into()` which
384    /// then looks for various handlers on the stack.
385    User(Error),
386
387    /// A trap raised from Cranelift-generated code.
388    Jit {
389        /// The program counter where this trap originated.
390        ///
391        /// This is later used with side tables from compilation to translate
392        /// the trapping address to a trap code.
393        pc: usize,
394
395        /// If the trap was a memory-related trap such as SIGSEGV then this
396        /// field will contain the address of the inaccessible data.
397        ///
398        /// Note that wasm loads/stores are not guaranteed to fill in this
399        /// information. Dynamically-bounds-checked memories, for example, will
400        /// not access an invalid address but may instead load from NULL or may
401        /// explicitly jump to a `ud2` instruction. This is only available for
402        /// fault-based traps which are one of the main ways, but not the only
403        /// way, to run wasm.
404        faulting_addr: Option<usize>,
405
406        /// The trap code associated with this trap.
407        trap: wasmtime_environ::CompiledTrap,
408    },
409}
410
411impl<E> From<E> for TrapReason
412where
413    E: Into<Error>,
414{
415    fn from(error: E) -> Self {
416        TrapReason::User(error.into())
417    }
418}
419
420/// Catches any wasm traps that happen within the execution of `closure`,
421/// returning them as a `Result`.
422pub fn catch_traps<T, F>(
423    store: &mut StoreContextMut<'_, T>,
424    old_state: &mut EntryStoreContext,
425    mut closure: F,
426) -> Result<()>
427where
428    F: FnMut(NonNull<VMContext>, Option<InterpreterRef<'_>>) -> bool,
429{
430    let caller = store.0.default_caller();
431
432    let result = CallThreadState::new(store.0, old_state).with(|_cx| match store.0.executor() {
433        ExecutorRef::Interpreter(r) => closure(caller, Some(r)),
434        #[cfg(has_host_compiler_backend)]
435        ExecutorRef::Native => closure(caller, None),
436    });
437
438    match result {
439        Ok(x) => Ok(x),
440        Err(UnwindReason::Trap(reason)) => Err(crate::trap::from_runtime_box(store.0, reason?)),
441        #[cfg(all(feature = "std", panic = "unwind"))]
442        Err(UnwindReason::Panic(panic)) => std::panic::resume_unwind(panic),
443    }
444}
445
446// Module to hide visibility of the `CallThreadState::prev` field and force
447// usage of its accessor methods.
448mod call_thread_state {
449    use super::*;
450    use crate::EntryStoreContext;
451    use crate::runtime::vm::{Unwind, VMStackChain};
452
453    /// Temporary state stored on the stack which is registered in the `tls`
454    /// module below for calls into wasm.
455    ///
456    /// This structure is stored on the stack and allocated during the
457    /// `catch_traps` function above. The purpose of this structure is to track
458    /// the state of an "activation" or a sequence of 0-or-more contiguous
459    /// WebAssembly call frames. A `CallThreadState` always lives on the stack
460    /// and additionally maintains pointers to previous states to form a linked
461    /// list of activations.
462    ///
463    /// One of the primary goals of `CallThreadState` is to store the state of
464    /// various fields in `VMStoreContext` when it was created. This is done
465    /// because calling WebAssembly will clobber these fields otherwise.
466    ///
467    /// Another major purpose of `CallThreadState` is to assist with unwinding
468    /// and track state necessary when an unwind happens for the original
469    /// creator of `CallThreadState` to determine why the unwind happened.
470    ///
471    /// Note that this structure is pointed-to from TLS, hence liberal usage of
472    /// interior mutability here since that only gives access to
473    /// `&CallThreadState`.
474    pub struct CallThreadState {
475        /// Unwind state set when initiating an unwind and read when
476        /// the control transfer occurs (after the `raise` point is
477        /// reached for host-code destinations and right when
478        /// performing the jump for Wasm-code destinations).
479        pub(super) unwind: Cell<Option<UnwindReason>>,
480        #[cfg(all(has_native_signals))]
481        pub(super) signal_handler: Option<*const SignalHandler>,
482        pub(super) capture_backtrace: bool,
483        #[cfg(feature = "coredump")]
484        pub(super) capture_coredump: bool,
485
486        pub(crate) vm_store_context: Cell<NonNull<VMStoreContext>>,
487        pub(crate) unwinder: &'static dyn Unwind,
488
489        pub(super) prev: Cell<tls::Ptr>,
490
491        // The state of the runtime for the *previous* `CallThreadState` for
492        // this same store. Our *current* state is saved in `self.vm_store_context`,
493        // etc. We need access to the old values of these
494        // fields because the `VMStoreContext` typically doesn't change across
495        // nested calls into Wasm (i.e. they are typically calls back into the
496        // same store and `self.vm_store_context == self.prev.vm_store_context`) and we must to
497        // maintain the list of contiguous-Wasm-frames stack regions for
498        // backtracing purposes.
499        old_state: *mut EntryStoreContext,
500    }
501
502    impl Drop for CallThreadState {
503        fn drop(&mut self) {
504            // Unwind information should not be present as it should have
505            // already been processed.
506            debug_assert!(self.unwind.replace(None).is_none());
507        }
508    }
509
510    impl CallThreadState {
511        #[inline]
512        pub(super) fn new(
513            store: &mut StoreOpaque,
514            old_state: *mut EntryStoreContext,
515        ) -> CallThreadState {
516            CallThreadState {
517                unwind: Cell::new(None),
518                unwinder: store.unwinder(),
519                #[cfg(all(has_native_signals))]
520                signal_handler: store.signal_handler(),
521                capture_backtrace: store.engine().config().wasm_backtrace_max_frames.is_some(),
522                #[cfg(feature = "coredump")]
523                capture_coredump: store.engine().config().coredump_on_trap,
524                vm_store_context: Cell::new(store.vm_store_context_ptr()),
525                prev: Cell::new(ptr::null()),
526                old_state,
527            }
528        }
529
530        /// Get the saved FP upon exit from Wasm for the previous `CallThreadState`.
531        ///
532        /// # Safety
533        ///
534        /// Requires that the saved last Wasm trampoline FP points to
535        /// a valid trampoline frame, or is null.
536        pub unsafe fn old_last_wasm_exit_fp(&self) -> usize {
537            let trampoline_fp = unsafe { (&*self.old_state).last_wasm_exit_trampoline_fp };
538            // SAFETY: `trampoline_fp` is either a valid FP from an
539            // active trampoline frame or is null.
540            unsafe { VMStoreContext::wasm_exit_fp_from_trampoline_fp(trampoline_fp) }
541        }
542
543        /// Get the saved PC upon exit from Wasm for the previous `CallThreadState`.
544        pub unsafe fn old_last_wasm_exit_pc(&self) -> usize {
545            unsafe { (&*self.old_state).last_wasm_exit_pc }
546        }
547
548        /// Get the saved FP upon entry into Wasm for the previous `CallThreadState`.
549        pub unsafe fn old_last_wasm_entry_fp(&self) -> usize {
550            unsafe { (&*self.old_state).last_wasm_entry_fp }
551        }
552
553        /// Get the saved `VMStackChain` for the previous `CallThreadState`.
554        pub unsafe fn old_stack_chain(&self) -> VMStackChain {
555            unsafe { (&*self.old_state).stack_chain.clone() }
556        }
557
558        /// Get the previous `CallThreadState`.
559        pub fn prev(&self) -> tls::Ptr {
560            self.prev.get()
561        }
562
563        /// Pushes this `CallThreadState` activation on to the linked list
564        /// stored in TLS.
565        ///
566        /// This method will take the current head of the linked list, stored in
567        /// our TLS pointer, and move it into `prev`. The TLS pointer is then
568        /// updated to `self`.
569        ///
570        /// # Panics
571        ///
572        /// Panics if this activation is already in a linked list (e.g.
573        /// `self.prev` is set).
574        #[inline]
575        pub(crate) unsafe fn push(&self) {
576            assert!(self.prev.get().is_null());
577            self.prev.set(tls::raw::replace(self));
578        }
579
580        /// Pops this `CallThreadState` from the linked list stored in TLS.
581        ///
582        /// This method will restore `self.prev` into the head of the linked
583        /// list stored in TLS and will additionally null-out `self.prev`.
584        ///
585        /// # Panics
586        ///
587        /// Panics if this activation isn't the head of the list.
588        #[inline]
589        pub(crate) unsafe fn pop(&self) {
590            let prev = self.prev.replace(ptr::null());
591            let head = tls::raw::replace(prev);
592            assert!(core::ptr::eq(head, self));
593        }
594
595        /// Swaps the state in this `CallThreadState`'s `VMStoreContext` with
596        /// the state in `EntryStoreContext` that was saved when this
597        /// activation was created.
598        ///
599        /// This method is using during suspension of a fiber to restore the
600        /// store back to what it originally was and prepare it to be resumed
601        /// later on. This takes various fields of `VMStoreContext` and swaps
602        /// them with what was saved in `EntryStoreContext`. That restores
603        /// a store to just before this activation was called but saves off the
604        /// fields of this activation to get restored/resumed at a later time.
605        #[cfg(feature = "async")]
606        pub(super) unsafe fn swap(&self) {
607            unsafe fn swap<T>(a: &core::cell::UnsafeCell<T>, b: &mut T) {
608                unsafe { core::mem::swap(&mut *a.get(), b) }
609            }
610
611            unsafe {
612                let cx = self.vm_store_context.get().as_ref();
613                swap(
614                    &cx.last_wasm_exit_trampoline_fp,
615                    &mut (*self.old_state).last_wasm_exit_trampoline_fp,
616                );
617                swap(
618                    &cx.last_wasm_exit_pc,
619                    &mut (*self.old_state).last_wasm_exit_pc,
620                );
621                swap(
622                    &cx.last_wasm_entry_fp,
623                    &mut (*self.old_state).last_wasm_entry_fp,
624                );
625                swap(
626                    &cx.last_wasm_entry_sp,
627                    &mut (*self.old_state).last_wasm_entry_sp,
628                );
629                swap(
630                    &cx.last_wasm_entry_trap_handler,
631                    &mut (*self.old_state).last_wasm_entry_trap_handler,
632                );
633                swap(&cx.stack_chain, &mut (*self.old_state).stack_chain);
634            }
635        }
636    }
637}
638pub use call_thread_state::*;
639
640#[cfg(feature = "gc")]
641use super::compute_handler;
642
643/// The reasons why Wasmtime might unwind, stored within `CallThreadState`.
644pub enum UnwindReason {
645    /// The host panicked.
646    ///
647    /// In this situation Wasmtime must transfer the panic payload across Wasm
648    /// code since the native unwinder isn't guaranteed to be able to unwind
649    /// wasm. Once wasm is unwound, however, the panic is re-thrown on the
650    /// other side to propagate like usual.
651    #[cfg(all(feature = "std", panic = "unwind"))]
652    Panic(Box<dyn std::any::Any + Send>),
653
654    /// Wasm or the host raised a trap for some reason.
655    ///
656    /// This is specifically stored as a `Result` to carry the `OutOfMemory`
657    /// error from when this is allocated to the catch-site of the error.
658    /// Otherwise keeping this in a `Box` means that moving this value in and
659    /// out of `CallThreadState` is optimized. Specifically the "hot function"
660    /// doesn't need a slow path which is much larger with lots of memcpy's and
661    /// such.
662    Trap(Result<Box<Trap>, OutOfMemory>),
663}
664
665impl<E> From<E> for UnwindReason
666where
667    E: Into<TrapReason>,
668{
669    fn from(value: E) -> UnwindReason {
670        UnwindReason::Trap(try_new::<Box<_>>(Trap {
671            reason: value.into(),
672            backtrace: None,
673            coredumpstack: None,
674        }))
675    }
676}
677
678impl CallThreadState {
679    #[inline]
680    fn with(mut self, closure: impl FnOnce(&CallThreadState) -> bool) -> Result<(), UnwindReason> {
681        let succeeded = tls::set(&mut self, |me| closure(me));
682        if succeeded {
683            Ok(())
684        } else {
685            Err(self.read_unwind())
686        }
687    }
688
689    #[cold]
690    fn read_unwind(&self) -> UnwindReason {
691        self.unwind.replace(None).unwrap()
692    }
693
694    /// Records the unwind information provided within this `CallThreadState`.
695    ///
696    /// This function is used to stash metadata for why an unwind is about to
697    /// happen. The actual unwind is expected to happen after this function is
698    /// called using the `unwind` function below. This function is expected to
699    /// be called from the host or a signal handler the moment a trap happens.
700    /// Signal handlers then immediately unwind to the entry state, and host
701    /// functions will return back to the entry trampoline which will
702    /// immediately turn around and call the `unwind` function below.
703    ///
704    /// Note that this is a relatively low-level function and will panic if
705    /// misused.
706    ///
707    /// # Panics
708    ///
709    /// Panics if unwind information has already been recorded as that should
710    /// have been processed first.
711    fn record_unwind(&self, reason: UnwindReason) {
712        if cfg!(debug_assertions) {
713            let prev = self.unwind.replace(None);
714            assert!(prev.is_none());
715        }
716
717        self.unwind.set(Some(reason));
718    }
719
720    /// Helper function to perform an actual unwinding operation.
721    ///
722    /// This must be preceded by a `record_unwind` operation above to be
723    /// processed correctly on the other side.
724    ///
725    /// This is not used for signals-based-traps. When a signal is caught the
726    /// thread's register state is updated to the entrypoint handler. This is
727    /// only used for host-initiated traps. Note that this includes the host
728    /// implementation of throwing a wasm exception.
729    ///
730    /// Note that this function is expected to be called with the wasm backtrace
731    /// in such a state that it represents the unwinding condition.
732    /// Effectively, if a wasm backtrace is captured here, it reflects why the
733    /// unwind happened.
734    ///
735    /// # Unsafety
736    ///
737    /// This function is not safe if a corresponding handler wasn't already
738    /// setup in the entry trampoline. Additionally this isn't safe as it may
739    /// skip all Rust destructors on the stack, if there are any, for native
740    /// executors as `Handler::resume` will be used.
741    unsafe fn unwind(&self, store: &mut dyn VMStore) {
742        #[allow(unused_mut, reason = "only  mutated in `debug` configuration")]
743        let mut unwind = self.unwind.replace(None);
744
745        // If configured, fire a debug event for the cause of unwinding here.
746        //
747        // Note that by firing a debug event the trap being handled can be
748        // subtly different. For example in the event of a thrown exception the
749        // debug handler might take the exception from the store and put
750        // another one there, changing the type of the exception being thrown.
751        // This notably means that the calculation for what to do about `unwind`
752        // happens after this block, down below.
753        //
754        // Also note that this can execute arbitrary WebAssembly code within
755        // this block due to the store's debug handler. That means that we
756        // might be paused here for quite some time.
757        #[cfg(feature = "debug")]
758        if let Some(UnwindReason::Trap(Ok(trap))) = &unwind {
759            #[cfg(feature = "gc")]
760            use wasmtime_core::alloc::PanicOnOom;
761
762            let result = match &trap.reason {
763                TrapReason::User(err) => {
764                    let mut event = crate::DebugEvent::HostcallError(err);
765                    if let Some(trap) = err.downcast_ref() {
766                        event = crate::DebugEvent::Trap(*trap);
767                    }
768
769                    if let Some(trap) = err.downcast_ref() {
770                        event = crate::DebugEvent::Trap(*trap);
771                    }
772
773                    // For `ThrownException` errors that indicates that we should
774                    // look at the store to see if there's a pending exception
775                    // there, and if so then that's a different debug event than the
776                    // `HostcallError`.
777                    //
778                    // TODO(#12069): handle allocation failure here
779                    #[cfg(feature = "gc")]
780                    if err.is::<ThrownException>()
781                        && let Some(exn) = store.pending_exception_owned_rooted().panic_on_oom()
782                    {
783                        event = crate::DebugEvent::Exception(exn.clone());
784                    }
785
786                    store.block_on_debug_handler(event)
787                }
788
789                TrapReason::Jit { .. } => {
790                    // Not handled here. JIT traps only show up via signal
791                    // handlers, and the debugger isn't invoked from signal
792                    // handlers at this time.
793                    Ok(())
794                }
795            };
796
797            // If the debugger invocation itself resulted in an `Err`
798            // (which can only come from the `block_on` hitting a
799            // failure mode), we need to override our unwind as-if
800            // were handling a host error.
801            if let Err(err) = result {
802                unwind = Some(UnwindReason::from(err));
803            }
804        }
805
806        let handler;
807        let payload1;
808        let payload2;
809
810        // Determine, from `unwind`,  the `handler` and payloads that will be
811        // used to resume execution to. Note that the entry trampoline into wasm
812        // setup an entrypoint handler meaning we're guaranteed *something* to
813        // unwind to. In the case of a wasm exception, however, we may want to
814        // unwind to a different landing pad on the stack which is in-wasm.
815        'done: {
816            if let Some(UnwindReason::Trap(Ok(trap))) = &mut unwind {
817                let mut has_backtrace = trap.backtrace.is_some();
818
819                if let TrapReason::User(err) = &trap.reason {
820                    // If this trap indicates an exception is being thrown, aka
821                    // `ThrownException`, and there's a stored exception within the
822                    // store to lookup tag information for, then do so here. If
823                    // there's a wasm handler for this exception on the stack then
824                    // that's the handler to resume to.
825                    //
826                    // Note that `unwind` is intentionally dropped on the floor
827                    // here. We're resuming back into wasm with a normal state
828                    // meaning we're no longer in an exceptional state. By doing
829                    // this the internal `self.unwind` state reflects `None`.
830                    //
831                    // SAFETY: we are invoking `compute_handler()` while Wasm is
832                    // on the stack and we have re-entered via a trampoline, as
833                    // required by its stack-walking logic.
834                    #[cfg(feature = "gc")]
835                    if err.is::<ThrownException>()
836                        && let Some((instance, tag)) = store.pending_exception_tag_and_instance()
837                        && let Some(catch) = unsafe { compute_handler(store, instance, tag) }
838                    {
839                        handler = catch;
840                        // Take the pending exception at this time and use it as
841                        // payload.
842                        payload1 = usize::try_from(
843                            store.expose_pending_exception_to_wasm().unwrap().get(),
844                        )
845                        .expect("GC ref does not fit in usize");
846                        payload2 = 0;
847                        drop(unwind);
848                        break 'done;
849                    }
850
851                    has_backtrace = has_backtrace || err.is::<WasmBacktrace>();
852                }
853
854                // If doesn't yet already have a backtrace, and one's not been
855                // captured yet, then assign one now.
856                if !has_backtrace {
857                    trap.backtrace = self.capture_backtrace(store.vm_store_context_mut(), None);
858                    trap.coredumpstack = self.capture_coredump(store.vm_store_context_mut(), None);
859                }
860            }
861
862            // If this wasn't a wasm-caught exception, then catch the exception
863            // within the original entrypoint into wasm. Note that in this
864            // situation the `unwind` value is replaced within `self` to ensure
865            // that it's picked up on the other side of the trampoline catching
866            // this error.
867            handler = entry_trap_handler(store.vm_store_context());
868            payload1 = 0;
869            payload2 = 0;
870            self.unwind.set(unwind);
871            break 'done; // be sure `'done` is considered used
872        }
873
874        unsafe {
875            self.resume_to_exception_handler(store.executor(), &handler, payload1, payload2);
876        }
877    }
878
879    pub(crate) fn entry_trap_handler(&self) -> Handler {
880        unsafe { entry_trap_handler(self.vm_store_context.get().as_ref()) }
881    }
882
883    unsafe fn resume_to_exception_handler(
884        &self,
885        executor: ExecutorRef<'_>,
886        handler: &Handler,
887        payload1: usize,
888        payload2: usize,
889    ) {
890        unsafe {
891            match executor {
892                ExecutorRef::Interpreter(mut r) => {
893                    r.resume_to_exception_handler(handler, payload1, payload2)
894                }
895                #[cfg(has_host_compiler_backend)]
896                ExecutorRef::Native => handler.resume_tailcc(payload1, payload2),
897            }
898        }
899    }
900
901    fn capture_backtrace(
902        &self,
903        limits: *const VMStoreContext,
904        trap_pc_and_fp: Option<(usize, usize)>,
905    ) -> Option<Backtrace> {
906        if !self.capture_backtrace {
907            return None;
908        }
909
910        Some(unsafe { Backtrace::new_with_trap_state(limits, self.unwinder, self, trap_pc_and_fp) })
911    }
912
913    pub(crate) fn iter<'a>(&'a self) -> impl Iterator<Item = &'a Self> + 'a {
914        let mut state = Some(self);
915        core::iter::from_fn(move || {
916            let this = state?;
917            state = unsafe { this.prev().as_ref() };
918            Some(this)
919        })
920    }
921
922    /// Trap handler using our thread-local state.
923    ///
924    /// * `regs` - some special program registers at the time that the trap
925    ///   happened, for example `pc`.
926    /// * `faulting_addr` - the system-provided address that the a fault, if
927    ///   any, happened at. This is used when debug-asserting that all segfaults
928    ///   are known to live within a `Store<T>` in a valid range.
929    /// * `call_handler` - a closure used to invoke the platform-specific
930    ///   signal handler for each instance, if available.
931    ///
932    /// Attempts to handle the trap if it's a wasm trap. Returns a `TrapTest`
933    /// which indicates what this could be, such as:
934    ///
935    /// * `TrapTest::NotWasm` - not a wasm fault, this should get forwarded to
936    ///   the next platform-specific fault handler.
937    /// * `TrapTest::HandledByEmbedder` - the embedder `call_handler` handled
938    ///   this signal, nothing else to do.
939    /// * `TrapTest::Trap` - this is a wasm trap an the stack needs to be
940    ///   unwound now.
941    pub(crate) fn test_if_trap(
942        &self,
943        regs: TrapRegisters,
944        faulting_addr: Option<usize>,
945        call_handler: impl FnOnce(&SignalHandler) -> bool,
946    ) -> TrapTest {
947        // First up see if any instance registered has a custom trap handler,
948        // in which case run them all. If anything handles the trap then we
949        // return that the trap was handled.
950        let _ = &call_handler;
951        #[cfg(all(has_native_signals, not(miri)))]
952        if let Some(handler) = self.signal_handler {
953            if unsafe { call_handler(&*handler) } {
954                return TrapTest::HandledByEmbedder;
955            }
956        }
957
958        // If this fault wasn't in wasm code, then it's not our problem
959        let Some((code, text_offset)) = lookup_code(regs.pc) else {
960            return TrapTest::NotWasm;
961        };
962
963        // If the fault was at a location that was not marked as potentially
964        // trapping, then that's a bug in Cranelift/Winch/etc. Don't try to
965        // catch the trap and pretend this isn't wasm so the program likely
966        // aborts.
967        let Some(trap) = code.lookup_trap_code(text_offset) else {
968            return TrapTest::NotWasm;
969        };
970
971        // If all that passed then this is indeed a wasm trap, so return the
972        // `Handler` setup in the original wasm frame.
973        self.set_jit_trap(regs, faulting_addr, trap);
974        let entry_handler = self.entry_trap_handler();
975        TrapTest::Trap(entry_handler)
976    }
977
978    pub(crate) fn set_jit_trap(
979        &self,
980        TrapRegisters { pc, fp, .. }: TrapRegisters,
981        faulting_addr: Option<usize>,
982        trap: wasmtime_environ::CompiledTrap,
983    ) {
984        let mut unwind = UnwindReason::from(TrapReason::Jit {
985            pc,
986            faulting_addr,
987            trap,
988        });
989        if let UnwindReason::Trap(Ok(trap)) = &mut unwind {
990            trap.backtrace =
991                self.capture_backtrace(self.vm_store_context.get().as_ptr(), Some((pc, fp)));
992            trap.coredumpstack =
993                self.capture_coredump(self.vm_store_context.get().as_ptr(), Some((pc, fp)));
994        }
995        self.record_unwind(unwind);
996    }
997}
998
999fn entry_trap_handler(vm_store_context: &VMStoreContext) -> Handler {
1000    unsafe {
1001        let fp = *vm_store_context.last_wasm_entry_fp.get();
1002        let sp = *vm_store_context.last_wasm_entry_sp.get();
1003        let pc = *vm_store_context.last_wasm_entry_trap_handler.get();
1004        Handler { pc, sp, fp }
1005    }
1006}
1007
1008/// A private inner module managing the state of Wasmtime's thread-local storage
1009/// (TLS) state.
1010///
1011/// Wasmtime at this time has a single pointer of TLS. This single pointer of
1012/// TLS is the totality of all TLS required by Wasmtime. By keeping this as
1013/// small as possible it generally makes it easier to integrate with external
1014/// systems and implement features such as fiber context switches. This single
1015/// TLS pointer is declared in platform-specific modules to handle platform
1016/// differences, so this module here uses getters/setters which delegate to
1017/// platform-specific implementations.
1018///
1019/// The single TLS pointer used by Wasmtime is morally
1020/// `Option<&CallThreadState>` meaning that it's a possibly-present pointer to
1021/// some state. This pointer is a pointer to the most recent (youngest)
1022/// `CallThreadState` activation, or the most recent call into WebAssembly.
1023///
1024/// This TLS pointer is additionally the head of a linked list of activations
1025/// that are all stored on the stack for the current thread. Each time
1026/// WebAssembly is recursively invoked by an embedder will push a new entry into
1027/// this linked list. This singly-linked list is maintained with its head in TLS
1028/// node pointers are stored in `CallThreadState::prev`.
1029///
1030/// An example stack might look like this:
1031///
1032/// ```text
1033/// ┌─────────────────────┐◄───── highest, or oldest, stack address
1034/// │ native stack frames │
1035/// │         ...         │
1036/// │  ┌───────────────┐◄─┼──┐
1037/// │  │CallThreadState│  │  │
1038/// │  └───────────────┘  │  p
1039/// ├─────────────────────┤  r
1040/// │  wasm stack frames  │  e
1041/// │         ...         │  v
1042/// ├─────────────────────┤  │
1043/// │ native stack frames │  │
1044/// │         ...         │  │
1045/// │  ┌───────────────┐◄─┼──┼── TLS pointer
1046/// │  │CallThreadState├──┼──┘
1047/// │  └───────────────┘  │
1048/// ├─────────────────────┤
1049/// │  wasm stack frames  │
1050/// │         ...         │
1051/// ├─────────────────────┤
1052/// │ native stack frames │
1053/// │         ...         │
1054/// └─────────────────────┘◄───── smallest, or youngest, stack address
1055/// ```
1056///
1057/// # Fibers and async
1058///
1059/// Wasmtime supports stack-switching with fibers to implement async. This means
1060/// that Wasmtime will temporarily execute code on a separate stack and then
1061/// suspend from this stack back to the embedder for async operations. Doing
1062/// this safely requires manual management of the TLS pointer updated by
1063/// Wasmtime.
1064///
1065/// For example when a fiber is suspended that means that the TLS pointer needs
1066/// to be restored to whatever it was when the fiber was resumed. Additionally
1067/// this may need to pop multiple `CallThreadState` activations, one for each
1068/// one located on the fiber stack itself.
1069///
1070/// The `AsyncWasmCallState` and `PreviousAsyncWasmCallState` structures in this
1071/// module are used to manage this state, namely:
1072///
1073/// * The `AsyncWasmCallState` structure represents the state of a suspended
1074///   fiber. This is a linked list, in reverse order, from oldest activation on
1075///   the fiber to youngest activation on the fiber.
1076///
1077/// * The `PreviousAsyncWasmCallState` structure represents a pointer within our
1078///   thread's TLS linked list of activations when a fiber was resumed. This
1079///   pointer is used during fiber suspension to know when to stop popping
1080///   activations from the thread's linked list.
1081///
1082/// Note that this means that the directionality of linked list links is
1083/// opposite when stored in TLS vs when stored for a suspended fiber. The
1084/// thread's current list pointed to by TLS is youngest-to-oldest links, while a
1085/// suspended fiber stores oldest-to-youngest links.
1086pub(crate) mod tls {
1087    use super::CallThreadState;
1088
1089    pub use raw::Ptr;
1090
1091    // An even *more* inner module for dealing with TLS. This actually has the
1092    // thread local variable and has functions to access the variable.
1093    //
1094    // Note that this is specially done to fully encapsulate that the accessors
1095    // for tls may or may not be inlined. Wasmtime's async support employs stack
1096    // switching which can resume execution on different OS threads. This means
1097    // that borrows of our TLS pointer must never live across accesses because
1098    // otherwise the access may be split across two threads and cause unsafety.
1099    //
1100    // This also means that extra care is taken by the runtime to save/restore
1101    // these TLS values when the runtime may have crossed threads.
1102    //
1103    // Note, though, that if async support is disabled at compile time then
1104    // these functions are free to be inlined.
1105    pub(super) mod raw {
1106        use super::CallThreadState;
1107
1108        pub type Ptr = *const CallThreadState;
1109
1110        const _: () = {
1111            assert!(core::mem::align_of::<CallThreadState>() > 1);
1112        };
1113
1114        fn tls_get() -> (Ptr, bool) {
1115            let mut initialized = false;
1116            let p = crate::runtime::vm::sys::tls_get().map_addr(|a| {
1117                initialized = (a & 1) != 0;
1118                a & !1
1119            });
1120            (p.cast(), initialized)
1121        }
1122
1123        fn tls_set(ptr: Ptr, initialized: bool) {
1124            let encoded = ptr.map_addr(|a| a | usize::from(initialized));
1125            crate::runtime::vm::sys::tls_set(encoded.cast_mut().cast::<u8>());
1126        }
1127
1128        #[cfg_attr(feature = "async", inline(never))] // see module docs
1129        #[cfg_attr(not(feature = "async"), inline)]
1130        pub fn replace(val: Ptr) -> Ptr {
1131            // When a new value is configured that means that we may be
1132            // entering WebAssembly so check to see if this thread has
1133            // performed per-thread initialization for traps.
1134            let (prev, initialized) = tls_get();
1135            if !initialized {
1136                super::super::lazy_per_thread_init();
1137            }
1138            tls_set(val, true);
1139            prev
1140        }
1141
1142        /// Eagerly initialize thread-local runtime functionality. This will be performed
1143        /// lazily by the runtime if users do not perform it eagerly.
1144        #[cfg_attr(feature = "async", inline(never))] // see module docs
1145        #[cfg_attr(not(feature = "async"), inline)]
1146        pub fn initialize() {
1147            let (state, initialized) = tls_get();
1148            if initialized {
1149                return;
1150            }
1151            super::super::lazy_per_thread_init();
1152            tls_set(state, true);
1153        }
1154
1155        #[cfg_attr(feature = "async", inline(never))] // see module docs
1156        #[cfg_attr(not(feature = "async"), inline)]
1157        pub fn get() -> Ptr {
1158            tls_get().0
1159        }
1160    }
1161
1162    pub use raw::initialize as tls_eager_initialize;
1163
1164    /// Opaque state used to persist the state of the `CallThreadState`
1165    /// activations associated with a fiber stack that's used as part of an
1166    /// async wasm call.
1167    #[cfg(feature = "async")]
1168    pub struct AsyncWasmCallState {
1169        // The head of a linked list of activations that are currently present
1170        // on an async call's fiber stack. This pointer points to the oldest
1171        // activation frame where the `prev` links internally link to younger
1172        // activation frames.
1173        //
1174        // When pushed onto a thread this linked list is traversed to get pushed
1175        // onto the current thread at the time.
1176        //
1177        // If this pointer is null then that means that the fiber this state is
1178        // associated with has no activations.
1179        state: raw::Ptr,
1180    }
1181
1182    // SAFETY: This is a relatively unsafe unsafe block and not really all that
1183    // well audited. The general idea is that the linked list of activations
1184    // owned by `self.state` are safe to send to other threads, but that relies
1185    // on everything internally being safe as well as stack variables and such.
1186    // This is more-or-less tied to the very large comment in `fiber.rs` about
1187    // `unsafe impl Send` there.
1188    #[cfg(feature = "async")]
1189    unsafe impl Send for AsyncWasmCallState {}
1190
1191    #[cfg(feature = "async")]
1192    impl AsyncWasmCallState {
1193        /// Creates new state that initially starts as null.
1194        pub fn new() -> AsyncWasmCallState {
1195            AsyncWasmCallState {
1196                state: core::ptr::null_mut(),
1197            }
1198        }
1199
1200        /// Pushes the saved state of this wasm's call onto the current thread's
1201        /// state.
1202        ///
1203        /// This will iterate over the linked list of states stored within
1204        /// `self` and push them sequentially onto the current thread's
1205        /// activation list.
1206        ///
1207        /// The returned `PreviousAsyncWasmCallState` captures the state of this
1208        /// thread just before this operation, and it must have its `restore`
1209        /// method called to restore the state when the async wasm is suspended
1210        /// from.
1211        ///
1212        /// # Unsafety
1213        ///
1214        /// Must be carefully coordinated with
1215        /// `PreviousAsyncWasmCallState::restore` and fiber switches to ensure
1216        /// that this doesn't push stale data and the data is popped
1217        /// appropriately.
1218        pub unsafe fn push(self) -> PreviousAsyncWasmCallState {
1219            // First save the state of TLS as-is so when this state is popped
1220            // off later on we know where to stop.
1221            let ret = PreviousAsyncWasmCallState { state: raw::get() };
1222
1223            // The oldest activation, if present, has various `VMStoreContext`
1224            // fields saved within it. These fields were the state for the
1225            // *youngest* activation when a suspension previously happened. By
1226            // swapping them back into the store this is an O(1) way of
1227            // restoring the state of a store's metadata fields at the time of
1228            // the suspension.
1229            //
1230            // The store's previous values before this function will all get
1231            // saved in the oldest activation's state on the stack. The store's
1232            // current state then describes the youngest activation which is
1233            // restored via the loop below.
1234            unsafe {
1235                if let Some(state) = self.state.as_ref() {
1236                    state.swap();
1237                }
1238            }
1239
1240            // Our `state` pointer is a linked list of oldest-to-youngest so by
1241            // pushing in order of the list we restore the youngest-to-oldest
1242            // list as stored in the state of this current thread.
1243            let mut ptr = self.state;
1244            unsafe {
1245                while let Some(state) = ptr.as_ref() {
1246                    ptr = state.prev.replace(core::ptr::null_mut());
1247                    state.push();
1248                }
1249            }
1250            ret
1251        }
1252
1253        /// Performs a runtime check that this state is indeed null.
1254        pub fn assert_null(&self) {
1255            assert!(self.state.is_null());
1256        }
1257
1258        /// Asserts that the current CallThreadState pointer, if present, is not
1259        /// in the `range` specified.
1260        ///
1261        /// This is used when exiting a future in Wasmtime to assert that the
1262        /// current CallThreadState pointer does not point within the stack
1263        /// we're leaving (e.g. allocated for a fiber).
1264        pub fn assert_current_state_not_in_range(range: core::ops::Range<usize>) {
1265            let p = raw::get() as usize;
1266            assert!(!range.contains(&p));
1267        }
1268    }
1269
1270    /// Opaque state used to help control TLS state across stack switches for
1271    /// async support.
1272    ///
1273    /// This structure is returned from [`AsyncWasmCallState::push`] and
1274    /// represents the state of this thread's TLS variable prior to the push
1275    /// operation.
1276    #[cfg(feature = "async")]
1277    pub struct PreviousAsyncWasmCallState {
1278        // The raw value of this thread's TLS pointer when this structure was
1279        // created. This is not dereferenced or inspected but is used to halt
1280        // linked list traversal in [`PreviousAsyncWasmCallState::restore`].
1281        state: raw::Ptr,
1282    }
1283
1284    #[cfg(feature = "async")]
1285    impl PreviousAsyncWasmCallState {
1286        /// Pops a fiber's linked list of activations and stores them in
1287        /// `AsyncWasmCallState`.
1288        ///
1289        /// This will pop the top activation of this current thread continuously
1290        /// until it reaches whatever the current activation was when
1291        /// [`AsyncWasmCallState::push`] was originally called.
1292        ///
1293        /// # Unsafety
1294        ///
1295        /// Must be paired with a `push` and only performed at a time when a
1296        /// fiber is being suspended.
1297        pub unsafe fn restore(self) -> AsyncWasmCallState {
1298            let thread_head = self.state;
1299            core::mem::forget(self);
1300            let mut ret = AsyncWasmCallState::new();
1301            loop {
1302                // If the current TLS state is as we originally found it, then
1303                // this loop is finished.
1304                //
1305                // Note, though, that before exiting, if the oldest
1306                // `CallThreadState` is present, the current state of
1307                // `VMStoreContext` is saved off within it. This will save the
1308                // current state, before this function, of `VMStoreContext`
1309                // into the `EntryStoreContext` stored with the oldest
1310                // activation. This is a bit counter-intuitive where the state
1311                // for the youngest activation is stored in the "old" state
1312                // of the oldest activation.
1313                //
1314                // What this does is restores the state of the store to just
1315                // before this async fiber was started. The fiber's state will
1316                // be entirely self-contained in the fiber itself and the
1317                // returned `AsyncWasmCallState`. Resumption above in
1318                // `AsyncWasmCallState::push` will perform the swap back into
1319                // the store to hook things up again.
1320                let ptr = raw::get();
1321                if ptr == thread_head {
1322                    unsafe {
1323                        if let Some(state) = ret.state.as_ref() {
1324                            state.swap();
1325                        }
1326                    }
1327
1328                    break ret;
1329                }
1330
1331                // Pop this activation from the current thread's TLS state, and
1332                // then afterwards push it onto our own linked list within this
1333                // `AsyncWasmCallState`. Note that the linked list in
1334                // `AsyncWasmCallState` is stored in reverse order so a
1335                // subsequent `push` later on pushes everything in the right
1336                // order.
1337                unsafe {
1338                    (*ptr).pop();
1339                    if let Some(state) = ret.state.as_ref() {
1340                        (*ptr).prev.set(state);
1341                    }
1342                }
1343                ret.state = ptr;
1344            }
1345        }
1346    }
1347
1348    #[cfg(feature = "async")]
1349    impl Drop for PreviousAsyncWasmCallState {
1350        fn drop(&mut self) {
1351            panic!("must be consumed with `restore`");
1352        }
1353    }
1354
1355    /// Configures thread local state such that for the duration of the
1356    /// execution of `closure` any call to `with` will yield `state`, unless
1357    /// this is recursively called again.
1358    #[inline]
1359    pub fn set<R>(state: &mut CallThreadState, closure: impl FnOnce(&CallThreadState) -> R) -> R {
1360        struct Reset<'a> {
1361            state: &'a CallThreadState,
1362        }
1363
1364        impl Drop for Reset<'_> {
1365            #[inline]
1366            fn drop(&mut self) {
1367                unsafe {
1368                    self.state.pop();
1369                }
1370            }
1371        }
1372
1373        unsafe {
1374            state.push();
1375            let reset = Reset { state };
1376            closure(reset.state)
1377        }
1378    }
1379
1380    /// Returns the last pointer configured with `set` above, if any.
1381    pub fn with<R>(closure: impl FnOnce(Option<&CallThreadState>) -> R) -> R {
1382        let p = raw::get();
1383        unsafe { closure(if p.is_null() { None } else { Some(&*p) }) }
1384    }
1385}