@@ -55,7 +55,7 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
55
55
return ;
56
56
}
57
57
58
- let mut mapgen = CoverageMapGenerator :: new ( tcx) ;
58
+ let mut global_file_table = GlobalFileTable :: new ( tcx) ;
59
59
60
60
// Encode coverage mappings and generate function records
61
61
let mut function_data = Vec :: new ( ) ;
@@ -68,7 +68,12 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
68
68
function_coverage. get_expressions_and_counter_regions ( ) ;
69
69
70
70
let coverage_mapping_buffer = llvm:: build_byte_buffer ( |coverage_mapping_buffer| {
71
- mapgen. write_coverage_mapping ( expressions, counter_regions, coverage_mapping_buffer) ;
71
+ write_coverage_mapping (
72
+ & mut global_file_table,
73
+ expressions,
74
+ counter_regions,
75
+ coverage_mapping_buffer,
76
+ ) ;
72
77
} ) ;
73
78
74
79
if coverage_mapping_buffer. is_empty ( ) {
@@ -87,19 +92,14 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
87
92
}
88
93
89
94
// Encode all filenames referenced by counters/expressions in this module
90
- let filenames_buffer = llvm:: build_byte_buffer ( |filenames_buffer| {
91
- coverageinfo:: write_filenames_section_to_buffer (
92
- mapgen. filenames . iter ( ) . map ( Symbol :: as_str) ,
93
- filenames_buffer,
94
- ) ;
95
- } ) ;
95
+ let filenames_buffer = global_file_table. into_filenames_buffer ( ) ;
96
96
97
97
let filenames_size = filenames_buffer. len ( ) ;
98
98
let filenames_val = cx. const_bytes ( & filenames_buffer) ;
99
99
let filenames_ref = coverageinfo:: hash_bytes ( & filenames_buffer) ;
100
100
101
101
// Generate the LLVM IR representation of the coverage map and store it in a well-known global
102
- let cov_data_val = mapgen . generate_coverage_map ( cx, version, filenames_size, filenames_val) ;
102
+ let cov_data_val = generate_coverage_map ( cx, version, filenames_size, filenames_val) ;
103
103
104
104
let covfun_section_name = coverageinfo:: covfun_section_name ( cx) ;
105
105
for ( mangled_function_name, source_hash, is_used, coverage_mapping_buffer) in function_data {
@@ -118,13 +118,13 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
118
118
coverageinfo:: save_cov_data_to_mod ( cx, cov_data_val) ;
119
119
}
120
120
121
- struct CoverageMapGenerator {
122
- filenames : FxIndexSet < Symbol > ,
121
+ struct GlobalFileTable {
122
+ global_file_table : FxIndexSet < Symbol > ,
123
123
}
124
124
125
- impl CoverageMapGenerator {
125
+ impl GlobalFileTable {
126
126
fn new ( tcx : TyCtxt < ' _ > ) -> Self {
127
- let mut filenames = FxIndexSet :: default ( ) ;
127
+ let mut global_file_table = FxIndexSet :: default ( ) ;
128
128
// LLVM Coverage Mapping Format version 6 (zero-based encoded as 5)
129
129
// requires setting the first filename to the compilation directory.
130
130
// Since rustc generates coverage maps with relative paths, the
@@ -133,48 +133,67 @@ impl CoverageMapGenerator {
133
133
let working_dir = Symbol :: intern (
134
134
& tcx. sess . opts . working_dir . remapped_path_if_available ( ) . to_string_lossy ( ) ,
135
135
) ;
136
- filenames . insert ( working_dir) ;
137
- Self { filenames }
136
+ global_file_table . insert ( working_dir) ;
137
+ Self { global_file_table }
138
138
}
139
139
140
- /// Using the `expressions` and `counter_regions` collected for the current function, generate
141
- /// the `mapping_regions` and `virtual_file_mapping`, and capture any new filenames. Then use
142
- /// LLVM APIs to encode the `virtual_file_mapping`, `expressions`, and `mapping_regions` into
143
- /// the given `coverage_mapping` byte buffer, compliant with the LLVM Coverage Mapping format.
144
- fn write_coverage_mapping < ' a > (
145
- & mut self ,
146
- expressions : Vec < CounterExpression > ,
147
- counter_regions : impl Iterator < Item = ( Counter , & ' a CodeRegion ) > ,
148
- coverage_mapping_buffer : & RustString ,
149
- ) {
150
- let mut counter_regions = counter_regions. collect :: < Vec < _ > > ( ) ;
151
- if counter_regions. is_empty ( ) {
152
- return ;
153
- }
140
+ fn global_file_id_for_file_name ( & mut self , file_name : Symbol ) -> u32 {
141
+ let ( global_file_id, _) = self . global_file_table . insert_full ( file_name) ;
142
+ global_file_id as u32
143
+ }
144
+
145
+ fn into_filenames_buffer ( self ) -> Vec < u8 > {
146
+ // This method takes `self` so that the caller can't accidentally
147
+ // modify the original file table after encoding it into a buffer.
148
+
149
+ llvm:: build_byte_buffer ( |buffer| {
150
+ coverageinfo:: write_filenames_section_to_buffer (
151
+ self . global_file_table . iter ( ) . map ( Symbol :: as_str) ,
152
+ buffer,
153
+ ) ;
154
+ } )
155
+ }
156
+ }
157
+
158
+ /// Using the `expressions` and `counter_regions` collected for the current function, generate
159
+ /// the `mapping_regions` and `virtual_file_mapping`, and capture any new filenames. Then use
160
+ /// LLVM APIs to encode the `virtual_file_mapping`, `expressions`, and `mapping_regions` into
161
+ /// the given `coverage_mapping` byte buffer, compliant with the LLVM Coverage Mapping format.
162
+ fn write_coverage_mapping < ' a > (
163
+ global_file_table : & mut GlobalFileTable ,
164
+ expressions : Vec < CounterExpression > ,
165
+ counter_regions : impl Iterator < Item = ( Counter , & ' a CodeRegion ) > ,
166
+ coverage_mapping_buffer : & RustString ,
167
+ ) {
168
+ let mut counter_regions = counter_regions. collect :: < Vec < _ > > ( ) ;
169
+ if counter_regions. is_empty ( ) {
170
+ return ;
171
+ }
154
172
155
- let mut virtual_file_mapping = Vec :: new ( ) ;
156
- let mut mapping_regions = Vec :: new ( ) ;
157
- let mut current_file_name = None ;
158
- let mut current_file_id = 0 ;
159
-
160
- // Convert the list of (Counter, CodeRegion) pairs to an array of `CounterMappingRegion`, sorted
161
- // by filename and position. Capture any new files to compute the `CounterMappingRegion`s
162
- // `file_id` (indexing files referenced by the current function), and construct the
163
- // function-specific `virtual_file_mapping` from `file_id` to its index in the module's
164
- // `filenames` array.
165
- counter_regions. sort_unstable_by_key ( |( _counter, region) | * region) ;
166
- for ( counter, region) in counter_regions {
167
- let CodeRegion { file_name, start_line, start_col, end_line, end_col } = * region;
168
- let same_file = current_file_name. is_some_and ( |p| p == file_name) ;
169
- if !same_file {
170
- if current_file_name. is_some ( ) {
171
- current_file_id += 1 ;
172
- }
173
- current_file_name = Some ( file_name) ;
174
- debug ! ( " file_id: {} = '{:?}'" , current_file_id, file_name) ;
175
- let ( filenames_index, _) = self . filenames . insert_full ( file_name) ;
176
- virtual_file_mapping. push ( filenames_index as u32 ) ;
173
+ let mut virtual_file_mapping = Vec :: new ( ) ;
174
+ let mut mapping_regions = Vec :: new ( ) ;
175
+ let mut current_file_name = None ;
176
+ let mut current_file_id = 0 ;
177
+
178
+ // Convert the list of (Counter, CodeRegion) pairs to an array of `CounterMappingRegion`, sorted
179
+ // by filename and position. Capture any new files to compute the `CounterMappingRegion`s
180
+ // `file_id` (indexing files referenced by the current function), and construct the
181
+ // function-specific `virtual_file_mapping` from `file_id` to its index in the module's
182
+ // `filenames` array.
183
+ counter_regions. sort_unstable_by_key ( |( _counter, region) | * region) ;
184
+ for ( counter, region) in counter_regions {
185
+ let CodeRegion { file_name, start_line, start_col, end_line, end_col } = * region;
186
+ let same_file = current_file_name. is_some_and ( |p| p == file_name) ;
187
+ if !same_file {
188
+ if current_file_name. is_some ( ) {
189
+ current_file_id += 1 ;
177
190
}
191
+ current_file_name = Some ( file_name) ;
192
+ debug ! ( " file_id: {} = '{:?}'" , current_file_id, file_name) ;
193
+ let global_file_id = global_file_table. global_file_id_for_file_name ( file_name) ;
194
+ virtual_file_mapping. push ( global_file_id) ;
195
+ }
196
+ {
178
197
debug ! ( "Adding counter {:?} to map for {:?}" , counter, region) ;
179
198
mapping_regions. push ( CounterMappingRegion :: code_region (
180
199
counter,
@@ -185,7 +204,9 @@ impl CoverageMapGenerator {
185
204
end_col,
186
205
) ) ;
187
206
}
207
+ }
188
208
209
+ {
189
210
// Encode and append the current function's coverage mapping data
190
211
coverageinfo:: write_mapping_to_buffer (
191
212
virtual_file_mapping,
@@ -194,33 +215,32 @@ impl CoverageMapGenerator {
194
215
coverage_mapping_buffer,
195
216
) ;
196
217
}
218
+ }
197
219
198
- /// Construct coverage map header and the array of function records, and combine them into the
199
- /// coverage map. Save the coverage map data into the LLVM IR as a static global using a
200
- /// specific, well-known section and name.
201
- fn generate_coverage_map < ' ll > (
202
- self ,
203
- cx : & CodegenCx < ' ll , ' _ > ,
204
- version : u32 ,
205
- filenames_size : usize ,
206
- filenames_val : & ' ll llvm:: Value ,
207
- ) -> & ' ll llvm:: Value {
208
- debug ! ( "cov map: filenames_size = {}, 0-based version = {}" , filenames_size, version) ;
209
-
210
- // Create the coverage data header (Note, fields 0 and 2 are now always zero,
211
- // as of `llvm::coverage::CovMapVersion::Version4`.)
212
- let zero_was_n_records_val = cx. const_u32 ( 0 ) ;
213
- let filenames_size_val = cx. const_u32 ( filenames_size as u32 ) ;
214
- let zero_was_coverage_size_val = cx. const_u32 ( 0 ) ;
215
- let version_val = cx. const_u32 ( version) ;
216
- let cov_data_header_val = cx. const_struct (
217
- & [ zero_was_n_records_val, filenames_size_val, zero_was_coverage_size_val, version_val] ,
218
- /*packed=*/ false ,
219
- ) ;
220
+ /// Construct coverage map header and the array of function records, and combine them into the
221
+ /// coverage map. Save the coverage map data into the LLVM IR as a static global using a
222
+ /// specific, well-known section and name.
223
+ fn generate_coverage_map < ' ll > (
224
+ cx : & CodegenCx < ' ll , ' _ > ,
225
+ version : u32 ,
226
+ filenames_size : usize ,
227
+ filenames_val : & ' ll llvm:: Value ,
228
+ ) -> & ' ll llvm:: Value {
229
+ debug ! ( "cov map: filenames_size = {}, 0-based version = {}" , filenames_size, version) ;
230
+
231
+ // Create the coverage data header (Note, fields 0 and 2 are now always zero,
232
+ // as of `llvm::coverage::CovMapVersion::Version4`.)
233
+ let zero_was_n_records_val = cx. const_u32 ( 0 ) ;
234
+ let filenames_size_val = cx. const_u32 ( filenames_size as u32 ) ;
235
+ let zero_was_coverage_size_val = cx. const_u32 ( 0 ) ;
236
+ let version_val = cx. const_u32 ( version) ;
237
+ let cov_data_header_val = cx. const_struct (
238
+ & [ zero_was_n_records_val, filenames_size_val, zero_was_coverage_size_val, version_val] ,
239
+ /*packed=*/ false ,
240
+ ) ;
220
241
221
- // Create the complete LLVM coverage data value to add to the LLVM IR
222
- cx. const_struct ( & [ cov_data_header_val, filenames_val] , /*packed=*/ false )
223
- }
242
+ // Create the complete LLVM coverage data value to add to the LLVM IR
243
+ cx. const_struct ( & [ cov_data_header_val, filenames_val] , /*packed=*/ false )
224
244
}
225
245
226
246
/// Construct a function record and combine it with the function's coverage mapping data.
0 commit comments