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