1 use super::{
2     InstanceAllocationRequest, InstanceAllocator, MemoryAllocationIndex, TableAllocationIndex,
3 };
4 use crate::prelude::*;
5 use crate::runtime::vm::CompiledModuleId;
6 use crate::runtime::vm::instance::RuntimeMemoryCreator;
7 use crate::runtime::vm::memory::{DefaultMemoryCreator, Memory};
8 use crate::runtime::vm::mpk::ProtectionKey;
9 use crate::runtime::vm::table::Table;
10 use alloc::sync::Arc;
11 use core::future::Future;
12 use core::pin::Pin;
13 use wasmtime_environ::{DefinedMemoryIndex, DefinedTableIndex, HostPtr, Module, VMOffsets};
14 
15 #[cfg(feature = "gc")]
16 use crate::runtime::vm::{GcHeap, GcHeapAllocationIndex, GcRuntime};
17 
18 #[cfg(feature = "async")]
19 use wasmtime_fiber::RuntimeFiberStackCreator;
20 
21 #[cfg(feature = "component-model")]
22 use wasmtime_environ::{
23     StaticModuleIndex,
24     component::{Component, VMComponentOffsets},
25 };
26 
27 /// Represents the on-demand instance allocator.
28 #[derive(Clone)]
29 pub struct OnDemandInstanceAllocator {
30     mem_creator: Option<Arc<dyn RuntimeMemoryCreator>>,
31     #[cfg(feature = "async")]
32     stack_creator: Option<Arc<dyn RuntimeFiberStackCreator>>,
33     #[cfg(feature = "async")]
34     stack_size: usize,
35     #[cfg(feature = "async")]
36     stack_zeroing: bool,
37 }
38 
39 impl OnDemandInstanceAllocator {
40     /// Creates a new on-demand instance allocator.
new( mem_creator: Option<Arc<dyn RuntimeMemoryCreator>>, stack_size: usize, stack_zeroing: bool, ) -> Self41     pub fn new(
42         mem_creator: Option<Arc<dyn RuntimeMemoryCreator>>,
43         stack_size: usize,
44         stack_zeroing: bool,
45     ) -> Self {
46         let _ = (stack_size, stack_zeroing); // suppress warnings when async feature is disabled.
47         Self {
48             mem_creator,
49             #[cfg(feature = "async")]
50             stack_creator: None,
51             #[cfg(feature = "async")]
52             stack_size,
53             #[cfg(feature = "async")]
54             stack_zeroing,
55         }
56     }
57 
58     /// Set the stack creator.
59     #[cfg(feature = "async")]
set_stack_creator(&mut self, stack_creator: Arc<dyn RuntimeFiberStackCreator>)60     pub fn set_stack_creator(&mut self, stack_creator: Arc<dyn RuntimeFiberStackCreator>) {
61         self.stack_creator = Some(stack_creator);
62     }
63 }
64 
65 impl Default for OnDemandInstanceAllocator {
default() -> Self66     fn default() -> Self {
67         Self {
68             mem_creator: None,
69             #[cfg(feature = "async")]
70             stack_creator: None,
71             #[cfg(feature = "async")]
72             stack_size: 0,
73             #[cfg(feature = "async")]
74             stack_zeroing: false,
75         }
76     }
77 }
78 
79 unsafe impl InstanceAllocator for OnDemandInstanceAllocator {
80     #[cfg(feature = "component-model")]
validate_component<'a>( &self, _component: &Component, _offsets: &VMComponentOffsets<HostPtr>, _get_module: &'a dyn Fn(StaticModuleIndex) -> &'a Module, ) -> Result<()>81     fn validate_component<'a>(
82         &self,
83         _component: &Component,
84         _offsets: &VMComponentOffsets<HostPtr>,
85         _get_module: &'a dyn Fn(StaticModuleIndex) -> &'a Module,
86     ) -> Result<()> {
87         Ok(())
88     }
89 
validate_module(&self, _module: &Module, _offsets: &VMOffsets<HostPtr>) -> Result<()>90     fn validate_module(&self, _module: &Module, _offsets: &VMOffsets<HostPtr>) -> Result<()> {
91         Ok(())
92     }
93 
94     #[cfg(feature = "gc")]
validate_memory(&self, _memory: &wasmtime_environ::Memory) -> Result<()>95     fn validate_memory(&self, _memory: &wasmtime_environ::Memory) -> Result<()> {
96         Ok(())
97     }
98 
99     #[cfg(feature = "component-model")]
increment_component_instance_count(&self) -> Result<()>100     fn increment_component_instance_count(&self) -> Result<()> {
101         Ok(())
102     }
103 
104     #[cfg(feature = "component-model")]
decrement_component_instance_count(&self)105     fn decrement_component_instance_count(&self) {}
106 
increment_core_instance_count(&self) -> Result<()>107     fn increment_core_instance_count(&self) -> Result<()> {
108         Ok(())
109     }
110 
decrement_core_instance_count(&self)111     fn decrement_core_instance_count(&self) {}
112 
allocate_memory<'a, 'b: 'a, 'c: 'a>( &'a self, request: &'a mut InstanceAllocationRequest<'b, 'c>, ty: &'a wasmtime_environ::Memory, memory_index: Option<DefinedMemoryIndex>, ) -> Pin<Box<dyn Future<Output = Result<(MemoryAllocationIndex, Memory)>> + Send + 'a>>113     fn allocate_memory<'a, 'b: 'a, 'c: 'a>(
114         &'a self,
115         request: &'a mut InstanceAllocationRequest<'b, 'c>,
116         ty: &'a wasmtime_environ::Memory,
117         memory_index: Option<DefinedMemoryIndex>,
118     ) -> Pin<Box<dyn Future<Output = Result<(MemoryAllocationIndex, Memory)>> + Send + 'a>> {
119         let creator = self
120             .mem_creator
121             .as_deref()
122             .unwrap_or_else(|| &DefaultMemoryCreator);
123 
124         crate::runtime::box_future(async move {
125             let image = if let Some(memory_index) = memory_index {
126                 request.runtime_info.memory_image(memory_index)?
127             } else {
128                 None
129             };
130 
131             let allocation_index = MemoryAllocationIndex::default();
132             let memory = Memory::new_dynamic(
133                 ty,
134                 request.store.engine(),
135                 creator,
136                 image,
137                 request.limiter.as_deref_mut(),
138             )
139             .await?;
140             Ok((allocation_index, memory))
141         })
142     }
143 
deallocate_memory( &self, _memory_index: Option<DefinedMemoryIndex>, allocation_index: MemoryAllocationIndex, _memory: Memory, )144     unsafe fn deallocate_memory(
145         &self,
146         _memory_index: Option<DefinedMemoryIndex>,
147         allocation_index: MemoryAllocationIndex,
148         _memory: Memory,
149     ) {
150         debug_assert_eq!(allocation_index, MemoryAllocationIndex::default());
151         // Normal destructors do all the necessary clean up.
152     }
153 
allocate_table<'a, 'b: 'a, 'c: 'a>( &'a self, request: &'a mut InstanceAllocationRequest<'b, 'c>, ty: &'a wasmtime_environ::Table, _table_index: DefinedTableIndex, ) -> Pin<Box<dyn Future<Output = Result<(TableAllocationIndex, Table)>> + Send + 'a>>154     fn allocate_table<'a, 'b: 'a, 'c: 'a>(
155         &'a self,
156         request: &'a mut InstanceAllocationRequest<'b, 'c>,
157         ty: &'a wasmtime_environ::Table,
158         _table_index: DefinedTableIndex,
159     ) -> Pin<Box<dyn Future<Output = Result<(TableAllocationIndex, Table)>> + Send + 'a>> {
160         crate::runtime::box_future(async move {
161             let allocation_index = TableAllocationIndex::default();
162             let table = Table::new_dynamic(
163                 ty,
164                 request.store.engine().tunables(),
165                 request.limiter.as_deref_mut(),
166             )
167             .await?;
168             Ok((allocation_index, table))
169         })
170     }
171 
deallocate_table( &self, _table_index: DefinedTableIndex, allocation_index: TableAllocationIndex, _table: Table, )172     unsafe fn deallocate_table(
173         &self,
174         _table_index: DefinedTableIndex,
175         allocation_index: TableAllocationIndex,
176         _table: Table,
177     ) {
178         debug_assert_eq!(allocation_index, TableAllocationIndex::default());
179         // Normal destructors do all the necessary clean up.
180     }
181 
182     #[cfg(feature = "async")]
allocate_fiber_stack(&self) -> Result<wasmtime_fiber::FiberStack>183     fn allocate_fiber_stack(&self) -> Result<wasmtime_fiber::FiberStack> {
184         if self.stack_size == 0 {
185             crate::bail!("fiber stacks are not supported by the allocator")
186         }
187         let stack = match &self.stack_creator {
188             Some(stack_creator) => {
189                 let stack = stack_creator.new_stack(self.stack_size, self.stack_zeroing)?;
190                 wasmtime_fiber::FiberStack::from_custom(stack)
191             }
192             None => wasmtime_fiber::FiberStack::new(self.stack_size, self.stack_zeroing),
193         }?;
194         Ok(stack)
195     }
196 
197     #[cfg(feature = "async")]
deallocate_fiber_stack(&self, stack: wasmtime_fiber::FiberStack)198     unsafe fn deallocate_fiber_stack(&self, stack: wasmtime_fiber::FiberStack) {
199         // The on-demand allocator has no further bookkeeping for fiber stacks
200         // beyond dropping them.
201         let _ = stack;
202     }
203 
purge_module(&self, _: CompiledModuleId)204     fn purge_module(&self, _: CompiledModuleId) {}
205 
next_available_pkey(&self) -> Option<ProtectionKey>206     fn next_available_pkey(&self) -> Option<ProtectionKey> {
207         // The on-demand allocator cannot use protection keys--it requires
208         // back-to-back allocation of memory slots that this allocator cannot
209         // guarantee.
210         None
211     }
212 
restrict_to_pkey(&self, _: ProtectionKey)213     fn restrict_to_pkey(&self, _: ProtectionKey) {
214         // The on-demand allocator cannot use protection keys; an on-demand
215         // allocator will never hand out protection keys to the stores its
216         // engine creates.
217         unreachable!()
218     }
219 
allow_all_pkeys(&self)220     fn allow_all_pkeys(&self) {
221         // The on-demand allocator cannot use protection keys; an on-demand
222         // allocator will never hand out protection keys to the stores its
223         // engine creates.
224         unreachable!()
225     }
226 
227     #[cfg(feature = "gc")]
allocate_gc_heap( &self, engine: &crate::Engine, gc_runtime: &dyn GcRuntime, memory_alloc_index: MemoryAllocationIndex, memory: Memory, ) -> Result<(GcHeapAllocationIndex, Box<dyn GcHeap>)>228     fn allocate_gc_heap(
229         &self,
230         engine: &crate::Engine,
231         gc_runtime: &dyn GcRuntime,
232         memory_alloc_index: MemoryAllocationIndex,
233         memory: Memory,
234     ) -> Result<(GcHeapAllocationIndex, Box<dyn GcHeap>)> {
235         debug_assert_eq!(memory_alloc_index, MemoryAllocationIndex::default());
236         let mut heap = gc_runtime.new_gc_heap(engine)?;
237         heap.attach(memory);
238         Ok((GcHeapAllocationIndex::default(), heap))
239     }
240 
241     #[cfg(feature = "gc")]
deallocate_gc_heap( &self, allocation_index: GcHeapAllocationIndex, mut gc_heap: Box<dyn crate::runtime::vm::GcHeap>, ) -> (MemoryAllocationIndex, Memory)242     fn deallocate_gc_heap(
243         &self,
244         allocation_index: GcHeapAllocationIndex,
245         mut gc_heap: Box<dyn crate::runtime::vm::GcHeap>,
246     ) -> (MemoryAllocationIndex, Memory) {
247         debug_assert_eq!(allocation_index, GcHeapAllocationIndex::default());
248         (MemoryAllocationIndex::default(), gc_heap.detach())
249     }
250 }
251