mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 06:14:46 +00:00
Cache many layouts into interner by default
This commit is contained in:
parent
b60d5c0251
commit
b1424afefd
2 changed files with 81 additions and 4 deletions
|
@ -3,6 +3,7 @@
|
||||||
use std::{
|
use std::{
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
hash::{BuildHasher, Hash, Hasher},
|
hash::{BuildHasher, Hash, Hasher},
|
||||||
|
marker::PhantomData,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -23,6 +24,25 @@ impl<T> Clone for Interned<T> {
|
||||||
|
|
||||||
impl<T> Copy for Interned<T> {}
|
impl<T> Copy for Interned<T> {}
|
||||||
|
|
||||||
|
impl<T> Interned<T> {
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The index is not guaranteed to exist. Use this only when creating an interner with constant
|
||||||
|
/// indices, with the variant that `insert` returns a monotonically increasing index.
|
||||||
|
///
|
||||||
|
/// For example:
|
||||||
|
///
|
||||||
|
/// ```ignore(illustrative)
|
||||||
|
/// let reserved_interned = Interned::from_reserved_index(0);
|
||||||
|
/// let interner = GlobalInterner::with_capacity(1);
|
||||||
|
/// let inserted = interner.insert("something");
|
||||||
|
/// assert_eq!(reserved_interned, inserted);
|
||||||
|
/// ```
|
||||||
|
pub const unsafe fn from_reserved_index(index: usize) -> Self {
|
||||||
|
Self(index, PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A concurrent interner, suitable for usage between threads.
|
/// A concurrent interner, suitable for usage between threads.
|
||||||
///
|
///
|
||||||
/// The interner does not currently maintain its own arena; you will have to supply
|
/// The interner does not currently maintain its own arena; you will have to supply
|
||||||
|
@ -143,6 +163,10 @@ impl<'a, K: Hash + Eq> GlobalInterner<'a, K> {
|
||||||
let Interned(index, _) = interned;
|
let Interned(index, _) = interned;
|
||||||
self.vec.read()[index]
|
self.vec.read()[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.vec.read().is_empty()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, K: Hash + Eq> ThreadLocalInterner<'a, K> {
|
impl<'a, K: Hash + Eq> ThreadLocalInterner<'a, K> {
|
||||||
|
@ -201,6 +225,10 @@ impl<'a, K> SingleThreadedInterner<'a, K> {
|
||||||
vec: RwLock::new(vec),
|
vec: RwLock::new(vec),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.vec.is_empty()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, K: Hash + Eq> Interner<'a, K> for SingleThreadedInterner<'a, K> {
|
impl<'a, K: Hash + Eq> Interner<'a, K> for SingleThreadedInterner<'a, K> {
|
||||||
|
|
|
@ -1,10 +1,57 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use roc_builtins::bitcode::IntWidth;
|
||||||
use roc_intern::{GlobalInterner, Interned, Interner, SingleThreadedInterner, ThreadLocalInterner};
|
use roc_intern::{GlobalInterner, Interned, Interner, SingleThreadedInterner, ThreadLocalInterner};
|
||||||
|
|
||||||
use super::Layout;
|
use super::{Builtin, Layout};
|
||||||
|
|
||||||
pub trait LayoutInterner<'a>: Interner<'a, Layout<'a>> {}
|
macro_rules! cache_interned_layouts {
|
||||||
|
($($i:literal, $name:ident, $layout:expr)*; $total_constants:literal) => {
|
||||||
|
pub trait LayoutInterner<'a>: Interner<'a, Layout<'a>> {
|
||||||
|
$(
|
||||||
|
const $name: Interned<Layout<'a>> = unsafe { Interned::from_reserved_index($i) };
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fill_reserved_layouts<'a>(interner: &mut STLayoutInterner<'a>) {
|
||||||
|
assert!(interner.0.is_empty());
|
||||||
|
$(
|
||||||
|
interner.0.insert(&$layout);
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn _are_constants_in_order_non_redundant() -> usize {
|
||||||
|
let mut total_seen = 0;
|
||||||
|
$(total_seen += ($i * 0) + 1;)*
|
||||||
|
match 0usize {
|
||||||
|
$($i => {})*
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
total_seen
|
||||||
|
}
|
||||||
|
|
||||||
|
const _ASSERT_NON_REDUNDANT_CONSTANTS: () =
|
||||||
|
assert!(_are_constants_in_order_non_redundant() == $total_constants);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cache_interned_layouts! {
|
||||||
|
0, VOID, Layout::VOID
|
||||||
|
1, UNIT, Layout::UNIT
|
||||||
|
2, BOOL, Layout::Builtin(Builtin::Bool)
|
||||||
|
3, U8, Layout::Builtin(Builtin::Int(IntWidth::U8))
|
||||||
|
4, U16, Layout::Builtin(Builtin::Int(IntWidth::U16))
|
||||||
|
5, U32, Layout::Builtin(Builtin::Int(IntWidth::U32))
|
||||||
|
6, U64, Layout::Builtin(Builtin::Int(IntWidth::U64))
|
||||||
|
7, U128, Layout::Builtin(Builtin::Int(IntWidth::U128))
|
||||||
|
8, I8, Layout::Builtin(Builtin::Int(IntWidth::I8))
|
||||||
|
9, I16, Layout::Builtin(Builtin::Int(IntWidth::I16))
|
||||||
|
10, I32, Layout::Builtin(Builtin::Int(IntWidth::I32))
|
||||||
|
11, I64, Layout::Builtin(Builtin::Int(IntWidth::I64))
|
||||||
|
12, I128, Layout::Builtin(Builtin::Int(IntWidth::I128))
|
||||||
|
|
||||||
|
; 13
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct GlobalLayoutInterner<'a>(Arc<GlobalInterner<'a, Layout<'a>>>);
|
pub struct GlobalLayoutInterner<'a>(Arc<GlobalInterner<'a, Layout<'a>>>);
|
||||||
|
@ -15,7 +62,7 @@ pub struct STLayoutInterner<'a>(SingleThreadedInterner<'a, Layout<'a>>);
|
||||||
|
|
||||||
impl<'a> GlobalLayoutInterner<'a> {
|
impl<'a> GlobalLayoutInterner<'a> {
|
||||||
pub fn with_capacity(capacity: usize) -> Self {
|
pub fn with_capacity(capacity: usize) -> Self {
|
||||||
Self(GlobalInterner::with_capacity(capacity))
|
STLayoutInterner::with_capacity(capacity).into_global()
|
||||||
}
|
}
|
||||||
pub fn fork(&self) -> TLLayoutInterner<'a> {
|
pub fn fork(&self) -> TLLayoutInterner<'a> {
|
||||||
TLLayoutInterner(self.0.fork())
|
TLLayoutInterner(self.0.fork())
|
||||||
|
@ -30,7 +77,9 @@ impl<'a> GlobalLayoutInterner<'a> {
|
||||||
|
|
||||||
impl<'a> STLayoutInterner<'a> {
|
impl<'a> STLayoutInterner<'a> {
|
||||||
pub fn with_capacity(capacity: usize) -> Self {
|
pub fn with_capacity(capacity: usize) -> Self {
|
||||||
Self(SingleThreadedInterner::with_capacity(capacity))
|
let mut interner = Self(SingleThreadedInterner::with_capacity(capacity));
|
||||||
|
fill_reserved_layouts(&mut interner);
|
||||||
|
interner
|
||||||
}
|
}
|
||||||
pub fn into_global(self) -> GlobalLayoutInterner<'a> {
|
pub fn into_global(self) -> GlobalLayoutInterner<'a> {
|
||||||
GlobalLayoutInterner(self.0.into_global())
|
GlobalLayoutInterner(self.0.into_global())
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue