wasmtime/runtime/trampoline/
memory.rs
1use crate::memory::{LinearMemory, MemoryCreator};
2use crate::prelude::*;
3use crate::runtime::vm::mpk::ProtectionKey;
4use crate::runtime::vm::{
5 CompiledModuleId, Imports, InstanceAllocationRequest, InstanceAllocator, InstanceAllocatorImpl,
6 Memory, MemoryAllocationIndex, MemoryBase, ModuleRuntimeInfo, OnDemandInstanceAllocator,
7 RuntimeLinearMemory, RuntimeMemoryCreator, SharedMemory, StorePtr, Table, TableAllocationIndex,
8};
9use crate::store::{InstanceId, StoreOpaque};
10use crate::MemoryType;
11use alloc::sync::Arc;
12use wasmtime_environ::{
13 DefinedMemoryIndex, DefinedTableIndex, EntityIndex, HostPtr, Module, Tunables, VMOffsets,
14};
15
16#[cfg(feature = "component-model")]
17use wasmtime_environ::{
18 component::{Component, VMComponentOffsets},
19 StaticModuleIndex,
20};
21
22pub fn create_memory(
28 store: &mut StoreOpaque,
29 memory_ty: &MemoryType,
30 preallocation: Option<&SharedMemory>,
31) -> Result<InstanceId> {
32 let mut module = Module::new();
33
34 let memory_id = module.memories.push(*memory_ty.wasmtime_memory());
38
39 debug_assert_eq!(memory_id.as_u32(), 0);
42 module
43 .exports
44 .insert(String::new(), EntityIndex::Memory(memory_id));
45
46 let runtime_info = &ModuleRuntimeInfo::bare_maybe_imported_func(Arc::new(module), None);
51 let host_state = Box::new(());
52 let imports = Imports::default();
53 let request = InstanceAllocationRequest {
54 imports,
55 host_state,
56 store: StorePtr::new(store.traitobj()),
57 runtime_info,
58 wmemcheck: false,
59 pkey: None,
60 tunables: store.engine().tunables(),
61 };
62
63 unsafe {
64 let handle = SingleMemoryInstance {
65 preallocation,
66 ondemand: OnDemandInstanceAllocator::default(),
67 }
68 .allocate_module(request)?;
69 let instance_id = store.add_dummy_instance(handle.clone());
70 Ok(instance_id)
71 }
72}
73
74struct LinearMemoryProxy {
75 mem: Box<dyn LinearMemory>,
76}
77
78impl RuntimeLinearMemory for LinearMemoryProxy {
79 fn byte_size(&self) -> usize {
80 self.mem.byte_size()
81 }
82
83 fn byte_capacity(&self) -> usize {
84 self.mem.byte_capacity()
85 }
86
87 fn grow_to(&mut self, new_size: usize) -> Result<()> {
88 self.mem.grow_to(new_size)
89 }
90
91 fn base(&self) -> MemoryBase {
92 MemoryBase::new_raw(self.mem.as_ptr())
93 }
94}
95
96#[derive(Clone)]
97pub(crate) struct MemoryCreatorProxy(pub Arc<dyn MemoryCreator>);
98
99impl RuntimeMemoryCreator for MemoryCreatorProxy {
100 fn new_memory(
101 &self,
102 ty: &wasmtime_environ::Memory,
103 tunables: &Tunables,
104 minimum: usize,
105 maximum: Option<usize>,
106 ) -> Result<Box<dyn RuntimeLinearMemory>> {
107 let reserved_size_in_bytes = Some(tunables.memory_reservation.try_into().unwrap());
108 self.0
109 .new_memory(
110 MemoryType::from_wasmtime_memory(ty),
111 minimum,
112 maximum,
113 reserved_size_in_bytes,
114 usize::try_from(tunables.memory_guard_size).unwrap(),
115 )
116 .map(|mem| Box::new(LinearMemoryProxy { mem }) as Box<dyn RuntimeLinearMemory>)
117 .map_err(|e| anyhow!(e))
118 }
119}
120
121struct SingleMemoryInstance<'a> {
122 preallocation: Option<&'a SharedMemory>,
123 ondemand: OnDemandInstanceAllocator,
124}
125
126unsafe impl InstanceAllocatorImpl for SingleMemoryInstance<'_> {
127 #[cfg(feature = "component-model")]
128 fn validate_component_impl<'a>(
129 &self,
130 _component: &Component,
131 _offsets: &VMComponentOffsets<HostPtr>,
132 _get_module: &'a dyn Fn(StaticModuleIndex) -> &'a Module,
133 ) -> Result<()> {
134 unreachable!("`SingleMemoryInstance` allocator never used with components")
135 }
136
137 fn validate_module_impl(&self, module: &Module, offsets: &VMOffsets<HostPtr>) -> Result<()> {
138 anyhow::ensure!(
139 module.memories.len() == 1,
140 "`SingleMemoryInstance` allocator can only be used for modules with a single memory"
141 );
142 self.ondemand.validate_module_impl(module, offsets)?;
143 Ok(())
144 }
145
146 fn increment_component_instance_count(&self) -> Result<()> {
147 self.ondemand.increment_component_instance_count()
148 }
149
150 fn decrement_component_instance_count(&self) {
151 self.ondemand.decrement_component_instance_count();
152 }
153
154 fn increment_core_instance_count(&self) -> Result<()> {
155 self.ondemand.increment_core_instance_count()
156 }
157
158 fn decrement_core_instance_count(&self) {
159 self.ondemand.decrement_core_instance_count();
160 }
161
162 unsafe fn allocate_memory(
163 &self,
164 request: &mut InstanceAllocationRequest,
165 ty: &wasmtime_environ::Memory,
166 tunables: &Tunables,
167 memory_index: DefinedMemoryIndex,
168 ) -> Result<(MemoryAllocationIndex, Memory)> {
169 #[cfg(debug_assertions)]
170 {
171 let module = request.runtime_info.env_module();
172 let offsets = request.runtime_info.offsets();
173 self.validate_module_impl(module, offsets)
174 .expect("should have already validated the module before allocating memory");
175 }
176
177 match self.preallocation {
178 Some(shared_memory) => Ok((
179 MemoryAllocationIndex::default(),
180 shared_memory.clone().as_memory(),
181 )),
182 None => self
183 .ondemand
184 .allocate_memory(request, ty, tunables, memory_index),
185 }
186 }
187
188 unsafe fn deallocate_memory(
189 &self,
190 memory_index: DefinedMemoryIndex,
191 allocation_index: MemoryAllocationIndex,
192 memory: Memory,
193 ) {
194 self.ondemand
195 .deallocate_memory(memory_index, allocation_index, memory)
196 }
197
198 unsafe fn allocate_table(
199 &self,
200 req: &mut InstanceAllocationRequest,
201 ty: &wasmtime_environ::Table,
202 tunables: &Tunables,
203 table_index: DefinedTableIndex,
204 ) -> Result<(TableAllocationIndex, Table)> {
205 self.ondemand.allocate_table(req, ty, tunables, table_index)
206 }
207
208 unsafe fn deallocate_table(
209 &self,
210 table_index: DefinedTableIndex,
211 allocation_index: TableAllocationIndex,
212 table: Table,
213 ) {
214 self.ondemand
215 .deallocate_table(table_index, allocation_index, table)
216 }
217
218 #[cfg(feature = "async")]
219 fn allocate_fiber_stack(&self) -> Result<wasmtime_fiber::FiberStack> {
220 unreachable!()
221 }
222
223 #[cfg(feature = "async")]
224 unsafe fn deallocate_fiber_stack(&self, _stack: wasmtime_fiber::FiberStack) {
225 unreachable!()
226 }
227
228 fn purge_module(&self, _: CompiledModuleId) {
229 unreachable!()
230 }
231
232 fn next_available_pkey(&self) -> Option<ProtectionKey> {
233 unreachable!()
234 }
235
236 fn restrict_to_pkey(&self, _: ProtectionKey) {
237 unreachable!()
238 }
239
240 fn allow_all_pkeys(&self) {
241 unreachable!()
242 }
243
244 #[cfg(feature = "gc")]
245 fn allocate_gc_heap(
246 &self,
247 _gc_runtime: &dyn crate::runtime::vm::GcRuntime,
248 ) -> Result<(
249 crate::runtime::vm::GcHeapAllocationIndex,
250 Box<dyn crate::runtime::vm::GcHeap>,
251 )> {
252 unreachable!()
253 }
254
255 #[cfg(feature = "gc")]
256 fn deallocate_gc_heap(
257 &self,
258 _allocation_index: crate::runtime::vm::GcHeapAllocationIndex,
259 _gc_heap: Box<dyn crate::runtime::vm::GcHeap>,
260 ) {
261 unreachable!()
262 }
263}