Skip to main content

wasmer_compiler/engine/
tunables.rs

1use crate::engine::error::LinkError;
2use std::ptr::NonNull;
3use wasmer_types::{
4    FunctionType, GlobalType, LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex, MemoryIndex,
5    MemoryType, ModuleInfo, TableIndex, TableType, TagKind, entity::PrimaryMap,
6};
7use wasmer_vm::{InternalStoreHandle, MemoryError, StoreObjects, VMTag};
8use wasmer_vm::{MemoryStyle, TableStyle};
9use wasmer_vm::{VMConfig, VMGlobal, VMGlobalDefinition, VMMemory, VMTable};
10use wasmer_vm::{VMMemoryDefinition, VMTableDefinition};
11
12/// An engine delegates the creation of memories, tables, and globals
13/// to a foreign implementor of this trait.
14pub trait Tunables {
15    /// Construct a `MemoryStyle` for the provided `MemoryType`
16    fn memory_style(&self, memory: &MemoryType) -> MemoryStyle;
17
18    /// Construct a `TableStyle` for the provided `TableType`
19    fn table_style(&self, table: &TableType) -> TableStyle;
20
21    /// Create a memory owned by the host given a [`MemoryType`] and a [`MemoryStyle`].
22    fn create_host_memory(
23        &self,
24        ty: &MemoryType,
25        style: &MemoryStyle,
26    ) -> Result<VMMemory, MemoryError>;
27
28    /// Create a memory owned by the VM given a [`MemoryType`] and a [`MemoryStyle`].
29    ///
30    /// # Safety
31    /// - `vm_definition_location` must point to a valid location in VM memory.
32    unsafe fn create_vm_memory(
33        &self,
34        ty: &MemoryType,
35        style: &MemoryStyle,
36        vm_definition_location: NonNull<VMMemoryDefinition>,
37    ) -> Result<VMMemory, MemoryError>;
38
39    /// Create a table owned by the host given a [`TableType`] and a [`TableStyle`].
40    fn create_host_table(&self, ty: &TableType, style: &TableStyle) -> Result<VMTable, String>;
41
42    /// Create a table owned by the VM given a [`TableType`] and a [`TableStyle`].
43    ///
44    /// # Safety
45    /// - `vm_definition_location` must point to a valid location in VM memory.
46    unsafe fn create_vm_table(
47        &self,
48        ty: &TableType,
49        style: &TableStyle,
50        vm_definition_location: NonNull<VMTableDefinition>,
51    ) -> Result<VMTable, String>;
52
53    /// Create a global with an unset value.
54    fn create_global(&self, ty: GlobalType) -> Result<VMGlobal, String> {
55        Ok(VMGlobal::new(ty))
56    }
57
58    /// Create a global owned by the VM with backing storage in the `VMContext`.
59    ///
60    /// # Safety
61    /// - `vm_definition_location` must point to a valid location in VM memory.
62    unsafe fn create_vm_global(
63        &self,
64        ty: GlobalType,
65        vm_definition_location: NonNull<VMGlobalDefinition>,
66    ) -> Result<VMGlobal, String> {
67        unsafe { Ok(VMGlobal::new_instance(ty, vm_definition_location)) }
68    }
69
70    /// Create a new tag.
71    fn create_tag(&self, kind: TagKind, ty: FunctionType) -> Result<VMTag, String> {
72        Ok(VMTag::new(kind, ty))
73    }
74
75    /// Allocate memory for just the memories of the current module.
76    ///
77    /// # Safety
78    /// - `memory_definition_locations` must point to a valid locations in VM memory.
79    #[allow(clippy::result_large_err)]
80    unsafe fn create_memories(
81        &self,
82        context: &mut StoreObjects,
83        module: &ModuleInfo,
84        memory_styles: &PrimaryMap<MemoryIndex, MemoryStyle>,
85        memory_definition_locations: &[NonNull<VMMemoryDefinition>],
86    ) -> Result<PrimaryMap<LocalMemoryIndex, InternalStoreHandle<VMMemory>>, LinkError> {
87        unsafe {
88            let num_imports = module.num_imported_memories;
89            let mut memories: PrimaryMap<LocalMemoryIndex, _> =
90                PrimaryMap::with_capacity(module.memories.len() - num_imports);
91            for ((mi, ty), mdl) in module
92                .memories
93                .iter()
94                .skip(num_imports)
95                .zip(memory_definition_locations)
96            {
97                let style = &memory_styles[mi];
98                memories.push(InternalStoreHandle::new(
99                    context,
100                    self.create_vm_memory(ty, style, *mdl).map_err(|e| {
101                        LinkError::Resource(format!("Failed to create memory: {e}"))
102                    })?,
103                ));
104            }
105            Ok(memories)
106        }
107    }
108
109    /// Allocate memory for just the tables of the current module.
110    ///
111    /// # Safety
112    ///
113    /// To be done
114    #[allow(clippy::result_large_err)]
115    unsafe fn create_tables(
116        &self,
117        context: &mut StoreObjects,
118        module: &ModuleInfo,
119        table_styles: &PrimaryMap<TableIndex, TableStyle>,
120        table_definition_locations: &[NonNull<VMTableDefinition>],
121    ) -> Result<PrimaryMap<LocalTableIndex, InternalStoreHandle<VMTable>>, LinkError> {
122        unsafe {
123            let num_imports = module.num_imported_tables;
124            let mut tables: PrimaryMap<LocalTableIndex, _> =
125                PrimaryMap::with_capacity(module.tables.len() - num_imports);
126            for ((ti, ty), tdl) in module
127                .tables
128                .iter()
129                .skip(num_imports)
130                .zip(table_definition_locations)
131            {
132                let style = &table_styles[ti];
133                tables.push(InternalStoreHandle::new(
134                    context,
135                    self.create_vm_table(ty, style, *tdl)
136                        .map_err(LinkError::Resource)?,
137                ));
138            }
139            Ok(tables)
140        }
141    }
142
143    /// Allocate memory for just the globals of the current module,
144    /// with initializers applied.
145    #[allow(clippy::result_large_err)]
146    fn create_globals(
147        &self,
148        context: &mut StoreObjects,
149        module: &ModuleInfo,
150        vm_definition_locations: &[NonNull<VMGlobalDefinition>],
151    ) -> Result<PrimaryMap<LocalGlobalIndex, InternalStoreHandle<VMGlobal>>, LinkError> {
152        let num_imports = module.num_imported_globals;
153        let mut vmctx_globals = PrimaryMap::with_capacity(module.globals.len() - num_imports);
154
155        for (i, &global_type) in module.globals.values().skip(num_imports).enumerate() {
156            let location = vm_definition_locations
157                .get(i)
158                .ok_or_else(|| LinkError::Resource("global definition location missing".into()))?;
159            vmctx_globals.push(InternalStoreHandle::new(context, unsafe {
160                self.create_vm_global(global_type, *location)
161                    .map_err(LinkError::Resource)?
162            }));
163        }
164
165        Ok(vmctx_globals)
166    }
167
168    /// Get the VMConfig for this tunables
169    /// Currently, VMConfig have optional Stack size
170    /// If wasm_stack_size is left to None (the default value)
171    /// then the global stack size will be use
172    /// Else the defined stack size will be used. Size is in byte
173    /// and the value might be rounded to sane value is needed.
174    fn vmconfig(&self) -> &VMConfig {
175        &VMConfig {
176            wasm_stack_size: None,
177        }
178    }
179}
180
181/// Tunable parameters for WebAssembly compilation.
182/// This is the reference implementation of the `Tunables` trait,
183/// used by default.
184///
185/// You can use this as a template for creating a custom Tunables
186/// implementation or use composition to wrap your Tunables around
187/// this one. The later approach is demonstrated in the
188/// tunables-limit-memory example.
189#[derive(Clone, Default)]
190pub struct BaseTunables {}
191
192impl BaseTunables {
193    /// Get the default `BaseTunables`.
194    pub fn new() -> Self {
195        Self {}
196    }
197}
198
199impl Tunables for BaseTunables {
200    /// Always return Static memory style.
201    fn memory_style(&self, _memory: &MemoryType) -> MemoryStyle {
202        MemoryStyle::Static
203    }
204
205    /// Get a [`TableStyle`] for the provided [`TableType`].
206    fn table_style(&self, _table: &TableType) -> TableStyle {
207        TableStyle::CallerChecksSignature
208    }
209
210    /// Create a memory owned by the host given a [`MemoryType`] and a [`MemoryStyle`].
211    fn create_host_memory(
212        &self,
213        ty: &MemoryType,
214        style: &MemoryStyle,
215    ) -> Result<VMMemory, MemoryError> {
216        VMMemory::new(ty, style)
217    }
218
219    /// Create a memory owned by the VM given a [`MemoryType`] and a [`MemoryStyle`].
220    ///
221    /// # Safety
222    /// - `vm_definition_location` must point to a valid, owned `VMMemoryDefinition`,
223    ///   for example in `VMContext`.
224    unsafe fn create_vm_memory(
225        &self,
226        ty: &MemoryType,
227        style: &MemoryStyle,
228        vm_definition_location: NonNull<VMMemoryDefinition>,
229    ) -> Result<VMMemory, MemoryError> {
230        unsafe { VMMemory::from_definition(ty, style, vm_definition_location) }
231    }
232
233    /// Create a table owned by the host given a [`TableType`] and a [`TableStyle`].
234    fn create_host_table(&self, ty: &TableType, style: &TableStyle) -> Result<VMTable, String> {
235        VMTable::new(ty, style)
236    }
237
238    /// Create a table owned by the VM given a [`TableType`] and a [`TableStyle`].
239    ///
240    /// # Safety
241    /// - `vm_definition_location` must point to a valid, owned `VMTableDefinition`,
242    ///   for example in `VMContext`.
243    unsafe fn create_vm_table(
244        &self,
245        ty: &TableType,
246        style: &TableStyle,
247        vm_definition_location: NonNull<VMTableDefinition>,
248    ) -> Result<VMTable, String> {
249        unsafe { VMTable::from_definition(ty, style, vm_definition_location) }
250    }
251}
252
253impl Tunables for Box<dyn Tunables + Send + Sync> {
254    fn memory_style(&self, memory: &MemoryType) -> MemoryStyle {
255        self.as_ref().memory_style(memory)
256    }
257
258    fn table_style(&self, table: &TableType) -> TableStyle {
259        self.as_ref().table_style(table)
260    }
261
262    fn create_host_memory(
263        &self,
264        ty: &MemoryType,
265        style: &MemoryStyle,
266    ) -> Result<VMMemory, MemoryError> {
267        self.as_ref().create_host_memory(ty, style)
268    }
269
270    unsafe fn create_vm_memory(
271        &self,
272        ty: &MemoryType,
273        style: &MemoryStyle,
274        vm_definition_location: NonNull<VMMemoryDefinition>,
275    ) -> Result<VMMemory, MemoryError> {
276        unsafe {
277            self.as_ref()
278                .create_vm_memory(ty, style, vm_definition_location)
279        }
280    }
281
282    fn create_host_table(&self, ty: &TableType, style: &TableStyle) -> Result<VMTable, String> {
283        self.as_ref().create_host_table(ty, style)
284    }
285
286    unsafe fn create_vm_table(
287        &self,
288        ty: &TableType,
289        style: &TableStyle,
290        vm_definition_location: NonNull<VMTableDefinition>,
291    ) -> Result<VMTable, String> {
292        unsafe {
293            self.as_ref()
294                .create_vm_table(ty, style, vm_definition_location)
295        }
296    }
297}
298
299impl Tunables for std::sync::Arc<dyn Tunables + Send + Sync> {
300    fn memory_style(&self, memory: &MemoryType) -> MemoryStyle {
301        self.as_ref().memory_style(memory)
302    }
303
304    fn table_style(&self, table: &TableType) -> TableStyle {
305        self.as_ref().table_style(table)
306    }
307
308    fn create_host_memory(
309        &self,
310        ty: &MemoryType,
311        style: &MemoryStyle,
312    ) -> Result<VMMemory, MemoryError> {
313        self.as_ref().create_host_memory(ty, style)
314    }
315
316    unsafe fn create_vm_memory(
317        &self,
318        ty: &MemoryType,
319        style: &MemoryStyle,
320        vm_definition_location: NonNull<VMMemoryDefinition>,
321    ) -> Result<VMMemory, MemoryError> {
322        unsafe {
323            self.as_ref()
324                .create_vm_memory(ty, style, vm_definition_location)
325        }
326    }
327
328    fn create_host_table(&self, ty: &TableType, style: &TableStyle) -> Result<VMTable, String> {
329        self.as_ref().create_host_table(ty, style)
330    }
331
332    unsafe fn create_vm_table(
333        &self,
334        ty: &TableType,
335        style: &TableStyle,
336        vm_definition_location: NonNull<VMTableDefinition>,
337    ) -> Result<VMTable, String> {
338        unsafe {
339            self.as_ref()
340                .create_vm_table(ty, style, vm_definition_location)
341        }
342    }
343}