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 base::text::{Utf8CodeUnitLength, Utf16CodeUnitLength};
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 smallvec::SmallVec;
25use style::author_styles::AuthorStyles;
26use style::stylesheet_set::{AuthorStylesheetSet, DocumentStylesheetSet};
27use tendril::TendrilSink;
28use tendril::fmt::UTF8;
29use tendril::stream::LossyDecoder;
30#[cfg(feature = "webxr")]
31use webxr_api::{Finger, Hand};
32use xml5ever::interface::TreeSink as XmlTreeSink;
33use xml5ever::tokenizer::XmlTokenizer;
34use xml5ever::tree_builder::{Tracer as XmlTracer, XmlTreeBuilder};
35
36use crate::JSTraceable;
37use crate::error::Error;
38use crate::reflector::Reflector;
39use crate::str::USVString;
40
41pub unsafe fn trace_reflector<T>(
46 tracer: *mut JSTracer,
47 description: &str,
48 reflector: &Reflector<T>,
49) {
50 trace!("tracing reflector {}", description);
51 unsafe { trace_object(tracer, description, reflector.rootable()) }
52}
53
54pub(crate) unsafe fn trace_object(
59 tracer: *mut JSTracer,
60 description: &str,
61 obj: &Heap<*mut JSObject>,
62) {
63 unsafe {
64 trace!("tracing {}", description);
65 CallObjectTracer(
66 tracer,
67 obj.ptr.get() as *mut _,
68 GCTraceKindToAscii(TraceKind::Object),
69 );
70 }
71}
72
73macro_rules! unsafe_no_jsmanaged_fields(
76 ($($ty:ty),+) => (
77 $(
78 #[expect(unsafe_code)]
79 unsafe impl crate::JSTraceable for $ty {
80 #[inline]
81 unsafe fn trace(&self, _: *mut ::js::jsapi::JSTracer) {
82 }
84 }
85 )+
86 );
87);
88
89unsafe_no_jsmanaged_fields!(USVString);
90unsafe_no_jsmanaged_fields!(Error);
91
92pub unsafe trait CustomTraceable {
99 unsafe fn trace(&self, trc: *mut JSTracer);
107}
108
109unsafe impl<T: CustomTraceable> CustomTraceable for Box<T> {
110 #[inline]
111 unsafe fn trace(&self, trc: *mut JSTracer) {
112 unsafe { (**self).trace(trc) };
113 }
114}
115
116unsafe impl<T: JSTraceable> CustomTraceable for OnceCell<T> {
117 unsafe fn trace(&self, tracer: *mut JSTracer) {
118 if let Some(value) = self.get() {
119 unsafe { value.trace(tracer) }
120 }
121 }
122}
123
124unsafe impl<T> CustomTraceable for Sender<T> {
125 unsafe fn trace(&self, _: *mut JSTracer) {}
126}
127
128unsafe impl<T: JSTraceable> CustomTraceable for ServoArc<T> {
129 unsafe fn trace(&self, trc: *mut JSTracer) {
130 unsafe { (**self).trace(trc) }
131 }
132}
133
134unsafe impl<T: JSTraceable> CustomTraceable for RwLock<T> {
135 unsafe fn trace(&self, trc: *mut JSTracer) {
136 unsafe { self.read().trace(trc) }
137 }
138}
139
140unsafe impl<T: JSTraceable + Eq + Hash> CustomTraceable for indexmap::IndexSet<T> {
141 #[inline]
142 unsafe fn trace(&self, trc: *mut JSTracer) {
143 for e in self.iter() {
144 unsafe { e.trace(trc) };
145 }
146 }
147}
148
149unsafe impl<T: JSTraceable + 'static> CustomTraceable for SmallVec<[T; 1]> {
152 #[inline]
153 unsafe fn trace(&self, trc: *mut JSTracer) {
154 for e in self.iter() {
155 unsafe { e.trace(trc) };
156 }
157 }
158}
159
160unsafe impl<K, V, S> CustomTraceable for IndexMap<K, V, S>
161where
162 K: Hash + Eq + JSTraceable,
163 V: JSTraceable,
164 S: BuildHasher,
165{
166 #[inline]
167 unsafe fn trace(&self, trc: *mut JSTracer) {
168 for (k, v) in self {
169 unsafe { k.trace(trc) };
170 unsafe { v.trace(trc) };
171 }
172 }
173}
174
175unsafe impl<S> CustomTraceable for DocumentStylesheetSet<S>
176where
177 S: JSTraceable + ::style::stylesheets::StylesheetInDocument + PartialEq + 'static,
178{
179 unsafe fn trace(&self, tracer: *mut JSTracer) {
180 for (s, _origin) in self.iter() {
181 unsafe { s.trace(tracer) };
182 }
183 }
184}
185
186unsafe impl<S> CustomTraceable for AuthorStylesheetSet<S>
187where
188 S: JSTraceable + ::style::stylesheets::StylesheetInDocument + PartialEq + 'static,
189{
190 unsafe fn trace(&self, tracer: *mut JSTracer) {
191 for s in self.iter() {
192 unsafe { s.trace(tracer) };
193 }
194 }
195}
196
197unsafe impl<S> CustomTraceable for AuthorStyles<S>
198where
199 S: JSTraceable + ::style::stylesheets::StylesheetInDocument + PartialEq + 'static,
200{
201 unsafe fn trace(&self, tracer: *mut JSTracer) {
202 unsafe { self.stylesheets.trace(tracer) };
203 }
204}
205
206unsafe impl<Sink> CustomTraceable for LossyDecoder<Sink>
207where
208 Sink: JSTraceable + TendrilSink<UTF8>,
209{
210 unsafe fn trace(&self, tracer: *mut JSTracer) {
211 unsafe { self.inner_sink().trace(tracer) };
212 }
213}
214
215#[cfg(feature = "webxr")]
216unsafe impl<J> CustomTraceable for Hand<J>
217where
218 J: JSTraceable,
219{
220 #[inline]
221 unsafe fn trace(&self, trc: *mut JSTracer) {
222 let Hand {
224 ref wrist,
225 ref thumb_metacarpal,
226 ref thumb_phalanx_proximal,
227 ref thumb_phalanx_distal,
228 ref thumb_phalanx_tip,
229 ref index,
230 ref middle,
231 ref ring,
232 ref little,
233 } = *self;
234 unsafe {
235 wrist.trace(trc);
236 thumb_metacarpal.trace(trc);
237 thumb_phalanx_proximal.trace(trc);
238 thumb_phalanx_distal.trace(trc);
239 thumb_phalanx_tip.trace(trc);
240 index.trace(trc);
241 middle.trace(trc);
242 ring.trace(trc);
243 little.trace(trc);
244 }
245 }
246}
247
248#[cfg(feature = "webxr")]
249unsafe impl<J> CustomTraceable for Finger<J>
250where
251 J: JSTraceable,
252{
253 #[inline]
254 unsafe fn trace(&self, trc: *mut JSTracer) {
255 let Finger {
257 ref metacarpal,
258 ref phalanx_proximal,
259 ref phalanx_intermediate,
260 ref phalanx_distal,
261 ref phalanx_tip,
262 } = *self;
263 unsafe {
264 metacarpal.trace(trc);
265 phalanx_proximal.trace(trc);
266 phalanx_intermediate.trace(trc);
267 phalanx_distal.trace(trc);
268 phalanx_tip.trace(trc);
269 }
270 }
271}
272
273unsafe impl<Handle: JSTraceable + Clone, Sink: TreeSink<Handle = Handle> + JSTraceable>
274 CustomTraceable for TreeBuilder<Handle, Sink>
275{
276 unsafe fn trace(&self, trc: *mut JSTracer) {
277 struct Tracer<Handle>(*mut JSTracer, PhantomData<Handle>);
278 let tracer = Tracer::<Handle>(trc, PhantomData);
279
280 impl<Handle: JSTraceable> HtmlTracer for Tracer<Handle> {
281 type Handle = Handle;
282 fn trace_handle(&self, node: &Handle) {
283 unsafe {
284 node.trace(self.0);
285 }
286 }
287 }
288
289 self.trace_handles(&tracer);
290 unsafe { self.sink.trace(trc) };
291 }
292}
293
294#[expect(unsafe_code)]
295unsafe impl<Handle: JSTraceable + Clone, Sink: TokenSink<Handle = Handle> + CustomTraceable>
296 CustomTraceable for Tokenizer<Sink>
297{
298 unsafe fn trace(&self, trc: *mut JSTracer) {
299 unsafe { self.sink.trace(trc) };
300 }
301}
302
303#[expect(unsafe_code)]
304unsafe impl<Handle: JSTraceable + Clone, Sink: JSTraceable + XmlTreeSink<Handle = Handle>>
305 CustomTraceable for XmlTokenizer<XmlTreeBuilder<Handle, Sink>>
306{
307 unsafe fn trace(&self, trc: *mut JSTracer) {
308 struct Tracer<Handle>(*mut JSTracer, PhantomData<Handle>);
309 let tracer = Tracer(trc, PhantomData);
310
311 impl<Handle: JSTraceable> XmlTracer for Tracer<Handle> {
312 type Handle = Handle;
313 fn trace_handle(&self, node: &Handle) {
314 unsafe {
315 node.trace(self.0);
316 }
317 }
318 }
319
320 let tree_builder = &self.sink;
321 tree_builder.trace_handles(&tracer);
322 unsafe { tree_builder.sink.trace(trc) };
323 }
324}
325
326#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]
333pub struct RootedTraceableBox<T: JSTraceable + 'static>(js::gc::RootedTraceableBox<T>);
334
335unsafe impl<T: JSTraceable + 'static> JSTraceable for RootedTraceableBox<T> {
336 unsafe fn trace(&self, tracer: *mut JSTracer) {
337 unsafe { self.0.trace(tracer) };
338 }
339}
340
341impl<T: JSTraceable + 'static> RootedTraceableBox<T> {
342 pub fn new(traceable: T) -> RootedTraceableBox<T> {
344 Self(js::gc::RootedTraceableBox::new(traceable))
345 }
346
347 pub fn from_box(boxed_traceable: Box<T>) -> RootedTraceableBox<T> {
349 Self(js::gc::RootedTraceableBox::from_box(boxed_traceable))
350 }
351}
352
353impl<T> RootedTraceableBox<Heap<T>>
354where
355 Heap<T>: JSTraceable + 'static,
356 T: GCMethods + Copy,
357{
358 pub fn handle(&self) -> Handle<'_, T> {
359 self.0.handle()
360 }
361}
362
363impl<T: JSTraceable + MallocSizeOf> MallocSizeOf for RootedTraceableBox<T> {
364 fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
365 let inner = unsafe { Box::from_raw(self.0.ptr()) };
368 let size = inner.size_of(ops);
369 mem::forget(inner);
370 size
371 }
372}
373
374impl<T: JSTraceable + Default> Default for RootedTraceableBox<T> {
375 fn default() -> RootedTraceableBox<T> {
376 RootedTraceableBox::new(T::default())
377 }
378}
379
380impl<T: JSTraceable> Deref for RootedTraceableBox<T> {
381 type Target = T;
382 fn deref(&self) -> &T {
383 self.0.deref()
384 }
385}
386
387impl<T: JSTraceable> DerefMut for RootedTraceableBox<T> {
388 fn deref_mut(&mut self) -> &mut T {
389 self.0.deref_mut()
390 }
391}
392
393#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
397#[cfg_attr(crown, crown::trace_in_no_trace_lint::must_not_have_traceable)]
398pub(crate) struct NoTrace<T>(pub(crate) T);
399
400impl<T: Display> Display for NoTrace<T> {
401 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
402 self.0.fmt(f)
403 }
404}
405
406impl<T> From<T> for NoTrace<T> {
407 fn from(item: T) -> Self {
408 Self(item)
409 }
410}
411
412#[expect(unsafe_code)]
413unsafe impl<T> JSTraceable for NoTrace<T> {
414 #[inline]
415 unsafe fn trace(&self, _: *mut ::js::jsapi::JSTracer) {}
416}
417
418impl<T: MallocSizeOf> MallocSizeOf for NoTrace<T> {
419 fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
420 self.0.size_of(ops)
421 }
422}
423
424unsafe impl CustomTraceable for Utf8CodeUnitLength {
425 #[inline]
426 unsafe fn trace(&self, _: *mut JSTracer) {}
427}
428
429unsafe impl CustomTraceable for Utf16CodeUnitLength {
430 #[inline]
431 unsafe fn trace(&self, _: *mut JSTracer) {}
432}
433
434unsafe impl<T: CustomTraceable> CustomTraceable for Option<T> {
435 #[inline]
436 unsafe fn trace(&self, tracer: *mut JSTracer) {
437 unsafe {
438 self.as_ref().inspect(|value| value.trace(tracer));
439 }
440 }
441}