diff --git a/compiler/cl-arena/src/lib.rs b/compiler/cl-arena/src/lib.rs index 7aba181..5bca8e0 100644 --- a/compiler/cl-arena/src/lib.rs +++ b/compiler/cl-arena/src/lib.rs @@ -87,22 +87,24 @@ pub mod typed_arena { /// A [TypedArena] can hold many instances of a single type, and will properly [Drop] them when /// it falls out of scope. - pub struct TypedArena { + pub struct TypedArena<'arena, T> { + _lives: PhantomData<&'arena T>, _drops: PhantomData, chunks: RefCell>>, head: Cell<*mut T>, tail: Cell<*mut T>, } - impl Default for TypedArena { + impl<'arena, T> Default for TypedArena<'arena, T> { fn default() -> Self { Self::new() } } - impl TypedArena { + impl<'arena, T> TypedArena<'arena, T> { pub const fn new() -> Self { Self { + _lives: PhantomData, _drops: PhantomData, chunks: RefCell::new(Vec::new()), head: Cell::new(ptr::null_mut()), @@ -111,7 +113,7 @@ pub mod typed_arena { } #[allow(clippy::mut_from_ref)] - pub fn alloc(&self, value: T) -> &mut T { + pub fn alloc(&'arena self, value: T) -> &'arena mut T { if self.head == self.tail { self.grow(1); } @@ -165,9 +167,9 @@ pub mod typed_arena { } } - unsafe impl Send for TypedArena {} + unsafe impl<'arena, T: Send> Send for TypedArena<'arena, T> {} - unsafe impl<#[may_dangle] T> Drop for TypedArena { + unsafe impl<'arena, #[may_dangle] T> Drop for TypedArena<'arena, T> { fn drop(&mut self) { let mut chunks = self.chunks.borrow_mut(); @@ -194,24 +196,27 @@ pub mod dropless_arena { use core::{ alloc::Layout, cell::{Cell, RefCell}, + marker::PhantomData, mem, ptr, slice, }; - pub struct DroplessArena { + pub struct DroplessArena<'arena> { + _lives: PhantomData<&'arena u8>, chunks: RefCell>>, head: Cell<*mut u8>, tail: Cell<*mut u8>, } - impl Default for DroplessArena { + impl Default for DroplessArena<'_> { fn default() -> Self { Self::new() } } - impl DroplessArena { + impl<'arena> DroplessArena<'arena> { pub const fn new() -> Self { Self { + _lives: PhantomData, chunks: RefCell::new(Vec::new()), head: Cell::new(ptr::null_mut()), tail: Cell::new(ptr::null_mut()), @@ -224,7 +229,7 @@ pub mod dropless_arena { /// - Panics if T implements [Drop] /// - Panics if T is zero-sized #[allow(clippy::mut_from_ref)] - pub fn alloc(&self, value: T) -> &mut T { + pub fn alloc(&'arena self, value: T) -> &'arena mut T { assert!(!mem::needs_drop::()); assert!(mem::size_of::() != 0); @@ -244,7 +249,7 @@ pub mod dropless_arena { /// - Panics if T is zero-sized /// - Panics if the slice is empty #[allow(clippy::mut_from_ref)] - pub fn alloc_slice(&self, slice: &[T]) -> &mut [T] { + pub fn alloc_slice(&'arena self, slice: &[T]) -> &'arena mut [T] { assert!(!mem::needs_drop::()); assert!(mem::size_of::() != 0); assert!(!slice.is_empty()); @@ -261,7 +266,7 @@ pub mod dropless_arena { /// /// # Panics /// Panics if the string is empty. - pub fn alloc_str(&self, string: &str) -> &str { + pub fn alloc_str(&'arena self, string: &str) -> &'arena str { let slice = self.alloc_slice(string.as_bytes()); // Safety: This is a clone of the input string, which was valid @@ -272,7 +277,7 @@ pub mod dropless_arena { /// /// # Panics /// Panics if the provided [Layout] has size 0 - pub fn alloc_raw(&self, layout: Layout) -> *mut u8 { + pub fn alloc_raw(&'arena self, layout: Layout) -> *mut u8 { /// Rounds the given size (or pointer value) *up* to the given alignment fn align_up(size: usize, align: usize) -> usize { (size + align - 1) & !(align - 1) @@ -337,7 +342,7 @@ pub mod dropless_arena { } } - unsafe impl Send for DroplessArena {} + unsafe impl<'arena> Send for DroplessArena<'arena> {} #[cfg(test)] mod tests; diff --git a/compiler/cl-structures/src/intern.rs b/compiler/cl-structures/src/intern.rs index 8329a97..31370a2 100644 --- a/compiler/cl-structures/src/intern.rs +++ b/compiler/cl-structures/src/intern.rs @@ -115,13 +115,12 @@ pub mod string_interner { use cl_arena::dropless_arena::DroplessArena; use std::{ collections::HashSet, - ptr::addr_of, sync::{OnceLock, RwLock}, }; /// A string interner hands out [Interned] copies of each unique string given to it. pub struct StringInterner<'a> { - arena: &'a DroplessArena, + arena: DroplessArena<'a>, keys: RwLock>, } @@ -129,12 +128,11 @@ pub mod string_interner { /// Gets a reference to a global string interner whose [Interned] strings are `'static` pub fn global() -> &'static Self { static GLOBAL_INTERNER: OnceLock> = OnceLock::new(); - static mut ARENA: DroplessArena = DroplessArena::new(); // SAFETY: The RwLock within the interner's `keys` protects the arena // from being modified concurrently. GLOBAL_INTERNER.get_or_init(|| StringInterner { - arena: unsafe { &*addr_of!(ARENA) }, + arena: DroplessArena::new(), keys: Default::default(), }) } @@ -142,7 +140,7 @@ pub mod string_interner { impl<'a> StringInterner<'a> { /// Creates a new [StringInterner] backed by the provided [DroplessArena] - pub fn new(arena: &'a DroplessArena) -> Self { + pub fn new(arena: DroplessArena<'a>) -> Self { Self { arena, keys: RwLock::new(HashSet::new()) } } @@ -151,7 +149,7 @@ pub mod string_interner { /// /// # Blocks /// This function blocks when the interner is held by another thread. - pub fn get_or_insert(&self, value: &str) -> Interned<'a, str> { + pub fn get_or_insert(&'a self, value: &str) -> Interned<'a, str> { let Self { arena, keys } = self; // Safety: Holding this write guard for the entire duration of this @@ -173,7 +171,7 @@ pub mod string_interner { /// Gets a reference to the interned copy of the given value, if it exists /// # Blocks /// This function blocks when the interner is held by another thread. - pub fn get(&self, value: &str) -> Option> { + pub fn get(&'a self, value: &str) -> Option> { let keys = self.keys.read().expect("should not be poisoned"); keys.get(value).copied().map(Interned::new) } @@ -243,13 +241,13 @@ pub mod typed_interner { /// /// See the [module-level documentation](self) for more information. pub struct TypedInterner<'a, T: Eq + Hash> { - arena: &'a TypedArena, + arena: TypedArena<'a, T>, keys: RwLock>, } impl<'a, T: Eq + Hash> TypedInterner<'a, T> { /// Creates a new [TypedInterner] backed by the provided [TypedArena] - pub fn new(arena: &'a TypedArena) -> Self { + pub fn new(arena: TypedArena<'a, T>) -> Self { Self { arena, keys: RwLock::new(HashSet::new()) } } @@ -257,7 +255,7 @@ pub mod typed_interner { /// /// # Blocks /// This function blocks when the interner is held by another thread. - pub fn get_or_insert(&self, value: T) -> Interned<'a, T> { + pub fn get_or_insert(&'a self, value: T) -> Interned<'a, T> { let Self { arena, keys } = self; // Safety: Locking the keyset for the entire duration of this function