feat: gc (does compile, but WIP)

This commit is contained in:
2025-05-27 21:08:59 +08:00
parent 319c12c1f4
commit c3ace28af1
20 changed files with 696 additions and 575 deletions

View File

@@ -1,6 +1,6 @@
use std::ops::Deref;
use gc_arena::{Collect, Gc};
use gc_arena::{Collect, Gc, Mutation};
use inkwell::OptimizationLevel;
use inkwell::builder::Builder;
use inkwell::context::Context;
@@ -60,10 +60,12 @@ impl<'gc> From<JITValue> for Value<'gc> {
fn from(value: JITValue) -> Self {
use ValueTag::*;
match value.tag {
Int => Value::Const(Const::Int(unsafe { value.data.int })),
Null => Value::Const(Const::Null),
Int => Value::Int(unsafe { value.data.int }),
Null => Value::Null,
Function => Value::Func(unsafe { Gc::from_ptr(value.data.ptr as *const _) }),
Thunk => Value::Thunk(self::Thunk { thunk: unsafe { Gc::from_ptr(value.data.ptr as *const _) } }),
Thunk => Value::Thunk(self::Thunk {
thunk: unsafe { Gc::from_ptr(value.data.ptr as *const _) },
}),
_ => todo!("not implemented for {:?}", value.tag),
}
}
@@ -72,7 +74,7 @@ impl<'gc> From<JITValue> for Value<'gc> {
impl From<&Value<'_>> for JITValue {
fn from(value: &Value<'_>) -> Self {
match *value {
Value::Const(Const::Int(int)) => JITValue {
Value::Int(int) => JITValue {
tag: ValueTag::Int,
data: JITValueData { int },
},
@@ -96,7 +98,7 @@ impl From<&Value<'_>> for JITValue {
impl From<Value<'_>> for JITValue {
fn from(value: Value) -> Self {
match value {
Value::Const(Const::Int(int)) => JITValue {
Value::Int(int) => JITValue {
tag: ValueTag::Int,
data: JITValueData { int },
},
@@ -117,18 +119,33 @@ impl From<Value<'_>> for JITValue {
}
}
#[derive(Collect)]
#[collect(require_static)]
pub struct JITFunc<'gc>(JitFunction<'gc, unsafe extern "C" fn(*const VM<'gc>, *const VmEnv<'gc>) -> JITValue>);
pub struct JITFunc<'gc>(
JitFunction<'gc, unsafe extern "C" fn(*const VmEnv<'gc>, *const Mutation<'gc>) -> JITValue>,
);
impl<'gc> From<JitFunction<'gc, unsafe extern "C" fn(*const VM<'gc>, *const VmEnv<'gc>) -> JITValue>> for JITFunc<'gc> {
fn from(value: JitFunction<'gc, unsafe extern "C" fn(*const VM<'gc>, *const VmEnv<'gc>) -> JITValue>) -> Self {
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<
JitFunction<'gc, unsafe extern "C" fn(*const VmEnv<'gc>, *const Mutation<'gc>) -> JITValue>,
> for JITFunc<'gc>
{
fn from(
value: JitFunction<
'gc,
unsafe extern "C" fn(*const VmEnv<'gc>, *const Mutation<'gc>) -> JITValue,
>,
) -> Self {
Self(value)
}
}
impl<'gc> Deref for JITFunc<'gc> {
type Target = JitFunction<'gc, unsafe extern "C" fn(*const VM<'gc>, *const VmEnv<'gc>) -> JITValue>;
type Target =
JitFunction<'gc, unsafe extern "C" fn(*const VmEnv<'gc>, *const Mutation<'gc>) -> JITValue>;
fn deref(&self) -> &Self::Target {
&self.0
}
@@ -143,15 +160,10 @@ pub struct JITContext<'gc> {
helpers: Helpers<'gc>,
}
unsafe impl<'gc> Collect for JITContext<'gc> {
fn trace(&self, _cc: &gc_arena::Collection) {}
fn needs_trace() -> bool
where
Self: Sized, {
false
}
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
@@ -184,20 +196,25 @@ impl<'gc> JITContext<'gc> {
.unwrap()
}
pub fn compile_function(
&self,
func: &'gc Func,
vm: &'gc VM<'gc>,
) -> Result<JITFunc<'gc>> {
pub fn compile_function(&self, func: &'gc Func, vm: &'gc VM<'gc>) -> Result<JITFunc<'gc>> {
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);
let env = func_.get_nth_param(1).unwrap().into_pointer_value();
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);
self.build_expr(&mut iter, vm, env, &mut stack, func_, func.opcodes.len())?;
self.build_expr(
&mut iter,
vm,
env,
mc,
&mut stack,
func_,
func.opcodes.len(),
)?;
assert_eq!(stack.len(), 1);
let value = stack.pop();
@@ -221,13 +238,14 @@ impl<'gc> JITContext<'gc> {
iter: &mut impl Iterator<Item = OpCode>,
vm: &'gc 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, stack)?;
let br = self.single_op(opcode, vm, env, mc, stack)?;
length -= 1;
if br > 0 {
let consq = self.context.append_basic_block(func, "consq");
@@ -259,13 +277,13 @@ impl<'gc> JITContext<'gc> {
length -= br;
self.builder.position_at_end(consq);
let br = self.build_expr(iter, vm, env, stack, func, br)?;
let br = self.build_expr(iter, vm, env, mc, 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, stack, func, br)?;
self.build_expr(iter, vm, env, mc, stack, func, br)?;
self.builder.build_store(result, stack.pop())?;
self.builder.build_unconditional_branch(cont)?;
@@ -278,7 +296,7 @@ impl<'gc> JITContext<'gc> {
}
}
if length > 0 {
self.single_op(iter.next().unwrap(), vm, env, stack)
self.single_op(iter.next().unwrap(), vm, env, mc, stack)
} else {
Ok(0)
}
@@ -290,6 +308,7 @@ impl<'gc> JITContext<'gc> {
opcode: OpCode,
vm: &'gc VM<'_>,
env: PointerValue<'gc>,
mc: PointerValue<'gc>,
stack: &mut Stack<BasicValueEnum<'gc>, CAP>,
) -> Result<usize> {
match opcode {
@@ -304,8 +323,18 @@ impl<'gc> JITContext<'gc> {
}
}
OpCode::LoadThunk { idx } => stack.push(
self.helpers
.new_thunk(Thunk::new(vm.get_thunk(idx))),
self.builder
.build_direct_call(
self.helpers.new_thunk,
&[
self.new_ptr(vm.get_thunk(idx) as *const _).into(),
mc.into(),
],
"call_capture_env",
)?
.try_as_basic_value()
.unwrap_left()
.into(),
)?,
OpCode::CaptureEnv => {
let thunk = *stack.tos();