@@ -425,8 +425,27 @@ mod call_thread_state {
425
425
use super :: * ;
426
426
use crate :: runtime:: vm:: Unwind ;
427
427
428
- /// Temporary state stored on the stack which is registered in the `tls` module
429
- /// below for calls into wasm.
428
+ /// Temporary state stored on the stack which is registered in the `tls`
429
+ /// module below for calls into wasm.
430
+ ///
431
+ /// This structure is stored on the stack and allocated during the
432
+ /// `catch_traps` function above. The purpose of this structure is to track
433
+ /// the state of an "activation" or a sequence of 0-or-more contiguous
434
+ /// WebAssembly call frames. A `CallThreadState` always lives on the stack
435
+ /// and additionally maintains pointers to previous states to form a linked
436
+ /// list of activations.
437
+ ///
438
+ /// One of the primary goals of `CallThreadState` is to store the state of
439
+ /// various fields in `VMStoreContext` when it was created. This is done
440
+ /// because calling WebAssembly will clobber these fields otherwise.
441
+ ///
442
+ /// Another major purpose of `CallThreadState` is to assist with unwinding
443
+ /// and track state necessary when an unwind happens for the original
444
+ /// creator of `CallThreadState` to determine why the unwind happened.
445
+ ///
446
+ /// Note that this structure is pointed-to from TLS, hence liberal usage of
447
+ /// interior mutability here since that only gives access to
448
+ /// `&CallThreadState`.
430
449
pub struct CallThreadState {
431
450
pub ( super ) unwind : Cell < Option < ( UnwindReason , Option < Backtrace > , Option < CoreDumpStack > ) > > ,
432
451
pub ( super ) jmp_buf : Cell < * const u8 > ,
@@ -525,12 +544,31 @@ mod call_thread_state {
525
544
self . prev . get ( )
526
545
}
527
546
547
+ /// Pushes this `CallThreadState` activation on to the linked list
548
+ /// stored in TLS.
549
+ ///
550
+ /// This method will take the current head of the linked list, stored in
551
+ /// our TLS pointer, and move it into `prev`. The TLS pointer is then
552
+ /// updated to `self`.
553
+ ///
554
+ /// # Panics
555
+ ///
556
+ /// Panics if this activation is already in a linked list (e.g.
557
+ /// `self.prev` is set).
528
558
#[ inline]
529
559
pub ( crate ) unsafe fn push ( & self ) {
530
560
assert ! ( self . prev. get( ) . is_null( ) ) ;
531
561
self . prev . set ( tls:: raw:: replace ( self ) ) ;
532
562
}
533
563
564
+ /// Pops this `CallThreadState` from the linked list stored in TLS.
565
+ ///
566
+ /// This method will restore `self.prev` into the head of the linked
567
+ /// list stored in TLS and will additionally null-out `self.prev`.
568
+ ///
569
+ /// # Panics
570
+ ///
571
+ /// Panics if this activation isn't the head of the list.
534
572
#[ inline]
535
573
pub ( crate ) unsafe fn pop ( & self ) {
536
574
let prev = self . prev . replace ( ptr:: null ( ) ) ;
@@ -734,11 +772,84 @@ impl CallThreadState {
734
772
}
735
773
}
736
774
737
- // A private inner module for managing the TLS state that we require across
738
- // calls in wasm. The WebAssembly code is called from C++ and then a trap may
739
- // happen which requires us to read some contextual state to figure out what to
740
- // do with the trap. This `tls` module is used to persist that information from
741
- // the caller to the trap site.
775
+ /// A private inner module managing the state of Wasmtime's thread-local storage
776
+ /// (TLS) state.
777
+ ///
778
+ /// Wasmtime at this time has a single pointer of TLS. This single pointer of
779
+ /// TLS is the totality of all TLS required by Wasmtime. By keeping this as
780
+ /// small as possible it generally makes it easier to integrate with external
781
+ /// systems and implement features such as fiber context switches. This single
782
+ /// TLS pointer is declared in platform-specific modules to handle platform
783
+ /// differences, so this module here uses getters/setters which delegate to
784
+ /// platform-specific implementations.
785
+ ///
786
+ /// The single TLS pointer used by Wasmtime is morally
787
+ /// `Option<&CallThreadState>` meaning that it's a possibly-present pointer to
788
+ /// some state. This pointer is a pointer to the most recent (youngest)
789
+ /// `CallThreadState` activation, or the most recent call into WebAssembly.
790
+ ///
791
+ /// This TLS pointer is additionally the head of a linked list of activations
792
+ /// that are all stored on the stack for the current thread. Each time
793
+ /// WebAssembly is recursively invoked by an embedder will push a new entry into
794
+ /// this linked list. This singly-linked list is maintained with its head in TLS
795
+ /// node pointers are stored in `CallThreadState::prev`.
796
+ ///
797
+ /// An example stack might look like this:
798
+ ///
799
+ /// ```text
800
+ /// ┌─────────────────────┐◄───── highest, or oldest, stack address
801
+ /// │ native stack frames │
802
+ /// │ ... │
803
+ /// │ ┌───────────────┐◄─┼──┐
804
+ /// │ │CallThreadState│ │ │
805
+ /// │ └───────────────┘ │ p
806
+ /// ├─────────────────────┤ r
807
+ /// │ wasm stack frames │ e
808
+ /// │ ... │ v
809
+ /// ├─────────────────────┤ │
810
+ /// │ native stack frames │ │
811
+ /// │ ... │ │
812
+ /// │ ┌───────────────┐◄─┼──┼── TLS pointer
813
+ /// │ │CallThreadState├──┼──┘
814
+ /// │ └───────────────┘ │
815
+ /// ├─────────────────────┤
816
+ /// │ wasm stack frames │
817
+ /// │ ... │
818
+ /// ├─────────────────────┤
819
+ /// │ native stack frames │
820
+ /// │ ... │
821
+ /// └─────────────────────┘◄───── smallest, or youngest, stack address
822
+ /// ```
823
+ ///
824
+ /// # Fibers and async
825
+ ///
826
+ /// Wasmtime supports stack-switching with fibers to implement async. This means
827
+ /// that Wasmtime will temporarily execute code on a separate stack and then
828
+ /// suspend from this stack back to the embedder for async operations. Doing
829
+ /// this safely requires manual management of the TLS pointer updated by
830
+ /// Wasmtime.
831
+ ///
832
+ /// For example when a fiber is suspended that means that the TLS pointer needs
833
+ /// to be restored to whatever it was when the fiber was resumed. Additionally
834
+ /// this may need to pop multiple `CallThreadState` activations, one for each
835
+ /// one located on the fiber stack itself.
836
+ ///
837
+ /// The `AsyncWasmCallState` and `PreviousAsyncWasmCallState` structures in this
838
+ /// module are used to manage this state, namely:
839
+ ///
840
+ /// * The `AsyncWasmCallState` structure represents the state of a suspended
841
+ /// fiber. This is a linked list, in reverse order, from oldest activation on
842
+ /// the fiber to youngest activation on the fiber.
843
+ ///
844
+ /// * The `PreviousAsyncWasmCallState` structure represents a pointer within our
845
+ /// thread's TLS linked list of activations when a fiber was resumed. This
846
+ /// pointer is used during fiber suspension to know when to stop popping
847
+ /// activations from the thread's linked list.
848
+ ///
849
+ /// Note that this means that the directionality of linked list links is
850
+ /// opposite when stored in TLS vs when stored for a suspended fiber. The
851
+ /// thread's current list pointed to by TLS is youngest-to-oldest links, while a
852
+ /// suspended fiber stores oldest-to-youngest links.
742
853
pub ( crate ) mod tls {
743
854
use super :: CallThreadState ;
744
855
@@ -830,6 +941,9 @@ pub(crate) mod tls {
830
941
//
831
942
// When pushed onto a thread this linked list is traversed to get pushed
832
943
// onto the current thread at the time.
944
+ //
945
+ // If this pointer is null then that means that the fiber this state is
946
+ // associated with has no activations.
833
947
state : raw:: Ptr ,
834
948
}
835
949
@@ -883,7 +997,7 @@ pub(crate) mod tls {
883
997
///
884
998
/// This is used when exiting a future in Wasmtime to assert that the
885
999
/// current CallThreadState pointer does not point within the stack
886
- /// we're leaving (e.g. allocated for a fiber).
1000
+ /// we're leaving (e.g. allocated for a fiber).
887
1001
pub fn assert_current_state_not_in_range ( range : core:: ops:: Range < usize > ) {
888
1002
let p = raw:: get ( ) as usize ;
889
1003
assert ! ( p < range. start || range. end < p) ;
@@ -892,14 +1006,15 @@ pub(crate) mod tls {
892
1006
893
1007
/// Opaque state used to help control TLS state across stack switches for
894
1008
/// async support.
1009
+ ///
1010
+ /// This structure is returned from [`AsyncWasmCallState::push`] and
1011
+ /// represents the state of this thread's TLS variable prior to the push
1012
+ /// operation.
895
1013
#[ cfg( feature = "async" ) ]
896
1014
pub struct PreviousAsyncWasmCallState {
897
- // The head of a linked list, similar to the TLS state. Note though that
898
- // this list is stored in reverse order to assist with `push` and `pop`
899
- // below.
900
- //
901
- // After a `push` call this stores the previous head for the current
902
- // thread so we know when to stop popping during a `pop`.
1015
+ // The raw value of this thread's TLS pointer when this structure was
1016
+ // created. This is not dereferenced or inspected but is used to halt
1017
+ // linked list traversal in [`PreviousAsyncWasmCallState::restore`].
903
1018
state : raw:: Ptr ,
904
1019
}
905
1020
@@ -909,8 +1024,8 @@ pub(crate) mod tls {
909
1024
/// `AsyncWasmCallState`.
910
1025
///
911
1026
/// This will pop the top activation of this current thread continuously
912
- /// until it reaches whatever the current activation was when `push` was
913
- /// originally called.
1027
+ /// until it reaches whatever the current activation was when
1028
+ /// [`AsyncWasmCallState::push`] was originally called.
914
1029
///
915
1030
/// # Unsafety
916
1031
///
0 commit comments