@@ -17,7 +17,6 @@ use rustc_hir::definitions::DefPathData;
1717use rustc_hir:: intravisit:: { self , Visitor } ;
1818use rustc_hir:: lang_items;
1919use rustc_hir:: { AnonConst , GenericParamKind } ;
20- use rustc_index:: bit_set:: GrowableBitSet ;
2120use rustc_middle:: hir:: nested_filter;
2221use rustc_middle:: middle:: dependency_format:: Linkage ;
2322use rustc_middle:: middle:: exported_symbols:: {
@@ -66,13 +65,10 @@ pub(super) struct EncodeContext<'a, 'tcx> {
6665 // The indices (into the `SourceMap`'s `MonotonicVec`)
6766 // of all of the `SourceFiles` that we need to serialize.
6867 // When we serialize a `Span`, we insert the index of its
69- // `SourceFile` into the `GrowableBitSet`.
70- //
71- // This needs to be a `GrowableBitSet` and not a
72- // regular `BitSet` because we may actually import new `SourceFiles`
73- // during metadata encoding, due to executing a query
74- // with a result containing a foreign `Span`.
75- required_source_files : Option < GrowableBitSet < usize > > ,
68+ // `SourceFile` into the `FxIndexSet`.
69+ // The order inside the `FxIndexSet` is used as on-disk
70+ // order of `SourceFiles`, and encoded inside `Span`s.
71+ required_source_files : Option < FxIndexSet < usize > > ,
7672 is_proc_macro : bool ,
7773 hygiene_ctxt : & ' a HygieneEncodeContext ,
7874}
@@ -245,10 +241,6 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Span {
245241 return TAG_PARTIAL_SPAN . encode ( s) ;
246242 }
247243
248- let source_files = s. required_source_files . as_mut ( ) . expect ( "Already encoded SourceMap!" ) ;
249- // Record the fact that we need to encode the data for this `SourceFile`
250- source_files. insert ( s. source_file_cache . 1 ) ;
251-
252244 // There are two possible cases here:
253245 // 1. This span comes from a 'foreign' crate - e.g. some crate upstream of the
254246 // crate we are writing metadata for. When the metadata for *this* crate gets
@@ -265,30 +257,38 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Span {
265257 // if we're a proc-macro crate.
266258 // This allows us to avoid loading the dependencies of proc-macro crates: all of
267259 // the information we need to decode `Span`s is stored in the proc-macro crate.
268- let ( tag, lo, hi) = if s. source_file_cache . 0 . is_imported ( ) && !s. is_proc_macro {
269- // To simplify deserialization, we 'rebase' this span onto the crate it originally came from
270- // (the crate that 'owns' the file it references. These rebased 'lo' and 'hi' values
271- // are relative to the source map information for the 'foreign' crate whose CrateNum
272- // we write into the metadata. This allows `imported_source_files` to binary
273- // search through the 'foreign' crate's source map information, using the
274- // deserialized 'lo' and 'hi' values directly.
275- //
276- // All of this logic ensures that the final result of deserialization is a 'normal'
277- // Span that can be used without any additional trouble.
278- let external_start_pos = {
279- // Introduce a new scope so that we drop the 'lock()' temporary
280- match & * s. source_file_cache . 0 . external_src . lock ( ) {
281- ExternalSource :: Foreign { original_start_pos, .. } => * original_start_pos,
282- src => panic ! ( "Unexpected external source {:?}" , src) ,
283- }
284- } ;
285- let lo = ( span. lo - s. source_file_cache . 0 . start_pos ) + external_start_pos;
286- let hi = ( span. hi - s. source_file_cache . 0 . start_pos ) + external_start_pos;
260+ let ( tag, lo, hi, metadata_index) =
261+ if s. source_file_cache . 0 . is_imported ( ) && !s. is_proc_macro {
262+ // To simplify deserialization, we 'rebase' this span onto the crate it originally came from
263+ // (the crate that 'owns' the file it references. These rebased 'lo' and 'hi' values
264+ // are relative to the source map information for the 'foreign' crate whose CrateNum
265+ // we write into the metadata. This allows `imported_source_files` to binary
266+ // search through the 'foreign' crate's source map information, using the
267+ // deserialized 'lo' and 'hi' values directly.
268+ //
269+ // All of this logic ensures that the final result of deserialization is a 'normal'
270+ // Span that can be used without any additional trouble.
271+ let ( external_start_pos, metadata_index) = {
272+ // Introduce a new scope so that we drop the 'lock()' temporary
273+ match & * s. source_file_cache . 0 . external_src . lock ( ) {
274+ ExternalSource :: Foreign { original_start_pos, metadata_index, .. } => {
275+ ( * original_start_pos, * metadata_index as usize )
276+ }
277+ src => panic ! ( "Unexpected external source {:?}" , src) ,
278+ }
279+ } ;
280+ let lo = ( span. lo - s. source_file_cache . 0 . start_pos ) + external_start_pos;
281+ let hi = ( span. hi - s. source_file_cache . 0 . start_pos ) + external_start_pos;
287282
288- ( TAG_VALID_SPAN_FOREIGN , lo, hi)
289- } else {
290- ( TAG_VALID_SPAN_LOCAL , span. lo , span. hi )
291- } ;
283+ ( TAG_VALID_SPAN_FOREIGN , lo, hi, metadata_index)
284+ } else {
285+ // Record the fact that we need to encode the data for this `SourceFile`
286+ let source_files =
287+ s. required_source_files . as_mut ( ) . expect ( "Already encoded SourceMap!" ) ;
288+ let ( source_file_index, _) = source_files. insert_full ( s. source_file_cache . 1 ) ;
289+
290+ ( TAG_VALID_SPAN_LOCAL , span. lo , span. hi , source_file_index)
291+ } ;
292292
293293 tag. encode ( s) ;
294294 lo. encode ( s) ;
@@ -298,6 +298,9 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Span {
298298 let len = hi - lo;
299299 len. encode ( s) ;
300300
301+ // Encode the index of the `SourceFile` for the span, in order to make decoding faster.
302+ metadata_index. encode ( s) ;
303+
301304 if tag == TAG_VALID_SPAN_FOREIGN {
302305 // This needs to be two lines to avoid holding the `s.source_file_cache`
303306 // while calling `cnum.encode(s)`
@@ -460,18 +463,17 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
460463
461464 let working_directory = & self . tcx . sess . opts . working_dir ;
462465
463- let adapted = all_source_files
466+ // Only serialize `SourceFile`s that were used during the encoding of a `Span`.
467+ //
468+ // The order in which we encode source files is important here: the on-disk format for
469+ // `Span` contains the index of the corresponding `SourceFile`.
470+ let adapted = required_source_files
464471 . iter ( )
465- . enumerate ( )
466- . filter ( |( idx, source_file) | {
467- // Only serialize `SourceFile`s that were used
468- // during the encoding of a `Span`
469- required_source_files. contains ( * idx) &&
470- // Don't serialize imported `SourceFile`s, unless
471- // we're in a proc-macro crate.
472- ( !source_file. is_imported ( ) || self . is_proc_macro )
473- } )
474- . map ( |( _, source_file) | {
472+ . map ( |& source_file_index| & all_source_files[ source_file_index] )
473+ . map ( |source_file| {
474+ // Don't serialize imported `SourceFile`s, unless we're in a proc-macro crate.
475+ assert ! ( !source_file. is_imported( ) || self . is_proc_macro) ;
476+
475477 // At export time we expand all source file paths to absolute paths because
476478 // downstream compilation sessions can have a different compiler working
477479 // directory, so relative paths from this or any other upstream crate
@@ -2228,7 +2230,7 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>, path: &Path) {
22282230
22292231 let source_map_files = tcx. sess . source_map ( ) . files ( ) ;
22302232 let source_file_cache = ( source_map_files[ 0 ] . clone ( ) , 0 ) ;
2231- let required_source_files = Some ( GrowableBitSet :: with_capacity ( source_map_files . len ( ) ) ) ;
2233+ let required_source_files = Some ( FxIndexSet :: default ( ) ) ;
22322234 drop ( source_map_files) ;
22332235
22342236 let hygiene_ctxt = HygieneEncodeContext :: default ( ) ;
0 commit comments