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