Skip to content

Commit afaf976

Browse files
committed
Auto merge of #61350 - RalfJung:alloc, r=oli-obk
light refactoring of global AllocMap * rename AllocKind -> GlobalAlloc. This stores the allocation itself, not just its kind. * rename the methods that allocate stuff to have consistent names. Cc @oli-obk
2 parents cd3f21b + cf26120 commit afaf976

File tree

9 files changed

+87
-74
lines changed

9 files changed

+87
-74
lines changed

src/librustc/mir/interpret/mod.rs

+54-41
Original file line numberDiff line numberDiff line change
@@ -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

273275
pub 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> {
285289
impl<'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

src/librustc/ty/context.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1156,7 +1156,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
11561156
// create an allocation that just contains these bytes
11571157
let alloc = interpret::Allocation::from_byte_aligned_bytes(bytes, ());
11581158
let alloc = self.intern_const_alloc(alloc);
1159-
self.alloc_map.lock().allocate(alloc)
1159+
self.alloc_map.lock().create_memory_alloc(alloc)
11601160
}
11611161

11621162
pub fn intern_stability(self, stab: attr::Stability) -> &'gcx attr::Stability {

src/librustc_codegen_llvm/common.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc_codegen_ssa::traits::*;
1212

1313
use crate::consts::const_alloc_to_llvm;
1414
use rustc::ty::layout::{HasDataLayout, LayoutOf, self, TyLayout, Size};
15-
use rustc::mir::interpret::{Scalar, AllocKind, Allocation};
15+
use rustc::mir::interpret::{Scalar, GlobalAlloc, Allocation};
1616
use rustc_codegen_ssa::mir::place::PlaceRef;
1717

1818
use libc::{c_uint, c_char};
@@ -310,18 +310,18 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
310310
Scalar::Ptr(ptr) => {
311311
let alloc_kind = self.tcx.alloc_map.lock().get(ptr.alloc_id);
312312
let base_addr = match alloc_kind {
313-
Some(AllocKind::Memory(alloc)) => {
313+
Some(GlobalAlloc::Memory(alloc)) => {
314314
let init = const_alloc_to_llvm(self, alloc);
315315
if alloc.mutability == Mutability::Mutable {
316316
self.static_addr_of_mut(init, alloc.align, None)
317317
} else {
318318
self.static_addr_of(init, alloc.align, None)
319319
}
320320
}
321-
Some(AllocKind::Function(fn_instance)) => {
321+
Some(GlobalAlloc::Function(fn_instance)) => {
322322
self.get_fn(fn_instance)
323323
}
324-
Some(AllocKind::Static(def_id)) => {
324+
Some(GlobalAlloc::Static(def_id)) => {
325325
assert!(self.tcx.is_static(def_id));
326326
self.get_static(def_id)
327327
}

src/librustc_codegen_ssa/mir/operand.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> {
9898
_ => bug!("from_const: invalid ScalarPair layout: {:#?}", layout)
9999
};
100100
let a = Scalar::from(Pointer::new(
101-
bx.tcx().alloc_map.lock().allocate(data),
101+
bx.tcx().alloc_map.lock().create_memory_alloc(data),
102102
Size::from_bytes(start as u64),
103103
)).into();
104104
let a_llval = bx.scalar_to_backend(

src/librustc_mir/interpret/memory.rs

+13-13
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use syntax::ast::Mutability;
1818

1919
use super::{
2020
Pointer, AllocId, Allocation, GlobalId, AllocationExtra,
21-
EvalResult, Scalar, InterpError, AllocKind, PointerArithmetic,
21+
EvalResult, Scalar, InterpError, GlobalAlloc, PointerArithmetic,
2222
Machine, AllocMap, MayLeak, ErrorHandled, CheckInAllocMsg, InboundsCheck,
2323
};
2424

@@ -193,12 +193,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
193193
None => {
194194
// Deallocating static memory -- always an error
195195
return match self.tcx.alloc_map.lock().get(ptr.alloc_id) {
196-
Some(AllocKind::Function(..)) => err!(DeallocatedWrongMemoryKind(
196+
Some(GlobalAlloc::Function(..)) => err!(DeallocatedWrongMemoryKind(
197197
"function".to_string(),
198198
format!("{:?}", kind),
199199
)),
200-
Some(AllocKind::Static(..)) |
201-
Some(AllocKind::Memory(..)) => err!(DeallocatedWrongMemoryKind(
200+
Some(GlobalAlloc::Static(..)) |
201+
Some(GlobalAlloc::Memory(..)) => err!(DeallocatedWrongMemoryKind(
202202
"static".to_string(),
203203
format!("{:?}", kind),
204204
)),
@@ -313,15 +313,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
313313
) -> EvalResult<'tcx, Cow<'tcx, Allocation<M::PointerTag, M::AllocExtra>>> {
314314
let alloc = tcx.alloc_map.lock().get(id);
315315
let def_id = match alloc {
316-
Some(AllocKind::Memory(mem)) => {
316+
Some(GlobalAlloc::Memory(mem)) => {
317317
// We got tcx memory. Let the machine figure out whether and how to
318318
// turn that into memory with the right pointer tag.
319319
return Ok(M::adjust_static_allocation(mem, memory_extra))
320320
}
321-
Some(AllocKind::Function(..)) => {
321+
Some(GlobalAlloc::Function(..)) => {
322322
return err!(DerefFunctionPointer)
323323
}
324-
Some(AllocKind::Static(did)) => {
324+
Some(GlobalAlloc::Static(did)) => {
325325
did
326326
}
327327
None =>
@@ -429,8 +429,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
429429
}
430430
// Could also be a fn ptr or extern static
431431
match self.tcx.alloc_map.lock().get(id) {
432-
Some(AllocKind::Function(..)) => Ok((Size::ZERO, Align::from_bytes(1).unwrap())),
433-
Some(AllocKind::Static(did)) => {
432+
Some(GlobalAlloc::Function(..)) => Ok((Size::ZERO, Align::from_bytes(1).unwrap())),
433+
Some(GlobalAlloc::Static(did)) => {
434434
// The only way `get` couldn't have worked here is if this is an extern static
435435
assert!(self.tcx.is_foreign_item(did));
436436
// Use size and align of the type
@@ -456,7 +456,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
456456
}
457457
trace!("reading fn ptr: {}", ptr.alloc_id);
458458
match self.tcx.alloc_map.lock().get(ptr.alloc_id) {
459-
Some(AllocKind::Function(instance)) => Ok(instance),
459+
Some(GlobalAlloc::Function(instance)) => Ok(instance),
460460
_ => Err(InterpError::ExecuteMemory.into()),
461461
}
462462
}
@@ -554,16 +554,16 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
554554
Err(()) => {
555555
// static alloc?
556556
match self.tcx.alloc_map.lock().get(id) {
557-
Some(AllocKind::Memory(alloc)) => {
557+
Some(GlobalAlloc::Memory(alloc)) => {
558558
self.dump_alloc_helper(
559559
&mut allocs_seen, &mut allocs_to_print,
560560
msg, alloc, " (immutable)".to_owned()
561561
);
562562
}
563-
Some(AllocKind::Function(func)) => {
563+
Some(GlobalAlloc::Function(func)) => {
564564
trace!("{} {}", msg, func);
565565
}
566-
Some(AllocKind::Static(did)) => {
566+
Some(GlobalAlloc::Static(did)) => {
567567
trace!("{} {:?}", msg, did);
568568
}
569569
None => {

src/librustc_mir/interpret/operand.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
550550
ConstValue::Slice { data, start, end } =>
551551
Operand::Immediate(Immediate::ScalarPair(
552552
Scalar::from(Pointer::new(
553-
self.tcx.alloc_map.lock().allocate(data),
553+
self.tcx.alloc_map.lock().create_memory_alloc(data),
554554
Size::from_bytes(start as u64),
555555
)).with_default_tag().into(),
556556
Scalar::from_uint(

src/librustc_mir/interpret/place.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,7 @@ where
597597
// want! This way, computing statics works concistently between codegen
598598
// and miri: They use the same query to eventually obtain a `ty::Const`
599599
// and use that for further computation.
600-
let alloc = self.tcx.alloc_map.lock().intern_static(cid.instance.def_id());
600+
let alloc = self.tcx.alloc_map.lock().create_static_alloc(cid.instance.def_id());
601601
MPlaceTy::from_aligned_ptr(Pointer::from(alloc).with_default_tag(), layout)
602602
}
603603
})

src/librustc_mir/interpret/validity.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc::ty::layout::{self, Size, Align, TyLayout, LayoutOf, VariantIdx};
88
use rustc::ty;
99
use rustc_data_structures::fx::FxHashSet;
1010
use rustc::mir::interpret::{
11-
Scalar, AllocKind, EvalResult, InterpError, CheckInAllocMsg,
11+
Scalar, GlobalAlloc, EvalResult, InterpError, CheckInAllocMsg,
1212
};
1313

1414
use super::{
@@ -403,7 +403,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
403403
"integer pointer in non-ZST reference", self.path);
404404
// Skip validation entirely for some external statics
405405
let alloc_kind = self.ecx.tcx.alloc_map.lock().get(ptr.alloc_id);
406-
if let Some(AllocKind::Static(did)) = alloc_kind {
406+
if let Some(GlobalAlloc::Static(did)) = alloc_kind {
407407
// `extern static` cannot be validated as they have no body.
408408
// FIXME: Statics from other crates are also skipped.
409409
// They might be checked at a different type, but for now we

0 commit comments

Comments
 (0)