use std::sync::mpsc::{Receiver, Sender};
use std::sync::Arc;
use std::thread::JoinHandle;
use super::instruction::{Constant, Op};
use super::native_tier::{CalleeSig, NativeCtx, NativeFn, NativeTier, ParamKind, SlotKind};
pub(crate) struct FunctionRequest {
pub fi: usize,
pub code: Vec<Op>,
pub entry_pc: usize,
pub constants: Arc<[Constant]>,
pub param_count: u16,
pub register_count: u16,
pub param_kinds: Vec<Option<ParamKind>>,
pub ret_kind: Option<SlotKind>,
pub callees: Vec<CalleeSig>,
pub ctx: NativeCtx,
}
pub(crate) enum CompileRequest {
Function(FunctionRequest),
}
pub(crate) enum CompileResult {
Function {
fi: usize,
nf: Option<Box<dyn NativeFn>>,
},
}
pub(crate) struct BgCompiler {
req_tx: Sender<CompileRequest>,
res_rx: Receiver<CompileResult>,
inflight: usize,
_worker: JoinHandle<()>,
}
impl BgCompiler {
pub(crate) fn new(tier: &'static dyn NativeTier) -> Self {
let (req_tx, req_rx) = std::sync::mpsc::channel::<CompileRequest>();
let (res_tx, res_rx) = std::sync::mpsc::channel::<CompileResult>();
let worker = std::thread::spawn(move || {
while let Ok(req) = req_rx.recv() {
let res = match req {
CompileRequest::Function(f) => {
let nf = tier.compile_function(
&f.code,
f.entry_pc,
&f.constants,
f.param_count,
f.register_count,
f.fi as u16,
&f.param_kinds,
f.ret_kind,
&f.ctx,
&f.callees,
);
CompileResult::Function { fi: f.fi, nf }
}
};
if res_tx.send(res).is_err() {
break;
}
}
});
BgCompiler { req_tx, res_rx, inflight: 0, _worker: worker }
}
pub(crate) fn submit(&mut self, req: CompileRequest) {
if self.req_tx.send(req).is_ok() {
self.inflight += 1;
}
}
pub(crate) fn try_drain(&mut self) -> Option<CompileResult> {
match self.res_rx.try_recv() {
Ok(r) => {
self.inflight = self.inflight.saturating_sub(1);
Some(r)
}
Err(_) => None,
}
}
pub(crate) fn is_idle(&self) -> bool {
self.inflight == 0
}
pub(crate) fn drain_blocking(&mut self) -> Vec<CompileResult> {
let mut out = Vec::with_capacity(self.inflight);
while self.inflight > 0 {
match self.res_rx.recv() {
Ok(r) => {
self.inflight -= 1;
out.push(r);
}
Err(_) => break, }
}
out
}
}