@@ -28,12 +28,17 @@ use rustc_data_structures::fx::FxIndexSet;
28
28
/// Inline (compressed) format:
29
29
/// - `span.base_or_index == span_data.lo`
30
30
/// - `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`)
32
37
///
33
38
/// Interned format:
34
39
/// - `span.base_or_index == index` (indexes into the interner table)
35
40
/// - `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 `
37
42
///
38
43
/// The inline form uses 0 for the tag value (rather than 1) so that we don't
39
44
/// 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;
50
55
/// at 3 or 4, and then it drops off quickly from 8 onwards. 15 bits is enough
51
56
/// for 99.99%+ of cases, but larger values (sometimes 20+ bits) might occur
52
57
/// 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
54
59
/// large `ctxt` values will cause interning. The number of bits needed for
55
60
/// `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 `,
57
62
/// but larger crates might need more than 16 bits.
58
63
///
59
64
/// In order to reliably use parented spans in incremental compilation,
@@ -65,15 +70,16 @@ use rustc_data_structures::fx::FxIndexSet;
65
70
pub struct Span {
66
71
base_or_index : u32 ,
67
72
len_or_tag : u16 ,
68
- ctxt_or_zero : u16 ,
73
+ ctxt_or_tag : u16 ,
69
74
}
70
75
71
76
const LEN_TAG : u16 = 0b1000_0000_0000_0000 ;
72
77
const 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 ;
74
80
75
81
/// 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 } ;
77
83
78
84
impl Span {
79
85
#[ inline]
@@ -91,12 +97,13 @@ impl Span {
91
97
92
98
if len <= MAX_LEN && ctxt2 <= MAX_CTXT && parent. is_none ( ) {
93
99
// 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 }
95
101
} else {
96
102
// Interned format.
97
103
let index =
98
104
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 }
100
107
}
101
108
}
102
109
@@ -119,16 +126,29 @@ impl Span {
119
126
SpanData {
120
127
lo : BytePos ( self . base_or_index ) ,
121
128
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 ) ,
123
130
parent : None ,
124
131
}
125
132
} else {
126
133
// Interned format.
127
- debug_assert ! ( self . ctxt_or_zero == 0 ) ;
128
134
let index = self . base_or_index ;
129
135
with_span_interner ( |interner| interner. spans [ index as usize ] )
130
136
}
131
137
}
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
+ }
132
152
}
133
153
134
154
#[ derive( Default ) ]
0 commit comments