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 ,
@@ -1266,7 +1263,7 @@ impl HygieneEncodeContext {
12661263 pub fn encode < T > (
12671264 & self ,
12681265 encoder : & mut T ,
1269- mut encode_ctxt : impl FnMut ( & mut T , u32 , & SyntaxContextData ) ,
1266+ mut encode_ctxt : impl FnMut ( & mut T , u32 , & SyntaxContextKey ) ,
12701267 mut encode_expn : impl FnMut ( & mut T , ExpnId , & ExpnData , ExpnHash ) ,
12711268 ) {
12721269 // When we serialize a `SyntaxContextData`, we may end up serializing
@@ -1286,9 +1283,9 @@ impl HygieneEncodeContext {
12861283 // of the table that we insert data into doesn't depend on insertion
12871284 // order
12881285 #[ allow( rustc:: potential_query_instability) ]
1289- for_all_ctxts_in ( latest_ctxts. into_iter ( ) , |index, ctxt, data | {
1286+ for_all_ctxts_in ( latest_ctxts. into_iter ( ) , |index, ctxt, ctxt_key | {
12901287 if self . serialized_ctxts . lock ( ) . insert ( ctxt) {
1291- encode_ctxt ( encoder, index, data ) ;
1288+ encode_ctxt ( encoder, index, ctxt_key ) ;
12921289 }
12931290 } ) ;
12941291
@@ -1306,29 +1303,6 @@ impl HygieneEncodeContext {
13061303 }
13071304}
13081305
1309- #[ derive( Default ) ]
1310- /// Additional information used to assist in decoding hygiene data
1311- struct HygieneDecodeContextInner {
1312- // Maps serialized `SyntaxContext` ids to a `SyntaxContext` in the current
1313- // global `HygieneData`. When we deserialize a `SyntaxContext`, we need to create
1314- // a new id in the global `HygieneData`. This map tracks the ID we end up picking,
1315- // so that multiple occurrences of the same serialized id are decoded to the same
1316- // `SyntaxContext`. This only stores `SyntaxContext`s which are completely decoded.
1317- remapped_ctxts : Vec < Option < SyntaxContext > > ,
1318-
1319- /// Maps serialized `SyntaxContext` ids that are currently being decoded to a `SyntaxContext`.
1320- decoding : FxHashMap < u32 , SyntaxContext > ,
1321- }
1322-
1323- #[ derive( Default ) ]
1324- /// Additional information used to assist in decoding hygiene data
1325- pub struct HygieneDecodeContext {
1326- inner : Lock < HygieneDecodeContextInner > ,
1327-
1328- /// A set of serialized `SyntaxContext` ids that are currently being decoded on each thread.
1329- local_in_progress : WorkerLocal < RefCell < FxHashSet < u32 > > > ,
1330- }
1331-
13321306/// Register an expansion which has been decoded from the on-disk-cache for the local crate.
13331307pub fn register_local_expn_id ( data : ExpnData , hash : ExpnHash ) -> ExpnId {
13341308 HygieneData :: with ( |hygiene_data| {
@@ -1393,14 +1367,11 @@ pub fn decode_expn_id(
13931367 register_expn_id ( krate, index, expn_data, hash)
13941368}
13951369
1396- // Decodes `SyntaxContext`, using the provided `HygieneDecodeContext`
1397- // to track which `SyntaxContext`s we have already decoded.
1398- // The provided closure will be invoked to deserialize a `SyntaxContextData`
1399- // if we haven't already seen the id of the `SyntaxContext` we are deserializing.
1400- pub fn decode_syntax_context < D : Decoder , F : FnOnce ( & mut D , u32 ) -> SyntaxContextData > (
1370+ // Decodes `SyntaxContext`.
1371+ // The provided closure will be invoked to deserialize a `SyntaxContextData`.
1372+ pub fn decode_syntax_context < D : Decoder , F : FnOnce ( & mut D , u32 ) -> SyntaxContextKey > (
14011373 d : & mut D ,
1402- context : & HygieneDecodeContext ,
1403- decode_data : F ,
1374+ decode_ctxt_key : F ,
14041375) -> SyntaxContext {
14051376 let raw_id: u32 = Decodable :: decode ( d) ;
14061377 if raw_id == 0 {
@@ -1409,115 +1380,21 @@ pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContext
14091380 return SyntaxContext :: root ( ) ;
14101381 }
14111382
1412- let pending_ctxt = {
1413- let mut inner = context. inner . lock ( ) ;
1414-
1415- // Reminder: `HygieneDecodeContext` is per-crate, so there are no collisions between
1416- // raw ids from different crate metadatas.
1417- if let Some ( ctxt) = inner. remapped_ctxts . get ( raw_id as usize ) . copied ( ) . flatten ( ) {
1418- // This has already been decoded.
1419- return ctxt;
1420- }
1421-
1422- match inner. decoding . entry ( raw_id) {
1423- Entry :: Occupied ( ctxt_entry) => {
1424- let pending_ctxt = * ctxt_entry. get ( ) ;
1425- match context. local_in_progress . borrow_mut ( ) . entry ( raw_id) {
1426- // We're decoding this already on the current thread. Return here and let the
1427- // function higher up the stack finish decoding to handle recursive cases.
1428- // Hopefully having a `SyntaxContext` that refers to an incorrect data is ok
1429- // during reminder of the decoding process, it's certainly not ok after the
1430- // top level decoding function returns.
1431- SetEntry :: Occupied ( ..) => return pending_ctxt,
1432- // Some other thread is currently decoding this.
1433- // Race with it (alternatively we could wait here).
1434- // We cannot return this value, unlike in the recursive case above, because it
1435- // may expose a `SyntaxContext` pointing to incorrect data to arbitrary code.
1436- SetEntry :: Vacant ( entry) => {
1437- entry. insert ( ) ;
1438- pending_ctxt
1439- }
1440- }
1441- }
1442- Entry :: Vacant ( entry) => {
1443- // We are the first thread to start decoding. Mark the current thread as being
1444- // progress.
1445- context. local_in_progress . borrow_mut ( ) . insert ( raw_id) ;
1446-
1447- // Allocate and store SyntaxContext id *before* calling the decoder function,
1448- // as the SyntaxContextData may reference itself.
1449- let new_ctxt = HygieneData :: with ( |hygiene_data| {
1450- // Push a dummy SyntaxContextData to ensure that nobody else can get the
1451- // same ID as us. This will be overwritten after call `decode_data`.
1452- hygiene_data. syntax_context_data . push ( SyntaxContextData :: decode_placeholder ( ) ) ;
1453- SyntaxContext :: from_usize ( hygiene_data. syntax_context_data . len ( ) - 1 )
1454- } ) ;
1455- entry. insert ( new_ctxt) ;
1456- new_ctxt
1457- }
1458- }
1459- } ;
1460-
14611383 // Don't try to decode data while holding the lock, since we need to
14621384 // be able to recursively decode a SyntaxContext
1463- let ctxt_data = decode_data ( d, raw_id) ;
1464- let ctxt_key = ctxt_data. key ( ) ;
1465-
1466- let ctxt = HygieneData :: with ( |hygiene_data| {
1467- match hygiene_data. syntax_context_map . get ( & ctxt_key) {
1468- // Ensure that syntax contexts are unique.
1469- // If syntax contexts with the given key already exists, reuse it instead of
1470- // using `pending_ctxt`.
1471- // `pending_ctxt` will leave an unused hole in the vector of syntax contexts.
1472- // Hopefully its value isn't stored anywhere during decoding and its dummy data
1473- // is never accessed later. The `is_decode_placeholder` asserts on all
1474- // accesses to syntax context data attempt to ensure it.
1475- Some ( & ctxt) => ctxt,
1476- // This is a completely new context.
1477- // Overwrite its placeholder data with our decoded data.
1478- None => {
1479- let ctxt_data_ref =
1480- & mut hygiene_data. syntax_context_data [ pending_ctxt. as_u32 ( ) as usize ] ;
1481- let prev_ctxt_data = mem:: replace ( ctxt_data_ref, ctxt_data) ;
1482- // Reset `dollar_crate_name` so that it will be updated by `update_dollar_crate_names`.
1483- // We don't care what the encoding crate set this to - we want to resolve it
1484- // from the perspective of the current compilation session.
1485- ctxt_data_ref. dollar_crate_name = kw:: DollarCrate ;
1486- // Make sure nothing weird happened while `decode_data` was running.
1487- if !prev_ctxt_data. is_decode_placeholder ( ) {
1488- // Another thread may have already inserted the decoded data,
1489- // but the decoded data should match.
1490- assert_eq ! ( prev_ctxt_data, * ctxt_data_ref) ;
1491- }
1492- hygiene_data. syntax_context_map . insert ( ctxt_key, pending_ctxt) ;
1493- pending_ctxt
1494- }
1495- }
1496- } ) ;
1497-
1498- // Mark the context as completed
1499- context. local_in_progress . borrow_mut ( ) . remove ( & raw_id) ;
1500-
1501- let mut inner = context. inner . lock ( ) ;
1502- let new_len = raw_id as usize + 1 ;
1503- if inner. remapped_ctxts . len ( ) < new_len {
1504- inner. remapped_ctxts . resize ( new_len, None ) ;
1505- }
1506- inner. remapped_ctxts [ raw_id as usize ] = Some ( ctxt) ;
1507- inner. decoding . remove ( & raw_id) ;
1508-
1509- ctxt
1385+ let ( parent, expn_id, transparency) = decode_ctxt_key ( d, raw_id) ;
1386+ HygieneData :: with ( |hygiene_data| hygiene_data. alloc_ctxt ( parent, expn_id, transparency) )
15101387}
15111388
1512- fn for_all_ctxts_in < F : FnMut ( u32 , SyntaxContext , & SyntaxContextData ) > (
1389+ fn for_all_ctxts_in < F : FnMut ( u32 , SyntaxContext , & SyntaxContextKey ) > (
15131390 ctxts : impl Iterator < Item = SyntaxContext > ,
15141391 mut f : F ,
15151392) {
15161393 let all_data: Vec < _ > = HygieneData :: with ( |data| {
15171394 ctxts. map ( |ctxt| ( ctxt, data. syntax_context_data [ ctxt. 0 as usize ] . clone ( ) ) ) . collect ( )
15181395 } ) ;
15191396 for ( ctxt, data) in all_data. into_iter ( ) {
1520- f ( ctxt. 0 , ctxt, & data) ;
1397+ f ( ctxt. 0 , ctxt, & data. key ( ) ) ;
15211398 }
15221399}
15231400
0 commit comments