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