refactor: reduce coupling
This commit is contained in:
762
evaluator/nixjit_jit/src/lib.rs
Normal file
762
evaluator/nixjit_jit/src/lib.rs
Normal file
@@ -0,0 +1,762 @@
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
|
||||
use cranelift::codegen::ir::Function;
|
||||
use cranelift::codegen::ir::{self, ArgumentExtension, ArgumentPurpose, StackSlot};
|
||||
use cranelift::prelude::*;
|
||||
use cranelift_jit::{JITBuilder, JITModule};
|
||||
use cranelift_module::{FuncId, Linkage, Module};
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
|
||||
use nixjit_eval::{EvalContext, Value};
|
||||
use nixjit_lir::Lir;
|
||||
|
||||
mod compile;
|
||||
mod helpers;
|
||||
|
||||
pub use compile::JITCompile;
|
||||
use helpers::*;
|
||||
|
||||
pub trait JITContext: EvalContext + Sized {
|
||||
fn lookup_stack(&self, offset: usize) -> &Value<Self>;
|
||||
fn lookup_arg(&self, offset: usize) -> &Value<Self>;
|
||||
fn enter_with(&mut self, namespace: Rc<HashMap<String, Value<Self>>>);
|
||||
fn exit_with(&mut self);
|
||||
}
|
||||
|
||||
type F<Ctx: JITContext> = unsafe extern "C" fn(*const Ctx, *mut Value<Ctx>);
|
||||
|
||||
pub struct JITFunc<Ctx: JITContext> {
|
||||
func: F<Ctx>,
|
||||
strings: HashSet<String>,
|
||||
}
|
||||
|
||||
impl<Ctx: JITContext> Deref for JITFunc<Ctx> {
|
||||
type Target = F<Ctx>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.func
|
||||
}
|
||||
}
|
||||
|
||||
struct Context<'comp, 'ctx, Ctx: JITContext> {
|
||||
pub compiler: &'comp mut JITCompiler<Ctx>,
|
||||
pub builder: FunctionBuilder<'ctx>,
|
||||
free_slots: Vec<StackSlot>,
|
||||
strings: HashSet<String>,
|
||||
}
|
||||
|
||||
impl<'comp, 'ctx, Ctx: JITContext> Context<'comp, 'ctx, Ctx> {
|
||||
fn new(compiler: &'comp mut JITCompiler<Ctx>, builder: FunctionBuilder<'ctx>) -> Self {
|
||||
Self {
|
||||
compiler,
|
||||
builder,
|
||||
free_slots: Vec::new(),
|
||||
strings: HashSet::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn alloca(&mut self) -> StackSlot {
|
||||
self.free_slots.pop().map_or_else(
|
||||
|| {
|
||||
let slot = StackSlotData::new(StackSlotKind::ExplicitSlot, 32, 3);
|
||||
self.builder.create_sized_stack_slot(slot)
|
||||
},
|
||||
|x| x,
|
||||
)
|
||||
}
|
||||
|
||||
fn free_slot(&mut self, slot: StackSlot) {
|
||||
self.free_slots.push(slot);
|
||||
}
|
||||
|
||||
fn alloc_array(&mut self, len: usize) -> ir::Value {
|
||||
let len = self
|
||||
.builder
|
||||
.ins()
|
||||
.iconst(self.compiler.ptr_type, len as i64);
|
||||
let alloc_array = self
|
||||
.compiler
|
||||
.module
|
||||
.declare_func_in_func(self.compiler.alloc_array, self.builder.func);
|
||||
let inst = self.builder.ins().call(alloc_array, &[len]);
|
||||
self.builder.inst_results(inst)[0]
|
||||
}
|
||||
|
||||
fn create_string(&mut self, string: &str) -> StackSlot {
|
||||
let string = self
|
||||
.strings
|
||||
.get_or_insert_with(string, |_| string.to_owned());
|
||||
let ptr = self
|
||||
.builder
|
||||
.ins()
|
||||
.iconst(self.compiler.ptr_type, string.as_ptr() as i64);
|
||||
let len = self
|
||||
.builder
|
||||
.ins()
|
||||
.iconst(self.compiler.ptr_type, string.len() as i64);
|
||||
let create_string = self
|
||||
.compiler
|
||||
.module
|
||||
.declare_func_in_func(self.compiler.create_string, self.builder.func);
|
||||
let slot = self.alloca();
|
||||
let ret = self
|
||||
.builder
|
||||
.ins()
|
||||
.stack_addr(self.compiler.ptr_type, slot, 0);
|
||||
self.builder.ins().call(create_string, &[ptr, len, ret]);
|
||||
slot
|
||||
}
|
||||
|
||||
fn create_list(&mut self, ptr: ir::Value, len: usize) -> StackSlot {
|
||||
let len = self
|
||||
.builder
|
||||
.ins()
|
||||
.iconst(self.compiler.ptr_type, len as i64);
|
||||
let create_list = self
|
||||
.compiler
|
||||
.module
|
||||
.declare_func_in_func(self.compiler.create_list, self.builder.func);
|
||||
let slot = self.alloca();
|
||||
let ret = self
|
||||
.builder
|
||||
.ins()
|
||||
.stack_addr(self.compiler.ptr_type, slot, 0);
|
||||
self.builder.ins().call(create_list, &[ptr, len, ret]);
|
||||
slot
|
||||
}
|
||||
|
||||
fn create_attrs(&mut self) -> StackSlot {
|
||||
let create_attrs = self
|
||||
.compiler
|
||||
.module
|
||||
.declare_func_in_func(self.compiler.create_attrs, self.builder.func);
|
||||
let slot = StackSlotData::new(StackSlotKind::ExplicitSlot, 40, 3);
|
||||
let slot = self.builder.create_sized_stack_slot(slot);
|
||||
let ret = self
|
||||
.builder
|
||||
.ins()
|
||||
.stack_addr(self.compiler.ptr_type, slot, 0);
|
||||
self.builder.ins().call(create_attrs, &[ret]);
|
||||
slot
|
||||
}
|
||||
|
||||
fn push_attr(&mut self, attrs: StackSlot, sym: &str, val: StackSlot) {
|
||||
self.free_slot(attrs);
|
||||
self.free_slot(val);
|
||||
let attrs = self.builder.ins().stack_addr(types::I64, attrs, 0);
|
||||
let val = self.builder.ins().stack_addr(types::I64, val, 0);
|
||||
let sym = self.strings.get_or_insert_with(sym, |_| sym.to_owned());
|
||||
let ptr = self
|
||||
.builder
|
||||
.ins()
|
||||
.iconst(self.compiler.ptr_type, sym.as_ptr() as i64);
|
||||
let len = self
|
||||
.builder
|
||||
.ins()
|
||||
.iconst(self.compiler.ptr_type, sym.len() as i64);
|
||||
let push_attr = self
|
||||
.compiler
|
||||
.module
|
||||
.declare_func_in_func(self.compiler.push_attr, self.builder.func);
|
||||
self.builder.ins().call(push_attr, &[attrs, ptr, len, val]);
|
||||
}
|
||||
|
||||
fn finalize_attrs(&mut self, attrs: StackSlot) -> StackSlot {
|
||||
let attrs = self.builder.ins().stack_addr(types::I64, attrs, 0);
|
||||
let finalize_attrs = self
|
||||
.compiler
|
||||
.module
|
||||
.declare_func_in_func(self.compiler.finalize_attrs, self.builder.func);
|
||||
let slot = self.alloca();
|
||||
let ret = self
|
||||
.builder
|
||||
.ins()
|
||||
.stack_addr(self.compiler.ptr_type, slot, 0);
|
||||
self.builder.ins().call(finalize_attrs, &[attrs, ret]);
|
||||
slot
|
||||
}
|
||||
|
||||
fn enter_with(&mut self, env: ir::Value, namespace: StackSlot) {
|
||||
let ptr = self
|
||||
.builder
|
||||
.ins()
|
||||
.stack_addr(self.compiler.ptr_type, namespace, 0);
|
||||
let enter_with = self
|
||||
.compiler
|
||||
.module
|
||||
.declare_func_in_func(self.compiler.enter_with, self.builder.func);
|
||||
self.builder.ins().call(enter_with, &[env, ptr]);
|
||||
}
|
||||
|
||||
fn exit_with(&mut self, env: ir::Value) {
|
||||
let exit_with = self
|
||||
.compiler
|
||||
.module
|
||||
.declare_func_in_func(self.compiler.exit_with, self.builder.func);
|
||||
self.builder.ins().call(exit_with, &[env]);
|
||||
}
|
||||
|
||||
fn dbg(&mut self, slot: StackSlot) {
|
||||
let ptr = self
|
||||
.builder
|
||||
.ins()
|
||||
.stack_addr(self.compiler.ptr_type, slot, 0);
|
||||
let dbg = self
|
||||
.compiler
|
||||
.module
|
||||
.declare_func_in_func(self.compiler.dbg, self.builder.func);
|
||||
self.builder.ins().call(dbg, &[ptr]);
|
||||
}
|
||||
|
||||
fn call(
|
||||
&mut self,
|
||||
func: StackSlot,
|
||||
args_ptr: ir::Value,
|
||||
args_len: usize,
|
||||
engine: ir::Value,
|
||||
env: ir::Value,
|
||||
) {
|
||||
let args_len = self
|
||||
.builder
|
||||
.ins()
|
||||
.iconst(self.compiler.ptr_type, args_len as i64);
|
||||
let call = self
|
||||
.compiler
|
||||
.module
|
||||
.declare_func_in_func(self.compiler.call, self.builder.func);
|
||||
let func = self
|
||||
.builder
|
||||
.ins()
|
||||
.stack_addr(self.compiler.ptr_type, func, 0);
|
||||
self.builder
|
||||
.ins()
|
||||
.call(call, &[func, args_ptr, args_len, engine, env]);
|
||||
}
|
||||
|
||||
fn lookup(&mut self, env: ir::Value, sym: &str) -> StackSlot {
|
||||
let sym = self.strings.get_or_insert_with(sym, |_| sym.to_owned());
|
||||
let ptr = self
|
||||
.builder
|
||||
.ins()
|
||||
.iconst(self.compiler.ptr_type, sym.as_ptr() as i64);
|
||||
let len = self
|
||||
.builder
|
||||
.ins()
|
||||
.iconst(self.compiler.ptr_type, sym.len() as i64);
|
||||
let lookup = self
|
||||
.compiler
|
||||
.module
|
||||
.declare_func_in_func(self.compiler.lookup, self.builder.func);
|
||||
let slot = self.alloca();
|
||||
let ret = self
|
||||
.builder
|
||||
.ins()
|
||||
.stack_addr(self.compiler.ptr_type, slot, 0);
|
||||
self.builder.ins().call(lookup, &[env, ptr, len, ret]);
|
||||
slot
|
||||
}
|
||||
|
||||
fn lookup_stack(&mut self, env: ir::Value, idx: usize) -> StackSlot {
|
||||
let slot = self.alloca();
|
||||
let lookup_stack = self
|
||||
.compiler
|
||||
.module
|
||||
.declare_func_in_func(self.compiler.lookup_stack, self.builder.func);
|
||||
let idx = self
|
||||
.builder
|
||||
.ins()
|
||||
.iconst(self.compiler.ptr_type, idx as i64);
|
||||
let ptr = self
|
||||
.builder
|
||||
.ins()
|
||||
.stack_addr(self.compiler.ptr_type, slot, 0);
|
||||
self.builder.ins().call(lookup_stack, &[env, idx, ptr]);
|
||||
slot
|
||||
}
|
||||
|
||||
fn lookup_arg(&mut self, env: ir::Value, idx: usize) -> StackSlot {
|
||||
let slot = self.alloca();
|
||||
let lookup_arg = self
|
||||
.compiler
|
||||
.module
|
||||
.declare_func_in_func(self.compiler.lookup_arg, self.builder.func);
|
||||
let idx = self
|
||||
.builder
|
||||
.ins()
|
||||
.iconst(self.compiler.ptr_type, idx as i64);
|
||||
let ptr = self
|
||||
.builder
|
||||
.ins()
|
||||
.stack_addr(self.compiler.ptr_type, slot, 0);
|
||||
self.builder.ins().call(lookup_arg, &[env, idx, ptr]);
|
||||
slot
|
||||
}
|
||||
|
||||
fn select(
|
||||
&mut self,
|
||||
slot: StackSlot,
|
||||
path_ptr: ir::Value,
|
||||
path_len: usize,
|
||||
engine: ir::Value,
|
||||
env: ir::Value,
|
||||
) {
|
||||
let select = self
|
||||
.compiler
|
||||
.module
|
||||
.declare_func_in_func(self.compiler.select, self.builder.func);
|
||||
let path_len = self
|
||||
.builder
|
||||
.ins()
|
||||
.iconst(self.compiler.ptr_type, path_len as i64);
|
||||
let ptr = self
|
||||
.builder
|
||||
.ins()
|
||||
.stack_addr(self.compiler.ptr_type, slot, 0);
|
||||
self.builder
|
||||
.ins()
|
||||
.call(select, &[ptr, path_ptr, path_len, engine, env]);
|
||||
}
|
||||
|
||||
fn select_with_default(
|
||||
&mut self,
|
||||
slot: StackSlot,
|
||||
path_ptr: ir::Value,
|
||||
path_len: usize,
|
||||
default: StackSlot,
|
||||
engine: ir::Value,
|
||||
env: ir::Value,
|
||||
) {
|
||||
let select_with_default = self
|
||||
.compiler
|
||||
.module
|
||||
.declare_func_in_func(self.compiler.select_with_default, self.builder.func);
|
||||
let path_len = self
|
||||
.builder
|
||||
.ins()
|
||||
.iconst(self.compiler.ptr_type, path_len as i64);
|
||||
let ptr = self
|
||||
.builder
|
||||
.ins()
|
||||
.stack_addr(self.compiler.ptr_type, slot, 0);
|
||||
let default_ptr = self
|
||||
.builder
|
||||
.ins()
|
||||
.stack_addr(self.compiler.ptr_type, default, 0);
|
||||
self.builder.ins().call(
|
||||
select_with_default,
|
||||
&[ptr, path_ptr, path_len, default_ptr, engine, env],
|
||||
);
|
||||
}
|
||||
|
||||
pub fn eq(&mut self, lhs: StackSlot, rhs: StackSlot) {
|
||||
let lhs = self
|
||||
.builder
|
||||
.ins()
|
||||
.stack_addr(self.compiler.ptr_type, lhs, 0);
|
||||
let rhs = self
|
||||
.builder
|
||||
.ins()
|
||||
.stack_addr(self.compiler.ptr_type, rhs, 0);
|
||||
let eq = self
|
||||
.compiler
|
||||
.module
|
||||
.declare_func_in_func(self.compiler.eq, self.builder.func);
|
||||
self.builder.ins().call(eq, &[lhs, rhs]);
|
||||
}
|
||||
|
||||
pub fn get_tag(&mut self, slot: StackSlot) -> ir::Value {
|
||||
self.builder.ins().stack_load(types::I64, slot, 0)
|
||||
}
|
||||
|
||||
pub fn get_small_value(&mut self, ty: Type, slot: StackSlot) -> ir::Value {
|
||||
self.builder.ins().stack_load(ty, slot, 8)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct JITCompiler<Ctx: JITContext> {
|
||||
ctx: codegen::Context,
|
||||
module: JITModule,
|
||||
builder_ctx: Option<FunctionBuilderContext>,
|
||||
_marker: PhantomData<Ctx>,
|
||||
|
||||
int_type: Type,
|
||||
float_type: Type,
|
||||
bool_type: Type,
|
||||
ptr_type: Type,
|
||||
value_type: Type,
|
||||
func_sig: Signature,
|
||||
|
||||
call: FuncId,
|
||||
lookup_stack: FuncId,
|
||||
lookup_arg: FuncId,
|
||||
lookup: FuncId,
|
||||
select: FuncId,
|
||||
select_with_default: FuncId,
|
||||
|
||||
eq: FuncId,
|
||||
|
||||
alloc_array: FuncId,
|
||||
create_string: FuncId,
|
||||
create_list: FuncId,
|
||||
create_attrs: FuncId,
|
||||
push_attr: FuncId,
|
||||
finalize_attrs: FuncId,
|
||||
enter_with: FuncId,
|
||||
exit_with: FuncId,
|
||||
dbg: FuncId,
|
||||
}
|
||||
|
||||
impl<Ctx: JITContext> Default for JITCompiler<Ctx> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: JITContext> JITCompiler<Ctx> {
|
||||
pub fn new() -> Self {
|
||||
let mut flag_builder = settings::builder();
|
||||
flag_builder.set("use_colocated_libcalls", "false").unwrap();
|
||||
flag_builder.set("is_pic", "false").unwrap();
|
||||
let isa_builder = cranelift_native::builder().unwrap_or_else(|msg| {
|
||||
panic!("host machine is not supported: {msg}");
|
||||
});
|
||||
let isa = isa_builder
|
||||
.finish(settings::Flags::new(flag_builder))
|
||||
.unwrap();
|
||||
let mut builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
|
||||
|
||||
builder.symbol("helper_call", helper_call::<Ctx> as _);
|
||||
builder.symbol("helper_lookup_stack", helper_lookup_stack::<Ctx> as _);
|
||||
builder.symbol("helper_lookup_arg", helper_lookup_arg::<Ctx> as _);
|
||||
builder.symbol("helper_lookup", helper_lookup::<Ctx> as _);
|
||||
builder.symbol("helper_select", helper_select::<Ctx> as _);
|
||||
builder.symbol(
|
||||
"helper_select_with_default",
|
||||
helper_select_with_default::<Ctx> as _,
|
||||
);
|
||||
builder.symbol("helper_eq", helper_eq::<Ctx> as _);
|
||||
|
||||
builder.symbol("helper_alloc_array", helper_alloc_array::<Ctx> as _);
|
||||
builder.symbol("helper_create_string", helper_create_string::<Ctx> as _);
|
||||
builder.symbol("helper_create_list", helper_create_list::<Ctx> as _);
|
||||
builder.symbol("helper_create_attrs", helper_create_attrs::<Ctx> as _);
|
||||
builder.symbol("helper_push_attr", helper_push_attr::<Ctx> as _);
|
||||
builder.symbol("helper_finalize_attrs", helper_finalize_attrs::<Ctx> as _);
|
||||
builder.symbol("helper_enter_with", helper_enter_with::<Ctx> as _);
|
||||
builder.symbol("helper_exit_with", helper_exit_with::<Ctx> as _);
|
||||
builder.symbol("helper_dbg", helper_dbg::<Ctx> as _);
|
||||
|
||||
let mut module = JITModule::new(builder);
|
||||
let ctx = module.make_context();
|
||||
|
||||
let int_type = types::I64;
|
||||
let float_type = types::F64;
|
||||
let bool_type = types::I8;
|
||||
let ptr_type = module.target_config().pointer_type();
|
||||
let value_type = types::I128;
|
||||
|
||||
// fn(*const Context, *const Env, *mut Value)
|
||||
let mut func_sig = module.make_signature();
|
||||
func_sig.params.extend(
|
||||
[AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
}; 3],
|
||||
);
|
||||
|
||||
// fn(func: &mut Value, args_ptr: *mut Value, args_len: usize, engine: &mut Context, env:
|
||||
// &mut Env)
|
||||
let mut call_sig = module.make_signature();
|
||||
call_sig.params.extend(
|
||||
[AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
}; 5],
|
||||
);
|
||||
let call = module
|
||||
.declare_function("helper_call", Linkage::Import, &call_sig)
|
||||
.unwrap();
|
||||
|
||||
let mut lookup_stack_sig = module.make_signature();
|
||||
lookup_stack_sig.params.extend(
|
||||
[AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
}; 3],
|
||||
);
|
||||
let lookup_stack = module
|
||||
.declare_function("helper_lookup_stack", Linkage::Import, &lookup_stack_sig)
|
||||
.unwrap();
|
||||
|
||||
// fn(env: &Env, level: usize, ret: &mut MaybeUninit<Value>)
|
||||
let mut lookup_arg_sig = module.make_signature();
|
||||
lookup_arg_sig.params.extend(
|
||||
[AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
}; 3],
|
||||
);
|
||||
let lookup_arg = module
|
||||
.declare_function("helper_lookup_arg", Linkage::Import, &lookup_arg_sig)
|
||||
.unwrap();
|
||||
|
||||
// fn(env: &Env, sym_ptr: *const u8, sym_len: usize, ret: &mut MaybeUninit<Value>)
|
||||
let mut lookup_sig = module.make_signature();
|
||||
lookup_sig.params.extend(
|
||||
[AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
}; 4],
|
||||
);
|
||||
let lookup = module
|
||||
.declare_function("helper_lookup", Linkage::Import, &lookup_sig)
|
||||
.unwrap();
|
||||
|
||||
// fn(val: &mut Value, path_ptr: *mut Value, path_len: usize, engine: &mut Context, env: &mut Env)
|
||||
let mut select_sig = module.make_signature();
|
||||
select_sig.params.extend(
|
||||
[AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
}; 5],
|
||||
);
|
||||
let select = module
|
||||
.declare_function("helper_select", Linkage::Import, &select_sig)
|
||||
.unwrap();
|
||||
|
||||
// fn(val: &mut Value, path_ptr: *mut Value, path_len: usize, default: NonNull<Value>, engine: &mut Context, env: &mut Env)
|
||||
let mut select_with_default_sig = module.make_signature();
|
||||
select_with_default_sig.params.extend(
|
||||
[AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
}; 6],
|
||||
);
|
||||
let select_with_default = module
|
||||
.declare_function(
|
||||
"helper_select_with_default",
|
||||
Linkage::Import,
|
||||
&select_with_default_sig,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut eq_sig = module.make_signature();
|
||||
eq_sig.params.extend(
|
||||
[AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
}; 2],
|
||||
);
|
||||
let eq = module
|
||||
.declare_function("helper_eq", Linkage::Import, &eq_sig)
|
||||
.unwrap();
|
||||
|
||||
let mut alloc_array_sig = module.make_signature();
|
||||
alloc_array_sig.params.push(AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
});
|
||||
alloc_array_sig.returns.push(AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
});
|
||||
let alloc_array = module
|
||||
.declare_function("helper_alloc_array", Linkage::Import, &alloc_array_sig)
|
||||
.unwrap();
|
||||
|
||||
let mut create_string_sig = module.make_signature();
|
||||
create_string_sig.params.extend(
|
||||
[AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
}; 3],
|
||||
);
|
||||
let create_string = module
|
||||
.declare_function("helper_create_string", Linkage::Import, &create_string_sig)
|
||||
.unwrap();
|
||||
|
||||
let mut create_list_sig = module.make_signature();
|
||||
create_list_sig.params.extend(
|
||||
[AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
}; 3],
|
||||
);
|
||||
let create_list = module
|
||||
.declare_function("helper_create_list", Linkage::Import, &create_list_sig)
|
||||
.unwrap();
|
||||
|
||||
let mut create_attrs_sig = module.make_signature();
|
||||
create_attrs_sig.params.push(AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
});
|
||||
let create_attrs = module
|
||||
.declare_function("helper_create_attrs", Linkage::Import, &create_attrs_sig)
|
||||
.unwrap();
|
||||
|
||||
let mut push_attr_sig = module.make_signature();
|
||||
push_attr_sig.params.extend(
|
||||
[AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
}; 4],
|
||||
);
|
||||
let push_attr = module
|
||||
.declare_function("helper_push_attr", Linkage::Import, &push_attr_sig)
|
||||
.unwrap();
|
||||
|
||||
let mut finalize_attrs_sig = module.make_signature();
|
||||
finalize_attrs_sig.params.extend(
|
||||
[AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
}; 2],
|
||||
);
|
||||
let finalize_attrs = module
|
||||
.declare_function(
|
||||
"helper_finalize_attrs",
|
||||
Linkage::Import,
|
||||
&finalize_attrs_sig,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut enter_with_sig = module.make_signature();
|
||||
enter_with_sig.params.extend(
|
||||
[AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
}; 2],
|
||||
);
|
||||
let enter_with = module
|
||||
.declare_function("helper_enter_with", Linkage::Import, &enter_with_sig)
|
||||
.unwrap();
|
||||
|
||||
let mut exit_with_sig = module.make_signature();
|
||||
exit_with_sig.params.push(AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
});
|
||||
let exit_with = module
|
||||
.declare_function("helper_exit_with", Linkage::Import, &exit_with_sig)
|
||||
.unwrap();
|
||||
|
||||
let mut dbg_sig = module.make_signature();
|
||||
dbg_sig.params.push(AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
});
|
||||
let dbg = module
|
||||
.declare_function("helper_dbg", Linkage::Import, &dbg_sig)
|
||||
.unwrap();
|
||||
|
||||
Self {
|
||||
builder_ctx: None,
|
||||
_marker: PhantomData,
|
||||
ctx,
|
||||
module,
|
||||
|
||||
int_type,
|
||||
float_type,
|
||||
bool_type,
|
||||
ptr_type,
|
||||
value_type,
|
||||
func_sig,
|
||||
|
||||
call,
|
||||
lookup_stack,
|
||||
lookup_arg,
|
||||
lookup,
|
||||
select,
|
||||
select_with_default,
|
||||
|
||||
eq,
|
||||
|
||||
alloc_array,
|
||||
create_string,
|
||||
create_list,
|
||||
create_attrs,
|
||||
push_attr,
|
||||
finalize_attrs,
|
||||
enter_with,
|
||||
exit_with,
|
||||
dbg,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compile(&mut self, ir: &Lir, id: usize) -> JITFunc<Ctx> {
|
||||
let func_id = self
|
||||
.module
|
||||
.declare_function(
|
||||
format!("nixjit_thunk{id}").as_str(),
|
||||
Linkage::Local,
|
||||
&self.func_sig,
|
||||
)
|
||||
.unwrap();
|
||||
let mut func = Function::new();
|
||||
func.signature = self.func_sig.clone();
|
||||
let mut builder_ctx = self.builder_ctx.take().unwrap_or_default();
|
||||
let mut ctx = Context::new(self, FunctionBuilder::new(&mut func, &mut builder_ctx));
|
||||
|
||||
let entry = ctx.builder.create_block();
|
||||
ctx.builder.append_block_params_for_function_params(entry);
|
||||
ctx.builder.switch_to_block(entry);
|
||||
|
||||
let params = ctx.builder.block_params(entry);
|
||||
let engine = params[0];
|
||||
let env = params[1];
|
||||
let ret = params[2];
|
||||
let res = ir.compile(&mut ctx, engine, env);
|
||||
|
||||
let tag = ctx.builder.ins().stack_load(types::I64, res, 0);
|
||||
let val0 = ctx.builder.ins().stack_load(types::I64, res, 8);
|
||||
let val1 = ctx.builder.ins().stack_load(types::I64, res, 16);
|
||||
let val2 = ctx.builder.ins().stack_load(types::I64, res, 24);
|
||||
ctx.builder.ins().store(MemFlags::new(), tag, ret, 0);
|
||||
ctx.builder.ins().store(MemFlags::new(), val0, ret, 8);
|
||||
ctx.builder.ins().store(MemFlags::new(), val1, ret, 16);
|
||||
ctx.builder.ins().store(MemFlags::new(), val2, ret, 24);
|
||||
ctx.builder.ins().return_(&[]);
|
||||
ctx.builder.seal_all_blocks();
|
||||
ctx.builder.finalize();
|
||||
|
||||
let strings = ctx.strings;
|
||||
if cfg!(debug_assertions) {
|
||||
println!("{ir:#?}");
|
||||
println!("{}", func.display());
|
||||
}
|
||||
self.ctx.func = func;
|
||||
self.module.define_function(func_id, &mut self.ctx).unwrap();
|
||||
self.module.finalize_definitions().unwrap();
|
||||
self.ctx.clear();
|
||||
|
||||
let _ = self.builder_ctx.insert(builder_ctx);
|
||||
unsafe {
|
||||
JITFunc {
|
||||
func: std::mem::transmute::<*const u8, F<Ctx>>(
|
||||
self.module.get_finalized_function(func_id),
|
||||
),
|
||||
strings,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user