]> git.lizzy.rs Git - rust.git/commitdiff
Merge remote-tracking branch 'origin/master' into rustup
authorRalf Jung <post@ralfj.de>
Sat, 6 Jul 2019 07:29:17 +0000 (09:29 +0200)
committerRalf Jung <post@ralfj.de>
Sat, 6 Jul 2019 07:29:17 +0000 (09:29 +0200)
1  2 
src/eval.rs
src/machine.rs
src/shims/tls.rs
src/stacked_borrows.rs

diff --cc src/eval.rs
index 616e11a51561f00288f97234eabdc58ea66d401d,b29ce3537706bf01be3da729f03cf40c1e1370d4..6132c502531fa5c919b49083d8d39fe03f19b254
@@@ -30,14 -28,24 +30,23 @@@ pub fn create_ecx<'mir, 'tcx: 'mir>
      tcx: TyCtxt<'tcx>,
      main_id: DefId,
      config: MiriConfig,
- ) -> InterpResult<'tcx, InterpretCx<'mir, 'tcx, Evaluator<'tcx>>> {
-     let mut ecx = InterpretCx::new(
+ ) -> InterpResult<'tcx, InterpCx<'mir, 'tcx, Evaluator<'tcx>>> {
 -    let mut ecx = InterpCx::new(
 -        tcx.at(syntax::source_map::DUMMY_SP),
 -        ty::ParamEnv::reveal_all(),
 -        Evaluator::new(),
 -    );
+     // FIXME(https://github.com/rust-lang/miri/pull/803): no validation on Windows.
 -    let target_os = ecx.tcx.tcx.sess.target.target.target_os.to_lowercase();
++    let target_os = tcx.sess.target.target.target_os.to_lowercase();
+     let validate = if target_os == "windows" {
+         false
+     } else {
+         config.validate
+     };
 -    // FIXME: InterpCx::new should take an initial MemoryExtra
 -    ecx.memory_mut().extra = MemoryExtra::new(config.seed.map(StdRng::seed_from_u64), validate);
 -    
++    let mut ecx = InterpCx::new(
 +        tcx.at(syntax::source_map::DUMMY_SP),
 +        ty::ParamEnv::reveal_all(),
-         Evaluator::new(config.validate),
-         MemoryExtra::with_rng(config.seed.map(StdRng::seed_from_u64)),
++        Evaluator::new(),
++        MemoryExtra::new(config.seed.map(StdRng::seed_from_u64), validate),
 +    );
-     
++
      let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id);
      let main_mir = ecx.load_mir(main_instance.def)?;
  
diff --cc src/machine.rs
Simple merge
index 0000000000000000000000000000000000000000,9a22c03bf2f69c68279131aae285455cde273641..e2f2dab518058169e33975a0d6006ea1a82a59c7
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,175 +1,177 @@@
++//! Implement thread-local storage.
++
+ use std::collections::BTreeMap;
+ use rustc_target::abi::LayoutOf;
+ use rustc::{ty, ty::layout::HasDataLayout, mir};
+ use crate::{
+     InterpResult, InterpError, StackPopCleanup,
+     MPlaceTy, Scalar, Tag,
+     HelpersEvalContextExt,
+ };
+ pub type TlsKey = u128;
+ #[derive(Copy, Clone, Debug)]
+ pub struct TlsEntry<'tcx> {
+     /// The data for this key. None is used to represent NULL.
+     /// (We normalize this early to avoid having to do a NULL-ptr-test each time we access the data.)
+     /// Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread.
+     pub(crate) data: Option<Scalar<Tag>>,
+     pub(crate) dtor: Option<ty::Instance<'tcx>>,
+ }
+ #[derive(Debug)]
+ pub struct TlsData<'tcx> {
+     /// The Key to use for the next thread-local allocation.
+     pub(crate) next_key: TlsKey,
+     /// pthreads-style thread-local storage.
+     pub(crate) keys: BTreeMap<TlsKey, TlsEntry<'tcx>>,
+ }
+ impl<'tcx> Default for TlsData<'tcx> {
+     fn default() -> Self {
+         TlsData {
+             next_key: 1, // start with 1 as we must not use 0 on Windows
+             keys: Default::default(),
+         }
+     }
+ }
+ impl<'tcx> TlsData<'tcx> {
+     pub fn create_tls_key(
+         &mut self,
+         dtor: Option<ty::Instance<'tcx>>,
+     ) -> TlsKey {
+         let new_key = self.next_key;
+         self.next_key += 1;
+         self.keys.insert(
+             new_key,
+             TlsEntry {
+                 data: None,
+                 dtor,
+             },
+         );
+         trace!("New TLS key allocated: {} with dtor {:?}", new_key, dtor);
+         new_key
+     }
+     pub fn delete_tls_key(&mut self, key: TlsKey) -> InterpResult<'tcx> {
+         match self.keys.remove(&key) {
+             Some(_) => {
+                 trace!("TLS key {} removed", key);
+                 Ok(())
+             }
+             None => err!(TlsOutOfBounds),
+         }
+     }
+     pub fn load_tls(
+         &mut self,
+         key: TlsKey,
+         cx: &impl HasDataLayout,
+     ) -> InterpResult<'tcx, Scalar<Tag>> {
+         match self.keys.get(&key) {
+             Some(&TlsEntry { data, .. }) => {
+                 trace!("TLS key {} loaded: {:?}", key, data);
+                 Ok(data.unwrap_or_else(|| Scalar::ptr_null(cx).into()))
+             }
+             None => err!(TlsOutOfBounds),
+         }
+     }
+     pub fn store_tls(&mut self, key: TlsKey, new_data: Option<Scalar<Tag>>) -> InterpResult<'tcx> {
+         match self.keys.get_mut(&key) {
+             Some(&mut TlsEntry { ref mut data, .. }) => {
+                 trace!("TLS key {} stored: {:?}", key, new_data);
+                 *data = new_data;
+                 Ok(())
+             }
+             None => err!(TlsOutOfBounds),
+         }
+     }
+     /// Returns a dtor, its argument and its index, if one is supposed to run
+     ///
+     /// An optional destructor function may be associated with each key value.
+     /// At thread exit, if a key value has a non-NULL destructor pointer,
+     /// and the thread has a non-NULL value associated with that key,
+     /// the value of the key is set to NULL, and then the function pointed
+     /// to is called with the previously associated value as its sole argument.
+     /// The order of destructor calls is unspecified if more than one destructor
+     /// exists for a thread when it exits.
+     ///
+     /// If, after all the destructors have been called for all non-NULL values
+     /// with associated destructors, there are still some non-NULL values with
+     /// associated destructors, then the process is repeated.
+     /// If, after at least {PTHREAD_DESTRUCTOR_ITERATIONS} iterations of destructor
+     /// calls for outstanding non-NULL values, there are still some non-NULL values
+     /// with associated destructors, implementations may stop calling destructors,
+     /// or they may continue calling destructors until no non-NULL values with
+     /// associated destructors exist, even though this might result in an infinite loop.
+     fn fetch_tls_dtor(
+         &mut self,
+         key: Option<TlsKey>,
+     ) -> Option<(ty::Instance<'tcx>, Scalar<Tag>, TlsKey)> {
+         use std::collections::Bound::*;
+         let thread_local = &mut self.keys;
+         let start = match key {
+             Some(key) => Excluded(key),
+             None => Unbounded,
+         };
+         for (&key, &mut TlsEntry { ref mut data, dtor }) in
+             thread_local.range_mut((start, Unbounded))
+         {
+             if let Some(data_scalar) = *data {
+                 if let Some(dtor) = dtor {
+                     let ret = Some((dtor, data_scalar, key));
+                     *data = None;
+                     return ret;
+                 }
+             }
+         }
+         None
+     }
+ }
+ impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
+ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
+     fn run_tls_dtors(&mut self) -> InterpResult<'tcx> {
+         let this = self.eval_context_mut();
+         let mut dtor = this.machine.tls.fetch_tls_dtor(None);
+         // FIXME: replace loop by some structure that works with stepping
+         while let Some((instance, ptr, key)) = dtor {
+             trace!("Running TLS dtor {:?} on {:?}", instance, ptr);
+             assert!(!this.is_null(ptr).unwrap(), "Data can't be NULL when dtor is called!");
+             // TODO: Potentially, this has to support all the other possible instances?
+             // See eval_fn_call in interpret/terminator/mod.rs
+             let mir = this.load_mir(instance.def)?;
+             let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into();
+             this.push_stack_frame(
+                 instance,
+                 mir.span,
+                 mir,
+                 Some(ret_place),
+                 StackPopCleanup::None { cleanup: true },
+             )?;
+             let arg_local = this.frame().body.args_iter().next().ok_or_else(
+                 || InterpError::AbiViolation("TLS dtor does not take enough arguments.".to_owned()),
+             )?;
+             let dest = this.eval_place(&mir::Place::Base(mir::PlaceBase::Local(arg_local)))?;
+             this.write_scalar(ptr, dest)?;
+             // step until out of stackframes
+             this.run()?;
+             dtor = match this.machine.tls.fetch_tls_dtor(Some(key)) {
+                 dtor @ Some(_) => dtor,
+                 None => this.machine.tls.fetch_tls_dtor(None),
+             };
+         }
+         // FIXME: On a windows target, call `unsafe extern "system" fn on_tls_callback`.
+         Ok(())
+     }
+ }
Simple merge