@@ -169,52 +169,60 @@ fn allocate_first_fit(previous: &mut Hole, size: usize, align: usize) -> Option<
169169 } )
170170}
171171
172+ /// Frees the allocation given by `(addr, size)`. It starts at the given hole and walks the list to
173+ /// find the correct place (the list is sorted by address).
172174fn deallocate ( hole : & mut Hole , addr : usize , size : usize ) {
175+ assert ! ( size >= HoleList :: min_size( ) ) ;
176+
173177 let hole_addr = if hole. size == 0 {
174- 0 // dummy
178+ // It's the dummy hole, which is the head of the HoleList. It's somewhere on the stack,
179+ // so it's address is not the address of the hole. We set the addr to 0 as it's always
180+ // the first hole.
181+ 0
175182 } else {
183+ // tt's a real hole in memory and its address is the address of the hole
176184 hole as * mut _ as usize
177185 } ;
178- assert ! ( addr >= hole_addr + hole. size) ;
179186
187+ // Each freed block must be handled by the previous hole in memory. Thus the freed address must
188+ // be always behind the current hole.
189+ assert ! ( hole_addr + hole. size <= addr) ;
180190
191+ // get information about the next block
192+ let next_hole_info = hole. next . as_ref ( ) . map ( |next| unsafe { next. get ( ) . info ( ) } ) ;
181193
182- match mem :: replace ( & mut hole . next , None ) {
183- Some ( ref mut next) if addr == hole_addr + hole. size && addr + size == * * next as usize => {
194+ match next_hole_info {
195+ Some ( next) if hole_addr + hole. size == addr && addr + size == next. addr => {
184196 // block fills the gap between this hole and the next hole
185197 // before: ___XXX____YYYYY____ where X is this hole and Y the next hole
186198 // after: ___XXXFFFFYYYYY____ where F is the freed block
187- hole. size += size + unsafe { next. get ( ) . size } ;
188- hole. next = unsafe { next. get_mut ( ) } . next . take ( ) ;
199+
200+ hole. size += size + next. size ; // merge the F and Y blocks to this X block
201+ hole. next = hole. next_unwrap ( ) . next . take ( ) ; // remove the Y block
189202 }
190- Some ( ref next ) if addr == hole_addr + hole. size => {
203+ Some ( _ ) if hole_addr + hole. size == addr => {
191204 // block is right behind this hole but there is used memory after it
192205 // before: ___XXX______YYYYY____ where X is this hole and Y the next hole
193206 // after: ___XXXFFFF__YYYYY____ where F is the freed block
194- hole. size += size;
195207
196- // hole.next should stay the same
197- hole. next = Some ( unsafe { Unique :: new ( * * next) } ) ; //hack to avoid implementing clone
208+ hole. size += size; // merge the F block to this X block
198209 }
199- Some ( ref mut next) if addr + size == * * next as usize => {
210+ Some ( next) if addr + size == next. addr => {
200211 // block is right before the next hole but there is used memory before it
201212 // before: ___XXX______YYYYY____ where X is this hole and Y the next hole
202213 // after: ___XXX__FFFFYYYYY____ where F is the freed block
203- let next_hole_next = unsafe { next. get_mut ( ) } . next . take ( ) ;
204- let next_hole_size = unsafe { next. get ( ) } . size ;
205- hole. next = next_hole_next; // delete next block
206- deallocate ( hole, addr, size + next_hole_size) ; // free it again as a big block
214+
215+ hole. next = hole. next_unwrap ( ) . next . take ( ) ; // remove the Y block
216+ deallocate ( hole, addr, size + next. size ) ; // free the merged F/Y block
207217 }
208- Some ( ref mut next) if addr >= * * next as usize => {
218+ Some ( next) if next . addr <= addr => {
209219 // block is behind the next hole, so we delegate it to the next hole
210220 // before: ___XXX__YYYYY________ where X is this hole and Y the next hole
211221 // after: ___XXX__YYYYY__FFFF__ where F is the freed block
212222
213- // hole.next should stay the same
214- hole. next = Some ( unsafe { Unique :: new ( * * next) } ) ; // hack to avoid implementing clone
215- deallocate ( unsafe { next. get_mut ( ) } , addr, size) ;
223+ deallocate ( hole. next_unwrap ( ) , addr, size) ;
216224 }
217- next => {
225+ _ => {
218226 // block is between this and the next hole
219227 // before: ___XXX________YYYYY_ where X is this hole and Y the next hole
220228 // after: ___XXX__FFFF__YYYYY_ where F is the freed block
@@ -225,10 +233,12 @@ fn deallocate(hole: &mut Hole, addr: usize, size: usize) {
225233
226234 let new_hole = Hole {
227235 size : size,
228- next : next,
236+ next : hole . next . take ( ) , // the reference to the Y block (if it exists)
229237 } ;
238+ // write the new hole to the freed memory
230239 let ptr = addr as * mut Hole ;
231240 mem:: forget ( mem:: replace ( unsafe { & mut * ptr } , new_hole) ) ;
241+ // add the F block as the next block of the X block
232242 hole. next = Some ( unsafe { Unique :: new ( ptr) } ) ;
233243 }
234244 }
0 commit comments