Skip to main content

sp1_jit/
memory.rs

1use crate::{shm::ShmMemory, JitMemory, JitResetableMemory};
2use memmap2::{MmapMut, MmapOptions};
3use std::{
4    fs::File,
5    io,
6    ops::{Deref, DerefMut},
7    os::fd::AsRawFd,
8};
9
10/// JIT memory fulfilled using anonymous memory
11pub struct AnonymousMemory {
12    pub mem_fd: File,
13    pub memory: MmapMut,
14}
15
16impl AsRawFd for AnonymousMemory {
17    fn as_raw_fd(&self) -> i32 {
18        self.mem_fd.as_raw_fd()
19    }
20}
21
22impl Deref for AnonymousMemory {
23    type Target = [u8];
24
25    fn deref(&self) -> &<Self as Deref>::Target {
26        self.memory.deref()
27    }
28}
29
30impl DerefMut for AnonymousMemory {
31    fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
32        self.memory.deref_mut()
33    }
34}
35
36impl JitMemory for AnonymousMemory {
37    fn new(memory_size: usize) -> Self {
38        let file = create_anonymous_file(memory_size);
39
40        let memory = unsafe {
41            MmapOptions::new().no_reserve_swap().map_mut(&file).expect("Failed to call mmap")
42        };
43
44        Self { mem_fd: file, memory }
45    }
46}
47
48impl JitResetableMemory for AnonymousMemory {
49    fn reset(&mut self) {
50        // Store the original size of the memory.
51        let memory_size = self.memory.len();
52
53        // Create a new memfd for the backing memory.
54        self.mem_fd = create_anonymous_file(memory_size);
55
56        self.memory = unsafe {
57            MmapOptions::new()
58                .no_reserve_swap()
59                .map_mut(&self.mem_fd)
60                .expect("Failed to map memory")
61        };
62    }
63}
64
65#[cfg(target_os = "linux")]
66fn create_anonymous_file(size: usize) -> File {
67    let fd = memfd::MemfdOptions::default()
68        .create(uuid::Uuid::new_v4().to_string())
69        .expect("Failed to create jit memory");
70    let file = fd.into_file();
71    file.set_len(size as u64).expect("Faile to set length for jit memory");
72    file
73}
74
75#[cfg(target_os = "macos")]
76fn create_anonymous_file(size: usize) -> File {
77    use libc::{c_char, c_uint, ftruncate, shm_open, O_CREAT, O_RDWR, S_IRUSR, S_IWUSR};
78    use std::io;
79    use std::os::fd::FromRawFd;
80
81    // This is missing in libc, we have to manually define it.
82    const SHM_ANON: *const c_char = -1isize as *const c_char;
83
84    let fd = unsafe { shm_open(SHM_ANON, O_RDWR | O_CREAT, (S_IRUSR | S_IWUSR) as c_uint) };
85    if fd < 0 {
86        panic!("Error creating anonymous memory file: {}", io::Error::last_os_error());
87    }
88
89    let res = unsafe { ftruncate(fd, size as _) };
90    if res != 0 {
91        panic!("Error setting file size: {}", io::Error::last_os_error());
92    }
93
94    unsafe { File::from_raw_fd(fd) }
95}
96
97/// JIT memory fulfilled using shared memory
98pub struct SharedMemory {
99    handle: Option<ShmMemory>,
100}
101
102impl SharedMemory {
103    pub fn create_readonly(id: &str, memory_size: usize) -> io::Result<Self> {
104        Ok(Self { handle: Some(ShmMemory::create_readonly(id, memory_size)?) })
105    }
106
107    pub fn open_readwrite(&mut self, id: &str) -> io::Result<()> {
108        self.handle = Some(ShmMemory::open_readwrite(id)?);
109        Ok(())
110    }
111}
112
113impl AsRawFd for SharedMemory {
114    fn as_raw_fd(&self) -> i32 {
115        self.handle.as_ref().unwrap().as_raw_fd()
116    }
117}
118
119impl Deref for SharedMemory {
120    type Target = [u8];
121
122    fn deref(&self) -> &<Self as Deref>::Target {
123        self.handle.as_ref().unwrap().deref()
124    }
125}
126
127impl DerefMut for SharedMemory {
128    fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
129        self.handle.as_mut().unwrap().deref_mut()
130    }
131}
132
133impl JitMemory for SharedMemory {
134    fn new(_memory_size: usize) -> Self {
135        Self { handle: None }
136    }
137}