1
- use crate :: { hoard_space :: HoardSpace , super_block :: SuperBlock } ;
1
+ use crate :: { block :: Block , immix_space :: ImmixSpace } ;
2
2
use mallockit:: {
3
3
space:: page_resource:: MemRegion ,
4
4
util:: { mem:: size_class:: SizeClass , Address } ,
@@ -8,361 +8,23 @@ use spin::{relax::Yield, MutexGuard};
8
8
9
9
type Mutex < T > = spin:: mutex:: Mutex < T , Yield > ;
10
10
11
- struct EmptyClass {
12
- // 0 => emoty blocks
13
- // classes+1 => full blocks
14
- groups : [ Option < SuperBlock > ; Self :: GROUPS ] ,
15
- }
16
-
17
- impl EmptyClass {
18
- const EMPTINESS_CLASSES : usize = 8 ;
19
- const GROUPS : usize = Self :: EMPTINESS_CLASSES + 2 ;
20
-
21
- const fn new ( ) -> Self {
22
- Self {
23
- groups : [ None ; Self :: GROUPS ] ,
24
- }
25
- }
26
-
27
- const fn group ( block : SuperBlock ) -> usize {
28
- let t =
29
- SuperBlock :: DATA_BYTES >> block. size_class . log_bytes ( ) << block. size_class . log_bytes ( ) ;
30
- let u = block. used_bytes ( ) ;
31
- if u == 0 {
32
- 0
33
- } else {
34
- 1 + ( Self :: EMPTINESS_CLASSES * u / t)
35
- }
36
- }
37
-
38
- #[ cold]
39
- fn transfer ( & mut self , mut block : SuperBlock , oldg : usize , newg : usize ) {
40
- if Some ( block) == self . groups [ newg] || newg == oldg {
41
- return ;
42
- }
43
- if self . groups [ oldg] == Some ( block) {
44
- self . groups [ oldg] = block. next ;
45
- }
46
- if let Some ( mut prev) = block. prev {
47
- prev. next = block. next ;
48
- }
49
- if let Some ( mut next) = block. next {
50
- next. prev = block. prev ;
51
- }
52
- block. group = newg as _ ;
53
- block. next = self . groups [ newg] ;
54
- block. prev = None ;
55
- if let Some ( mut head) = self . groups [ newg] {
56
- head. prev = Some ( block)
57
- }
58
- self . groups [ newg] = Some ( block) ;
59
- }
60
-
61
- fn put ( & mut self , mut block : SuperBlock ) {
62
- let group = Self :: group ( block) ;
63
- block. group = group as _ ;
64
- block. next = self . groups [ group] ;
65
- block. prev = None ;
66
- if let Some ( mut head) = self . groups [ group] {
67
- head. prev = Some ( block)
68
- }
69
- self . groups [ group] = Some ( block) ;
70
- debug_assert_ne ! ( block. prev, Some ( block) ) ;
71
- }
72
-
73
- fn remove ( & mut self , block : SuperBlock ) {
74
- if self . groups [ block. group as usize ] == Some ( block) {
75
- self . groups [ block. group as usize ] = block. next ;
76
- }
77
- if let Some ( mut prev) = block. prev {
78
- prev. next = block. next ;
79
- }
80
- if let Some ( mut next) = block. next {
81
- next. prev = block. prev ;
82
- }
83
- }
84
-
85
- fn pop ( & mut self , group : usize ) -> Option < SuperBlock > {
86
- if let Some ( block) = self . groups [ group] {
87
- self . groups [ group] = block. next ;
88
- if let Some ( mut next) = block. next {
89
- next. prev = None ;
90
- }
91
- return Some ( block) ;
92
- }
93
- None
94
- }
95
-
96
- fn pop_most_empty_block ( & mut self ) -> Option < SuperBlock > {
97
- for i in 0 ..Self :: EMPTINESS_CLASSES + 1 {
98
- while let Some ( block) = self . groups [ i] {
99
- // remove
100
- self . groups [ i] = block. next ;
101
- if let Some ( mut next) = block. next {
102
- next. prev = None ;
103
- }
104
- let bg = Self :: group ( block) ;
105
- if bg > i {
106
- self . put ( block)
107
- } else {
108
- return Some ( block) ;
109
- }
110
- }
111
- }
112
- None
113
- }
114
-
115
- #[ cold]
116
- fn free_cell ( & mut self , a : Address , mut b : SuperBlock ) {
117
- let oldg = Self :: group ( b) ;
118
- b. free_cell ( a) ;
119
- let newg = Self :: group ( b) ;
120
- if oldg != newg {
121
- self . transfer ( b, oldg, newg)
122
- }
123
- }
124
- }
125
-
126
- pub struct BlockList {
127
- cache : Option < SuperBlock > ,
128
- groups : EmptyClass ,
129
- used_bytes : usize ,
130
- total_bytes : usize ,
131
- }
132
-
133
- impl BlockList {
134
- const fn new ( ) -> Self {
135
- Self {
136
- cache : None ,
137
- groups : EmptyClass :: new ( ) ,
138
- used_bytes : 0 ,
139
- total_bytes : 0 ,
140
- }
141
- }
142
-
143
- const fn should_flush ( & self , log_obj_size : usize ) -> bool {
144
- let u = self . used_bytes ;
145
- let a = self . total_bytes ;
146
- ( EmptyClass :: EMPTINESS_CLASSES * u) < ( ( EmptyClass :: EMPTINESS_CLASSES - 1 ) * a)
147
- && u + ( ( 2 * SuperBlock :: BYTES ) >> log_obj_size) < a
148
- }
149
-
150
- fn remove ( & mut self , block : SuperBlock ) {
151
- self . dec_used_bytes ( block. used_bytes ( ) ) ;
152
- self . dec_total_bytes ( SuperBlock :: DATA_BYTES ) ;
153
- if self . cache == Some ( block) {
154
- self . cache = None ;
155
- return ;
156
- }
157
- self . groups . remove ( block) ;
158
- }
159
-
160
- fn pop_most_empty_block ( & mut self ) -> Option < SuperBlock > {
161
- if let Some ( cache) = self . cache . take ( ) {
162
- self . dec_total_bytes ( SuperBlock :: DATA_BYTES ) ;
163
- self . dec_used_bytes ( cache. used_bytes ( ) ) ;
164
- return Some ( cache) ;
165
- }
166
- let b = self . groups . pop_most_empty_block ( ) ?;
167
- self . dec_total_bytes ( SuperBlock :: DATA_BYTES ) ;
168
- self . dec_used_bytes ( b. used_bytes ( ) ) ;
169
- Some ( b)
170
- }
171
-
172
- const fn inc_used_bytes ( & mut self , used_bytes : usize ) {
173
- self . used_bytes += used_bytes;
174
- }
175
-
176
- const fn dec_used_bytes ( & mut self , used_bytes : usize ) {
177
- self . used_bytes -= used_bytes;
178
- }
179
-
180
- const fn inc_total_bytes ( & mut self , total_bytes : usize ) {
181
- self . total_bytes += total_bytes;
182
- }
183
-
184
- const fn dec_total_bytes ( & mut self , total_bytes : usize ) {
185
- self . total_bytes -= total_bytes;
186
- }
187
-
188
- fn put ( & mut self , b : SuperBlock ) {
189
- if Some ( b) == self . cache {
190
- return ;
191
- }
192
- if let Some ( c) = self . cache {
193
- self . groups . put ( c) ;
194
- }
195
- self . cache = Some ( b) ;
196
- self . inc_total_bytes ( SuperBlock :: DATA_BYTES ) ;
197
- self . inc_used_bytes ( b. used_bytes ( ) ) ;
198
- }
199
-
200
- #[ cold]
201
- fn alloc_cell_slow ( & mut self , size_class : SizeClass ) -> Option < Address > {
202
- loop {
203
- if self . cache . is_none ( ) {
204
- self . cache = Some ( self . groups . pop_most_empty_block ( ) ?) ;
205
- }
206
- let mut b = self . cache . unwrap ( ) ;
207
- if let Some ( a) = b. alloc_cell ( ) {
208
- self . inc_used_bytes ( size_class. bytes ( ) ) ;
209
- return Some ( a) ;
210
- } else {
211
- self . cache = None ;
212
- self . groups . put ( b) ;
213
- }
214
- }
215
- }
216
-
217
- #[ inline]
218
- fn alloc_cell ( & mut self , size_class : SizeClass ) -> Option < Address > {
219
- if let Some ( mut b) = self . cache {
220
- if let Some ( a) = b. alloc_cell ( ) {
221
- self . inc_used_bytes ( size_class. bytes ( ) ) ;
222
- return Some ( a) ;
223
- }
224
- }
225
- self . alloc_cell_slow ( size_class)
226
- }
227
-
228
- #[ inline]
229
- fn free_cell ( & mut self , a : Address , mut b : SuperBlock , size_class : SizeClass ) {
230
- if Some ( b) == self . cache {
231
- b. free_cell ( a)
232
- } else {
233
- self . groups . free_cell ( a, b) ;
234
- }
235
- self . dec_used_bytes ( size_class. bytes ( ) ) ;
236
- }
237
- }
238
-
239
11
pub struct Pool {
240
12
pub global : bool ,
241
- // This is a major difference to the original hoard: we lock bins instead of the entire local heap.
242
- blocks : [ Mutex < BlockList > ; Self :: MAX_BINS ] ,
13
+ head : Option < Block > ,
243
14
}
244
15
245
16
impl Drop for Pool {
246
- fn drop ( & mut self ) {
247
- let space = & crate :: Hoard :: get ( ) . hoard_space ;
248
- for ( i, block) in self . blocks . iter ( ) . enumerate ( ) {
249
- let sz: SizeClass = SizeClass ( i as _ ) ;
250
- let mut block = block. lock ( ) ;
251
- if let Some ( b) = block. cache . take ( ) {
252
- space. flush_block ( sz, b) ;
253
- }
254
- for i in 0 ..EmptyClass :: GROUPS {
255
- while let Some ( b) = block. groups . pop ( i) {
256
- space. flush_block ( sz, b) ;
257
- }
258
- }
259
- }
260
- }
17
+ fn drop ( & mut self ) { }
261
18
}
262
19
263
20
impl Pool {
264
21
const MAX_BINS : usize = 32 ;
265
22
266
23
pub const fn new ( global : bool ) -> Self {
267
- Self {
268
- global,
269
- blocks : [ const { Mutex :: new ( BlockList :: new ( ) ) } ; 32 ] ,
270
- }
24
+ Self { global, head : None }
271
25
}
272
26
273
27
pub const fn static_ref ( & self ) -> & ' static Self {
274
28
unsafe { & * ( self as * const Self ) }
275
29
}
276
-
277
- pub fn put ( & self , size_class : SizeClass , mut block : SuperBlock ) {
278
- // debug_assert!(!block.is_full());
279
- let mut blocks = self . lock_blocks ( size_class) ;
280
- block. owner = self . static_ref ( ) ;
281
- blocks. put ( block) ;
282
- }
283
-
284
- pub fn pop_most_empty_block (
285
- & self ,
286
- size_class : SizeClass ,
287
- ) -> Option < ( SuperBlock , MutexGuard < BlockList > ) > {
288
- debug_assert ! ( self . global) ;
289
- let mut blocks = self . lock_blocks ( size_class) ;
290
- if let Some ( block) = blocks. pop_most_empty_block ( ) {
291
- debug_assert ! ( block. is_owned_by( self ) ) ;
292
- return Some ( ( block, blocks) ) ;
293
- }
294
- None
295
- }
296
-
297
- fn lock_blocks ( & self , size_class : SizeClass ) -> MutexGuard < BlockList > {
298
- unsafe { self . blocks . get_unchecked ( size_class. as_usize ( ) ) . lock ( ) }
299
- }
300
-
301
- pub fn alloc_cell (
302
- & mut self ,
303
- size_class : SizeClass ,
304
- space : & ' static HoardSpace ,
305
- ) -> Option < Address > {
306
- debug_assert ! ( !self . global) ;
307
- let mut blocks = self . lock_blocks ( size_class) ;
308
- if let Some ( a) = blocks. alloc_cell ( size_class) {
309
- return Some ( a) ;
310
- }
311
- // slow-path
312
- loop {
313
- if let Some ( a) = blocks. alloc_cell ( size_class) {
314
- return Some ( a) ;
315
- }
316
- let block = space. acquire_block ( size_class, self ) ?;
317
- blocks. put ( block) ;
318
- }
319
- }
320
-
321
- pub fn free_cell ( & self , cell : Address , space : & ' static HoardSpace ) {
322
- let block = SuperBlock :: containing ( cell) ;
323
- let mut owner = block. owner ;
324
- let mut blocks = owner. lock_blocks ( block. size_class ) ;
325
- while !block. is_owned_by ( owner) {
326
- std:: mem:: drop ( blocks) ;
327
- std:: thread:: yield_now ( ) ;
328
- owner = block. owner ;
329
- blocks = owner. lock_blocks ( block. size_class ) ;
330
- }
331
- owner. free_cell_slow_impl ( cell, space, & mut blocks, block)
332
- }
333
-
334
- fn free_cell_slow_impl (
335
- & self ,
336
- cell : Address ,
337
- space : & ' static HoardSpace ,
338
- blocks : & mut BlockList ,
339
- block : SuperBlock ,
340
- ) {
341
- blocks. free_cell ( cell, block, block. size_class ) ;
342
- if block. is_empty ( ) {
343
- blocks. remove ( block) ;
344
- space. release_block ( block) ;
345
- }
346
- // Flush?
347
- if !self . global && blocks. should_flush ( block. size_class . log_bytes ( ) ) {
348
- self . flush_block_slow ( block. size_class , space, blocks) ;
349
- }
350
- }
351
-
352
- #[ cold]
353
- fn flush_block_slow (
354
- & self ,
355
- size_class : SizeClass ,
356
- space : & ' static HoardSpace ,
357
- blocks : & mut BlockList ,
358
- ) {
359
- // Transit a mostly-empty block to the global pool
360
- debug_assert ! ( !self . global) ;
361
- if let Some ( mostly_empty_block) = blocks. pop_most_empty_block ( ) {
362
- // debug_assert!(!mostly_empty_block.is_full());
363
- debug_assert ! ( mostly_empty_block. is_owned_by( self ) ) ;
364
- space. flush_block ( size_class, mostly_empty_block) ;
365
- debug_assert ! ( !mostly_empty_block. is_owned_by( self ) ) ;
366
- }
367
- }
368
30
}
0 commit comments