1 use crate::MemoryType; 2 use crate::memory::{LinearMemory, MemoryCreator}; 3 use crate::prelude::*; 4 use crate::runtime::vm::mpk::ProtectionKey; 5 use crate::runtime::vm::{ 6 CompiledModuleId, InstanceAllocationRequest, InstanceAllocator, Memory, MemoryAllocationIndex, 7 MemoryBase, ModuleRuntimeInfo, OnDemandInstanceAllocator, RuntimeLinearMemory, 8 RuntimeMemoryCreator, SharedMemory, Table, TableAllocationIndex, 9 }; 10 use crate::store::{AllocateInstanceKind, InstanceId, StoreOpaque, StoreResourceLimiter}; 11 use alloc::sync::Arc; 12 use wasmtime_environ::{ 13 DefinedMemoryIndex, DefinedTableIndex, EntityIndex, HostPtr, Module, StaticModuleIndex, 14 Tunables, VMOffsets, 15 }; 16 17 #[cfg(feature = "component-model")] 18 use wasmtime_environ::component::{Component, VMComponentOffsets}; 19 20 /// Create a "frankenstein" instance with a single memory. 21 /// 22 /// This separate instance is necessary because Wasm objects in Wasmtime must be 23 /// attached to instances (versus the store, e.g.) and some objects exist 24 /// outside: a host-provided memory import, shared memory. 25 pub async fn create_memory( 26 store: &mut StoreOpaque, 27 limiter: Option<&mut StoreResourceLimiter<'_>>, 28 memory_ty: &MemoryType, 29 preallocation: Option<&SharedMemory>, 30 ) -> Result<InstanceId> { 31 let mut module = Module::new(StaticModuleIndex::from_u32(0)); 32 33 // Create a memory, though it will never be used for constructing a memory 34 // with an allocator: instead the memories are either preallocated (i.e., 35 // shared memory) or allocated manually below. 36 let memory_id = module.memories.push(*memory_ty.wasmtime_memory()); 37 38 // Since we have only associated a single memory with the "frankenstein" 39 // instance, it will be exported at index 0. 40 debug_assert_eq!(memory_id.as_u32(), 0); 41 module 42 .exports 43 .insert(String::new(), EntityIndex::Memory(memory_id)); 44 45 // We create an instance in the on-demand allocator when creating handles 46 // associated with external objects. The configured instance allocator 47 // should only be used when creating module instances as we don't want host 48 // objects to count towards instance limits. 49 let allocator = SingleMemoryInstance { 50 preallocation, 51 ondemand: OnDemandInstanceAllocator::default(), 52 }; 53 unsafe { 54 store 55 .allocate_instance( 56 limiter, 57 AllocateInstanceKind::Dummy { 58 allocator: &allocator, 59 }, 60 &ModuleRuntimeInfo::bare(Arc::new(module)), 61 Default::default(), 62 ) 63 .await 64 } 65 } 66 67 struct LinearMemoryProxy { 68 mem: Box<dyn LinearMemory>, 69 } 70 71 impl RuntimeLinearMemory for LinearMemoryProxy { 72 fn byte_size(&self) -> usize { 73 self.mem.byte_size() 74 } 75 76 fn byte_capacity(&self) -> usize { 77 self.mem.byte_capacity() 78 } 79 80 fn grow_to(&mut self, new_size: usize) -> Result<()> { 81 self.mem.grow_to(new_size) 82 } 83 84 fn base(&self) -> MemoryBase { 85 MemoryBase::new_raw(self.mem.as_ptr()) 86 } 87 88 fn vmmemory(&self) -> crate::vm::VMMemoryDefinition { 89 let base = core::ptr::NonNull::new(self.mem.as_ptr()).unwrap(); 90 crate::vm::VMMemoryDefinition { 91 base: base.into(), 92 current_length: self.mem.byte_size().into(), 93 } 94 } 95 } 96 97 #[derive(Clone)] 98 pub(crate) struct MemoryCreatorProxy(pub Arc<dyn MemoryCreator>); 99 100 impl RuntimeMemoryCreator for MemoryCreatorProxy { 101 fn new_memory( 102 &self, 103 ty: &wasmtime_environ::Memory, 104 tunables: &Tunables, 105 minimum: usize, 106 maximum: Option<usize>, 107 ) -> Result<Box<dyn RuntimeLinearMemory>> { 108 let reserved_size_in_bytes = Some(tunables.memory_reservation.try_into().unwrap()); 109 self.0 110 .new_memory( 111 MemoryType::from_wasmtime_memory(ty), 112 minimum, 113 maximum, 114 reserved_size_in_bytes, 115 usize::try_from(tunables.memory_guard_size).unwrap(), 116 ) 117 .map(|mem| Box::new(LinearMemoryProxy { mem }) as Box<dyn RuntimeLinearMemory>) 118 .map_err(|e| anyhow!(e)) 119 } 120 } 121 122 struct SingleMemoryInstance<'a> { 123 preallocation: Option<&'a SharedMemory>, 124 ondemand: OnDemandInstanceAllocator, 125 } 126 127 #[async_trait::async_trait] 128 unsafe impl InstanceAllocator for SingleMemoryInstance<'_> { 129 #[cfg(feature = "component-model")] 130 fn validate_component<'a>( 131 &self, 132 _component: &Component, 133 _offsets: &VMComponentOffsets<HostPtr>, 134 _get_module: &'a dyn Fn(StaticModuleIndex) -> &'a Module, 135 ) -> Result<()> { 136 unreachable!("`SingleMemoryInstance` allocator never used with components") 137 } 138 139 fn validate_module(&self, module: &Module, offsets: &VMOffsets<HostPtr>) -> Result<()> { 140 anyhow::ensure!( 141 module.memories.len() == 1, 142 "`SingleMemoryInstance` allocator can only be used for modules with a single memory" 143 ); 144 self.ondemand.validate_module(module, offsets)?; 145 Ok(()) 146 } 147 148 #[cfg(feature = "gc")] 149 fn validate_memory(&self, memory: &wasmtime_environ::Memory) -> Result<()> { 150 self.ondemand.validate_memory(memory) 151 } 152 153 #[cfg(feature = "component-model")] 154 fn increment_component_instance_count(&self) -> Result<()> { 155 self.ondemand.increment_component_instance_count() 156 } 157 158 #[cfg(feature = "component-model")] 159 fn decrement_component_instance_count(&self) { 160 self.ondemand.decrement_component_instance_count(); 161 } 162 163 fn increment_core_instance_count(&self) -> Result<()> { 164 self.ondemand.increment_core_instance_count() 165 } 166 167 fn decrement_core_instance_count(&self) { 168 self.ondemand.decrement_core_instance_count(); 169 } 170 171 async fn allocate_memory( 172 &self, 173 request: &mut InstanceAllocationRequest<'_, '_>, 174 ty: &wasmtime_environ::Memory, 175 memory_index: Option<DefinedMemoryIndex>, 176 ) -> Result<(MemoryAllocationIndex, Memory)> { 177 if cfg!(debug_assertions) { 178 let module = request.runtime_info.env_module(); 179 let offsets = request.runtime_info.offsets(); 180 self.validate_module(module, offsets) 181 .expect("should have already validated the module before allocating memory"); 182 } 183 184 match self.preallocation { 185 Some(shared_memory) => Ok(( 186 MemoryAllocationIndex::default(), 187 shared_memory.clone().as_memory(), 188 )), 189 None => { 190 self.ondemand 191 .allocate_memory(request, ty, memory_index) 192 .await 193 } 194 } 195 } 196 197 unsafe fn deallocate_memory( 198 &self, 199 memory_index: Option<DefinedMemoryIndex>, 200 allocation_index: MemoryAllocationIndex, 201 memory: Memory, 202 ) { 203 unsafe { 204 self.ondemand 205 .deallocate_memory(memory_index, allocation_index, memory) 206 } 207 } 208 209 async fn allocate_table( 210 &self, 211 req: &mut InstanceAllocationRequest<'_, '_>, 212 ty: &wasmtime_environ::Table, 213 table_index: DefinedTableIndex, 214 ) -> Result<(TableAllocationIndex, Table)> { 215 self.ondemand.allocate_table(req, ty, table_index).await 216 } 217 218 unsafe fn deallocate_table( 219 &self, 220 table_index: DefinedTableIndex, 221 allocation_index: TableAllocationIndex, 222 table: Table, 223 ) { 224 unsafe { 225 self.ondemand 226 .deallocate_table(table_index, allocation_index, table) 227 } 228 } 229 230 #[cfg(feature = "async")] 231 fn allocate_fiber_stack(&self) -> Result<wasmtime_fiber::FiberStack> { 232 unreachable!() 233 } 234 235 #[cfg(feature = "async")] 236 unsafe fn deallocate_fiber_stack(&self, _stack: wasmtime_fiber::FiberStack) { 237 unreachable!() 238 } 239 240 fn purge_module(&self, _: CompiledModuleId) { 241 unreachable!() 242 } 243 244 fn next_available_pkey(&self) -> Option<ProtectionKey> { 245 unreachable!() 246 } 247 248 fn restrict_to_pkey(&self, _: ProtectionKey) { 249 unreachable!() 250 } 251 252 fn allow_all_pkeys(&self) { 253 unreachable!() 254 } 255 256 #[cfg(feature = "gc")] 257 fn allocate_gc_heap( 258 &self, 259 _engine: &crate::Engine, 260 _gc_runtime: &dyn crate::vm::GcRuntime, 261 _memory_alloc_index: crate::vm::MemoryAllocationIndex, 262 _memory: Memory, 263 ) -> Result<(crate::vm::GcHeapAllocationIndex, Box<dyn crate::vm::GcHeap>)> { 264 unreachable!() 265 } 266 267 #[cfg(feature = "gc")] 268 fn deallocate_gc_heap( 269 &self, 270 _allocation_index: crate::vm::GcHeapAllocationIndex, 271 _gc_heap: Box<dyn crate::vm::GcHeap>, 272 ) -> (crate::vm::MemoryAllocationIndex, crate::vm::Memory) { 273 unreachable!() 274 } 275 } 276