@@ -87,6 +87,45 @@ pub struct Span {
8787 ctxt_or_parent_or_marker : u16 ,
8888}
8989
90+ impl Span {
91+ #[ inline]
92+ fn data_inline_ctxt ( self ) -> SpanData {
93+ let len = self . len_with_tag_or_marker as u32 ;
94+ debug_assert ! ( len <= MAX_LEN ) ;
95+ SpanData {
96+ lo : BytePos ( self . lo_or_index ) ,
97+ hi : BytePos ( self . lo_or_index . debug_strict_add ( len) ) ,
98+ ctxt : SyntaxContext :: from_u32 ( self . ctxt_or_parent_or_marker as u32 ) ,
99+ parent : None ,
100+ }
101+ }
102+ #[ inline]
103+ fn data_inline_parent ( self ) -> SpanData {
104+ let len = ( self . len_with_tag_or_marker & !PARENT_TAG ) as u32 ;
105+ debug_assert ! ( len <= MAX_LEN ) ;
106+ let parent = LocalDefId {
107+ local_def_index : DefIndex :: from_u32 ( self . ctxt_or_parent_or_marker as u32 ) ,
108+ } ;
109+ SpanData {
110+ lo : BytePos ( self . lo_or_index ) ,
111+ hi : BytePos ( self . lo_or_index . debug_strict_add ( len) ) ,
112+ ctxt : SyntaxContext :: root ( ) ,
113+ parent : Some ( parent) ,
114+ }
115+ }
116+ #[ inline]
117+ fn data_partially_interned ( self ) -> SpanData {
118+ SpanData {
119+ ctxt : SyntaxContext :: from_u32 ( self . ctxt_or_parent_or_marker as u32 ) ,
120+ ..with_span_interner ( |interner| interner. spans [ self . lo_or_index as usize ] )
121+ }
122+ }
123+ #[ inline]
124+ fn data_interned ( self ) -> SpanData {
125+ with_span_interner ( |interner| interner. spans [ self . lo_or_index as usize ] )
126+ }
127+ }
128+
90129// `MAX_LEN` is chosen so that `PARENT_TAG | MAX_LEN` is distinct from
91130// `BASE_LEN_INTERNED_MARKER`. (If `MAX_LEN` was 1 higher, this wouldn't be true.)
92131const MAX_LEN : u32 = 0b0111_1111_1111_1110 ;
@@ -111,42 +150,49 @@ impl Span {
111150 std:: mem:: swap ( & mut lo, & mut hi) ;
112151 }
113152
114- let ( lo2 , len, ctxt2 ) = ( lo . 0 , hi . 0 - lo . 0 , ctxt . as_u32 ( ) ) ;
115-
153+ // Small len may enable one of fully inline formats (or may not).
154+ let ( len , ctxt32 ) = ( hi . 0 - lo . 0 , ctxt . as_u32 ( ) ) ;
116155 if len <= MAX_LEN {
117- if ctxt2 <= MAX_CTXT && parent. is_none ( ) {
156+ if ctxt32 <= MAX_CTXT && parent. is_none ( ) {
118157 // Inline-context format.
119158 return Span {
120- lo_or_index : lo2 ,
159+ lo_or_index : lo . 0 ,
121160 len_with_tag_or_marker : len as u16 ,
122- ctxt_or_parent_or_marker : ctxt2 as u16 ,
161+ ctxt_or_parent_or_marker : ctxt32 as u16 ,
123162 } ;
124- } else if ctxt2 == SyntaxContext :: root ( ) . as_u32 ( )
163+ } else if ctxt32 == 0
125164 && let Some ( parent) = parent
126- && let parent2 = parent. local_def_index . as_u32 ( )
127- && parent2 <= MAX_CTXT
165+ && let parent32 = parent. local_def_index . as_u32 ( )
166+ && parent32 <= MAX_CTXT
128167 {
129168 // Inline-parent format.
130169 return Span {
131- lo_or_index : lo2 ,
170+ lo_or_index : lo . 0 ,
132171 len_with_tag_or_marker : PARENT_TAG | len as u16 ,
133- ctxt_or_parent_or_marker : parent2 as u16 ,
172+ ctxt_or_parent_or_marker : parent32 as u16 ,
134173 } ;
135174 }
136175 }
137176
138- // Partially-interned or fully-interned format.
139- let index =
140- with_span_interner ( |interner| interner. intern ( & SpanData { lo, hi, ctxt, parent } ) ) ;
141- let ctxt_or_parent_or_marker = if ctxt2 <= MAX_CTXT {
142- ctxt2 as u16 // partially-interned
143- } else {
144- CTXT_INTERNED_MARKER // fully-interned
177+ // Otherwise small ctxt may enable the partially inline format.
178+ let index = |ctxt| {
179+ with_span_interner ( |interner| interner. intern ( & SpanData { lo, hi, ctxt, parent } ) )
145180 } ;
146- Span {
147- lo_or_index : index,
148- len_with_tag_or_marker : BASE_LEN_INTERNED_MARKER ,
149- ctxt_or_parent_or_marker,
181+ if ctxt32 <= MAX_CTXT {
182+ // Partially-interned format.
183+ Span {
184+ // Any value, should never be read.
185+ lo_or_index : index ( SyntaxContext :: from_u32 ( u32:: MAX ) ) ,
186+ len_with_tag_or_marker : BASE_LEN_INTERNED_MARKER ,
187+ ctxt_or_parent_or_marker : ctxt32 as u16 ,
188+ }
189+ } else {
190+ // Interned format.
191+ Span {
192+ lo_or_index : index ( ctxt) ,
193+ len_with_tag_or_marker : BASE_LEN_INTERNED_MARKER ,
194+ ctxt_or_parent_or_marker : CTXT_INTERNED_MARKER ,
195+ }
150196 }
151197 }
152198
@@ -166,34 +212,17 @@ impl Span {
166212 if self . len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
167213 if self . len_with_tag_or_marker & PARENT_TAG == 0 {
168214 // Inline-context format.
169- let len = self . len_with_tag_or_marker as u32 ;
170- debug_assert ! ( len <= MAX_LEN ) ;
171- SpanData {
172- lo : BytePos ( self . lo_or_index ) ,
173- hi : BytePos ( self . lo_or_index . debug_strict_add ( len) ) ,
174- ctxt : SyntaxContext :: from_u32 ( self . ctxt_or_parent_or_marker as u32 ) ,
175- parent : None ,
176- }
215+ self . data_inline_ctxt ( )
177216 } else {
178217 // Inline-parent format.
179- let len = ( self . len_with_tag_or_marker & !PARENT_TAG ) as u32 ;
180- debug_assert ! ( len <= MAX_LEN ) ;
181- let parent = LocalDefId {
182- local_def_index : DefIndex :: from_u32 ( self . ctxt_or_parent_or_marker as u32 ) ,
183- } ;
184- SpanData {
185- lo : BytePos ( self . lo_or_index ) ,
186- hi : BytePos ( self . lo_or_index . debug_strict_add ( len) ) ,
187- ctxt : SyntaxContext :: root ( ) ,
188- parent : Some ( parent) ,
189- }
218+ self . data_inline_parent ( )
190219 }
220+ } else if self . ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER {
221+ // Partially-interned format.
222+ self . data_partially_interned ( )
191223 } else {
192- // Fully-interned or partially-interned format. In either case,
193- // the interned value contains all the data, so we don't need to
194- // distinguish them.
195- let index = self . lo_or_index ;
196- with_span_interner ( |interner| interner. spans [ index as usize ] )
224+ // Interned format.
225+ self . data_interned ( )
197226 }
198227 }
199228
@@ -214,26 +243,71 @@ impl Span {
214243 }
215244 }
216245
246+ // For optimization we are interested in cases in which the context is inline and the context
247+ // update doesn't change format. All non-inline or format changing scenarios require accessing
248+ // interner and can fall back to `Span::new`.
249+ #[ inline]
250+ pub fn update_ctxt ( & mut self , update : impl FnOnce ( SyntaxContext ) -> SyntaxContext ) {
251+ let ( updated_ctxt32, data) ;
252+ if self . len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
253+ if self . len_with_tag_or_marker & PARENT_TAG == 0 {
254+ // Inline-context format.
255+ updated_ctxt32 =
256+ update ( SyntaxContext :: from_u32 ( self . ctxt_or_parent_or_marker as u32 ) ) . as_u32 ( ) ;
257+ // Any small new context including zero will preserve the format.
258+ if updated_ctxt32 <= MAX_CTXT {
259+ self . ctxt_or_parent_or_marker = updated_ctxt32 as u16 ;
260+ return ;
261+ }
262+ data = self . data_inline_ctxt ( ) ;
263+ } else {
264+ // Inline-parent format.
265+ updated_ctxt32 = update ( SyntaxContext :: root ( ) ) . as_u32 ( ) ;
266+ // Only if the new context is zero the format will be preserved.
267+ if updated_ctxt32 == 0 {
268+ // Do nothing.
269+ return ;
270+ }
271+ data = self . data_inline_parent ( ) ;
272+ }
273+ } else if self . ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER {
274+ // Partially-interned format.
275+ updated_ctxt32 =
276+ update ( SyntaxContext :: from_u32 ( self . ctxt_or_parent_or_marker as u32 ) ) . as_u32 ( ) ;
277+ // Any small new context excluding zero will preserve the format.
278+ // Zero may change the format to `InlineParent` if parent and len are small enough.
279+ if updated_ctxt32 <= MAX_CTXT && updated_ctxt32 != 0 {
280+ self . ctxt_or_parent_or_marker = updated_ctxt32 as u16 ;
281+ return ;
282+ }
283+ data = self . data_partially_interned ( ) ;
284+ } else {
285+ // Interned format.
286+ data = self . data_interned ( ) ;
287+ updated_ctxt32 = update ( data. ctxt ) . as_u32 ( ) ;
288+ }
289+
290+ * self = data. with_ctxt ( SyntaxContext :: from_u32 ( updated_ctxt32) ) ;
291+ }
292+
217293 // Returns either syntactic context, if it can be retrieved without taking the interner lock,
218294 // or an index into the interner if it cannot.
219295 fn inline_ctxt ( self ) -> Result < SyntaxContext , usize > {
220- Ok ( if self . len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
296+ if self . len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
221297 if self . len_with_tag_or_marker & PARENT_TAG == 0 {
222298 // Inline-context format.
223- SyntaxContext :: from_u32 ( self . ctxt_or_parent_or_marker as u32 )
299+ Ok ( SyntaxContext :: from_u32 ( self . ctxt_or_parent_or_marker as u32 ) )
224300 } else {
225- // Inline-parent format. We know that the SyntaxContext is root.
226- SyntaxContext :: root ( )
301+ // Inline-parent format.
302+ Ok ( SyntaxContext :: root ( ) )
227303 }
228304 } else if self . ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER {
229- // Partially-interned format. This path avoids looking up the
230- // interned value, and is the whole point of the
231- // partially-interned format.
232- SyntaxContext :: from_u32 ( self . ctxt_or_parent_or_marker as u32 )
305+ // Partially-interned format.
306+ Ok ( SyntaxContext :: from_u32 ( self . ctxt_or_parent_or_marker as u32 ) )
233307 } else {
234- // Fully-interned format.
235- return Err ( self . lo_or_index as usize ) ;
236- } )
308+ // Interned format.
309+ Err ( self . lo_or_index as usize )
310+ }
237311 }
238312
239313 /// This function is used as a fast path when decoding the full `SpanData` is not necessary.
0 commit comments