1
1
use std:: alloc:: { self , Layout } ;
2
- use std:: collections:: HashMap ;
3
- use std:: hash:: { BuildHasherDefault , DefaultHasher } ;
4
- use std:: sync;
5
2
6
3
use rustc_index:: bit_set:: DenseBitSet ;
7
4
8
- static ALLOCATOR : sync:: Mutex < IsolatedAlloc > = sync:: Mutex :: new ( IsolatedAlloc :: empty ( ) ) ;
9
-
10
- pub struct IsolatedAlloc {
11
- /// A map of machine ID to allocator. If running in multi-seeded mode,
12
- /// each machine should have its own pool of memory that can be accessed
13
- /// separately. We use the normal `HashMap` type so that it's available
14
- /// in a `const` context.
15
- #[ allow( rustc:: default_hash_types) ]
16
- allocators : HashMap < u64 , IsolatedAllocInner , BuildHasherDefault < DefaultHasher > > ,
17
- /// The host (not emulated) page size, or 0 if it has not yet been set.
18
- page_size : usize ,
19
- }
20
-
21
5
/// A dedicated allocator for interpreter memory contents, ensuring they are stored on dedicated
22
6
/// pages (not mixed with Miri's own memory). This is very useful for native-lib mode.
23
7
#[ derive( Debug ) ]
24
- pub struct IsolatedAllocInner {
8
+ pub struct IsolatedAlloc {
25
9
/// Pointers to page-aligned memory that has been claimed by the allocator.
26
10
/// Every pointer here must point to a page-sized allocation claimed via
27
11
/// the global allocator.
@@ -38,80 +22,19 @@ pub struct IsolatedAllocInner {
38
22
/// indexing into it should be done with a value one-eighth of the corresponding
39
23
/// offset on the matching `page_ptrs` element.
40
24
page_infos : Vec < DenseBitSet < usize > > ,
25
+ /// The host (not emulated) page size, or 0 if it has not yet been set.
26
+ page_size : usize ,
41
27
}
42
28
43
- // SAFETY: We only point to heap-allocated data
44
- unsafe impl Send for IsolatedAlloc { }
45
-
46
29
impl IsolatedAlloc {
47
- /// Initializes the allocator. `page_size` is set to 0 as a placeholder to
48
- /// allow this function to be `const`; it is updated to its real value on
49
- /// the first call to `alloc()` or `alloc_zeroed()`.
50
- const fn empty ( ) -> Self {
51
- // We need this to be `const`
52
- #[ allow( rustc:: default_hash_types) ]
53
- Self { allocators : HashMap :: with_hasher ( BuildHasherDefault :: new ( ) ) , page_size : 0 }
54
- }
55
-
56
- /// Allocates memory as described in `Layout`, from the pool marked by
57
- /// `id`. Note that the same `id` must be used upon calling `dealloc`.
58
- ///
59
- /// SAFETY: See `alloc::alloc()`.
60
- pub unsafe fn alloc ( layout : Layout , id : u64 ) -> * mut u8 {
61
- unsafe { Self :: alloc_inner ( layout, id, false ) }
62
- }
63
-
64
- /// Same as `alloc()`, but zeroes out data before allocating.
65
- ///
66
- /// SAFETY: See `alloc::alloc_zeroed()`.
67
- pub unsafe fn alloc_zeroed ( layout : Layout , id : u64 ) -> * mut u8 {
68
- unsafe { Self :: alloc_inner ( layout, id, true ) }
69
- }
70
-
71
- /// Abstracts over `alloc` and `alloc_zeroed`.
72
- ///
73
- /// SAFETY: See `alloc::alloc()`/`alloc::alloc_zeroed()`.
74
- unsafe fn alloc_inner ( layout : Layout , id : u64 , zeroed : bool ) -> * mut u8 {
75
- let mut alloc = ALLOCATOR . lock ( ) . unwrap ( ) ;
76
- if alloc. page_size == 0 {
77
- unsafe {
78
- alloc. page_size = libc:: sysconf ( libc:: _SC_PAGESIZE) . try_into ( ) . unwrap ( ) ;
79
- }
80
- }
81
- // Store this this AFTER setting the page size
82
- let page_size = alloc. page_size ;
83
-
84
- match alloc. allocators . get_mut ( & id) {
85
- Some ( alloc_inner) => unsafe { alloc_inner. allocate ( layout, page_size, zeroed) } ,
86
- None => {
87
- let mut new_inner = IsolatedAllocInner :: new ( ) ;
88
- let ret = unsafe { new_inner. allocate ( layout, page_size, zeroed) } ;
89
- alloc. allocators . insert ( id, new_inner) ;
90
- ret
91
- }
92
- }
93
- }
94
-
95
- /// Deallocates a pointer from the memory pool associated with a given `id`.
96
- ///
97
- /// SAFETY: See `alloc::dealloc()`, with the extra caveat that `id` must
98
- /// correspond to the `id` used upon first allocating the memory.
99
- pub unsafe fn dealloc ( ptr : * mut u8 , layout : Layout , id : u64 ) {
100
- let mut alloc = ALLOCATOR . lock ( ) . unwrap ( ) ;
101
- let page_size = alloc. page_size ;
102
- let alloc_inner = alloc. allocators . get_mut ( & id) . unwrap ( ) ;
103
- unsafe { alloc_inner. deallocate ( ptr, layout, page_size) } ;
104
- // Remove if the machine with that id no longer has any memory
105
- if alloc_inner. huge_ptrs . is_empty ( ) && alloc_inner. page_ptrs . is_empty ( ) {
106
- alloc. allocators . remove ( & id) ;
107
- }
108
- }
109
- }
110
-
111
- impl IsolatedAllocInner {
112
30
/// Creates an empty allocator.
113
- const fn new ( ) -> Self {
114
- Self { page_ptrs : Vec :: new ( ) , huge_ptrs : Vec :: new ( ) , page_infos : Vec :: new ( ) }
31
+ pub fn new ( ) -> Self {
32
+ Self {
33
+ page_ptrs : Vec :: new ( ) ,
34
+ huge_ptrs : Vec :: new ( ) ,
35
+ page_infos : Vec :: new ( ) ,
36
+ page_size : unsafe { libc:: sysconf ( libc:: _SC_PAGESIZE) . try_into ( ) . unwrap ( ) } ,
37
+ }
115
38
}
116
39
117
40
/// Expands the available memory pool by adding one page.
@@ -137,24 +60,40 @@ impl IsolatedAllocInner {
137
60
( size, align)
138
61
}
139
62
63
+ /// Allocates memory as described in `Layout`. This memory should be deallocated
64
+ /// by calling `dealloc` on this same allocator.
65
+ ///
66
+ /// SAFETY: See `alloc::alloc()`
67
+ pub fn alloc ( & mut self , layout : Layout ) -> * mut u8 {
68
+ unsafe { self . allocate ( layout, false ) }
69
+ }
70
+
71
+ /// Same as `alloc`, but zeroes out the memory.
72
+ ///
73
+ /// SAFETY: See `alloc::alloc_zeroed()`
74
+ pub fn alloc_zeroed ( & mut self , layout : Layout ) -> * mut u8 {
75
+ unsafe { self . allocate ( layout, true ) }
76
+ }
77
+
140
78
/// Abstracts over the logic of `alloc_zeroed` vs `alloc`, as determined by
141
79
/// the `zeroed` argument.
142
80
///
143
81
/// SAFETY: See `alloc::alloc()`, with the added restriction that `page_size`
144
82
/// corresponds to the host pagesize.
145
- unsafe fn allocate ( & mut self , layout : Layout , page_size : usize , zeroed : bool ) -> * mut u8 {
146
- if layout. align ( ) > page_size || layout. size ( ) > page_size {
83
+ unsafe fn allocate ( & mut self , layout : Layout , zeroed : bool ) -> * mut u8 {
84
+ if layout. align ( ) > self . page_size || layout. size ( ) > self . page_size {
147
85
unsafe { self . alloc_multi_page ( layout, zeroed) }
148
86
} else {
149
87
for ( & mut page, pinfo) in std:: iter:: zip ( & mut self . page_ptrs , & mut self . page_infos ) {
150
88
if let Some ( ptr) =
151
- unsafe { Self :: alloc_from_page ( page_size, layout, page, pinfo, zeroed) }
89
+ unsafe { Self :: alloc_from_page ( self . page_size , layout, page, pinfo, zeroed) }
152
90
{
153
91
return ptr;
154
92
}
155
93
}
156
94
157
95
// We get here only if there's no space in our existing pages
96
+ let page_size = self . page_size ;
158
97
let ( page, pinfo) = self . add_page ( page_size) ;
159
98
unsafe { Self :: alloc_from_page ( page_size, layout, page, pinfo, zeroed) . unwrap ( ) }
160
99
}
@@ -171,7 +110,7 @@ impl IsolatedAllocInner {
171
110
pinfo : & mut DenseBitSet < usize > ,
172
111
zeroed : bool ,
173
112
) -> Option < * mut u8 > {
174
- let ( size, align) = IsolatedAllocInner :: normalized_layout ( layout) ;
113
+ let ( size, align) = IsolatedAlloc :: normalized_layout ( layout) ;
175
114
176
115
// Check every alignment-sized block and see if there exists a `size`
177
116
// chunk of empty space i.e. forall idx . !pinfo.contains(idx / 8)
@@ -213,15 +152,14 @@ impl IsolatedAllocInner {
213
152
///
214
153
/// SAFETY: This pointer must have been allocated by calling `alloc()` (or
215
154
/// `alloc_zeroed()`) with the same layout as the one passed on this same
216
- /// `IsolatedAllocInner`, and `page_size` must correspond to the host
217
- /// pagesize.
218
- unsafe fn deallocate ( & mut self , ptr : * mut u8 , layout : Layout , page_size : usize ) {
219
- let ( size, align) = IsolatedAllocInner :: normalized_layout ( layout) ;
155
+ /// `IsolatedAlloc`.
156
+ pub unsafe fn dealloc ( & mut self , ptr : * mut u8 , layout : Layout ) {
157
+ let ( size, align) = IsolatedAlloc :: normalized_layout ( layout) ;
220
158
221
- let ptr_idx = ptr. addr ( ) % page_size;
159
+ let ptr_idx = ptr. addr ( ) % self . page_size ;
222
160
let page_addr = ptr. addr ( ) - ptr_idx;
223
161
224
- if align > page_size || size > page_size {
162
+ if align > self . page_size || size > self . page_size {
225
163
unsafe {
226
164
self . dealloc_multi_page ( ptr, layout) ;
227
165
}
@@ -242,7 +180,8 @@ impl IsolatedAllocInner {
242
180
}
243
181
244
182
let mut free = vec ! [ ] ;
245
- let page_layout = unsafe { Layout :: from_size_align_unchecked ( page_size, page_size) } ;
183
+ let page_layout =
184
+ unsafe { Layout :: from_size_align_unchecked ( self . page_size , self . page_size ) } ;
246
185
for ( idx, pinfo) in self . page_infos . iter ( ) . enumerate ( ) {
247
186
if pinfo. is_empty ( ) {
248
187
free. push ( idx) ;
@@ -271,7 +210,7 @@ impl IsolatedAllocInner {
271
210
}
272
211
}
273
212
}
274
-
213
+ /*
275
214
#[cfg(test)]
276
215
mod tests {
277
216
use super::*;
@@ -365,3 +304,4 @@ mod tests {
365
304
assert!(!alloc.allocators.contains_key(&4));
366
305
}
367
306
}
307
+ */
0 commit comments