rustc_span: Optimize span parent get/set methods

This commit is contained in:
Vadim Petrochenkov 2024-06-16 00:53:00 +03:00
parent 1aaab8b9f8
commit 4d3b617911
2 changed files with 70 additions and 35 deletions

View File

@ -525,8 +525,9 @@ pub fn with_hi(&self, hi: BytePos) -> Span {
fn with_ctxt(&self, ctxt: SyntaxContext) -> Span {
Span::new(self.lo, self.hi, ctxt, self.parent)
}
/// Avoid if possible, `Span::with_parent` should be preferred.
#[inline]
pub fn with_parent(&self, parent: Option<LocalDefId>) -> Span {
fn with_parent(&self, parent: Option<LocalDefId>) -> Span {
Span::new(self.lo, self.hi, self.ctxt, parent)
}
/// Returns `true` if this is a dummy span with any hygienic context.
@ -580,14 +581,6 @@ pub fn with_hi(self, hi: BytePos) -> Span {
pub fn with_ctxt(self, ctxt: SyntaxContext) -> Span {
self.map_ctxt(|_| ctxt)
}
#[inline]
pub fn parent(self) -> Option<LocalDefId> {
self.data().parent
}
#[inline]
pub fn with_parent(self, ctxt: Option<LocalDefId>) -> Span {
self.data().with_parent(ctxt)
}
#[inline]
pub fn is_visible(self, sm: &SourceMap) -> bool {

View File

@ -257,17 +257,17 @@ pub fn new(
std::mem::swap(&mut lo, &mut hi);
}
// Small len may enable one of fully inline formats (or may not).
// Small len and ctxt may enable one of fully inline formats (or may not).
let (len, ctxt32) = (hi.0 - lo.0, ctxt.as_u32());
if len <= MAX_LEN {
if ctxt32 <= MAX_CTXT && parent.is_none() {
return InlineCtxt::span(lo.0, len as u16, ctxt32 as u16);
} else if ctxt32 == 0
&& let Some(parent) = parent
&& let parent32 = parent.local_def_index.as_u32()
&& parent32 <= MAX_CTXT
{
return InlineParent::span(lo.0, len as u16, parent32 as u16);
if len <= MAX_LEN && ctxt32 <= MAX_CTXT {
match parent {
None => return InlineCtxt::span(lo.0, len as u16, ctxt32 as u16),
Some(parent) => {
let parent32 = parent.local_def_index.as_u32();
if ctxt32 == 0 && parent32 <= MAX_CTXT {
return InlineParent::span(lo.0, len as u16, parent32 as u16);
}
}
}
}
@ -322,29 +322,28 @@ pub fn is_dummy(self) -> bool {
}
}
// For optimization we are interested in cases in which the context is inline and the context
// update doesn't change format. All non-inline or format changing scenarios require accessing
// interner and can fall back to `Span::new`.
#[inline]
pub fn map_ctxt(self, update: impl FnOnce(SyntaxContext) -> SyntaxContext) -> Span {
match_span_kind! {
pub fn map_ctxt(self, map: impl FnOnce(SyntaxContext) -> SyntaxContext) -> Span {
let data = match_span_kind! {
self,
InlineCtxt(span) => {
let updated_ctxt32 = update(SyntaxContext::from_u16(span.ctxt)).as_u32();
// Any small new context including zero will preserve the format.
return if updated_ctxt32 <= MAX_CTXT {
InlineCtxt::span(span.lo, span.len, updated_ctxt32 as u16)
// This format occurs 1-2 orders of magnitude more often than others (#125017),
// so it makes sense to micro-optimize it to avoid `span.data()` and `Span::new()`.
let new_ctxt = map(SyntaxContext::from_u16(span.ctxt));
let new_ctxt32 = new_ctxt.as_u32();
return if new_ctxt32 <= MAX_CTXT {
// Any small new context including zero will preserve the format.
InlineCtxt::span(span.lo, span.len, new_ctxt32 as u16)
} else {
span.data().with_ctxt(SyntaxContext::from_u32(updated_ctxt32))
span.data().with_ctxt(new_ctxt)
};
},
InlineParent(_span) => {},
PartiallyInterned(_span) => {},
Interned(_span) => {},
}
InlineParent(span) => span.data(),
PartiallyInterned(span) => span.data(),
Interned(span) => span.data(),
};
let data = self.data_untracked();
data.with_ctxt(update(data.ctxt))
data.with_ctxt(map(data.ctxt))
}
// Returns either syntactic context, if it can be retrieved without taking the interner lock,
@ -381,6 +380,49 @@ pub fn eq_ctxt(self, other: Span) -> bool {
}),
}
}
#[inline]
pub fn with_parent(self, parent: Option<LocalDefId>) -> Span {
let data = match_span_kind! {
self,
InlineCtxt(span) => {
// This format occurs 1-2 orders of magnitude more often than others (#126544),
// so it makes sense to micro-optimize it to avoid `span.data()` and `Span::new()`.
// Copypaste from `Span::new`, the small len & ctxt conditions are known to hold.
match parent {
None => return self,
Some(parent) => {
let parent32 = parent.local_def_index.as_u32();
if span.ctxt == 0 && parent32 <= MAX_CTXT {
return InlineParent::span(span.lo, span.len, parent32 as u16);
}
}
}
span.data()
},
InlineParent(span) => span.data(),
PartiallyInterned(span) => span.data(),
Interned(span) => span.data(),
};
if let Some(old_parent) = data.parent {
(*SPAN_TRACK)(old_parent);
}
data.with_parent(parent)
}
#[inline]
pub fn parent(self) -> Option<LocalDefId> {
let interned_parent =
|index: u32| with_span_interner(|interner| interner.spans[index as usize].parent);
match_span_kind! {
self,
InlineCtxt(_span) => None,
InlineParent(span) => Some(LocalDefId { local_def_index: DefIndex::from_u16(span.parent) }),
PartiallyInterned(span) => interned_parent(span.index),
Interned(span) => interned_parent(span.index),
}
}
}
#[derive(Default)]