diff --git a/src/fn_call.rs b/src/fn_call.rs index 0e768fcccf9e..3e795f165331 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -8,10 +8,6 @@ use std::mem; use super::*; -use tls::MemoryExt; - -use super::memory::MemoryKind; - pub trait EvalContextExt<'tcx, 'mir> { /// Emulate calling a foreign item, fail if the item is not supported. /// This function will handle `goto_block` if needed. @@ -129,7 +125,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' self.write_null(dest)?; } else { let align = self.tcx.data_layout.pointer_align; - let ptr = self.memory.allocate(Size::from_bytes(size), align, MemoryKind::C.into())?; + let ptr = self.memory.allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into())?; self.write_scalar(Scalar::Ptr(ptr), dest)?; } } @@ -140,7 +136,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' self.memory.deallocate( ptr.to_ptr()?, None, - MemoryKind::C.into(), + MiriMemoryKind::C.into(), )?; } } @@ -156,7 +152,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' } let ptr = self.memory.allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), - MemoryKind::Rust.into())?; + MiriMemoryKind::Rust.into())?; self.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_alloc_zeroed" => { @@ -170,7 +166,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' } let ptr = self.memory.allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), - MemoryKind::Rust.into())?; + MiriMemoryKind::Rust.into())?; self.memory.write_repeat(ptr.into(), 0, Size::from_bytes(size))?; self.write_scalar(Scalar::Ptr(ptr), dest)?; } @@ -187,7 +183,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' self.memory.deallocate( ptr, Some((Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap())), - MemoryKind::Rust.into(), + MiriMemoryKind::Rust.into(), )?; } "__rust_realloc" => { @@ -207,7 +203,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' Align::from_bytes(align, align).unwrap(), Size::from_bytes(new_size), Align::from_bytes(align, align).unwrap(), - MemoryKind::Rust.into(), + MiriMemoryKind::Rust.into(), )?; self.write_scalar(Scalar::Ptr(new_ptr), dest)?; } @@ -365,7 +361,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' } if let Some(old) = success { if let Some(var) = old { - self.memory.deallocate(var, None, MemoryKind::Env.into())?; + self.memory.deallocate(var, None, MiriMemoryKind::Env.into())?; } self.write_null(dest)?; } else { @@ -391,7 +387,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' let value_copy = self.memory.allocate( Size::from_bytes((value.len() + 1) as u64), Align::from_bytes(1, 1).unwrap(), - MemoryKind::Env.into(), + MiriMemoryKind::Env.into(), )?; self.memory.write_bytes(value_copy.into(), &value)?; let trailing_zero_ptr = value_copy.offset(Size::from_bytes(value.len() as u64), &self)?.into(); @@ -401,7 +397,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' value_copy, ) { - self.memory.deallocate(var, None, MemoryKind::Env.into())?; + self.memory.deallocate(var, None, MiriMemoryKind::Env.into())?; } self.write_null(dest)?; } else { @@ -504,7 +500,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' let key_layout = self.layout_of(key_type)?; // Create key and write it into the memory where key_ptr wants it - let key = self.memory.create_tls_key(dtor) as u128; + let key = self.machine.tls.create_tls_key(dtor, *self.tcx) as u128; if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) { return err!(OutOfTls); } @@ -520,19 +516,19 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' } "pthread_key_delete" => { let key = self.read_scalar(args[0])?.to_bytes()?; - self.memory.delete_tls_key(key)?; + self.machine.tls.delete_tls_key(key)?; // Return success (0) self.write_null(dest)?; } "pthread_getspecific" => { let key = self.read_scalar(args[0])?.to_bytes()?; - let ptr = self.memory.load_tls(key)?; + let ptr = self.machine.tls.load_tls(key)?; self.write_scalar(ptr, dest)?; } "pthread_setspecific" => { let key = self.read_scalar(args[0])?.to_bytes()?; let new_ptr = self.read_scalar(args[1])?.not_undef()?; - self.memory.store_tls(key, new_ptr)?; + self.machine.tls.store_tls(key, new_ptr)?; // Return success (0) self.write_null(dest)?; @@ -607,7 +603,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' // This just creates a key; Windows does not natively support TLS dtors. // Create key and return it - let key = self.memory.create_tls_key(None) as u128; + let key = self.machine.tls.create_tls_key(None, *self.tcx) as u128; // Figure out how large a TLS key actually is. This is c::DWORD. if dest.layout.size.bits() < 128 && key >= (1u128 << dest.layout.size.bits() as u128) { @@ -617,13 +613,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' } "TlsGetValue" => { let key = self.read_scalar(args[0])?.to_bytes()?; - let ptr = self.memory.load_tls(key)?; + let ptr = self.machine.tls.load_tls(key)?; self.write_scalar(ptr, dest)?; } "TlsSetValue" => { let key = self.read_scalar(args[0])?.to_bytes()?; let new_ptr = self.read_scalar(args[1])?.not_undef()?; - self.memory.store_tls(key, new_ptr)?; + self.machine.tls.store_tls(key, new_ptr)?; // Return success (1) self.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; diff --git a/src/lib.rs b/src/lib.rs index 8bf66999c3de..98d89510251c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,17 +21,16 @@ use rustc::mir; use syntax::ast::Mutability; use syntax::attr; -use std::marker::PhantomData; use std::collections::HashMap; pub use rustc::mir::interpret::*; pub use rustc_mir::interpret::*; +pub use rustc_mir::interpret; mod fn_call; mod operator; mod intrinsic; mod helpers; -mod memory; mod tls; mod locks; mod range_map; @@ -39,9 +38,7 @@ mod range_map; use fn_call::EvalContextExt as MissingFnsEvalContextExt; use operator::EvalContextExt as OperatorEvalContextExt; use intrinsic::EvalContextExt as IntrinsicEvalContextExt; -use tls::EvalContextExt as TlsEvalContextExt; -use memory::{MemoryKind as MiriMemoryKind, TlsKey, TlsEntry, MemoryData}; -use locks::LockInfo; +use tls::{EvalContextExt as TlsEvalContextExt, TlsData}; use range_map::RangeMap; use helpers::FalibleScalarExt; @@ -54,7 +51,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), Default::default(), - MemoryData::new() + Default::default(), ); let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); @@ -201,21 +198,41 @@ pub fn eval_main<'a, 'tcx: 'a>( } } + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum MiriMemoryKind { + /// `__rust_alloc` memory + Rust, + /// `malloc` memory + C, + /// Part of env var emulation + Env, + /// mutable statics + MutStatic, +} + +impl Into> for MiriMemoryKind { + fn into(self) -> MemoryKind { + MemoryKind::Machine(self) + } +} + + #[derive(Clone, Default, PartialEq, Eq)] pub struct Evaluator<'tcx> { /// Environment variables set by `setenv` /// Miri does not expose env vars from the host to the emulated program pub(crate) env_vars: HashMap, Pointer>, - /// Use the lifetime - _dummy : PhantomData<&'tcx ()>, + /// TLS state + pub(crate) tls: TlsData<'tcx>, } impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { - type MemoryData = memory::MemoryData<'tcx>; - type MemoryKinds = memory::MemoryKind; + type MemoryData = (); + type MemoryKinds = MiriMemoryKind; - const MUT_STATIC_KIND: Option = Some(memory::MemoryKind::MutStatic); + const MUT_STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); const DETECT_LOOPS: bool = false; /// Returns Ok() when the function was handled, fail otherwise diff --git a/src/memory.rs b/src/memory.rs deleted file mode 100644 index 4e0fcd4f511f..000000000000 --- a/src/memory.rs +++ /dev/null @@ -1,57 +0,0 @@ -use std::collections::{HashMap, BTreeMap}; - -use rustc::ty; - -use super::{AllocId, Scalar, LockInfo, RangeMap}; - -pub type TlsKey = u128; - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct TlsEntry<'tcx> { - pub(crate) data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. - pub(crate) dtor: Option>, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct MemoryData<'tcx> { - /// The Key to use for the next thread-local allocation. - pub(crate) next_thread_local: TlsKey, - - /// pthreads-style thread-local storage. - pub(crate) thread_local: BTreeMap>, - - /// Memory regions that are locked by some function - /// - /// Only mutable (static mut, heap, stack) allocations have an entry in this map. - /// The entry is created when allocating the memory and deleted after deallocation. - pub(crate) locks: HashMap>>, -} - -impl<'tcx> MemoryData<'tcx> { - pub(crate) fn new() -> Self { - MemoryData { - next_thread_local: 1, // start with 1 as we must not use 0 on Windows - thread_local: BTreeMap::new(), - locks: HashMap::new(), - } - } -} - - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum MemoryKind { - /// `__rust_alloc` memory - Rust, - /// `malloc` memory - C, - /// Part of env var emulation - Env, - /// mutable statics - MutStatic, -} - -impl Into<::rustc_mir::interpret::MemoryKind> for MemoryKind { - fn into(self) -> ::rustc_mir::interpret::MemoryKind { - ::rustc_mir::interpret::MemoryKind::Machine(self) - } -} diff --git a/src/tls.rs b/src/tls.rs index bd0318a62ed4..a1ddaf64cc0f 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -1,31 +1,52 @@ -use rustc::{ty, mir}; +use std::collections::BTreeMap; -use super::{TlsKey, TlsEntry, EvalResult, EvalErrorKind, Scalar, Memory, Evaluator, +use rustc::{ty, ty::layout::HasDataLayout, mir}; + +use super::{EvalResult, EvalErrorKind, Scalar, Evaluator, Place, StackPopCleanup, EvalContext}; -pub trait MemoryExt<'tcx> { - fn create_tls_key(&mut self, dtor: Option>) -> TlsKey; - fn delete_tls_key(&mut self, key: TlsKey) -> EvalResult<'tcx>; - fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar>; - fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx>; - fn fetch_tls_dtor( - &mut self, - key: Option, - ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)>; +pub type TlsKey = u128; + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct TlsEntry<'tcx> { + pub(crate) data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. + pub(crate) dtor: Option>, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +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>, +} + +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(), + } + } } pub trait EvalContextExt<'tcx> { fn run_tls_dtors(&mut self) -> EvalResult<'tcx>; } -impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evaluator<'tcx>> { - fn create_tls_key(&mut self, dtor: Option>) -> TlsKey { - let new_key = self.data.next_thread_local; - self.data.next_thread_local += 1; - self.data.thread_local.insert( +impl<'tcx> TlsData<'tcx> { + pub fn create_tls_key( + &mut self, + dtor: Option>, + cx: impl HasDataLayout, + ) -> TlsKey { + let new_key = self.next_key; + self.next_key += 1; + self.keys.insert( new_key, TlsEntry { - data: Scalar::ptr_null(*self.tcx).into(), + data: Scalar::ptr_null(cx).into(), dtor, }, ); @@ -33,8 +54,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu new_key } - fn delete_tls_key(&mut self, key: TlsKey) -> EvalResult<'tcx> { - match self.data.thread_local.remove(&key) { + pub fn delete_tls_key(&mut self, key: TlsKey) -> EvalResult<'tcx> { + match self.keys.remove(&key) { Some(_) => { trace!("TLS key {} removed", key); Ok(()) @@ -43,8 +64,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu } } - fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar> { - match self.data.thread_local.get(&key) { + pub fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar> { + match self.keys.get(&key) { Some(&TlsEntry { data, .. }) => { trace!("TLS key {} loaded: {:?}", key, data); Ok(data) @@ -53,8 +74,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu } } - fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx> { - match self.data.thread_local.get_mut(&key) { + pub fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx> { + match self.keys.get_mut(&key) { Some(&mut TlsEntry { ref mut data, .. }) => { trace!("TLS key {} stored: {:?}", key, new_data); *data = new_data; @@ -85,10 +106,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu fn fetch_tls_dtor( &mut self, key: Option, + cx: impl HasDataLayout, ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { use std::collections::Bound::*; - let thread_local = &mut self.data.thread_local; + let thread_local = &mut self.keys; let start = match key { Some(key) => Excluded(key), None => Unbounded, @@ -99,7 +121,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu if !data.is_null() { if let Some(dtor) = dtor { let ret = Some((dtor, *data, key)); - *data = Scalar::ptr_null(*self.tcx); + *data = Scalar::ptr_null(cx); return ret; } } @@ -110,7 +132,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>> { fn run_tls_dtors(&mut self) -> EvalResult<'tcx> { - let mut dtor = self.memory.fetch_tls_dtor(None); + let mut dtor = self.machine.tls.fetch_tls_dtor(None, *self.tcx); // FIXME: replace loop by some structure that works with stepping while let Some((instance, ptr, key)) = dtor { trace!("Running TLS dtor {:?} on {:?}", instance, ptr); @@ -134,9 +156,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // step until out of stackframes self.run()?; - dtor = match self.memory.fetch_tls_dtor(Some(key)) { + dtor = match self.machine.tls.fetch_tls_dtor(Some(key), *self.tcx) { dtor @ Some(_) => dtor, - None => self.memory.fetch_tls_dtor(None), + None => self.machine.tls.fetch_tls_dtor(None, *self.tcx), }; } // FIXME: On a windows target, call `unsafe extern "system" fn on_tls_callback`.