@@ -28,12 +28,17 @@ use rustc_data_structures::fx::FxIndexSet;
2828/// Inline (compressed) format:
2929/// - `span.base_or_index == span_data.lo`
3030/// - `span.len_or_tag == len == span_data.hi - span_data.lo` (must be `<= MAX_LEN`)
31- /// - `span.ctxt == span_data.ctxt` (must be `<= MAX_CTXT`)
31+ /// - `span.ctxt_or_tag == span_data.ctxt` (must be `<= MAX_CTXT`)
32+ ///
33+ /// Interned format with inline `SyntaxContext`:
34+ /// - `span.base_or_index == index` (indexes into the interner table)
35+ /// - `span.len_or_tag == LEN_TAG` (high bit set, all other bits are zero)
36+ /// - `span.ctxt_or_tag == span_data.ctxt` (must be `<= MAX_CTXT`)
3237///
3338/// Interned format:
3439/// - `span.base_or_index == index` (indexes into the interner table)
3540/// - `span.len_or_tag == LEN_TAG` (high bit set, all other bits are zero)
36- /// - `span.ctxt == 0 `
41+ /// - `span.ctxt_or_tag == CTXT_TAG `
3742///
3843/// The inline form uses 0 for the tag value (rather than 1) so that we don't
3944/// need to mask out the tag bit when getting the length, and so that the
@@ -50,10 +55,10 @@ use rustc_data_structures::fx::FxIndexSet;
5055/// at 3 or 4, and then it drops off quickly from 8 onwards. 15 bits is enough
5156/// for 99.99%+ of cases, but larger values (sometimes 20+ bits) might occur
5257/// dozens of times in a typical crate.
53- /// - `ctxt ` is 16 bits in `Span` and 32 bits in `SpanData`, which means that
58+ /// - `ctxt_or_tag ` is 16 bits in `Span` and 32 bits in `SpanData`, which means that
5459/// large `ctxt` values will cause interning. The number of bits needed for
5560/// `ctxt` values depend partly on the crate size and partly on the form of
56- /// the code. No crates in `rustc-perf` need more than 15 bits for `ctxt `,
61+ /// the code. No crates in `rustc-perf` need more than 15 bits for `ctxt_or_tag `,
5762/// but larger crates might need more than 16 bits.
5863///
5964/// In order to reliably use parented spans in incremental compilation,
@@ -65,15 +70,16 @@ use rustc_data_structures::fx::FxIndexSet;
6570pub struct Span {
6671 base_or_index : u32 ,
6772 len_or_tag : u16 ,
68- ctxt_or_zero : u16 ,
73+ ctxt_or_tag : u16 ,
6974}
7075
7176const LEN_TAG : u16 = 0b1000_0000_0000_0000 ;
7277const MAX_LEN : u32 = 0b0111_1111_1111_1111 ;
73- const MAX_CTXT : u32 = 0b1111_1111_1111_1111 ;
78+ const CTXT_TAG : u32 = 0b1111_1111_1111_1111 ;
79+ const MAX_CTXT : u32 = CTXT_TAG - 1 ;
7480
7581/// Dummy span, both position and length are zero, syntax context is zero as well.
76- pub const DUMMY_SP : Span = Span { base_or_index : 0 , len_or_tag : 0 , ctxt_or_zero : 0 } ;
82+ pub const DUMMY_SP : Span = Span { base_or_index : 0 , len_or_tag : 0 , ctxt_or_tag : 0 } ;
7783
7884impl Span {
7985 #[ inline]
@@ -91,12 +97,13 @@ impl Span {
9197
9298 if len <= MAX_LEN && ctxt2 <= MAX_CTXT && parent. is_none ( ) {
9399 // Inline format.
94- Span { base_or_index : base, len_or_tag : len as u16 , ctxt_or_zero : ctxt2 as u16 }
100+ Span { base_or_index : base, len_or_tag : len as u16 , ctxt_or_tag : ctxt2 as u16 }
95101 } else {
96102 // Interned format.
97103 let index =
98104 with_span_interner ( |interner| interner. intern ( & SpanData { lo, hi, ctxt, parent } ) ) ;
99- Span { base_or_index : index, len_or_tag : LEN_TAG , ctxt_or_zero : 0 }
105+ let ctxt_or_tag = if ctxt2 <= MAX_CTXT { ctxt2 } else { CTXT_TAG } as u16 ;
106+ Span { base_or_index : index, len_or_tag : LEN_TAG , ctxt_or_tag }
100107 }
101108 }
102109
@@ -119,16 +126,29 @@ impl Span {
119126 SpanData {
120127 lo : BytePos ( self . base_or_index ) ,
121128 hi : BytePos ( self . base_or_index + self . len_or_tag as u32 ) ,
122- ctxt : SyntaxContext :: from_u32 ( self . ctxt_or_zero as u32 ) ,
129+ ctxt : SyntaxContext :: from_u32 ( self . ctxt_or_tag as u32 ) ,
123130 parent : None ,
124131 }
125132 } else {
126133 // Interned format.
127- debug_assert ! ( self . ctxt_or_zero == 0 ) ;
128134 let index = self . base_or_index ;
129135 with_span_interner ( |interner| interner. spans [ index as usize ] )
130136 }
131137 }
138+
139+ /// This function is used as a fast path when decoding the full `SpanData` is not necessary.
140+ #[ inline]
141+ pub fn ctxt ( self ) -> SyntaxContext {
142+ let ctxt_or_tag = self . ctxt_or_tag as u32 ;
143+ if ctxt_or_tag <= MAX_CTXT {
144+ // Inline format or interned format with inline ctxt.
145+ SyntaxContext :: from_u32 ( ctxt_or_tag)
146+ } else {
147+ // Interned format.
148+ let index = self . base_or_index ;
149+ with_span_interner ( |interner| interner. spans [ index as usize ] . ctxt )
150+ }
151+ }
132152}
133153
134154#[ derive( Default ) ]
0 commit comments