Skip to content

Commit

Permalink
perf(check): Re-use the allocations for variables
Browse files Browse the repository at this point in the history
  • Loading branch information
Marwes committed Jan 31, 2019
1 parent 5b91b6d commit d569cdc
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 26 deletions.
10 changes: 9 additions & 1 deletion base/src/fixed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ impl<K: Eq + Hash, V> FixedMap<K, V> {
}

pub fn clear(&mut self) {
error!("Clear");
self.map.borrow_mut().clear();
}

Expand Down Expand Up @@ -210,6 +209,11 @@ impl<V> FixedVecMap<V> {
self.map.get_mut().retain(|i, _| i < index);
self.values.truncate(index);
}

pub fn drain<'a>(&'a mut self) -> impl Iterator<Item = V> + 'a {
self.map.get_mut().clear();
self.values.drain()
}
}

impl<V> Index<usize> for FixedVecMap<V> {
Expand Down Expand Up @@ -368,6 +372,10 @@ impl<T> Buffer<T> {
}
}

fn drain<'a>(&'a mut self) -> impl Iterator<Item = T> + 'a {
self.values.get_mut().drain(..).flat_map(|vec| vec)
}

fn pop(&mut self) -> Option<T> {
let values = self.values.get_mut();
let out = values.last_mut().and_then(|vec| vec.pop());
Expand Down
10 changes: 10 additions & 0 deletions base/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1224,6 +1224,7 @@ where
}
}

#[derive(Clone)]
struct ArcTypeInner<Id = Symbol> {
typ: Type<Id, ArcType<Id>>,
flags: Flags,
Expand Down Expand Up @@ -1929,6 +1930,15 @@ where
}

impl<Id> ArcType<Id> {
pub fn set(into: &mut Self, typ: Type<Id, Self>)
where
Id: Clone,
{
let into = Arc::make_mut(&mut into.typ);
into.flags = Flags::from_type(&typ);
into.typ = typ;
}

/// Returns the lowest level which this type contains. The level informs from where type
/// variables where created.
pub fn level(&self) -> u32 {
Expand Down
4 changes: 3 additions & 1 deletion benches/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@ fn typecheck_benchmark(c: &mut Criterion) {
b.iter(|| {
let vm = new_vm();
let mut compiler = Compiler::new();
compiler.load_file(&vm, "examples/lisp/lisp.glu").unwrap()
compiler
.load_file(&vm, "examples/lisp/lisp.glu")
.unwrap_or_else(|err| panic!("{}", err))
})
});
}
Expand Down
8 changes: 8 additions & 0 deletions check/src/kindcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,14 @@ impl Substitutable for ArcKind {
Kind::variable(x)
}

fn into_variable(&mut self, x: Self::Variable) {
*ArcKind::make_mut(self) = Kind::Variable(x);
}

fn is_unique(self_: &Self) -> bool {
ArcKind::strong_count(self_) == 1
}

fn get_var(&self) -> Option<&u32> {
match **self {
Kind::Variable(ref var) => Some(var),
Expand Down
67 changes: 43 additions & 24 deletions check/src/substitution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::base::{
fixed::{FixedVec, FixedVecMap},
kind::ArcKind,
symbol::Symbol,
types::{self, ArcType, Flags, FlagsVisitor, Skolem, Type, TypeContext, TypeExt, Walker},
types::{self, ArcType, Flags, FlagsVisitor, Skolem, Type, TypeContext, Walker},
};
use crate::typ::RcType;

Expand Down Expand Up @@ -45,6 +45,7 @@ where
types: FixedVecMap<T>,
factory: T::Factory,
interner: T::Interner,
variable_cache: RefCell<Vec<T>>,
}

impl<T> TypeContext<Symbol, T> for Substitution<T>
Expand Down Expand Up @@ -120,6 +121,10 @@ pub trait Substitutable: Sized {
/// Constructs a new object from its variable type
fn from_variable(subs: &Substitution<Self>, x: Self::Variable) -> Self;

fn into_variable(&mut self, x: Self::Variable);

fn is_unique(self_: &Self) -> bool;

/// Retrieves the variable if `self` is a variable otherwise returns `None`
fn get_var(&self) -> Option<&Self::Variable>;

Expand Down Expand Up @@ -263,6 +268,7 @@ where
types: FixedVecMap::new(),
factory: factory,
interner,
variable_cache: Default::default(),
}
}

Expand All @@ -288,12 +294,37 @@ where
self.types.insert(var as usize, t.into());
}

/// Assumes that no variables unified with anything (but variables < level may exist)
pub fn clear_from(&mut self, level: u32) {
self.union = RefCell::new(QuickFindUf::new(0));
let mut u = self.union.borrow_mut();
for _ in 0..level {
u.insert(UnionByLevel {
..UnionByLevel::default()
});
}

let mut variable_cache = self.variable_cache.borrow_mut();
// Since no types should be unified with anything we can remove all of this and reuse the
// unique values
variable_cache.extend(self.types.drain().filter(T::is_unique));
while self.variables.len() > level as usize {
variable_cache.push(self.variables.pop().unwrap());
}
}

/// Creates a new variable
pub fn new_var(&self) -> T
where
T: Clone,
{
self.new_var_fn(|var| T::from_variable(self, self.factory.new(var)))
self.new_var_fn(|var| match self.variable_cache.borrow_mut().pop() {
Some(mut typ) => {
T::into_variable(&mut typ, self.factory.new(var));
typ
}
None => T::from_variable(self, self.factory.new(var)),
})
}

pub fn new_var_fn<F>(&self, f: F) -> T
Expand Down Expand Up @@ -448,7 +479,16 @@ impl<T: Substitutable + PartialEq + Clone> Substitution<T> {

impl Substitution<RcType> {
pub fn new_skolem(&self, name: Symbol, kind: ArcKind) -> RcType {
self.new_var_fn(|id| (&*self).skolem(Skolem { name, id, kind }))
self.new_var_fn(|id| {
let skolem = Skolem { name, id, kind };
match self.variable_cache.borrow_mut().pop() {
Some(mut typ) => {
RcType::set(&mut typ, Type::Skolem(skolem));
typ
}
None => (&*self).skolem(skolem),
}
})
}

pub fn zonk(&self, typ: &RcType) -> RcType {
Expand All @@ -468,25 +508,4 @@ impl Substitution<RcType> {
pub fn bind_arc(&self, typ: &RcType) -> ArcType {
typ.clone()
}

/// Assumes that all variables < `level` are not unified with anything
pub fn clear_from(&mut self, level: u32) {
self.union = RefCell::new(QuickFindUf::new(0));
let mut u = self.union.borrow_mut();
for _ in 0..level {
u.insert(UnionByLevel {
..UnionByLevel::default()
});
}
self.types.truncate(level as usize);
for t in self.variables.iter().skip(level as usize) {
assert_eq!(
RcType::strong_count(t),
1,
"Variable {} is not unbound at this stage",
t
);
}
self.variables.truncate(level as usize);
}
}
1 change: 1 addition & 0 deletions check/src/typecheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2153,6 +2153,7 @@ impl<'a> Typecheck<'a> {
self.generalize_type_errors(&mut errors);
self.errors = errors;

// Clear any location which could have skolems or variables left in them
self.named_variables.clear();
self.implicit_resolver.implicit_vars.clear();

Expand Down
9 changes: 9 additions & 0 deletions check/src/unify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,15 @@ mod test {
fn from_variable(_: &Substitution<Self>, var: u32) -> TType {
TType(Box::new(Type::Variable(var)))
}

fn into_variable(&mut self, x: Self::Variable) {
*self.0 = Type::Variable(x);
}

fn is_unique(self_: &Self) -> bool {
true
}

fn get_var(&self) -> Option<&u32> {
match *self.0 {
Type::Variable(ref var) => Some(var),
Expand Down
8 changes: 8 additions & 0 deletions check/src/unify_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,14 @@ impl Substitutable for RcType<Symbol> {
subs.variable(var)
}

fn into_variable(&mut self, x: Self::Variable) {
Self::set(self, Type::Variable(x))
}

fn is_unique(self_: &Self) -> bool {
RcType::strong_count(self_) == 1
}

fn get_var(&self) -> Option<&TypeVariable> {
match **self {
Type::Variable(ref var) => Some(var),
Expand Down

0 comments on commit d569cdc

Please sign in to comment.