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