From 8ea8cd29190cae7ea50dc939ad63b0e8bc650373 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Oct 2018 18:08:50 +0200 Subject: [PATCH] update for ptr provenance --- src/intrinsic.rs | 4 +- src/lib.rs | 27 +++++++++---- src/mono_hash_map.rs | 91 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 9 deletions(-) create mode 100644 src/mono_hash_map.rs diff --git a/src/intrinsic.rs b/src/intrinsic.rs index e9a5714587f..b7338d4d521 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -252,7 +252,7 @@ fn call_intrinsic( _ => { // Do it in memory let mplace = self.force_allocation(dest)?; - assert!(mplace.extra.is_none()); + assert!(mplace.meta.is_none()); self.memory.write_repeat(mplace.ptr, 0, dest.layout.size)?; } } @@ -410,7 +410,7 @@ fn call_intrinsic( _ => { // Do it in memory let mplace = self.force_allocation(dest)?; - assert!(mplace.extra.is_none()); + assert!(mplace.meta.is_none()); self.memory.mark_definedness(mplace.ptr.to_ptr()?, dest.layout.size, false)?; } } diff --git a/src/lib.rs b/src/lib.rs index e4a389427c5..81a2ceead0a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,9 @@ extern crate rustc_target; extern crate syntax; +use std::collections::HashMap; +use std::borrow::Cow; + use rustc::ty::{self, TyCtxt, query::TyCtxtAt}; use rustc::ty::layout::{TyLayout, LayoutOf, Size}; use rustc::hir::def_id::DefId; @@ -21,11 +24,10 @@ use syntax::ast::Mutability; use syntax::attr; -use std::collections::HashMap; pub use rustc::mir::interpret::*; pub use rustc_mir::interpret::*; -pub use rustc_mir::interpret; +pub use rustc_mir::interpret::{self, AllocMap}; // resolve ambiguity mod fn_call; mod operator; @@ -34,6 +36,7 @@ mod tls; mod locks; mod range_map; +mod mono_hash_map; use fn_call::EvalContextExt as MissingFnsEvalContextExt; use operator::EvalContextExt as OperatorEvalContextExt; @@ -41,6 +44,7 @@ use tls::{EvalContextExt as TlsEvalContextExt, TlsData}; use range_map::RangeMap; use helpers::FalibleScalarExt; +use mono_hash_map::MonoHashMap; pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -231,8 +235,11 @@ pub struct Evaluator<'tcx> { impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { type MemoryData = (); type MemoryKinds = MiriMemoryKind; + type PointerTag = (); // still WIP - const MUT_STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); + type MemoryMap = MonoHashMap, Allocation<()>)>; + + const STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); const ENFORCE_VALIDITY: bool = false; // this is still WIP /// Returns Ok() when the function was handled, fail otherwise @@ -308,7 +315,7 @@ fn box_alloc( fn find_foreign_static( tcx: TyCtxtAt<'a, 'tcx, 'tcx>, def_id: DefId, - ) -> EvalResult<'tcx, &'tcx Allocation> { + ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> { let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { Some(name) => name.as_str(), @@ -319,14 +326,13 @@ fn find_foreign_static( "__cxa_thread_atexit_impl" => { // This should be all-zero, pointer-sized let data = vec![0; tcx.data_layout.pointer_size.bytes() as usize]; - let alloc = Allocation::from_bytes(&data[..], tcx.data_layout.pointer_align); - tcx.intern_const_alloc(alloc) + Allocation::from_bytes(&data[..], tcx.data_layout.pointer_align) } _ => return err!(Unimplemented( format!("can't access foreign static: {}", link_name), )), }; - Ok(alloc) + Ok(Cow::Owned(alloc)) } fn validation_op( @@ -344,4 +350,11 @@ fn before_terminator(_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult // We are not interested in detecting loops Ok(()) } + + fn static_with_default_tag( + alloc: &'_ Allocation + ) -> Cow<'_, Allocation> { + let alloc = alloc.clone(); + Cow::Owned(alloc) + } } diff --git a/src/mono_hash_map.rs b/src/mono_hash_map.rs new file mode 100644 index 00000000000..76ca7ac6a13 --- /dev/null +++ b/src/mono_hash_map.rs @@ -0,0 +1,91 @@ +//! This is a "monotonic HashMap": A HashMap that, when shared, can be pushed to but not +//! otherwise mutated. We also Box items in the map. This means we can safely provide +//! shared references into existing items in the HashMap, because they will not be dropped +//! (from being removed) or moved (because they are boxed). +//! The API is is completely tailored to what `memory.rs` needs. It is still in +//! a separate file to minimize the amount of code that has to care about the unsafety. + +use std::collections::hash_map::Entry; +use std::cell::RefCell; +use std::hash::Hash; +use std::borrow::Borrow; + +use rustc_data_structures::fx::FxHashMap; + +use super::AllocMap; + +#[derive(Debug, Clone)] +pub struct MonoHashMap(RefCell>>); + +impl Default for MonoHashMap { + fn default() -> Self { + MonoHashMap(RefCell::new(Default::default())) + } +} + +impl AllocMap for MonoHashMap { + #[inline(always)] + fn contains_key(&mut self, k: &Q) -> bool + where K: Borrow + { + self.0.get_mut().contains_key(k) + } + + #[inline(always)] + fn insert(&mut self, k: K, v: V) -> Option + { + self.0.get_mut().insert(k, Box::new(v)).map(|x| *x) + } + + #[inline(always)] + fn remove(&mut self, k: &Q) -> Option + where K: Borrow + { + self.0.get_mut().remove(k).map(|x| *x) + } + + #[inline(always)] + fn filter_map_collect(&self, mut f: impl FnMut(&K, &V) -> Option) -> Vec { + self.0.borrow() + .iter() + .filter_map(move |(k, v)| f(k, &*v)) + .collect() + } + + /// The most interesting method: Providing a shared ref without + /// holding the `RefCell` open, and inserting new data if the key + /// is not used yet. + /// `vacant` is called if the key is not found in the map; + /// if it returns a reference, that is used directly, if it + /// returns owned data, that is put into the map and returned. + #[inline(always)] + fn get_or( + &self, + k: K, + vacant: impl FnOnce() -> Result + ) -> Result<&V, E> { + let val: *const V = match self.0.borrow_mut().entry(k) { + Entry::Occupied(entry) => &**entry.get(), + Entry::Vacant(entry) => &**entry.insert(Box::new(vacant()?)), + }; + // This is safe because `val` points into a `Box`, that we know will not move and + // will also not be dropped as long as the shared reference `self` is live. + unsafe { Ok(&*val) } + } + + #[inline(always)] + fn get_mut_or( + &mut self, + k: K, + vacant: impl FnOnce() -> Result + ) -> Result<&mut V, E> + { + match self.0.get_mut().entry(k) { + Entry::Occupied(e) => Ok(e.into_mut()), + Entry::Vacant(e) => { + let v = vacant()?; + Ok(e.insert(Box::new(v))) + } + } + } +} -- 2.44.0