24
24
// because getting it wrong can lead to nested `HygieneData::with` calls that
25
25
// trigger runtime aborts. (Fortunately these are obvious and easy to fix.)
26
26
27
- use std:: cell:: RefCell ;
28
- use std:: collections:: hash_map:: Entry ;
29
- use std:: collections:: hash_set:: Entry as SetEntry ;
30
27
use std:: hash:: Hash ;
31
28
use std:: sync:: Arc ;
32
29
use std:: { fmt, iter, mem} ;
33
30
34
31
use rustc_data_structures:: fingerprint:: Fingerprint ;
35
32
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
36
33
use rustc_data_structures:: stable_hasher:: { HashStable , HashingControls , StableHasher } ;
37
- use rustc_data_structures:: sync:: { Lock , WorkerLocal } ;
34
+ use rustc_data_structures:: sync:: Lock ;
38
35
use rustc_data_structures:: unhash:: UnhashMap ;
39
36
use rustc_hashes:: Hash64 ;
40
37
use rustc_index:: IndexVec ;
@@ -59,10 +56,10 @@ impl !PartialOrd for SyntaxContext {}
59
56
60
57
/// If this part of two syntax contexts is equal, then the whole syntax contexts should be equal.
61
58
/// The other fields are only for caching.
62
- type SyntaxContextKey = ( SyntaxContext , ExpnId , Transparency ) ;
59
+ pub type SyntaxContextKey = ( SyntaxContext , ExpnId , Transparency ) ;
63
60
64
61
#[ derive( Clone , Copy , PartialEq , Debug , Encodable , Decodable ) ]
65
- pub struct SyntaxContextData {
62
+ struct SyntaxContextData {
66
63
outer_expn : ExpnId ,
67
64
outer_transparency : Transparency ,
68
65
parent : SyntaxContext ,
@@ -1266,7 +1263,7 @@ impl HygieneEncodeContext {
1266
1263
pub fn encode < T > (
1267
1264
& self ,
1268
1265
encoder : & mut T ,
1269
- mut encode_ctxt : impl FnMut ( & mut T , u32 , & SyntaxContextData ) ,
1266
+ mut encode_ctxt : impl FnMut ( & mut T , u32 , & SyntaxContextKey ) ,
1270
1267
mut encode_expn : impl FnMut ( & mut T , ExpnId , & ExpnData , ExpnHash ) ,
1271
1268
) {
1272
1269
// When we serialize a `SyntaxContextData`, we may end up serializing
@@ -1315,18 +1312,12 @@ struct HygieneDecodeContextInner {
1315
1312
// so that multiple occurrences of the same serialized id are decoded to the same
1316
1313
// `SyntaxContext`. This only stores `SyntaxContext`s which are completely decoded.
1317
1314
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
1315
}
1322
1316
1323
1317
#[ derive( Default ) ]
1324
1318
/// Additional information used to assist in decoding hygiene data
1325
1319
pub struct HygieneDecodeContext {
1326
1320
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
1321
}
1331
1322
1332
1323
/// Register an expansion which has been decoded from the on-disk-cache for the local crate.
@@ -1397,10 +1388,10 @@ pub fn decode_expn_id(
1397
1388
// to track which `SyntaxContext`s we have already decoded.
1398
1389
// The provided closure will be invoked to deserialize a `SyntaxContextData`
1399
1390
// 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 > (
1391
+ pub fn decode_syntax_context < D : Decoder , F : FnOnce ( & mut D , u32 ) -> SyntaxContextKey > (
1401
1392
d : & mut D ,
1402
1393
context : & HygieneDecodeContext ,
1403
- decode_data : F ,
1394
+ decode_ctxt_key : F ,
1404
1395
) -> SyntaxContext {
1405
1396
let raw_id: u32 = Decodable :: decode ( d) ;
1406
1397
if raw_id == 0 {
@@ -1409,115 +1400,39 @@ pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContext
1409
1400
return SyntaxContext :: root ( ) ;
1410
1401
}
1411
1402
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
- } ;
1403
+ // Reminder: `HygieneDecodeContext` is per-crate, so there are no collisions between
1404
+ // raw ids from different crate metadatas.
1405
+ if let Some ( ctxt) = context. inner . lock ( ) . remapped_ctxts . get ( raw_id as usize ) . copied ( ) . flatten ( )
1406
+ {
1407
+ // This has already been decoded.
1408
+ return ctxt;
1409
+ }
1460
1410
1461
1411
// Don't try to decode data while holding the lock, since we need to
1462
1412
// 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) ;
1413
+ let ( parent, expn_id, transparency) = decode_ctxt_key ( d, raw_id) ;
1414
+ let ctxt =
1415
+ HygieneData :: with ( |hygiene_data| hygiene_data. alloc_ctxt ( parent, expn_id, transparency) ) ;
1500
1416
1501
1417
let mut inner = context. inner . lock ( ) ;
1502
1418
let new_len = raw_id as usize + 1 ;
1503
1419
if inner. remapped_ctxts . len ( ) < new_len {
1504
1420
inner. remapped_ctxts . resize ( new_len, None ) ;
1505
1421
}
1506
1422
inner. remapped_ctxts [ raw_id as usize ] = Some ( ctxt) ;
1507
- inner. decoding . remove ( & raw_id) ;
1508
1423
1509
1424
ctxt
1510
1425
}
1511
1426
1512
- fn for_all_ctxts_in < F : FnMut ( u32 , SyntaxContext , & SyntaxContextData ) > (
1427
+ fn for_all_ctxts_in < F : FnMut ( u32 , SyntaxContext , & SyntaxContextKey ) > (
1513
1428
ctxts : impl Iterator < Item = SyntaxContext > ,
1514
1429
mut f : F ,
1515
1430
) {
1516
1431
let all_data: Vec < _ > = HygieneData :: with ( |data| {
1517
1432
ctxts. map ( |ctxt| ( ctxt, data. syntax_context_data [ ctxt. 0 as usize ] . clone ( ) ) ) . collect ( )
1518
1433
} ) ;
1519
1434
for ( ctxt, data) in all_data. into_iter ( ) {
1520
- f ( ctxt. 0 , ctxt, & data) ;
1435
+ f ( ctxt. 0 , ctxt, & data. key ( ) ) ;
1521
1436
}
1522
1437
}
1523
1438
0 commit comments