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