cranelift_jit/memory/
system.rs1use std::io;
2use std::mem;
3use std::ptr;
4
5use cranelift_module::{ModuleError, ModuleResult};
6use memmap2::MmapMut;
7
8use super::{BranchProtection, JITMemoryKind, JITMemoryProvider};
9
10struct PtrLen {
12 map: Option<MmapMut>,
13 ptr: *mut u8,
14 len: usize,
15}
16
17impl PtrLen {
18 fn new() -> Self {
20 Self {
21 map: None,
22 ptr: ptr::null_mut(),
23 len: 0,
24 }
25 }
26
27 fn with_size(size: usize) -> io::Result<Self> {
30 let alloc_size = region::page::ceil(size as *const ()) as usize;
31 MmapMut::map_anon(alloc_size).map(|mut mmap| {
32 Self {
35 ptr: mmap.as_mut_ptr(),
36 map: Some(mmap),
37 len: alloc_size,
38 }
39 })
40 }
41}
42
43pub(crate) struct Memory {
48 allocations: Vec<PtrLen>,
49 already_protected: usize,
50 current: PtrLen,
51 position: usize,
52}
53
54unsafe impl Send for Memory {}
55
56impl Memory {
57 pub(crate) fn new() -> Self {
58 Self {
59 allocations: Vec::new(),
60 already_protected: 0,
61 current: PtrLen::new(),
62 position: 0,
63 }
64 }
65
66 fn finish_current(&mut self) {
67 self.allocations
68 .push(mem::replace(&mut self.current, PtrLen::new()));
69 self.position = 0;
70 }
71
72 pub(crate) fn allocate(&mut self, size: usize, align: u64) -> io::Result<*mut u8> {
73 let align = usize::try_from(align).expect("alignment too big");
74 if self.position % align != 0 {
75 self.position += align - self.position % align;
76 debug_assert!(self.position % align == 0);
77 }
78
79 if size <= self.current.len - self.position {
80 let ptr = unsafe { self.current.ptr.add(self.position) };
82 self.position += size;
83 return Ok(ptr);
84 }
85
86 self.finish_current();
87
88 self.current = PtrLen::with_size(size)?;
90 self.position = size;
91
92 Ok(self.current.ptr)
93 }
94
95 pub(crate) fn set_readable_and_executable(
97 &mut self,
98 branch_protection: BranchProtection,
99 ) -> ModuleResult<()> {
100 self.finish_current();
101
102 for &PtrLen { ptr, len, .. } in self.non_protected_allocations_iter() {
103 super::set_readable_and_executable(ptr, len, branch_protection)?;
104 }
105
106 wasmtime_jit_icache_coherence::pipeline_flush_mt().expect("Failed pipeline flush");
108
109 self.already_protected = self.allocations.len();
110 Ok(())
111 }
112
113 pub(crate) fn set_readonly(&mut self) -> ModuleResult<()> {
115 self.finish_current();
116
117 for &PtrLen { ptr, len, .. } in self.non_protected_allocations_iter() {
118 unsafe {
119 region::protect(ptr, len, region::Protection::READ).map_err(|e| {
120 ModuleError::Backend(
121 anyhow::Error::new(e).context("unable to make memory readonly"),
122 )
123 })?;
124 }
125 }
126
127 self.already_protected = self.allocations.len();
128 Ok(())
129 }
130
131 fn non_protected_allocations_iter(&self) -> impl Iterator<Item = &PtrLen> {
133 self.allocations[self.already_protected..]
134 .iter()
135 .filter(|&PtrLen { map, len, .. }| *len != 0 && map.is_some())
136 }
137
138 pub(crate) unsafe fn free_memory(&mut self) {
141 self.allocations.clear();
142 self.already_protected = 0;
143 }
144}
145
146impl Drop for Memory {
147 fn drop(&mut self) {
148 mem::replace(&mut self.allocations, Vec::new())
150 .into_iter()
151 .for_each(mem::forget);
152 }
153}
154
155pub struct SystemMemoryProvider {
162 code: Memory,
163 readonly: Memory,
164 writable: Memory,
165}
166
167impl SystemMemoryProvider {
168 pub fn new() -> Self {
170 Self {
171 code: Memory::new(),
172 readonly: Memory::new(),
173 writable: Memory::new(),
174 }
175 }
176}
177
178impl JITMemoryProvider for SystemMemoryProvider {
179 unsafe fn free_memory(&mut self) {
180 self.code.free_memory();
181 self.readonly.free_memory();
182 self.writable.free_memory();
183 }
184
185 fn finalize(&mut self, branch_protection: BranchProtection) -> ModuleResult<()> {
186 self.readonly.set_readonly()?;
187 self.code.set_readable_and_executable(branch_protection)
188 }
189
190 fn allocate(&mut self, size: usize, align: u64, kind: JITMemoryKind) -> io::Result<*mut u8> {
191 match kind {
192 JITMemoryKind::Executable => self.code.allocate(size, align),
193 JITMemoryKind::Writable => self.writable.allocate(size, align),
194 JITMemoryKind::ReadOnly => self.readonly.allocate(size, align),
195 }
196 }
197}