Skip to content

Commit 23299ed

Browse files
committed
Auto merge of #50997 - michaelwoerister:pre-analyze-filemaps, r=<try>
Make FileMap::{lines, multibyte_chars, non_narrow_chars} non-mutable. This PR removes most of the interior mutability from `FileMap`, which should be beneficial, especially in a multithreaded setting. This is achieved by initializing the state in question when the filemap is constructed instead of during lexing. Hopefully this doesn't degrade performance. cc @wesleywiser
2 parents 910e29a + 2874a87 commit 23299ed

File tree

9 files changed

+142
-214
lines changed

9 files changed

+142
-214
lines changed

src/librustc/ich/impls_syntax.rs

+12-18
Original file line numberDiff line numberDiff line change
@@ -457,27 +457,21 @@ impl<'a> HashStable<StableHashingContext<'a>> for FileMap {
457457
src_hash.hash_stable(hcx, hasher);
458458

459459
// We only hash the relative position within this filemap
460-
lines.with_lock(|lines| {
461-
lines.len().hash_stable(hcx, hasher);
462-
for &line in lines.iter() {
463-
stable_byte_pos(line, start_pos).hash_stable(hcx, hasher);
464-
}
465-
});
460+
lines.len().hash_stable(hcx, hasher);
461+
for &line in lines.iter() {
462+
stable_byte_pos(line, start_pos).hash_stable(hcx, hasher);
463+
}
466464

467465
// We only hash the relative position within this filemap
468-
multibyte_chars.with_lock(|multibyte_chars| {
469-
multibyte_chars.len().hash_stable(hcx, hasher);
470-
for &char_pos in multibyte_chars.iter() {
471-
stable_multibyte_char(char_pos, start_pos).hash_stable(hcx, hasher);
472-
}
473-
});
466+
multibyte_chars.len().hash_stable(hcx, hasher);
467+
for &char_pos in multibyte_chars.iter() {
468+
stable_multibyte_char(char_pos, start_pos).hash_stable(hcx, hasher);
469+
}
474470

475-
non_narrow_chars.with_lock(|non_narrow_chars| {
476-
non_narrow_chars.len().hash_stable(hcx, hasher);
477-
for &char_pos in non_narrow_chars.iter() {
478-
stable_non_narrow_char(char_pos, start_pos).hash_stable(hcx, hasher);
479-
}
480-
});
471+
non_narrow_chars.len().hash_stable(hcx, hasher);
472+
for &char_pos in non_narrow_chars.iter() {
473+
stable_non_narrow_char(char_pos, start_pos).hash_stable(hcx, hasher);
474+
}
481475
}
482476
}
483477

src/librustc/ty/maps/on_disk_cache.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -654,7 +654,7 @@ impl<'a, 'tcx, 'x> SpecializedDecoder<Span> for CacheDecoder<'a, 'tcx, 'x> {
654654
let len = BytePos::decode(self)?;
655655

656656
let file_lo = self.file_index_to_file(file_lo_index);
657-
let lo = file_lo.lines.borrow()[line_lo - 1] + col_lo;
657+
let lo = file_lo.lines[line_lo - 1] + col_lo;
658658
let hi = lo + len;
659659

660660
let expn_info_tag = u8::decode(self)?;

src/librustc_metadata/decoder.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -1164,9 +1164,9 @@ impl<'a, 'tcx> CrateMetadata {
11641164
src_hash,
11651165
start_pos,
11661166
end_pos,
1167-
lines,
1168-
multibyte_chars,
1169-
non_narrow_chars,
1167+
mut lines,
1168+
mut multibyte_chars,
1169+
mut non_narrow_chars,
11701170
name_hash,
11711171
.. } = filemap_to_import;
11721172

@@ -1177,15 +1177,12 @@ impl<'a, 'tcx> CrateMetadata {
11771177
// `CodeMap::new_imported_filemap()` will then translate those
11781178
// coordinates to their new global frame of reference when the
11791179
// offset of the FileMap is known.
1180-
let mut lines = lines.into_inner();
11811180
for pos in &mut lines {
11821181
*pos = *pos - start_pos;
11831182
}
1184-
let mut multibyte_chars = multibyte_chars.into_inner();
11851183
for mbc in &mut multibyte_chars {
11861184
mbc.pos = mbc.pos - start_pos;
11871185
}
1188-
let mut non_narrow_chars = non_narrow_chars.into_inner();
11891186
for swc in &mut non_narrow_chars {
11901187
*swc = *swc - start_pos;
11911188
}

src/libsyntax/codemap.rs

+28-95
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,7 @@ impl CodeMap {
211211
}
212212
}
213213

214-
/// Creates a new filemap without setting its line information. If you don't
215-
/// intend to set the line information yourself, you should use new_filemap_and_lines.
214+
/// Creates a new filemap.
216215
/// This does not ensure that only one FileMap exists per file name.
217216
pub fn new_filemap(&self, filename: FileName, src: String) -> Lrc<FileMap> {
218217
let start_pos = self.next_start_pos();
@@ -247,22 +246,6 @@ impl CodeMap {
247246
filemap
248247
}
249248

250-
/// Creates a new filemap and sets its line information.
251-
/// This does not ensure that only one FileMap exists per file name.
252-
pub fn new_filemap_and_lines(&self, filename: &Path, src: &str) -> Lrc<FileMap> {
253-
let fm = self.new_filemap(filename.to_owned().into(), src.to_owned());
254-
let mut byte_pos: u32 = fm.start_pos.0;
255-
for line in src.lines() {
256-
// register the start of this line
257-
fm.next_line(BytePos(byte_pos));
258-
259-
// update byte_pos to include this line and the \n at the end
260-
byte_pos += line.len() as u32 + 1;
261-
}
262-
fm
263-
}
264-
265-
266249
/// Allocates a new FileMap representing a source file from an external
267250
/// crate. The source code of such an "imported filemap" is not available,
268251
/// but we still know enough to generate accurate debuginfo location
@@ -305,9 +288,9 @@ impl CodeMap {
305288
external_src: Lock::new(ExternalSource::AbsentOk),
306289
start_pos,
307290
end_pos,
308-
lines: Lock::new(file_local_lines),
309-
multibyte_chars: Lock::new(file_local_multibyte_chars),
310-
non_narrow_chars: Lock::new(file_local_non_narrow_chars),
291+
lines: file_local_lines,
292+
multibyte_chars: file_local_multibyte_chars,
293+
non_narrow_chars: file_local_non_narrow_chars,
311294
name_hash,
312295
});
313296

@@ -345,21 +328,22 @@ impl CodeMap {
345328
match self.lookup_line(pos) {
346329
Ok(FileMapAndLine { fm: f, line: a }) => {
347330
let line = a + 1; // Line numbers start at 1
348-
let linebpos = (*f.lines.borrow())[a];
331+
let linebpos = f.lines[a];
349332
let linechpos = self.bytepos_to_file_charpos(linebpos);
350333
let col = chpos - linechpos;
351334

352335
let col_display = {
353-
let non_narrow_chars = f.non_narrow_chars.borrow();
354-
let start_width_idx = non_narrow_chars
336+
let start_width_idx = f
337+
.non_narrow_chars
355338
.binary_search_by_key(&linebpos, |x| x.pos())
356339
.unwrap_or_else(|x| x);
357-
let end_width_idx = non_narrow_chars
340+
let end_width_idx = f
341+
.non_narrow_chars
358342
.binary_search_by_key(&pos, |x| x.pos())
359343
.unwrap_or_else(|x| x);
360344
let special_chars = end_width_idx - start_width_idx;
361-
let non_narrow: usize =
362-
non_narrow_chars[start_width_idx..end_width_idx]
345+
let non_narrow: usize = f
346+
.non_narrow_chars[start_width_idx..end_width_idx]
363347
.into_iter()
364348
.map(|x| x.width())
365349
.sum();
@@ -380,12 +364,12 @@ impl CodeMap {
380364
}
381365
Err(f) => {
382366
let col_display = {
383-
let non_narrow_chars = f.non_narrow_chars.borrow();
384-
let end_width_idx = non_narrow_chars
367+
let end_width_idx = f
368+
.non_narrow_chars
385369
.binary_search_by_key(&pos, |x| x.pos())
386370
.unwrap_or_else(|x| x);
387-
let non_narrow: usize =
388-
non_narrow_chars[0..end_width_idx]
371+
let non_narrow: usize = f
372+
.non_narrow_chars[0..end_width_idx]
389373
.into_iter()
390374
.map(|x| x.width())
391375
.sum();
@@ -830,7 +814,7 @@ impl CodeMap {
830814
// The number of extra bytes due to multibyte chars in the FileMap
831815
let mut total_extra_bytes = 0;
832816

833-
for mbc in map.multibyte_chars.borrow().iter() {
817+
for mbc in map.multibyte_chars.iter() {
834818
debug!("{}-byte char at {:?}", mbc.bytes, mbc.pos);
835819
if mbc.pos < bpos {
836820
// every character is at least one byte, so we only
@@ -1028,51 +1012,16 @@ impl FilePathMapping {
10281012
#[cfg(test)]
10291013
mod tests {
10301014
use super::*;
1031-
use std::borrow::Cow;
10321015
use rustc_data_structures::sync::Lrc;
10331016

1034-
#[test]
1035-
fn t1 () {
1036-
let cm = CodeMap::new(FilePathMapping::empty());
1037-
let fm = cm.new_filemap(PathBuf::from("blork.rs").into(),
1038-
"first line.\nsecond line".to_string());
1039-
fm.next_line(BytePos(0));
1040-
// Test we can get lines with partial line info.
1041-
assert_eq!(fm.get_line(0), Some(Cow::from("first line.")));
1042-
// TESTING BROKEN BEHAVIOR: line break declared before actual line break.
1043-
fm.next_line(BytePos(10));
1044-
assert_eq!(fm.get_line(1), Some(Cow::from(".")));
1045-
fm.next_line(BytePos(12));
1046-
assert_eq!(fm.get_line(2), Some(Cow::from("second line")));
1047-
}
1048-
1049-
#[test]
1050-
#[should_panic]
1051-
fn t2 () {
1052-
let cm = CodeMap::new(FilePathMapping::empty());
1053-
let fm = cm.new_filemap(PathBuf::from("blork.rs").into(),
1054-
"first line.\nsecond line".to_string());
1055-
// TESTING *REALLY* BROKEN BEHAVIOR:
1056-
fm.next_line(BytePos(0));
1057-
fm.next_line(BytePos(10));
1058-
fm.next_line(BytePos(2));
1059-
}
1060-
10611017
fn init_code_map() -> CodeMap {
10621018
let cm = CodeMap::new(FilePathMapping::empty());
1063-
let fm1 = cm.new_filemap(PathBuf::from("blork.rs").into(),
1064-
"first line.\nsecond line".to_string());
1065-
let fm2 = cm.new_filemap(PathBuf::from("empty.rs").into(),
1066-
"".to_string());
1067-
let fm3 = cm.new_filemap(PathBuf::from("blork2.rs").into(),
1068-
"first line.\nsecond line".to_string());
1069-
1070-
fm1.next_line(BytePos(0));
1071-
fm1.next_line(BytePos(12));
1072-
fm2.next_line(fm2.start_pos);
1073-
fm3.next_line(fm3.start_pos);
1074-
fm3.next_line(fm3.start_pos + BytePos(12));
1075-
1019+
cm.new_filemap(PathBuf::from("blork.rs").into(),
1020+
"first line.\nsecond line".to_string());
1021+
cm.new_filemap(PathBuf::from("empty.rs").into(),
1022+
"".to_string());
1023+
cm.new_filemap(PathBuf::from("blork2.rs").into(),
1024+
"first line.\nsecond line".to_string());
10761025
cm
10771026
}
10781027

@@ -1125,26 +1074,10 @@ mod tests {
11251074
fn init_code_map_mbc() -> CodeMap {
11261075
let cm = CodeMap::new(FilePathMapping::empty());
11271076
// € is a three byte utf8 char.
1128-
let fm1 =
1129-
cm.new_filemap(PathBuf::from("blork.rs").into(),
1130-
"fir€st €€€€ line.\nsecond line".to_string());
1131-
let fm2 = cm.new_filemap(PathBuf::from("blork2.rs").into(),
1132-
"first line€€.\n€ second line".to_string());
1133-
1134-
fm1.next_line(BytePos(0));
1135-
fm1.next_line(BytePos(28));
1136-
fm2.next_line(fm2.start_pos);
1137-
fm2.next_line(fm2.start_pos + BytePos(20));
1138-
1139-
fm1.record_multibyte_char(BytePos(3), 3);
1140-
fm1.record_multibyte_char(BytePos(9), 3);
1141-
fm1.record_multibyte_char(BytePos(12), 3);
1142-
fm1.record_multibyte_char(BytePos(15), 3);
1143-
fm1.record_multibyte_char(BytePos(18), 3);
1144-
fm2.record_multibyte_char(fm2.start_pos + BytePos(10), 3);
1145-
fm2.record_multibyte_char(fm2.start_pos + BytePos(13), 3);
1146-
fm2.record_multibyte_char(fm2.start_pos + BytePos(18), 3);
1147-
1077+
cm.new_filemap(PathBuf::from("blork.rs").into(),
1078+
"fir€st €€€€ line.\nsecond line".to_string());
1079+
cm.new_filemap(PathBuf::from("blork2.rs").into(),
1080+
"first line€€.\n€ second line".to_string());
11481081
cm
11491082
}
11501083

@@ -1196,7 +1129,7 @@ mod tests {
11961129
let cm = CodeMap::new(FilePathMapping::empty());
11971130
let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n";
11981131
let selection = " \n ~~\n~~~\n~~~~~ \n \n";
1199-
cm.new_filemap_and_lines(Path::new("blork.rs"), inputtext);
1132+
cm.new_filemap(Path::new("blork.rs").to_owned().into(), inputtext.to_string());
12001133
let span = span_from_selection(inputtext, selection);
12011134

12021135
// check that we are extracting the text we thought we were extracting
@@ -1239,7 +1172,7 @@ mod tests {
12391172
let inputtext = "bbbb BB\ncc CCC\n";
12401173
let selection1 = " ~~\n \n";
12411174
let selection2 = " \n ~~~\n";
1242-
cm.new_filemap_and_lines(Path::new("blork.rs"), inputtext);
1175+
cm.new_filemap(Path::new("blork.rs").to_owned().into(), inputtext.to_owned());
12431176
let span1 = span_from_selection(inputtext, selection1);
12441177
let span2 = span_from_selection(inputtext, selection2);
12451178

src/libsyntax/ext/expand.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1451,17 +1451,19 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
14511451

14521452
match String::from_utf8(buf) {
14531453
Ok(src) => {
1454+
let src_interned = Symbol::intern(&src);
1455+
14541456
// Add this input file to the code map to make it available as
14551457
// dependency information
1456-
self.cx.codemap().new_filemap_and_lines(&filename, &src);
1458+
self.cx.codemap().new_filemap(filename.into(), src);
14571459

14581460
let include_info = vec![
14591461
dummy_spanned(ast::NestedMetaItemKind::MetaItem(
14601462
attr::mk_name_value_item_str(Ident::from_str("file"),
14611463
dummy_spanned(file)))),
14621464
dummy_spanned(ast::NestedMetaItemKind::MetaItem(
14631465
attr::mk_name_value_item_str(Ident::from_str("contents"),
1464-
dummy_spanned(Symbol::intern(&src))))),
1466+
dummy_spanned(src_interned)))),
14651467
];
14661468

14671469
let include_ident = Ident::from_str("include");

src/libsyntax/ext/source_util.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -150,11 +150,13 @@ pub fn expand_include_str(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenT
150150
};
151151
match String::from_utf8(bytes) {
152152
Ok(src) => {
153+
let interned_src = Symbol::intern(&src);
154+
153155
// Add this input file to the code map to make it available as
154156
// dependency information
155-
cx.codemap().new_filemap_and_lines(&file, &src);
157+
cx.codemap().new_filemap(file.into(), src);
156158

157-
base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&src)))
159+
base::MacEager::expr(cx.expr_str(sp, interned_src))
158160
}
159161
Err(_) => {
160162
cx.span_err(sp,
@@ -182,7 +184,7 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::Toke
182184
Ok(..) => {
183185
// Add this input file to the code map to make it available as
184186
// dependency information, but don't enter it's contents
185-
cx.codemap().new_filemap_and_lines(&file, "");
187+
cx.codemap().new_filemap(file.into(), "".to_string());
186188

187189
base::MacEager::expr(cx.expr_lit(sp, ast::LitKind::ByteStr(Lrc::new(bytes))))
188190
}

src/libsyntax/parse/lexer/mod.rs

-18
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,6 @@ pub struct StringReader<'a> {
5252
pub filemap: Lrc<syntax_pos::FileMap>,
5353
/// Stop reading src at this index.
5454
pub end_src_index: usize,
55-
/// Whether to record new-lines and multibyte chars in filemap.
56-
/// This is only necessary the first time a filemap is lexed.
57-
/// If part of a filemap is being re-lexed, this should be set to false.
58-
pub save_new_lines_and_multibyte: bool,
5955
// cached:
6056
peek_tok: token::Token,
6157
peek_span: Span,
@@ -190,7 +186,6 @@ impl<'a> StringReader<'a> {
190186
ch: Some('\n'),
191187
filemap,
192188
end_src_index: src.len(),
193-
save_new_lines_and_multibyte: true,
194189
// dummy values; not read
195190
peek_tok: token::Eof,
196191
peek_span: syntax_pos::DUMMY_SP,
@@ -227,7 +222,6 @@ impl<'a> StringReader<'a> {
227222
let mut sr = StringReader::new_raw_internal(sess, begin.fm, None);
228223

229224
// Seek the lexer to the right byte range.
230-
sr.save_new_lines_and_multibyte = false;
231225
sr.next_pos = span.lo();
232226
sr.end_src_index = sr.src_index(span.hi());
233227

@@ -460,18 +454,6 @@ impl<'a> StringReader<'a> {
460454
let next_ch = char_at(&self.src, next_src_index);
461455
let next_ch_len = next_ch.len_utf8();
462456

463-
if self.ch.unwrap() == '\n' {
464-
if self.save_new_lines_and_multibyte {
465-
self.filemap.next_line(self.next_pos);
466-
}
467-
}
468-
if next_ch_len > 1 {
469-
if self.save_new_lines_and_multibyte {
470-
self.filemap.record_multibyte_char(self.next_pos, next_ch_len);
471-
}
472-
}
473-
self.filemap.record_width(self.next_pos, next_ch);
474-
475457
self.ch = Some(next_ch);
476458
self.pos = self.next_pos;
477459
self.next_pos = self.next_pos + Pos::from_usize(next_ch_len);

src/libsyntax/test_snippet.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &
5151
let output = Arc::new(Mutex::new(Vec::new()));
5252

5353
let code_map = Lrc::new(CodeMap::new(FilePathMapping::empty()));
54-
code_map.new_filemap_and_lines(Path::new("test.rs"), &file_text);
54+
code_map.new_filemap(Path::new("test.rs").to_owned().into(), file_text.to_owned());
5555

5656
let primary_span = make_span(&file_text, &span_labels[0].start, &span_labels[0].end);
5757
let mut msp = MultiSpan::from_span(primary_span);

0 commit comments

Comments
 (0)