@@ -55,7 +55,7 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
5555 return ;
5656 }
5757
58- let mut mapgen = CoverageMapGenerator :: new ( tcx) ;
58+ let mut global_file_table = GlobalFileTable :: new ( tcx) ;
5959
6060 // Encode coverage mappings and generate function records
6161 let mut function_data = Vec :: new ( ) ;
@@ -68,7 +68,12 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
6868 function_coverage. get_expressions_and_counter_regions ( ) ;
6969
7070 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+ ) ;
7277 } ) ;
7378
7479 if coverage_mapping_buffer. is_empty ( ) {
@@ -87,19 +92,14 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
8792 }
8893
8994 // 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 ( ) ;
9696
9797 let filenames_size = filenames_buffer. len ( ) ;
9898 let filenames_val = cx. const_bytes ( & filenames_buffer) ;
9999 let filenames_ref = coverageinfo:: hash_bytes ( & filenames_buffer) ;
100100
101101 // 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) ;
103103
104104 let covfun_section_name = coverageinfo:: covfun_section_name ( cx) ;
105105 for ( mangled_function_name, source_hash, is_used, coverage_mapping_buffer) in function_data {
@@ -118,13 +118,13 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
118118 coverageinfo:: save_cov_data_to_mod ( cx, cov_data_val) ;
119119}
120120
121- struct CoverageMapGenerator {
122- filenames : FxIndexSet < Symbol > ,
121+ struct GlobalFileTable {
122+ global_file_table : FxIndexSet < Symbol > ,
123123}
124124
125- impl CoverageMapGenerator {
125+ impl GlobalFileTable {
126126 fn new ( tcx : TyCtxt < ' _ > ) -> Self {
127- let mut filenames = FxIndexSet :: default ( ) ;
127+ let mut global_file_table = FxIndexSet :: default ( ) ;
128128 // LLVM Coverage Mapping Format version 6 (zero-based encoded as 5)
129129 // requires setting the first filename to the compilation directory.
130130 // Since rustc generates coverage maps with relative paths, the
@@ -133,48 +133,67 @@ impl CoverageMapGenerator {
133133 let working_dir = Symbol :: intern (
134134 & tcx. sess . opts . working_dir . remapped_path_if_available ( ) . to_string_lossy ( ) ,
135135 ) ;
136- filenames . insert ( working_dir) ;
137- Self { filenames }
136+ global_file_table . insert ( working_dir) ;
137+ Self { global_file_table }
138138 }
139139
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+ }
154172
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 ;
177190 }
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+ {
178197 debug ! ( "Adding counter {:?} to map for {:?}" , counter, region) ;
179198 mapping_regions. push ( CounterMappingRegion :: code_region (
180199 counter,
@@ -185,7 +204,9 @@ impl CoverageMapGenerator {
185204 end_col,
186205 ) ) ;
187206 }
207+ }
188208
209+ {
189210 // Encode and append the current function's coverage mapping data
190211 coverageinfo:: write_mapping_to_buffer (
191212 virtual_file_mapping,
@@ -194,33 +215,32 @@ impl CoverageMapGenerator {
194215 coverage_mapping_buffer,
195216 ) ;
196217 }
218+ }
197219
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+ ) ;
220241
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 )
224244}
225245
226246/// Construct a function record and combine it with the function's coverage mapping data.
0 commit comments