use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::StableHasher;
-use rustc_data_structures::sync::{Lock, LockGuard, Lrc, MappedLockGuard};
+use rustc_data_structures::sync::{AtomicU32, Lock, LockGuard, Lrc, MappedLockGuard};
use std::cmp;
+use std::convert::TryFrom;
use std::hash::Hash;
use std::path::{Path, PathBuf};
+use std::sync::atomic::Ordering;
use log::debug;
use std::env;
}
pub struct SourceMap {
+ /// The address space below this value is currently used by the files in the source map.
+ used_address_space: AtomicU32,
+
files: Lock<SourceMapFiles>,
file_loader: Box<dyn FileLoader + Sync + Send>,
// This is used to apply the file path remapping as specified via
impl SourceMap {
pub fn new(path_mapping: FilePathMapping) -> SourceMap {
- SourceMap { files: Default::default(), file_loader: Box::new(RealFileLoader), path_mapping }
+ SourceMap {
+ used_address_space: AtomicU32::new(0),
+ files: Default::default(),
+ file_loader: Box::new(RealFileLoader),
+ path_mapping,
+ }
}
pub fn with_file_loader(
file_loader: Box<dyn FileLoader + Sync + Send>,
path_mapping: FilePathMapping,
) -> SourceMap {
- SourceMap { files: Default::default(), file_loader, path_mapping }
+ SourceMap {
+ used_address_space: AtomicU32::new(0),
+ files: Default::default(),
+ file_loader,
+ path_mapping,
+ }
}
pub fn path_mapping(&self) -> &FilePathMapping {
self.files.borrow().stable_id_to_source_file.get(&stable_id).map(|sf| sf.clone())
}
- fn next_start_pos(&self) -> usize {
- match self.files.borrow().source_files.last() {
- None => 0,
- // Add one so there is some space between files. This lets us distinguish
- // positions in the `SourceMap`, even in the presence of zero-length files.
- Some(last) => last.end_pos.to_usize() + 1,
+ fn allocate_address_space(&self, size: usize) -> Result<usize, OffsetOverflowError> {
+ let size = u32::try_from(size).map_err(|_| OffsetOverflowError)?;
+
+ loop {
+ let current = self.used_address_space.load(Ordering::Relaxed);
+ let next = current
+ .checked_add(size)
+ // Add one so there is some space between files. This lets us distinguish
+ // positions in the `SourceMap`, even in the presence of zero-length files.
+ .and_then(|next| next.checked_add(1))
+ .ok_or(OffsetOverflowError)?;
+
+ if self
+ .used_address_space
+ .compare_exchange(current, next, Ordering::Relaxed, Ordering::Relaxed)
+ .is_ok()
+ {
+ return Ok(usize::try_from(current).unwrap());
+ }
}
}
filename: FileName,
src: String,
) -> Result<Lrc<SourceFile>, OffsetOverflowError> {
- let start_pos = self.next_start_pos();
-
// The path is used to determine the directory for loading submodules and
// include files, so it must be before remapping.
// Note that filename may not be a valid path, eg it may be `<anon>` etc,
let lrc_sf = match self.source_file_by_stable_id(file_id) {
Some(lrc_sf) => lrc_sf,
None => {
+ let start_pos = self.allocate_address_space(src.len())?;
+
let source_file = Lrc::new(SourceFile::new(
filename,
was_remapped,
unmapped_path,
src,
Pos::from_usize(start_pos),
- )?);
+ ));
let mut files = self.files.borrow_mut();
mut file_local_non_narrow_chars: Vec<NonNarrowChar>,
mut file_local_normalized_pos: Vec<NormalizedPos>,
) -> Lrc<SourceFile> {
- let start_pos = self.next_start_pos();
+ let start_pos = self
+ .allocate_address_space(source_len)
+ .expect("not enough address space for imported source file");
let end_pos = Pos::from_usize(start_pos + source_len);
let start_pos = Pos::from_usize(start_pos);