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