1 //! This module contains a modified version of the `wasmtime_fiber` crate,
2 //! specialized for executing stack switching continuations.
3 
4 use crate::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