feat: get rid of gc and cyclic thunk

This commit is contained in:
2025-06-05 16:43:47 +08:00
parent 51f8df9cca
commit 484cfa4610
17 changed files with 342 additions and 595 deletions

View File

@@ -1,8 +1,7 @@
use std::marker::PhantomData;
use std::rc::Rc;
use std::ops::Deref;
use std::rc::Rc;
use gc_arena::{Collect, Gc, Mutation};
use inkwell::OptimizationLevel;
use inkwell::builder::Builder;
use inkwell::context::Context;
@@ -66,7 +65,7 @@ impl<'gc> From<JITValue> for Value<'gc> {
Null => Value::Null,
Function => Value::Func(unsafe { Rc::from_raw(value.data.ptr as *const _) }),
Thunk => Value::Thunk(self::Thunk {
thunk: unsafe { Gc::from_ptr(value.data.ptr as *const _) },
thunk: unsafe { Rc::from_raw(value.data.ptr as *const _) },
}),
_ => todo!("not implemented for {:?}", value.tag),
}
@@ -80,18 +79,16 @@ impl From<Value<'_>> for JITValue {
tag: ValueTag::Int,
data: JITValueData { int },
},
Value::Func(func) => {
JITValue {
tag: ValueTag::Function,
data: JITValueData {
ptr: Rc::into_raw(func) as *const _,
},
}
}
Value::Func(func) => JITValue {
tag: ValueTag::Function,
data: JITValueData {
ptr: Rc::into_raw(func) as *const _,
},
},
Value::Thunk(thunk) => JITValue {
tag: ValueTag::Thunk,
data: JITValueData {
ptr: Gc::as_ptr(thunk.thunk) as *const _,
ptr: Rc::into_raw(thunk.thunk) as *const _,
},
},
_ => todo!(),
@@ -99,19 +96,11 @@ impl From<Value<'_>> for JITValue {
}
}
pub struct JITFunc<'gc>(F<'gc>, PhantomData<fn(&'gc F<'gc>) -> &'gc F<'gc>>);
type F<'gc> = unsafe extern "C" fn(*const VmEnv<'gc>, *const Mutation<'gc>) -> JITValue;
pub struct JITFunc<'gc>(F<'gc>, PhantomData<&'gc mut ()>);
type F<'gc> = unsafe extern "C" fn(*const VmEnv<'gc>) -> JITValue;
unsafe impl<'gc> Collect<'gc> for JITFunc<'gc> {
fn trace<T: gc_arena::collect::Trace<'gc>>(&self, _: &mut T) {}
const NEEDS_TRACE: bool = false;
}
impl<'gc> From<F<'gc>> for JITFunc<'gc>
{
fn from(
value: F<'gc>
) -> Self {
impl<'gc> From<F<'gc>> for JITFunc<'gc> {
fn from(value: F<'gc>) -> Self {
Self(value, PhantomData)
}
}
@@ -132,11 +121,6 @@ pub struct JITContext<'gc> {
helpers: Helpers<'gc>,
}
unsafe impl<'gc> Collect<'gc> for JITContext<'gc> {
fn trace<T: gc_arena::collect::Trace<'gc>>(&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
@@ -172,18 +156,17 @@ impl<'gc> JITContext<'gc> {
pub fn compile_seq(
&self,
mut opcodes: impl ExactSizeIterator<Item = OpCode>,
vm: &'gc VM<'gc>,
vm: &VM<'gc>,
) -> Result<JITFunc<'gc>> {
let mut stack = Stack::<_, STACK_SIZE>::new();
let func_ = self
.module
.add_function("nixjit_function", self.helpers.func_type, None);
let env = func_.get_nth_param(0).unwrap().into_pointer_value();
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);
let len = opcodes.len();
self.build_expr(&mut opcodes, vm, env, mc, &mut stack, func_, len)?;
self.build_expr(&mut opcodes, vm, env, &mut stack, func_, len)?;
assert_eq!(stack.len(), 1);
let value = stack.pop();
@@ -205,16 +188,15 @@ impl<'gc> JITContext<'gc> {
fn build_expr<const CAP: usize>(
&self,
iter: &mut impl Iterator<Item = OpCode>,
vm: &'gc VM<'gc>,
vm: &VM<'gc>,
env: PointerValue<'gc>,
mc: PointerValue<'gc>,
stack: &mut Stack<BasicValueEnum<'gc>, CAP>,
func: FunctionValue<'gc>,
mut length: usize,
) -> Result<usize> {
while length > 1 {
let opcode = iter.next().unwrap();
let br = self.single_op(opcode, vm, env, mc, stack)?;
let br = self.single_op(opcode, vm, env, stack)?;
length -= 1;
if br > 0 {
let consq = self.context.append_basic_block(func, "consq");
@@ -246,13 +228,13 @@ impl<'gc> JITContext<'gc> {
length -= br;
self.builder.position_at_end(consq);
let br = self.build_expr(iter, vm, env, mc, stack, func, br)?;
let br = self.build_expr(iter, vm, env, stack, func, br)?;
self.builder.build_store(result, stack.pop())?;
self.builder.build_unconditional_branch(cont)?;
length -= br;
self.builder.position_at_end(alter);
self.build_expr(iter, vm, env, mc, stack, func, br)?;
self.build_expr(iter, vm, env, stack, func, br)?;
self.builder.build_store(result, stack.pop())?;
self.builder.build_unconditional_branch(cont)?;
@@ -265,7 +247,7 @@ impl<'gc> JITContext<'gc> {
}
}
if length > 0 {
self.single_op(iter.next().unwrap(), vm, env, mc, stack)
self.single_op(iter.next().unwrap(), vm, env, stack)
} else {
Ok(0)
}
@@ -275,9 +257,8 @@ impl<'gc> JITContext<'gc> {
fn single_op<const CAP: usize>(
&self,
opcode: OpCode,
vm: &'gc VM<'_>,
vm: &VM<'_>,
env: PointerValue<'gc>,
mc: PointerValue<'gc>,
stack: &mut Stack<BasicValueEnum<'gc>, CAP>,
) -> Result<usize> {
match opcode {
@@ -295,11 +276,7 @@ impl<'gc> JITContext<'gc> {
self.builder
.build_direct_call(
self.helpers.new_thunk,
&[
self.new_ptr(vm.get_thunk(idx) as *const _).into(),
env.into(),
mc.into(),
],
&[self.new_ptr(vm.get_thunk(idx) as *const _).into()],
"call_capture_env",
)?
.try_as_basic_value()
@@ -314,7 +291,6 @@ impl<'gc> JITContext<'gc> {
&[
thunk.into(),
self.new_ptr(vm as *const _).into(),
mc.into(),
self.new_ptr(self as *const _).into(),
],
"call_force",
@@ -475,7 +451,7 @@ impl<'gc> JITContext<'gc> {
.builder
.build_direct_call(
self.helpers.call,
&[func.into(), arg.into(), self.new_ptr(vm).into(), env.into(), mc.into()],
&[func.into(), arg.into(), self.new_ptr(vm).into()],
"call",
)?
.try_as_basic_value()