]> git.lizzy.rs Git - rust.git/commitdiff
update for ptr provenance
authorRalf Jung <post@ralfj.de>
Fri, 5 Oct 2018 16:08:50 +0000 (18:08 +0200)
committerRalf Jung <post@ralfj.de>
Thu, 11 Oct 2018 06:42:26 +0000 (08:42 +0200)
src/intrinsic.rs
src/lib.rs
src/mono_hash_map.rs [new file with mode: 0644]

index e9a5714587fb0c15a9a1403300fed373445786fd..b7338d4d52143380ff8010cab67f3c774cc294ab 100644 (file)
@@ -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)?;
                         }
                     }
index e4a389427c52aa249e26e4a34cf1eafae2faa548..81a2ceead0a623b191cf45d47586eb5a90e95306 100644 (file)
@@ -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;
 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<MiriMemoryKind> = Some(MiriMemoryKind::MutStatic);
+    type MemoryMap = MonoHashMap<AllocId, (MemoryKind<MiriMemoryKind>, Allocation<()>)>;
+
+    const STATIC_KIND: Option<MiriMemoryKind> = 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<Self::PointerTag>> {
+        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 (file)
index 0000000..76ca7ac
--- /dev/null
@@ -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<K: Hash + Eq, V>(RefCell<FxHashMap<K, Box<V>>>);
+
+impl<K: Hash + Eq, V> Default for MonoHashMap<K, V> {
+    fn default() -> Self {
+        MonoHashMap(RefCell::new(Default::default()))
+    }
+}
+
+impl<K: Hash + Eq, V> AllocMap<K, V> for MonoHashMap<K, V> {
+    #[inline(always)]
+    fn contains_key<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> bool
+        where K: Borrow<Q>
+    {
+        self.0.get_mut().contains_key(k)
+    }
+
+    #[inline(always)]
+    fn insert(&mut self, k: K, v: V) -> Option<V>
+    {
+        self.0.get_mut().insert(k, Box::new(v)).map(|x| *x)
+    }
+
+    #[inline(always)]
+    fn remove<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> Option<V>
+        where K: Borrow<Q>
+    {
+        self.0.get_mut().remove(k).map(|x| *x)
+    }
+
+    #[inline(always)]
+    fn filter_map_collect<T>(&self, mut f: impl FnMut(&K, &V) -> Option<T>) -> Vec<T> {
+        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<E>(
+        &self,
+        k: K,
+        vacant: impl FnOnce() -> Result<V, E>
+    ) -> 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<E>(
+        &mut self,
+        k: K,
+        vacant: impl FnOnce() -> Result<V, E>
+    ) -> 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)))
+            }
+        }
+    }
+}