@@ -72,20 +72,20 @@ pub fn specialized_encode_alloc_id<
72
72
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
73
73
alloc_id : AllocId ,
74
74
) -> Result < ( ) , E :: Error > {
75
- let alloc_kind : AllocKind < ' tcx > =
75
+ let alloc : GlobalAlloc < ' tcx > =
76
76
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) => {
79
79
trace ! ( "encoding {:?} with {:#?}" , alloc_id, alloc) ;
80
80
AllocDiscriminant :: Alloc . encode ( encoder) ?;
81
81
alloc. encode ( encoder) ?;
82
82
}
83
- AllocKind :: Function ( fn_instance) => {
83
+ GlobalAlloc :: Function ( fn_instance) => {
84
84
trace ! ( "encoding {:?} with {:#?}" , alloc_id, fn_instance) ;
85
85
AllocDiscriminant :: Fn . encode ( encoder) ?;
86
86
fn_instance. encode ( encoder) ?;
87
87
}
88
- AllocKind :: Static ( did) => {
88
+ GlobalAlloc :: Static ( did) => {
89
89
// referring to statics doesn't need to know about their allocations,
90
90
// just about its DefId
91
91
AllocDiscriminant :: Static . encode ( encoder) ?;
@@ -239,7 +239,7 @@ impl<'s> AllocDecodingSession<'s> {
239
239
assert ! ( alloc_id. is_none( ) ) ;
240
240
trace ! ( "creating extern static alloc id at" ) ;
241
241
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) ;
243
243
Ok ( alloc_id)
244
244
}
245
245
}
@@ -259,8 +259,10 @@ impl fmt::Display for AllocId {
259
259
}
260
260
}
261
261
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.
262
264
#[ derive( Debug , Clone , Eq , PartialEq , Hash , RustcDecodable , RustcEncodable , HashStable ) ]
263
- pub enum AllocKind < ' tcx > {
265
+ pub enum GlobalAlloc < ' tcx > {
264
266
/// The alloc ID is used as a function pointer
265
267
Function ( Instance < ' tcx > ) ,
266
268
/// The alloc ID points to a "lazy" static variable that did not get computed (yet).
@@ -272,10 +274,12 @@ pub enum AllocKind<'tcx> {
272
274
273
275
pub struct AllocMap < ' tcx > {
274
276
/// Lets you know what an `AllocId` refers to.
275
- id_to_kind : FxHashMap < AllocId , AllocKind < ' tcx > > ,
277
+ alloc_map : FxHashMap < AllocId , GlobalAlloc < ' tcx > > ,
276
278
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 > ,
279
283
280
284
/// The `AllocId` to assign to the next requested ID.
281
285
/// Always incremented, never gets smaller.
@@ -285,8 +289,8 @@ pub struct AllocMap<'tcx> {
285
289
impl < ' tcx > AllocMap < ' tcx > {
286
290
pub fn new ( ) -> Self {
287
291
AllocMap {
288
- id_to_kind : Default :: default ( ) ,
289
- type_interner : Default :: default ( ) ,
292
+ alloc_map : Default :: default ( ) ,
293
+ dedup : Default :: default ( ) ,
290
294
next_id : AllocId ( 0 ) ,
291
295
}
292
296
}
@@ -308,17 +312,32 @@ impl<'tcx> AllocMap<'tcx> {
308
312
next
309
313
}
310
314
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) {
313
324
return alloc_id;
314
325
}
315
326
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) ;
319
330
id
320
331
}
321
332
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.
322
341
pub fn create_fn_alloc ( & mut self , instance : Instance < ' tcx > ) -> AllocId {
323
342
// Functions cannot be identified by pointers, as asm-equal functions can get deduplicated
324
343
// by the linker (we set the "unnamed_addr" attribute for LLVM) and functions can be
@@ -336,61 +355,55 @@ impl<'tcx> AllocMap<'tcx> {
336
355
if is_generic {
337
356
// Get a fresh ID
338
357
let id = self . reserve ( ) ;
339
- self . id_to_kind . insert ( id, AllocKind :: Function ( instance) ) ;
358
+ self . alloc_map . insert ( id, GlobalAlloc :: Function ( instance) ) ;
340
359
id
341
360
} else {
342
361
// Deduplicate
343
- self . intern ( AllocKind :: Function ( instance) )
362
+ self . reserve_and_set_dedup ( GlobalAlloc :: Function ( instance) )
344
363
}
345
364
}
346
365
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
+
347
377
/// Returns `None` in case the `AllocId` is dangling. An `InterpretCx` can still have a
348
378
/// local `Allocation` for that `AllocId`, but having such an `AllocId` in a constant is
349
379
/// illegal and will likely ICE.
350
380
/// This function exists to allow const eval to detect the difference between evaluation-
351
381
/// local dangling pointers and allocations in constants/statics.
352
382
#[ 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 ( )
355
385
}
356
386
357
387
/// Panics if the `AllocId` does not refer to an `Allocation`
358
388
pub fn unwrap_memory ( & self , id : AllocId ) -> & ' tcx Allocation {
359
389
match self . get ( id) {
360
- Some ( AllocKind :: Memory ( mem) ) => mem,
390
+ Some ( GlobalAlloc :: Memory ( mem) ) => mem,
361
391
_ => bug ! ( "expected allocation id {} to point to memory" , id) ,
362
392
}
363
393
}
364
394
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
-
382
395
/// Freeze an `AllocId` created with `reserve` by pointing it at an `Allocation`. Trying to
383
396
/// call this function twice, even with the same `Allocation` will ICE the compiler.
384
397
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) ) {
386
399
bug ! ( "tried to set allocation id {}, but it was already existing as {:#?}" , id, old) ;
387
400
}
388
401
}
389
402
390
403
/// Freeze an `AllocId` created with `reserve` by pointing it at an `Allocation`. May be called
391
404
/// twice for the same `(AllocId, Allocation)` pair.
392
405
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) ) ;
394
407
}
395
408
}
396
409
0 commit comments