181a89169SAlex Crichton use crate::prelude::*;
2abcd6accSChris Fallin use alloc::sync::Arc;
3abcd6accSChris Fallin use core::ops::Range;
4d4242001SAdam Bratschi-Kaye use wasmtime_fiber::{RuntimeFiberStack, RuntimeFiberStackCreator};
5d4242001SAdam Bratschi-Kaye 
6d4242001SAdam Bratschi-Kaye /// A stack creator. Can be used to provide a stack creator to wasmtime
7d4242001SAdam Bratschi-Kaye /// which supplies stacks for async support.
8d4242001SAdam Bratschi-Kaye ///
9d4242001SAdam Bratschi-Kaye /// # Safety
10d4242001SAdam Bratschi-Kaye ///
11d4242001SAdam Bratschi-Kaye /// This trait is unsafe, as memory safety depends on a proper implementation
12d4242001SAdam Bratschi-Kaye /// of memory management. Stacks created by the StackCreator should always be
13d4242001SAdam Bratschi-Kaye /// treated as owned by an wasmtime instance, and any modification of them
14d4242001SAdam Bratschi-Kaye /// outside of wasmtime invoked routines is unsafe and may lead to corruption.
15d4242001SAdam Bratschi-Kaye ///
16d4242001SAdam Bratschi-Kaye /// Note that this is a relatively new and experimental feature and it is
17d4242001SAdam Bratschi-Kaye /// recommended to be familiar with wasmtime runtime code to use it.
18d4242001SAdam Bratschi-Kaye pub unsafe trait StackCreator: Send + Sync {
19d4242001SAdam Bratschi-Kaye     /// Create a new `StackMemory` object with the specified size.
20d4242001SAdam Bratschi-Kaye     ///
21d4242001SAdam Bratschi-Kaye     /// The `size` parameter is the expected size of the stack without any guard pages.
22d4242001SAdam Bratschi-Kaye     ///
23*980a136eSNick Fitzgerald     /// The `zeroed` parameter is whether the stack's memory should be zeroed,
24*980a136eSNick Fitzgerald     /// as a defense-in-depth measure.
25*980a136eSNick Fitzgerald     ///
26d4242001SAdam Bratschi-Kaye     /// Note there should be at least one guard page of protected memory at the bottom
27d4242001SAdam Bratschi-Kaye     /// of the stack to catch potential stack overflow scenarios. Additionally, stacks should be
28d4242001SAdam Bratschi-Kaye     /// page aligned and zero filled.
new_stack(&self, size: usize, zeroed: bool) -> Result<Box<dyn StackMemory>, Error>29*980a136eSNick Fitzgerald     fn new_stack(&self, size: usize, zeroed: bool) -> Result<Box<dyn StackMemory>, Error>;
30d4242001SAdam Bratschi-Kaye }
31d4242001SAdam Bratschi-Kaye 
32d4242001SAdam Bratschi-Kaye #[derive(Clone)]
33d4242001SAdam Bratschi-Kaye pub(crate) struct StackCreatorProxy(pub Arc<dyn StackCreator>);
34d4242001SAdam Bratschi-Kaye 
35d4242001SAdam Bratschi-Kaye unsafe impl RuntimeFiberStackCreator for StackCreatorProxy {
new_stack(&self, size: usize, zeroed: bool) -> Result<Box<dyn RuntimeFiberStack>, Error>36*980a136eSNick Fitzgerald     fn new_stack(&self, size: usize, zeroed: bool) -> Result<Box<dyn RuntimeFiberStack>, Error> {
37*980a136eSNick Fitzgerald         let stack = self.0.new_stack(size, zeroed)?;
38d4242001SAdam Bratschi-Kaye         Ok(Box::new(FiberStackProxy(stack)) as Box<dyn RuntimeFiberStack>)
39d4242001SAdam Bratschi-Kaye     }
40d4242001SAdam Bratschi-Kaye }
41d4242001SAdam Bratschi-Kaye 
42d4242001SAdam Bratschi-Kaye /// A stack memory. This trait provides an interface for raw memory buffers
43d4242001SAdam Bratschi-Kaye /// which are used by wasmtime inside of stacks which wasmtime executes
44d4242001SAdam Bratschi-Kaye /// WebAssembly in for async support. By implementing this trait together
45d4242001SAdam Bratschi-Kaye /// with StackCreator, one can supply wasmtime with custom allocated host
46d4242001SAdam Bratschi-Kaye /// managed stacks.
47d4242001SAdam Bratschi-Kaye ///
48d4242001SAdam Bratschi-Kaye /// # Safety
49d4242001SAdam Bratschi-Kaye ///
50d4242001SAdam Bratschi-Kaye /// The memory should be page aligned and a multiple of page size.
51d4242001SAdam Bratschi-Kaye /// To prevent possible silent overflows, the memory should be protected by a
52d4242001SAdam Bratschi-Kaye /// guard page. Additionally the safety concerns explained in ['Memory'], for
53d4242001SAdam Bratschi-Kaye /// accessing the memory apply here as well.
54d4242001SAdam Bratschi-Kaye ///
55d4242001SAdam Bratschi-Kaye /// Note that this is a relatively new and experimental feature and it is
56d4242001SAdam Bratschi-Kaye /// recommended to be familiar with wasmtime runtime code to use it.
57d4242001SAdam Bratschi-Kaye pub unsafe trait StackMemory: Send + Sync {
58d4242001SAdam Bratschi-Kaye     /// The top of the allocated stack.
59d4242001SAdam Bratschi-Kaye     ///
60d4242001SAdam Bratschi-Kaye     /// This address should be page aligned.
top(&self) -> *mut u861d4242001SAdam Bratschi-Kaye     fn top(&self) -> *mut u8;
62d4242001SAdam Bratschi-Kaye     /// The range of where this stack resides in memory, excluding guard pages.
range(&self) -> Range<usize>63d4242001SAdam Bratschi-Kaye     fn range(&self) -> Range<usize>;
64110e70f3SAlex Crichton     /// The range of memory where the guard region of this stack resides.
guard_range(&self) -> Range<*mut u8>65110e70f3SAlex Crichton     fn guard_range(&self) -> Range<*mut u8>;
66d4242001SAdam Bratschi-Kaye }
67d4242001SAdam Bratschi-Kaye 
68d4242001SAdam Bratschi-Kaye pub(crate) struct FiberStackProxy(pub Box<dyn StackMemory>);
69d4242001SAdam Bratschi-Kaye 
70d4242001SAdam Bratschi-Kaye unsafe impl RuntimeFiberStack for FiberStackProxy {
top(&self) -> *mut u871d4242001SAdam Bratschi-Kaye     fn top(&self) -> *mut u8 {
72d4242001SAdam Bratschi-Kaye         self.0.top()
73d4242001SAdam Bratschi-Kaye     }
74d4242001SAdam Bratschi-Kaye 
range(&self) -> Range<usize>75d4242001SAdam Bratschi-Kaye     fn range(&self) -> Range<usize> {
76d4242001SAdam Bratschi-Kaye         self.0.range()
77d4242001SAdam Bratschi-Kaye     }
78110e70f3SAlex Crichton 
guard_range(&self) -> Range<*mut u8>79110e70f3SAlex Crichton     fn guard_range(&self) -> Range<*mut u8> {
80110e70f3SAlex Crichton         self.0.guard_range()
81110e70f3SAlex Crichton     }
82d4242001SAdam Bratschi-Kaye }
83