1#[allow(unused_imports)]
10use core::ops::Deref;
11
12#[derive(Debug)]
15pub struct JitAllocError;
16
17#[derive(Debug, Clone, Copy, Eq, PartialEq)]
19pub enum ProtectJitAccess {
20 ReadWrite = 0,
22 ReadExecute = 1,
24}
25
26pub trait JitAlloc {
31 fn alloc(&self, size: usize) -> Result<(*const u8, *mut u8), JitAllocError>;
35
36 unsafe fn release(&self, rx_ptr: *const u8) -> Result<(), JitAllocError>;
44
45 unsafe fn protect_jit_memory(&self, ptr: *const u8, size: usize, access: ProtectJitAccess);
55
56 unsafe fn flush_instruction_cache(&self, rx_ptr: *const u8, size: usize);
64}
65
66impl<J: JitAlloc, D: Deref<Target = J>> JitAlloc for D {
67 fn alloc(&self, size: usize) -> Result<(*const u8, *mut u8), JitAllocError> {
68 (**self).alloc(size)
69 }
70
71 unsafe fn release(&self, rx_ptr: *const u8) -> Result<(), JitAllocError> {
72 (**self).release(rx_ptr)
73 }
74
75 #[inline(always)]
76 unsafe fn flush_instruction_cache(&self, rx_ptr: *const u8, size: usize) {
77 (**self).flush_instruction_cache(rx_ptr, size);
78 }
79
80 #[inline(always)]
81 unsafe fn protect_jit_memory(&self, ptr: *const u8, size: usize, access: ProtectJitAccess) {
82 (**self).protect_jit_memory(ptr, size, access);
83 }
84}
85
86#[cfg(feature = "global_jit_alloc")]
87#[derive(Default, Clone, Copy)]
96pub struct GlobalJitAlloc;
97
98#[cfg(feature = "default_jit_alloc")]
99mod default_jit_alloc {
100 use jit_allocator2::JitAllocator;
101
102 use super::*;
103
104 #[inline(always)]
105 fn convert_access(access: ProtectJitAccess) -> jit_allocator2::ProtectJitAccess {
106 match access {
107 ProtectJitAccess::ReadExecute => jit_allocator2::ProtectJitAccess::ReadExecute,
108 ProtectJitAccess::ReadWrite => jit_allocator2::ProtectJitAccess::ReadWrite,
109 }
110 }
111
112 fn flush_instruction_cache(rx_ptr: *const u8, size: usize) {
113 #[cfg(all(target_arch = "arm", target_os = "linux"))]
114 unsafe {
115 const __ARM_NR_CACHEFLUSH: i32 = 0x0f0002;
116 libc::syscall(__ARM_NR_CACHEFLUSH, rx_ptr, rx_ptr.byte_add(size), 0);
117 return;
118 }
119 #[allow(unreachable_code)]
120 jit_allocator2::flush_instruction_cache(rx_ptr, size);
121 }
122
123 #[cfg(not(feature = "std"))]
124 static GLOBAL_JIT_ALLOC: spin::Mutex<Option<alloc::boxed::Box<JitAllocator>>> =
125 spin::Mutex::new(None);
126 #[cfg(feature = "std")]
127 static GLOBAL_JIT_ALLOC: std::sync::Mutex<Option<alloc::boxed::Box<JitAllocator>>> =
128 std::sync::Mutex::new(None);
129
130 impl super::GlobalJitAlloc {
131 fn use_alloc<T>(&self, action: impl FnOnce(&mut JitAllocator) -> T) -> T {
132 #[cfg(not(feature = "std"))]
133 let mut maybe_alloc = GLOBAL_JIT_ALLOC.lock();
134 #[cfg(feature = "std")]
135 let mut maybe_alloc = GLOBAL_JIT_ALLOC.lock().unwrap();
136
137 let alloc = maybe_alloc.get_or_insert_with(|| JitAllocator::new(Default::default()));
138 action(alloc)
139 }
140 }
141
142 #[cfg_attr(docsrs, doc(cfg(feature = "global_jit_alloc")))]
143 impl JitAlloc for super::GlobalJitAlloc {
144 fn alloc(&self, size: usize) -> Result<(*const u8, *mut u8), JitAllocError> {
145 self.use_alloc(|a| a.alloc(size)).map_err(|_| JitAllocError)
146 }
147
148 unsafe fn release(&self, rx_ptr: *const u8) -> Result<(), JitAllocError> {
149 self.use_alloc(|a| a.release(rx_ptr)).map_err(|_| JitAllocError)
150 }
151
152 #[inline(always)]
153 unsafe fn flush_instruction_cache(&self, rx_ptr: *const u8, size: usize) {
154 flush_instruction_cache(rx_ptr, size);
155 }
156
157 #[inline(always)]
158 unsafe fn protect_jit_memory(
159 &self,
160 _ptr: *const u8,
161 _size: usize,
162 access: ProtectJitAccess,
163 ) {
164 jit_allocator2::protect_jit_memory(convert_access(access));
165 }
166 }
167
168 #[cfg(feature = "std")]
169 pub(super) mod thread_jit_alloc {
170 use core::{cell::UnsafeCell, marker::PhantomData};
171 use std::{boxed::Box, thread_local};
172
173 use jit_allocator2::JitAllocator;
174
175 #[allow(unused_imports)]
176 use super::*;
177
178 thread_local! {
179 static THREAD_JIT_ALLOC: UnsafeCell<Box<JitAllocator>> =
180 UnsafeCell::new(JitAllocator::new(Default::default()));
181 }
182
183 #[derive(Default, Clone)]
187 pub struct ThreadJitAlloc(PhantomData<*mut ()>);
188
189 impl JitAlloc for ThreadJitAlloc {
190 fn alloc(&self, size: usize) -> Result<(*const u8, *mut u8), JitAllocError> {
191 THREAD_JIT_ALLOC
192 .with(|a| unsafe { &mut *a.get() }.alloc(size))
193 .map_err(|_| JitAllocError)
194 }
195
196 unsafe fn release(&self, rx_ptr: *const u8) -> Result<(), JitAllocError> {
197 THREAD_JIT_ALLOC
198 .with(|a| unsafe { &mut *a.get() }.release(rx_ptr))
199 .map_err(|_| JitAllocError)
200 }
201
202 #[inline(always)]
203 unsafe fn flush_instruction_cache(&self, rx_ptr: *const u8, size: usize) {
204 flush_instruction_cache(rx_ptr, size);
205 }
206
207 #[inline(always)]
208 unsafe fn protect_jit_memory(
209 &self,
210 _ptr: *const u8,
211 _size: usize,
212 access: ProtectJitAccess,
213 ) {
214 jit_allocator2::protect_jit_memory(convert_access(access));
215 }
216 }
217 }
218}
219#[cfg(all(feature = "default_jit_alloc", feature = "std"))]
220#[doc(inline)]
221pub use default_jit_alloc::thread_jit_alloc::ThreadJitAlloc;
222
223#[macro_export]
245#[cfg(any(
246 docsrs,
247 all(feature = "global_jit_alloc", not(feature = "default_jit_alloc")),
248))]
249#[cfg_attr(
250 docsrs,
251 doc(cfg(all(feature = "global_jit_alloc", not(feature = "default_jit_alloc"))))
252)]
253macro_rules! global_jit_alloc {
254 (unsafe $provider:block) => {
255 #[no_mangle]
256 extern "Rust" fn _closure_ffi_3_global_jit_alloc(
257 ) -> &'static (dyn $crate::jit_alloc::JitAlloc + Sync) {
258 unsafe { $provider }
259 }
260 };
261 ($static_var:path) => {
262 #[no_mangle]
263 extern "Rust" fn _closure_ffi_3_global_jit_alloc(
264 ) -> &'static (dyn $crate::jit_alloc::JitAlloc + Sync) {
265 &$static_var
266 }
267 };
268}
269#[cfg(any(
270 docsrs,
271 all(feature = "global_jit_alloc", not(feature = "default_jit_alloc"))
272))]
273#[cfg_attr(
274 docsrs,
275 doc(cfg(all(feature = "global_jit_alloc", not(feature = "default_jit_alloc"))))
276)]
277pub use global_jit_alloc;
278
279#[cfg(all(feature = "global_jit_alloc", not(feature = "default_jit_alloc")))]
280mod custom_jit_alloc {
281 use super::{GlobalJitAlloc, JitAlloc, JitAllocError, ProtectJitAccess};
282
283 extern "Rust" {
284 fn _closure_ffi_3_global_jit_alloc() -> &'static (dyn JitAlloc + Sync);
285 }
286
287 fn get_global_jit_alloc() -> &'static dyn JitAlloc {
288 unsafe { _closure_ffi_3_global_jit_alloc() }
289 }
290
291 impl JitAlloc for GlobalJitAlloc {
292 fn alloc(&self, size: usize) -> Result<(*const u8, *mut u8), JitAllocError> {
293 get_global_jit_alloc().alloc(size)
294 }
295
296 unsafe fn release(&self, rx_ptr: *const u8) -> Result<(), JitAllocError> {
297 get_global_jit_alloc().release(rx_ptr)
298 }
299
300 unsafe fn flush_instruction_cache(&self, rx_ptr: *const u8, size: usize) {
301 get_global_jit_alloc().flush_instruction_cache(rx_ptr, size);
302 }
303
304 unsafe fn protect_jit_memory(&self, ptr: *const u8, size: usize, access: ProtectJitAccess) {
305 get_global_jit_alloc().protect_jit_memory(ptr, size, access);
306 }
307 }
308}