about summary refs log tree commit diff
path: root/compiler/rustc_span/src/span_encoding.rs
diff options
context:
space:
mode:
authorCamille GILLOT <gillot.camille@gmail.com>2022-10-25 20:52:34 +0000
committerCamille GILLOT <gillot.camille@gmail.com>2022-12-25 16:41:33 +0000
commit6d42636456cc140739b13f787cab5ce550785d94 (patch)
treed8606ee3520acc43124100b22f0078aafabb6cd9 /compiler/rustc_span/src/span_encoding.rs
parentd9ee0f468f8d07e92da94fe991db91e95822d721 (diff)
downloadrust-6d42636456cc140739b13f787cab5ce550785d94.tar.gz
rust-6d42636456cc140739b13f787cab5ce550785d94.zip
Encode span parent in the inlined representation.
Diffstat (limited to 'compiler/rustc_span/src/span_encoding.rs')
-rw-r--r--compiler/rustc_span/src/span_encoding.rs86
1 files changed, 64 insertions, 22 deletions
diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs
index f0e91e5a6a9..d48c4f7e5a8 100644
--- a/compiler/rustc_span/src/span_encoding.rs
+++ b/compiler/rustc_span/src/span_encoding.rs
@@ -4,7 +4,7 @@
 // The encoding format for inline spans were obtained by optimizing over crates in rustc/libstd.
 // See https://internals.rust-lang.org/t/rfc-compiler-refactoring-spans/1357/28
 
-use crate::def_id::LocalDefId;
+use crate::def_id::{DefIndex, LocalDefId};
 use crate::hygiene::SyntaxContext;
 use crate::SPAN_TRACK;
 use crate::{BytePos, SpanData};
@@ -13,8 +13,8 @@ use rustc_data_structures::fx::FxIndexSet;
 
 /// A compressed span.
 ///
-/// Whereas [`SpanData`] is 12 bytes, which is a bit too big to stick everywhere, `Span`
-/// is a form that only takes up 8 bytes, with less space for the length and
+/// Whereas [`SpanData`] is 16 bytes, which is a bit too big to stick everywhere, `Span`
+/// is a form that only takes up 8 bytes, with less space for the length, parent and
 /// context. The vast majority (99.9%+) of `SpanData` instances will fit within
 /// those 8 bytes; any `SpanData` whose fields don't fit into a `Span` are
 /// stored in a separate interner table, and the `Span` will index into that
@@ -25,7 +25,7 @@ use rustc_data_structures::fx::FxIndexSet;
 /// slower because only 80--90% of spans could be stored inline (even less in
 /// very large crates) and so the interner was used a lot more.
 ///
-/// Inline (compressed) format:
+/// Inline (compressed) format with no parent:
 /// - `span.base_or_index == span_data.lo`
 /// - `span.len_or_tag == len == span_data.hi - span_data.lo` (must be `<= MAX_LEN`)
 /// - `span.ctxt_or_tag == span_data.ctxt` (must be `<= MAX_CTXT`)
@@ -35,6 +35,12 @@ use rustc_data_structures::fx::FxIndexSet;
 /// - `span.len_or_tag == LEN_TAG` (high bit set, all other bits are zero)
 /// - `span.ctxt_or_tag == span_data.ctxt` (must be `<= MAX_CTXT`)
 ///
+/// Inline (compressed) format with root context:
+/// - `span.base_or_index == span_data.lo`
+/// - `span.len_or_tag == len == span_data.hi - span_data.lo` (must be `<= MAX_LEN`)
+/// - `span.len_or_tag` has top bit (`PARENT_MASK`) set
+/// - `span.ctxt == span_data.parent` (must be `<= MAX_CTXT`)
+///
 /// Interned format:
 /// - `span.base_or_index == index` (indexes into the interner table)
 /// - `span.len_or_tag == LEN_TAG` (high bit set, all other bits are zero)
@@ -73,7 +79,8 @@ pub struct Span {
     ctxt_or_tag: u16,
 }
 
-const LEN_TAG: u16 = 0b1000_0000_0000_0000;
+const LEN_TAG: u16 = 0b1111_1111_1111_1111;
+const PARENT_MASK: u16 = 0b1000_0000_0000_0000;
 const MAX_LEN: u32 = 0b0111_1111_1111_1111;
 const CTXT_TAG: u32 = 0b1111_1111_1111_1111;
 const MAX_CTXT: u32 = CTXT_TAG - 1;
@@ -95,16 +102,32 @@ impl Span {
 
         let (base, len, ctxt2) = (lo.0, hi.0 - lo.0, ctxt.as_u32());
 
-        if len <= MAX_LEN && ctxt2 <= MAX_CTXT && parent.is_none() {
-            // Inline format.
-            Span { base_or_index: base, len_or_tag: len as u16, ctxt_or_tag: ctxt2 as u16 }
-        } else {
-            // Interned format.
-            let index =
-                with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt, parent }));
-            let ctxt_or_tag = if ctxt2 <= MAX_CTXT { ctxt2 } else { CTXT_TAG } as u16;
-            Span { base_or_index: index, len_or_tag: LEN_TAG, ctxt_or_tag }
+        if len <= MAX_LEN && ctxt2 <= MAX_CTXT {
+            let len_or_tag = len as u16;
+            debug_assert_eq!(len_or_tag & PARENT_MASK, 0);
+
+            if let Some(parent) = parent {
+                // Inline format with parent.
+                let len_or_tag = len_or_tag | PARENT_MASK;
+                let parent2 = parent.local_def_index.as_u32();
+                if ctxt2 == SyntaxContext::root().as_u32() && parent2 <= MAX_CTXT {
+                    return Span { base_or_index: base, len_or_tag, ctxt_or_tag: parent2 as u16 };
+                }
+            } else {
+                // Inline format with ctxt.
+                return Span {
+                    base_or_index: base,
+                    len_or_tag: len as u16,
+                    ctxt_or_tag: ctxt2 as u16,
+                };
+            }
         }
+
+        // Interned format.
+        let index =
+            with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt, parent }));
+        let ctxt_or_tag = if ctxt2 <= MAX_CTXT { ctxt2 } else { CTXT_TAG } as u16;
+        Span { base_or_index: index, len_or_tag: LEN_TAG, ctxt_or_tag }
     }
 
     #[inline]
@@ -122,12 +145,25 @@ impl Span {
     pub fn data_untracked(self) -> SpanData {
         if self.len_or_tag != LEN_TAG {
             // Inline format.
-            debug_assert!(self.len_or_tag as u32 <= MAX_LEN);
-            SpanData {
-                lo: BytePos(self.base_or_index),
-                hi: BytePos(self.base_or_index + self.len_or_tag as u32),
-                ctxt: SyntaxContext::from_u32(self.ctxt_or_tag as u32),
-                parent: None,
+            if self.len_or_tag & PARENT_MASK == 0 {
+                debug_assert!(self.len_or_tag as u32 <= MAX_LEN);
+                SpanData {
+                    lo: BytePos(self.base_or_index),
+                    hi: BytePos(self.base_or_index + self.len_or_tag as u32),
+                    ctxt: SyntaxContext::from_u32(self.ctxt_or_tag as u32),
+                    parent: None,
+                }
+            } else {
+                let len = self.len_or_tag & !PARENT_MASK;
+                debug_assert!(len as u32 <= MAX_LEN);
+                let parent =
+                    LocalDefId { local_def_index: DefIndex::from_u32(self.ctxt_or_tag as u32) };
+                SpanData {
+                    lo: BytePos(self.base_or_index),
+                    hi: BytePos(self.base_or_index + len as u32),
+                    ctxt: SyntaxContext::root(),
+                    parent: Some(parent),
+                }
             }
         } else {
             // Interned format.
@@ -141,8 +177,14 @@ impl Span {
     pub fn ctxt(self) -> SyntaxContext {
         let ctxt_or_tag = self.ctxt_or_tag as u32;
         if ctxt_or_tag <= MAX_CTXT {
-            // Inline format or interned format with inline ctxt.
-            SyntaxContext::from_u32(ctxt_or_tag)
+            if self.len_or_tag == LEN_TAG || self.len_or_tag & PARENT_MASK == 0 {
+                // Inline format or interned format with inline ctxt.
+                SyntaxContext::from_u32(ctxt_or_tag)
+            } else {
+                // Inline format or interned format with inline parent.
+                // We know that the SyntaxContext is root.
+                SyntaxContext::root()
+            }
         } else {
             // Interned format.
             let index = self.base_or_index;