11use std:: alloc:: { self , Layout } ;
2- use std:: collections:: HashMap ;
3- use std:: hash:: { BuildHasherDefault , DefaultHasher } ;
4- use std:: sync;
52
63use rustc_index:: bit_set:: DenseBitSet ;
74
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-
215/// A dedicated allocator for interpreter memory contents, ensuring they are stored on dedicated
226/// pages (not mixed with Miri's own memory). This is very useful for native-lib mode.
237#[ derive( Debug ) ]
24- pub struct IsolatedAllocInner {
8+ pub struct IsolatedAlloc {
259 /// Pointers to page-aligned memory that has been claimed by the allocator.
2610 /// Every pointer here must point to a page-sized allocation claimed via
2711 /// the global allocator.
@@ -38,80 +22,19 @@ pub struct IsolatedAllocInner {
3822 /// indexing into it should be done with a value one-eighth of the corresponding
3923 /// offset on the matching `page_ptrs` element.
4024 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 ,
4127}
4228
43- // SAFETY: We only point to heap-allocated data
44- unsafe impl Send for IsolatedAlloc { }
45-
4629impl 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 {
11230 /// 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+ }
11538 }
11639
11740 /// Expands the available memory pool by adding one page.
@@ -137,24 +60,40 @@ impl IsolatedAllocInner {
13760 ( size, align)
13861 }
13962
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+
14078 /// Abstracts over the logic of `alloc_zeroed` vs `alloc`, as determined by
14179 /// the `zeroed` argument.
14280 ///
14381 /// SAFETY: See `alloc::alloc()`, with the added restriction that `page_size`
14482 /// 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 {
14785 unsafe { self . alloc_multi_page ( layout, zeroed) }
14886 } else {
14987 for ( & mut page, pinfo) in std:: iter:: zip ( & mut self . page_ptrs , & mut self . page_infos ) {
15088 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) }
15290 {
15391 return ptr;
15492 }
15593 }
15694
15795 // We get here only if there's no space in our existing pages
96+ let page_size = self . page_size ;
15897 let ( page, pinfo) = self . add_page ( page_size) ;
15998 unsafe { Self :: alloc_from_page ( page_size, layout, page, pinfo, zeroed) . unwrap ( ) }
16099 }
@@ -171,7 +110,7 @@ impl IsolatedAllocInner {
171110 pinfo : & mut DenseBitSet < usize > ,
172111 zeroed : bool ,
173112 ) -> Option < * mut u8 > {
174- let ( size, align) = IsolatedAllocInner :: normalized_layout ( layout) ;
113+ let ( size, align) = IsolatedAlloc :: normalized_layout ( layout) ;
175114
176115 // Check every alignment-sized block and see if there exists a `size`
177116 // chunk of empty space i.e. forall idx . !pinfo.contains(idx / 8)
@@ -213,15 +152,14 @@ impl IsolatedAllocInner {
213152 ///
214153 /// SAFETY: This pointer must have been allocated by calling `alloc()` (or
215154 /// `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) ;
220158
221- let ptr_idx = ptr. addr ( ) % page_size;
159+ let ptr_idx = ptr. addr ( ) % self . page_size ;
222160 let page_addr = ptr. addr ( ) - ptr_idx;
223161
224- if align > page_size || size > page_size {
162+ if align > self . page_size || size > self . page_size {
225163 unsafe {
226164 self . dealloc_multi_page ( ptr, layout) ;
227165 }
@@ -242,7 +180,8 @@ impl IsolatedAllocInner {
242180 }
243181
244182 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 ) } ;
246185 for ( idx, pinfo) in self . page_infos . iter ( ) . enumerate ( ) {
247186 if pinfo. is_empty ( ) {
248187 free. push ( idx) ;
@@ -271,7 +210,7 @@ impl IsolatedAllocInner {
271210 }
272211 }
273212}
274-
213+ /*
275214#[cfg(test)]
276215mod tests {
277216 use super::*;
@@ -365,3 +304,4 @@ mod tests {
365304 assert!(!alloc.allocators.contains_key(&4));
366305 }
367306}
307+ */
0 commit comments