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