@@ -13,7 +13,6 @@ use std::num::NonZero;
13
13
use std:: { fmt, io} ;
14
14
15
15
use rustc_ast:: LitKind ;
16
- use rustc_attr:: InlineAttr ;
17
16
use rustc_data_structures:: fx:: FxHashMap ;
18
17
use rustc_data_structures:: sync:: Lock ;
19
18
use rustc_errors:: ErrorGuaranteed ;
@@ -46,7 +45,7 @@ pub use self::pointer::{CtfeProvenance, Pointer, PointerArithmetic, Provenance};
46
45
pub use self :: value:: Scalar ;
47
46
use crate :: mir;
48
47
use crate :: ty:: codec:: { TyDecoder , TyEncoder } ;
49
- use crate :: ty:: { self , GenericArgKind , Instance , Ty , TyCtxt } ;
48
+ use crate :: ty:: { self , Instance , Ty , TyCtxt } ;
50
49
51
50
/// Uniquely identifies one of the following:
52
51
/// - A constant
@@ -126,11 +125,10 @@ pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>>(
126
125
AllocDiscriminant :: Alloc . encode ( encoder) ;
127
126
alloc. encode ( encoder) ;
128
127
}
129
- GlobalAlloc :: Function { instance, unique } => {
128
+ GlobalAlloc :: Function { instance } => {
130
129
trace ! ( "encoding {:?} with {:#?}" , alloc_id, instance) ;
131
130
AllocDiscriminant :: Fn . encode ( encoder) ;
132
131
instance. encode ( encoder) ;
133
- unique. encode ( encoder) ;
134
132
}
135
133
GlobalAlloc :: VTable ( ty, poly_trait_ref) => {
136
134
trace ! ( "encoding {:?} with {ty:#?}, {poly_trait_ref:#?}" , alloc_id) ;
@@ -219,38 +217,32 @@ impl<'s> AllocDecodingSession<'s> {
219
217
}
220
218
221
219
// Now decode the actual data.
222
- let alloc_id = decoder. with_position ( pos, |decoder| {
223
- match alloc_kind {
224
- AllocDiscriminant :: Alloc => {
225
- trace ! ( "creating memory alloc ID" ) ;
226
- let alloc = <ConstAllocation < ' tcx > as Decodable < _ > >:: decode ( decoder) ;
227
- trace ! ( "decoded alloc {:?}" , alloc) ;
228
- decoder. interner ( ) . reserve_and_set_memory_alloc ( alloc)
229
- }
230
- AllocDiscriminant :: Fn => {
231
- trace ! ( "creating fn alloc ID" ) ;
232
- let instance = ty:: Instance :: decode ( decoder) ;
233
- trace ! ( "decoded fn alloc instance: {:?}" , instance) ;
234
- let unique = bool:: decode ( decoder) ;
235
- // Here we cannot call `reserve_and_set_fn_alloc` as that would use a query, which
236
- // is not possible in this context. That's why the allocation stores
237
- // whether it is unique or not.
238
- decoder. interner ( ) . reserve_and_set_fn_alloc_internal ( instance, unique)
239
- }
240
- AllocDiscriminant :: VTable => {
241
- trace ! ( "creating vtable alloc ID" ) ;
242
- let ty = <Ty < ' _ > as Decodable < D > >:: decode ( decoder) ;
243
- let poly_trait_ref =
244
- <Option < ty:: PolyExistentialTraitRef < ' _ > > as Decodable < D > >:: decode ( decoder) ;
245
- trace ! ( "decoded vtable alloc instance: {ty:?}, {poly_trait_ref:?}" ) ;
246
- decoder. interner ( ) . reserve_and_set_vtable_alloc ( ty, poly_trait_ref)
247
- }
248
- AllocDiscriminant :: Static => {
249
- trace ! ( "creating extern static alloc ID" ) ;
250
- let did = <DefId as Decodable < D > >:: decode ( decoder) ;
251
- trace ! ( "decoded static def-ID: {:?}" , did) ;
252
- decoder. interner ( ) . reserve_and_set_static_alloc ( did)
253
- }
220
+ let alloc_id = decoder. with_position ( pos, |decoder| match alloc_kind {
221
+ AllocDiscriminant :: Alloc => {
222
+ trace ! ( "creating memory alloc ID" ) ;
223
+ let alloc = <ConstAllocation < ' tcx > as Decodable < _ > >:: decode ( decoder) ;
224
+ trace ! ( "decoded alloc {:?}" , alloc) ;
225
+ decoder. interner ( ) . reserve_and_set_memory_alloc ( alloc)
226
+ }
227
+ AllocDiscriminant :: Fn => {
228
+ trace ! ( "creating fn alloc ID" ) ;
229
+ let instance = ty:: Instance :: decode ( decoder) ;
230
+ trace ! ( "decoded fn alloc instance: {:?}" , instance) ;
231
+ decoder. interner ( ) . reserve_and_set_fn_alloc ( instance, CTFE_ALLOC_SALT )
232
+ }
233
+ AllocDiscriminant :: VTable => {
234
+ trace ! ( "creating vtable alloc ID" ) ;
235
+ let ty = <Ty < ' _ > as Decodable < D > >:: decode ( decoder) ;
236
+ let poly_trait_ref =
237
+ <Option < ty:: PolyExistentialTraitRef < ' _ > > as Decodable < D > >:: decode ( decoder) ;
238
+ trace ! ( "decoded vtable alloc instance: {ty:?}, {poly_trait_ref:?}" ) ;
239
+ decoder. interner ( ) . reserve_and_set_vtable_alloc ( ty, poly_trait_ref, CTFE_ALLOC_SALT )
240
+ }
241
+ AllocDiscriminant :: Static => {
242
+ trace ! ( "creating extern static alloc ID" ) ;
243
+ let did = <DefId as Decodable < D > >:: decode ( decoder) ;
244
+ trace ! ( "decoded static def-ID: {:?}" , did) ;
245
+ decoder. interner ( ) . reserve_and_set_static_alloc ( did)
254
246
}
255
247
} ) ;
256
248
@@ -265,12 +257,7 @@ impl<'s> AllocDecodingSession<'s> {
265
257
#[ derive( Debug , Clone , Eq , PartialEq , Hash , TyDecodable , TyEncodable , HashStable ) ]
266
258
pub enum GlobalAlloc < ' tcx > {
267
259
/// The alloc ID is used as a function pointer.
268
- Function {
269
- instance : Instance < ' tcx > ,
270
- /// Stores whether this instance is unique, i.e. all pointers to this function use the same
271
- /// alloc ID.
272
- unique : bool ,
273
- } ,
260
+ Function { instance : Instance < ' tcx > } ,
274
261
/// This alloc ID points to a symbolic (not-reified) vtable.
275
262
VTable ( Ty < ' tcx > , Option < ty:: PolyExistentialTraitRef < ' tcx > > ) ,
276
263
/// The alloc ID points to a "lazy" static variable that did not get computed (yet).
@@ -323,14 +310,17 @@ impl<'tcx> GlobalAlloc<'tcx> {
323
310
}
324
311
}
325
312
313
+ pub const CTFE_ALLOC_SALT : usize = 0 ;
314
+
326
315
pub ( crate ) struct AllocMap < ' tcx > {
327
316
/// Maps `AllocId`s to their corresponding allocations.
328
317
alloc_map : FxHashMap < AllocId , GlobalAlloc < ' tcx > > ,
329
318
330
- /// Used to ensure that statics and functions only get one associated `AllocId`.
331
- //
332
- // FIXME: Should we just have two separate dedup maps for statics and functions each?
333
- dedup : FxHashMap < GlobalAlloc < ' tcx > , AllocId > ,
319
+ /// Used to deduplicate global allocations: functions, vtables, string literals, ...
320
+ ///
321
+ /// The `usize` is a "salt" used by Miri to make deduplication imperfect, thus better emulating
322
+ /// the actual guarantees.
323
+ dedup : FxHashMap < ( GlobalAlloc < ' tcx > , usize ) , AllocId > ,
334
324
335
325
/// The `AllocId` to assign to the next requested ID.
336
326
/// Always incremented; never gets smaller.
@@ -368,83 +358,50 @@ impl<'tcx> TyCtxt<'tcx> {
368
358
369
359
/// Reserves a new ID *if* this allocation has not been dedup-reserved before.
370
360
/// Should not be used for mutable memory.
371
- fn reserve_and_set_dedup ( self , alloc : GlobalAlloc < ' tcx > ) -> AllocId {
361
+ fn reserve_and_set_dedup ( self , alloc : GlobalAlloc < ' tcx > , salt : usize ) -> AllocId {
372
362
let mut alloc_map = self . alloc_map . lock ( ) ;
373
363
if let GlobalAlloc :: Memory ( mem) = alloc {
374
364
if mem. inner ( ) . mutability . is_mut ( ) {
375
365
bug ! ( "trying to dedup-reserve mutable memory" ) ;
376
366
}
377
367
}
378
- if let Some ( & alloc_id) = alloc_map. dedup . get ( & alloc) {
368
+ let alloc_salt = ( alloc, salt) ;
369
+ if let Some ( & alloc_id) = alloc_map. dedup . get ( & alloc_salt) {
379
370
return alloc_id;
380
371
}
381
372
let id = alloc_map. reserve ( ) ;
382
- debug ! ( "creating alloc {alloc :?} with id {id:?}" ) ;
383
- alloc_map. alloc_map . insert ( id, alloc . clone ( ) ) ;
384
- alloc_map. dedup . insert ( alloc , id) ;
373
+ debug ! ( "creating alloc {:?} with id {id:?}" , alloc_salt . 0 ) ;
374
+ alloc_map. alloc_map . insert ( id, alloc_salt . 0 . clone ( ) ) ;
375
+ alloc_map. dedup . insert ( alloc_salt , id) ;
385
376
id
386
377
}
387
378
388
379
/// Generates an `AllocId` for a memory allocation. If the exact same memory has been
389
380
/// allocated before, this will return the same `AllocId`.
390
- pub fn reserve_and_set_memory_dedup ( self , mem : ConstAllocation < ' tcx > ) -> AllocId {
391
- self . reserve_and_set_dedup ( GlobalAlloc :: Memory ( mem) )
381
+ pub fn reserve_and_set_memory_dedup ( self , mem : ConstAllocation < ' tcx > , salt : usize ) -> AllocId {
382
+ self . reserve_and_set_dedup ( GlobalAlloc :: Memory ( mem) , salt )
392
383
}
393
384
394
385
/// Generates an `AllocId` for a static or return a cached one in case this function has been
395
386
/// called on the same static before.
396
387
pub fn reserve_and_set_static_alloc ( self , static_id : DefId ) -> AllocId {
397
- self . reserve_and_set_dedup ( GlobalAlloc :: Static ( static_id) )
398
- }
399
-
400
- /// Generates an `AllocId` for a function. The caller must already have decided whether this
401
- /// function obtains a unique AllocId or gets de-duplicated via the cache.
402
- fn reserve_and_set_fn_alloc_internal ( self , instance : Instance < ' tcx > , unique : bool ) -> AllocId {
403
- let alloc = GlobalAlloc :: Function { instance, unique } ;
404
- if unique {
405
- // Deduplicate.
406
- self . reserve_and_set_dedup ( alloc)
407
- } else {
408
- // Get a fresh ID.
409
- let mut alloc_map = self . alloc_map . lock ( ) ;
410
- let id = alloc_map. reserve ( ) ;
411
- alloc_map. alloc_map . insert ( id, alloc) ;
412
- id
413
- }
388
+ let salt = 0 ; // Statics have a guaranteed unique address, no salt added.
389
+ self . reserve_and_set_dedup ( GlobalAlloc :: Static ( static_id) , salt)
414
390
}
415
391
416
- /// Generates an `AllocId` for a function. Depending on the function type,
417
- /// this might get deduplicated or assigned a new ID each time.
418
- pub fn reserve_and_set_fn_alloc ( self , instance : Instance < ' tcx > ) -> AllocId {
419
- // Functions cannot be identified by pointers, as asm-equal functions can get deduplicated
420
- // by the linker (we set the "unnamed_addr" attribute for LLVM) and functions can be
421
- // duplicated across crates. We thus generate a new `AllocId` for every mention of a
422
- // function. This means that `main as fn() == main as fn()` is false, while `let x = main as
423
- // fn(); x == x` is true. However, as a quality-of-life feature it can be useful to identify
424
- // certain functions uniquely, e.g. for backtraces. So we identify whether codegen will
425
- // actually emit duplicate functions. It does that when they have non-lifetime generics, or
426
- // when they can be inlined. All other functions are given a unique address.
427
- // This is not a stable guarantee! The `inline` attribute is a hint and cannot be relied
428
- // upon for anything. But if we don't do this, backtraces look terrible.
429
- let is_generic = instance
430
- . args
431
- . into_iter ( )
432
- . any ( |kind| !matches ! ( kind. unpack( ) , GenericArgKind :: Lifetime ( _) ) ) ;
433
- let can_be_inlined = match self . codegen_fn_attrs ( instance. def_id ( ) ) . inline {
434
- InlineAttr :: Never => false ,
435
- _ => true ,
436
- } ;
437
- let unique = !is_generic && !can_be_inlined;
438
- self . reserve_and_set_fn_alloc_internal ( instance, unique)
392
+ /// Generates an `AllocId` for a function. Will get deduplicated.
393
+ pub fn reserve_and_set_fn_alloc ( self , instance : Instance < ' tcx > , salt : usize ) -> AllocId {
394
+ self . reserve_and_set_dedup ( GlobalAlloc :: Function { instance } , salt)
439
395
}
440
396
441
397
/// Generates an `AllocId` for a (symbolic, not-reified) vtable. Will get deduplicated.
442
398
pub fn reserve_and_set_vtable_alloc (
443
399
self ,
444
400
ty : Ty < ' tcx > ,
445
401
poly_trait_ref : Option < ty:: PolyExistentialTraitRef < ' tcx > > ,
402
+ salt : usize ,
446
403
) -> AllocId {
447
- self . reserve_and_set_dedup ( GlobalAlloc :: VTable ( ty, poly_trait_ref) )
404
+ self . reserve_and_set_dedup ( GlobalAlloc :: VTable ( ty, poly_trait_ref) , salt )
448
405
}
449
406
450
407
/// Interns the `Allocation` and return a new `AllocId`, even if there's already an identical
0 commit comments