3 use super::{TlsKey, TlsEntry, EvalResult, EvalErrorKind, Scalar, ScalarExt, Memory, Evaluator,
4 Place, StackPopCleanup, EvalContext};
6 pub trait MemoryExt<'tcx> {
7 fn create_tls_key(&mut self, dtor: Option<ty::Instance<'tcx>>) -> TlsKey;
8 fn delete_tls_key(&mut self, key: TlsKey) -> EvalResult<'tcx>;
9 fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar>;
10 fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx>;
14 ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)>;
17 pub trait EvalContextExt<'tcx> {
18 fn run_tls_dtors(&mut self) -> EvalResult<'tcx>;
21 impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evaluator<'tcx>> {
22 fn create_tls_key(&mut self, dtor: Option<ty::Instance<'tcx>>) -> TlsKey {
23 let new_key = self.data.next_thread_local;
24 self.data.next_thread_local += 1;
25 let ptr_size = self.pointer_size();
26 self.data.thread_local.insert(
29 data: Scalar::null(ptr_size).into(),
33 trace!("New TLS key allocated: {} with dtor {:?}", new_key, dtor);
37 fn delete_tls_key(&mut self, key: TlsKey) -> EvalResult<'tcx> {
38 match self.data.thread_local.remove(&key) {
40 trace!("TLS key {} removed", key);
43 None => err!(TlsOutOfBounds),
47 fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar> {
48 match self.data.thread_local.get(&key) {
49 Some(&TlsEntry { data, .. }) => {
50 trace!("TLS key {} loaded: {:?}", key, data);
53 None => err!(TlsOutOfBounds),
57 fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx> {
58 match self.data.thread_local.get_mut(&key) {
59 Some(&mut TlsEntry { ref mut data, .. }) => {
60 trace!("TLS key {} stored: {:?}", key, new_data);
64 None => err!(TlsOutOfBounds),
68 /// Returns a dtor, its argument and its index, if one is supposed to run
70 /// An optional destructor function may be associated with each key value.
71 /// At thread exit, if a key value has a non-NULL destructor pointer,
72 /// and the thread has a non-NULL value associated with that key,
73 /// the value of the key is set to NULL, and then the function pointed
74 /// to is called with the previously associated value as its sole argument.
75 /// The order of destructor calls is unspecified if more than one destructor
76 /// exists for a thread when it exits.
78 /// If, after all the destructors have been called for all non-NULL values
79 /// with associated destructors, there are still some non-NULL values with
80 /// associated destructors, then the process is repeated.
81 /// If, after at least {PTHREAD_DESTRUCTOR_ITERATIONS} iterations of destructor
82 /// calls for outstanding non-NULL values, there are still some non-NULL values
83 /// with associated destructors, implementations may stop calling destructors,
84 /// or they may continue calling destructors until no non-NULL values with
85 /// associated destructors exist, even though this might result in an infinite loop.
89 ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> {
90 use std::collections::Bound::*;
92 let ptr_size = self.pointer_size();
93 let thread_local = &mut self.data.thread_local;
94 let start = match key {
95 Some(key) => Excluded(key),
98 for (&key, &mut TlsEntry { ref mut data, dtor }) in
99 thread_local.range_mut((start, Unbounded))
102 if let Some(dtor) = dtor {
103 let ret = Some((dtor, *data, key));
104 *data = Scalar::null(ptr_size);
113 impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>> {
114 fn run_tls_dtors(&mut self) -> EvalResult<'tcx> {
115 let mut dtor = self.memory.fetch_tls_dtor(None);
116 // FIXME: replace loop by some structure that works with stepping
117 while let Some((instance, ptr, key)) = dtor {
118 trace!("Running TLS dtor {:?} on {:?}", instance, ptr);
119 // TODO: Potentially, this has to support all the other possible instances?
120 // See eval_fn_call in interpret/terminator/mod.rs
121 let mir = self.load_mir(instance.def)?;
122 self.push_stack_frame(
127 StackPopCleanup::None,
129 let arg_local = self.frame().mir.args_iter().next().ok_or_else(
130 || EvalErrorKind::AbiViolation("TLS dtor does not take enough arguments.".to_owned()),
132 let dest = self.eval_place(&mir::Place::Local(arg_local))?;
133 let ty = self.tcx.mk_mut_ptr(self.tcx.types.u8);
134 self.write_ptr(dest, ptr, ty)?;
136 // step until out of stackframes
137 while self.step()? {}
139 dtor = match self.memory.fetch_tls_dtor(Some(key)) {
140 dtor @ Some(_) => dtor,
141 None => self.memory.fetch_tls_dtor(None),
144 // FIXME: On a windows target, call `unsafe extern "system" fn on_tls_callback`.