@@ -17,7 +17,6 @@ use rustc_hir::definitions::DefPathData;
17
17
use rustc_hir:: intravisit:: { self , Visitor } ;
18
18
use rustc_hir:: lang_items;
19
19
use rustc_hir:: { AnonConst , GenericParamKind } ;
20
- use rustc_index:: bit_set:: GrowableBitSet ;
21
20
use rustc_middle:: hir:: nested_filter;
22
21
use rustc_middle:: middle:: dependency_format:: Linkage ;
23
22
use rustc_middle:: middle:: exported_symbols:: {
@@ -66,13 +65,10 @@ pub(super) struct EncodeContext<'a, 'tcx> {
66
65
// The indices (into the `SourceMap`'s `MonotonicVec`)
67
66
// of all of the `SourceFiles` that we need to serialize.
68
67
// 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 > > ,
76
72
is_proc_macro : bool ,
77
73
hygiene_ctxt : & ' a HygieneEncodeContext ,
78
74
}
@@ -245,10 +241,6 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Span {
245
241
return TAG_PARTIAL_SPAN . encode ( s) ;
246
242
}
247
243
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
-
252
244
// There are two possible cases here:
253
245
// 1. This span comes from a 'foreign' crate - e.g. some crate upstream of the
254
246
// 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 {
265
257
// if we're a proc-macro crate.
266
258
// This allows us to avoid loading the dependencies of proc-macro crates: all of
267
259
// 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;
287
282
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
+ } ;
292
292
293
293
tag. encode ( s) ;
294
294
lo. encode ( s) ;
@@ -298,6 +298,9 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Span {
298
298
let len = hi - lo;
299
299
len. encode ( s) ;
300
300
301
+ // Encode the index of the `SourceFile` for the span, in order to make decoding faster.
302
+ metadata_index. encode ( s) ;
303
+
301
304
if tag == TAG_VALID_SPAN_FOREIGN {
302
305
// This needs to be two lines to avoid holding the `s.source_file_cache`
303
306
// while calling `cnum.encode(s)`
@@ -460,18 +463,17 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
460
463
461
464
let working_directory = & self . tcx . sess . opts . working_dir ;
462
465
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
464
471
. 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
+
475
477
// At export time we expand all source file paths to absolute paths because
476
478
// downstream compilation sessions can have a different compiler working
477
479
// directory, so relative paths from this or any other upstream crate
@@ -2228,7 +2230,7 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>, path: &Path) {
2228
2230
2229
2231
let source_map_files = tcx. sess . source_map ( ) . files ( ) ;
2230
2232
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 ( ) ) ;
2232
2234
drop ( source_map_files) ;
2233
2235
2234
2236
let hygiene_ctxt = HygieneEncodeContext :: default ( ) ;
0 commit comments