Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/span/src/ast_id.rs')
| -rw-r--r-- | crates/span/src/ast_id.rs | 61 |
1 files changed, 57 insertions, 4 deletions
diff --git a/crates/span/src/ast_id.rs b/crates/span/src/ast_id.rs index e803747998..599b3c7175 100644 --- a/crates/span/src/ast_id.rs +++ b/crates/span/src/ast_id.rs @@ -44,9 +44,15 @@ pub const ROOT_ERASED_FILE_AST_ID: ErasedFileAstId = /// ErasedFileAstId used as the span for syntax node fixups. Any Span containing this file id is to be /// considered fake. +/// Do not modify this, it is used by the proc-macro server. pub const FIXUP_ERASED_FILE_AST_ID_MARKER: ErasedFileAstId = ErasedFileAstId(pack_hash_index_and_kind(0, 0, ErasedFileAstIdKind::Fixup as u32)); +/// [`ErasedFileAstId`] used as the span for syntax nodes that should not be mapped down to +/// macro expansion. Any `Span` containing this file id is to be considered fake. +pub const NO_DOWNMAP_ERASED_FILE_AST_ID_MARKER: ErasedFileAstId = + ErasedFileAstId(pack_hash_index_and_kind(0, 0, ErasedFileAstIdKind::NoDownmap as u32)); + /// This is a type erased FileAstId. #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct ErasedFileAstId(u32); @@ -94,6 +100,7 @@ impl fmt::Debug for ErasedFileAstId { BlockExpr, AsmExpr, Fixup, + NoDownmap, ); if f.alternate() { write!(f, "{kind}[{:04X}, {}]", self.hash_value(), self.index()) @@ -149,6 +156,9 @@ enum ErasedFileAstIdKind { // because incrementality is not a problem, they will always be the only item in the macro file, // and memory usage also not because they're rare. AsmExpr, + /// Represents a fake [`ErasedFileAstId`] that should not be mapped down to macro expansion + /// result. + NoDownmap, /// Keep this last. Root, } @@ -157,7 +167,7 @@ enum ErasedFileAstIdKind { const HASH_BITS: u32 = 16; const INDEX_BITS: u32 = 11; const KIND_BITS: u32 = 5; -const _: () = assert!(ErasedFileAstIdKind::Fixup as u32 <= ((1 << KIND_BITS) - 1)); +const _: () = assert!(ErasedFileAstIdKind::Root as u32 <= ((1 << KIND_BITS) - 1)); const _: () = assert!(HASH_BITS + INDEX_BITS + KIND_BITS == u32::BITS); #[inline] @@ -593,8 +603,9 @@ impl AstIdMap { // After all, the block will then contain the *outer* item, so we allocate // an ID for it anyway. let mut blocks = Vec::new(); - let mut curr_layer = vec![(node.clone(), None)]; - let mut next_layer = vec![]; + let mut curr_layer = Vec::with_capacity(32); + curr_layer.push((node.clone(), None)); + let mut next_layer = Vec::with_capacity(32); while !curr_layer.is_empty() { curr_layer.drain(..).for_each(|(node, parent_idx)| { let mut preorder = node.preorder(); @@ -700,7 +711,7 @@ impl AstIdMap { } } - /// The [`AstId`] of the root node + /// The root node. pub fn root(&self) -> SyntaxNodePtr { self.arena[Idx::from_raw(RawIdx::from_u32(0))].0 } @@ -766,6 +777,48 @@ impl AstIdMap { } } +#[cfg(not(no_salsa_async_drops))] +impl Drop for AstIdMap { + fn drop(&mut self) { + let arena = std::mem::take(&mut self.arena); + let ptr_map = std::mem::take(&mut self.ptr_map); + let id_map = std::mem::take(&mut self.id_map); + static AST_ID_MAP_DROP_THREAD: std::sync::OnceLock< + std::sync::mpsc::Sender<( + Arena<(SyntaxNodePtr, ErasedFileAstId)>, + hashbrown::HashTable<ArenaId>, + hashbrown::HashTable<ArenaId>, + )>, + > = std::sync::OnceLock::new(); + AST_ID_MAP_DROP_THREAD + .get_or_init(|| { + let (sender, receiver) = std::sync::mpsc::channel::<( + Arena<(SyntaxNodePtr, ErasedFileAstId)>, + hashbrown::HashTable<ArenaId>, + hashbrown::HashTable<ArenaId>, + )>(); + std::thread::Builder::new() + .name("AstIdMapDropper".to_owned()) + .spawn(move || { + loop { + // block on a receive + _ = receiver.recv(); + // then drain the entire channel + while receiver.try_recv().is_ok() {} + // and sleep for a bit + std::thread::sleep(std::time::Duration::from_millis(100)); + } + // why do this over just a `receiver.iter().for_each(drop)`? To reduce contention on the channel lock. + // otherwise this thread will constantly wake up and sleep again. + }) + .unwrap(); + sender + }) + .send((arena, ptr_map, id_map)) + .unwrap(); + } +} + #[inline] fn hash_ptr(ptr: &SyntaxNodePtr) -> u64 { FxBuildHasher.hash_one(ptr) |