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
@@ -1286,9 +1283,9 @@ impl HygieneEncodeContext {
1286
1283
// of the table that we insert data into doesn't depend on insertion
1287
1284
// order
1288
1285
#[ 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 | {
1290
1287
if self . serialized_ctxts . lock ( ) . insert ( ctxt) {
1291
- encode_ctxt ( encoder, index, data ) ;
1288
+ encode_ctxt ( encoder, index, ctxt_key ) ;
1292
1289
}
1293
1290
} ) ;
1294
1291
@@ -1306,29 +1303,6 @@ impl HygieneEncodeContext {
1306
1303
}
1307
1304
}
1308
1305
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
-
1332
1306
/// Register an expansion which has been decoded from the on-disk-cache for the local crate.
1333
1307
pub fn register_local_expn_id ( data : ExpnData , hash : ExpnHash ) -> ExpnId {
1334
1308
HygieneData :: with ( |hygiene_data| {
@@ -1393,14 +1367,11 @@ pub fn decode_expn_id(
1393
1367
register_expn_id ( krate, index, expn_data, hash)
1394
1368
}
1395
1369
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 > (
1401
1373
d : & mut D ,
1402
- context : & HygieneDecodeContext ,
1403
- decode_data : F ,
1374
+ decode_ctxt_key : F ,
1404
1375
) -> SyntaxContext {
1405
1376
let raw_id: u32 = Decodable :: decode ( d) ;
1406
1377
if raw_id == 0 {
@@ -1409,115 +1380,21 @@ pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContext
1409
1380
return SyntaxContext :: root ( ) ;
1410
1381
}
1411
1382
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
-
1461
1383
// Don't try to decode data while holding the lock, since we need to
1462
1384
// 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) )
1510
1387
}
1511
1388
1512
- fn for_all_ctxts_in < F : FnMut ( u32 , SyntaxContext , & SyntaxContextData ) > (
1389
+ fn for_all_ctxts_in < F : FnMut ( u32 , SyntaxContext , & SyntaxContextKey ) > (
1513
1390
ctxts : impl Iterator < Item = SyntaxContext > ,
1514
1391
mut f : F ,
1515
1392
) {
1516
1393
let all_data: Vec < _ > = HygieneData :: with ( |data| {
1517
1394
ctxts. map ( |ctxt| ( ctxt, data. syntax_context_data [ ctxt. 0 as usize ] . clone ( ) ) ) . collect ( )
1518
1395
} ) ;
1519
1396
for ( ctxt, data) in all_data. into_iter ( ) {
1520
- f ( ctxt. 0 , ctxt, & data) ;
1397
+ f ( ctxt. 0 , ctxt, & data. key ( ) ) ;
1521
1398
}
1522
1399
}
1523
1400
0 commit comments