Skip to content

Commit ff8fa5c

Browse files
committed
Auto merge of rust-lang#50520 - Zoxc:alloc-misc, r=oli-obk
Misc changes related to Miri allocations This builds on top of rust-lang#50249 r? @oli-obk
2 parents 1bbae5f + ddc5418 commit ff8fa5c

File tree

14 files changed

+322
-318
lines changed

14 files changed

+322
-318
lines changed

src/librustc/ich/impls_ty.rs

+19-31
Original file line numberDiff line numberDiff line change
@@ -420,17 +420,6 @@ impl_stable_hash_for!(struct mir::interpret::MemoryPointer {
420420
offset
421421
});
422422

423-
enum AllocDiscriminant {
424-
Alloc,
425-
Static,
426-
Function,
427-
}
428-
impl_stable_hash_for!(enum self::AllocDiscriminant {
429-
Alloc,
430-
Static,
431-
Function
432-
});
433-
434423
impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::AllocId {
435424
fn hash_stable<W: StableHasherResult>(
436425
&self,
@@ -440,30 +429,29 @@ impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::AllocId {
440429
ty::tls::with_opt(|tcx| {
441430
trace!("hashing {:?}", *self);
442431
let tcx = tcx.expect("can't hash AllocIds during hir lowering");
443-
if let Some(def_id) = tcx.interpret_interner.get_static(*self) {
444-
AllocDiscriminant::Static.hash_stable(hcx, hasher);
445-
trace!("hashing {:?} as static {:?}", *self, def_id);
446-
def_id.hash_stable(hcx, hasher);
447-
} else if let Some(alloc) = tcx.interpret_interner.get_alloc(*self) {
448-
AllocDiscriminant::Alloc.hash_stable(hcx, hasher);
449-
if hcx.alloc_id_recursion_tracker.insert(*self) {
450-
trace!("hashing {:?} as alloc {:#?}", *self, alloc);
451-
alloc.hash_stable(hcx, hasher);
452-
assert!(hcx.alloc_id_recursion_tracker.remove(self));
453-
} else {
454-
trace!("skipping hashing of {:?} due to recursion", *self);
455-
}
456-
} else if let Some(inst) = tcx.interpret_interner.get_fn(*self) {
457-
trace!("hashing {:?} as fn {:#?}", *self, inst);
458-
AllocDiscriminant::Function.hash_stable(hcx, hasher);
459-
inst.hash_stable(hcx, hasher);
460-
} else {
461-
bug!("no allocation for {}", self);
462-
}
432+
let alloc_kind = tcx.alloc_map.lock().get(*self).expect("no value for AllocId");
433+
alloc_kind.hash_stable(hcx, hasher);
463434
});
464435
}
465436
}
466437

438+
impl<'a, 'gcx, M: HashStable<StableHashingContext<'a>>> HashStable<StableHashingContext<'a>>
439+
for mir::interpret::AllocType<'gcx, M> {
440+
fn hash_stable<W: StableHasherResult>(&self,
441+
hcx: &mut StableHashingContext<'a>,
442+
hasher: &mut StableHasher<W>) {
443+
use mir::interpret::AllocType::*;
444+
445+
mem::discriminant(self).hash_stable(hcx, hasher);
446+
447+
match *self {
448+
Function(instance) => instance.hash_stable(hcx, hasher),
449+
Static(def_id) => def_id.hash_stable(hcx, hasher),
450+
Memory(ref mem) => mem.hash_stable(hcx, hasher),
451+
}
452+
}
453+
}
454+
467455
impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::Allocation {
468456
fn hash_stable<W: StableHasherResult>(
469457
&self,

src/librustc/mir/interpret/mod.rs

+119-22
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@ use std::collections::BTreeMap;
1616
use std::fmt;
1717
use mir;
1818
use hir::def_id::DefId;
19-
use ty::{self, TyCtxt};
19+
use ty::{self, TyCtxt, Instance};
2020
use ty::layout::{self, Align, HasDataLayout, Size};
2121
use middle::region;
2222
use std::iter;
2323
use std::io;
24+
use std::hash::Hash;
2425
use syntax::ast::Mutability;
2526
use rustc_serialize::{Encoder, Decoder, Decodable, Encodable};
27+
use rustc_data_structures::fx::FxHashMap;
2628
use byteorder::{WriteBytesExt, ReadBytesExt, LittleEndian, BigEndian};
2729

2830
#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
@@ -150,7 +152,7 @@ impl<'tcx> MemoryPointer {
150152
}
151153

152154

153-
#[derive(Copy, Clone, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Debug)]
155+
#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd, Debug)]
154156
pub struct AllocId(pub u64);
155157

156158
impl ::rustc_serialize::UseSpecializedEncodable for AllocId {}
@@ -171,20 +173,25 @@ pub fn specialized_encode_alloc_id<
171173
tcx: TyCtxt<'a, 'tcx, 'tcx>,
172174
alloc_id: AllocId,
173175
) -> Result<(), E::Error> {
174-
if let Some(alloc) = tcx.interpret_interner.get_alloc(alloc_id) {
175-
trace!("encoding {:?} with {:#?}", alloc_id, alloc);
176-
AllocKind::Alloc.encode(encoder)?;
177-
alloc.encode(encoder)?;
178-
} else if let Some(fn_instance) = tcx.interpret_interner.get_fn(alloc_id) {
179-
trace!("encoding {:?} with {:#?}", alloc_id, fn_instance);
180-
AllocKind::Fn.encode(encoder)?;
181-
fn_instance.encode(encoder)?;
182-
} else if let Some(did) = tcx.interpret_interner.get_static(alloc_id) {
183-
// referring to statics doesn't need to know about their allocations, just about its DefId
184-
AllocKind::Static.encode(encoder)?;
185-
did.encode(encoder)?;
186-
} else {
187-
bug!("alloc id without corresponding allocation: {}", alloc_id);
176+
let alloc_type: AllocType<'tcx, &'tcx Allocation> =
177+
tcx.alloc_map.lock().get(alloc_id).expect("no value for AllocId");
178+
match alloc_type {
179+
AllocType::Memory(alloc) => {
180+
trace!("encoding {:?} with {:#?}", alloc_id, alloc);
181+
AllocKind::Alloc.encode(encoder)?;
182+
alloc.encode(encoder)?;
183+
}
184+
AllocType::Function(fn_instance) => {
185+
trace!("encoding {:?} with {:#?}", alloc_id, fn_instance);
186+
AllocKind::Fn.encode(encoder)?;
187+
fn_instance.encode(encoder)?;
188+
}
189+
AllocType::Static(did) => {
190+
// referring to statics doesn't need to know about their allocations,
191+
// just about its DefId
192+
AllocKind::Static.encode(encoder)?;
193+
did.encode(encoder)?;
194+
}
188195
}
189196
Ok(())
190197
}
@@ -200,31 +207,30 @@ pub fn specialized_decode_alloc_id<
200207
) -> Result<AllocId, D::Error> {
201208
match AllocKind::decode(decoder)? {
202209
AllocKind::Alloc => {
203-
let alloc_id = tcx.interpret_interner.reserve();
210+
let alloc_id = tcx.alloc_map.lock().reserve();
204211
trace!("creating alloc id {:?}", alloc_id);
205212
// insert early to allow recursive allocs
206213
cache(decoder, alloc_id);
207214

208-
let allocation = Allocation::decode(decoder)?;
215+
let allocation = <&'tcx Allocation as Decodable>::decode(decoder)?;
209216
trace!("decoded alloc {:?} {:#?}", alloc_id, allocation);
210-
let allocation = tcx.intern_const_alloc(allocation);
211-
tcx.interpret_interner.intern_at_reserved(alloc_id, allocation);
217+
tcx.alloc_map.lock().set_id_memory(alloc_id, allocation);
212218

213219
Ok(alloc_id)
214220
},
215221
AllocKind::Fn => {
216222
trace!("creating fn alloc id");
217223
let instance = ty::Instance::decode(decoder)?;
218224
trace!("decoded fn alloc instance: {:?}", instance);
219-
let id = tcx.interpret_interner.create_fn_alloc(instance);
225+
let id = tcx.alloc_map.lock().create_fn_alloc(instance);
220226
trace!("created fn alloc id: {:?}", id);
221227
cache(decoder, id);
222228
Ok(id)
223229
},
224230
AllocKind::Static => {
225231
trace!("creating extern static alloc id at");
226232
let did = DefId::decode(decoder)?;
227-
let alloc_id = tcx.interpret_interner.cache_static(did);
233+
let alloc_id = tcx.alloc_map.lock().intern_static(did);
228234
cache(decoder, alloc_id);
229235
Ok(alloc_id)
230236
},
@@ -237,6 +243,97 @@ impl fmt::Display for AllocId {
237243
}
238244
}
239245

246+
#[derive(Debug, Clone, Eq, PartialEq, Hash, RustcDecodable, RustcEncodable)]
247+
pub enum AllocType<'tcx, M> {
248+
/// The alloc id is used as a function pointer
249+
Function(Instance<'tcx>),
250+
/// The alloc id points to a static variable
251+
Static(DefId),
252+
/// The alloc id points to memory
253+
Memory(M)
254+
}
255+
256+
pub struct AllocMap<'tcx, M> {
257+
/// Lets you know what an AllocId refers to
258+
id_to_type: FxHashMap<AllocId, AllocType<'tcx, M>>,
259+
260+
/// Used to ensure that functions and statics only get one associated AllocId
261+
type_interner: FxHashMap<AllocType<'tcx, M>, AllocId>,
262+
263+
/// The AllocId to assign to the next requested id.
264+
/// Always incremented, never gets smaller.
265+
next_id: AllocId,
266+
}
267+
268+
impl<'tcx, M: fmt::Debug + Eq + Hash + Clone> AllocMap<'tcx, M> {
269+
pub fn new() -> Self {
270+
AllocMap {
271+
id_to_type: FxHashMap(),
272+
type_interner: FxHashMap(),
273+
next_id: AllocId(0),
274+
}
275+
}
276+
277+
/// obtains a new allocation ID that can be referenced but does not
278+
/// yet have an allocation backing it.
279+
pub fn reserve(
280+
&mut self,
281+
) -> AllocId {
282+
let next = self.next_id;
283+
self.next_id.0 = self.next_id.0
284+
.checked_add(1)
285+
.expect("You overflowed a u64 by incrementing by 1... \
286+
You've just earned yourself a free drink if we ever meet. \
287+
Seriously, how did you do that?!");
288+
next
289+
}
290+
291+
fn intern(&mut self, alloc_type: AllocType<'tcx, M>) -> AllocId {
292+
if let Some(&alloc_id) = self.type_interner.get(&alloc_type) {
293+
return alloc_id;
294+
}
295+
let id = self.reserve();
296+
debug!("creating alloc_type {:?} with id {}", alloc_type, id);
297+
self.id_to_type.insert(id, alloc_type.clone());
298+
self.type_interner.insert(alloc_type, id);
299+
id
300+
}
301+
302+
// FIXME: Check if functions have identity. If not, we should not intern these,
303+
// but instead create a new id per use.
304+
// Alternatively we could just make comparing function pointers an error.
305+
pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> AllocId {
306+
self.intern(AllocType::Function(instance))
307+
}
308+
309+
pub fn get(&self, id: AllocId) -> Option<AllocType<'tcx, M>> {
310+
self.id_to_type.get(&id).cloned()
311+
}
312+
313+
pub fn unwrap_memory(&self, id: AllocId) -> M {
314+
match self.get(id) {
315+
Some(AllocType::Memory(mem)) => mem,
316+
_ => bug!("expected allocation id {} to point to memory", id),
317+
}
318+
}
319+
320+
pub fn intern_static(&mut self, static_id: DefId) -> AllocId {
321+
self.intern(AllocType::Static(static_id))
322+
}
323+
324+
pub fn allocate(&mut self, mem: M) -> AllocId {
325+
let id = self.reserve();
326+
self.set_id_memory(id, mem);
327+
id
328+
}
329+
330+
pub fn set_id_memory(&mut self, id: AllocId, mem: M) {
331+
if let Some(old) = self.id_to_type.insert(id, AllocType::Memory(mem)) {
332+
bug!("tried to set allocation id {}, but it was already existing as {:#?}", id, old);
333+
}
334+
}
335+
}
336+
240337
#[derive(Clone, Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)]
241338
pub struct Allocation {
242339
/// The actual bytes of the allocation.

src/librustc/mir/mod.rs

+9-11
Original file line numberDiff line numberDiff line change
@@ -1908,17 +1908,15 @@ pub fn print_miri_value<W: Write>(value: Value, ty: Ty, f: &mut W) -> fmt::Resul
19081908
(Value::ByValPair(PrimVal::Ptr(ptr), PrimVal::Bytes(len)),
19091909
&TyRef(_, &ty::TyS { sty: TyStr, .. }, _)) => {
19101910
ty::tls::with(|tcx| {
1911-
let alloc = tcx
1912-
.interpret_interner
1913-
.get_alloc(ptr.alloc_id);
1914-
if let Some(alloc) = alloc {
1915-
assert_eq!(len as usize as u128, len);
1916-
let slice = &alloc.bytes[(ptr.offset.bytes() as usize)..][..(len as usize)];
1917-
let s = ::std::str::from_utf8(slice)
1918-
.expect("non utf8 str from miri");
1919-
write!(f, "{:?}", s)
1920-
} else {
1921-
write!(f, "pointer to erroneous constant {:?}, {:?}", ptr, len)
1911+
match tcx.alloc_map.lock().get(ptr.alloc_id) {
1912+
Some(interpret::AllocType::Memory(alloc)) => {
1913+
assert_eq!(len as usize as u128, len);
1914+
let slice = &alloc.bytes[(ptr.offset.bytes() as usize)..][..(len as usize)];
1915+
let s = ::std::str::from_utf8(slice)
1916+
.expect("non utf8 str from miri");
1917+
write!(f, "{:?}", s)
1918+
}
1919+
_ => write!(f, "pointer to erroneous constant {:?}, {:?}", ptr, len),
19221920
}
19231921
})
19241922
},

0 commit comments

Comments
 (0)