1
1
mod spans;
2
2
3
3
use std:: ffi:: CString ;
4
- use std:: iter ;
4
+ use std:: sync :: Arc ;
5
5
6
6
use itertools:: Itertools as _;
7
7
use rustc_abi:: Align ;
8
8
use rustc_codegen_ssa:: traits:: {
9
9
BaseTypeCodegenMethods , ConstCodegenMethods , StaticCodegenMethods ,
10
10
} ;
11
- use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap , FxIndexSet } ;
11
+ use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap } ;
12
12
use rustc_hir:: def_id:: { DefId , LocalDefId } ;
13
13
use rustc_index:: IndexVec ;
14
14
use rustc_middle:: mir:: coverage:: MappingKind ;
@@ -17,7 +17,7 @@ use rustc_middle::{bug, mir};
17
17
use rustc_session:: RemapFileNameExt ;
18
18
use rustc_session:: config:: RemapPathScopeComponents ;
19
19
use rustc_span:: def_id:: DefIdSet ;
20
- use rustc_span:: { Span , Symbol } ;
20
+ use rustc_span:: { SourceFile , StableSourceFileId } ;
21
21
use rustc_target:: spec:: HasTargetSpec ;
22
22
use tracing:: debug;
23
23
@@ -74,11 +74,11 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
74
74
. map ( |( instance, function_coverage) | ( instance, function_coverage. into_finished ( ) ) )
75
75
. collect :: < Vec < _ > > ( ) ;
76
76
77
- let all_file_names = function_coverage_entries
77
+ let all_files = function_coverage_entries
78
78
. iter ( )
79
79
. map ( |( _, fn_cov) | fn_cov. function_coverage_info . body_span )
80
- . map ( |span| span_file_name ( tcx, span) ) ;
81
- let global_file_table = GlobalFileTable :: new ( all_file_names ) ;
80
+ . map ( |span| tcx. sess . source_map ( ) . lookup_source_file ( span. lo ( ) ) ) ;
81
+ let global_file_table = GlobalFileTable :: new ( all_files ) ;
82
82
83
83
// Encode all filenames referenced by coverage mappings in this CGU.
84
84
let filenames_buffer = global_file_table. make_filenames_buffer ( tcx) ;
@@ -143,54 +143,62 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
143
143
}
144
144
}
145
145
146
- /// Maps "global" (per-CGU) file ID numbers to their underlying filenames .
146
+ /// Maps "global" (per-CGU) file ID numbers to their underlying source files .
147
147
struct GlobalFileTable {
148
- /// This "raw" table doesn't include the working dir, so a filename 's
148
+ /// This "raw" table doesn't include the working dir, so a file 's
149
149
/// global ID is its index in this set **plus one**.
150
- raw_file_table : FxIndexSet < Symbol > ,
150
+ raw_file_table : FxIndexMap < StableSourceFileId , Arc < SourceFile > > ,
151
151
}
152
152
153
153
impl GlobalFileTable {
154
- fn new ( all_file_names : impl IntoIterator < Item = Symbol > ) -> Self {
155
- // Collect all of the filenames into a set. Filenames usually come in
156
- // contiguous runs, so we can dedup adjacent ones to save work.
157
- let mut raw_file_table = all_file_names. into_iter ( ) . dedup ( ) . collect :: < FxIndexSet < Symbol > > ( ) ;
154
+ fn new ( all_files : impl IntoIterator < Item = Arc < SourceFile > > ) -> Self {
155
+ // Collect all of the files into a set. Files usually come in contiguous
156
+ // runs, so we can dedup adjacent ones to save work.
157
+ let mut raw_file_table = all_files
158
+ . into_iter ( )
159
+ . dedup_by ( |a, b| a. stable_id == b. stable_id )
160
+ . map ( |f| ( f. stable_id , f) )
161
+ . collect :: < FxIndexMap < StableSourceFileId , Arc < SourceFile > > > ( ) ;
158
162
159
- // Sort the file table by its actual string values, not the arbitrary
160
- // ordering of its symbols.
161
- raw_file_table. sort_unstable_by ( |a, b| a. as_str ( ) . cmp ( b. as_str ( ) ) ) ;
163
+ // Sort the file table by its underlying filenames.
164
+ raw_file_table. sort_unstable_by ( |_, a, _, b| {
165
+ Ord :: cmp ( & a. name , & b. name ) . then_with ( || Ord :: cmp ( & a. stable_id , & b. stable_id ) )
166
+ } ) ;
162
167
163
168
Self { raw_file_table }
164
169
}
165
170
166
- fn global_file_id_for_file_name ( & self , file_name : Symbol ) -> GlobalFileId {
167
- let raw_id = self . raw_file_table . get_index_of ( & file_name ) . unwrap_or_else ( || {
168
- bug ! ( "file name not found in prepared global file table: {file_name}" ) ;
171
+ fn global_file_id_for_file ( & self , file : & SourceFile ) -> GlobalFileId {
172
+ let raw_id = self . raw_file_table . get_index_of ( & file . stable_id ) . unwrap_or_else ( || {
173
+ bug ! ( "file not found in prepared global file table: {:?}" , file . name ) ;
169
174
} ) ;
170
175
// The raw file table doesn't include an entry for the working dir
171
176
// (which has ID 0), so add 1 to get the correct ID.
172
177
GlobalFileId :: from_usize ( raw_id + 1 )
173
178
}
174
179
175
180
fn make_filenames_buffer ( & self , tcx : TyCtxt < ' _ > ) -> Vec < u8 > {
181
+ let mut table = Vec :: with_capacity ( self . raw_file_table . len ( ) + 1 ) ;
182
+
176
183
// LLVM Coverage Mapping Format version 6 (zero-based encoded as 5)
177
184
// requires setting the first filename to the compilation directory.
178
185
// Since rustc generates coverage maps with relative paths, the
179
186
// compilation directory can be combined with the relative paths
180
187
// to get absolute paths, if needed.
181
- use rustc_session:: RemapFileNameExt ;
182
- use rustc_session:: config:: RemapPathScopeComponents ;
183
- let working_dir: & str = & tcx
184
- . sess
185
- . opts
186
- . working_dir
187
- . for_scope ( tcx. sess , RemapPathScopeComponents :: MACRO )
188
- . to_string_lossy ( ) ;
189
-
190
- // Insert the working dir at index 0, before the other filenames.
191
- let filenames =
192
- iter:: once ( working_dir) . chain ( self . raw_file_table . iter ( ) . map ( Symbol :: as_str) ) ;
193
- llvm_cov:: write_filenames_to_buffer ( filenames)
188
+ table. push (
189
+ tcx. sess
190
+ . opts
191
+ . working_dir
192
+ . for_scope ( tcx. sess , RemapPathScopeComponents :: MACRO )
193
+ . to_string_lossy ( ) ,
194
+ ) ;
195
+
196
+ // Add the regular entries after the base directory.
197
+ table. extend ( self . raw_file_table . values ( ) . map ( |file| {
198
+ file. name . for_scope ( tcx. sess , RemapPathScopeComponents :: MACRO ) . to_string_lossy ( )
199
+ } ) ) ;
200
+
201
+ llvm_cov:: write_filenames_to_buffer ( table. iter ( ) . map ( |f| f. as_ref ( ) ) )
194
202
}
195
203
}
196
204
@@ -229,13 +237,6 @@ impl VirtualFileMapping {
229
237
}
230
238
}
231
239
232
- fn span_file_name ( tcx : TyCtxt < ' _ > , span : Span ) -> Symbol {
233
- let source_file = tcx. sess . source_map ( ) . lookup_source_file ( span. lo ( ) ) ;
234
- let name =
235
- source_file. name . for_scope ( tcx. sess , RemapPathScopeComponents :: MACRO ) . to_string_lossy ( ) ;
236
- Symbol :: intern ( & name)
237
- }
238
-
239
240
/// Using the expressions and counter regions collected for a single function,
240
241
/// generate the variable-sized payload of its corresponding `__llvm_covfun`
241
242
/// entry. The payload is returned as a vector of bytes.
@@ -262,16 +263,14 @@ fn encode_mappings_for_function(
262
263
let mut mcdc_decision_regions = vec ! [ ] ;
263
264
264
265
// Currently a function's mappings must all be in the same file as its body span.
265
- let file_name = span_file_name ( tcx, fn_cov_info. body_span ) ;
266
266
let source_map = tcx. sess . source_map ( ) ;
267
267
let source_file = source_map. lookup_source_file ( fn_cov_info. body_span . lo ( ) ) ;
268
268
269
- // Look up the global file ID for that filename .
270
- let global_file_id = global_file_table. global_file_id_for_file_name ( file_name ) ;
269
+ // Look up the global file ID for that file .
270
+ let global_file_id = global_file_table. global_file_id_for_file ( & source_file ) ;
271
271
272
272
// Associate that global file ID with a local file ID for this function.
273
273
let local_file_id = virtual_file_mapping. local_id_for_global ( global_file_id) ;
274
- debug ! ( " file id: {local_file_id:?} => {global_file_id:?} = '{file_name:?}'" ) ;
275
274
276
275
let make_cov_span = |span| {
277
276
spans:: make_coverage_span ( local_file_id, source_map, fn_cov_info, & source_file, span)
0 commit comments