wasmtime/runtime/trampoline/
memory.rs1use crate::MemoryType;
2use crate::memory::{LinearMemory, MemoryCreator};
3use crate::prelude::*;
4use crate::runtime::vm::mpk::ProtectionKey;
5use crate::runtime::vm::{
6 CompiledModuleId, InstanceAllocationRequest, InstanceAllocator, Memory, MemoryAllocationIndex,
7 MemoryBase, ModuleRuntimeInfo, OnDemandInstanceAllocator, RuntimeLinearMemory,
8 RuntimeMemoryCreator, SharedMemory, Table, TableAllocationIndex,
9};
10use crate::store::{AllocateInstanceKind, InstanceId, StoreOpaque, StoreResourceLimiter};
11use alloc::sync::Arc;
12use wasmtime_environ::{
13 DefinedMemoryIndex, DefinedTableIndex, EntityIndex, HostPtr, Module, StaticModuleIndex,
14 Tunables, VMOffsets,
15};
16
17#[cfg(feature = "component-model")]
18use wasmtime_environ::component::{Component, VMComponentOffsets};
19
20pub 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 let memory_id = module.memories.push(*memory_ty.wasmtime_memory());
37
38 debug_assert_eq!(memory_id.as_u32(), 0);
41 module
42 .exports
43 .insert(String::new(), EntityIndex::Memory(memory_id));
44
45 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
67struct LinearMemoryProxy {
68 mem: Box<dyn LinearMemory>,
69}
70
71impl 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)]
98pub(crate) struct MemoryCreatorProxy(pub Arc<dyn MemoryCreator>);
99
100impl 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
122struct SingleMemoryInstance<'a> {
123 preallocation: Option<&'a SharedMemory>,
124 ondemand: OnDemandInstanceAllocator,
125}
126
127#[async_trait::async_trait]
128unsafe 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}