@@ -4,7 +4,7 @@ use core::mem::{align_of, size_of};
4
4
use core:: ptr:: null_mut;
5
5
use core:: ptr:: NonNull ;
6
6
7
- use crate :: { align_up_size , ExtendError } ;
7
+ use crate :: { align_down_size , align_up_size } ;
8
8
9
9
use super :: align_up;
10
10
@@ -13,6 +13,7 @@ pub struct HoleList {
13
13
pub ( crate ) first : Hole , // dummy
14
14
pub ( crate ) bottom : * mut u8 ,
15
15
pub ( crate ) top : * mut u8 ,
16
+ pub ( crate ) pending_extend : u8 ,
16
17
}
17
18
18
19
pub ( crate ) struct Cursor {
@@ -278,6 +279,7 @@ impl HoleList {
278
279
} ,
279
280
bottom : null_mut ( ) ,
280
281
top : null_mut ( ) ,
282
+ pending_extend : 0 ,
281
283
}
282
284
}
283
285
@@ -328,6 +330,11 @@ impl HoleList {
328
330
/// alignment of the `hole_addr` pointer, the minimum size is between
329
331
/// `2 * size_of::<usize>` and `3 * size_of::<usize>`.
330
332
///
333
+ /// The usable size for allocations will be truncated to the nearest
334
+ /// alignment of `align_of::<usize>`. Any extra bytes left at the end
335
+ /// will be reclaimed once sufficient additional space is given to
336
+ /// [`extend`][crate::Heap::extend].
337
+ ///
331
338
/// # Safety
332
339
///
333
340
/// This function is unsafe because it creates a hole at the given `hole_addr`.
@@ -338,7 +345,8 @@ impl HoleList {
338
345
assert ! ( hole_size >= size_of:: <Hole >( ) ) ;
339
346
340
347
let aligned_hole_addr = align_up ( hole_addr, align_of :: < Hole > ( ) ) ;
341
- let aligned_hole_size = hole_size - ( ( aligned_hole_addr as usize ) - ( hole_addr as usize ) ) ;
348
+ let requested_hole_size = hole_size - ( ( aligned_hole_addr as usize ) - ( hole_addr as usize ) ) ;
349
+ let aligned_hole_size = align_down_size ( requested_hole_size, align_of :: < Hole > ( ) ) ;
342
350
assert ! ( aligned_hole_size >= size_of:: <Hole >( ) ) ;
343
351
344
352
let ptr = aligned_hole_addr as * mut Hole ;
@@ -349,15 +357,17 @@ impl HoleList {
349
357
350
358
assert_eq ! (
351
359
hole_addr. wrapping_add( hole_size) ,
352
- aligned_hole_addr. wrapping_add( aligned_hole_size )
360
+ aligned_hole_addr. wrapping_add( requested_hole_size )
353
361
) ;
362
+
354
363
HoleList {
355
364
first : Hole {
356
365
size : 0 ,
357
366
next : Some ( NonNull :: new_unchecked ( ptr) ) ,
358
367
} ,
359
368
bottom : aligned_hole_addr,
360
- top : hole_addr. wrapping_add ( hole_size) ,
369
+ top : aligned_hole_addr. wrapping_add ( aligned_hole_size) ,
370
+ pending_extend : ( requested_hole_size - aligned_hole_size) as u8 ,
361
371
}
362
372
}
363
373
@@ -443,51 +453,40 @@ impl HoleList {
443
453
} )
444
454
}
445
455
446
- // amount previously extended but not big enough to be claimed by a Hole yet
447
- pub ( crate ) fn pending_extend ( & self ) -> usize {
448
- // this field is not used by anything else
449
- self . first . size
450
- }
451
-
452
- pub ( crate ) unsafe fn try_extend ( & mut self , by : usize ) -> Result < ( ) , ExtendError > {
456
+ pub ( crate ) unsafe fn extend ( & mut self , by : usize ) {
453
457
let top = self . top ;
454
- if top. is_null ( ) {
455
- // this is the only case where I don't think will need to make/init a new heap...
456
- // since we can't do that from here, maybe we just add this to the
457
- // documentation to not call .extend() on uninitialized Heaps
458
- unreachable ! ( ) ;
459
- }
460
-
461
- // join this extend request with any pending (but not yet acted on) extensions
462
- let by = self . pending_extend ( ) + by;
463
458
464
459
let dead_space = top. align_offset ( align_of :: < Hole > ( ) ) ;
465
- let minimum_extend = dead_space + Self :: min_size ( ) ;
466
-
467
- if by < minimum_extend {
468
- self . first . size = by;
460
+ debug_assert_eq ! (
461
+ 0 , dead_space,
462
+ "dead space detected during extend: {} bytes. This means top was unaligned" ,
463
+ dead_space
464
+ ) ;
469
465
470
- #[ cfg( test) ]
471
- println ! ( "pending extend size: {} bytes" , self . pending_extend( ) ) ;
466
+ debug_assert ! (
467
+ ( self . pending_extend as usize ) < Self :: min_size( ) ,
468
+ "pending extend was larger than expected"
469
+ ) ;
472
470
473
- return Ok ( ( ) ) ;
474
- }
471
+ // join this extend request with any pending (but not yet acted on) extension
472
+ let extend_by = self . pending_extend as usize + by ;
475
473
476
- #[ cfg( test) ]
477
- if dead_space > 0 {
478
- println ! ( "dead space created during extend: {} bytes" , dead_space) ;
474
+ let minimum_extend = Self :: min_size ( ) ;
475
+ if extend_by < minimum_extend {
476
+ self . pending_extend = extend_by as u8 ;
477
+ return ;
479
478
}
480
479
481
- let aligned_top = align_up ( top, align_of :: < Hole > ( ) ) ;
482
- let layout = Layout :: from_size_align ( by - dead_space, 1 ) . unwrap ( ) ;
483
-
484
- self . deallocate ( NonNull :: new_unchecked ( aligned_top as * mut u8 ) , layout) ;
485
- self . top = top. add ( by) ;
480
+ // only extend up to another valid boundary
481
+ let new_hole_size = align_down_size ( extend_by, align_of :: < Hole > ( ) ) ;
482
+ let layout = Layout :: from_size_align ( new_hole_size, 1 ) . unwrap ( ) ;
486
483
487
- // reset pending resizes
488
- self . first . size = 0 ;
484
+ // instantiate the hole by forcing a deallocation on the new memory
485
+ self . deallocate ( NonNull :: new_unchecked ( top as * mut u8 ) , layout) ;
486
+ self . top = top. add ( new_hole_size) ;
489
487
490
- Ok ( ( ) )
488
+ // save extra bytes given to extend that weren't aligned to the hole size
489
+ self . pending_extend = ( extend_by - new_hole_size) as u8 ;
491
490
}
492
491
}
493
492
@@ -566,7 +565,10 @@ impl Cursor {
566
565
// Does hole overlap node?
567
566
assert ! (
568
567
hole_u8. wrapping_add( hole_size) <= node_u8,
569
- "Freed node aliases existing hole! Bad free?" ,
568
+ "Freed node ({:?}) aliases existing hole ({:?}[{}])! Bad free?" ,
569
+ node_u8,
570
+ hole_u8,
571
+ hole_size,
570
572
) ;
571
573
572
574
// All good! Let's insert that after.
@@ -692,7 +694,8 @@ fn deallocate(list: &mut HoleList, addr: *mut u8, size: usize) {
692
694
#[ cfg( test) ]
693
695
pub mod test {
694
696
use super :: HoleList ;
695
- use crate :: Heap ;
697
+ use crate :: { align_down_size, Heap } ;
698
+ use core:: mem:: size_of;
696
699
use std:: { alloc:: Layout , convert:: TryInto , mem:: MaybeUninit , prelude:: v1:: * , ptr:: NonNull } ;
697
700
698
701
#[ repr( align( 128 ) ) ]
@@ -715,8 +718,8 @@ pub mod test {
715
718
let assumed_location = data. as_mut_ptr ( ) . cast ( ) ;
716
719
717
720
let heap = Heap :: from_slice ( data) ;
718
- assert ! ( heap. bottom( ) == assumed_location) ;
719
- assert ! ( heap. size( ) == HEAP_SIZE ) ;
721
+ assert_eq ! ( heap. bottom( ) , assumed_location) ;
722
+ assert_eq ! ( heap. size( ) , align_down_size ( HEAP_SIZE , size_of :: < usize > ( ) ) ) ;
720
723
heap
721
724
}
722
725
@@ -727,7 +730,10 @@ pub mod test {
727
730
// This is the "dummy" node
728
731
assert_eq ! ( curs. previous( ) . size, 0 ) ;
729
732
// This is the "full" heap
730
- assert_eq ! ( curs. current( ) . size, 1000 ) ;
733
+ assert_eq ! (
734
+ curs. current( ) . size,
735
+ align_down_size( 1000 , size_of:: <usize >( ) )
736
+ ) ;
731
737
// There is no other hole
732
738
assert ! ( curs. next( ) . is_none( ) ) ;
733
739
}
0 commit comments