2424// because getting it wrong can lead to nested `HygieneData::with` calls that
2525// trigger runtime aborts. (Fortunately these are obvious and easy to fix.)
2626
27- use std:: cell:: RefCell ;
28- use std:: collections:: hash_map:: Entry ;
29- use std:: collections:: hash_set:: Entry as SetEntry ;
3027use std:: hash:: Hash ;
3128use std:: sync:: Arc ;
3229use std:: { fmt, iter, mem} ;
3330
3431use rustc_data_structures:: fingerprint:: Fingerprint ;
3532use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
3633use rustc_data_structures:: stable_hasher:: { HashStable , HashingControls , StableHasher } ;
37- use rustc_data_structures:: sync:: { Lock , WorkerLocal } ;
34+ use rustc_data_structures:: sync:: Lock ;
3835use rustc_data_structures:: unhash:: UnhashMap ;
3936use rustc_hashes:: Hash64 ;
4037use rustc_index:: IndexVec ;
@@ -59,10 +56,10 @@ impl !PartialOrd for SyntaxContext {}
5956
6057/// If this part of two syntax contexts is equal, then the whole syntax contexts should be equal.
6158/// The other fields are only for caching.
62- type SyntaxContextKey = ( SyntaxContext , ExpnId , Transparency ) ;
59+ pub type SyntaxContextKey = ( SyntaxContext , ExpnId , Transparency ) ;
6360
6461#[ derive( Clone , Copy , PartialEq , Debug , Encodable , Decodable ) ]
65- pub struct SyntaxContextData {
62+ struct SyntaxContextData {
6663 outer_expn : ExpnId ,
6764 outer_transparency : Transparency ,
6865 parent : SyntaxContext ,
@@ -94,6 +91,21 @@ impl SyntaxContextData {
9491 self . dollar_crate_name == kw:: Empty
9592 }
9693
94+ fn new (
95+ ( parent, outer_expn, outer_transparency) : SyntaxContextKey ,
96+ opaque : SyntaxContext ,
97+ opaque_and_semitransparent : SyntaxContext ,
98+ ) -> Self {
99+ SyntaxContextData {
100+ parent,
101+ outer_expn,
102+ outer_transparency,
103+ opaque,
104+ opaque_and_semitransparent,
105+ dollar_crate_name : kw:: DollarCrate ,
106+ }
107+ }
108+
97109 fn key ( & self ) -> SyntaxContextKey {
98110 ( self . parent , self . outer_expn , self . outer_transparency )
99111 }
@@ -574,67 +586,49 @@ impl HygieneData {
574586
575587 fn apply_mark_internal (
576588 & mut self ,
577- ctxt : SyntaxContext ,
589+ parent : SyntaxContext ,
578590 expn_id : ExpnId ,
579591 transparency : Transparency ,
580592 ) -> SyntaxContext {
581- let syntax_context_data = & mut self . syntax_context_data ;
582- debug_assert ! ( !syntax_context_data[ ctxt. 0 as usize ] . is_decode_placeholder( ) ) ;
583- let mut opaque = syntax_context_data[ ctxt. 0 as usize ] . opaque ;
584- let mut opaque_and_semitransparent =
585- syntax_context_data[ ctxt. 0 as usize ] . opaque_and_semitransparent ;
586-
587- if transparency >= Transparency :: Opaque {
588- let parent = opaque;
589- opaque = * self
590- . syntax_context_map
591- . entry ( ( parent, expn_id, transparency) )
592- . or_insert_with ( || {
593- let new_opaque = SyntaxContext :: from_usize ( syntax_context_data. len ( ) ) ;
594- syntax_context_data. push ( SyntaxContextData {
595- outer_expn : expn_id,
596- outer_transparency : transparency,
597- parent,
598- opaque : new_opaque,
599- opaque_and_semitransparent : new_opaque,
600- dollar_crate_name : kw:: DollarCrate ,
601- } ) ;
602- new_opaque
603- } ) ;
604- }
605-
606- if transparency >= Transparency :: SemiTransparent {
607- let parent = opaque_and_semitransparent;
608- opaque_and_semitransparent = * self
609- . syntax_context_map
610- . entry ( ( parent, expn_id, transparency) )
611- . or_insert_with ( || {
612- let new_opaque_and_semitransparent =
613- SyntaxContext :: from_usize ( syntax_context_data. len ( ) ) ;
614- syntax_context_data. push ( SyntaxContextData {
615- outer_expn : expn_id,
616- outer_transparency : transparency,
617- parent,
618- opaque,
619- opaque_and_semitransparent : new_opaque_and_semitransparent,
620- dollar_crate_name : kw:: DollarCrate ,
621- } ) ;
622- new_opaque_and_semitransparent
623- } ) ;
593+ debug_assert ! ( !self . syntax_context_data[ parent. 0 as usize ] . is_decode_placeholder( ) ) ;
594+ // Look into the cache first.
595+ let key = ( parent, expn_id, transparency) ;
596+ if let Some ( ctxt) = self . syntax_context_map . get ( & key) {
597+ return * ctxt;
624598 }
599+ // Reserve a new syntax context.
600+ let ctxt = SyntaxContext :: from_usize ( self . syntax_context_data . len ( ) ) ;
601+ self . syntax_context_data . push ( SyntaxContextData :: decode_placeholder ( ) ) ;
602+ self . syntax_context_map . insert ( key, ctxt) ;
603+
604+ // Opaque and semi-transparent versions of the parent. Note that they may be equal to the
605+ // parent itself. E.g. `parent_opaque` == `parent` if the expn chain contains only opaques,
606+ // and `parent_opaque_and_semitransparent` == `parent` if the expn contains only opaques
607+ // and semi-transparents.
608+ let parent_opaque = self . syntax_context_data [ parent. 0 as usize ] . opaque ;
609+ let parent_opaque_and_semitransparent =
610+ self . syntax_context_data [ parent. 0 as usize ] . opaque_and_semitransparent ;
611+
612+ // Evaluate opaque and semi-transparent versions of the new syntax context.
613+ let ( opaque, opaque_and_semitransparent) = match transparency {
614+ Transparency :: Transparent => ( parent_opaque, parent_opaque_and_semitransparent) ,
615+ Transparency :: SemiTransparent => (
616+ parent_opaque,
617+ // Will be the same as `ctxt` if the expn chain contains only opaques and semi-transparents.
618+ self . apply_mark_internal ( parent_opaque_and_semitransparent, expn_id, transparency) ,
619+ ) ,
620+ Transparency :: Opaque => (
621+ // Will be the same as `ctxt` if the expn chain contains only opaques.
622+ self . apply_mark_internal ( parent_opaque, expn_id, transparency) ,
623+ // Will be the same as `ctxt` if the expn chain contains only opaques and semi-transparents.
624+ self . apply_mark_internal ( parent_opaque_and_semitransparent, expn_id, transparency) ,
625+ ) ,
626+ } ;
625627
626- let parent = ctxt;
627- * self . syntax_context_map . entry ( ( parent, expn_id, transparency) ) . or_insert_with ( || {
628- syntax_context_data. push ( SyntaxContextData {
629- outer_expn : expn_id,
630- outer_transparency : transparency,
631- parent,
632- opaque,
633- opaque_and_semitransparent,
634- dollar_crate_name : kw:: DollarCrate ,
635- } ) ;
636- SyntaxContext :: from_usize ( syntax_context_data. len ( ) - 1 )
637- } )
628+ // Fill the full data, now that we have it.
629+ self . syntax_context_data [ ctxt. as_u32 ( ) as usize ] =
630+ SyntaxContextData :: new ( key, opaque, opaque_and_semitransparent) ;
631+ ctxt
638632 }
639633}
640634
@@ -1265,7 +1259,7 @@ impl HygieneEncodeContext {
12651259 pub fn encode < T > (
12661260 & self ,
12671261 encoder : & mut T ,
1268- mut encode_ctxt : impl FnMut ( & mut T , u32 , & SyntaxContextData ) ,
1262+ mut encode_ctxt : impl FnMut ( & mut T , u32 , & SyntaxContextKey ) ,
12691263 mut encode_expn : impl FnMut ( & mut T , ExpnId , & ExpnData , ExpnHash ) ,
12701264 ) {
12711265 // When we serialize a `SyntaxContextData`, we may end up serializing
@@ -1323,9 +1317,6 @@ struct HygieneDecodeContextInner {
13231317/// Additional information used to assist in decoding hygiene data
13241318pub struct HygieneDecodeContext {
13251319 inner : Lock < HygieneDecodeContextInner > ,
1326-
1327- /// A set of serialized `SyntaxContext` ids that are currently being decoded on each thread.
1328- local_in_progress : WorkerLocal < RefCell < FxHashSet < u32 > > > ,
13291320}
13301321
13311322/// Register an expansion which has been decoded from the on-disk-cache for the local crate.
@@ -1396,10 +1387,10 @@ pub fn decode_expn_id(
13961387// to track which `SyntaxContext`s we have already decoded.
13971388// The provided closure will be invoked to deserialize a `SyntaxContextData`
13981389// if we haven't already seen the id of the `SyntaxContext` we are deserializing.
1399- pub fn decode_syntax_context < D : Decoder , F : FnOnce ( & mut D , u32 ) -> SyntaxContextData > (
1390+ pub fn decode_syntax_context < D : Decoder , F : FnOnce ( & mut D , u32 ) -> SyntaxContextKey > (
14001391 d : & mut D ,
14011392 context : & HygieneDecodeContext ,
1402- decode_data : F ,
1393+ decode_ctxt_key : F ,
14031394) -> SyntaxContext {
14041395 let raw_id: u32 = Decodable :: decode ( d) ;
14051396 if raw_id == 0 {
@@ -1408,58 +1399,9 @@ pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContext
14081399 return SyntaxContext :: root ( ) ;
14091400 }
14101401
1411- let pending_ctxt = {
1412- let mut inner = context. inner . lock ( ) ;
1413-
1414- // Reminder: `HygieneDecodeContext` is per-crate, so there are no collisions between
1415- // raw ids from different crate metadatas.
1416- if let Some ( ctxt) = inner. remapped_ctxts . get ( raw_id as usize ) . copied ( ) . flatten ( ) {
1417- // This has already been decoded.
1418- return ctxt;
1419- }
1420-
1421- match inner. decoding . entry ( raw_id) {
1422- Entry :: Occupied ( ctxt_entry) => {
1423- let pending_ctxt = * ctxt_entry. get ( ) ;
1424- match context. local_in_progress . borrow_mut ( ) . entry ( raw_id) {
1425- // We're decoding this already on the current thread. Return here and let the
1426- // function higher up the stack finish decoding to handle recursive cases.
1427- // Hopefully having a `SyntaxContext` that refers to an incorrect data is ok
1428- // during reminder of the decoding process, it's certainly not ok after the
1429- // top level decoding function returns.
1430- SetEntry :: Occupied ( ..) => return pending_ctxt,
1431- // Some other thread is currently decoding this.
1432- // Race with it (alternatively we could wait here).
1433- // We cannot return this value, unlike in the recursive case above, because it
1434- // may expose a `SyntaxContext` pointing to incorrect data to arbitrary code.
1435- SetEntry :: Vacant ( entry) => {
1436- entry. insert ( ) ;
1437- pending_ctxt
1438- }
1439- }
1440- }
1441- Entry :: Vacant ( entry) => {
1442- // We are the first thread to start decoding. Mark the current thread as being progress.
1443- context. local_in_progress . borrow_mut ( ) . insert ( raw_id) ;
1444-
1445- // Allocate and store SyntaxContext id *before* calling the decoder function,
1446- // as the SyntaxContextData may reference itself.
1447- let new_ctxt = HygieneData :: with ( |hygiene_data| {
1448- // Push a dummy SyntaxContextData to ensure that nobody else can get the
1449- // same ID as us. This will be overwritten after call `decode_data`.
1450- hygiene_data. syntax_context_data . push ( SyntaxContextData :: decode_placeholder ( ) ) ;
1451- SyntaxContext :: from_usize ( hygiene_data. syntax_context_data . len ( ) - 1 )
1452- } ) ;
1453- entry. insert ( new_ctxt) ;
1454- new_ctxt
1455- }
1456- }
1457- } ;
1458-
14591402 // Don't try to decode data while holding the lock, since we need to
14601403 // be able to recursively decode a SyntaxContext
1461- let ctxt_data = decode_data ( d, raw_id) ;
1462- let ctxt_key = ctxt_data. key ( ) ;
1404+ let ctxt_key = decode_ctxt_key ( d, raw_id) ;
14631405
14641406 let ctxt = HygieneData :: with ( |hygiene_data| {
14651407 match hygiene_data. syntax_context_map . get ( & ctxt_key) {
@@ -1473,29 +1415,10 @@ pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContext
14731415 Some ( & ctxt) => ctxt,
14741416 // This is a completely new context.
14751417 // Overwrite its placeholder data with our decoded data.
1476- None => {
1477- let ctxt_data_ref =
1478- & mut hygiene_data. syntax_context_data [ pending_ctxt. as_u32 ( ) as usize ] ;
1479- let prev_ctxt_data = mem:: replace ( ctxt_data_ref, ctxt_data) ;
1480- // Reset `dollar_crate_name` so that it will be updated by `update_dollar_crate_names`.
1481- // We don't care what the encoding crate set this to - we want to resolve it
1482- // from the perspective of the current compilation session.
1483- ctxt_data_ref. dollar_crate_name = kw:: DollarCrate ;
1484- // Make sure nothing weird happened while `decode_data` was running.
1485- if !prev_ctxt_data. is_decode_placeholder ( ) {
1486- // Another thread may have already inserted the decoded data,
1487- // but the decoded data should match.
1488- assert_eq ! ( prev_ctxt_data, * ctxt_data_ref) ;
1489- }
1490- hygiene_data. syntax_context_map . insert ( ctxt_key, pending_ctxt) ;
1491- pending_ctxt
1492- }
1418+ None => hygiene_data. apply_mark_internal ( ctxt_key. 0 , ctxt_key. 1 , ctxt_key. 2 ) ,
14931419 }
14941420 } ) ;
14951421
1496- // Mark the context as completed
1497- context. local_in_progress . borrow_mut ( ) . remove ( & raw_id) ;
1498-
14991422 let mut inner = context. inner . lock ( ) ;
15001423 let new_len = raw_id as usize + 1 ;
15011424 if inner. remapped_ctxts . len ( ) < new_len {
@@ -1507,15 +1430,15 @@ pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContext
15071430 ctxt
15081431}
15091432
1510- fn for_all_ctxts_in < F : FnMut ( u32 , SyntaxContext , & SyntaxContextData ) > (
1433+ fn for_all_ctxts_in < F : FnMut ( u32 , SyntaxContext , & SyntaxContextKey ) > (
15111434 ctxts : impl Iterator < Item = SyntaxContext > ,
15121435 mut f : F ,
15131436) {
15141437 let all_data: Vec < _ > = HygieneData :: with ( |data| {
15151438 ctxts. map ( |ctxt| ( ctxt, data. syntax_context_data [ ctxt. 0 as usize ] . clone ( ) ) ) . collect ( )
15161439 } ) ;
15171440 for ( ctxt, data) in all_data. into_iter ( ) {
1518- f ( ctxt. 0 , ctxt, & data) ;
1441+ f ( ctxt. 0 , ctxt, & data. key ( ) ) ;
15191442 }
15201443}
15211444
0 commit comments