163d482c8SFrank Emrich //! This module contains a modified version of the `wasmtime_fiber` crate, 263d482c8SFrank Emrich //! specialized for executing stack switching continuations. 363d482c8SFrank Emrich 4*96e19700SNick Fitzgerald use crate::Result; 563d482c8SFrank Emrich use core::ops::Range; 663d482c8SFrank Emrich 763d482c8SFrank Emrich use crate::runtime::vm::stack_switching::VMHostArray; 863d482c8SFrank Emrich use crate::runtime::vm::{VMContext, VMFuncRef, ValRaw}; 963d482c8SFrank Emrich 1063d482c8SFrank Emrich cfg_if::cfg_if! { 1163d482c8SFrank Emrich if #[cfg(all(feature = "stack-switching", unix, target_arch = "x86_64"))] { 1263d482c8SFrank Emrich mod unix; 1363d482c8SFrank Emrich use unix as imp; 1463d482c8SFrank Emrich } else { 1563d482c8SFrank Emrich mod dummy; 1663d482c8SFrank Emrich use dummy as imp; 1763d482c8SFrank Emrich } 1863d482c8SFrank Emrich } 1963d482c8SFrank Emrich 2063d482c8SFrank Emrich /// Represents an execution stack to use for a fiber. 2163d482c8SFrank Emrich #[derive(Debug)] 2263d482c8SFrank Emrich #[repr(C)] 2363d482c8SFrank Emrich pub struct VMContinuationStack(imp::VMContinuationStack); 2463d482c8SFrank Emrich 2563d482c8SFrank Emrich impl VMContinuationStack { 2663d482c8SFrank Emrich /// Creates a new fiber stack of the given size. new(size: usize) -> Result<Self>2763d482c8SFrank Emrich pub fn new(size: usize) -> Result<Self> { 2863d482c8SFrank Emrich Ok(Self(imp::VMContinuationStack::new(size)?)) 2963d482c8SFrank Emrich } 3063d482c8SFrank Emrich 3163d482c8SFrank Emrich /// Returns a stack of size 0. unallocated() -> Self3263d482c8SFrank Emrich pub fn unallocated() -> Self { 3363d482c8SFrank Emrich Self(imp::VMContinuationStack::unallocated()) 3463d482c8SFrank Emrich } 3563d482c8SFrank Emrich 3663d482c8SFrank Emrich /// Is this stack unallocated/of size 0? is_unallocated(&self) -> bool3763d482c8SFrank Emrich pub fn is_unallocated(&self) -> bool { 3863d482c8SFrank Emrich imp::VMContinuationStack::is_unallocated(&self.0) 3963d482c8SFrank Emrich } 4063d482c8SFrank Emrich 4163d482c8SFrank Emrich /// Creates a new fiber stack with the given pointer to the bottom of the 4263d482c8SFrank Emrich /// stack plus the byte length of the stack. 4363d482c8SFrank Emrich /// 4463d482c8SFrank Emrich /// The `bottom` pointer should be addressable for `len` bytes. The page 4563d482c8SFrank Emrich /// beneath `bottom` should be unmapped as a guard page. 4663d482c8SFrank Emrich /// 4763d482c8SFrank Emrich /// # Safety 4863d482c8SFrank Emrich /// 4963d482c8SFrank Emrich /// This is unsafe because there is no validation of the given pointer. 5063d482c8SFrank Emrich /// 5163d482c8SFrank Emrich /// The caller must properly allocate the stack space with a guard page and 5263d482c8SFrank Emrich /// make the pages accessible for correct behavior. from_raw_parts(bottom: *mut u8, guard_size: usize, len: usize) -> Result<Self>5363d482c8SFrank Emrich pub unsafe fn from_raw_parts(bottom: *mut u8, guard_size: usize, len: usize) -> Result<Self> { 5435786823SAlex Crichton Ok(Self(unsafe { 5535786823SAlex Crichton imp::VMContinuationStack::from_raw_parts(bottom, guard_size, len)? 5635786823SAlex Crichton })) 5763d482c8SFrank Emrich } 5863d482c8SFrank Emrich 5963d482c8SFrank Emrich /// Is this a manually-managed stack created from raw parts? If so, it is up 6063d482c8SFrank Emrich /// to whoever created it to manage the stack's memory allocation. is_from_raw_parts(&self) -> bool6163d482c8SFrank Emrich pub fn is_from_raw_parts(&self) -> bool { 6263d482c8SFrank Emrich self.0.is_from_raw_parts() 6363d482c8SFrank Emrich } 6463d482c8SFrank Emrich 6563d482c8SFrank Emrich /// Gets the top of the stack. 6663d482c8SFrank Emrich /// 6763d482c8SFrank Emrich /// Returns `None` if the platform does not support getting the top of the 6863d482c8SFrank Emrich /// stack. top(&self) -> Option<*mut u8>6963d482c8SFrank Emrich pub fn top(&self) -> Option<*mut u8> { 7063d482c8SFrank Emrich self.0.top() 7163d482c8SFrank Emrich } 7263d482c8SFrank Emrich 7363d482c8SFrank Emrich /// Returns the range of where this stack resides in memory if the platform 7463d482c8SFrank Emrich /// supports it. range(&self) -> Option<Range<usize>>7563d482c8SFrank Emrich pub fn range(&self) -> Option<Range<usize>> { 7663d482c8SFrank Emrich self.0.range() 7763d482c8SFrank Emrich } 7863d482c8SFrank Emrich 7963d482c8SFrank Emrich /// Returns the instruction pointer stored in the Fiber's ControlContext. control_context_instruction_pointer(&self) -> usize8063d482c8SFrank Emrich pub fn control_context_instruction_pointer(&self) -> usize { 8163d482c8SFrank Emrich self.0.control_context_instruction_pointer() 8263d482c8SFrank Emrich } 8363d482c8SFrank Emrich 8463d482c8SFrank Emrich /// Returns the frame pointer stored in the Fiber's ControlContext. control_context_frame_pointer(&self) -> usize8563d482c8SFrank Emrich pub fn control_context_frame_pointer(&self) -> usize { 8663d482c8SFrank Emrich self.0.control_context_frame_pointer() 8763d482c8SFrank Emrich } 8863d482c8SFrank Emrich 8963d482c8SFrank Emrich /// Returns the stack pointer stored in the Fiber's ControlContext. control_context_stack_pointer(&self) -> usize9063d482c8SFrank Emrich pub fn control_context_stack_pointer(&self) -> usize { 9163d482c8SFrank Emrich self.0.control_context_stack_pointer() 9263d482c8SFrank Emrich } 9363d482c8SFrank Emrich 9463d482c8SFrank Emrich /// Initializes this stack, such that it will execute the function denoted 9563d482c8SFrank Emrich /// by `func_ref`. `parameter_count` and `return_value_count` must be the 9663d482c8SFrank Emrich /// corresponding number of parameters and return values of `func_ref`. 9763d482c8SFrank Emrich /// `args` must point to the `args` field of the `VMContRef` owning this pointer. 9863d482c8SFrank Emrich /// 9963d482c8SFrank Emrich /// It will be updated by this function to correctly describe 10063d482c8SFrank Emrich /// the buffer used by this function for its arguments and return values. initialize( &self, func_ref: *const VMFuncRef, caller_vmctx: *mut VMContext, args: *mut VMHostArray<ValRaw>, parameter_count: u32, return_value_count: u32, )10163d482c8SFrank Emrich pub fn initialize( 10263d482c8SFrank Emrich &self, 10363d482c8SFrank Emrich func_ref: *const VMFuncRef, 10463d482c8SFrank Emrich caller_vmctx: *mut VMContext, 10563d482c8SFrank Emrich args: *mut VMHostArray<ValRaw>, 10663d482c8SFrank Emrich parameter_count: u32, 10763d482c8SFrank Emrich return_value_count: u32, 10863d482c8SFrank Emrich ) { 10963d482c8SFrank Emrich self.0.initialize( 11063d482c8SFrank Emrich func_ref, 11163d482c8SFrank Emrich caller_vmctx, 11263d482c8SFrank Emrich args, 11363d482c8SFrank Emrich parameter_count, 11463d482c8SFrank Emrich return_value_count, 11563d482c8SFrank Emrich ) 11663d482c8SFrank Emrich } 11763d482c8SFrank Emrich } 118