diff --git a/src/fn_call.rs b/src/fn_call.rs index de40ef943a5..31b3b4b18d1 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -607,7 +607,7 @@ fn call_foreign_item( } "_tlv_atexit" => { - return err!(Unimplemented("can't interpret with full mir for osx target".to_owned())); + return err!(Unimplemented("Thread-local store is not fully supported on macOS".to_owned())); }, // Stub out all the other pthread calls to just return 0 @@ -643,6 +643,34 @@ fn call_foreign_item( self.write_scalar(dest, Scalar::from_u128(120), dest_ty)?; }, + // Windows TLS + "TlsAlloc" => { + // This just creates a key; Windows does not natively support TLS dtors. + + // Figure out how large a TLS key actually is. This is c::DWORD. + let key_size = self.layout_of(dest_ty)?.size; + + // Create key and return it + let key = self.memory.create_tls_key(None) as u128; + if key_size.bits() < 128 && key >= (1u128 << key_size.bits() as u128) { + return err!(OutOfTls); + } + self.write_scalar(dest, Scalar::from_u128(key), dest_ty)?; + } + "TlsGetValue" => { + let key = self.value_to_scalar(args[0])?.to_bytes()?; + let ptr = self.memory.load_tls(key)?; + self.write_ptr(dest, ptr, dest_ty)?; + } + "TlsSetValue" => { + let key = self.value_to_scalar(args[0])?.to_bytes()?; + let new_ptr = self.into_ptr(args[1].value)?; + self.memory.store_tls(key, new_ptr)?; + + // Return success (1) + self.write_scalar(dest, Scalar::from_u128(1), dest_ty)?; + } + // We can't execute anything else _ => { return err!(Unimplemented( diff --git a/src/lib.rs b/src/lib.rs index 520d696405a..5a2d7e77d65 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -141,7 +141,12 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( main_id: DefId, start_wrapper: Option, ) -> EvalResult<'tcx, (EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>, Option)> { - let mut ecx = EvalContext::new(tcx.at(syntax::codemap::DUMMY_SP), ty::ParamEnv::reveal_all(), Default::default(), Default::default()); + let mut ecx = EvalContext::new( + tcx.at(syntax::codemap::DUMMY_SP), + ty::ParamEnv::reveal_all(), + Default::default(), + MemoryData::new() + ); let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; @@ -338,7 +343,7 @@ pub struct TlsEntry<'tcx> { dtor: Option>, } -#[derive(Clone, Default, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq)] pub struct MemoryData<'tcx> { /// The Key to use for the next thread-local allocation. next_thread_local: TlsKey, @@ -355,6 +360,17 @@ pub struct MemoryData<'tcx> { statics: HashMap, AllocId>, } +impl<'tcx> MemoryData<'tcx> { + 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(), + statics: HashMap::new(), + } + } +} + impl<'tcx> Hash for MemoryData<'tcx> { fn hash(&self, state: &mut H) { let MemoryData { diff --git a/src/tls.rs b/src/tls.rs index 45805f3aa8c..ffcf8629159 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -139,6 +139,7 @@ fn run_tls_dtors(&mut self) -> EvalResult<'tcx> { None => self.memory.fetch_tls_dtor(None)?, }; } + // FIXME: On a windows target, call `unsafe extern "system" fn on_tls_callback`. Ok(()) } }