@@ -18,6 +18,8 @@ use rustc_span::symbol::{sym, Symbol};
1818
1919use crate :: * ;
2020
21+ pub use crate :: threads:: { ThreadId , ThreadSet , ThreadLocalStorage } ;
22+
2123// Some global facts about the emulated machine.
2224pub const PAGE_SIZE : u64 = 4 * 1024 ; // FIXME: adjust to target architecture
2325pub const STACK_ADDR : u64 = 32 * PAGE_SIZE ; // not really about the "stack", but where we start assigning integer addresses to allocations
@@ -74,6 +76,7 @@ pub struct AllocExtra {
7476pub struct MemoryExtra {
7577 pub stacked_borrows : Option < stacked_borrows:: MemoryExtra > ,
7678 pub intptrcast : intptrcast:: MemoryExtra ,
79+ pub tls : ThreadLocalStorage ,
7780
7881 /// Mapping extern static names to their canonical allocation.
7982 extern_statics : FxHashMap < Symbol , AllocId > ,
@@ -100,6 +103,7 @@ impl MemoryExtra {
100103 extern_statics : FxHashMap :: default ( ) ,
101104 rng : RefCell :: new ( rng) ,
102105 tracked_alloc_id,
106+ tls : Default :: default ( ) ,
103107 }
104108 }
105109
@@ -147,7 +151,7 @@ impl MemoryExtra {
147151}
148152
149153/// The machine itself.
150- pub struct Evaluator < ' tcx > {
154+ pub struct Evaluator < ' mir , ' tcx > {
151155 /// Environment variables set by `setenv`.
152156 /// Miri does not expose env vars from the host to the emulated program.
153157 pub ( crate ) env_vars : EnvVars < ' tcx > ,
@@ -182,9 +186,11 @@ pub struct Evaluator<'tcx> {
182186
183187 /// The "time anchor" for this machine's monotone clock (for `Instant` simulation).
184188 pub ( crate ) time_anchor : Instant ,
189+
190+ pub ( crate ) threads : ThreadSet < ' mir , ' tcx > ,
185191}
186192
187- impl < ' tcx > Evaluator < ' tcx > {
193+ impl < ' mir , ' tcx > Evaluator < ' mir , ' tcx > {
188194 pub ( crate ) fn new ( communicate : bool , validate : bool ) -> Self {
189195 Evaluator {
190196 // `env_vars` could be initialized properly here if `Memory` were available before
@@ -201,12 +207,13 @@ impl<'tcx> Evaluator<'tcx> {
201207 dir_handler : Default :: default ( ) ,
202208 panic_payload : None ,
203209 time_anchor : Instant :: now ( ) ,
210+ threads : Default :: default ( ) ,
204211 }
205212 }
206213}
207214
208215/// A rustc InterpCx for Miri.
209- pub type MiriEvalContext < ' mir , ' tcx > = InterpCx < ' mir , ' tcx , Evaluator < ' tcx > > ;
216+ pub type MiriEvalContext < ' mir , ' tcx > = InterpCx < ' mir , ' tcx , Evaluator < ' mir , ' tcx > > ;
210217
211218/// A little trait that's useful to be inherited by extension traits.
212219pub trait MiriEvalContextExt < ' mir , ' tcx > {
@@ -225,7 +232,7 @@ impl<'mir, 'tcx> MiriEvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx>
225232}
226233
227234/// Machine hook implementations.
228- impl < ' mir , ' tcx > Machine < ' mir , ' tcx > for Evaluator < ' tcx > {
235+ impl < ' mir , ' tcx > Machine < ' mir , ' tcx > for Evaluator < ' mir , ' tcx > {
229236 type MemoryKind = MiriMemoryKind ;
230237
231238 type FrameExtra = FrameData < ' tcx > ;
@@ -241,6 +248,19 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
241248
242249 const CHECK_ALIGN : bool = true ;
243250
251+ #[ inline( always) ]
252+ fn stack < ' a > (
253+ ecx : & ' a InterpCx < ' mir , ' tcx , Self >
254+ ) -> & ' a [ Frame < ' mir , ' tcx , Self :: PointerTag , Self :: FrameExtra > ] {
255+ ecx. active_thread_stack ( )
256+ }
257+
258+ fn stack_mut < ' a > (
259+ ecx : & ' a mut InterpCx < ' mir , ' tcx , Self >
260+ ) -> & ' a mut Vec < Frame < ' mir , ' tcx , Self :: PointerTag , Self :: FrameExtra > > {
261+ ecx. active_thread_stack_mut ( )
262+ }
263+
244264 #[ inline( always) ]
245265 fn enforce_validity ( ecx : & InterpCx < ' mir , ' tcx , Self > ) -> bool {
246266 ecx. machine . validate
@@ -333,29 +353,39 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
333353
334354 fn canonical_alloc_id ( mem : & Memory < ' mir , ' tcx , Self > , id : AllocId ) -> AllocId {
335355 let tcx = mem. tcx ;
336- // Figure out if this is an extern static, and if yes, which one.
337- let def_id = match tcx. alloc_map . lock ( ) . get ( id) {
338- Some ( GlobalAlloc :: Static ( def_id) ) if tcx. is_foreign_item ( def_id) => def_id,
356+ let alloc = tcx. alloc_map . lock ( ) . get ( id) ;
357+ match alloc {
358+ Some ( GlobalAlloc :: Static ( def_id) ) if tcx. is_foreign_item ( def_id) => {
359+ // Figure out if this is an extern static, and if yes, which one.
360+ let attrs = tcx. get_attrs ( def_id) ;
361+ let link_name = match attr:: first_attr_value_str_by_name ( & attrs, sym:: link_name) {
362+ Some ( name) => name,
363+ None => tcx. item_name ( def_id) ,
364+ } ;
365+ // Check if we know this one.
366+ if let Some ( canonical_id) = mem. extra . extern_statics . get ( & link_name) {
367+ trace ! ( "canonical_alloc_id: {:?} ({}) -> {:?}" , id, link_name, canonical_id) ;
368+ * canonical_id
369+ } else {
370+ // Return original id; `Memory::get_static_alloc` will throw an error.
371+ id
372+ }
373+ } ,
374+ Some ( GlobalAlloc :: Static ( def_id) ) if tcx. has_attr ( def_id, sym:: thread_local) => {
375+ // We have a thread local, so we need to get a unique allocation id for it.
376+ mem. extra . tls . get_or_register_allocation ( * tcx, id)
377+ } ,
339378 _ => {
340379 // No need to canonicalize anything.
341- return id ;
380+ id
342381 }
343- } ;
344- let attrs = tcx. get_attrs ( def_id) ;
345- let link_name = match attr:: first_attr_value_str_by_name ( & attrs, sym:: link_name) {
346- Some ( name) => name,
347- None => tcx. item_name ( def_id) ,
348- } ;
349- // Check if we know this one.
350- if let Some ( canonical_id) = mem. extra . extern_statics . get ( & link_name) {
351- trace ! ( "canonical_alloc_id: {:?} ({}) -> {:?}" , id, link_name, canonical_id) ;
352- * canonical_id
353- } else {
354- // Return original id; `Memory::get_static_alloc` will throw an error.
355- id
356382 }
357383 }
358384
385+ fn resolve_thread_local_allocation_id ( extra : & Self :: MemoryExtra , id : AllocId ) -> AllocId {
386+ extra. tls . resolve_allocation ( id)
387+ }
388+
359389 fn init_allocation_extra < ' b > (
360390 memory_extra : & MemoryExtra ,
361391 id : AllocId ,
0 commit comments