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