wasmer_runtime_core_fl/memory/
dynamic.rs

1use crate::error::GrowError;
2use crate::{
3    error::CreationError,
4    sys,
5    types::MemoryDescriptor,
6    units::{Bytes, Pages},
7    vm,
8};
9
10pub const DYNAMIC_GUARD_SIZE: usize = 4096;
11
12/// This is an internal-only api.
13///
14/// A Dynamic memory allocates only the minimum amount of memory
15/// when first created. Over time, as it grows, it may reallocate to
16/// a different location and size.
17///
18/// Dynamic memories are significantly faster to create than static
19/// memories and use much less virtual memory, however, they require
20/// the WebAssembly module to bounds-check memory accesses.
21///
22/// While, a dynamic memory could use a vector of some sort as its
23/// backing memory, we use mmap (or the platform-equivalent) to allow
24/// us to add a guard-page at the end to help elide some bounds-checks.
25pub struct DynamicMemory {
26    memory: sys::Memory,
27    current: Pages,
28    max: Option<Pages>,
29}
30
31impl DynamicMemory {
32    pub(super) fn new(
33        desc: MemoryDescriptor,
34        local: &mut vm::LocalMemory,
35    ) -> Result<Box<Self>, CreationError> {
36        let min_bytes: Bytes = desc.minimum.into();
37        let memory = {
38            let mut memory = sys::Memory::with_size(min_bytes.0 + DYNAMIC_GUARD_SIZE)
39                .map_err(|_| CreationError::UnableToCreateMemory)?;
40            if desc.minimum != Pages(0) {
41                unsafe {
42                    memory
43                        .protect(0..min_bytes.0, sys::Protect::ReadWrite)
44                        .map_err(|_| CreationError::UnableToCreateMemory)?;
45                }
46            }
47
48            memory
49        };
50
51        let mut storage = Box::new(DynamicMemory {
52            memory,
53            current: desc.minimum,
54            max: desc.maximum,
55        });
56        let storage_ptr: *mut DynamicMemory = &mut *storage;
57
58        local.base = storage.memory.as_ptr();
59        local.bound = min_bytes.0;
60        local.memory = storage_ptr as *mut ();
61
62        Ok(storage)
63    }
64
65    /// The size of this memory in `Pages`.
66    pub fn size(&self) -> Pages {
67        self.current
68    }
69
70    /// Try to grow self by the given number of delta pages.
71    pub fn grow(&mut self, delta: Pages, local: &mut vm::LocalMemory) -> Result<Pages, GrowError> {
72        if delta == Pages(0) {
73            return Ok(self.current);
74        }
75
76        let new_pages = self.current.checked_add(delta).map_err(|e| e.into())?;
77
78        if let Some(max) = self.max {
79            if new_pages > max {
80                return Err(GrowError::ExceededMaxPagesForMemory(
81                    new_pages.0 as usize,
82                    max.0 as usize,
83                ));
84            }
85        }
86
87        let mut new_memory = sys::Memory::with_size(new_pages.bytes().0 + DYNAMIC_GUARD_SIZE)
88            .map_err(|e| e.into())?;
89
90        unsafe {
91            new_memory
92                .protect(0..new_pages.bytes().0, sys::Protect::ReadWrite)
93                .map_err(|e| e.into())?;
94
95            new_memory.as_slice_mut()[..self.current.bytes().0]
96                .copy_from_slice(&self.memory.as_slice()[..self.current.bytes().0]);
97        }
98
99        self.memory = new_memory; //The old memory gets dropped.
100
101        local.base = self.memory.as_ptr();
102        local.bound = new_pages.bytes().0;
103
104        let old_pages = self.current;
105        self.current = new_pages;
106        Ok(old_pages)
107    }
108
109    /// Get this memory represented as a slice of bytes.
110    pub fn as_slice(&self) -> &[u8] {
111        unsafe { &self.memory.as_slice()[0..self.current.bytes().0] }
112    }
113
114    /// Get this memory represented as a mutable slice of bytes
115    pub fn as_slice_mut(&mut self) -> &mut [u8] {
116        unsafe { &mut self.memory.as_slice_mut()[0..self.current.bytes().0] }
117    }
118}