@@ -27,9 +27,9 @@ pub type GlobalState = RefCell<GlobalStateInner>;
27
27
#[ derive( Clone , Debug ) ]
28
28
pub struct GlobalStateInner {
29
29
/// This is used as a map between the address of each allocation and its `AllocId`. It is always
30
- /// sorted. We cannot use a `HashMap` since we can be given an address that is offset from the
31
- /// base address, and we need to find the `AllocId` it belongs to.
32
- /// This is not the *full* inverse of `base_addr`; dead allocations have been removed.
30
+ /// sorted by address . We cannot use a `HashMap` since we can be given an address that is offset
31
+ /// from the base address, and we need to find the `AllocId` it belongs to. This is not the
32
+ /// *full* inverse of `base_addr`; dead allocations have been removed.
33
33
int_to_ptr_map : Vec < ( u64 , AllocId ) > ,
34
34
/// The base address for each allocation. We cannot put that into
35
35
/// `AllocExtra` because function pointers also have a base address, and
@@ -285,7 +285,12 @@ impl GlobalStateInner {
285
285
// However, we *can* remove it from `int_to_ptr_map`, since any wildcard pointers that exist
286
286
// can no longer actually be accessing that address. This ensures `alloc_id_from_addr` never
287
287
// returns a dead allocation.
288
- self . int_to_ptr_map . retain ( |& ( _, id) | id != dead_id) ;
288
+ // To avoid a linear scan we first look up the address in `base_addr`, and then find it in
289
+ // `int_to_ptr_map`.
290
+ let addr = * self . base_addr . get ( & dead_id) . unwrap ( ) ;
291
+ let pos = self . int_to_ptr_map . binary_search_by_key ( & addr, |( addr, _) | * addr) . unwrap ( ) ;
292
+ let removed = self . int_to_ptr_map . remove ( pos) ;
293
+ assert_eq ! ( removed, ( addr, dead_id) ) ; // double-check that we removed the right thing
289
294
// We can also remove it from `exposed`, since this allocation can anyway not be returned by
290
295
// `alloc_id_from_addr` any more.
291
296
self . exposed . remove ( & dead_id) ;
0 commit comments