Skip to main content

wasmer_types/
memory.rs

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