Skip to content

Commit a9c8887

Browse files
committed
Auto merge of #126544 - petrochenkov:upparent, r=cjgillot
rustc_span: Optimize span parent get/set methods Like #125017, but for span parents. r? `@cjgillot`
2 parents 684b355 + 4d3b617 commit a9c8887

File tree

2 files changed

+70
-35
lines changed

2 files changed

+70
-35
lines changed

compiler/rustc_span/src/lib.rs

+2-9
Original file line numberDiff line numberDiff line change
@@ -525,8 +525,9 @@ impl SpanData {
525525
fn with_ctxt(&self, ctxt: SyntaxContext) -> Span {
526526
Span::new(self.lo, self.hi, ctxt, self.parent)
527527
}
528+
/// Avoid if possible, `Span::with_parent` should be preferred.
528529
#[inline]
529-
pub fn with_parent(&self, parent: Option<LocalDefId>) -> Span {
530+
fn with_parent(&self, parent: Option<LocalDefId>) -> Span {
530531
Span::new(self.lo, self.hi, self.ctxt, parent)
531532
}
532533
/// Returns `true` if this is a dummy span with any hygienic context.
@@ -580,14 +581,6 @@ impl Span {
580581
pub fn with_ctxt(self, ctxt: SyntaxContext) -> Span {
581582
self.map_ctxt(|_| ctxt)
582583
}
583-
#[inline]
584-
pub fn parent(self) -> Option<LocalDefId> {
585-
self.data().parent
586-
}
587-
#[inline]
588-
pub fn with_parent(self, ctxt: Option<LocalDefId>) -> Span {
589-
self.data().with_parent(ctxt)
590-
}
591584

592585
#[inline]
593586
pub fn is_visible(self, sm: &SourceMap) -> bool {

compiler/rustc_span/src/span_encoding.rs

+68-26
Original file line numberDiff line numberDiff line change
@@ -257,17 +257,17 @@ impl Span {
257257
std::mem::swap(&mut lo, &mut hi);
258258
}
259259

260-
// Small len may enable one of fully inline formats (or may not).
260+
// Small len and ctxt may enable one of fully inline formats (or may not).
261261
let (len, ctxt32) = (hi.0 - lo.0, ctxt.as_u32());
262-
if len <= MAX_LEN {
263-
if ctxt32 <= MAX_CTXT && parent.is_none() {
264-
return InlineCtxt::span(lo.0, len as u16, ctxt32 as u16);
265-
} else if ctxt32 == 0
266-
&& let Some(parent) = parent
267-
&& let parent32 = parent.local_def_index.as_u32()
268-
&& parent32 <= MAX_CTXT
269-
{
270-
return InlineParent::span(lo.0, len as u16, parent32 as u16);
262+
if len <= MAX_LEN && ctxt32 <= MAX_CTXT {
263+
match parent {
264+
None => return InlineCtxt::span(lo.0, len as u16, ctxt32 as u16),
265+
Some(parent) => {
266+
let parent32 = parent.local_def_index.as_u32();
267+
if ctxt32 == 0 && parent32 <= MAX_CTXT {
268+
return InlineParent::span(lo.0, len as u16, parent32 as u16);
269+
}
270+
}
271271
}
272272
}
273273

@@ -322,29 +322,28 @@ impl Span {
322322
}
323323
}
324324

325-
// For optimization we are interested in cases in which the context is inline and the context
326-
// update doesn't change format. All non-inline or format changing scenarios require accessing
327-
// interner and can fall back to `Span::new`.
328325
#[inline]
329-
pub fn map_ctxt(self, update: impl FnOnce(SyntaxContext) -> SyntaxContext) -> Span {
330-
match_span_kind! {
326+
pub fn map_ctxt(self, map: impl FnOnce(SyntaxContext) -> SyntaxContext) -> Span {
327+
let data = match_span_kind! {
331328
self,
332329
InlineCtxt(span) => {
333-
let updated_ctxt32 = update(SyntaxContext::from_u16(span.ctxt)).as_u32();
334-
// Any small new context including zero will preserve the format.
335-
return if updated_ctxt32 <= MAX_CTXT {
336-
InlineCtxt::span(span.lo, span.len, updated_ctxt32 as u16)
330+
// This format occurs 1-2 orders of magnitude more often than others (#125017),
331+
// so it makes sense to micro-optimize it to avoid `span.data()` and `Span::new()`.
332+
let new_ctxt = map(SyntaxContext::from_u16(span.ctxt));
333+
let new_ctxt32 = new_ctxt.as_u32();
334+
return if new_ctxt32 <= MAX_CTXT {
335+
// Any small new context including zero will preserve the format.
336+
InlineCtxt::span(span.lo, span.len, new_ctxt32 as u16)
337337
} else {
338-
span.data().with_ctxt(SyntaxContext::from_u32(updated_ctxt32))
338+
span.data().with_ctxt(new_ctxt)
339339
};
340340
},
341-
InlineParent(_span) => {},
342-
PartiallyInterned(_span) => {},
343-
Interned(_span) => {},
344-
}
341+
InlineParent(span) => span.data(),
342+
PartiallyInterned(span) => span.data(),
343+
Interned(span) => span.data(),
344+
};
345345

346-
let data = self.data_untracked();
347-
data.with_ctxt(update(data.ctxt))
346+
data.with_ctxt(map(data.ctxt))
348347
}
349348

350349
// Returns either syntactic context, if it can be retrieved without taking the interner lock,
@@ -381,6 +380,49 @@ impl Span {
381380
}),
382381
}
383382
}
383+
384+
#[inline]
385+
pub fn with_parent(self, parent: Option<LocalDefId>) -> Span {
386+
let data = match_span_kind! {
387+
self,
388+
InlineCtxt(span) => {
389+
// This format occurs 1-2 orders of magnitude more often than others (#126544),
390+
// so it makes sense to micro-optimize it to avoid `span.data()` and `Span::new()`.
391+
// Copypaste from `Span::new`, the small len & ctxt conditions are known to hold.
392+
match parent {
393+
None => return self,
394+
Some(parent) => {
395+
let parent32 = parent.local_def_index.as_u32();
396+
if span.ctxt == 0 && parent32 <= MAX_CTXT {
397+
return InlineParent::span(span.lo, span.len, parent32 as u16);
398+
}
399+
}
400+
}
401+
span.data()
402+
},
403+
InlineParent(span) => span.data(),
404+
PartiallyInterned(span) => span.data(),
405+
Interned(span) => span.data(),
406+
};
407+
408+
if let Some(old_parent) = data.parent {
409+
(*SPAN_TRACK)(old_parent);
410+
}
411+
data.with_parent(parent)
412+
}
413+
414+
#[inline]
415+
pub fn parent(self) -> Option<LocalDefId> {
416+
let interned_parent =
417+
|index: u32| with_span_interner(|interner| interner.spans[index as usize].parent);
418+
match_span_kind! {
419+
self,
420+
InlineCtxt(_span) => None,
421+
InlineParent(span) => Some(LocalDefId { local_def_index: DefIndex::from_u16(span.parent) }),
422+
PartiallyInterned(span) => interned_parent(span.index),
423+
Interned(span) => interned_parent(span.index),
424+
}
425+
}
384426
}
385427

386428
#[derive(Default)]

0 commit comments

Comments
 (0)