From 99dce2e7780e69056cde25b9300a39d16487c851 Mon Sep 17 00:00:00 2001 From: imxyy_soope_ Date: Wed, 28 May 2025 21:52:13 +0800 Subject: [PATCH] feat: gc-arena finally... --- src/jit/helpers.rs | 55 ++++++++++++++++++++------------------ src/jit/mod.rs | 55 +++++++++++++++++++++----------------- src/ty/internal/attrset.rs | 11 -------- src/ty/internal/func.rs | 29 ++++++++------------ src/ty/internal/list.rs | 5 ++-- src/ty/internal/mod.rs | 6 ++--- src/vm/mod.rs | 36 +++++++++++++++---------- 7 files changed, 98 insertions(+), 99 deletions(-) diff --git a/src/jit/helpers.rs b/src/jit/helpers.rs index aef6a06..a5591b8 100644 --- a/src/jit/helpers.rs +++ b/src/jit/helpers.rs @@ -12,7 +12,7 @@ use crate::jit::JITValueData; use crate::ty::internal::{Thunk, Value}; use crate::vm::VM; -use super::{JITValue, ValueTag}; +use super::{JITContext, JITValue, ValueTag}; pub struct Helpers<'ctx> { pub int_type: IntType<'ctx>, @@ -103,7 +103,7 @@ impl<'ctx> Helpers<'ctx> { let call = module.add_function( "call", value_type.fn_type( - &[value_type.into(), value_type.into(), ptr_type.into()], + &[value_type.into(), value_type.into(), ptr_type.into(), ptr_type.into()], false, ), None, @@ -115,7 +115,7 @@ impl<'ctx> Helpers<'ctx> { ); let force = module.add_function( "force", - value_type.fn_type(&[value_type.into(), ptr_type.into()], false), + value_type.fn_type(&[value_type.into(), ptr_type.into(), ptr_type.into(), ptr_type.into()], false), None, ); @@ -310,30 +310,26 @@ extern "C" fn helper_or(lhs: JITValue, rhs: JITValue) -> JITValue { }, }, _ => todo!( - "Substruction not implemented for {:?} and {:?}", + "Substraction not implemented for {:?} and {:?}", lhs.tag, rhs.tag ), } } -extern "C" fn helper_call( +extern "C" fn helper_call<'gc>( func: JITValue, arg: JITValue, - vm: *const VM, - mc: *const Mutation, + vm: *const VM<'gc>, + mc: *const Mutation<'gc>, ) -> JITValue { - use ValueTag::*; + let vm = unsafe { vm.as_ref() }.unwrap(); + let mc = unsafe { mc.as_ref() }.unwrap(); + let arg = Value::from(arg); match func.tag { - Function => { - let mut func: Value = func.into(); - func.call( - arg.into(), - unsafe { vm.as_ref() }.unwrap(), - unsafe { mc.as_ref() }.unwrap(), - ) - .unwrap(); - func.into() + ValueTag::Function => { + let func = Value::from(func).unwrap_func(); + func.call_compile(arg, vm, mc).unwrap().into() } _ => todo!(), } @@ -345,15 +341,22 @@ extern "C" fn helper_lookup(sym: usize, env: *const VmEnv) -> JITValue { val } -extern "C" fn helper_force(thunk: JITValue, vm: *const VM, mc: *const Mutation) -> JITValue { - todo!() - /* let mut val = Value::from(thunk); - val.force( - unsafe { vm.as_ref() }.unwrap(), - unsafe { mc.as_ref() }.unwrap(), - ) - .unwrap(); - val.into() */ +extern "C" fn helper_force<'gc>(thunk: JITValue, vm: *const VM<'gc>, mc: *const Mutation<'gc>, jit: *const JITContext<'gc>) -> JITValue { + if !matches!(thunk.tag, ValueTag::Thunk) { + return thunk; + } + + let vm = unsafe { vm.as_ref() }.unwrap(); + let mc = unsafe { mc.as_ref() }.unwrap(); + let thunk = Value::from(thunk).unwrap_thunk(); + if let Some(val) = thunk.get_value() { + return val.into() + } + let (opcodes, env) = thunk.suspend(mc).unwrap(); + let func = unsafe { jit.as_ref() }.unwrap().compile_seq(opcodes.iter().copied(), vm).unwrap(); + let val = unsafe { func.call(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 { diff --git a/src/jit/mod.rs b/src/jit/mod.rs index c6e609c..8bc3fca 100644 --- a/src/jit/mod.rs +++ b/src/jit/mod.rs @@ -8,7 +8,7 @@ use inkwell::execution_engine::{ExecutionEngine, JitFunction}; use inkwell::module::Module; use inkwell::values::{BasicValueEnum, FunctionValue, PointerValue}; -use crate::bytecode::{Func, OpCode, UnOp}; +use crate::bytecode::{OpCode, UnOp}; use crate::env::VmEnv; use crate::error::*; use crate::stack::Stack; @@ -28,6 +28,7 @@ const STACK_SIZE: usize = 8 * 1024 / size_of::(); #[repr(u64)] #[derive(Debug, Clone, Copy)] pub enum ValueTag { + Null, Int, Float, String, @@ -37,7 +38,6 @@ pub enum ValueTag { Function, Thunk, Path, - Null, } #[repr(C)] @@ -164,6 +164,7 @@ unsafe impl<'gc> Collect<'gc> for JITContext<'gc> { fn trace>(&self, _: &mut T) {} const NEEDS_TRACE: bool = false; } + impl<'gc> JITContext<'gc> { pub fn new(context: &'gc Context) -> Self { // force linker to link JIT engine @@ -196,9 +197,12 @@ impl<'gc> JITContext<'gc> { .unwrap() } - pub fn compile_function(&self, func: &'gc Func, vm: &'gc VM<'gc>) -> Result> { + pub fn compile_seq( + &self, + opcodes: impl Iterator + ExactSizeIterator + DoubleEndedIterator, + vm: &'gc VM<'gc>, + ) -> Result> { let mut stack = Stack::<_, STACK_SIZE>::new(); - let mut iter = func.opcodes.iter().copied(); let func_ = self .module .add_function("nixjit_function", self.helpers.func_type, None); @@ -206,15 +210,8 @@ impl<'gc> JITContext<'gc> { let mc = func_.get_nth_param(1).unwrap().into_pointer_value(); let entry = self.context.append_basic_block(func_, "entry"); self.builder.position_at_end(entry); - self.build_expr( - &mut iter, - vm, - env, - mc, - &mut stack, - func_, - func.opcodes.len(), - )?; + let len = opcodes.len(); + self.build_expr(&mut opcodes.rev(), vm, env, mc, &mut stack, func_, len)?; assert_eq!(stack.len(), 1); let value = stack.pop(); @@ -336,6 +333,25 @@ impl<'gc> JITContext<'gc> { .unwrap_left() .into(), )?, + OpCode::ForceValue => { + let thunk = stack.pop(); + let _ = stack.push( + self.builder + .build_direct_call( + self.helpers.force, + &[ + thunk.into(), + self.new_ptr(vm as *const _).into(), + mc.into(), + self.new_ptr(self as *const _).into(), + ], + "call_force", + )? + .try_as_basic_value() + .left() + .unwrap(), + ); + } OpCode::CaptureEnv => { let thunk = *stack.tos(); self.builder.build_direct_call( @@ -442,21 +458,12 @@ impl<'gc> JITContext<'gc> { )?, OpCode::Call => { let arg = stack.pop(); - let func = self - .builder - .build_direct_call( - self.helpers.force, - &[stack.pop().into(), self.new_ptr(vm).into()], - "force", - )? - .try_as_basic_value() - .left() - .unwrap(); + let func = stack.pop(); let ret = self .builder .build_direct_call( self.helpers.call, - &[func.into(), arg.into(), self.new_ptr(vm).into()], + &[func.into(), arg.into(), self.new_ptr(vm).into(), mc.into()], "call", )? .try_as_basic_value() diff --git a/src/ty/internal/attrset.rs b/src/ty/internal/attrset.rs index 57246cb..8ff11bb 100644 --- a/src/ty/internal/attrset.rs +++ b/src/ty/internal/attrset.rs @@ -7,7 +7,6 @@ use hashbrown::{HashMap, HashSet}; use itertools::Itertools; use crate::env::VmEnv; -use crate::error::Result; use crate::vm::VM; use super::super::public as p; @@ -85,16 +84,6 @@ impl<'jit: 'vm, 'vm, 'gc> AttrSet<'gc> { Self { data } } - pub fn force_deep(&mut self, vm: &VM, mc: &Mutation<'gc>) -> Result<()> { - todo!() - /* let mut map: Vec<_> = self.data.iter().map(|(k, v)| (*k, v.clone())).collect(); - for (_, v) in map.iter_mut() { - v.force_deep(vm, mc)?; - } - self.data = map.into_iter().collect(); - Ok(()) */ - } - pub fn eq_impl(&self, other: &AttrSet<'gc>) -> bool { self.data.iter().len() == other.data.iter().len() && std::iter::zip( diff --git a/src/ty/internal/func.rs b/src/ty/internal/func.rs index 0a60b3d..26b88d5 100644 --- a/src/ty/internal/func.rs +++ b/src/ty/internal/func.rs @@ -1,7 +1,7 @@ use std::cell::Cell; use gc_arena::lock::{GcRefLock, RefLock}; -use gc_arena::{Arena, Collect, Gc, Mutation, Rootable}; +use gc_arena::{Collect, Gc, Mutation}; use hashbrown::HashMap; use itertools::Itertools; @@ -11,7 +11,7 @@ use crate::error::Result; use crate::ir; use crate::jit::JITFunc; use crate::ty::internal::{Thunk, Value}; -use crate::vm::{GcRoot, VM, eval}; +use crate::vm::VM; #[derive(Debug, Clone, Collect)] #[collect(no_drop)] @@ -44,7 +44,6 @@ impl From for Param { } } -#[derive(Clone)] pub struct Func<'gc> { pub func: &'gc BFunc, pub env: Gc<'gc, VmEnv<'gc>>, @@ -70,15 +69,13 @@ impl<'gc> Func<'gc> { } } - pub fn call( + pub fn call_compile( &self, arg: Value<'gc>, vm: &'gc VM<'gc>, mc: &Mutation<'gc>, - arena: &Arena Rootable<'a, Root = GcRoot<'a>>>, ) -> Result> { - todo!() - /* use Param::*; + use Param::*; let mut env = self.env; env = match self.func.param.clone() { @@ -117,17 +114,13 @@ impl<'gc> Func<'gc> { } }; - let count = self.count.get(); - self.count.replace(count + 1); - if count >= 1 { - let compiled = &mut *self.compiled.borrow_mut(mc); - let compiled = compiled.get_or_insert_with(|| vm.compile_func(self.func)); - let ret = unsafe { compiled.call(env.as_ref() as *const VmEnv, mc as *const _) }; - return Ok(ret.into()); - } - eval(self.func.opcodes.iter().copied(), arena, |val, _| { - Ok(val) - }) */ + let compiled = self + .compiled + .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 _) }; + Ok(ret.into()) } } diff --git a/src/ty/internal/list.rs b/src/ty/internal/list.rs index 902413a..f7c7cc1 100644 --- a/src/ty/internal/list.rs +++ b/src/ty/internal/list.rs @@ -1,12 +1,11 @@ use hashbrown::HashSet; use derive_more::Constructor; -use gc_arena::{Arena, Collect, Rootable}; +use gc_arena::Collect; use rpds::Vector; -use crate::error::Result; use crate::ty::public as p; -use crate::vm::{GcRoot, VM}; +use crate::vm::VM; use super::Value; diff --git a/src/ty/internal/mod.rs b/src/ty/internal/mod.rs index a8a150c..0ce0c63 100644 --- a/src/ty/internal/mod.rs +++ b/src/ty/internal/mod.rs @@ -604,13 +604,13 @@ impl<'gc> Thunk<'gc> { } } - pub fn suspend(&self, mc: &Mutation<'gc>) -> (&'gc OpCodes, Gc<'gc, VmEnv<'gc>>) { + pub fn suspend(&self, mc: &Mutation<'gc>) -> Result<(&'gc OpCodes, Gc<'gc, VmEnv<'gc>>)> { let _Thunk::Code(opcodes, env) = std::mem::replace(&mut *self.thunk.borrow_mut(mc), _Thunk::Suspended) else { - unreachable!() + return Err(Error::EvalError("infinite recursion occured".into())) }; - (opcodes, env.unwrap()) + Ok((opcodes, env.unwrap())) } pub fn insert_value(&self, value: Value<'gc>, mc: &Mutation<'gc>) { diff --git a/src/vm/mod.rs b/src/vm/mod.rs index d7a4e90..e175382 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -31,8 +31,10 @@ struct ContextWrapper(Context); pub fn run(mut prog: Program) -> Result { let mut arena: Arena]> = Arena::new(|mc| { let jit = Gc::new(mc, ContextWrapper(Context::create())); - let thunks = std::mem::take(&mut prog.thunks); - let funcs = std::mem::take(&mut prog.funcs); + let mut thunks = std::mem::take(&mut prog.thunks); + thunks.iter_mut().for_each(|code| code.reverse()); + let mut funcs = std::mem::take(&mut prog.funcs); + funcs.iter_mut().for_each(|F { opcodes, .. }| opcodes.reverse()); let symbols = std::mem::take(&mut prog.symbols); let symmap = std::mem::take(&mut prog.symmap); let consts = std::mem::take(&mut prog.consts); @@ -52,6 +54,7 @@ pub fn run(mut prog: Program) -> Result { envs: vec![env(&vm, mc)], } }); + prog.top_level.reverse(); eval(prog.top_level, &mut arena, |val, root, _| { Ok(val.to_public(&root.vm, &mut HashSet::new())) }) @@ -62,7 +65,6 @@ pub fn eval FnOnce(Value<'gc>, &mut GcRoot<'gc>, &Mutation<'gc>) f: F, ) -> Result { let mut opcodes = opcodes.into_vec(); - opcodes.reverse(); while let Some(opcode) = opcodes.pop() { arena.mutate_root(|mc, root| { let consq = single_op( @@ -77,9 +79,7 @@ pub fn eval FnOnce(Value<'gc>, &mut GcRoot<'gc>, &Mutation<'gc>) Consq::Jmp(step) => opcodes.resize_with(opcodes.len() - step, || unreachable!()), Consq::Force => { let thunk = root.stack.tos().as_ref().unwrap_thunk(); - let (code, env) = thunk.suspend(mc); - let mut code = code.to_vec(); - code.reverse(); + let (code, env) = thunk.suspend(mc)?; opcodes.push(OpCode::InsertValue); opcodes.push(OpCode::PopEnv); opcodes.extend(code); @@ -90,8 +90,8 @@ pub fn eval FnOnce(Value<'gc>, &mut GcRoot<'gc>, &Mutation<'gc>) use Param::*; let arg = root.stack.pop(); let func = root.stack.pop().unwrap_func(); - let mut env = func.env; - env = match func.func.param.clone() { + let env = func.env; + let env = match func.func.param.clone() { Ident(ident) => env.enter_arg(ident, arg, mc), Formals { formals, @@ -130,16 +130,24 @@ pub fn eval FnOnce(Value<'gc>, &mut GcRoot<'gc>, &Mutation<'gc>) env.enter_let(Gc::new(mc, new.into()), mc) } }; - root.envs.push(env); - let mut code = func.func.opcodes.to_vec(); - code.reverse(); - opcodes.push(OpCode::PopEnv); - opcodes.extend(code); + let count = func.count.get(); + func.count.set(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 _) }; + root.stack.push(ret.into())?; + } else { + root.envs.push(env); + opcodes.push(OpCode::PopEnv); + opcodes.extend(&func.func.opcodes); + } } } Result::Ok(()) })?; + arena.finish_cycle(); } + arena.collect_debt(); arena.mutate_root(|mc, root| { assert_eq!(root.stack.len(), 1); let ret = root.stack.pop(); @@ -407,6 +415,6 @@ impl<'gc> VM<'gc> { } pub fn compile_func(&'gc self, func: &'gc F) -> JITFunc<'gc> { - self.jit.compile_function(func, self).unwrap() + self.jit.compile_seq(func.opcodes.iter().copied(), self).unwrap() } }