@@ -13,7 +13,6 @@ use std::num::NonZero;
1313use std:: { fmt, io} ;
1414
1515use rustc_ast:: LitKind ;
16- use rustc_attr:: InlineAttr ;
1716use rustc_data_structures:: fx:: FxHashMap ;
1817use rustc_data_structures:: sync:: Lock ;
1918use rustc_errors:: ErrorGuaranteed ;
@@ -46,7 +45,7 @@ pub use self::pointer::{CtfeProvenance, Pointer, PointerArithmetic, Provenance};
4645pub use self :: value:: Scalar ;
4746use crate :: mir;
4847use crate :: ty:: codec:: { TyDecoder , TyEncoder } ;
49- use crate :: ty:: { self , GenericArgKind , Instance , Ty , TyCtxt } ;
48+ use crate :: ty:: { self , Instance , Ty , TyCtxt } ;
5049
5150/// Uniquely identifies one of the following:
5251/// - A constant
@@ -126,11 +125,10 @@ pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>>(
126125 AllocDiscriminant :: Alloc . encode ( encoder) ;
127126 alloc. encode ( encoder) ;
128127 }
129- GlobalAlloc :: Function { instance, unique } => {
128+ GlobalAlloc :: Function { instance } => {
130129 trace ! ( "encoding {:?} with {:#?}" , alloc_id, instance) ;
131130 AllocDiscriminant :: Fn . encode ( encoder) ;
132131 instance. encode ( encoder) ;
133- unique. encode ( encoder) ;
134132 }
135133 GlobalAlloc :: VTable ( ty, poly_trait_ref) => {
136134 trace ! ( "encoding {:?} with {ty:#?}, {poly_trait_ref:#?}" , alloc_id) ;
@@ -219,38 +217,32 @@ impl<'s> AllocDecodingSession<'s> {
219217 }
220218
221219 // 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)
254246 }
255247 } ) ;
256248
@@ -265,12 +257,7 @@ impl<'s> AllocDecodingSession<'s> {
265257#[ derive( Debug , Clone , Eq , PartialEq , Hash , TyDecodable , TyEncodable , HashStable ) ]
266258pub enum GlobalAlloc < ' tcx > {
267259 /// 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 > } ,
274261 /// This alloc ID points to a symbolic (not-reified) vtable.
275262 VTable ( Ty < ' tcx > , Option < ty:: PolyExistentialTraitRef < ' tcx > > ) ,
276263 /// The alloc ID points to a "lazy" static variable that did not get computed (yet).
@@ -323,14 +310,17 @@ impl<'tcx> GlobalAlloc<'tcx> {
323310 }
324311}
325312
313+ pub const CTFE_ALLOC_SALT : usize = 0 ;
314+
326315pub ( crate ) struct AllocMap < ' tcx > {
327316 /// Maps `AllocId`s to their corresponding allocations.
328317 alloc_map : FxHashMap < AllocId , GlobalAlloc < ' tcx > > ,
329318
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 > ,
334324
335325 /// The `AllocId` to assign to the next requested ID.
336326 /// Always incremented; never gets smaller.
@@ -368,83 +358,50 @@ impl<'tcx> TyCtxt<'tcx> {
368358
369359 /// Reserves a new ID *if* this allocation has not been dedup-reserved before.
370360 /// 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 {
372362 let mut alloc_map = self . alloc_map . lock ( ) ;
373363 if let GlobalAlloc :: Memory ( mem) = alloc {
374364 if mem. inner ( ) . mutability . is_mut ( ) {
375365 bug ! ( "trying to dedup-reserve mutable memory" ) ;
376366 }
377367 }
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) {
379370 return alloc_id;
380371 }
381372 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) ;
385376 id
386377 }
387378
388379 /// Generates an `AllocId` for a memory allocation. If the exact same memory has been
389380 /// 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 )
392383 }
393384
394385 /// Generates an `AllocId` for a static or return a cached one in case this function has been
395386 /// called on the same static before.
396387 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)
414390 }
415391
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)
439395 }
440396
441397 /// Generates an `AllocId` for a (symbolic, not-reified) vtable. Will get deduplicated.
442398 pub fn reserve_and_set_vtable_alloc (
443399 self ,
444400 ty : Ty < ' tcx > ,
445401 poly_trait_ref : Option < ty:: PolyExistentialTraitRef < ' tcx > > ,
402+ salt : usize ,
446403 ) -> 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 )
448405 }
449406
450407 /// Interns the `Allocation` and return a new `AllocId`, even if there's already an identical
0 commit comments