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