1use std::cell::OnceCell;
6use std::fmt::Display;
7use std::hash::{BuildHasher, Hash};
8use std::marker::PhantomData;
9use std::mem;
10use std::ops::{Deref, DerefMut};
11
12use atomic_refcell::AtomicRefCell;
13use crossbeam_channel::Sender;
14use html5ever::interface::{Tracer as HtmlTracer, TreeSink};
15use html5ever::tokenizer::{TokenSink, Tokenizer};
16use html5ever::tree_builder::TreeBuilder;
17use indexmap::IndexMap;
18use js::gc::{GCMethods, Handle};
19use js::glue::CallObjectTracer;
20use js::jsapi::{GCTraceKindToAscii, Heap, JSObject, JSTracer, TraceKind};
21use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
22use parking_lot::RwLock;
23use servo_arc::Arc as ServoArc;
24use servo_base::text::{Utf8CodeUnits, Utf16CodeUnits};
25use smallvec::{Array, SmallVec};
26use style::author_styles::AuthorStyles;
27use style::stylesheet_set::{AuthorStylesheetSet, DocumentStylesheetSet};
28use tendril::TendrilSink;
29use tendril::fmt::UTF8;
30use tendril::stream::LossyDecoder;
31#[cfg(feature = "webxr")]
32use webxr_api::{Finger, Hand};
33use xml5ever::interface::TreeSink as XmlTreeSink;
34use xml5ever::tokenizer::XmlTokenizer;
35use xml5ever::tree_builder::{Tracer as XmlTracer, XmlTreeBuilder};
36
37use crate::JSTraceable;
38use crate::error::Error;
39use crate::reflector::Reflector;
40use crate::str::USVString;
41use crate::tasks::TaskBox;
42
43pub unsafe fn trace_reflector<T>(
48 tracer: *mut JSTracer,
49 description: &str,
50 reflector: &Reflector<T>,
51) {
52 trace!("tracing reflector {}", description);
53 unsafe { trace_object(tracer, description, reflector.rootable()) }
54}
55
56pub(crate) unsafe fn trace_object(
61 tracer: *mut JSTracer,
62 description: &str,
63 obj: &Heap<*mut JSObject>,
64) {
65 unsafe {
66 trace!("tracing {}", description);
67 CallObjectTracer(
68 tracer,
69 obj.ptr.get() as *mut _,
70 GCTraceKindToAscii(TraceKind::Object),
71 );
72 }
73}
74
75macro_rules! unsafe_no_jsmanaged_fields(
78 ($($ty:ty),+) => (
79 $(
80 #[expect(unsafe_code)]
81 unsafe impl crate::JSTraceable for $ty {
82 #[inline]
83 unsafe fn trace(&self, _: *mut ::js::jsapi::JSTracer) {
84 }
86 }
87 )+
88 );
89);
90
91unsafe_no_jsmanaged_fields!(USVString);
92unsafe_no_jsmanaged_fields!(Error);
93unsafe_no_jsmanaged_fields!(Box<dyn TaskBox>);
94
95pub unsafe trait CustomTraceable {
102 unsafe fn trace(&self, trc: *mut JSTracer);
110}
111
112unsafe impl<T: CustomTraceable> CustomTraceable for Box<T> {
113 #[inline]
114 unsafe fn trace(&self, trc: *mut JSTracer) {
115 unsafe { (**self).trace(trc) };
116 }
117}
118
119unsafe impl<T: JSTraceable> CustomTraceable for OnceCell<T> {
120 unsafe fn trace(&self, tracer: *mut JSTracer) {
121 if let Some(value) = self.get() {
122 unsafe { value.trace(tracer) }
123 }
124 }
125}
126
127unsafe impl<T> CustomTraceable for Sender<T> {
128 unsafe fn trace(&self, _: *mut JSTracer) {}
129}
130
131unsafe impl<T: JSTraceable> CustomTraceable for ServoArc<T> {
132 unsafe fn trace(&self, trc: *mut JSTracer) {
133 unsafe { (**self).trace(trc) }
134 }
135}
136
137unsafe impl<T: JSTraceable> CustomTraceable for RwLock<T> {
138 unsafe fn trace(&self, trc: *mut JSTracer) {
139 unsafe { self.read().trace(trc) }
140 }
141}
142
143unsafe impl<T: JSTraceable> CustomTraceable for AtomicRefCell<T> {
144 unsafe fn trace(&self, trc: *mut JSTracer) {
145 unsafe { self.borrow().trace(trc) }
146 }
147}
148
149unsafe impl<T: JSTraceable + Eq + Hash> CustomTraceable for indexmap::IndexSet<T> {
150 #[inline]
151 unsafe fn trace(&self, trc: *mut JSTracer) {
152 for e in self.iter() {
153 unsafe { e.trace(trc) };
154 }
155 }
156}
157
158unsafe impl<T: JSTraceable + 'static, const N: usize> CustomTraceable for SmallVec<[T; N]> {
161 #[inline]
162 unsafe fn trace(&self, trc: *mut JSTracer) {
163 for e in self.iter() {
164 unsafe { e.trace(trc) };
165 }
166 }
167}
168
169unsafe impl<K, V, S> CustomTraceable for IndexMap<K, V, S>
170where
171 K: Hash + Eq + JSTraceable,
172 V: JSTraceable,
173 S: BuildHasher,
174{
175 #[inline]
176 unsafe fn trace(&self, trc: *mut JSTracer) {
177 for (k, v) in self {
178 unsafe { k.trace(trc) };
179 unsafe { v.trace(trc) };
180 }
181 }
182}
183
184unsafe impl<S> CustomTraceable for DocumentStylesheetSet<S>
185where
186 S: JSTraceable + ::style::stylesheets::StylesheetInDocument + PartialEq + 'static,
187{
188 unsafe fn trace(&self, tracer: *mut JSTracer) {
189 for (s, _origin) in self.iter() {
190 unsafe { s.trace(tracer) };
191 }
192 }
193}
194
195unsafe impl<S> CustomTraceable for AuthorStylesheetSet<S>
196where
197 S: JSTraceable + ::style::stylesheets::StylesheetInDocument + PartialEq + 'static,
198{
199 unsafe fn trace(&self, tracer: *mut JSTracer) {
200 for s in self.iter() {
201 unsafe { s.trace(tracer) };
202 }
203 }
204}
205
206unsafe impl<S> CustomTraceable for AuthorStyles<S>
207where
208 S: JSTraceable + ::style::stylesheets::StylesheetInDocument + PartialEq + 'static,
209{
210 unsafe fn trace(&self, tracer: *mut JSTracer) {
211 unsafe { self.stylesheets.trace(tracer) };
212 }
213}
214
215unsafe impl<Sink> CustomTraceable for LossyDecoder<Sink>
216where
217 Sink: JSTraceable + TendrilSink<UTF8>,
218{
219 unsafe fn trace(&self, tracer: *mut JSTracer) {
220 unsafe { self.inner_sink().trace(tracer) };
221 }
222}
223
224#[cfg(feature = "webxr")]
225unsafe impl<J> CustomTraceable for Hand<J>
226where
227 J: JSTraceable,
228{
229 #[inline]
230 unsafe fn trace(&self, trc: *mut JSTracer) {
231 let Hand {
233 ref wrist,
234 ref thumb_metacarpal,
235 ref thumb_phalanx_proximal,
236 ref thumb_phalanx_distal,
237 ref thumb_phalanx_tip,
238 ref index,
239 ref middle,
240 ref ring,
241 ref little,
242 } = *self;
243 unsafe {
244 wrist.trace(trc);
245 thumb_metacarpal.trace(trc);
246 thumb_phalanx_proximal.trace(trc);
247 thumb_phalanx_distal.trace(trc);
248 thumb_phalanx_tip.trace(trc);
249 index.trace(trc);
250 middle.trace(trc);
251 ring.trace(trc);
252 little.trace(trc);
253 }
254 }
255}
256
257#[cfg(feature = "webxr")]
258unsafe impl<J> CustomTraceable for Finger<J>
259where
260 J: JSTraceable,
261{
262 #[inline]
263 unsafe fn trace(&self, trc: *mut JSTracer) {
264 let Finger {
266 ref metacarpal,
267 ref phalanx_proximal,
268 ref phalanx_intermediate,
269 ref phalanx_distal,
270 ref phalanx_tip,
271 } = *self;
272 unsafe {
273 metacarpal.trace(trc);
274 phalanx_proximal.trace(trc);
275 phalanx_intermediate.trace(trc);
276 phalanx_distal.trace(trc);
277 phalanx_tip.trace(trc);
278 }
279 }
280}
281
282unsafe impl<Handle: JSTraceable + Clone, Sink: TreeSink<Handle = Handle> + JSTraceable>
283 CustomTraceable for TreeBuilder<Handle, Sink>
284{
285 unsafe fn trace(&self, trc: *mut JSTracer) {
286 struct Tracer<Handle>(*mut JSTracer, PhantomData<Handle>);
287 let tracer = Tracer::<Handle>(trc, PhantomData);
288
289 impl<Handle: JSTraceable> HtmlTracer for Tracer<Handle> {
290 type Handle = Handle;
291 fn trace_handle(&self, node: &Handle) {
292 unsafe {
293 node.trace(self.0);
294 }
295 }
296 }
297
298 self.trace_handles(&tracer);
299 unsafe { self.sink.trace(trc) };
300 }
301}
302
303#[expect(unsafe_code)]
304unsafe impl<Handle: JSTraceable + Clone, Sink: TokenSink<Handle = Handle> + CustomTraceable>
305 CustomTraceable for Tokenizer<Sink>
306{
307 unsafe fn trace(&self, trc: *mut JSTracer) {
308 unsafe { self.sink.trace(trc) };
309 }
310}
311
312#[expect(unsafe_code)]
313unsafe impl<Handle: JSTraceable + Clone, Sink: JSTraceable + XmlTreeSink<Handle = Handle>>
314 CustomTraceable for XmlTokenizer<XmlTreeBuilder<Handle, Sink>>
315{
316 unsafe fn trace(&self, trc: *mut JSTracer) {
317 struct Tracer<Handle>(*mut JSTracer, PhantomData<Handle>);
318 let tracer = Tracer(trc, PhantomData);
319
320 impl<Handle: JSTraceable> XmlTracer for Tracer<Handle> {
321 type Handle = Handle;
322 fn trace_handle(&self, node: &Handle) {
323 unsafe {
324 node.trace(self.0);
325 }
326 }
327 }
328
329 let tree_builder = &self.sink;
330 tree_builder.trace_handles(&tracer);
331 unsafe { tree_builder.sink.trace(trc) };
332 }
333}
334
335#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]
342pub struct RootedTraceableBox<T: JSTraceable + 'static>(js::gc::RootedTraceableBox<T>);
343
344unsafe impl<T: JSTraceable + 'static> JSTraceable for RootedTraceableBox<T> {
345 unsafe fn trace(&self, tracer: *mut JSTracer) {
346 unsafe { self.0.trace(tracer) };
347 }
348}
349
350impl<T: JSTraceable + 'static> RootedTraceableBox<T> {
351 pub fn new(traceable: T) -> RootedTraceableBox<T> {
353 Self(js::gc::RootedTraceableBox::new(traceable))
354 }
355
356 pub fn from_box(boxed_traceable: Box<T>) -> RootedTraceableBox<T> {
358 Self(js::gc::RootedTraceableBox::from_box(boxed_traceable))
359 }
360
361 pub fn into_box(self) -> Box<T> {
362 self.0.into_box()
363 }
364}
365
366impl<T> RootedTraceableBox<Heap<T>>
367where
368 Heap<T>: JSTraceable + 'static,
369 T: GCMethods + Copy,
370{
371 pub fn handle(&self) -> Handle<'_, T> {
372 self.0.handle()
373 }
374}
375
376impl<T: JSTraceable + MallocSizeOf> MallocSizeOf for RootedTraceableBox<T> {
377 fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
378 let inner = unsafe { Box::from_raw(self.0.ptr()) };
381 let size = inner.size_of(ops);
382 mem::forget(inner);
383 size
384 }
385}
386
387impl<T: JSTraceable + Default> Default for RootedTraceableBox<T> {
388 fn default() -> RootedTraceableBox<T> {
389 RootedTraceableBox::new(T::default())
390 }
391}
392
393impl<T: JSTraceable> Deref for RootedTraceableBox<T> {
394 type Target = T;
395 fn deref(&self) -> &T {
396 self.0.deref()
397 }
398}
399
400impl<T: JSTraceable> DerefMut for RootedTraceableBox<T> {
401 fn deref_mut(&mut self) -> &mut T {
402 self.0.deref_mut()
403 }
404}
405
406#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
410#[cfg_attr(crown, crown::trace_in_no_trace_lint::must_not_have_traceable)]
411pub(crate) struct NoTrace<T>(pub(crate) T);
412
413impl<T: Display> Display for NoTrace<T> {
414 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
415 self.0.fmt(f)
416 }
417}
418
419impl<T> From<T> for NoTrace<T> {
420 fn from(item: T) -> Self {
421 Self(item)
422 }
423}
424
425#[expect(unsafe_code)]
426unsafe impl<T> JSTraceable for NoTrace<T> {
427 #[inline]
428 unsafe fn trace(&self, _: *mut ::js::jsapi::JSTracer) {}
429}
430
431impl<T: MallocSizeOf> MallocSizeOf for NoTrace<T> {
432 fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
433 self.0.size_of(ops)
434 }
435}
436
437unsafe impl CustomTraceable for Utf8CodeUnits {
438 #[inline]
439 unsafe fn trace(&self, _: *mut JSTracer) {}
440}
441
442unsafe impl CustomTraceable for Utf16CodeUnits {
443 #[inline]
444 unsafe fn trace(&self, _: *mut JSTracer) {}
445}
446
447unsafe impl<T: CustomTraceable> CustomTraceable for Option<T> {
448 #[inline]
449 unsafe fn trace(&self, tracer: *mut JSTracer) {
450 unsafe {
451 self.as_ref().inspect(|value| value.trace(tracer));
452 }
453 }
454}
455
456pub struct TraceableSmallVec<A: Array>(SmallVec<A>);
460
461impl<A: Array> Default for TraceableSmallVec<A> {
462 fn default() -> Self {
463 Self(Default::default())
464 }
465}
466
467impl<A: Array> Deref for TraceableSmallVec<A> {
468 type Target = SmallVec<A>;
469 fn deref(&self) -> &SmallVec<A> {
470 &self.0
471 }
472}
473
474impl<A: Array> DerefMut for TraceableSmallVec<A> {
475 fn deref_mut(&mut self) -> &mut SmallVec<A> {
476 &mut self.0
477 }
478}
479
480unsafe impl<A: Array> js::rust::Trace for TraceableSmallVec<A>
481where
482 A::Item: JSTraceable,
483{
484 #[inline]
485 unsafe fn trace(&self, tracer: *mut JSTracer) {
486 for value in self.0.iter() {
487 unsafe { value.trace(tracer) };
488 }
489 }
490}