Skip to content

Commit 7489ee9

Browse files
committedDec 13, 2018
Auto merge of rust-lang#56461 - oli-obk:alloc_ids, r=RalfJung
Some cleanups around `AllocId` management r? @eddyb cc @RalfJung

File tree

9 files changed

+101
-79
lines changed

9 files changed

+101
-79
lines changed
 

‎src/librustc/ich/impls_ty.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ impl_stable_hash_for!(
338338
);
339339

340340
impl_stable_hash_for!(
341-
impl<'tcx, M> for enum mir::interpret::AllocType<'tcx, M> [ mir::interpret::AllocType ] {
341+
impl<'tcx> for enum mir::interpret::AllocKind<'tcx> [ mir::interpret::AllocKind ] {
342342
Function(instance),
343343
Static(def_id),
344344
Memory(mem),

‎src/librustc/mir/interpret/mod.rs

+69-47
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ use ty::{self, TyCtxt, Instance};
4141
use ty::layout::{self, Size};
4242
use middle::region;
4343
use std::io;
44-
use std::hash::Hash;
4544
use rustc_serialize::{Encoder, Decodable, Encodable};
4645
use rustc_data_structures::fx::FxHashMap;
4746
use rustc_data_structures::sync::{Lock as Mutex, HashMapExt};
@@ -90,7 +89,7 @@ impl ::rustc_serialize::UseSpecializedEncodable for AllocId {}
9089
impl ::rustc_serialize::UseSpecializedDecodable for AllocId {}
9190

9291
#[derive(RustcDecodable, RustcEncodable)]
93-
enum AllocKind {
92+
enum AllocDiscriminant {
9493
Alloc,
9594
Fn,
9695
Static,
@@ -104,23 +103,23 @@ pub fn specialized_encode_alloc_id<
104103
tcx: TyCtxt<'a, 'tcx, 'tcx>,
105104
alloc_id: AllocId,
106105
) -> Result<(), E::Error> {
107-
let alloc_type: AllocType<'tcx, &'tcx Allocation> =
106+
let alloc_kind: AllocKind<'tcx> =
108107
tcx.alloc_map.lock().get(alloc_id).expect("no value for AllocId");
109-
match alloc_type {
110-
AllocType::Memory(alloc) => {
108+
match alloc_kind {
109+
AllocKind::Memory(alloc) => {
111110
trace!("encoding {:?} with {:#?}", alloc_id, alloc);
112-
AllocKind::Alloc.encode(encoder)?;
111+
AllocDiscriminant::Alloc.encode(encoder)?;
113112
alloc.encode(encoder)?;
114113
}
115-
AllocType::Function(fn_instance) => {
114+
AllocKind::Function(fn_instance) => {
116115
trace!("encoding {:?} with {:#?}", alloc_id, fn_instance);
117-
AllocKind::Fn.encode(encoder)?;
116+
AllocDiscriminant::Fn.encode(encoder)?;
118117
fn_instance.encode(encoder)?;
119118
}
120-
AllocType::Static(did) => {
119+
AllocKind::Static(did) => {
121120
// referring to statics doesn't need to know about their allocations,
122121
// just about its DefId
123-
AllocKind::Static.encode(encoder)?;
122+
AllocDiscriminant::Static.encode(encoder)?;
124123
did.encode(encoder)?;
125124
}
126125
}
@@ -189,10 +188,10 @@ impl<'s> AllocDecodingSession<'s> {
189188
let idx = decoder.read_u32()? as usize;
190189
let pos = self.state.data_offsets[idx] as usize;
191190

192-
// Decode the AllocKind now so that we know if we have to reserve an
191+
// Decode the AllocDiscriminant now so that we know if we have to reserve an
193192
// AllocId.
194193
let (alloc_kind, pos) = decoder.with_position(pos, |decoder| {
195-
let alloc_kind = AllocKind::decode(decoder)?;
194+
let alloc_kind = AllocDiscriminant::decode(decoder)?;
196195
Ok((alloc_kind, decoder.position()))
197196
})?;
198197

@@ -208,7 +207,7 @@ impl<'s> AllocDecodingSession<'s> {
208207
ref mut entry @ State::Empty => {
209208
// We are allowed to decode
210209
match alloc_kind {
211-
AllocKind::Alloc => {
210+
AllocDiscriminant::Alloc => {
212211
// If this is an allocation, we need to reserve an
213212
// AllocId so we can decode cyclic graphs.
214213
let alloc_id = decoder.tcx().alloc_map.lock().reserve();
@@ -217,7 +216,7 @@ impl<'s> AllocDecodingSession<'s> {
217216
alloc_id);
218217
Some(alloc_id)
219218
},
220-
AllocKind::Fn | AllocKind::Static => {
219+
AllocDiscriminant::Fn | AllocDiscriminant::Static => {
221220
// Fns and statics cannot be cyclic and their AllocId
222221
// is determined later by interning
223222
*entry = State::InProgressNonAlloc(
@@ -251,23 +250,23 @@ impl<'s> AllocDecodingSession<'s> {
251250
// Now decode the actual data
252251
let alloc_id = decoder.with_position(pos, |decoder| {
253252
match alloc_kind {
254-
AllocKind::Alloc => {
253+
AllocDiscriminant::Alloc => {
255254
let allocation = <&'tcx Allocation as Decodable>::decode(decoder)?;
256255
// We already have a reserved AllocId.
257256
let alloc_id = alloc_id.unwrap();
258257
trace!("decoded alloc {:?} {:#?}", alloc_id, allocation);
259-
decoder.tcx().alloc_map.lock().set_id_same_memory(alloc_id, allocation);
258+
decoder.tcx().alloc_map.lock().set_alloc_id_same_memory(alloc_id, allocation);
260259
Ok(alloc_id)
261260
},
262-
AllocKind::Fn => {
261+
AllocDiscriminant::Fn => {
263262
assert!(alloc_id.is_none());
264263
trace!("creating fn alloc id");
265264
let instance = ty::Instance::decode(decoder)?;
266265
trace!("decoded fn alloc instance: {:?}", instance);
267266
let alloc_id = decoder.tcx().alloc_map.lock().create_fn_alloc(instance);
268267
Ok(alloc_id)
269268
},
270-
AllocKind::Static => {
269+
AllocDiscriminant::Static => {
271270
assert!(alloc_id.is_none());
272271
trace!("creating extern static alloc id at");
273272
let did = DefId::decode(decoder)?;
@@ -292,39 +291,42 @@ impl fmt::Display for AllocId {
292291
}
293292

294293
#[derive(Debug, Clone, Eq, PartialEq, Hash, RustcDecodable, RustcEncodable)]
295-
pub enum AllocType<'tcx, M> {
294+
pub enum AllocKind<'tcx> {
296295
/// The alloc id is used as a function pointer
297296
Function(Instance<'tcx>),
298297
/// The alloc id points to a "lazy" static variable that did not get computed (yet).
299298
/// This is also used to break the cycle in recursive statics.
300299
Static(DefId),
301300
/// The alloc id points to memory
302-
Memory(M)
301+
Memory(&'tcx Allocation),
303302
}
304303

305-
pub struct AllocMap<'tcx, M> {
304+
pub struct AllocMap<'tcx> {
306305
/// Lets you know what an AllocId refers to
307-
id_to_type: FxHashMap<AllocId, AllocType<'tcx, M>>,
306+
id_to_kind: FxHashMap<AllocId, AllocKind<'tcx>>,
308307

309-
/// Used to ensure that functions and statics only get one associated AllocId
310-
type_interner: FxHashMap<AllocType<'tcx, M>, AllocId>,
308+
/// Used to ensure that statics only get one associated AllocId
309+
type_interner: FxHashMap<AllocKind<'tcx>, AllocId>,
311310

312311
/// The AllocId to assign to the next requested id.
313312
/// Always incremented, never gets smaller.
314313
next_id: AllocId,
315314
}
316315

317-
impl<'tcx, M: fmt::Debug + Eq + Hash + Clone> AllocMap<'tcx, M> {
316+
impl<'tcx> AllocMap<'tcx> {
318317
pub fn new() -> Self {
319318
AllocMap {
320-
id_to_type: Default::default(),
319+
id_to_kind: Default::default(),
321320
type_interner: Default::default(),
322321
next_id: AllocId(0),
323322
}
324323
}
325324

326-
/// obtains a new allocation ID that can be referenced but does not
325+
/// Obtains a new allocation ID that can be referenced but does not
327326
/// yet have an allocation backing it.
327+
///
328+
/// Make sure to call `set_alloc_id_memory` or `set_alloc_id_same_memory` before returning such
329+
/// an `AllocId` from a query.
328330
pub fn reserve(
329331
&mut self,
330332
) -> AllocId {
@@ -337,53 +339,73 @@ impl<'tcx, M: fmt::Debug + Eq + Hash + Clone> AllocMap<'tcx, M> {
337339
next
338340
}
339341

340-
fn intern(&mut self, alloc_type: AllocType<'tcx, M>) -> AllocId {
341-
if let Some(&alloc_id) = self.type_interner.get(&alloc_type) {
342+
fn intern(&mut self, alloc_kind: AllocKind<'tcx>) -> AllocId {
343+
if let Some(&alloc_id) = self.type_interner.get(&alloc_kind) {
342344
return alloc_id;
343345
}
344346
let id = self.reserve();
345-
debug!("creating alloc_type {:?} with id {}", alloc_type, id);
346-
self.id_to_type.insert(id, alloc_type.clone());
347-
self.type_interner.insert(alloc_type, id);
347+
debug!("creating alloc_kind {:?} with id {}", alloc_kind, id);
348+
self.id_to_kind.insert(id, alloc_kind.clone());
349+
self.type_interner.insert(alloc_kind, id);
348350
id
349351
}
350352

351-
// FIXME: Check if functions have identity. If not, we should not intern these,
352-
// but instead create a new id per use.
353-
// Alternatively we could just make comparing function pointers an error.
353+
/// Functions cannot be identified by pointers, as asm-equal functions can get deduplicated
354+
/// by the linker and functions can be duplicated across crates.
355+
/// We thus generate a new `AllocId` for every mention of a function. This means that
356+
/// `main as fn() == main as fn()` is false, while `let x = main as fn(); x == x` is true.
354357
pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> AllocId {
355-
self.intern(AllocType::Function(instance))
358+
let id = self.reserve();
359+
self.id_to_kind.insert(id, AllocKind::Function(instance));
360+
id
356361
}
357362

358-
pub fn get(&self, id: AllocId) -> Option<AllocType<'tcx, M>> {
359-
self.id_to_type.get(&id).cloned()
363+
/// Returns `None` in case the `AllocId` is dangling. An `EvalContext` can still have a
364+
/// local `Allocation` for that `AllocId`, but having such an `AllocId` in a constant is
365+
/// illegal and will likely ICE.
366+
/// This function exists to allow const eval to detect the difference between evaluation-
367+
/// local dangling pointers and allocations in constants/statics.
368+
pub fn get(&self, id: AllocId) -> Option<AllocKind<'tcx>> {
369+
self.id_to_kind.get(&id).cloned()
360370
}
361371

362-
pub fn unwrap_memory(&self, id: AllocId) -> M {
372+
/// Panics if the `AllocId` does not refer to an `Allocation`
373+
pub fn unwrap_memory(&self, id: AllocId) -> &'tcx Allocation {
363374
match self.get(id) {
364-
Some(AllocType::Memory(mem)) => mem,
375+
Some(AllocKind::Memory(mem)) => mem,
365376
_ => bug!("expected allocation id {} to point to memory", id),
366377
}
367378
}
368379

380+
/// Generate an `AllocId` for a static or return a cached one in case this function has been
381+
/// called on the same static before.
369382
pub fn intern_static(&mut self, static_id: DefId) -> AllocId {
370-
self.intern(AllocType::Static(static_id))
383+
self.intern(AllocKind::Static(static_id))
371384
}
372385

373-
pub fn allocate(&mut self, mem: M) -> AllocId {
386+
/// Intern the `Allocation` and return a new `AllocId`, even if there's already an identical
387+
/// `Allocation` with a different `AllocId`.
388+
// FIXME: is this really necessary? Can we ensure `FOO` and `BAR` being different after codegen
389+
// in `static FOO: u32 = 42; static BAR: u32 = 42;` even if they reuse the same allocation
390+
// inside rustc?
391+
pub fn allocate(&mut self, mem: &'tcx Allocation) -> AllocId {
374392
let id = self.reserve();
375-
self.set_id_memory(id, mem);
393+
self.set_alloc_id_memory(id, mem);
376394
id
377395
}
378396

379-
pub fn set_id_memory(&mut self, id: AllocId, mem: M) {
380-
if let Some(old) = self.id_to_type.insert(id, AllocType::Memory(mem)) {
397+
/// Freeze an `AllocId` created with `reserve` by pointing it at an `Allocation`. Trying to
398+
/// call this function twice, even with the same `Allocation` will ICE the compiler.
399+
pub fn set_alloc_id_memory(&mut self, id: AllocId, mem: &'tcx Allocation) {
400+
if let Some(old) = self.id_to_kind.insert(id, AllocKind::Memory(mem)) {
381401
bug!("tried to set allocation id {}, but it was already existing as {:#?}", id, old);
382402
}
383403
}
384404

385-
pub fn set_id_same_memory(&mut self, id: AllocId, mem: M) {
386-
self.id_to_type.insert_same(id, AllocType::Memory(mem));
405+
/// Freeze an `AllocId` created with `reserve` by pointing it at an `Allocation`. May be called
406+
/// twice for the same `(AllocId, Allocation)` pair.
407+
fn set_alloc_id_same_memory(&mut self, id: AllocId, mem: &'tcx Allocation) {
408+
self.id_to_kind.insert_same(id, AllocKind::Memory(mem));
387409
}
388410
}
389411

‎src/librustc/mir/interpret/value.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use super::{EvalResult, Pointer, PointerArithmetic, Allocation, AllocId, sign_ex
1818
/// Represents the result of a raw const operation, pre-validation.
1919
#[derive(Copy, Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)]
2020
pub struct RawConst<'tcx> {
21-
// the value lives here, at offset 0, and that allocation definitely is a `AllocType::Memory`
21+
// the value lives here, at offset 0, and that allocation definitely is a `AllocKind::Memory`
2222
// (so you can use `AllocMap::unwrap_memory`).
2323
pub alloc_id: AllocId,
2424
pub ty: Ty<'tcx>,

‎src/librustc/mir/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2637,7 +2637,7 @@ pub fn fmt_const_val(f: &mut impl Write, const_val: &ty::Const<'_>) -> fmt::Resu
26372637
if let Ref(_, &ty::TyS { sty: Str, .. }, _) = ty.sty {
26382638
return ty::tls::with(|tcx| {
26392639
let alloc = tcx.alloc_map.lock().get(ptr.alloc_id);
2640-
if let Some(interpret::AllocType::Memory(alloc)) = alloc {
2640+
if let Some(interpret::AllocKind::Memory(alloc)) = alloc {
26412641
assert_eq!(len as usize as u128, len);
26422642
let slice =
26432643
&alloc.bytes[(ptr.offset.bytes() as usize)..][..(len as usize)];

‎src/librustc/ty/context.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -946,7 +946,7 @@ pub struct GlobalCtxt<'tcx> {
946946
/// Stores the value of constants (and deduplicates the actual memory)
947947
allocation_interner: Lock<FxHashMap<&'tcx Allocation, ()>>,
948948

949-
pub alloc_map: Lock<interpret::AllocMap<'tcx, &'tcx Allocation>>,
949+
pub alloc_map: Lock<interpret::AllocMap<'tcx>>,
950950

951951
layout_interner: Lock<FxHashMap<&'tcx LayoutDetails, ()>>,
952952

‎src/librustc_codegen_llvm/common.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use value::Value;
2121
use rustc_codegen_ssa::traits::*;
2222

2323
use rustc::ty::layout::{HasDataLayout, LayoutOf, self, TyLayout, Size};
24-
use rustc::mir::interpret::{Scalar, AllocType, Allocation};
24+
use rustc::mir::interpret::{Scalar, AllocKind, Allocation};
2525
use consts::const_alloc_to_llvm;
2626
use rustc_codegen_ssa::mir::place::PlaceRef;
2727

@@ -316,20 +316,20 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
316316
}
317317
},
318318
Scalar::Ptr(ptr) => {
319-
let alloc_type = self.tcx.alloc_map.lock().get(ptr.alloc_id);
320-
let base_addr = match alloc_type {
321-
Some(AllocType::Memory(alloc)) => {
319+
let alloc_kind = self.tcx.alloc_map.lock().get(ptr.alloc_id);
320+
let base_addr = match alloc_kind {
321+
Some(AllocKind::Memory(alloc)) => {
322322
let init = const_alloc_to_llvm(self, alloc);
323323
if alloc.mutability == Mutability::Mutable {
324324
self.static_addr_of_mut(init, alloc.align, None)
325325
} else {
326326
self.static_addr_of(init, alloc.align, None)
327327
}
328328
}
329-
Some(AllocType::Function(fn_instance)) => {
329+
Some(AllocKind::Function(fn_instance)) => {
330330
self.get_fn(fn_instance)
331331
}
332-
Some(AllocType::Static(def_id)) => {
332+
Some(AllocKind::Static(def_id)) => {
333333
assert!(self.tcx.is_static(def_id).is_some());
334334
self.get_static(def_id)
335335
}

0 commit comments

Comments
 (0)
Please sign in to comment.