@@ -72,20 +72,20 @@ pub fn specialized_encode_alloc_id<
7272 tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
7373 alloc_id : AllocId ,
7474) -> Result < ( ) , E :: Error > {
75- let alloc_kind : AllocKind < ' tcx > =
75+ let alloc : GlobalAlloc < ' tcx > =
7676 tcx. alloc_map . lock ( ) . get ( alloc_id) . expect ( "no value for AllocId" ) ;
77- match alloc_kind {
78- AllocKind :: Memory ( alloc) => {
77+ match alloc {
78+ GlobalAlloc :: Memory ( alloc) => {
7979 trace ! ( "encoding {:?} with {:#?}" , alloc_id, alloc) ;
8080 AllocDiscriminant :: Alloc . encode ( encoder) ?;
8181 alloc. encode ( encoder) ?;
8282 }
83- AllocKind :: Function ( fn_instance) => {
83+ GlobalAlloc :: Function ( fn_instance) => {
8484 trace ! ( "encoding {:?} with {:#?}" , alloc_id, fn_instance) ;
8585 AllocDiscriminant :: Fn . encode ( encoder) ?;
8686 fn_instance. encode ( encoder) ?;
8787 }
88- AllocKind :: Static ( did) => {
88+ GlobalAlloc :: Static ( did) => {
8989 // referring to statics doesn't need to know about their allocations,
9090 // just about its DefId
9191 AllocDiscriminant :: Static . encode ( encoder) ?;
@@ -239,7 +239,7 @@ impl<'s> AllocDecodingSession<'s> {
239239 assert ! ( alloc_id. is_none( ) ) ;
240240 trace ! ( "creating extern static alloc id at" ) ;
241241 let did = DefId :: decode ( decoder) ?;
242- let alloc_id = decoder. tcx ( ) . alloc_map . lock ( ) . intern_static ( did) ;
242+ let alloc_id = decoder. tcx ( ) . alloc_map . lock ( ) . create_static_alloc ( did) ;
243243 Ok ( alloc_id)
244244 }
245245 }
@@ -259,8 +259,10 @@ impl fmt::Display for AllocId {
259259 }
260260}
261261
262+ /// An allocation in the global (tcx-managed) memory can be either a function pointer,
263+ /// a static, or a "real" allocation with some data in it.
262264#[ derive( Debug , Clone , Eq , PartialEq , Hash , RustcDecodable , RustcEncodable , HashStable ) ]
263- pub enum AllocKind < ' tcx > {
265+ pub enum GlobalAlloc < ' tcx > {
264266 /// The alloc ID is used as a function pointer
265267 Function ( Instance < ' tcx > ) ,
266268 /// The alloc ID points to a "lazy" static variable that did not get computed (yet).
@@ -272,10 +274,12 @@ pub enum AllocKind<'tcx> {
272274
273275pub struct AllocMap < ' tcx > {
274276 /// Lets you know what an `AllocId` refers to.
275- id_to_kind : FxHashMap < AllocId , AllocKind < ' tcx > > ,
277+ alloc_map : FxHashMap < AllocId , GlobalAlloc < ' tcx > > ,
276278
277- /// Used to ensure that statics only get one associated `AllocId`.
278- type_interner : FxHashMap < AllocKind < ' tcx > , AllocId > ,
279+ /// Used to ensure that statics and functions only get one associated `AllocId`.
280+ /// Should never contain a `GlobalAlloc::Memory`!
281+ /// FIXME: Should we just have two separate dedup maps for statics and functions each?
282+ dedup : FxHashMap < GlobalAlloc < ' tcx > , AllocId > ,
279283
280284 /// The `AllocId` to assign to the next requested ID.
281285 /// Always incremented, never gets smaller.
@@ -285,8 +289,8 @@ pub struct AllocMap<'tcx> {
285289impl < ' tcx > AllocMap < ' tcx > {
286290 pub fn new ( ) -> Self {
287291 AllocMap {
288- id_to_kind : Default :: default ( ) ,
289- type_interner : Default :: default ( ) ,
292+ alloc_map : Default :: default ( ) ,
293+ dedup : Default :: default ( ) ,
290294 next_id : AllocId ( 0 ) ,
291295 }
292296 }
@@ -308,17 +312,32 @@ impl<'tcx> AllocMap<'tcx> {
308312 next
309313 }
310314
311- fn intern ( & mut self , alloc_kind : AllocKind < ' tcx > ) -> AllocId {
312- if let Some ( & alloc_id) = self . type_interner . get ( & alloc_kind) {
315+ /// Reserve a new ID *if* this allocation has not been dedup-reserved before.
316+ /// Should only be used for function pointers and statics, we don't want
317+ /// to dedup IDs for "real" memory!
318+ fn reserve_and_set_dedup ( & mut self , alloc : GlobalAlloc < ' tcx > ) -> AllocId {
319+ match alloc {
320+ GlobalAlloc :: Function ( ..) | GlobalAlloc :: Static ( ..) => { } ,
321+ GlobalAlloc :: Memory ( ..) => bug ! ( "Trying to dedup-reserve memory with real data!" ) ,
322+ }
323+ if let Some ( & alloc_id) = self . dedup . get ( & alloc) {
313324 return alloc_id;
314325 }
315326 let id = self . reserve ( ) ;
316- debug ! ( "creating alloc_kind {:?} with id {}" , alloc_kind , id) ;
317- self . id_to_kind . insert ( id, alloc_kind . clone ( ) ) ;
318- self . type_interner . insert ( alloc_kind , id) ;
327+ debug ! ( "creating alloc {:?} with id {}" , alloc , id) ;
328+ self . alloc_map . insert ( id, alloc . clone ( ) ) ;
329+ self . dedup . insert ( alloc , id) ;
319330 id
320331 }
321332
333+ /// Generates an `AllocId` for a static or return a cached one in case this function has been
334+ /// called on the same static before.
335+ pub fn create_static_alloc ( & mut self , static_id : DefId ) -> AllocId {
336+ self . reserve_and_set_dedup ( GlobalAlloc :: Static ( static_id) )
337+ }
338+
339+ /// Generates an `AllocId` for a function. Depending on the function type,
340+ /// this might get deduplicated or assigned a new ID each time.
322341 pub fn create_fn_alloc ( & mut self , instance : Instance < ' tcx > ) -> AllocId {
323342 // Functions cannot be identified by pointers, as asm-equal functions can get deduplicated
324343 // by the linker (we set the "unnamed_addr" attribute for LLVM) and functions can be
@@ -336,61 +355,55 @@ impl<'tcx> AllocMap<'tcx> {
336355 if is_generic {
337356 // Get a fresh ID
338357 let id = self . reserve ( ) ;
339- self . id_to_kind . insert ( id, AllocKind :: Function ( instance) ) ;
358+ self . alloc_map . insert ( id, GlobalAlloc :: Function ( instance) ) ;
340359 id
341360 } else {
342361 // Deduplicate
343- self . intern ( AllocKind :: Function ( instance) )
362+ self . reserve_and_set_dedup ( GlobalAlloc :: Function ( instance) )
344363 }
345364 }
346365
366+ /// Intern the `Allocation` and return a new `AllocId`, even if there's already an identical
367+ /// `Allocation` with a different `AllocId`.
368+ /// Statics with identical content will still point to the same `Allocation`, i.e.,
369+ /// their data will be deduplicated through `Allocation` interning -- but they
370+ /// are different places in memory and as such need different IDs.
371+ pub fn create_memory_alloc ( & mut self , mem : & ' tcx Allocation ) -> AllocId {
372+ let id = self . reserve ( ) ;
373+ self . set_alloc_id_memory ( id, mem) ;
374+ id
375+ }
376+
347377 /// Returns `None` in case the `AllocId` is dangling. An `InterpretCx` can still have a
348378 /// local `Allocation` for that `AllocId`, but having such an `AllocId` in a constant is
349379 /// illegal and will likely ICE.
350380 /// This function exists to allow const eval to detect the difference between evaluation-
351381 /// local dangling pointers and allocations in constants/statics.
352382 #[ inline]
353- pub fn get ( & self , id : AllocId ) -> Option < AllocKind < ' tcx > > {
354- self . id_to_kind . get ( & id) . cloned ( )
383+ pub fn get ( & self , id : AllocId ) -> Option < GlobalAlloc < ' tcx > > {
384+ self . alloc_map . get ( & id) . cloned ( )
355385 }
356386
357387 /// Panics if the `AllocId` does not refer to an `Allocation`
358388 pub fn unwrap_memory ( & self , id : AllocId ) -> & ' tcx Allocation {
359389 match self . get ( id) {
360- Some ( AllocKind :: Memory ( mem) ) => mem,
390+ Some ( GlobalAlloc :: Memory ( mem) ) => mem,
361391 _ => bug ! ( "expected allocation id {} to point to memory" , id) ,
362392 }
363393 }
364394
365- /// Generates an `AllocId` for a static or return a cached one in case this function has been
366- /// called on the same static before.
367- pub fn intern_static ( & mut self , static_id : DefId ) -> AllocId {
368- self . intern ( AllocKind :: Static ( static_id) )
369- }
370-
371- /// Intern the `Allocation` and return a new `AllocId`, even if there's already an identical
372- /// `Allocation` with a different `AllocId`.
373- // FIXME: is this really necessary? Can we ensure `FOO` and `BAR` being different after codegen
374- // in `static FOO: u32 = 42; static BAR: u32 = 42;` even if they reuse the same allocation
375- // inside rustc?
376- pub fn allocate ( & mut self , mem : & ' tcx Allocation ) -> AllocId {
377- let id = self . reserve ( ) ;
378- self . set_alloc_id_memory ( id, mem) ;
379- id
380- }
381-
382395 /// Freeze an `AllocId` created with `reserve` by pointing it at an `Allocation`. Trying to
383396 /// call this function twice, even with the same `Allocation` will ICE the compiler.
384397 pub fn set_alloc_id_memory ( & mut self , id : AllocId , mem : & ' tcx Allocation ) {
385- if let Some ( old) = self . id_to_kind . insert ( id, AllocKind :: Memory ( mem) ) {
398+ if let Some ( old) = self . alloc_map . insert ( id, GlobalAlloc :: Memory ( mem) ) {
386399 bug ! ( "tried to set allocation id {}, but it was already existing as {:#?}" , id, old) ;
387400 }
388401 }
389402
390403 /// Freeze an `AllocId` created with `reserve` by pointing it at an `Allocation`. May be called
391404 /// twice for the same `(AllocId, Allocation)` pair.
392405 fn set_alloc_id_same_memory ( & mut self , id : AllocId , mem : & ' tcx Allocation ) {
393- self . id_to_kind . insert_same ( id, AllocKind :: Memory ( mem) ) ;
406+ self . alloc_map . insert_same ( id, GlobalAlloc :: Memory ( mem) ) ;
394407 }
395408}
396409
0 commit comments