Skip to main content

mozjs/gc/
trace.rs

1use crate::jsapi::{Heap, JSObject, JSTracer};
2use crate::rust::{Runtime, Stencil};
3use mozjs_sys::trace::Traceable;
4use std::cell::RefCell;
5use std::ffi::c_void;
6
7use crate::typedarray::{TypedArray, TypedArrayElement};
8
9unsafe impl<T: TypedArrayElement> Traceable for TypedArray<T, Box<Heap<*mut JSObject>>> {
10    unsafe fn trace(&self, trc: *mut JSTracer) {
11        self.underlying_object().trace(trc);
12    }
13}
14
15unsafe impl Traceable for Runtime {
16    #[inline]
17    unsafe fn trace(&self, _: *mut JSTracer) {}
18}
19
20unsafe impl Traceable for Stencil {
21    #[inline]
22    unsafe fn trace(&self, _: *mut JSTracer) {}
23}
24
25/// Holds a set of JSTraceables that need to be rooted
26pub struct RootedTraceableSet {
27    set: Vec<*const dyn Traceable>,
28}
29
30thread_local!(
31    static ROOTED_TRACEABLES: RefCell<RootedTraceableSet>  = RefCell::new(RootedTraceableSet::new())
32);
33
34impl RootedTraceableSet {
35    fn new() -> RootedTraceableSet {
36        RootedTraceableSet { set: Vec::new() }
37    }
38
39    pub unsafe fn add(traceable: *const dyn Traceable) {
40        ROOTED_TRACEABLES.with(|traceables| {
41            traceables.borrow_mut().set.push(traceable);
42        });
43    }
44
45    pub unsafe fn remove(traceable: *const dyn Traceable) {
46        ROOTED_TRACEABLES.with(|traceables| {
47            let mut traceables = traceables.borrow_mut();
48            let idx = match traceables
49                .set
50                .iter()
51                .rposition(|x| *x as *const () == traceable as *const ())
52            {
53                Some(idx) => idx,
54                None => return,
55            };
56            traceables.set.remove(idx);
57        });
58    }
59
60    /// Clear all rooted traceables on this thread.
61    /// Called during SpiderMonkey shutdown to prevent stale pointers
62    /// from being traced after JS_DestroyContext.
63    /// BAO PATCH (BCE-20260621-005): during multi-page teardown under servo,
64    /// rooted traceables may outlive the JSContext (e.g. libtest thread-pool
65    /// threads tearing down TLS) and would be traced during C++ TLS teardown
66    /// after JS_DestroyContext, causing SIGSEGV (js::gc::HeaderWord::get on
67    /// freed GC heap). Caller: `bao_engine::context::shutdown`.
68    pub unsafe fn clear() {
69        ROOTED_TRACEABLES.with(|traceables| {
70            traceables.borrow_mut().set.clear();
71        });
72    }
73
74    pub(crate) unsafe fn trace(&self, trc: *mut JSTracer) {
75        for traceable in &self.set {
76            (**traceable).trace(trc);
77        }
78    }
79}
80
81pub unsafe extern "C" fn trace_traceables(trc: *mut JSTracer, _: *mut c_void) {
82    ROOTED_TRACEABLES.with(|traceables| {
83        traceables.borrow().trace(trc);
84    });
85}