1
Fork 0

coverage: Identify source files by ID, not by interned filename

This commit is contained in:
Zalathar 2024-12-18 21:19:30 +11:00
parent 34ed51cb83
commit 837a25dd41
3 changed files with 32 additions and 36 deletions

View file

@ -40,11 +40,10 @@ pub(crate) fn create_pgo_func_name_var<'ll>(
} }
} }
pub(crate) fn write_filenames_to_buffer<'a>( pub(crate) fn write_filenames_to_buffer(filenames: &[impl AsRef<str>]) -> Vec<u8> {
filenames: impl IntoIterator<Item = &'a str>,
) -> Vec<u8> {
let (pointers, lengths) = filenames let (pointers, lengths) = filenames
.into_iter() .into_iter()
.map(AsRef::as_ref)
.map(|s: &str| (s.as_c_char_ptr(), s.len())) .map(|s: &str| (s.as_c_char_ptr(), s.len()))
.unzip::<_, _, Vec<_>, Vec<_>>(); .unzip::<_, _, Vec<_>, Vec<_>>();

View file

@ -1,11 +1,11 @@
use std::iter; use std::sync::Arc;
use itertools::Itertools; use itertools::Itertools;
use rustc_abi::Align; use rustc_abi::Align;
use rustc_codegen_ssa::traits::{ use rustc_codegen_ssa::traits::{
BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods, BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods,
}; };
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_index::IndexVec; use rustc_index::IndexVec;
use rustc_middle::mir; use rustc_middle::mir;
@ -13,7 +13,7 @@ use rustc_middle::ty::{self, TyCtxt};
use rustc_session::RemapFileNameExt; use rustc_session::RemapFileNameExt;
use rustc_session::config::RemapPathScopeComponents; use rustc_session::config::RemapPathScopeComponents;
use rustc_span::def_id::DefIdSet; use rustc_span::def_id::DefIdSet;
use rustc_span::{Span, Symbol}; use rustc_span::{SourceFile, StableSourceFileId};
use tracing::debug; use tracing::debug;
use crate::common::CodegenCx; use crate::common::CodegenCx;
@ -132,45 +132,51 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
generate_covmap_record(cx, covmap_version, &filenames_buffer); generate_covmap_record(cx, covmap_version, &filenames_buffer);
} }
/// Maps "global" (per-CGU) file ID numbers to their underlying filenames. /// Maps "global" (per-CGU) file ID numbers to their underlying source files.
struct GlobalFileTable { struct GlobalFileTable {
/// This "raw" table doesn't include the working dir, so a filename's /// This "raw" table doesn't include the working dir, so a file's
/// global ID is its index in this set **plus one**. /// global ID is its index in this set **plus one**.
raw_file_table: FxIndexSet<Symbol>, raw_file_table: FxIndexMap<StableSourceFileId, Arc<SourceFile>>,
} }
impl GlobalFileTable { impl GlobalFileTable {
fn new() -> Self { fn new() -> Self {
Self { raw_file_table: FxIndexSet::default() } Self { raw_file_table: FxIndexMap::default() }
} }
fn global_file_id_for_file_name(&mut self, file_name: Symbol) -> GlobalFileId { fn global_file_id_for_file(&mut self, file: &Arc<SourceFile>) -> GlobalFileId {
// Ensure the given file has a table entry, and get its index. // Ensure the given file has a table entry, and get its index.
let (raw_id, _) = self.raw_file_table.insert_full(file_name); let entry = self.raw_file_table.entry(file.stable_id);
let raw_id = entry.index();
entry.or_insert_with(|| Arc::clone(file));
// The raw file table doesn't include an entry for the working dir // The raw file table doesn't include an entry for the working dir
// (which has ID 0), so add 1 to get the correct ID. // (which has ID 0), so add 1 to get the correct ID.
GlobalFileId::from_usize(raw_id + 1) GlobalFileId::from_usize(raw_id + 1)
} }
fn make_filenames_buffer(&self, tcx: TyCtxt<'_>) -> Vec<u8> { fn make_filenames_buffer(&self, tcx: TyCtxt<'_>) -> Vec<u8> {
let mut table = Vec::with_capacity(self.raw_file_table.len() + 1);
// LLVM Coverage Mapping Format version 6 (zero-based encoded as 5) // LLVM Coverage Mapping Format version 6 (zero-based encoded as 5)
// requires setting the first filename to the compilation directory. // requires setting the first filename to the compilation directory.
// Since rustc generates coverage maps with relative paths, the // Since rustc generates coverage maps with relative paths, the
// compilation directory can be combined with the relative paths // compilation directory can be combined with the relative paths
// to get absolute paths, if needed. // to get absolute paths, if needed.
use rustc_session::RemapFileNameExt; table.push(
use rustc_session::config::RemapPathScopeComponents; tcx.sess
let working_dir: &str = &tcx .opts
.sess .working_dir
.opts .for_scope(tcx.sess, RemapPathScopeComponents::MACRO)
.working_dir .to_string_lossy(),
.for_scope(tcx.sess, RemapPathScopeComponents::MACRO) );
.to_string_lossy();
// Insert the working dir at index 0, before the other filenames. // Add the regular entries after the base directory.
let filenames = table.extend(self.raw_file_table.values().map(|file| {
iter::once(working_dir).chain(self.raw_file_table.iter().map(Symbol::as_str)); file.name.for_scope(tcx.sess, RemapPathScopeComponents::MACRO).to_string_lossy()
llvm_cov::write_filenames_to_buffer(filenames) }));
llvm_cov::write_filenames_to_buffer(&table)
} }
} }
@ -209,13 +215,6 @@ impl VirtualFileMapping {
} }
} }
fn span_file_name(tcx: TyCtxt<'_>, span: Span) -> Symbol {
let source_file = tcx.sess.source_map().lookup_source_file(span.lo());
let name =
source_file.name.for_scope(tcx.sess, RemapPathScopeComponents::MACRO).to_string_lossy();
Symbol::intern(&name)
}
/// Generates the contents of the covmap record for this CGU, which mostly /// Generates the contents of the covmap record for this CGU, which mostly
/// consists of a header and a list of filenames. The record is then stored /// consists of a header and a list of filenames. The record is then stored
/// as a global variable in the `__llvm_covmap` section. /// as a global variable in the `__llvm_covmap` section.

View file

@ -19,7 +19,7 @@ use rustc_target::spec::HasTargetSpec;
use tracing::debug; use tracing::debug;
use crate::common::CodegenCx; use crate::common::CodegenCx;
use crate::coverageinfo::mapgen::{GlobalFileTable, VirtualFileMapping, span_file_name, spans}; use crate::coverageinfo::mapgen::{GlobalFileTable, VirtualFileMapping, spans};
use crate::coverageinfo::{ffi, llvm_cov}; use crate::coverageinfo::{ffi, llvm_cov};
use crate::llvm; use crate::llvm;
@ -117,16 +117,14 @@ fn fill_region_tables<'tcx>(
covfun: &mut CovfunRecord<'tcx>, covfun: &mut CovfunRecord<'tcx>,
) { ) {
// Currently a function's mappings must all be in the same file as its body span. // Currently a function's mappings must all be in the same file as its body span.
let file_name = span_file_name(tcx, fn_cov_info.body_span);
let source_map = tcx.sess.source_map(); let source_map = tcx.sess.source_map();
let source_file = source_map.lookup_source_file(fn_cov_info.body_span.lo()); let source_file = source_map.lookup_source_file(fn_cov_info.body_span.lo());
// Look up the global file ID for that filename. // Look up the global file ID for that file.
let global_file_id = global_file_table.global_file_id_for_file_name(file_name); let global_file_id = global_file_table.global_file_id_for_file(&source_file);
// Associate that global file ID with a local file ID for this function. // Associate that global file ID with a local file ID for this function.
let local_file_id = covfun.virtual_file_mapping.local_id_for_global(global_file_id); let local_file_id = covfun.virtual_file_mapping.local_id_for_global(global_file_id);
debug!(" file id: {local_file_id:?} => {global_file_id:?} = '{file_name:?}'");
let ffi::Regions { code_regions, branch_regions, mcdc_branch_regions, mcdc_decision_regions } = let ffi::Regions { code_regions, branch_regions, mcdc_branch_regions, mcdc_decision_regions } =
&mut covfun.regions; &mut covfun.regions;