diff options
| author | bors <bors@rust-lang.org> | 2024-01-08 04:07:35 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-01-08 04:07:35 +0000 |
| commit | 0ee9cfd54db7b5f4be35f026588904500c866196 (patch) | |
| tree | 8dff0bd7d0d2a86481b962442ed41d634b6dddda | |
| parent | 76101eecbe9aa80753664bbe637ad06d1925f315 (diff) | |
| parent | edec91d624f41c25b3c75bb3df818dc081193dce (diff) | |
| download | rust-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.rs | 17 | ||||
| -rw-r--r-- | compiler/rustc_span/src/hygiene.rs | 2 |
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)) } |
