feat: get rid of gc and cyclic thunk
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
use gc_arena::{Gc, Mutation};
|
||||
use std::ptr::NonNull;
|
||||
use std::rc::Rc;
|
||||
|
||||
use inkwell::AddressSpace;
|
||||
use inkwell::context::Context;
|
||||
use inkwell::execution_engine::ExecutionEngine;
|
||||
@@ -52,11 +54,11 @@ impl<'ctx> Helpers<'ctx> {
|
||||
let ptr_int_type = context.ptr_sized_int_type(execution_engine.get_target_data(), None);
|
||||
let ptr_type = context.ptr_type(AddressSpace::default());
|
||||
let value_type = context.struct_type(&[int_type.into(), int_type.into()], false);
|
||||
let func_type = value_type.fn_type(&[ptr_type.into(), ptr_type.into()], false);
|
||||
let func_type = value_type.fn_type(&[ptr_type.into()], false);
|
||||
|
||||
let new_thunk = module.add_function(
|
||||
"new_thunk",
|
||||
value_type.fn_type(&[ptr_type.into(), ptr_type.into(), ptr_type.into()], false),
|
||||
value_type.fn_type(&[ptr_type.into()], false),
|
||||
None,
|
||||
);
|
||||
let debug = module.add_function(
|
||||
@@ -66,10 +68,9 @@ impl<'ctx> Helpers<'ctx> {
|
||||
);
|
||||
let capture_env = module.add_function(
|
||||
"capture_env",
|
||||
context.void_type().fn_type(
|
||||
&[value_type.into(), ptr_type.into(), ptr_type.into()],
|
||||
false,
|
||||
),
|
||||
context
|
||||
.void_type()
|
||||
.fn_type(&[value_type.into(), ptr_type.into()], false),
|
||||
None,
|
||||
);
|
||||
let neg = module.add_function(
|
||||
@@ -105,13 +106,7 @@ impl<'ctx> Helpers<'ctx> {
|
||||
let call = module.add_function(
|
||||
"call",
|
||||
value_type.fn_type(
|
||||
&[
|
||||
value_type.into(),
|
||||
value_type.into(),
|
||||
ptr_type.into(),
|
||||
ptr_type.into(),
|
||||
ptr_type.into(),
|
||||
],
|
||||
&[value_type.into(), value_type.into(), ptr_type.into()],
|
||||
false,
|
||||
),
|
||||
None,
|
||||
@@ -123,7 +118,10 @@ impl<'ctx> Helpers<'ctx> {
|
||||
);
|
||||
let lookup_let = module.add_function(
|
||||
"lookup_let",
|
||||
value_type.fn_type(&[ptr_int_type.into(), ptr_int_type.into(), ptr_type.into()], false),
|
||||
value_type.fn_type(
|
||||
&[ptr_int_type.into(), ptr_int_type.into(), ptr_type.into()],
|
||||
false,
|
||||
),
|
||||
None,
|
||||
);
|
||||
let lookup = module.add_function(
|
||||
@@ -134,12 +132,7 @@ impl<'ctx> Helpers<'ctx> {
|
||||
let force = module.add_function(
|
||||
"force",
|
||||
value_type.fn_type(
|
||||
&[
|
||||
value_type.into(),
|
||||
ptr_type.into(),
|
||||
ptr_type.into(),
|
||||
ptr_type.into(),
|
||||
],
|
||||
&[value_type.into(), ptr_type.into(), ptr_type.into()],
|
||||
false,
|
||||
),
|
||||
None,
|
||||
@@ -237,14 +230,11 @@ extern "C" fn helper_debug(value: JITValue) {
|
||||
dbg!(value.tag);
|
||||
}
|
||||
|
||||
extern "C" fn helper_capture_env<'gc>(
|
||||
thunk: JITValue,
|
||||
env: *const VmEnv<'gc>,
|
||||
mc: *const Mutation<'gc>,
|
||||
) {
|
||||
extern "C" fn helper_capture_env<'gc>(thunk: JITValue, env: *const VmEnv<'gc>) {
|
||||
let thunk = unsafe { (thunk.data.ptr as *const Thunk).as_ref().unwrap() };
|
||||
let env = unsafe { Gc::from_ptr(env) };
|
||||
thunk.capture_env(env, unsafe { mc.as_ref() }.unwrap());
|
||||
let env = unsafe { Rc::from_raw(env) };
|
||||
thunk.capture_env(env.clone());
|
||||
std::mem::forget(env);
|
||||
}
|
||||
|
||||
extern "C" fn helper_neg(rhs: JITValue, _env: *const VmEnv) -> JITValue {
|
||||
@@ -347,21 +337,13 @@ extern "C" fn helper_or(lhs: JITValue, rhs: JITValue) -> JITValue {
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn helper_call<'gc>(
|
||||
func: JITValue,
|
||||
arg: JITValue,
|
||||
vm: *const VM<'gc>,
|
||||
env: *mut VmEnv<'gc>,
|
||||
mc: *const Mutation<'gc>,
|
||||
) -> JITValue {
|
||||
extern "C" fn helper_call<'gc>(func: JITValue, arg: JITValue, vm: *const VM<'gc>) -> JITValue {
|
||||
let vm = unsafe { vm.as_ref() }.unwrap();
|
||||
let mc = unsafe { mc.as_ref() }.unwrap();
|
||||
let arg = Value::from(arg);
|
||||
match func.tag {
|
||||
ValueTag::Function => {
|
||||
let func = Value::from(func).unwrap_func();
|
||||
let env = unsafe { &mut *env };
|
||||
func.call_compile(arg, vm, mc).unwrap().clone().into()
|
||||
func.call_compile(arg, vm).unwrap().clone().into()
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
@@ -387,36 +369,28 @@ extern "C" fn helper_lookup(sym: usize, env: *const VmEnv) -> JITValue {
|
||||
|
||||
extern "C" fn helper_force<'gc>(
|
||||
thunk: JITValue,
|
||||
vm: *const VM<'gc>,
|
||||
mc: *const Mutation<'gc>,
|
||||
vm: NonNull<VM<'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 vm = unsafe { vm.as_ref() };
|
||||
let thunk = Value::from(thunk).unwrap_thunk();
|
||||
if let Some(val) = thunk.get_value() {
|
||||
return val.clone().into();
|
||||
}
|
||||
let (opcodes, env) = thunk.suspend(mc).unwrap();
|
||||
let (opcodes, env) = thunk.suspend().unwrap();
|
||||
let func = unsafe { jit.as_ref() }
|
||||
.unwrap()
|
||||
.compile_seq(opcodes.iter().copied().rev(), vm)
|
||||
.unwrap();
|
||||
let val = unsafe { func(env.as_ref() as *const _, mc as *const _) };
|
||||
thunk.insert_value(val.into(), mc);
|
||||
let val = unsafe { func(env.as_ref() as *const _) };
|
||||
thunk.insert_value(val.into());
|
||||
val
|
||||
}
|
||||
|
||||
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 };
|
||||
Value::Thunk(Thunk::new(
|
||||
unsafe { opcodes.as_ref() }.unwrap(),
|
||||
mc
|
||||
))
|
||||
.into()
|
||||
extern "C" fn helper_new_thunk(opcodes: *const OpCodes) -> JITValue {
|
||||
Value::Thunk(Thunk::new(unsafe { opcodes.as_ref() }.unwrap())).into()
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user