use std::{
cell::{Cell, UnsafeCell},
ffi::c_void,
fmt,
ptr::{NonNull, null_mut},
};
use jl_sys::{jl_gc_mark_queue_objarray, jl_sym_t, jl_tagged_gensym, jl_value_t};
use jlrs_sys::jlrs_gc_wb;
use crate::{
call::Call,
data::{
managed::{Managed, module::Module, private::ManagedPriv, symbol::Symbol, value::Value},
types::foreign_type::{ForeignType, OpaqueType},
},
gc_safe::GcSafeOnceLock,
memory::{PTls, target::unrooted::Unrooted},
prelude::{DataType, LocalScope, Target},
private::Private,
};
#[repr(C)]
#[derive(Default)]
pub(crate) struct Stack {
slots: UnsafeCell<Vec<Cell<*mut c_void>>>,
}
impl fmt::Debug for Stack {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let n_slots = unsafe { NonNull::new_unchecked(self.slots.get()).as_ref().capacity() };
f.debug_struct("Stack")
.field("addr", &self.slots.get())
.field("n_slots", &n_slots)
.finish()
}
}
unsafe impl Send for Stack {}
unsafe impl Sync for Stack {}
unsafe impl ForeignType for Stack {
unsafe fn mark<P>(ptls: PTls, data: &Self, parent: &P) -> usize {
let slots = unsafe { &*data.slots.get() };
let slots_ptr = slots.as_ptr() as *const _;
let n_slots = slots.len();
unsafe {
jl_gc_mark_queue_objarray(
ptls,
parent as *const _ as *mut _,
slots_ptr as *mut _,
n_slots,
);
}
0
}
}
impl Stack {
#[cfg_attr(
not(any(
feature = "local-rt",
feature = "async-rt",
feature = "multi-rt",
feature = "ccall"
)),
allow(unused)
)]
pub(crate) unsafe fn init<'target, Tgt: Target<'target>>(tgt: &Tgt) {
unsafe {
let module = Module::jlrs_core(tgt);
#[repr(transparent)]
struct SendSycSym(*mut jl_sym_t);
unsafe impl Send for SendSycSym {}
unsafe impl Sync for SendSycSym {}
static SYM: GcSafeOnceLock<SendSycSym> = GcSafeOnceLock::new();
let sym = SYM.get_or_init(|| {
let stack = "Stack";
SendSycSym(jl_tagged_gensym(stack.as_ptr().cast(), stack.len()))
});
let sym = Symbol::wrap_non_null(NonNull::new_unchecked(sym.0), Private);
if module.global(tgt, sym).is_ok() {
return;
}
let base = Module::base(tgt);
let get_fn = base.global(tgt, "get").unwrap().as_value();
let lock_fn = module.global(tgt, "lock_init_lock").unwrap().as_value();
let unlock_fn = module.global(tgt, "unlock_init_lock").unwrap().as_value();
let stacks = module.global(tgt, "STACKS").unwrap().as_value();
lock_fn.call(tgt, []).unwrap();
let stack_type = get_fn
.call(tgt, [stacks, sym.as_value(), Value::nothing(tgt)])
.unwrap()
.as_value();
if stack_type.is::<DataType>() {
unlock_fn.call(tgt, []).unwrap();
return;
}
tgt.local_scope::<_, 1>(|mut frame| {
let dt = <Self as OpaqueType>::create_type(&mut frame, sym, module).as_value();
let set_fn = base.global(tgt, "setindex!").unwrap().as_value();
set_fn
.call(&frame, [stacks, dt, sym.as_value()])
.map_err(|e| e.as_value())
.unwrap();
});
unlock_fn.call(tgt, []).unwrap();
};
}
#[inline]
pub(crate) unsafe fn push_root(&self, root: NonNull<jl_value_t>) {
unsafe {
{
let slots = &mut *self.slots.get();
slots.push(Cell::new(root.cast().as_ptr()));
}
jlrs_gc_wb(self as *const _ as *mut _, root.as_ptr().cast());
}
}
#[inline]
pub(crate) unsafe fn reserve_slot(&self) -> usize {
unsafe {
let slots = &mut *self.slots.get();
let offset = slots.len();
slots.push(Cell::new(null_mut()));
offset
}
}
#[inline]
pub(crate) fn reserve(&self, additional: usize) {
unsafe {
let slots = &mut *self.slots.get();
slots.reserve(additional)
}
}
#[inline]
pub(crate) unsafe fn set_root(&self, offset: usize, root: NonNull<jl_value_t>) {
unsafe {
let slots = &*self.slots.get();
slots[offset].set(root.cast().as_ptr());
jlrs_gc_wb(self as *const _ as *mut _, root.as_ptr().cast());
}
}
#[inline]
pub(crate) unsafe fn pop_roots(&self, offset: usize) {
unsafe {
let slots = &mut *self.slots.get();
slots.truncate(offset);
slots.shrink_to(offset);
}
}
#[inline]
pub(crate) fn size(&self) -> usize {
unsafe {
let slots = &*self.slots.get();
slots.len()
}
}
#[inline]
#[cfg_attr(
not(any(feature = "local-rt", feature = "async-rt", feature = "ccall")),
allow(unused)
)]
pub(crate) unsafe fn alloc() -> *mut Self {
unsafe {
let global = Unrooted::new();
let stack = Value::new(global, Stack::default());
stack.ptr().cast().as_ptr()
}
}
}