mozjs_sys/
trace.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5use crate::glue::{
6    CallBigIntTracer, CallFunctionTracer, CallIdTracer, CallObjectTracer,
7    CallPropertyDescriptorTracer, CallScriptTracer, CallStringTracer, CallSymbolTracer,
8    CallValueRootTracer, CallValueTracer,
9};
10use crate::jsapi::js::TraceValueArray;
11use crate::jsapi::JS::{PropertyDescriptor, Value};
12use crate::jsapi::{jsid, JSFunction, JSObject, JSScript, JSString, JSTracer};
13
14use crate::jsapi::JS::{BigInt, JobQueue, Symbol};
15use crate::jsgc::{Heap, ValueArray};
16use std::any::TypeId;
17use std::borrow::Cow;
18use std::cell::{Cell, RefCell, UnsafeCell};
19use std::collections::btree_map::BTreeMap;
20use std::collections::btree_set::BTreeSet;
21use std::collections::vec_deque::VecDeque;
22use std::collections::{HashMap, HashSet};
23use std::hash::{BuildHasher, Hash};
24use std::num::{
25    NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
26    NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize,
27};
28use std::ops::Range;
29use std::path::PathBuf;
30use std::rc::Rc;
31use std::sync::atomic::{
32    AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, AtomicU32,
33    AtomicU64, AtomicU8, AtomicUsize,
34};
35use std::thread::JoinHandle;
36use std::time::{Duration, Instant, SystemTime};
37
38/// Types that can be traced.
39///
40/// This trait is unsafe; if it is implemented incorrectly, the GC may end up collecting objects
41/// that are still reachable.
42pub unsafe trait Traceable {
43    /// Trace `self`.
44    unsafe fn trace(&self, trc: *mut JSTracer);
45}
46
47unsafe impl Traceable for Heap<*mut JSFunction> {
48    #[inline]
49    unsafe fn trace(&self, trc: *mut JSTracer) {
50        if self.get().is_null() {
51            return;
52        }
53        CallFunctionTracer(trc, self as *const _ as *mut Self, c"function".as_ptr());
54    }
55}
56
57unsafe impl Traceable for Heap<*mut JSObject> {
58    #[inline]
59    unsafe fn trace(&self, trc: *mut JSTracer) {
60        if self.get().is_null() {
61            return;
62        }
63        CallObjectTracer(trc, self as *const _ as *mut Self, c"object".as_ptr());
64    }
65}
66
67unsafe impl Traceable for Heap<*mut Symbol> {
68    unsafe fn trace(&self, trc: *mut JSTracer) {
69        if self.get().is_null() {
70            return;
71        }
72        CallSymbolTracer(trc, self as *const _ as *mut Self, c"symbol".as_ptr());
73    }
74}
75
76unsafe impl Traceable for Heap<*mut BigInt> {
77    unsafe fn trace(&self, trc: *mut JSTracer) {
78        if self.get().is_null() {
79            return;
80        }
81        CallBigIntTracer(trc, self as *const _ as *mut Self, c"bigint".as_ptr());
82    }
83}
84
85unsafe impl Traceable for Heap<*mut JSScript> {
86    #[inline]
87    unsafe fn trace(&self, trc: *mut JSTracer) {
88        if self.get().is_null() {
89            return;
90        }
91        CallScriptTracer(trc, self as *const _ as *mut Self, c"script".as_ptr());
92    }
93}
94
95unsafe impl Traceable for Heap<*mut JSString> {
96    #[inline]
97    unsafe fn trace(&self, trc: *mut JSTracer) {
98        if self.get().is_null() {
99            return;
100        }
101        CallStringTracer(trc, self as *const _ as *mut Self, c"string".as_ptr());
102    }
103}
104
105unsafe impl Traceable for Heap<Value> {
106    #[inline]
107    unsafe fn trace(&self, trc: *mut JSTracer) {
108        CallValueTracer(trc, self as *const _ as *mut Self, c"value".as_ptr());
109    }
110}
111
112unsafe impl Traceable for Value {
113    #[inline]
114    unsafe fn trace(&self, trc: *mut JSTracer) {
115        CallValueRootTracer(trc, self as *const _ as *mut Self, c"value".as_ptr());
116    }
117}
118
119unsafe impl Traceable for Heap<jsid> {
120    #[inline]
121    unsafe fn trace(&self, trc: *mut JSTracer) {
122        CallIdTracer(trc, self as *const _ as *mut Self, c"id".as_ptr());
123    }
124}
125
126unsafe impl Traceable for PropertyDescriptor {
127    #[inline]
128    unsafe fn trace(&self, trc: *mut JSTracer) {
129        CallPropertyDescriptorTracer(trc, self as *const _ as *mut _);
130    }
131}
132
133unsafe impl<T: Traceable> Traceable for Rc<T> {
134    #[inline]
135    unsafe fn trace(&self, trc: *mut JSTracer) {
136        (**self).trace(trc);
137    }
138}
139
140unsafe impl<T: Traceable + ?Sized> Traceable for Box<T> {
141    #[inline]
142    unsafe fn trace(&self, trc: *mut JSTracer) {
143        (**self).trace(trc);
144    }
145}
146
147unsafe impl<T: Traceable + Copy> Traceable for Cell<T> {
148    #[inline]
149    unsafe fn trace(&self, trc: *mut JSTracer) {
150        self.get().trace(trc);
151    }
152}
153
154unsafe impl<T: Traceable> Traceable for UnsafeCell<T> {
155    #[inline]
156    unsafe fn trace(&self, trc: *mut JSTracer) {
157        (*self.get()).trace(trc);
158    }
159}
160
161unsafe impl<T: Traceable> Traceable for RefCell<T> {
162    #[inline]
163    unsafe fn trace(&self, trc: *mut JSTracer) {
164        (*self).borrow().trace(trc);
165    }
166}
167
168unsafe impl<T: Traceable> Traceable for Option<T> {
169    #[inline]
170    unsafe fn trace(&self, trc: *mut JSTracer) {
171        self.as_ref().map(|t| t.trace(trc));
172    }
173}
174
175unsafe impl<T: Traceable, E: Traceable> Traceable for Result<T, E> {
176    #[inline]
177    unsafe fn trace(&self, trc: *mut JSTracer) {
178        match self {
179            Ok(t) => t.trace(trc),
180            Err(e) => e.trace(trc),
181        }
182    }
183}
184
185unsafe impl<T: Traceable> Traceable for [T] {
186    #[inline]
187    unsafe fn trace(&self, trc: *mut JSTracer) {
188        for t in self.iter() {
189            t.trace(trc);
190        }
191    }
192}
193
194// jsmanaged array
195unsafe impl<T: Traceable, const COUNT: usize> Traceable for [T; COUNT] {
196    #[inline]
197    unsafe fn trace(&self, tracer: *mut JSTracer) {
198        for v in self.iter() {
199            v.trace(tracer);
200        }
201    }
202}
203
204unsafe impl<const N: usize> Traceable for ValueArray<N> {
205    #[inline]
206    unsafe fn trace(&self, tracer: *mut JSTracer) {
207        TraceValueArray(tracer, N, self.get_mut_ptr());
208    }
209}
210
211// TODO: Check if the following two are optimized to no-ops
212// if e.trace() is a no-op (e.g it is an impl_traceable_simple type)
213unsafe impl<T: Traceable> Traceable for Vec<T> {
214    #[inline]
215    unsafe fn trace(&self, trc: *mut JSTracer) {
216        for t in &*self {
217            t.trace(trc);
218        }
219    }
220}
221
222unsafe impl<T: Traceable> Traceable for VecDeque<T> {
223    #[inline]
224    unsafe fn trace(&self, trc: *mut JSTracer) {
225        for t in &*self {
226            t.trace(trc);
227        }
228    }
229}
230
231unsafe impl<K: Traceable + Eq + Hash, V: Traceable, S: BuildHasher> Traceable for HashMap<K, V, S> {
232    #[inline]
233    unsafe fn trace(&self, trc: *mut JSTracer) {
234        for (k, v) in &*self {
235            k.trace(trc);
236            v.trace(trc);
237        }
238    }
239}
240
241unsafe impl<T: Traceable + Eq + Hash, S: BuildHasher> Traceable for HashSet<T, S> {
242    #[inline]
243    unsafe fn trace(&self, trc: *mut JSTracer) {
244        for t in &*self {
245            t.trace(trc);
246        }
247    }
248}
249
250unsafe impl<K: Traceable + Eq + Hash, V: Traceable> Traceable for BTreeMap<K, V> {
251    #[inline]
252    unsafe fn trace(&self, trc: *mut JSTracer) {
253        for (k, v) in &*self {
254            k.trace(trc);
255            v.trace(trc);
256        }
257    }
258}
259
260unsafe impl<T: Traceable> Traceable for BTreeSet<T> {
261    #[inline]
262    unsafe fn trace(&self, trc: *mut JSTracer) {
263        for t in &*self {
264            t.trace(trc);
265        }
266    }
267}
268
269macro_rules! impl_traceable_tuple {
270    () => {
271        unsafe impl Traceable for () {
272            #[inline]
273            unsafe fn trace(&self, _: *mut JSTracer) {}
274        }
275    };
276    ($($name:ident)+) => {
277        unsafe impl<$($name: Traceable,)+> Traceable for ($($name,)+) {
278            #[allow(non_snake_case)]
279            #[inline]
280            unsafe fn trace(&self, trc: *mut JSTracer) {
281                let ($(ref $name,)+) = *self;
282                $($name.trace(trc);)+
283            }
284        }
285    };
286}
287
288impl_traceable_tuple! {}
289impl_traceable_tuple! { A }
290impl_traceable_tuple! { A B }
291impl_traceable_tuple! { A B C }
292impl_traceable_tuple! { A B C D }
293impl_traceable_tuple! { A B C D E }
294impl_traceable_tuple! { A B C D E F }
295impl_traceable_tuple! { A B C D E F G }
296impl_traceable_tuple! { A B C D E F G H }
297impl_traceable_tuple! { A B C D E F G H I }
298impl_traceable_tuple! { A B C D E F G H I J }
299impl_traceable_tuple! { A B C D E F G H I J K }
300impl_traceable_tuple! { A B C D E F G H I J K L }
301
302macro_rules! impl_traceable_fnptr {
303    () => {
304        unsafe impl<Ret> Traceable for fn() -> Ret {
305            #[inline]
306            unsafe fn trace(&self, _: *mut JSTracer) {}
307        }
308        unsafe impl<Ret> Traceable for unsafe fn() -> Ret {
309            #[inline]
310            unsafe fn trace(&self, _: *mut JSTracer) {}
311        }
312        unsafe impl<Ret> Traceable for extern "C" fn() -> Ret {
313            #[inline]
314            unsafe fn trace(&self, _: *mut JSTracer) {}
315        }
316        unsafe impl<Ret> Traceable for unsafe extern "C" fn() -> Ret {
317            #[inline]
318            unsafe fn trace(&self, _: *mut JSTracer) {}
319        }
320    };
321    ($($arg:ident)+) => {
322        unsafe impl<Ret, $($arg,)+> Traceable for fn($($arg,)+) -> Ret {
323            #[inline]
324            unsafe fn trace(&self, _: *mut JSTracer) {}
325        }
326        unsafe impl<Ret, $($arg,)+> Traceable for unsafe fn($($arg,)+) -> Ret {
327            #[inline]
328            unsafe fn trace(&self, _: *mut JSTracer) {}
329        }
330        unsafe impl<Ret, $($arg,)+> Traceable for extern "C" fn($($arg,)+) -> Ret {
331            #[inline]
332            unsafe fn trace(&self, _: *mut JSTracer) {}
333        }
334        unsafe impl<Ret, $($arg,)+> Traceable for unsafe extern "C" fn($($arg,)+) -> Ret {
335            #[inline]
336            unsafe fn trace(&self, _: *mut JSTracer) {}
337        }
338        unsafe impl<Ret, $($arg,)+> Traceable for extern "C" fn($($arg),+, ...) -> Ret {
339            #[inline]
340            unsafe fn trace(&self, _: *mut JSTracer) {}
341        }
342        unsafe impl<Ret, $($arg,)+> Traceable for unsafe extern "C" fn($($arg),+, ...) -> Ret {
343            #[inline]
344            unsafe fn trace(&self, _: *mut JSTracer) {}
345        }
346    }
347}
348
349impl_traceable_fnptr! {}
350impl_traceable_fnptr! { A }
351impl_traceable_fnptr! { A B }
352impl_traceable_fnptr! { A B C }
353impl_traceable_fnptr! { A B C D }
354impl_traceable_fnptr! { A B C D E }
355impl_traceable_fnptr! { A B C D E F }
356impl_traceable_fnptr! { A B C D E F G }
357impl_traceable_fnptr! { A B C D E F G H }
358impl_traceable_fnptr! { A B C D E F G H I }
359impl_traceable_fnptr! { A B C D E F G H I J }
360impl_traceable_fnptr! { A B C D E F G H I J K }
361impl_traceable_fnptr! { A B C D E F G H I J K L }
362
363/// For use on non-jsmanaged types
364macro_rules! impl_traceable_simple {
365    ($($ty:ty $(,)?)+) => {
366        $(
367            unsafe impl Traceable for $ty {
368                #[inline]
369                unsafe fn trace(&self, _: *mut JSTracer) {}
370            }
371        )+
372    }
373}
374
375impl_traceable_simple!(bool);
376impl_traceable_simple!(i8, i16, i32, i64, isize);
377impl_traceable_simple!(u8, u16, u32, u64, usize);
378impl_traceable_simple!(f32, f64);
379impl_traceable_simple!(char, String);
380impl_traceable_simple!(
381    NonZeroI128,
382    NonZeroI16,
383    NonZeroI32,
384    NonZeroI64,
385    NonZeroI8,
386    NonZeroIsize
387);
388impl_traceable_simple!(
389    NonZeroU128,
390    NonZeroU16,
391    NonZeroU32,
392    NonZeroU64,
393    NonZeroU8,
394    NonZeroUsize
395);
396impl_traceable_simple!(AtomicBool);
397impl_traceable_simple!(AtomicI8, AtomicI16, AtomicI32, AtomicI64, AtomicIsize);
398impl_traceable_simple!(AtomicU8, AtomicU16, AtomicU32, AtomicU64, AtomicUsize);
399impl_traceable_simple!(Cow<'static, str>);
400impl_traceable_simple!(TypeId);
401impl_traceable_simple!(Duration, Instant, SystemTime);
402impl_traceable_simple!(PathBuf);
403impl_traceable_simple!(Range<u64>);
404impl_traceable_simple!(JoinHandle<()>);
405impl_traceable_simple!(*mut JobQueue);
406
407unsafe impl<'a> Traceable for &'a str {
408    #[inline]
409    unsafe fn trace(&self, _: *mut JSTracer) {}
410}