mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 13:59:08 +00:00
Store interened wrapped layout of lambda set on LambdaSet struct
The `LambdaSet` struct is frequently used independently to examine how a lambda set should be packed or unpacked. However, it is also often converted into a full layout via `Layout::LambdaSet(LambdaSet)` to be a part of function arguments, for example. In preparing to intern all layouts, we need a way to cheaply go from a `lambda_set` to an interned `Layout::LambdaSet(lambda_set)`, since this is a very common operation. The proposed solution is to keep the wrapped layout cached on `LambdaSet` itself, which this PR does. The tricky bit of inserting a lambda set is we need to fill in the interned `full_layout` only after the lambda set is inserted, but we don't want to allocate a new interned slot if the same lambda set layout has already been inserted with a different `full_layout` slot. For example, if we insert `LambdaSet { set : [A] }` twice in two different threads, we want the `full_layout` they map to to be the same. So we nede to check if an interned representation with a full_layout exists, before we allocate a new full_layout and insert a fresh lambda set. So, - check if the "normalized" lambda set (with a void full_layout slot) maps to an inserted lambda set in - in a thread-local cache, or globally - if so, use that one immediately - otherwise, allocate a new (global) slot, intern the lambda set, and then fill the slot in - save the interned layout and lambda set mapping thread-locally
This commit is contained in:
parent
ce717dca8b
commit
26f08c999c
3 changed files with 177 additions and 18 deletions
|
@ -1,4 +1,5 @@
|
|||
use crate::ir::Parens;
|
||||
use crate::layout::intern::InLayouts;
|
||||
use bitvec::vec::BitVec;
|
||||
use bumpalo::collections::Vec;
|
||||
use bumpalo::Bump;
|
||||
|
@ -1336,9 +1337,12 @@ impl<'a> LambdaName<'a> {
|
|||
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct LambdaSet<'a> {
|
||||
/// collection of function names and their closure arguments
|
||||
pub(crate) set: &'a [(Symbol, &'a [InLayout<'a>])],
|
||||
// Double reference to cut from fat slice (16 bytes) to 8 bytes
|
||||
pub(crate) set: &'a &'a [(Symbol, &'a [InLayout<'a>])],
|
||||
/// how the closure will be represented at runtime
|
||||
pub(crate) representation: InLayout<'a>,
|
||||
/// The interned [Layout] representation of the lambda set, as `Layout::LambdaSet(self)`.
|
||||
pub(crate) full_layout: InLayout<'a>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -1864,21 +1868,21 @@ impl<'a> LambdaSet<'a> {
|
|||
);
|
||||
let representation = env.cache.interner.insert(representation);
|
||||
|
||||
Cacheable(
|
||||
Ok(LambdaSet {
|
||||
set: set.into_bump_slice(),
|
||||
representation,
|
||||
}),
|
||||
criteria,
|
||||
)
|
||||
let lambda_set = env
|
||||
.cache
|
||||
.interner
|
||||
.insert_lambda_set(env.arena.alloc(set.into_bump_slice()), representation);
|
||||
|
||||
Cacheable(Ok(lambda_set), criteria)
|
||||
}
|
||||
ResolvedLambdaSet::Unbound => {
|
||||
// The lambda set is unbound which means it must be unused. Just give it the empty lambda set.
|
||||
// See also https://github.com/roc-lang/roc/issues/3163.
|
||||
cacheable(Ok(LambdaSet {
|
||||
set: &[],
|
||||
representation: env.cache.interner.insert(Layout::UNIT),
|
||||
}))
|
||||
let lambda_set = env
|
||||
.cache
|
||||
.interner
|
||||
.insert_lambda_set(&(&[] as &[(Symbol, &[InLayout])]), InLayouts::UNIT);
|
||||
cacheable(Ok(lambda_set))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4384,6 +4388,8 @@ where
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::layout::intern::InLayouts;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
|
@ -4391,8 +4397,9 @@ mod test {
|
|||
let mut interner = STLayoutInterner::with_capacity(4);
|
||||
|
||||
let lambda_set = LambdaSet {
|
||||
set: &[(Symbol::LIST_MAP, &[])],
|
||||
set: &(&[(Symbol::LIST_MAP, &[] as &[InLayout])] as &[(Symbol, &[InLayout])]),
|
||||
representation: interner.insert(Layout::UNIT),
|
||||
full_layout: InLayouts::VOID,
|
||||
};
|
||||
|
||||
let a = &[Layout::UNIT] as &[_];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue