1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
use crate::{
    error::{ExportError, MemoryError},
    get_global_store, new,
    types::ValueType,
    units::Pages,
};

pub mod ptr {
    pub use crate::new::wasmer::{Array, Item, WasmPtr};
}

pub use new::wasmer_types::MemoryType as MemoryDescriptor;
pub use new::wasmer::{Atomically, MemoryView};
pub use new::wasmer_vm::MemoryStyle as MemoryType;

/// A Wasm linear memory.
///
/// A `Memory` represents the memory used by a Wasm instance.
#[derive(Clone)]
pub struct Memory {
    new_memory: new::wasmer::Memory,
}

impl Memory {
    /// Create a new `Memory` from a [`MemoryDescriptor`]
    ///
    /// [`MemoryDescriptor`]: struct.MemoryDescriptor.html
    ///
    /// Usage:
    ///
    /// ```
    /// # use wasmer_runtime_core::{types::MemoryDescriptor, error::MemoryError, memory::Memory, units::Pages};
    /// fn create_memory() -> Result<(), MemoryError> {
    ///     let descriptor = MemoryDescriptor::new(Pages(10), None, false);
    ///
    ///     let memory = Memory::new(descriptor)?;
    ///     Ok(())
    /// }
    /// ```
    pub fn new(descriptor: MemoryDescriptor) -> Result<Self, MemoryError> {
        Ok(Memory {
            new_memory: new::wasmer::Memory::new(&get_global_store(), descriptor)?,
        })
    }

    /// Return the [`MemoryDescriptor`] that this memory
    /// was created with.
    ///
    /// [`MemoryDescriptor`]: struct.MemoryDescriptor.html
    pub fn descriptor(&self) -> MemoryDescriptor {
        self.new_memory.ty().clone()
    }

    /// Grow this memory by the specified number of pages.
    pub fn grow(&self, delta: Pages) -> Result<Pages, MemoryError> {
        self.new_memory.grow(delta)
    }

    /// The size, in wasm pages, of this memory.
    pub fn size(&self) -> Pages {
        self.new_memory.size()
    }

    /// Return a "view" of the currently accessible memory. By
    /// default, the view is unsynchronized, using regular memory
    /// accesses. You can force a memory view to use atomic accesses
    /// by calling the [`atomically`] method.
    ///
    /// [`atomically`]: struct.MemoryView.html#method.atomically
    ///
    /// # Notes
    ///
    /// This method is safe (as in, it won't cause the host to crash or have UB),
    /// but it doesn't obey rust's rules involving data races, especially concurrent ones.
    /// Therefore, if this memory is shared between multiple threads, a single memory
    /// location can be mutated concurrently without synchronization.
    ///
    /// # Usage
    ///
    /// ```
    /// # use wasmer_runtime_core::memory::{Memory, MemoryView};
    /// # use std::{cell::Cell, sync::atomic::Ordering};
    /// # fn view_memory(memory: Memory) {
    /// // Without synchronization.
    /// let view: MemoryView<u8> = memory.view();
    /// for byte in view[0x1000 .. 0x1010].iter().map(Cell::get) {
    ///     println!("byte: {}", byte);
    /// }
    ///
    /// // With synchronization.
    /// let atomic_view = view.atomically();
    /// for byte in atomic_view[0x1000 .. 0x1010].iter().map(|atom| atom.load(Ordering::SeqCst)) {
    ///     println!("byte: {}", byte);
    /// }
    /// # }
    /// ```
    pub fn view<T: ValueType>(&self) -> MemoryView<T> {
        self.new_memory.view()
    }
}

impl From<&new::wasmer::Memory> for Memory {
    fn from(new_memory: &new::wasmer::Memory) -> Self {
        Self {
            new_memory: new_memory.clone(),
        }
    }
}

impl<'a> new::wasmer::Exportable<'a> for Memory {
    fn to_export(&self) -> new::wasmer_vm::Export {
        self.new_memory.to_export()
    }

    fn get_self_from_extern(r#extern: &'a new::wasmer::Extern) -> Result<&'a Self, ExportError> {
        match r#extern {
            new::wasmer::Extern::Memory(memory) => Ok(
                // It's not ideal to call `Box::leak` here, but it
                // would introduce too much changes in the
                // `new::wasmer` API to support `Cow` or similar.
                Box::leak(Box::<Memory>::new(memory.into())),
            ),
            _ => Err(ExportError::IncompatibleType),
        }
    }
}

#[cfg(test)]
mod memory_tests {
    use super::{Memory, MemoryDescriptor, Pages};

    #[test]
    fn test_initial_memory_size() {
        let memory_desc = MemoryDescriptor::new(Pages(10), Some(Pages(20)), false);
        let unshared_memory = Memory::new(memory_desc).unwrap();

        assert_eq!(unshared_memory.size(), Pages(10));
    }
}