@@ -197,9 +197,7 @@ pub fn specialized_encode_alloc_id<'tcx, E: Encoder>(
197
197
tcx : TyCtxt < ' tcx > ,
198
198
alloc_id : AllocId ,
199
199
) -> Result < ( ) , E :: Error > {
200
- let alloc: GlobalAlloc < ' tcx > =
201
- tcx. alloc_map . lock ( ) . get ( alloc_id) . expect ( "no value for given alloc ID" ) ;
202
- match alloc {
200
+ match tcx. global_alloc ( alloc_id) {
203
201
GlobalAlloc :: Memory ( alloc) => {
204
202
trace ! ( "encoding {:?} with {:#?}" , alloc_id, alloc) ;
205
203
AllocDiscriminant :: Alloc . encode ( encoder) ?;
@@ -294,7 +292,7 @@ impl<'s> AllocDecodingSession<'s> {
294
292
AllocDiscriminant :: Alloc => {
295
293
// If this is an allocation, we need to reserve an
296
294
// `AllocId` so we can decode cyclic graphs.
297
- let alloc_id = decoder. tcx ( ) . alloc_map . lock ( ) . reserve ( ) ;
295
+ let alloc_id = decoder. tcx ( ) . reserve_alloc_id ( ) ;
298
296
* entry =
299
297
State :: InProgress ( TinyList :: new_single ( self . session_id ) , alloc_id) ;
300
298
Some ( alloc_id)
@@ -338,23 +336,23 @@ impl<'s> AllocDecodingSession<'s> {
338
336
// We already have a reserved `AllocId`.
339
337
let alloc_id = alloc_id. unwrap ( ) ;
340
338
trace ! ( "decoded alloc {:?}: {:#?}" , alloc_id, alloc) ;
341
- decoder. tcx ( ) . alloc_map . lock ( ) . set_alloc_id_same_memory ( alloc_id, alloc) ;
339
+ decoder. tcx ( ) . set_alloc_id_same_memory ( alloc_id, alloc) ;
342
340
Ok ( alloc_id)
343
341
}
344
342
AllocDiscriminant :: Fn => {
345
343
assert ! ( alloc_id. is_none( ) ) ;
346
344
trace ! ( "creating fn alloc ID" ) ;
347
345
let instance = ty:: Instance :: decode ( decoder) ?;
348
346
trace ! ( "decoded fn alloc instance: {:?}" , instance) ;
349
- let alloc_id = decoder. tcx ( ) . alloc_map . lock ( ) . create_fn_alloc ( instance) ;
347
+ let alloc_id = decoder. tcx ( ) . create_fn_alloc ( instance) ;
350
348
Ok ( alloc_id)
351
349
}
352
350
AllocDiscriminant :: Static => {
353
351
assert ! ( alloc_id. is_none( ) ) ;
354
352
trace ! ( "creating extern static alloc ID" ) ;
355
353
let did = DefId :: decode ( decoder) ?;
356
354
trace ! ( "decoded static def-ID: {:?}" , did) ;
357
- let alloc_id = decoder. tcx ( ) . alloc_map . lock ( ) . create_static_alloc ( did) ;
355
+ let alloc_id = decoder. tcx ( ) . create_static_alloc ( did) ;
358
356
Ok ( alloc_id)
359
357
}
360
358
}
@@ -381,7 +379,29 @@ pub enum GlobalAlloc<'tcx> {
381
379
Memory ( & ' tcx Allocation ) ,
382
380
}
383
381
384
- pub struct AllocMap < ' tcx > {
382
+ impl GlobalAlloc < ' tcx > {
383
+ /// Panics if the `GlobalAlloc` does not refer to an `GlobalAlloc::Memory`
384
+ #[ track_caller]
385
+ #[ inline]
386
+ pub fn unwrap_memory ( & self ) -> & ' tcx Allocation {
387
+ match * self {
388
+ GlobalAlloc :: Memory ( mem) => mem,
389
+ _ => bug ! ( "expected memory, got {:?}" , self ) ,
390
+ }
391
+ }
392
+
393
+ /// Panics if the `GlobalAlloc` is not `GlobalAlloc::Function`
394
+ #[ track_caller]
395
+ #[ inline]
396
+ pub fn unwrap_fn ( & self ) -> Instance < ' tcx > {
397
+ match * self {
398
+ GlobalAlloc :: Function ( instance) => instance,
399
+ _ => bug ! ( "expected function, got {:?}" , self ) ,
400
+ }
401
+ }
402
+ }
403
+
404
+ crate struct AllocMap < ' tcx > {
385
405
/// Maps `AllocId`s to their corresponding allocations.
386
406
alloc_map : FxHashMap < AllocId , GlobalAlloc < ' tcx > > ,
387
407
@@ -397,16 +417,10 @@ pub struct AllocMap<'tcx> {
397
417
}
398
418
399
419
impl < ' tcx > AllocMap < ' tcx > {
400
- pub fn new ( ) -> Self {
420
+ crate fn new ( ) -> Self {
401
421
AllocMap { alloc_map : Default :: default ( ) , dedup : Default :: default ( ) , next_id : AllocId ( 0 ) }
402
422
}
403
-
404
- /// Obtains a new allocation ID that can be referenced but does not
405
- /// yet have an allocation backing it.
406
- ///
407
- /// Make sure to call `set_alloc_id_memory` or `set_alloc_id_same_memory` before returning such
408
- /// an `AllocId` from a query.
409
- pub fn reserve ( & mut self ) -> AllocId {
423
+ fn reserve ( & mut self ) -> AllocId {
410
424
let next = self . next_id ;
411
425
self . next_id . 0 = self . next_id . 0 . checked_add ( 1 ) . expect (
412
426
"You overflowed a u64 by incrementing by 1... \
@@ -415,34 +429,46 @@ impl<'tcx> AllocMap<'tcx> {
415
429
) ;
416
430
next
417
431
}
432
+ }
433
+
434
+ impl < ' tcx > TyCtxt < ' tcx > {
435
+ /// Obtains a new allocation ID that can be referenced but does not
436
+ /// yet have an allocation backing it.
437
+ ///
438
+ /// Make sure to call `set_alloc_id_memory` or `set_alloc_id_same_memory` before returning such
439
+ /// an `AllocId` from a query.
440
+ pub fn reserve_alloc_id ( & self ) -> AllocId {
441
+ self . alloc_map . lock ( ) . reserve ( )
442
+ }
418
443
419
444
/// Reserves a new ID *if* this allocation has not been dedup-reserved before.
420
445
/// Should only be used for function pointers and statics, we don't want
421
446
/// to dedup IDs for "real" memory!
422
- fn reserve_and_set_dedup ( & mut self , alloc : GlobalAlloc < ' tcx > ) -> AllocId {
447
+ fn reserve_and_set_dedup ( & self , alloc : GlobalAlloc < ' tcx > ) -> AllocId {
448
+ let mut alloc_map = self . alloc_map . lock ( ) ;
423
449
match alloc {
424
450
GlobalAlloc :: Function ( ..) | GlobalAlloc :: Static ( ..) => { }
425
451
GlobalAlloc :: Memory ( ..) => bug ! ( "Trying to dedup-reserve memory with real data!" ) ,
426
452
}
427
- if let Some ( & alloc_id) = self . dedup . get ( & alloc) {
453
+ if let Some ( & alloc_id) = alloc_map . dedup . get ( & alloc) {
428
454
return alloc_id;
429
455
}
430
- let id = self . reserve ( ) ;
456
+ let id = alloc_map . reserve ( ) ;
431
457
debug ! ( "creating alloc {:?} with id {}" , alloc, id) ;
432
- self . alloc_map . insert ( id, alloc. clone ( ) ) ;
433
- self . dedup . insert ( alloc, id) ;
458
+ alloc_map . alloc_map . insert ( id, alloc. clone ( ) ) ;
459
+ alloc_map . dedup . insert ( alloc, id) ;
434
460
id
435
461
}
436
462
437
463
/// Generates an `AllocId` for a static or return a cached one in case this function has been
438
464
/// called on the same static before.
439
- pub fn create_static_alloc ( & mut self , static_id : DefId ) -> AllocId {
465
+ pub fn create_static_alloc ( & self , static_id : DefId ) -> AllocId {
440
466
self . reserve_and_set_dedup ( GlobalAlloc :: Static ( static_id) )
441
467
}
442
468
443
469
/// Generates an `AllocId` for a function. Depending on the function type,
444
470
/// this might get deduplicated or assigned a new ID each time.
445
- pub fn create_fn_alloc ( & mut self , instance : Instance < ' tcx > ) -> AllocId {
471
+ pub fn create_fn_alloc ( & self , instance : Instance < ' tcx > ) -> AllocId {
446
472
// Functions cannot be identified by pointers, as asm-equal functions can get deduplicated
447
473
// by the linker (we set the "unnamed_addr" attribute for LLVM) and functions can be
448
474
// duplicated across crates.
@@ -456,8 +482,9 @@ impl<'tcx> AllocMap<'tcx> {
456
482
} ) ;
457
483
if is_generic {
458
484
// Get a fresh ID.
459
- let id = self . reserve ( ) ;
460
- self . alloc_map . insert ( id, GlobalAlloc :: Function ( instance) ) ;
485
+ let mut alloc_map = self . alloc_map . lock ( ) ;
486
+ let id = alloc_map. reserve ( ) ;
487
+ alloc_map. alloc_map . insert ( id, GlobalAlloc :: Function ( instance) ) ;
461
488
id
462
489
} else {
463
490
// Deduplicate.
@@ -470,8 +497,8 @@ impl<'tcx> AllocMap<'tcx> {
470
497
/// Statics with identical content will still point to the same `Allocation`, i.e.,
471
498
/// their data will be deduplicated through `Allocation` interning -- but they
472
499
/// are different places in memory and as such need different IDs.
473
- pub fn create_memory_alloc ( & mut self , mem : & ' tcx Allocation ) -> AllocId {
474
- let id = self . reserve ( ) ;
500
+ pub fn create_memory_alloc ( & self , mem : & ' tcx Allocation ) -> AllocId {
501
+ let id = self . reserve_alloc_id ( ) ;
475
502
self . set_alloc_id_memory ( id, mem) ;
476
503
id
477
504
}
@@ -482,38 +509,35 @@ impl<'tcx> AllocMap<'tcx> {
482
509
/// This function exists to allow const eval to detect the difference between evaluation-
483
510
/// local dangling pointers and allocations in constants/statics.
484
511
#[ inline]
485
- pub fn get ( & self , id : AllocId ) -> Option < GlobalAlloc < ' tcx > > {
486
- self . alloc_map . get ( & id) . cloned ( )
487
- }
488
-
489
- /// Panics if the `AllocId` does not refer to an `Allocation`
490
- pub fn unwrap_memory ( & self , id : AllocId ) -> & ' tcx Allocation {
491
- match self . get ( id) {
492
- Some ( GlobalAlloc :: Memory ( mem) ) => mem,
493
- _ => bug ! ( "expected allocation ID {} to point to memory" , id) ,
494
- }
512
+ pub fn get_global_alloc ( & self , id : AllocId ) -> Option < GlobalAlloc < ' tcx > > {
513
+ self . alloc_map . lock ( ) . alloc_map . get ( & id) . cloned ( )
495
514
}
496
515
497
- /// Panics if the `AllocId` does not refer to a function
498
- pub fn unwrap_fn ( & self , id : AllocId ) -> Instance < ' tcx > {
499
- match self . get ( id) {
500
- Some ( GlobalAlloc :: Function ( instance) ) => instance,
501
- _ => bug ! ( "expected allocation ID {} to point to a function" , id) ,
516
+ #[ inline]
517
+ #[ track_caller]
518
+ /// Panics in case the `AllocId` is dangling. Since that is impossible for `AllocId`s in
519
+ /// constants (as all constants must pass interning and validation that check for dangling
520
+ /// ids), this function is frequently used throughout rustc, but should not be used within
521
+ /// the miri engine.
522
+ pub fn global_alloc ( & self , id : AllocId ) -> GlobalAlloc < ' tcx > {
523
+ match self . get_global_alloc ( id) {
524
+ Some ( alloc) => alloc,
525
+ None => bug ! ( "could not find allocation for {}" , id) ,
502
526
}
503
527
}
504
528
505
529
/// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. Trying to
506
530
/// call this function twice, even with the same `Allocation` will ICE the compiler.
507
- pub fn set_alloc_id_memory ( & mut self , id : AllocId , mem : & ' tcx Allocation ) {
508
- if let Some ( old) = self . alloc_map . insert ( id, GlobalAlloc :: Memory ( mem) ) {
531
+ pub fn set_alloc_id_memory ( & self , id : AllocId , mem : & ' tcx Allocation ) {
532
+ if let Some ( old) = self . alloc_map . lock ( ) . alloc_map . insert ( id, GlobalAlloc :: Memory ( mem) ) {
509
533
bug ! ( "tried to set allocation ID {}, but it was already existing as {:#?}" , id, old) ;
510
534
}
511
535
}
512
536
513
537
/// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. May be called
514
538
/// twice for the same `(AllocId, Allocation)` pair.
515
- fn set_alloc_id_same_memory ( & mut self , id : AllocId , mem : & ' tcx Allocation ) {
516
- self . alloc_map . insert_same ( id, GlobalAlloc :: Memory ( mem) ) ;
539
+ fn set_alloc_id_same_memory ( & self , id : AllocId , mem : & ' tcx Allocation ) {
540
+ self . alloc_map . lock ( ) . alloc_map . insert_same ( id, GlobalAlloc :: Memory ( mem) ) ;
517
541
}
518
542
}
519
543
0 commit comments