@@ -439,17 +439,19 @@ mod call_thread_state {
439439 #[ cfg( all( has_native_signals, unix) ) ]
440440 pub ( crate ) async_guard_range : Range < * mut u8 > ,
441441
442- // The values of `VMStoreContext::last_wasm_{exit_{pc,fp},entry_sp}` for
442+ // The values of
443+ // `VMStoreContext::{stack_limit,last_wasm_{exit_{pc,fp},entry_sp}}` for
443444 // the *previous* `CallThreadState` for this same store/limits. Our
444445 // *current* last wasm PC/FP/SP are saved in `self.vm_store_context`. We
445446 // save a copy of the old registers here because the `VMStoreContext`
446447 // typically doesn't change across nested calls into Wasm (i.e. they are
447448 // typically calls back into the same store and `self.vm_store_context
448449 // == self.prev.vm_store_context`) and we must to maintain the list of
449450 // contiguous-Wasm-frames stack regions for backtracing purposes.
450- old_last_wasm_exit_fp : Cell < usize > ,
451- old_last_wasm_exit_pc : Cell < usize > ,
452- old_last_wasm_entry_fp : Cell < usize > ,
451+ pub ( super ) old_stack_limit : Cell < usize > ,
452+ pub ( super ) old_last_wasm_exit_fp : Cell < usize > ,
453+ pub ( super ) old_last_wasm_exit_pc : Cell < usize > ,
454+ pub ( super ) old_last_wasm_entry_fp : Cell < usize > ,
453455 }
454456
455457 impl Drop for CallThreadState {
@@ -460,6 +462,7 @@ mod call_thread_state {
460462
461463 unsafe {
462464 let cx = self . vm_store_context . as_ref ( ) ;
465+ * cx. stack_limit . get ( ) = self . old_stack_limit . get ( ) ;
463466 * cx. last_wasm_exit_fp . get ( ) = self . old_last_wasm_exit_fp . get ( ) ;
464467 * cx. last_wasm_exit_pc . get ( ) = self . old_last_wasm_exit_pc . get ( ) ;
465468 * cx. last_wasm_entry_fp . get ( ) = self . old_last_wasm_entry_fp . get ( ) ;
@@ -500,6 +503,7 @@ mod call_thread_state {
500503 #[ cfg( all( has_native_signals, unix) ) ]
501504 async_guard_range,
502505 prev : Cell :: new ( ptr:: null ( ) ) ,
506+ old_stack_limit : Cell :: new ( unsafe { * vm_store_context. as_ref ( ) . stack_limit . get ( ) } ) ,
503507 old_last_wasm_exit_fp : Cell :: new ( unsafe {
504508 * vm_store_context. as_ref ( ) . last_wasm_exit_fp . get ( )
505509 } ) ,
@@ -825,6 +829,20 @@ pub(crate) mod tls {
825829
826830 pub use raw:: initialize as tls_eager_initialize;
827831
832+ impl CallThreadState {
833+ unsafe fn swap ( & self ) {
834+ unsafe fn swap ( a : & core:: cell:: UnsafeCell < usize > , b : & core:: cell:: Cell < usize > ) {
835+ * a. get ( ) = b. replace ( * a. get ( ) ) ;
836+ }
837+
838+ let cx = self . vm_store_context . as_ref ( ) ;
839+ swap ( & cx. stack_limit , & self . old_stack_limit ) ;
840+ swap ( & cx. last_wasm_exit_fp , & self . old_last_wasm_exit_fp ) ;
841+ swap ( & cx. last_wasm_exit_pc , & self . old_last_wasm_exit_pc ) ;
842+ swap ( & cx. last_wasm_entry_fp , & self . old_last_wasm_entry_fp ) ;
843+ }
844+ }
845+
828846 /// Opaque state used to persist the state of the `CallThreadState`
829847 /// activations associated with a fiber stack that's used as part of an
830848 /// async wasm call.
@@ -873,6 +891,13 @@ pub(crate) mod tls {
873891 // list as stored in the state of this current thread.
874892 let ret = PreviousAsyncWasmCallState { state : raw:: get ( ) } ;
875893 let mut ptr = self . state ;
894+
895+ if let Some ( state) = ptr. as_ref ( ) {
896+ // Swap the current PC/FP/SP/etc. with those in the oldest
897+ // activation so we can restore them later in
898+ // `PreviousAsyncWasmCallState::restore`
899+ state. swap ( ) ;
900+ }
876901 while let Some ( state) = ptr. as_ref ( ) {
877902 ptr = state. prev . replace ( core:: ptr:: null_mut ( ) ) ;
878903 state. push ( ) ;
@@ -932,14 +957,22 @@ pub(crate) mod tls {
932957 // this loop is finished.
933958 let ptr = raw:: get ( ) ;
934959 if ptr == thread_head {
960+ if let Some ( state) = ret. state . as_ref ( ) {
961+ // Swap the current PC/FP/SP/etc. with those in the
962+ // oldest activation, which reverses what we did in
963+ // `AsyncWasmCallState::push`.
964+ state. swap ( ) ;
965+ }
966+
935967 break ret;
936968 }
937969
938970 // Pop this activation from the current thread's TLS state, and
939971 // then afterwards push it onto our own linked list within this
940- // `AsyncWasmCallState`. Note that the linked list in `AsyncWasmCallState` is stored
941- // in reverse order so a subsequent `push` later on pushes
942- // everything in the right order.
972+ // `AsyncWasmCallState`. Note that the linked list in
973+ // `AsyncWasmCallState` is stored in reverse order so a
974+ // subsequent `push` later on pushes everything in the right
975+ // order.
943976 ( * ptr) . pop ( ) ;
944977 if let Some ( state) = ret. state . as_ref ( ) {
945978 ( * ptr) . prev . set ( state) ;
0 commit comments