From 54d88f88c6bbc001ff84902c2b03d9db01d91dee Mon Sep 17 00:00:00 2001 From: Troy Hinckley Date: Fri, 22 Dec 2023 12:27:22 -0600 Subject: [PATCH] Implement `Rt<[T; N]>` This will remove even more allocations from function calls --- src/core/gc/root.rs | 46 ++++++++++++++++++++++++++++++++++++++++---- src/core/gc/trace.rs | 8 ++++++++ src/fns.rs | 20 ++++++++----------- src/interpreter.rs | 8 +++----- 4 files changed, 61 insertions(+), 21 deletions(-) diff --git a/src/core/gc/root.rs b/src/core/gc/root.rs index 18cb912a..3333e579 100644 --- a/src/core/gc/root.rs +++ b/src/core/gc/root.rs @@ -212,6 +212,20 @@ where } } +impl<'new, T, const N: usize> WithLifetime<'new> for [T; N] +where + T: WithLifetime<'new>, +{ + type Out = [>::Out; N]; + unsafe fn with_lifetime(self) -> Self::Out { + // work around since we can't transmute arrays + let ptr = &self as *const [T; N] as *const Self::Out; + let value = unsafe { ptr.read() }; + std::mem::forget(self); + value + } +} + impl<'new, T> WithLifetime<'new> for Vec where T: WithLifetime<'new>, @@ -445,6 +459,34 @@ impl Rt> { } } +impl Index for Rt<[T; N]> +where + [Rt]: Index, +{ + type Output = <[Rt] as Index>::Output; + + fn index(&self, index: I) -> &Self::Output { + let slice = unsafe { std::mem::transmute::<&[T], &[Rt]>(&self.inner) }; + Index::index(slice, index) + } +} + +impl IndexMut for Rt<[T; N]> +where + [Rt]: IndexMut, +{ + fn index_mut(&mut self, index: I) -> &mut Self::Output { + let slice = unsafe { std::mem::transmute::<&mut [T], &mut [Rt]>(&mut self.inner) }; + IndexMut::index_mut(slice, index) + } +} + +impl AsRef<[Rt]> for Rt<[T; N]> { + fn as_ref(&self) -> &[Rt] { + unsafe { std::mem::transmute::<&[T], &[Rt]>(&self.inner) } + } +} + impl Rt> { // This is not safe to expose pub(crate) because you could call pop and get // an owned Rt @@ -465,10 +507,6 @@ impl Rt> { self.as_mut_ref().pop(); } - pub(crate) fn clear(&mut self) { - self.as_mut_ref().clear(); - } - pub(crate) fn swap_remove(&mut self, index: usize) { self.as_mut_ref().swap_remove(index); } diff --git a/src/core/gc/trace.rs b/src/core/gc/trace.rs index 5fba2bed..4a60b3ec 100755 --- a/src/core/gc/trace.rs +++ b/src/core/gc/trace.rs @@ -38,6 +38,14 @@ impl Trace for [T] { } } +impl Trace for [T; N] { + fn trace(&self, stack: &mut Vec) { + for x in self { + x.trace(stack); + } + } +} + impl Trace for Vec { fn trace(&self, stack: &mut Vec) { for x in self { diff --git a/src/fns.rs b/src/fns.rs index 016454fe..76a588c0 100644 --- a/src/fns.rs +++ b/src/fns.rs @@ -436,18 +436,16 @@ fn sort<'ob>( root!(tmp, nil(), cx); root!(vec, cx); - // TODO: Use an array - root!(args, Vec::new(), cx); + root!(args, [nil(), nil()], cx); // A simple insertion sort // TODO: use a better sort like tim sort for i in 1..len { tmp.set(&vec[i]); let mut j = i; while j > 0 { - args.clear(); - args.push(&vec[j - 1]); - args.push(&*tmp); - match predicate.call(args, None, env, cx) { + args[0].set(&vec[j - 1]); + args[1].set(&*tmp); + match predicate.call(&args[..], None, env, cx) { Ok(cmp) => { if cmp != nil() { break; @@ -690,21 +688,19 @@ fn maphash( } }; - // TODO: Use array - root!(args, Vec::new(), cx); + root!(args, [nil(), nil()], cx); loop { { let mut view = table.bind(cx).untag().try_borrow_mut()?; let Some(idx) = get_idx(&mut view) else { break }; let (key, val) = view.get_index(idx).unwrap(); - args.push(*key); - args.push(*val); + args[0].set(*key); + args[1].set(*val); } - if let Err(e) = function.call(args, None, env, cx) { + if let Err(e) = function.call(&args[..], None, env, cx) { table.bind(cx).untag().try_borrow_mut().unwrap().iter_next = 0; return Err(e.into()); } - args.clear(); } table.bind(cx).untag().try_borrow_mut().unwrap().iter_next = 0; Ok(false) diff --git a/src/interpreter.rs b/src/interpreter.rs index 4d23dfb6..678252b4 100755 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -215,11 +215,9 @@ impl Interpreter<'_, '_> { let closure_fn: Result<&Rt>, _> = closure_fn.try_into(); if let Ok(closure_fn) = closure_fn { root!(closure_fn, cx); - // TODO: use array - root!(args, Vec::new(), cx); - args.push(form.bind(cx)); - args.push(env); - return closure_fn.call(args, None, self.env, cx); + let args = [form.bind(cx), env]; + root!(args, cx); + return closure_fn.call(&args[..], None, self.env, cx); } } }