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