diff --git a/src/env.rs b/src/env.rs index b425837..7d54dc2 100644 --- a/src/env.rs +++ b/src/env.rs @@ -11,6 +11,7 @@ pub struct Env<'gc, K: Hash + Eq + Collect<'gc>, V: Collect<'gc>> { let_: Gc<'gc, LetEnv<'gc, V>>, with: Gc<'gc, With<'gc, K, V>>, args: Vec, + gc_alloced: Vec>, last: Option>>, } @@ -59,16 +60,17 @@ impl<'gc, K: Hash + Eq + Clone + Collect<'gc>, V: Clone + Collect<'gc>> Env<'gc, }, ), args: Vec::new(), + gc_alloced: Vec::new(), last: None, }, ) } - pub fn lookup_arg(&self, level: usize) -> V { - self.args[self.args.len() - level - 1].clone() + pub fn lookup_arg(&self, level: usize) -> &V { + &self.args[self.args.len() - level - 1] } - pub fn lookup_let(&self, level: usize, idx: usize) -> V { + pub fn lookup_let(&self, level: usize, idx: usize) -> &V { self.let_.lookup(level, idx) } @@ -90,6 +92,7 @@ impl<'gc, K: Hash + Eq + Clone + Collect<'gc>, V: Clone + Collect<'gc>> Env<'gc, let_: self.let_, with: self.with, last: Some(self), + gc_alloced: Vec::new(), args }, ) @@ -107,6 +110,7 @@ impl<'gc, K: Hash + Eq + Clone + Collect<'gc>, V: Clone + Collect<'gc>> Env<'gc, let_: self.let_.enter_let(map, mc), with: self.with, args: self.args.clone(), + gc_alloced: Vec::new(), last: Some(self), }, ) @@ -124,11 +128,19 @@ impl<'gc, K: Hash + Eq + Clone + Collect<'gc>, V: Clone + Collect<'gc>> Env<'gc, let_: self.let_, with: self.with.enter(map, mc), args: self.args.clone(), + gc_alloced: Vec::new(), last: Some(self), }, ) } + #[inline] + pub fn alloc_gc(&mut self, val: V, mc: &Mutation<'gc>) -> &'gc V { + let gc = Gc::new(mc, val); + self.gc_alloced.push(gc); + gc.as_ref() + } + pub fn leave(&self) -> Gc<'gc, Self> { self.last.unwrap() } @@ -145,13 +157,13 @@ impl<'gc, V: Clone + Collect<'gc>> LetEnv<'gc, V> { ) } - pub fn lookup(&self, level: usize, idx: usize) -> V { + pub fn lookup(&self, level: usize, idx: usize) -> &V { let mut cur = self; for _ in 0..level { let last = cur.last.unwrap(); cur = last.as_ref(); } - cur.map[idx].clone() + &cur.map[idx] } pub fn enter_let( diff --git a/src/jit/helpers.rs b/src/jit/helpers.rs index 927b79f..8d8a24f 100644 --- a/src/jit/helpers.rs +++ b/src/jit/helpers.rs @@ -56,7 +56,7 @@ impl<'ctx> Helpers<'ctx> { let new_thunk = module.add_function( "new_thunk", - value_type.fn_type(&[ptr_type.into(), ptr_type.into()], false), + value_type.fn_type(&[ptr_type.into(), ptr_type.into(), ptr_type.into()], false), None, ); let debug = module.add_function( @@ -110,6 +110,7 @@ impl<'ctx> Helpers<'ctx> { value_type.into(), ptr_type.into(), ptr_type.into(), + ptr_type.into(), ], false, ), @@ -350,6 +351,7 @@ extern "C" fn helper_call<'gc>( func: JITValue, arg: JITValue, vm: *const VM<'gc>, + env: *mut VmEnv<'gc>, mc: *const Mutation<'gc>, ) -> JITValue { let vm = unsafe { vm.as_ref() }.unwrap(); @@ -358,7 +360,8 @@ extern "C" fn helper_call<'gc>( match func.tag { ValueTag::Function => { let func = Value::from(func).unwrap_func(); - func.call_compile(arg, vm, mc).unwrap().into() + let env = unsafe { &mut *env }; + env.alloc_gc(func.call_compile(arg, vm, mc).unwrap(), mc).into() } _ => todo!(), } @@ -403,15 +406,17 @@ extern "C" fn helper_force<'gc>( .unwrap() .compile_seq(opcodes.iter().copied().rev(), vm) .unwrap(); - let val = unsafe { func.call(env.as_ref() as *const _, mc as *const _) }; + let val = unsafe { func(env.as_ref() as *const _, mc as *const _) }; thunk.insert_value(val.into(), mc); val } -extern "C" fn helper_new_thunk(opcodes: *const OpCodes, mc: *const Mutation) -> JITValue { - Value::Thunk(Thunk::new( +extern "C" fn helper_new_thunk<'gc>(opcodes: *const OpCodes, env: *mut VmEnv<'gc>, mc: *const Mutation<'gc>) -> JITValue { + let mc = unsafe { &*mc }; + let env = unsafe { &mut *env }; + env.alloc_gc(Value::Thunk(Thunk::new( unsafe { opcodes.as_ref() }.unwrap(), - unsafe { mc.as_ref() }.unwrap(), - )) + mc + )), mc) .into() } diff --git a/src/jit/mod.rs b/src/jit/mod.rs index ef5cd3f..631a3dd 100644 --- a/src/jit/mod.rs +++ b/src/jit/mod.rs @@ -1,10 +1,11 @@ +use std::marker::PhantomData; use std::ops::Deref; use gc_arena::{Collect, Gc, Mutation}; use inkwell::OptimizationLevel; use inkwell::builder::Builder; use inkwell::context::Context; -use inkwell::execution_engine::{ExecutionEngine, JitFunction}; +use inkwell::execution_engine::ExecutionEngine; use inkwell::module::Module; use inkwell::values::{BasicValueEnum, FunctionValue, PointerValue}; @@ -72,37 +73,13 @@ impl<'gc> From for Value<'gc> { } impl From<&Value<'_>> for JITValue { - fn from(value: &Value<'_>) -> Self { - match *value { - Value::Int(int) => JITValue { - tag: ValueTag::Int, - data: JITValueData { int }, - }, - Value::Func(func) => JITValue { - tag: ValueTag::Function, - data: JITValueData { - ptr: Gc::as_ptr(func) as *const _, - }, - }, - Value::Thunk(ref thunk) => JITValue { - tag: ValueTag::Thunk, - data: JITValueData { - ptr: Gc::as_ptr(thunk.thunk) as *const _, - }, - }, - _ => todo!(), - } - } -} - -impl From> for JITValue { - fn from(value: Value) -> Self { + fn from(value: &Value) -> Self { match value { - Value::Int(int) => JITValue { + &Value::Int(int) => JITValue { tag: ValueTag::Int, data: JITValueData { int }, }, - Value::Func(func) => JITValue { + &Value::Func(func) => JITValue { tag: ValueTag::Function, data: JITValueData { ptr: Gc::as_ptr(func) as *const _, @@ -119,33 +96,25 @@ impl From> for JITValue { } } -pub struct JITFunc<'gc>( - JitFunction<'gc, unsafe extern "C" fn(*const VmEnv<'gc>, *const Mutation<'gc>) -> JITValue>, -); +pub struct JITFunc<'gc>(F<'gc>, PhantomData) -> &'gc F<'gc>>); +type F<'gc> = unsafe extern "C" fn(*const VmEnv<'gc>, *const Mutation<'gc>) -> JITValue; unsafe impl<'gc> Collect<'gc> for JITFunc<'gc> { fn trace>(&self, _: &mut T) {} const NEEDS_TRACE: bool = false; } -impl<'gc> - From< - JitFunction<'gc, unsafe extern "C" fn(*const VmEnv<'gc>, *const Mutation<'gc>) -> JITValue>, - > for JITFunc<'gc> +impl<'gc> From> for JITFunc<'gc> { fn from( - value: JitFunction< - 'gc, - unsafe extern "C" fn(*const VmEnv<'gc>, *const Mutation<'gc>) -> JITValue, - >, + value: F<'gc> ) -> Self { - Self(value) + Self(value, PhantomData) } } impl<'gc> Deref for JITFunc<'gc> { - type Target = - JitFunction<'gc, unsafe extern "C" fn(*const VmEnv<'gc>, *const Mutation<'gc>) -> JITValue>; + type Target = F<'gc>; fn deref(&self) -> &Self::Target { &self.0 } @@ -223,7 +192,7 @@ impl<'gc> JITContext<'gc> { unsafe { let name = func_.get_name().to_str().unwrap(); let func = self.execution_engine.get_function(name).unwrap(); - Ok(func.into()) + Ok(JITFunc(func.as_raw(), PhantomData)) } } else { todo!() @@ -325,6 +294,7 @@ impl<'gc> JITContext<'gc> { self.helpers.new_thunk, &[ self.new_ptr(vm.get_thunk(idx) as *const _).into(), + env.into(), mc.into(), ], "call_capture_env", @@ -477,7 +447,6 @@ impl<'gc> JITContext<'gc> { .left() .unwrap(), )?, - OpCode::LookUp { sym } => stack.push( self.builder .build_direct_call( @@ -503,7 +472,7 @@ impl<'gc> JITContext<'gc> { .builder .build_direct_call( self.helpers.call, - &[func.into(), arg.into(), self.new_ptr(vm).into(), mc.into()], + &[func.into(), arg.into(), self.new_ptr(vm).into(), env.into(), mc.into()], "call", )? .try_as_basic_value() diff --git a/src/ty/internal/func.rs b/src/ty/internal/func.rs index 21bc071..47938b1 100644 --- a/src/ty/internal/func.rs +++ b/src/ty/internal/func.rs @@ -79,7 +79,7 @@ impl<'gc> Func<'gc> { .borrow_mut(mc) .get_or_insert_with(|| vm.compile_func(self.func)) .clone(); - let ret = unsafe { compiled.call(env.as_ref() as *const VmEnv, mc as *const _) }; + let ret = unsafe { compiled(env.as_ref() as *const VmEnv, mc as *const _) }; Ok(ret.into()) } } diff --git a/src/ty/internal/list.rs b/src/ty/internal/list.rs index 8925d2b..282ecc4 100644 --- a/src/ty/internal/list.rs +++ b/src/ty/internal/list.rs @@ -7,19 +7,12 @@ use crate::env::VmEnv; use super::Value; -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, Collect)] +#[collect(no_drop)] pub struct List<'gc> { data: Vec>, } -unsafe impl<'gc> Collect<'gc> for List<'gc> { - fn trace>(&self, cc: &mut Tr) { - for v in self.data.iter() { - v.trace(cc); - } - } -} - impl<'gc> List<'gc> { pub fn new() -> Self { List { diff --git a/src/ty/internal/mod.rs b/src/ty/internal/mod.rs index 0e18479..5b6a5aa 100644 --- a/src/ty/internal/mod.rs +++ b/src/ty/internal/mod.rs @@ -562,9 +562,9 @@ impl<'gc> Thunk<'gc> { *self.thunk.borrow_mut(mc) = _Thunk::Value(value); } - pub fn get_value(&self) -> Option> { - if let _Thunk::Value(val) = &*self.thunk.borrow() { - Some(val.clone()) + pub fn get_value(&self) -> Option<&Value<'gc>> { + if let _Thunk::Value(val) = unsafe { &*self.thunk.as_ptr() } { + Some(val) } else { None } diff --git a/src/vm/mod.rs b/src/vm/mod.rs index a4027bd..1509107 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -1,5 +1,6 @@ use std::cell::RefCell; +use gc_arena::arena::CollectionPhase; use gc_arena::{Arena, Collect, Gc, Mutation, Rootable}; use hashbrown::{HashMap, HashSet}; use inkwell::context::Context; @@ -21,6 +22,7 @@ use ecow::EcoString; mod test; const STACK_SIZE: usize = 8 * 1024 / size_of::(); +const COLLECTOR_GRANULARITY: f64 = 1024.0; #[derive(Collect)] #[collect(require_static)] @@ -59,6 +61,7 @@ pub fn run(mut prog: Program) -> Result { Ok(val.to_public(&root.vm, &mut HashSet::new())) }) } + pub fn eval FnOnce(Value<'gc>, &mut GcRoot<'gc>, &Mutation<'gc>) -> Result>( opcodes: Box<[OpCode]>, arena: &mut Arena Rootable<'gc, Root = GcRoot<'gc>>>, @@ -85,21 +88,23 @@ pub fn eval FnOnce(Value<'gc>, &mut GcRoot<'gc>, &Mutation<'gc>) opcodes.extend(code); root.envs.push(env); } - Consq::PopEnv => _ = root.envs.pop().unwrap(), + Consq::PopEnv => { + let _ = root.envs.pop().unwrap(); + } Consq::Call => { let arg = root.stack.pop(); let func = root.stack.pop().unwrap_func(); let env = func.env.enter_arg(arg, mc); let count = func.count.get(); func.count.set(count + 1); - if count >= 1 { + if count > 1 { let compiled = func .compiled .borrow_mut(mc) .get_or_insert_with(|| root.vm.compile_func(func.func)) .clone(); let ret = - unsafe { compiled.call(env.as_ref() as *const VmEnv, mc as *const _) }; + unsafe { compiled(env.as_ref() as *const VmEnv, mc as *const _) }; root.stack.push(ret.into())?; } else { root.envs.push(env); @@ -110,7 +115,13 @@ pub fn eval FnOnce(Value<'gc>, &mut GcRoot<'gc>, &Mutation<'gc>) } Result::Ok(()) })?; - arena.finish_cycle(); + if arena.metrics().allocation_debt() > COLLECTOR_GRANULARITY { + if arena.collection_phase() == CollectionPhase::Sweeping { + arena.collect_debt(); + } else if let Some(marked) = arena.mark_debt() { + marked.start_sweeping(); + } + } } arena.collect_debt(); arena.mutate_root(|mc, root| { @@ -128,6 +139,11 @@ enum Consq { NoOp, } +enum CycleAction { + Collect, + NoOp +} + #[inline(always)] fn single_op<'gc, const CAP: usize>( vm: &'gc VM<'gc>, @@ -159,7 +175,7 @@ fn single_op<'gc, const CAP: usize>( let Some(val) = stack.tos().as_ref().unwrap_thunk().get_value() else { return Ok(Consq::Force); }; - *stack.tos_mut() = val; + *stack.tos_mut() = val.clone(); } OpCode::InsertValue => { let val = stack.pop(); @@ -186,7 +202,7 @@ fn single_op<'gc, const CAP: usize>( stack.push(Value::Func(Gc::new(mc, Func::new(func, *env, mc))))?; } OpCode::Arg { level } => { - stack.push(env.lookup_arg(level))?; + stack.push(env.lookup_arg(level).clone())?; } OpCode::UnOp { op } => { use UnOp::*; @@ -289,7 +305,7 @@ fn single_op<'gc, const CAP: usize>( )?; } OpCode::LookUpLet { level, idx } => { - stack.push(env.lookup_let(level, idx))?; + stack.push(env.lookup_let(level, idx).clone())?; } OpCode::LeaveEnv => *env = env.leave(), OpCode::EnterWithEnv => {