use std::marker::PhantomData; use std::ops::Deref; use inkwell::OptimizationLevel; use inkwell::builder::Builder; use inkwell::context::Context; use inkwell::execution_engine::ExecutionEngine; use inkwell::module::Module; use crate::env::VmEnv; use crate::ty::internal::Value; mod compile; mod helpers; pub use compile::JITCompile; use helpers::Helpers; #[cfg(test)] mod test; #[repr(u64)] #[derive(Debug, Clone, Copy)] pub enum ValueTag { Null, Int, Float, String, Bool, AttrSet, List, Function, Thunk, Path, } #[repr(C)] #[derive(Clone, Copy)] pub struct JITValue { tag: ValueTag, data: JITValueData, } #[repr(C)] #[derive(Clone, Copy)] pub union JITValueData { int: i64, float: f64, bool: bool, ptr: *const (), } impl From for Value { fn from(value: JITValue) -> Self { use ValueTag::*; match value.tag { Int => Value::Int(unsafe { value.data.int }), Null => Value::Null, /* Function => Value::Func(unsafe { Rc::from_raw(value.data.ptr as *const _) }), Thunk => Value::Thunk(self::Thunk { thunk: unsafe { Rc::from_raw(value.data.ptr as *const _) }, }), */ _ => todo!("not implemented for {:?}", value.tag), } } } impl From 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: Rc::into_raw(func) as *const _, }, }, Value::Thunk(thunk) => JITValue { tag: ValueTag::Thunk, data: JITValueData { ptr: Rc::into_raw(thunk.thunk) as *const _, }, }, */ _ => todo!(), } } } pub struct JITFunc<'ctx>(F, PhantomData<&'ctx mut ()>); type F = unsafe extern "C" fn(*const VmEnv) -> JITValue; impl From for JITFunc<'_> { fn from(value: F) -> Self { Self(value, PhantomData) } } impl Deref for JITFunc<'_> { type Target = F; fn deref(&self) -> &Self::Target { &self.0 } } pub struct JITContext<'ctx> { context: &'ctx Context, module: Module<'ctx>, builder: Builder<'ctx>, execution_engine: ExecutionEngine<'ctx>, helpers: Helpers<'ctx>, } impl<'ctx> JITContext<'ctx> { pub fn new(context: &'ctx Context) -> Self { // force linker to link JIT engine unsafe { inkwell::llvm_sys::execution_engine::LLVMLinkInMCJIT(); } let module = context.create_module("nixjit"); let execution_engine = module .create_jit_execution_engine(OptimizationLevel::Aggressive) .unwrap(); let helpers = Helpers::new(context, &module, &execution_engine); JITContext { execution_engine, builder: context.create_builder(), context, module, helpers, } } }