Skip to main content

wasmer_types/
memory.rs

1use crate::{Pages, ValueType, WASM_PAGE_SIZE};
2use core::ops::SubAssign;
3use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
4#[cfg(feature = "enable-serde")]
5use serde::{Deserialize, Serialize};
6use std::convert::{TryFrom, TryInto};
7use std::iter::Sum;
8use std::ops::{Add, AddAssign};
9
10/// Implementation styles for WebAssembly linear memory.
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, RkyvSerialize, RkyvDeserialize, Archive)]
12#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
13#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
14#[rkyv(derive(Debug), compare(PartialEq))]
15#[repr(u8)]
16pub enum MemoryStyle {
17    /// The actual memory can be resized and moved.
18    Dynamic {
19        /// Our chosen offset-guard size.
20        ///
21        /// It represents the size in bytes of extra guard pages after the end
22        /// to optimize loads and stores with constant offsets.
23        offset_guard_size: u64,
24    },
25    /// Address space is allocated up front.
26    ///
27    /// Static memories reserve 8 GiB (plus one extra page) of virtual address space at runtime:
28    /// the 4 GiB wasm32 address space plus a 4 GiB offset guard. This lets generated
29    /// code omit bounds checks while still relying on protected virtual memory
30    /// to trap out-of-bounds accesses.
31    Static,
32}
33
34impl MemoryStyle {
35    /// Static memory reserves the wasm32 address space up front.
36    pub const fn static_bound() -> Pages {
37        Pages::max_value()
38    }
39
40    /// Static memory reserves an additional 4 GiB offset guard
41    /// (plus one extra page as one can access up to 16B at the effective address).
42    pub const fn static_offset_guard_size() -> u64 {
43        0x1_0000_0000 + WASM_PAGE_SIZE as u64
44    }
45
46    /// Returns the offset-guard size.
47    pub fn offset_guard_size(&self) -> u64 {
48        match self {
49            Self::Dynamic { offset_guard_size } => *offset_guard_size,
50            Self::Static => Self::static_offset_guard_size(),
51        }
52    }
53}
54
55/// Trait for the `Memory32` and `Memory64` marker types.
56///
57/// This allows code to be generic over 32-bit and 64-bit memories.
58/// # Safety
59/// Direct memory access is unsafe
60pub unsafe trait MemorySize: Copy {
61    /// Type used to represent an offset into a memory. This is `u32` or `u64`.
62    type Offset: Default
63        + std::fmt::Debug
64        + std::fmt::Display
65        + Eq
66        + Ord
67        + PartialEq<Self::Offset>
68        + PartialOrd<Self::Offset>
69        + Clone
70        + Copy
71        + Sync
72        + Send
73        + ValueType
74        + Into<u64>
75        + From<u32>
76        + From<u16>
77        + From<u8>
78        + TryFrom<u64>
79        + TryFrom<u32>
80        + TryFrom<u16>
81        + TryFrom<u8>
82        + TryFrom<i32>
83        + TryInto<usize>
84        + TryInto<u64>
85        + TryInto<u32>
86        + TryInto<u16>
87        + TryInto<u8>
88        + TryInto<i32>
89        + TryFrom<usize>
90        + Add<Self::Offset>
91        + Sum<Self::Offset>
92        + AddAssign<Self::Offset>
93        + SubAssign<Self::Offset>
94        + 'static;
95
96    /// Type used to pass this value as an argument or return value for a Wasm function.
97    type Native: super::NativeWasmType;
98
99    /// Zero value used for `WasmPtr::is_null`.
100    const ZERO: Self::Offset;
101
102    /// One value used for counting.
103    const ONE: Self::Offset;
104
105    /// Convert an `Offset` to a `Native`.
106    fn offset_to_native(offset: Self::Offset) -> Self::Native;
107
108    /// Convert a `Native` to an `Offset`.
109    fn native_to_offset(native: Self::Native) -> Self::Offset;
110
111    /// True if the memory is 64-bit
112    fn is_64bit() -> bool;
113}
114
115/// Marker trait for 32-bit memories.
116#[derive(Clone, Copy)]
117pub struct Memory32;
118unsafe impl MemorySize for Memory32 {
119    type Offset = u32;
120    type Native = i32;
121    const ZERO: Self::Offset = 0;
122    const ONE: Self::Offset = 1;
123    fn offset_to_native(offset: Self::Offset) -> Self::Native {
124        offset as Self::Native
125    }
126    fn native_to_offset(native: Self::Native) -> Self::Offset {
127        native as Self::Offset
128    }
129    fn is_64bit() -> bool {
130        false
131    }
132}
133
134/// Marker trait for 64-bit memories.
135#[derive(Clone, Copy)]
136pub struct Memory64;
137unsafe impl MemorySize for Memory64 {
138    type Offset = u64;
139    type Native = i64;
140    const ZERO: Self::Offset = 0;
141    const ONE: Self::Offset = 1;
142    fn offset_to_native(offset: Self::Offset) -> Self::Native {
143        offset as Self::Native
144    }
145    fn native_to_offset(native: Self::Native) -> Self::Offset {
146        native as Self::Offset
147    }
148    fn is_64bit() -> bool {
149        true
150    }
151}