Skip to content

Commit a9b2c6a

Browse files
committed
Auto merge of #114005 - Zalathar:no-cstr, r=jackh726
coverage: Don't convert filename/symbol strings to `CString` for FFI LLVM APIs are usually perfectly happy to accept pointer/length strings, as long as we supply a suitable length value when creating a `StringRef` or `std::string`. This lets us avoid quite a few intermediate `CString` copies during coverage codegen. It also lets us use an `IndexSet<Symbol>` (instead of an `IndexSet<CString>`) when building the deduplicated filename table.
2 parents 439d066 + 4b154bc commit a9b2c6a

File tree

4 files changed

+52
-26
lines changed

4 files changed

+52
-26
lines changed

compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs

+12-13
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ use rustc_middle::bug;
1212
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
1313
use rustc_middle::mir::coverage::CodeRegion;
1414
use rustc_middle::ty::TyCtxt;
15-
16-
use std::ffi::CString;
15+
use rustc_span::Symbol;
1716

1817
/// Generates and exports the Coverage Map.
1918
///
@@ -89,7 +88,10 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
8988

9089
// Encode all filenames referenced by counters/expressions in this module
9190
let filenames_buffer = llvm::build_byte_buffer(|filenames_buffer| {
92-
coverageinfo::write_filenames_section_to_buffer(&mapgen.filenames, filenames_buffer);
91+
coverageinfo::write_filenames_section_to_buffer(
92+
mapgen.filenames.iter().map(Symbol::as_str),
93+
filenames_buffer,
94+
);
9395
});
9496

9597
let filenames_size = filenames_buffer.len();
@@ -117,7 +119,7 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
117119
}
118120

119121
struct CoverageMapGenerator {
120-
filenames: FxIndexSet<CString>,
122+
filenames: FxIndexSet<Symbol>,
121123
}
122124

123125
impl CoverageMapGenerator {
@@ -128,11 +130,10 @@ impl CoverageMapGenerator {
128130
// Since rustc generates coverage maps with relative paths, the
129131
// compilation directory can be combined with the relative paths
130132
// to get absolute paths, if needed.
131-
let working_dir =
132-
tcx.sess.opts.working_dir.remapped_path_if_available().to_string_lossy().to_string();
133-
let c_filename =
134-
CString::new(working_dir).expect("null error converting filename to C string");
135-
filenames.insert(c_filename);
133+
let working_dir = Symbol::intern(
134+
&tcx.sess.opts.working_dir.remapped_path_if_available().to_string_lossy(),
135+
);
136+
filenames.insert(working_dir);
136137
Self { filenames }
137138
}
138139

@@ -170,10 +171,8 @@ impl CoverageMapGenerator {
170171
current_file_id += 1;
171172
}
172173
current_file_name = Some(file_name);
173-
let c_filename = CString::new(file_name.to_string())
174-
.expect("null error converting filename to C string");
175-
debug!(" file_id: {} = '{:?}'", current_file_id, c_filename);
176-
let (filenames_index, _) = self.filenames.insert_full(c_filename);
174+
debug!(" file_id: {} = '{:?}'", current_file_id, file_name);
175+
let (filenames_index, _) = self.filenames.insert_full(file_name);
177176
virtual_file_mapping.push(filenames_index as u32);
178177
}
179178
debug!("Adding counter {:?} to map for {:?}", counter, region);

compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs

+18-8
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ use rustc_middle::ty::Instance;
2525
use rustc_middle::ty::Ty;
2626

2727
use std::cell::RefCell;
28-
use std::ffi::CString;
2928

3029
pub(crate) mod ffi;
3130
pub(crate) mod map_data;
@@ -332,21 +331,32 @@ fn create_pgo_func_name_var<'ll, 'tcx>(
332331
cx: &CodegenCx<'ll, 'tcx>,
333332
instance: Instance<'tcx>,
334333
) -> &'ll llvm::Value {
335-
let mangled_fn_name = CString::new(cx.tcx.symbol_name(instance).name)
336-
.expect("error converting function name to C string");
334+
let mangled_fn_name: &str = cx.tcx.symbol_name(instance).name;
337335
let llfn = cx.get_fn(instance);
338-
unsafe { llvm::LLVMRustCoverageCreatePGOFuncNameVar(llfn, mangled_fn_name.as_ptr()) }
336+
unsafe {
337+
llvm::LLVMRustCoverageCreatePGOFuncNameVar(
338+
llfn,
339+
mangled_fn_name.as_ptr().cast(),
340+
mangled_fn_name.len(),
341+
)
342+
}
339343
}
340344

341345
pub(crate) fn write_filenames_section_to_buffer<'a>(
342-
filenames: impl IntoIterator<Item = &'a CString>,
346+
filenames: impl IntoIterator<Item = &'a str>,
343347
buffer: &RustString,
344348
) {
345-
let c_str_vec = filenames.into_iter().map(|cstring| cstring.as_ptr()).collect::<Vec<_>>();
349+
let (pointers, lengths) = filenames
350+
.into_iter()
351+
.map(|s: &str| (s.as_ptr().cast(), s.len()))
352+
.unzip::<_, _, Vec<_>, Vec<_>>();
353+
346354
unsafe {
347355
llvm::LLVMRustCoverageWriteFilenamesSectionToBuffer(
348-
c_str_vec.as_ptr(),
349-
c_str_vec.len(),
356+
pointers.as_ptr(),
357+
pointers.len(),
358+
lengths.as_ptr(),
359+
lengths.len(),
350360
buffer,
351361
);
352362
}

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -1707,6 +1707,8 @@ extern "C" {
17071707
pub fn LLVMRustCoverageWriteFilenamesSectionToBuffer(
17081708
Filenames: *const *const c_char,
17091709
FilenamesLen: size_t,
1710+
Lengths: *const size_t,
1711+
LengthsLen: size_t,
17101712
BufferOut: &RustString,
17111713
);
17121714

@@ -1721,7 +1723,11 @@ extern "C" {
17211723
BufferOut: &RustString,
17221724
);
17231725

1724-
pub fn LLVMRustCoverageCreatePGOFuncNameVar(F: &Value, FuncName: *const c_char) -> &Value;
1726+
pub fn LLVMRustCoverageCreatePGOFuncNameVar(
1727+
F: &Value,
1728+
FuncName: *const c_char,
1729+
FuncNameLen: size_t,
1730+
) -> &Value;
17251731
pub fn LLVMRustCoverageHashByteArray(Bytes: *const c_char, NumBytes: size_t) -> u64;
17261732

17271733
#[allow(improper_ctypes)]

compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp

+15-4
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,20 @@ fromRust(LLVMRustCounterExprKind Kind) {
103103
}
104104

105105
extern "C" void LLVMRustCoverageWriteFilenamesSectionToBuffer(
106-
const char* const Filenames[],
106+
const char *const Filenames[],
107107
size_t FilenamesLen,
108+
const size_t *const Lengths,
109+
size_t LengthsLen,
108110
RustStringRef BufferOut) {
111+
if (FilenamesLen != LengthsLen) {
112+
report_fatal_error(
113+
"Mismatched lengths in LLVMRustCoverageWriteFilenamesSectionToBuffer");
114+
}
115+
109116
SmallVector<std::string,32> FilenameRefs;
117+
FilenameRefs.reserve(FilenamesLen);
110118
for (size_t i = 0; i < FilenamesLen; i++) {
111-
FilenameRefs.push_back(std::string(Filenames[i]));
119+
FilenameRefs.emplace_back(Filenames[i], Lengths[i]);
112120
}
113121
auto FilenamesWriter =
114122
coverage::CoverageFilenamesSectionWriter(ArrayRef<std::string>(FilenameRefs));
@@ -153,8 +161,11 @@ extern "C" void LLVMRustCoverageWriteMappingToBuffer(
153161
CoverageMappingWriter.write(OS);
154162
}
155163

156-
extern "C" LLVMValueRef LLVMRustCoverageCreatePGOFuncNameVar(LLVMValueRef F, const char *FuncName) {
157-
StringRef FuncNameRef(FuncName);
164+
extern "C" LLVMValueRef LLVMRustCoverageCreatePGOFuncNameVar(
165+
LLVMValueRef F,
166+
const char *FuncName,
167+
size_t FuncNameLen) {
168+
StringRef FuncNameRef(FuncName, FuncNameLen);
158169
return wrap(createPGOFuncNameVar(*cast<Function>(unwrap(F)), FuncNameRef));
159170
}
160171

0 commit comments

Comments
 (0)