about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-01-08 04:07:35 +0000
committerbors <bors@rust-lang.org>2024-01-08 04:07:35 +0000
commit0ee9cfd54db7b5f4be35f026588904500c866196 (patch)
tree8dff0bd7d0d2a86481b962442ed41d634b6dddda
parent76101eecbe9aa80753664bbe637ad06d1925f315 (diff)
parentedec91d624f41c25b3c75bb3df818dc081193dce (diff)
downloadrust-0ee9cfd54db7b5f4be35f026588904500c866196.tar.gz
rust-0ee9cfd54db7b5f4be35f026588904500c866196.zip
Auto merge of #119693 - petrochenkov:cachemark, r=cjgillot
macro_rules: Add an expansion-local cache to span marker

Most tokens in a macro body typically have the same syntax context.
So the cache should usually be hit.

This change can either be combined with https://github.com/rust-lang/rust/pull/119689, or serve as its alternative, depending on perf results.
-rw-r--r--compiler/rustc_expand/src/mbe/transcribe.rs17
-rw-r--r--compiler/rustc_span/src/hygiene.rs2
2 files changed, 14 insertions, 5 deletions
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index c969ca7ef89..434891ebc76 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -13,19 +13,28 @@ use rustc_errors::DiagnosticBuilder;
 use rustc_errors::{pluralize, PResult};
 use rustc_span::hygiene::{LocalExpnId, Transparency};
 use rustc_span::symbol::{sym, Ident, MacroRulesNormalizedIdent};
-use rustc_span::Span;
+use rustc_span::{Span, SyntaxContext};
 
 use smallvec::{smallvec, SmallVec};
 use std::mem;
 
 // A Marker adds the given mark to the syntax context.
-struct Marker(LocalExpnId, Transparency);
+struct Marker(LocalExpnId, Transparency, FxHashMap<SyntaxContext, SyntaxContext>);
 
 impl MutVisitor for Marker {
     const VISIT_TOKENS: bool = true;
 
     fn visit_span(&mut self, span: &mut Span) {
-        *span = span.apply_mark(self.0.to_expn_id(), self.1)
+        // `apply_mark` is a relatively expensive operation, both due to taking hygiene lock, and
+        // by itself. All tokens in a macro body typically have the same syntactic context, unless
+        // it's some advanced case with macro-generated macros. So if we cache the marked version
+        // of that context once, we'll typically have a 100% cache hit rate after that.
+        let Marker(expn_id, transparency, ref mut cache) = *self;
+        let data = span.data();
+        let marked_ctxt = *cache
+            .entry(data.ctxt)
+            .or_insert_with(|| data.ctxt.apply_mark(expn_id.to_expn_id(), transparency));
+        *span = data.with_ctxt(marked_ctxt);
     }
 }
 
@@ -123,7 +132,7 @@ pub(super) fn transcribe<'a>(
     // again, and we are done transcribing.
     let mut result: Vec<TokenTree> = Vec::new();
     let mut result_stack = Vec::new();
-    let mut marker = Marker(cx.current_expansion.id, transparency);
+    let mut marker = Marker(cx.current_expansion.id, transparency, Default::default());
 
     loop {
         // Look at the last frame on the stack.
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index 08fb1d1345d..6a15961ee20 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -658,7 +658,7 @@ impl SyntaxContext {
     }
 
     /// Extend a syntax context with a given expansion and transparency.
-    pub(crate) fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> SyntaxContext {
+    pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> SyntaxContext {
         HygieneData::with(|data| data.apply_mark(self, expn_id, transparency))
     }