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 ,
@@ -94,6 +91,21 @@ impl SyntaxContextData {
94
91
self . dollar_crate_name == kw:: Empty
95
92
}
96
93
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
+
97
109
fn key ( & self ) -> SyntaxContextKey {
98
110
( self . parent , self . outer_expn , self . outer_transparency )
99
111
}
@@ -574,67 +586,49 @@ impl HygieneData {
574
586
575
587
fn apply_mark_internal (
576
588
& mut self ,
577
- ctxt : SyntaxContext ,
589
+ parent : SyntaxContext ,
578
590
expn_id : ExpnId ,
579
591
transparency : Transparency ,
580
592
) -> 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;
624
598
}
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
+ } ;
625
627
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
638
632
}
639
633
}
640
634
@@ -1265,7 +1259,7 @@ impl HygieneEncodeContext {
1265
1259
pub fn encode < T > (
1266
1260
& self ,
1267
1261
encoder : & mut T ,
1268
- mut encode_ctxt : impl FnMut ( & mut T , u32 , & SyntaxContextData ) ,
1262
+ mut encode_ctxt : impl FnMut ( & mut T , u32 , & SyntaxContextKey ) ,
1269
1263
mut encode_expn : impl FnMut ( & mut T , ExpnId , & ExpnData , ExpnHash ) ,
1270
1264
) {
1271
1265
// When we serialize a `SyntaxContextData`, we may end up serializing
@@ -1323,9 +1317,6 @@ struct HygieneDecodeContextInner {
1323
1317
/// Additional information used to assist in decoding hygiene data
1324
1318
pub struct HygieneDecodeContext {
1325
1319
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 > > > ,
1329
1320
}
1330
1321
1331
1322
/// 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(
1396
1387
// to track which `SyntaxContext`s we have already decoded.
1397
1388
// The provided closure will be invoked to deserialize a `SyntaxContextData`
1398
1389
// 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 > (
1400
1391
d : & mut D ,
1401
1392
context : & HygieneDecodeContext ,
1402
- decode_data : F ,
1393
+ decode_ctxt_key : F ,
1403
1394
) -> SyntaxContext {
1404
1395
let raw_id: u32 = Decodable :: decode ( d) ;
1405
1396
if raw_id == 0 {
@@ -1408,58 +1399,9 @@ pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContext
1408
1399
return SyntaxContext :: root ( ) ;
1409
1400
}
1410
1401
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
-
1459
1402
// Don't try to decode data while holding the lock, since we need to
1460
1403
// 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) ;
1463
1405
1464
1406
let ctxt = HygieneData :: with ( |hygiene_data| {
1465
1407
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
1473
1415
Some ( & ctxt) => ctxt,
1474
1416
// This is a completely new context.
1475
1417
// 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 ) ,
1493
1419
}
1494
1420
} ) ;
1495
1421
1496
- // Mark the context as completed
1497
- context. local_in_progress . borrow_mut ( ) . remove ( & raw_id) ;
1498
-
1499
1422
let mut inner = context. inner . lock ( ) ;
1500
1423
let new_len = raw_id as usize + 1 ;
1501
1424
if inner. remapped_ctxts . len ( ) < new_len {
@@ -1507,15 +1430,15 @@ pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContext
1507
1430
ctxt
1508
1431
}
1509
1432
1510
- fn for_all_ctxts_in < F : FnMut ( u32 , SyntaxContext , & SyntaxContextData ) > (
1433
+ fn for_all_ctxts_in < F : FnMut ( u32 , SyntaxContext , & SyntaxContextKey ) > (
1511
1434
ctxts : impl Iterator < Item = SyntaxContext > ,
1512
1435
mut f : F ,
1513
1436
) {
1514
1437
let all_data: Vec < _ > = HygieneData :: with ( |data| {
1515
1438
ctxts. map ( |ctxt| ( ctxt, data. syntax_context_data [ ctxt. 0 as usize ] . clone ( ) ) ) . collect ( )
1516
1439
} ) ;
1517
1440
for ( ctxt, data) in all_data. into_iter ( ) {
1518
- f ( ctxt. 0 , ctxt, & data) ;
1441
+ f ( ctxt. 0 , ctxt, & data. key ( ) ) ;
1519
1442
}
1520
1443
}
1521
1444
0 commit comments