| use crate::builder::Builder; |
| use crate::common::CodegenCx; |
| use log::debug; |
| use rustc_codegen_ssa::coverageinfo::map::*; |
| use rustc_codegen_ssa::traits::{CoverageInfoBuilderMethods, CoverageInfoMethods}; |
| use rustc_data_structures::fx::FxHashMap; |
| use rustc_middle::ty::Instance; |
| |
| use std::cell::RefCell; |
| |
| /// A context object for maintaining all state needed by the coverageinfo module. |
| pub struct CrateCoverageContext<'tcx> { |
| // Coverage region data for each instrumented function identified by DefId. |
| pub(crate) coverage_regions: RefCell<FxHashMap<Instance<'tcx>, FunctionCoverageRegions>>, |
| } |
| |
| impl<'tcx> CrateCoverageContext<'tcx> { |
| pub fn new() -> Self { |
| Self { coverage_regions: Default::default() } |
| } |
| } |
| |
| /// Generates and exports the Coverage Map. |
| // FIXME(richkadel): Actually generate and export the coverage map to LLVM. |
| // The current implementation is actually just debug messages to show the data is available. |
| pub fn finalize(cx: &CodegenCx<'_, '_>) { |
| let coverage_regions = &*cx.coverage_context().coverage_regions.borrow(); |
| for instance in coverage_regions.keys() { |
| let coverageinfo = cx.tcx.coverageinfo(instance.def_id()); |
| debug_assert!(coverageinfo.num_counters > 0); |
| debug!( |
| "Generate coverage map for: {:?}, hash: {}, num_counters: {}", |
| instance, coverageinfo.hash, coverageinfo.num_counters |
| ); |
| let function_coverage_regions = &coverage_regions[instance]; |
| for (index, region) in function_coverage_regions.indexed_regions() { |
| match region.kind { |
| CoverageKind::Counter => debug!( |
| " Counter {}, for {}..{}", |
| index, region.coverage_span.start_byte_pos, region.coverage_span.end_byte_pos |
| ), |
| CoverageKind::CounterExpression(lhs, op, rhs) => debug!( |
| " CounterExpression {} = {} {:?} {}, for {}..{}", |
| index, |
| lhs, |
| op, |
| rhs, |
| region.coverage_span.start_byte_pos, |
| region.coverage_span.end_byte_pos |
| ), |
| } |
| } |
| for unreachable in function_coverage_regions.unreachable_regions() { |
| debug!( |
| " Unreachable code region: {}..{}", |
| unreachable.start_byte_pos, unreachable.end_byte_pos |
| ); |
| } |
| } |
| } |
| |
| impl CoverageInfoMethods for CodegenCx<'ll, 'tcx> { |
| fn coverageinfo_finalize(&self) { |
| finalize(self) |
| } |
| } |
| |
| impl CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { |
| fn add_counter_region( |
| &mut self, |
| instance: Instance<'tcx>, |
| index: u32, |
| start_byte_pos: u32, |
| end_byte_pos: u32, |
| ) { |
| debug!( |
| "adding counter to coverage map: instance={:?}, index={}, byte range {}..{}", |
| instance, index, start_byte_pos, end_byte_pos, |
| ); |
| let mut coverage_regions = self.coverage_context().coverage_regions.borrow_mut(); |
| coverage_regions.entry(instance).or_default().add_counter( |
| index, |
| start_byte_pos, |
| end_byte_pos, |
| ); |
| } |
| |
| fn add_counter_expression_region( |
| &mut self, |
| instance: Instance<'tcx>, |
| index: u32, |
| lhs: u32, |
| op: CounterOp, |
| rhs: u32, |
| start_byte_pos: u32, |
| end_byte_pos: u32, |
| ) { |
| debug!( |
| "adding counter expression to coverage map: instance={:?}, index={}, {} {:?} {}, byte range {}..{}", |
| instance, index, lhs, op, rhs, start_byte_pos, end_byte_pos, |
| ); |
| let mut coverage_regions = self.coverage_context().coverage_regions.borrow_mut(); |
| coverage_regions.entry(instance).or_default().add_counter_expression( |
| index, |
| lhs, |
| op, |
| rhs, |
| start_byte_pos, |
| end_byte_pos, |
| ); |
| } |
| |
| fn add_unreachable_region( |
| &mut self, |
| instance: Instance<'tcx>, |
| start_byte_pos: u32, |
| end_byte_pos: u32, |
| ) { |
| debug!( |
| "adding unreachable code to coverage map: instance={:?}, byte range {}..{}", |
| instance, start_byte_pos, end_byte_pos, |
| ); |
| let mut coverage_regions = self.coverage_context().coverage_regions.borrow_mut(); |
| coverage_regions.entry(instance).or_default().add_unreachable(start_byte_pos, end_byte_pos); |
| } |
| } |