use std::sync::atomic::{AtomicI64, Ordering};
use std::sync::Arc;
use serde::{Deserialize, Serialize};
use super::instruction::{Constant, Op};
use super::value::Value;
#[derive(Debug)]
pub struct FnTable {
slots: Vec<AtomicI64>,
}
impl FnTable {
pub fn new(functions: usize) -> Self {
FnTable { slots: (0..functions * 2).map(|_| AtomicI64::new(0)).collect() }
}
pub fn publish(&self, fi: usize, entry: i64, register_count: i64) {
self.slots[fi * 2 + 1].store(register_count, Ordering::Release);
self.slots[fi * 2].store(entry, Ordering::Release);
}
pub fn slot_addr(&self, fi: usize) -> i64 {
&self.slots[fi * 2] as *const AtomicI64 as i64
}
}
#[derive(Debug, Clone)]
pub struct NativeCtx {
pub table: Arc<FnTable>,
pub status: Arc<AtomicI64>,
pub depth: Arc<AtomicI64>,
}
#[derive(Debug)]
pub enum NativeOutcome {
ReturnValue(Value),
DeoptAt { resume_pc: usize, frames: Vec<NativeFrame> },
Return(i64),
Deopt,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RegionOutcome {
Completed,
Deopt,
DeoptAt { resume_pc: usize },
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct RegionReturn {
pub flag_slot: u16,
pub value_slot: u16,
pub kind: RegionReturnKind,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RegionReturnKind {
Slot(SlotKind),
Register,
}
pub trait NativeFn: Send + Sync {
fn call(&self, args: &[i64], pins: &[i64], depth: usize) -> NativeOutcome;
fn ret(&self) -> NativeRet {
NativeRet::Scalar(SlotKind::Int)
}
fn entry_ptr(&self) -> i64;
fn published_regc(&self) -> i64;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NativeRet {
Scalar(SlotKind),
ListParam(u8),
ListByHandle,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ParamKind {
Scalar(SlotKind),
List(PinElem),
}
#[derive(Debug)]
pub struct NativeFrame {
pub offset: usize,
pub return_pc: usize,
pub return_reg: u16,
pub regs: Vec<i64>,
pub kinds: Vec<RegBox>,
pub resolved: Vec<(u16, Value)>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RegBox {
Dead,
Int,
Bool,
Float,
ListParam(u8),
Resolved,
}
pub trait NativeTier: Send + Sync {
#[allow(clippy::too_many_arguments)]
fn compile_function(
&self,
code: &[Op],
entry_pc: usize,
constants: &[Constant],
param_count: u16,
register_count: u16,
self_fi: u16,
param_kinds: &[Option<ParamKind>],
ret_kind: Option<SlotKind>,
ctx: &NativeCtx,
callees: &[CalleeSig],
) -> Option<Box<dyn NativeFn>>;
fn compile_region(
&self,
code: &[Op],
head_pc: usize,
exit_pc: usize,
constants: &[Constant],
register_count: u16,
named: &[bool],
observed: &[ObservedKind],
ctx: &NativeCtx,
callees: &[CalleeSig],
) -> Option<Box<dyn RegionFn>> {
let _ = (
code, head_pc, exit_pc, constants, register_count, named, observed, ctx, callees,
);
None
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum SlotKind {
Int,
Bool,
Float,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ObservedKind {
Int,
Bool,
Float,
IntList,
IntListI32,
FloatList,
BoolList,
Map,
TextBytes,
Other,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum PinElem {
Int,
IntI32,
Float,
Bool,
Map,
TextBytes,
TextMut,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ArrayPin {
pub reg: u16,
pub vec_slot: u16,
pub ptr_slot: u16,
pub len_slot: u16,
pub elem: PinElem,
pub mutated: bool,
}
#[derive(Debug, Clone)]
pub struct CalleeSig {
pub param_kinds: Vec<Option<ParamKind>>,
pub ret: Option<SlotKind>,
pub list_params_stable: bool,
pub returns_list_param: bool,
}
#[derive(Debug, Clone, Copy)]
pub struct HoistGuard {
pub len_slot: u16,
pub bound_reg: u16,
pub iv_reg: u16,
pub add_max: i32,
pub add_min: i32,
}
pub trait RegionFn: Send + Sync {
fn guard_set(&self) -> &[(u16, SlotKind)];
fn free_set(&self) -> &[u16];
fn write_set(&self) -> &[(u16, SlotKind)];
fn array_set(&self) -> &[ArrayPin] {
&[]
}
fn hoist_guards(&self) -> &[HoistGuard] {
&[]
}
fn region_return(&self) -> Option<RegionReturn> {
None
}
fn frame_size(&self) -> usize;
fn arena_slots(&self) -> usize {
0
}
fn precise_kinds(&self, _resume_pc: usize) -> Option<&[Option<SlotKind>]> {
None
}
fn run(&self, frame: &mut [i64], depth: usize) -> RegionOutcome;
}
static INSTALLED_TIER: std::sync::OnceLock<&'static (dyn NativeTier + 'static)> =
std::sync::OnceLock::new();
pub fn install_native_tier(tier: &'static (dyn NativeTier + 'static)) -> bool {
INSTALLED_TIER.set(tier).is_ok()
}
pub fn installed_native_tier() -> Option<&'static (dyn NativeTier + 'static)> {
INSTALLED_TIER.get().copied()
}
pub const NATIVE_TIER_THRESHOLD: u32 = 100;
pub const REGION_TIER_THRESHOLD: u32 = 100;
pub(crate) enum RegionSlot {
Failed,
Ready {
rf: Box<dyn RegionFn>,
exit_pc: usize,
misses: u32,
},
}
pub(crate) const REGION_DEMOTE_AFTER: u32 = 8;
pub(crate) enum NativeSlot {
Untried,
Pending,
Failed,
Ready(Box<dyn NativeFn>),
}