@@ -4,6 +4,7 @@ use crate::coverageinfo::ffi::CounterMappingRegion;
4
4
use crate :: coverageinfo:: map_data:: { FunctionCoverage , FunctionCoverageCollector } ;
5
5
use crate :: llvm;
6
6
7
+ use itertools:: Itertools as _;
7
8
use rustc_codegen_ssa:: traits:: { BaseTypeMethods , ConstMethods } ;
8
9
use rustc_data_structures:: fx:: FxIndexSet ;
9
10
use rustc_hir:: def:: DefKind ;
@@ -57,20 +58,26 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
57
58
return ;
58
59
}
59
60
60
- let mut global_file_table = GlobalFileTable :: new ( tcx) ;
61
+ let function_coverage_entries = function_coverage_map
62
+ . into_iter ( )
63
+ . map ( |( instance, function_coverage) | ( instance, function_coverage. into_finished ( ) ) )
64
+ . collect :: < Vec < _ > > ( ) ;
65
+
66
+ let all_file_names =
67
+ function_coverage_entries. iter ( ) . flat_map ( |( _, fn_cov) | fn_cov. all_file_names ( ) ) ;
68
+ let global_file_table = GlobalFileTable :: new ( all_file_names) ;
61
69
62
70
// Encode coverage mappings and generate function records
63
71
let mut function_data = Vec :: new ( ) ;
64
- for ( instance, function_coverage) in function_coverage_map {
65
- let function_coverage = function_coverage. into_finished ( ) ;
72
+ for ( instance, function_coverage) in function_coverage_entries {
66
73
debug ! ( "Generate function coverage for {}, {:?}" , cx. codegen_unit. name( ) , instance) ;
67
74
68
75
let mangled_function_name = tcx. symbol_name ( instance) . name ;
69
76
let source_hash = function_coverage. source_hash ( ) ;
70
77
let is_used = function_coverage. is_used ( ) ;
71
78
72
79
let coverage_mapping_buffer =
73
- encode_mappings_for_function ( & mut global_file_table, & function_coverage) ;
80
+ encode_mappings_for_function ( & global_file_table, & function_coverage) ;
74
81
75
82
if coverage_mapping_buffer. is_empty ( ) {
76
83
if function_coverage. is_used ( ) {
@@ -88,7 +95,7 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
88
95
}
89
96
90
97
// Encode all filenames referenced by counters/expressions in this module
91
- let filenames_buffer = global_file_table. into_filenames_buffer ( ) ;
98
+ let filenames_buffer = global_file_table. make_filenames_buffer ( tcx ) ;
92
99
93
100
let filenames_size = filenames_buffer. len ( ) ;
94
101
let filenames_val = cx. const_bytes ( & filenames_buffer) ;
@@ -139,37 +146,48 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
139
146
coverageinfo:: save_cov_data_to_mod ( cx, cov_data_val) ;
140
147
}
141
148
149
+ /// Maps "global" (per-CGU) file ID numbers to their underlying filenames.
142
150
struct GlobalFileTable {
143
- global_file_table : FxIndexSet < Symbol > ,
151
+ /// This "raw" table doesn't include the working dir, so a filename's
152
+ /// global ID is its index in this set **plus one**.
153
+ raw_file_table : FxIndexSet < Symbol > ,
144
154
}
145
155
146
156
impl GlobalFileTable {
147
- fn new ( tcx : TyCtxt < ' _ > ) -> Self {
148
- let mut global_file_table = FxIndexSet :: default ( ) ;
157
+ fn new ( all_file_names : impl IntoIterator < Item = Symbol > ) -> Self {
158
+ // Collect all of the filenames into a set. Filenames usually come in
159
+ // contiguous runs, so we can dedup adjacent ones to save work.
160
+ let mut raw_file_table = all_file_names. into_iter ( ) . dedup ( ) . collect :: < FxIndexSet < Symbol > > ( ) ;
161
+
162
+ // Sort the file table by its actual string values, not the arbitrary
163
+ // ordering of its symbols.
164
+ raw_file_table. sort_unstable_by ( |a, b| a. as_str ( ) . cmp ( b. as_str ( ) ) ) ;
165
+
166
+ Self { raw_file_table }
167
+ }
168
+
169
+ fn global_file_id_for_file_name ( & self , file_name : Symbol ) -> u32 {
170
+ let raw_id = self . raw_file_table . get_index_of ( & file_name) . unwrap_or_else ( || {
171
+ bug ! ( "file name not found in prepared global file table: {file_name}" ) ;
172
+ } ) ;
173
+ // The raw file table doesn't include an entry for the working dir
174
+ // (which has ID 0), so add 1 to get the correct ID.
175
+ ( raw_id + 1 ) as u32
176
+ }
177
+
178
+ fn make_filenames_buffer ( & self , tcx : TyCtxt < ' _ > ) -> Vec < u8 > {
149
179
// LLVM Coverage Mapping Format version 6 (zero-based encoded as 5)
150
180
// requires setting the first filename to the compilation directory.
151
181
// Since rustc generates coverage maps with relative paths, the
152
182
// compilation directory can be combined with the relative paths
153
183
// to get absolute paths, if needed.
154
184
use rustc_session:: RemapFileNameExt ;
155
- let working_dir =
156
- Symbol :: intern ( & tcx. sess . opts . working_dir . for_codegen ( & tcx. sess ) . to_string_lossy ( ) ) ;
157
- global_file_table. insert ( working_dir) ;
158
- Self { global_file_table }
159
- }
160
-
161
- fn global_file_id_for_file_name ( & mut self , file_name : Symbol ) -> u32 {
162
- let ( global_file_id, _) = self . global_file_table . insert_full ( file_name) ;
163
- global_file_id as u32
164
- }
165
-
166
- fn into_filenames_buffer ( self ) -> Vec < u8 > {
167
- // This method takes `self` so that the caller can't accidentally
168
- // modify the original file table after encoding it into a buffer.
185
+ let working_dir: & str = & tcx. sess . opts . working_dir . for_codegen ( & tcx. sess ) . to_string_lossy ( ) ;
169
186
170
187
llvm:: build_byte_buffer ( |buffer| {
171
188
coverageinfo:: write_filenames_section_to_buffer (
172
- self . global_file_table . iter ( ) . map ( Symbol :: as_str) ,
189
+ // Insert the working dir at index 0, before the other filenames.
190
+ std:: iter:: once ( working_dir) . chain ( self . raw_file_table . iter ( ) . map ( Symbol :: as_str) ) ,
173
191
buffer,
174
192
) ;
175
193
} )
@@ -182,7 +200,7 @@ impl GlobalFileTable {
182
200
///
183
201
/// Newly-encountered filenames will be added to the global file table.
184
202
fn encode_mappings_for_function (
185
- global_file_table : & mut GlobalFileTable ,
203
+ global_file_table : & GlobalFileTable ,
186
204
function_coverage : & FunctionCoverage < ' _ > ,
187
205
) -> Vec < u8 > {
188
206
let mut counter_regions = function_coverage. counter_regions ( ) . collect :: < Vec < _ > > ( ) ;
@@ -203,7 +221,7 @@ fn encode_mappings_for_function(
203
221
for counter_regions_for_file in
204
222
counter_regions. group_by ( |( _, a) , ( _, b) | a. file_name == b. file_name )
205
223
{
206
- // Look up (or allocate) the global file ID for this filename.
224
+ // Look up the global file ID for this filename.
207
225
let file_name = counter_regions_for_file[ 0 ] . 1 . file_name ;
208
226
let global_file_id = global_file_table. global_file_id_for_file_name ( file_name) ;
209
227
0 commit comments