Skip to content

rustc_span: Optimize span parent get/set methods #126544

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 2 additions & 9 deletions compiler/rustc_span/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -525,8 +525,9 @@ impl SpanData {
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.
Expand Down Expand Up @@ -580,14 +581,6 @@ impl 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 {
Expand Down
94 changes: 68 additions & 26 deletions compiler/rustc_span/src/span_encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,17 +257,17 @@ impl Span {
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);
}
}
}
}

Expand Down Expand Up @@ -322,29 +322,28 @@ impl Span {
}
}

// 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,
Expand Down Expand Up @@ -381,6 +380,49 @@ impl Span {
}),
}
}

#[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)]
Expand Down
Loading