1 //! This module contains a modified version of the `wasmtime_fiber` crate, 2 //! specialized for executing stack switching continuations. 3 4 use anyhow::Result; 5 use core::ops::Range; 6 7 use crate::runtime::vm::stack_switching::VMHostArray; 8 use crate::runtime::vm::{VMContext, VMFuncRef, ValRaw}; 9 10 cfg_if::cfg_if! { 11 if #[cfg(all(feature = "stack-switching", unix, target_arch = "x86_64"))] { 12 mod unix; 13 use unix as imp; 14 } else { 15 mod dummy; 16 use dummy as imp; 17 } 18 } 19 20 /// Represents an execution stack to use for a fiber. 21 #[derive(Debug)] 22 #[repr(C)] 23 pub struct VMContinuationStack(imp::VMContinuationStack); 24 25 impl VMContinuationStack { 26 /// Creates a new fiber stack of the given size. 27 pub fn new(size: usize) -> Result<Self> { 28 Ok(Self(imp::VMContinuationStack::new(size)?)) 29 } 30 31 /// Returns a stack of size 0. 32 pub fn unallocated() -> Self { 33 Self(imp::VMContinuationStack::unallocated()) 34 } 35 36 /// Is this stack unallocated/of size 0? 37 pub fn is_unallocated(&self) -> bool { 38 imp::VMContinuationStack::is_unallocated(&self.0) 39 } 40 41 /// Creates a new fiber stack with the given pointer to the bottom of the 42 /// stack plus the byte length of the stack. 43 /// 44 /// The `bottom` pointer should be addressable for `len` bytes. The page 45 /// beneath `bottom` should be unmapped as a guard page. 46 /// 47 /// # Safety 48 /// 49 /// This is unsafe because there is no validation of the given pointer. 50 /// 51 /// The caller must properly allocate the stack space with a guard page and 52 /// make the pages accessible for correct behavior. 53 pub unsafe fn from_raw_parts(bottom: *mut u8, guard_size: usize, len: usize) -> Result<Self> { 54 Ok(Self(unsafe { 55 imp::VMContinuationStack::from_raw_parts(bottom, guard_size, len)? 56 })) 57 } 58 59 /// Is this a manually-managed stack created from raw parts? If so, it is up 60 /// to whoever created it to manage the stack's memory allocation. 61 pub fn is_from_raw_parts(&self) -> bool { 62 self.0.is_from_raw_parts() 63 } 64 65 /// Gets the top of the stack. 66 /// 67 /// Returns `None` if the platform does not support getting the top of the 68 /// stack. 69 pub fn top(&self) -> Option<*mut u8> { 70 self.0.top() 71 } 72 73 /// Returns the range of where this stack resides in memory if the platform 74 /// supports it. 75 pub fn range(&self) -> Option<Range<usize>> { 76 self.0.range() 77 } 78 79 /// Returns the instruction pointer stored in the Fiber's ControlContext. 80 pub fn control_context_instruction_pointer(&self) -> usize { 81 self.0.control_context_instruction_pointer() 82 } 83 84 /// Returns the frame pointer stored in the Fiber's ControlContext. 85 pub fn control_context_frame_pointer(&self) -> usize { 86 self.0.control_context_frame_pointer() 87 } 88 89 /// Returns the stack pointer stored in the Fiber's ControlContext. 90 pub fn control_context_stack_pointer(&self) -> usize { 91 self.0.control_context_stack_pointer() 92 } 93 94 /// Initializes this stack, such that it will execute the function denoted 95 /// by `func_ref`. `parameter_count` and `return_value_count` must be the 96 /// corresponding number of parameters and return values of `func_ref`. 97 /// `args` must point to the `args` field of the `VMContRef` owning this pointer. 98 /// 99 /// It will be updated by this function to correctly describe 100 /// the buffer used by this function for its arguments and return values. 101 pub fn initialize( 102 &self, 103 func_ref: *const VMFuncRef, 104 caller_vmctx: *mut VMContext, 105 args: *mut VMHostArray<ValRaw>, 106 parameter_count: u32, 107 return_value_count: u32, 108 ) { 109 self.0.initialize( 110 func_ref, 111 caller_vmctx, 112 args, 113 parameter_count, 114 return_value_count, 115 ) 116 } 117 } 118