@@ -4,10 +4,10 @@ use crate::SPAN_TRACK;
44use  crate :: { BytePos ,  SpanData } ; 
55
66use  rustc_data_structures:: fx:: FxIndexSet ; 
7- 
87// This code is very hot and uses lots of arithmetic, avoid overflow checks for performance. 
98// See https://github.com/rust-lang/rust/pull/119440#issuecomment-1874255727 
109use  rustc_serialize:: int_overflow:: DebugStrictAdd ; 
10+ use  std:: mem:: transmute; 
1111
1212/// A compressed span. 
1313/// 
@@ -87,6 +87,99 @@ pub struct Span {
8787    ctxt_or_parent_or_marker :  u16 , 
8888} 
8989
90+ // Convenience structures for all span formats. 
91+ #[ derive( Clone ,  Copy ) ]  
92+ struct  InlineCtxt  { 
93+     lo :  u32 , 
94+     len :  u16 , 
95+     ctxt :  u16 , 
96+ } 
97+ #[ derive( Clone ,  Copy ) ]  
98+ struct  InlineParent  { 
99+     lo :  u32 , 
100+     len_with_tag :  u16 , 
101+     parent :  u16 , 
102+ } 
103+ #[ derive( Clone ,  Copy ) ]  
104+ struct  PartiallyInterned  { 
105+     index :  u32 , 
106+     _marker1 :  u16 , 
107+     ctxt :  u16 , 
108+ } 
109+ #[ derive( Clone ,  Copy ) ]  
110+ struct  Interned  { 
111+     index :  u32 , 
112+     _marker1 :  u16 , 
113+     _marker2 :  u16 , 
114+ } 
115+ enum  Fmt < ' a >  { 
116+     InlineCtxt ( & ' a  mut  InlineCtxt ) , 
117+     InlineParent ( & ' a  mut  InlineParent ) , 
118+     PartiallyInterned ( & ' a  mut  PartiallyInterned ) , 
119+     Interned ( & ' a  mut  Interned ) , 
120+ } 
121+ 
122+ impl  InlineCtxt  { 
123+     fn  data ( self )  -> SpanData  { 
124+         let  len = self . len  as  u32 ; 
125+         debug_assert ! ( len <= MAX_LEN ) ; 
126+         SpanData  { 
127+             lo :  BytePos ( self . lo ) , 
128+             hi :  BytePos ( self . lo . debug_strict_add ( len) ) , 
129+             ctxt :  SyntaxContext :: from_u32 ( self . ctxt  as  u32 ) , 
130+             parent :  None , 
131+         } 
132+     } 
133+     fn  to_span ( self )  -> Span  { 
134+         unsafe  {  transmute ( self )  } 
135+     } 
136+ } 
137+ impl  InlineParent  { 
138+     fn  data ( self )  -> SpanData  { 
139+         let  len = ( self . len_with_tag  &  !PARENT_TAG )  as  u32 ; 
140+         debug_assert ! ( len <= MAX_LEN ) ; 
141+         let  parent = LocalDefId  {  local_def_index :  DefIndex :: from_u32 ( self . parent  as  u32 )  } ; 
142+         SpanData  { 
143+             lo :  BytePos ( self . lo ) , 
144+             hi :  BytePos ( self . lo . debug_strict_add ( len) ) , 
145+             ctxt :  SyntaxContext :: root ( ) , 
146+             parent :  Some ( parent) , 
147+         } 
148+     } 
149+     fn  to_span ( self )  -> Span  { 
150+         unsafe  {  transmute ( self )  } 
151+     } 
152+ } 
153+ impl  PartiallyInterned  { 
154+     fn  data ( self )  -> SpanData  { 
155+         SpanData  { 
156+             ctxt :  SyntaxContext :: from_u32 ( self . ctxt  as  u32 ) , 
157+             ..with_span_interner ( |interner| interner. spans [ self . index  as  usize ] ) 
158+         } 
159+     } 
160+     fn  to_span ( self )  -> Span  { 
161+         unsafe  {  transmute ( self )  } 
162+     } 
163+ } 
164+ impl  Interned  { 
165+     fn  data ( self )  -> SpanData  { 
166+         with_span_interner ( |interner| interner. spans [ self . index  as  usize ] ) 
167+     } 
168+     fn  to_span ( self )  -> Span  { 
169+         unsafe  {  transmute ( self )  } 
170+     } 
171+ } 
172+ impl  Fmt < ' _ >  { 
173+     fn  data ( self )  -> SpanData  { 
174+         match  self  { 
175+             Fmt :: InlineCtxt ( span)  => span. data ( ) , 
176+             Fmt :: InlineParent ( span)  => span. data ( ) , 
177+             Fmt :: PartiallyInterned ( span)  => span. data ( ) , 
178+             Fmt :: Interned ( span)  => span. data ( ) , 
179+         } 
180+     } 
181+ } 
182+ 
90183// `MAX_LEN` is chosen so that `PARENT_TAG | MAX_LEN` is distinct from 
91184// `BASE_LEN_INTERNED_MARKER`. (If `MAX_LEN` was 1 higher, this wouldn't be true.) 
92185const  MAX_LEN :  u32  = 0b0111_1111_1111_1110 ; 
@@ -111,42 +204,48 @@ impl Span {
111204            std:: mem:: swap ( & mut  lo,  & mut  hi) ; 
112205        } 
113206
114-         let   ( lo2 ,  len,  ctxt2 )  =  ( lo . 0 ,  hi . 0  - lo . 0 ,  ctxt . as_u32 ( ) ) ; 
115- 
207+         // Small  len may enable one of fully inline formats (or may not). 
208+          let   ( len ,  ctxt32 )  =  ( hi . 0  - lo . 0 ,  ctxt . as_u32 ( ) ) ; 
116209        if  len <= MAX_LEN  { 
117-             if  ctxt2 <= MAX_CTXT  && parent. is_none ( )  { 
118-                 // Inline-context format. 
119-                 return  Span  { 
120-                     lo_or_index :  lo2, 
121-                     len_with_tag_or_marker :  len as  u16 , 
122-                     ctxt_or_parent_or_marker :  ctxt2 as  u16 , 
123-                 } ; 
124-             }  else  if  ctxt2 == SyntaxContext :: root ( ) . as_u32 ( ) 
210+             if  ctxt32 <= MAX_CTXT  && parent. is_none ( )  { 
211+                 return  InlineCtxt  {  lo :  lo. 0 ,  len :  len as  u16 ,  ctxt :  ctxt32 as  u16  } . to_span ( ) ; 
212+             }  else  if  ctxt32 == 0 
125213                && let  Some ( parent)  = parent
126-                 && let  parent2  = parent. local_def_index . as_u32 ( ) 
127-                 && parent2  <= MAX_CTXT 
214+                 && let  parent32  = parent. local_def_index . as_u32 ( ) 
215+                 && parent32  <= MAX_CTXT 
128216            { 
129-                 // Inline-parent format. 
130-                 return  Span  { 
131-                     lo_or_index :  lo2, 
132-                     len_with_tag_or_marker :  PARENT_TAG  | len as  u16 , 
133-                     ctxt_or_parent_or_marker :  parent2 as  u16 , 
134-                 } ; 
217+                 let  len_with_tag = PARENT_TAG  | len as  u16 ; 
218+                 return  InlineParent  {  lo :  lo. 0 ,  len_with_tag,  parent :  parent32 as  u16  } . to_span ( ) ; 
135219            } 
136220        } 
137221
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 
222+         // Otherwise small ctxt may enable the partially inline format. 
223+         let  index = |ctxt| { 
224+             with_span_interner ( |interner| interner. intern ( & SpanData  {  lo,  hi,  ctxt,  parent } ) ) 
145225        } ; 
146-         Span  { 
147-             lo_or_index :  index, 
148-             len_with_tag_or_marker :  BASE_LEN_INTERNED_MARKER , 
149-             ctxt_or_parent_or_marker, 
226+         if  ctxt32 <= MAX_CTXT  { 
227+             let  index = index ( SyntaxContext :: from_u32 ( u32:: MAX ) ) ;  // any value, should never be read 
228+             PartiallyInterned  {  index,  _marker1 :  BASE_LEN_INTERNED_MARKER ,  ctxt :  ctxt32 as  u16  } 
229+                 . to_span ( ) 
230+         }  else  { 
231+             let  index = index ( ctxt) ; 
232+             Interned  {  index,  _marker1 :  BASE_LEN_INTERNED_MARKER ,  _marker2 :  CTXT_INTERNED_MARKER  } 
233+                 . to_span ( ) 
234+         } 
235+     } 
236+ 
237+     #[ inline]  
238+     fn  fmt ( & mut  self )  -> Fmt < ' _ >  { 
239+         if  self . len_with_tag_or_marker  != BASE_LEN_INTERNED_MARKER  { 
240+             if  self . len_with_tag_or_marker  &  PARENT_TAG  == 0  { 
241+                 Fmt :: InlineCtxt ( unsafe  {  transmute ( self )  } ) 
242+             }  else  { 
243+                 Fmt :: InlineParent ( unsafe  {  transmute ( self )  } ) 
244+             } 
245+         }  else  if  self . ctxt_or_parent_or_marker  != CTXT_INTERNED_MARKER  { 
246+             Fmt :: PartiallyInterned ( unsafe  {  transmute ( self )  } ) 
247+         }  else  { 
248+             Fmt :: Interned ( unsafe  {  transmute ( self )  } ) 
150249        } 
151250    } 
152251
@@ -162,39 +261,8 @@ impl Span {
162261    /// Internal function to translate between an encoded span and the expanded representation. 
163262     /// This function must not be used outside the incremental engine. 
164263     #[ inline]  
165-     pub  fn  data_untracked ( self )  -> SpanData  { 
166-         if  self . len_with_tag_or_marker  != BASE_LEN_INTERNED_MARKER  { 
167-             if  self . len_with_tag_or_marker  &  PARENT_TAG  == 0  { 
168-                 // 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-                 } 
177-             }  else  { 
178-                 // 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-                 } 
190-             } 
191-         }  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 ] ) 
197-         } 
264+     pub  fn  data_untracked ( mut  self )  -> SpanData  { 
265+         self . fmt ( ) . data ( ) 
198266    } 
199267
200268    /// Returns `true` if this is a dummy span with any hygienic context. 
@@ -214,26 +282,26 @@ impl Span {
214282        } 
215283    } 
216284
285+     // For optimization we are interested in cases in which the context is inline and the context 
286+     // update doesn't change format. All non-inline or format changing scenarios require accessing 
287+     // interner and can fall back to `Span::new`. 
288+     pub  fn  update_ctxt ( & mut  self ,  update :  impl  FnOnce ( SyntaxContext )  -> SyntaxContext )  { 
289+         // FIXME(#125017): Update ctxt inline without touching interner when possible. 
290+         let  data = self . data ( ) ; 
291+         * self  = data. with_ctxt ( update ( data. ctxt ) ) ; 
292+     } 
293+ 
217294    // Returns either syntactic context, if it can be retrieved without taking the interner lock, 
218295    // or an index into the interner if it cannot. 
219-     fn  inline_ctxt ( self )  -> Result < SyntaxContext ,  usize >  { 
220-         Ok ( if  self . len_with_tag_or_marker  != BASE_LEN_INTERNED_MARKER  { 
221-             if  self . len_with_tag_or_marker  &  PARENT_TAG  == 0  { 
222-                 // Inline-context format. 
223-                 SyntaxContext :: from_u32 ( self . ctxt_or_parent_or_marker  as  u32 ) 
224-             }  else  { 
225-                 // Inline-parent format. We know that the SyntaxContext is root. 
226-                 SyntaxContext :: root ( ) 
296+     fn  inline_ctxt ( mut  self )  -> Result < SyntaxContext ,  usize >  { 
297+         match  self . fmt ( )  { 
298+             Fmt :: InlineCtxt ( InlineCtxt  {  ctxt,  .. } ) 
299+             | Fmt :: PartiallyInterned ( PartiallyInterned  {  ctxt,  .. } )  => { 
300+                 Ok ( SyntaxContext :: from_u32 ( * ctxt as  u32 ) ) 
227301            } 
228-         }  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 ) 
233-         }  else  { 
234-             // Fully-interned format. 
235-             return  Err ( self . lo_or_index  as  usize ) ; 
236-         } ) 
302+             Fmt :: InlineParent ( _)  => Ok ( SyntaxContext :: root ( ) ) , 
303+             Fmt :: Interned ( span)  => Err ( span. index  as  usize ) , 
304+         } 
237305    } 
238306
239307    /// This function is used as a fast path when decoding the full `SpanData` is not necessary. 
0 commit comments