Skip to content

Commit 70a86f7

Browse files
Auto merge of #144385 - xizheyin:macro-hygiene, r=<try>
Optimize performance in macro hygiene system
2 parents efd420c + e233072 commit 70a86f7

File tree

1 file changed

+53
-17
lines changed

1 file changed

+53
-17
lines changed

compiler/rustc_span/src/hygiene.rs

Lines changed: 53 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ impl ExpnId {
322322

323323
/// `expn_id.outer_expn_is_descendant_of(ctxt)` is equivalent to but faster than
324324
/// `expn_id.is_descendant_of(ctxt.outer_expn())`.
325+
#[inline]
325326
pub fn outer_expn_is_descendant_of(self, ctxt: SyntaxContext) -> bool {
326327
HygieneData::with(|data| data.is_descendant_of(self, data.outer_expn(ctxt)))
327328
}
@@ -437,23 +438,28 @@ impl HygieneData {
437438
}
438439
}
439440

441+
#[inline]
440442
fn normalize_to_macros_2_0(&self, ctxt: SyntaxContext) -> SyntaxContext {
441443
self.syntax_context_data[ctxt.0 as usize].opaque
442444
}
443445

446+
#[inline]
444447
fn normalize_to_macro_rules(&self, ctxt: SyntaxContext) -> SyntaxContext {
445448
self.syntax_context_data[ctxt.0 as usize].opaque_and_semiopaque
446449
}
447450

451+
#[inline]
448452
fn outer_expn(&self, ctxt: SyntaxContext) -> ExpnId {
449453
self.syntax_context_data[ctxt.0 as usize].outer_expn
450454
}
451455

456+
#[inline]
452457
fn outer_mark(&self, ctxt: SyntaxContext) -> (ExpnId, Transparency) {
453458
let data = &self.syntax_context_data[ctxt.0 as usize];
454459
(data.outer_expn, data.outer_transparency)
455460
}
456461

462+
#[inline]
457463
fn parent_ctxt(&self, ctxt: SyntaxContext) -> SyntaxContext {
458464
self.syntax_context_data[ctxt.0 as usize].parent
459465
}
@@ -572,35 +578,32 @@ impl HygieneData {
572578
}
573579

574580
// Reserve a new syntax context.
575-
// The inserted dummy data can only be potentially accessed by nested `alloc_ctxt` calls,
576-
// the assert below ensures that it doesn't happen.
577581
let ctxt = SyntaxContext::from_usize(self.syntax_context_data.len());
578582
self.syntax_context_data
579583
.push(SyntaxContextData { dollar_crate_name: sym::dummy, ..SyntaxContextData::root() });
580584
self.syntax_context_map.insert(key, ctxt);
581585

582-
// Opaque and semi-opaque versions of the parent. Note that they may be equal to the
583-
// parent itself. E.g. `parent_opaque` == `parent` if the expn chain contains only opaques,
584-
// and `parent_opaque_and_semiopaque` == `parent` if the expn contains only (semi-)opaques.
586+
// Get parent data
585587
let parent_data = &self.syntax_context_data[parent.0 as usize];
586588
assert_ne!(parent_data.dollar_crate_name, sym::dummy);
587589
let parent_opaque = parent_data.opaque;
588590
let parent_opaque_and_semiopaque = parent_data.opaque_and_semiopaque;
589591

590-
// Evaluate opaque and semi-opaque versions of the new syntax context.
592+
// Evaluate opaque and semi-opaque versions iteratively to avoid recursive calls
591593
let (opaque, opaque_and_semiopaque) = match transparency {
592594
Transparency::Transparent => (parent_opaque, parent_opaque_and_semiopaque),
593-
Transparency::SemiOpaque => (
594-
parent_opaque,
595-
// Will be the same as `ctxt` if the expn chain contains only (semi-)opaques.
596-
self.alloc_ctxt(parent_opaque_and_semiopaque, expn_id, transparency),
597-
),
598-
Transparency::Opaque => (
599-
// Will be the same as `ctxt` if the expn chain contains only opaques.
600-
self.alloc_ctxt(parent_opaque, expn_id, transparency),
601-
// Will be the same as `ctxt` if the expn chain contains only (semi-)opaques.
602-
self.alloc_ctxt(parent_opaque_and_semiopaque, expn_id, transparency),
603-
),
595+
Transparency::SemiOpaque => {
596+
let opaque = parent_opaque;
597+
let semi_opaque =
598+
self.alloc_ctxt_if_needed(parent_opaque_and_semiopaque, expn_id, transparency);
599+
(opaque, semi_opaque)
600+
}
601+
Transparency::Opaque => {
602+
let opaque = self.alloc_ctxt_if_needed(parent_opaque, expn_id, transparency);
603+
let semi_opaque =
604+
self.alloc_ctxt_if_needed(parent_opaque_and_semiopaque, expn_id, transparency);
605+
(opaque, semi_opaque)
606+
}
604607
};
605608

606609
// Fill the full data, now that we have it.
@@ -614,6 +617,31 @@ impl HygieneData {
614617
};
615618
ctxt
616619
}
620+
621+
/// Helper to allocate context only if it would be different from the current one.
622+
/// This avoids unnecessary recursive calls in common cases.
623+
#[inline]
624+
fn alloc_ctxt_if_needed(
625+
&mut self,
626+
parent: SyntaxContext,
627+
expn_id: ExpnId,
628+
transparency: Transparency,
629+
) -> SyntaxContext {
630+
// Fast path: if parent would be the same, return current context being built
631+
let current_idx = self.syntax_context_data.len() - 1;
632+
if parent.0 as usize == current_idx {
633+
return SyntaxContext::from_usize(current_idx);
634+
}
635+
636+
// Check cache first
637+
let key = (parent, expn_id, transparency);
638+
if let Some(ctxt) = self.syntax_context_map.get(&key) {
639+
return *ctxt;
640+
}
641+
642+
// Need to compute
643+
self.alloc_ctxt(parent, expn_id, transparency)
644+
}
617645
}
618646

619647
pub fn walk_chain(span: Span, to: SyntaxContext) -> Span {
@@ -718,11 +746,13 @@ impl SyntaxContext {
718746
SyntaxContext(raw as u32)
719747
}
720748

749+
#[inline]
721750
fn from_usize(raw: usize) -> SyntaxContext {
722751
SyntaxContext(u32::try_from(raw).unwrap())
723752
}
724753

725754
/// Extend a syntax context with a given expansion and transparency.
755+
#[inline]
726756
pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> SyntaxContext {
727757
HygieneData::with(|data| data.apply_mark(self, expn_id, transparency))
728758
}
@@ -743,10 +773,12 @@ impl SyntaxContext {
743773
/// of g (call it g1), calling remove_mark will result in the SyntaxContext for the
744774
/// invocation of f that created g1.
745775
/// Returns the mark that was removed.
776+
#[inline]
746777
pub fn remove_mark(&mut self) -> ExpnId {
747778
HygieneData::with(|data| data.remove_mark(self).0)
748779
}
749780

781+
#[inline]
750782
pub fn marks(self) -> Vec<(ExpnId, Transparency)> {
751783
HygieneData::with(|data| data.marks(self))
752784
}
@@ -776,11 +808,13 @@ impl SyntaxContext {
776808
/// ```
777809
/// This returns the expansion whose definition scope we use to privacy check the resolution,
778810
/// or `None` if we privacy check as usual (i.e., not w.r.t. a macro definition scope).
811+
#[inline]
779812
pub fn adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> {
780813
HygieneData::with(|data| data.adjust(self, expn_id))
781814
}
782815

783816
/// Like `SyntaxContext::adjust`, but also normalizes `self` to macros 2.0.
817+
#[inline]
784818
pub(crate) fn normalize_to_macros_2_0_and_adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> {
785819
HygieneData::with(|data| {
786820
*self = data.normalize_to_macros_2_0(*self);
@@ -901,10 +935,12 @@ impl SyntaxContext {
901935
HygieneData::with(|data| data.outer_mark(self))
902936
}
903937

938+
#[inline]
904939
pub(crate) fn dollar_crate_name(self) -> Symbol {
905940
HygieneData::with(|data| data.syntax_context_data[self.0 as usize].dollar_crate_name)
906941
}
907942

943+
#[inline]
908944
pub fn edition(self) -> Edition {
909945
HygieneData::with(|data| data.expn_data(data.outer_expn(self)).edition)
910946
}

0 commit comments

Comments
 (0)