1use std::{
2 any::TypeId,
3 borrow::{Cow, ToOwned},
4 cell::{Cell, OnceCell},
5 collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque},
6 hash::{BuildHasher, Hash},
7 marker::PhantomData,
8 num::{
9 NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize, NonZeroU8,
10 NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize,
11 },
12 path::{Path, PathBuf},
13 rc::Rc,
14 sync::atomic,
15 time::{Instant, SystemTime},
16};
17
18use crate::GcErasedPointer;
19
20#[doc(hidden)]
22#[allow(missing_debug_implementations)]
23pub struct Tracer {
24 queue: VecDeque<GcErasedPointer>,
25}
26
27impl Tracer {
28 pub(crate) fn new() -> Self {
29 Self {
30 queue: VecDeque::default(),
31 }
32 }
33
34 pub(crate) fn enqueue(&mut self, node: GcErasedPointer) {
35 self.queue.push_back(node);
36 }
37
38 pub(crate) unsafe fn trace_until_empty(&mut self) {
44 while let Some(node) = self.queue.pop_front() {
45 let node_ref = unsafe { node.as_ref() };
46 if node_ref.is_marked() {
47 continue;
48 }
49 node_ref.header.mark();
50 let trace_fn = node_ref.trace_fn();
51
52 unsafe { trace_fn(node, self) }
55 }
56 }
57
58 pub(crate) fn is_empty(&mut self) -> bool {
59 self.queue.is_empty()
60 }
61}
62
63pub trait Finalize {
65 fn finalize(&self) {}
67}
68
69pub unsafe trait Trace: Finalize {
79 unsafe fn trace(&self, tracer: &mut Tracer);
85
86 unsafe fn trace_non_roots(&self);
92
93 fn run_finalizer(&self);
96}
97
98#[macro_export]
102macro_rules! empty_trace {
103 () => {
104 #[inline]
105 unsafe fn trace(&self, _tracer: &mut $crate::Tracer) {}
106 #[inline]
107 unsafe fn trace_non_roots(&self) {}
108 #[inline]
109 fn run_finalizer(&self) {
110 $crate::Finalize::finalize(self)
111 }
112 };
113}
114
115#[macro_export]
125macro_rules! custom_trace {
126 ($this:ident, $marker:ident, $body:expr) => {
127 #[inline]
128 unsafe fn trace(&self, tracer: &mut $crate::Tracer) {
129 let mut $marker = |it: &dyn $crate::Trace| {
130 unsafe {
132 $crate::Trace::trace(it, tracer);
133 }
134 };
135 let $this = self;
136 $body
137 }
138 #[inline]
139 unsafe fn trace_non_roots(&self) {
140 fn $marker<T: $crate::Trace + ?Sized>(it: &T) {
141 unsafe {
143 $crate::Trace::trace_non_roots(it);
144 }
145 }
146 let $this = self;
147 $body
148 }
149 #[inline]
150 fn run_finalizer(&self) {
151 fn $marker<T: $crate::Trace + ?Sized>(it: &T) {
152 $crate::Trace::run_finalizer(it);
153 }
154 $crate::Finalize::finalize(self);
155 let $this = self;
156 $body
157 }
158 };
159}
160
161impl<T: ?Sized> Finalize for &'static T {}
162unsafe impl<T: ?Sized> Trace for &'static T {
164 empty_trace!();
165}
166
167macro_rules! simple_empty_finalize_trace {
168 ($($T:ty),*) => {
169 $(
170 impl Finalize for $T {}
171
172 unsafe impl Trace for $T { empty_trace!(); }
175 )*
176 }
177}
178
179simple_empty_finalize_trace![
180 (),
181 bool,
182 isize,
183 usize,
184 i8,
185 u8,
186 i16,
187 u16,
188 i32,
189 u32,
190 i64,
191 u64,
192 i128,
193 u128,
194 f32,
195 f64,
196 char,
197 TypeId,
198 String,
199 str,
200 Rc<str>,
201 Path,
202 PathBuf,
203 Instant,
204 SystemTime,
205 NonZeroIsize,
206 NonZeroUsize,
207 NonZeroI8,
208 NonZeroU8,
209 NonZeroI16,
210 NonZeroU16,
211 NonZeroI32,
212 NonZeroU32,
213 NonZeroI64,
214 NonZeroU64,
215 NonZeroI128,
216 NonZeroU128
217];
218
219#[cfg(not(target_family = "wasm"))]
220simple_empty_finalize_trace![
221 std::fs::File,
222 std::fs::FileType,
223 std::net::TcpStream,
224 std::net::UdpSocket
225];
226
227#[cfg(target_has_atomic = "8")]
228simple_empty_finalize_trace![atomic::AtomicBool, atomic::AtomicI8, atomic::AtomicU8];
229
230#[cfg(target_has_atomic = "16")]
231simple_empty_finalize_trace![atomic::AtomicI16, atomic::AtomicU16];
232
233#[cfg(target_has_atomic = "32")]
234simple_empty_finalize_trace![atomic::AtomicI32, atomic::AtomicU32];
235
236#[cfg(target_has_atomic = "64")]
237simple_empty_finalize_trace![atomic::AtomicI64, atomic::AtomicU64];
238
239#[cfg(target_has_atomic = "ptr")]
240simple_empty_finalize_trace![atomic::AtomicIsize, atomic::AtomicUsize];
241
242impl<T: Trace, const N: usize> Finalize for [T; N] {}
243unsafe impl<T: Trace, const N: usize> Trace for [T; N] {
246 custom_trace!(this, mark, {
247 for v in this {
248 mark(v);
249 }
250 });
251}
252
253macro_rules! fn_finalize_trace_one {
254 ($ty:ty $(,$args:ident)*) => {
255 impl<Ret $(,$args)*> Finalize for $ty {}
256 unsafe impl<Ret $(,$args)*> Trace for $ty { empty_trace!(); }
259 }
260}
261macro_rules! fn_finalize_trace_group {
262 () => {
263 fn_finalize_trace_one!(extern "Rust" fn () -> Ret);
264 fn_finalize_trace_one!(extern "C" fn () -> Ret);
265 fn_finalize_trace_one!(unsafe extern "Rust" fn () -> Ret);
266 fn_finalize_trace_one!(unsafe extern "C" fn () -> Ret);
267 };
268 ($($args:ident),*) => {
269 fn_finalize_trace_one!(extern "Rust" fn ($($args),*) -> Ret, $($args),*);
270 fn_finalize_trace_one!(extern "C" fn ($($args),*) -> Ret, $($args),*);
271 fn_finalize_trace_one!(extern "C" fn ($($args),*, ...) -> Ret, $($args),*);
272 fn_finalize_trace_one!(unsafe extern "Rust" fn ($($args),*) -> Ret, $($args),*);
273 fn_finalize_trace_one!(unsafe extern "C" fn ($($args),*) -> Ret, $($args),*);
274 fn_finalize_trace_one!(unsafe extern "C" fn ($($args),*, ...) -> Ret, $($args),*);
275 }
276}
277
278macro_rules! tuple_finalize_trace {
279 () => {}; ($($args:ident),*) => {
281 impl<$($args),*> Finalize for ($($args,)*) {}
282 unsafe impl<$($args: $crate::Trace),*> Trace for ($($args,)*) {
285 custom_trace!(this, mark, {
286 #[allow(non_snake_case, unused_unsafe, unused_mut)]
287 let mut avoid_lints = |&($(ref $args,)*): &($($args,)*)| {
288 unsafe { $(mark($args);)* }
290 };
291 avoid_lints(this)
292 });
293 }
294 }
295}
296
297macro_rules! type_arg_tuple_based_finalize_trace_impls {
298 ($(($($args:ident),*);)*) => {
299 $(
300 fn_finalize_trace_group!($($args),*);
301 tuple_finalize_trace!($($args),*);
302 )*
303 }
304}
305
306type_arg_tuple_based_finalize_trace_impls![
307 ();
308 (A);
309 (A, B);
310 (A, B, C);
311 (A, B, C, D);
312 (A, B, C, D, E);
313 (A, B, C, D, E, F);
314 (A, B, C, D, E, F, G);
315 (A, B, C, D, E, F, G, H);
316 (A, B, C, D, E, F, G, H, I);
317 (A, B, C, D, E, F, G, H, I, J);
318 (A, B, C, D, E, F, G, H, I, J, K);
319 (A, B, C, D, E, F, G, H, I, J, K, L);
320];
321
322impl<T: Trace + ?Sized> Finalize for Box<T> {}
323unsafe impl<T: Trace + ?Sized> Trace for Box<T> {
325 #[inline]
326 unsafe fn trace(&self, tracer: &mut Tracer) {
327 unsafe {
329 Trace::trace(&**self, tracer);
330 }
331 }
332 #[inline]
333 unsafe fn trace_non_roots(&self) {
334 unsafe {
336 Trace::trace_non_roots(&**self);
337 }
338 }
339 #[inline]
340 fn run_finalizer(&self) {
341 Finalize::finalize(self);
342 Trace::run_finalizer(&**self);
343 }
344}
345
346impl<T: Trace> Finalize for Box<[T]> {}
347unsafe impl<T: Trace> Trace for Box<[T]> {
349 custom_trace!(this, mark, {
350 for e in &**this {
351 mark(e);
352 }
353 });
354}
355
356impl<T: Trace> Finalize for Vec<T> {}
357unsafe impl<T: Trace> Trace for Vec<T> {
359 custom_trace!(this, mark, {
360 for e in this {
361 mark(e);
362 }
363 });
364}
365
366#[cfg(feature = "thin-vec")]
367impl<T: Trace> Finalize for thin_vec::ThinVec<T> {}
368
369#[cfg(feature = "thin-vec")]
370unsafe impl<T: Trace> Trace for thin_vec::ThinVec<T> {
372 custom_trace!(this, mark, {
373 for e in this {
374 mark(e);
375 }
376 });
377}
378
379#[cfg(feature = "arrayvec")]
380impl<T: Trace, const N: usize> Finalize for arrayvec::ArrayVec<T, N> {}
381
382#[cfg(feature = "arrayvec")]
383unsafe impl<T: Trace, const N: usize> Trace for arrayvec::ArrayVec<T, N> {
385 custom_trace!(this, mark, {
386 for e in this {
387 mark(e);
388 }
389 });
390}
391
392impl<T: Trace> Finalize for Option<T> {}
393unsafe impl<T: Trace> Trace for Option<T> {
395 custom_trace!(this, mark, {
396 if let Some(ref v) = *this {
397 mark(v);
398 }
399 });
400}
401
402impl<T: Trace, E: Trace> Finalize for Result<T, E> {}
403unsafe impl<T: Trace, E: Trace> Trace for Result<T, E> {
405 custom_trace!(this, mark, {
406 match *this {
407 Ok(ref v) => mark(v),
408 Err(ref v) => mark(v),
409 }
410 });
411}
412
413impl<T: Ord + Trace> Finalize for BinaryHeap<T> {}
414unsafe impl<T: Ord + Trace> Trace for BinaryHeap<T> {
416 custom_trace!(this, mark, {
417 for v in this {
418 mark(v);
419 }
420 });
421}
422
423impl<K: Trace, V: Trace> Finalize for BTreeMap<K, V> {}
424unsafe impl<K: Trace, V: Trace> Trace for BTreeMap<K, V> {
426 custom_trace!(this, mark, {
427 for (k, v) in this {
428 mark(k);
429 mark(v);
430 }
431 });
432}
433
434impl<T: Trace> Finalize for BTreeSet<T> {}
435unsafe impl<T: Trace> Trace for BTreeSet<T> {
437 custom_trace!(this, mark, {
438 for v in this {
439 mark(v);
440 }
441 });
442}
443
444impl<K: Eq + Hash + Trace, V: Trace, S: BuildHasher> Finalize
445 for hashbrown::hash_map::HashMap<K, V, S>
446{
447}
448unsafe impl<K: Eq + Hash + Trace, V: Trace, S: BuildHasher> Trace
450 for hashbrown::hash_map::HashMap<K, V, S>
451{
452 custom_trace!(this, mark, {
453 for (k, v) in this {
454 mark(k);
455 mark(v);
456 }
457 });
458}
459
460impl<K: Eq + Hash + Trace, V: Trace, S: BuildHasher> Finalize for HashMap<K, V, S> {}
461unsafe impl<K: Eq + Hash + Trace, V: Trace, S: BuildHasher> Trace for HashMap<K, V, S> {
463 custom_trace!(this, mark, {
464 for (k, v) in this {
465 mark(k);
466 mark(v);
467 }
468 });
469}
470
471impl<T: Eq + Hash + Trace, S: BuildHasher> Finalize for HashSet<T, S> {}
472unsafe impl<T: Eq + Hash + Trace, S: BuildHasher> Trace for HashSet<T, S> {
474 custom_trace!(this, mark, {
475 for v in this {
476 mark(v);
477 }
478 });
479}
480
481impl<T: Eq + Hash + Trace> Finalize for LinkedList<T> {}
482unsafe impl<T: Eq + Hash + Trace> Trace for LinkedList<T> {
484 custom_trace!(this, mark, {
485 #[allow(clippy::explicit_iter_loop)]
486 for v in this.iter() {
487 mark(v);
488 }
489 });
490}
491
492impl<T> Finalize for PhantomData<T> {}
493unsafe impl<T> Trace for PhantomData<T> {
495 empty_trace!();
496}
497
498impl<T: Trace> Finalize for VecDeque<T> {}
499unsafe impl<T: Trace> Trace for VecDeque<T> {
501 custom_trace!(this, mark, {
502 for v in this {
503 mark(v);
504 }
505 });
506}
507
508impl<T: ToOwned + Trace + ?Sized> Finalize for Cow<'static, T> {}
509unsafe impl<T: ToOwned + Trace + ?Sized> Trace for Cow<'static, T>
512where
513 T::Owned: Trace,
514{
515 custom_trace!(this, mark, {
516 if let Cow::Owned(v) = this {
517 mark(v);
518 }
519 });
520}
521
522impl<T: Trace + Default> Finalize for Cell<T> {}
523unsafe impl<T: Trace + Default> Trace for Cell<T> {
526 custom_trace!(this, mark, {
527 let v = this.take();
528 mark(&v);
529 this.set(v);
530 });
531}
532
533impl<T: Trace> Finalize for OnceCell<T> {}
534unsafe impl<T: Trace> Trace for OnceCell<T> {
536 custom_trace!(this, mark, {
537 if let Some(v) = this.get() {
538 mark(v);
539 }
540 });
541}
542
543#[cfg(feature = "icu")]
544mod icu {
545 use icu_locale_core::{LanguageIdentifier, Locale};
546
547 use crate::{Finalize, Trace};
548
549 impl Finalize for LanguageIdentifier {}
550
551 unsafe impl Trace for LanguageIdentifier {
553 empty_trace!();
554 }
555
556 impl Finalize for Locale {}
557
558 unsafe impl Trace for Locale {
560 empty_trace!();
561 }
562}
563
564#[cfg(feature = "boa_string")]
565mod boa_string_trace {
566 use crate::{Finalize, Trace};
567
568 unsafe impl Trace for boa_string::JsString {
570 empty_trace!();
571 }
572
573 impl Finalize for boa_string::JsString {}
574}
575#[cfg(feature = "either")]
576mod either_trace {
577 use crate::{Finalize, Trace};
578
579 impl<L: Trace, R: Trace> Finalize for either::Either<L, R> {}
580
581 unsafe impl<L: Trace, R: Trace> Trace for either::Either<L, R> {
582 custom_trace!(this, mark, {
583 match this {
584 either::Either::Left(l) => mark(l),
585 either::Either::Right(r) => mark(r),
586 }
587 });
588 }
589}