#[cfg(not(feature = "no-gc"))]
use crate::dynamics;
use crate::env::Env;
#[cfg(not(feature = "no-gc"))]
use crate::env::GlobalEnv;
use std::cell::RefCell;
thread_local! {
static ENV_ROOTS: RefCell<Vec<*const Env>> = const { RefCell::new(Vec::new()) };
static VALUE_ROOTS: RefCell<Vec<(*const cljrs_value::Value, usize)>> =
const { RefCell::new(Vec::new()) };
}
pub struct EnvRootGuard;
impl Drop for EnvRootGuard {
fn drop(&mut self) {
ENV_ROOTS.with(|roots| {
roots.borrow_mut().pop();
});
}
}
pub struct ValueRootGuard {
pushed: bool,
}
impl Drop for ValueRootGuard {
fn drop(&mut self) {
if self.pushed {
VALUE_ROOTS.with(|roots| {
roots.borrow_mut().pop();
});
}
}
}
pub fn push_env_root(env: &Env) -> EnvRootGuard {
ENV_ROOTS.with(|roots| {
roots.borrow_mut().push(env as *const Env);
});
EnvRootGuard
}
pub fn root_value(val: &cljrs_value::Value) -> ValueRootGuard {
VALUE_ROOTS.with(|roots| {
roots
.borrow_mut()
.push((val as *const cljrs_value::Value, 1));
});
ValueRootGuard { pushed: true }
}
pub fn root_values(vals: &[cljrs_value::Value]) -> ValueRootGuard {
if vals.is_empty() {
return ValueRootGuard { pushed: false };
}
VALUE_ROOTS.with(|roots| {
roots.borrow_mut().push((vals.as_ptr(), vals.len()));
});
ValueRootGuard { pushed: true }
}
#[cfg(feature = "no-gc")]
pub fn gc_safepoint(_env: &Env) {}
#[cfg(not(feature = "no-gc"))]
pub fn gc_safepoint(env: &Env) {
if !cljrs_gc::gc_requested() && !cljrs_gc::CONFIG_CANCELLATION.in_progress() {
return;
}
if cljrs_gc::CONFIG_CANCELLATION.in_progress() {
cljrs_gc::safepoint();
return;
}
if !cljrs_gc::take_gc_request() {
cljrs_gc::safepoint();
return;
}
let Some(_stw_guard) = cljrs_gc::begin_stw() else {
cljrs_gc::safepoint();
return;
};
cljrs_gc::HEAP.collect(|visitor| {
cljrs_gc::HEAP.trace_registered_roots(visitor);
trace_env_roots(env, visitor);
trace_thread_env_roots(visitor);
trace_value_roots(visitor);
dynamics::trace_current(visitor);
crate::taps::trace_roots(visitor);
cljrs_gc::trace_thread_alloc_roots(visitor);
});
}
#[cfg(not(feature = "no-gc"))]
fn trace_env_roots(env: &Env, visitor: &mut cljrs_gc::MarkVisitor) {
use cljrs_gc::Trace;
for frame in &env.frames {
for (_name, val) in &frame.bindings {
val.trace(visitor);
}
}
trace_globals(&env.globals, visitor);
}
#[cfg(not(feature = "no-gc"))]
fn trace_value_roots(visitor: &mut cljrs_gc::MarkVisitor) {
use cljrs_gc::Trace;
VALUE_ROOTS.with(|roots| {
for &(ptr, count) in roots.borrow().iter() {
let slice = unsafe { std::slice::from_raw_parts(ptr, count) };
for val in slice {
val.trace(visitor);
}
}
});
}
#[cfg(not(feature = "no-gc"))]
fn trace_thread_env_roots(visitor: &mut cljrs_gc::MarkVisitor) {
use cljrs_gc::Trace;
ENV_ROOTS.with(|roots| {
for env_ptr in roots.borrow().iter() {
let env = unsafe { &**env_ptr };
for frame in &env.frames {
for (_name, val) in &frame.bindings {
val.trace(visitor);
}
}
}
});
}
#[cfg(not(feature = "no-gc"))]
fn trace_globals(globals: &GlobalEnv, visitor: &mut cljrs_gc::MarkVisitor) {
use cljrs_gc::GcVisitor as _;
let namespaces = globals.namespaces.read().unwrap();
for (_name, ns_ptr) in namespaces.iter() {
visitor.visit(ns_ptr);
}
}