1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use crate::qjs;
use std::ptr::null_mut;
mod rust;
pub use rust::RustAllocator;
#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "allocator")))]
pub type RawMemPtr = *mut u8;
#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "allocator")))]
pub trait Allocator {
fn alloc(&mut self, size: usize) -> RawMemPtr;
fn dealloc(&mut self, ptr: RawMemPtr);
fn realloc(&mut self, ptr: RawMemPtr, new_size: usize) -> RawMemPtr;
fn usable_size(ptr: RawMemPtr) -> usize
where
Self: Sized;
}
type DynAllocator = Box<dyn Allocator>;
pub struct AllocatorHolder(*mut DynAllocator);
impl Drop for AllocatorHolder {
fn drop(&mut self) {
let _ = unsafe { Box::from_raw(self.0) };
}
}
impl AllocatorHolder {
pub(crate) fn functions<A>() -> qjs::JSMallocFunctions
where
A: Allocator,
{
qjs::JSMallocFunctions {
js_malloc: Some(Self::malloc),
js_free: Some(Self::free),
js_realloc: Some(Self::realloc),
js_malloc_usable_size: Some(Self::malloc_usable_size::<A>),
}
}
pub(crate) fn new<A>(allocator: A) -> Self
where
A: Allocator + 'static,
{
Self(Box::into_raw(Box::new(Box::new(allocator))))
}
pub(crate) fn opaque_ptr(&self) -> *mut DynAllocator {
self.0
}
unsafe extern "C" fn malloc(
state: *mut qjs::JSMallocState,
size: qjs::size_t,
) -> *mut qjs::c_void {
if size == 0 {
return null_mut();
}
let state = &*state;
let allocator = &mut *(state.opaque as *mut DynAllocator);
allocator.alloc(size as _) as _
}
unsafe extern "C" fn free(state: *mut qjs::JSMallocState, ptr: *mut qjs::c_void) {
if ptr.is_null() {
return;
}
let state = &*state;
let allocator = &mut *(state.opaque as *mut DynAllocator);
allocator.dealloc(ptr as _);
}
unsafe extern "C" fn realloc(
state: *mut qjs::JSMallocState,
ptr: *mut qjs::c_void,
size: qjs::size_t,
) -> *mut qjs::c_void {
let state = &*state;
let allocator = &mut *(state.opaque as *mut DynAllocator);
if ptr.is_null() {
return allocator.alloc(size as _) as _;
} else if size == 0 {
allocator.dealloc(ptr as _);
return null_mut();
}
allocator.realloc(ptr as _, size as _) as _
}
unsafe extern "C" fn malloc_usable_size<A>(ptr: *const qjs::c_void) -> qjs::size_t
where
A: Allocator,
{
if ptr.is_null() {
return 0;
}
A::usable_size(ptr as _) as _
}
}