1usestd::{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};1617usecrate::GcErasedPointer;1819/// A queue used to trace [`crate::Gc<T>`] non-recursively.20#[doc(hidden)]21#[allow(missing_debug_implementations)]22pub structTracer {23 queue: VecDeque<GcErasedPointer>,24}2526implTracer {27pub(crate)fnnew() ->Self{28Self{29 queue: VecDeque::default(),30 }31 }3233pub(crate)fnenqueue(&mutself, node: GcErasedPointer) {34self.queue.push_back(node);35 }3637/// Traces through all the queued nodes until the queue is empty.38 ///39 /// # Safety40 ///41 /// All the pointers inside of the queue must point to valid memory.42pub(crate)unsafe fntrace_until_empty(&mutself) {43while letSome(node) =self.queue.pop_front() {44letnode_ref =unsafe{ node.as_ref() };45ifnode_ref.is_marked() {46continue;47 }48 node_ref.header.mark();49lettrace_fn = node_ref.trace_fn();5051// SAFETY: The function pointer is appropriate for this node type because we extract it from it's VTable.52 // Additionally, the node pointer is valid per the caller's guarantee.53unsafe{ trace_fn(node,self) }54 }55 }5657pub(crate)fnis_empty(&mutself) -> bool {58self.queue.is_empty()59 }60}6162/// Substitute for the [`Drop`] trait for garbage collected types.63pub traitFinalize {64/// Cleanup logic for a type.65fnfinalize(&self) {}66}6768/// The Trace trait, which needs to be implemented on garbage-collected objects.69///70/// # Safety71///72/// - An incorrect implementation of the trait can result in heap overflows, data corruption,73/// use-after-free, or Undefined Behaviour in general.74///75/// - Calling any of the functions marked as `unsafe` outside of the context of the garbage collector76/// can result in Undefined Behaviour.77pub unsafe traitTrace: Finalize {78/// Marks all contained `Gc`s.79 ///80 /// # Safety81 ///82 /// See [`Trace`].83unsafe fntrace(&self, tracer:&mutTracer);8485/// Trace handles located in GC heap, and mark them as non root.86 ///87 /// # Safety88 ///89 /// See [`Trace`].90unsafe fntrace_non_roots(&self);9192/// Runs [`Finalize::finalize`] on this object and all93 /// contained subobjects.94fnrun_finalizer(&self);95}9697/// Utility macro to define an empty implementation of [`Trace`].98///99/// Use this for marking types as not containing any `Trace` types.100#[macro_export]101macro_rules! empty_trace {102 () => {103#[inline]104unsafe fntrace(&self, _tracer:&mut$crate::Tracer) {}105#[inline]106unsafe fntrace_non_roots(&self) {}107#[inline]108fnrun_finalizer(&self) {109$crate::Finalize::finalize(self)110 }111 };112}113114/// Utility macro to manually implement [`Trace`] on a type.115///116/// You define a `this` parameter name and pass in a body, which should call `mark` on every117/// traceable element inside the body. The mark implementation will automatically delegate to the118/// correct method on the argument.119///120/// # Safety121///122/// Misusing the `mark` function may result in Undefined Behaviour.123#[macro_export]124macro_rules! custom_trace {125 ($this:ident,$marker:ident,$body:expr) => {126#[inline]127unsafe fntrace(&self, tracer:&mut$crate::Tracer) {128letmut$marker= |it:&dyn$crate::Trace| {129// SAFETY: The implementor must ensure that `trace` is correctly implemented.130unsafe{131$crate::Trace::trace(it, tracer);132 }133 };134let$this=self;135$body136}137#[inline]138unsafe fntrace_non_roots(&self) {139fn$marker<T:$crate::Trace+?Sized>(it:&T) {140// SAFETY: The implementor must ensure that `trace` is correctly implemented.141unsafe{142$crate::Trace::trace_non_roots(it);143 }144 }145let$this=self;146$body147}148#[inline]149fnrun_finalizer(&self) {150fn$marker<T:$crate::Trace+?Sized>(it:&T) {151$crate::Trace::run_finalizer(it);152 }153$crate::Finalize::finalize(self);154let$this=self;155$body156}157 };158}159160impl<T:?Sized> Finalizefor&'staticT {}161// SAFETY: 'static references don't need to be traced, since they live indefinitely.162unsafe impl<T:?Sized> Tracefor&'staticT {163empty_trace!();164}165166macro_rules! simple_empty_finalize_trace {167 ($($T:ty),*) => {168 $(169implFinalizefor$T{}170171// SAFETY:172 // Primitive types and string types don't have inner nodes that need to be marked.173unsafe implTracefor$T{empty_trace!(); }174 )*175 }176}177178simple_empty_finalize_trace![179 (),180 bool,181 isize,182 usize,183 i8,184 u8,185 i16,186 u16,187 i32,188 u32,189 i64,190 u64,191 i128,192 u128,193 f32,194 f64,195 char,196 TypeId,197 String,198 str,199 Rc<str>,200 Path,201 PathBuf,202 NonZeroIsize,203 NonZeroUsize,204 NonZeroI8,205 NonZeroU8,206 NonZeroI16,207 NonZeroU16,208 NonZeroI32,209 NonZeroU32,210 NonZeroI64,211 NonZeroU64,212 NonZeroI128,213 NonZeroU128214];215216#[cfg(target_has_atomic ="8")]217simple_empty_finalize_trace![atomic::AtomicBool, atomic::AtomicI8, atomic::AtomicU8];218219#[cfg(target_has_atomic ="16")]220simple_empty_finalize_trace![atomic::AtomicI16, atomic::AtomicU16];221222#[cfg(target_has_atomic ="32")]223simple_empty_finalize_trace![atomic::AtomicI32, atomic::AtomicU32];224225#[cfg(target_has_atomic ="64")]226simple_empty_finalize_trace![atomic::AtomicI64, atomic::AtomicU64];227228#[cfg(target_has_atomic ="ptr")]229simple_empty_finalize_trace![atomic::AtomicIsize, atomic::AtomicUsize];230231impl<T: Trace,constN: usize> Finalizefor[T; N] {}232// SAFETY:233// All elements inside the array are correctly marked.234unsafe impl<T: Trace,constN: usize> Tracefor[T; N] {235custom_trace!(this, mark, {236forvinthis {237 mark(v);238 }239 });240}241242macro_rules! fn_finalize_trace_one {243 ($ty:ty $(,$args:ident)*) => {244impl<Ret $(,$args)*> Finalizefor$ty{}245// SAFETY:246 // Function pointers don't have inner nodes that need to be marked.247unsafe impl<Ret $(,$args)*> Tracefor$ty{empty_trace!(); }248 }249}250macro_rules! fn_finalize_trace_group {251 () => {252fn_finalize_trace_one!(extern"Rust"fn() -> Ret);253fn_finalize_trace_one!(extern"C"fn() -> Ret);254fn_finalize_trace_one!(unsafe extern"Rust"fn() -> Ret);255fn_finalize_trace_one!(unsafe extern"C"fn() -> Ret);256 };257 ($($args:ident),*) => {258fn_finalize_trace_one!(extern"Rust"fn($($args),*) -> Ret, $($args),*);259fn_finalize_trace_one!(extern"C"fn($($args),*) -> Ret, $($args),*);260fn_finalize_trace_one!(extern"C"fn($($args),*, ...) -> Ret, $($args),*);261fn_finalize_trace_one!(unsafe extern"Rust"fn($($args),*) -> Ret, $($args),*);262fn_finalize_trace_one!(unsafe extern"C"fn($($args),*) -> Ret, $($args),*);263fn_finalize_trace_one!(unsafe extern"C"fn($($args),*, ...) -> Ret, $($args),*);264 }265}266267macro_rules! tuple_finalize_trace {268 () => {};// This case is handled above, by simple_finalize_empty_trace!().269($($args:ident),*) => {270impl<$($args),*> Finalizefor($($args,)*) {}271// SAFETY:272 // All elements inside the tuple are correctly marked.273unsafe impl<$($args:$crate::Trace),*> Tracefor($($args,)*) {274custom_trace!(this, mark, {275#[allow(non_snake_case, unused_unsafe, unused_mut)]276letmutavoid_lints = |&($(ref$args,)*):&($($args,)*)| {277// SAFETY: The implementor must ensure a correct implementation.278unsafe{ $(mark($args);)* }279 };280 avoid_lints(this)281 });282 }283 }284}285286macro_rules! type_arg_tuple_based_finalize_trace_impls {287 ($(($($args:ident),*);)*) => {288 $(289fn_finalize_trace_group!($($args),*);290tuple_finalize_trace!($($args),*);291 )*292 }293}294295type_arg_tuple_based_finalize_trace_impls![296 ();297 (A);298 (A, B);299 (A, B, C);300 (A, B, C, D);301 (A, B, C, D, E);302 (A, B, C, D, E, F);303 (A, B, C, D, E, F, G);304 (A, B, C, D, E, F, G, H);305 (A, B, C, D, E, F, G, H, I);306 (A, B, C, D, E, F, G, H, I, J);307 (A, B, C, D, E, F, G, H, I, J, K);308 (A, B, C, D, E, F, G, H, I, J, K, L);309];310311impl<T: Trace +?Sized> FinalizeforBox<T> {}312// SAFETY: The inner value of the `Box` is correctly marked.313unsafe impl<T: Trace +?Sized> TraceforBox<T> {314#[inline]315unsafe fntrace(&self, tracer:&mutTracer) {316// SAFETY: The implementor must ensure that `trace` is correctly implemented.317unsafe{318 Trace::trace(&**self, tracer);319 }320 }321#[inline]322unsafe fntrace_non_roots(&self) {323// SAFETY: The implementor must ensure that `trace_non_roots` is correctly implemented.324unsafe{325 Trace::trace_non_roots(&**self);326 }327 }328#[inline]329fnrun_finalizer(&self) {330 Finalize::finalize(self);331 Trace::run_finalizer(&**self);332 }333}334335impl<T: Trace> FinalizeforBox<[T]> {}336// SAFETY: All the inner elements of the `Box` array are correctly marked.337unsafe impl<T: Trace> TraceforBox<[T]> {338custom_trace!(this, mark, {339forein&**this {340 mark(e);341 }342 });343}344345impl<T: Trace> FinalizeforVec<T> {}346// SAFETY: All the inner elements of the `Vec` are correctly marked.347unsafe impl<T: Trace> TraceforVec<T> {348custom_trace!(this, mark, {349foreinthis {350 mark(e);351 }352 });353}354355#[cfg(feature ="thin-vec")]356impl<T: Trace> Finalizeforthin_vec::ThinVec<T> {}357358#[cfg(feature ="thin-vec")]359// SAFETY: All the inner elements of the `Vec` are correctly marked.360unsafe impl<T: Trace> Traceforthin_vec::ThinVec<T> {361custom_trace!(this, mark, {362foreinthis {363 mark(e);364 }365 });366}367368impl<T: Trace> FinalizeforOption<T> {}369// SAFETY: The inner value of the `Option` is correctly marked.370unsafe impl<T: Trace> TraceforOption<T> {371custom_trace!(this, mark, {372if letSome(refv) =*this {373 mark(v);374 }375 });376}377378impl<T: Trace, E: Trace> FinalizeforResult<T, E> {}379// SAFETY: Both inner values of the `Result` are correctly marked.380unsafe impl<T: Trace, E: Trace> TraceforResult<T, E> {381custom_trace!(this, mark, {382match*this {383Ok(refv) => mark(v),384Err(refv) => mark(v),385 }386 });387}388389impl<T: Ord + Trace> FinalizeforBinaryHeap<T> {}390// SAFETY: All the elements of the `BinaryHeap` are correctly marked.391unsafe impl<T: Ord + Trace> TraceforBinaryHeap<T> {392custom_trace!(this, mark, {393forvinthis {394 mark(v);395 }396 });397}398399impl<K: Trace, V: Trace> FinalizeforBTreeMap<K, V> {}400// SAFETY: All the elements of the `BTreeMap` are correctly marked.401unsafe impl<K: Trace, V: Trace> TraceforBTreeMap<K, V> {402custom_trace!(this, mark, {403for(k, v)inthis {404 mark(k);405 mark(v);406 }407 });408}409410impl<T: Trace> FinalizeforBTreeSet<T> {}411// SAFETY: All the elements of the `BTreeSet` are correctly marked.412unsafe impl<T: Trace> TraceforBTreeSet<T> {413custom_trace!(this, mark, {414forvinthis {415 mark(v);416 }417 });418}419420impl<K: Eq + Hash + Trace, V: Trace, S: BuildHasher> Finalize421forhashbrown::hash_map::HashMap<K, V, S>422{423}424// SAFETY: All the elements of the `HashMap` are correctly marked.425unsafe impl<K: Eq + Hash + Trace, V: Trace, S: BuildHasher> Trace426forhashbrown::hash_map::HashMap<K, V, S>427{428custom_trace!(this, mark, {429for(k, v)inthis {430 mark(k);431 mark(v);432 }433 });434}435436impl<K: Eq + Hash + Trace, V: Trace, S: BuildHasher> FinalizeforHashMap<K, V, S> {}437// SAFETY: All the elements of the `HashMap` are correctly marked.438unsafe impl<K: Eq + Hash + Trace, V: Trace, S: BuildHasher> TraceforHashMap<K, V, S> {439custom_trace!(this, mark, {440for(k, v)inthis {441 mark(k);442 mark(v);443 }444 });445}446447impl<T: Eq + Hash + Trace, S: BuildHasher> FinalizeforHashSet<T, S> {}448// SAFETY: All the elements of the `HashSet` are correctly marked.449unsafe impl<T: Eq + Hash + Trace, S: BuildHasher> TraceforHashSet<T, S> {450custom_trace!(this, mark, {451forvinthis {452 mark(v);453 }454 });455}456457impl<T: Eq + Hash + Trace> FinalizeforLinkedList<T> {}458// SAFETY: All the elements of the `LinkedList` are correctly marked.459unsafe impl<T: Eq + Hash + Trace> TraceforLinkedList<T> {460custom_trace!(this, mark, {461#[allow(clippy::explicit_iter_loop)]462forvinthis.iter() {463 mark(v);464 }465 });466}467468impl<T> FinalizeforPhantomData<T> {}469// SAFETY: A `PhantomData` doesn't have inner data that needs to be marked.470unsafe impl<T> TraceforPhantomData<T> {471empty_trace!();472}473474impl<T: Trace> FinalizeforVecDeque<T> {}475// SAFETY: All the elements of the `VecDeque` are correctly marked.476unsafe impl<T: Trace> TraceforVecDeque<T> {477custom_trace!(this, mark, {478forvinthis {479 mark(v);480 }481 });482}483484impl<T: ToOwned + Trace +?Sized> FinalizeforCow<'static, T> {}485// SAFETY: 'static references don't need to be traced, since they live indefinitely, and the owned486// variant is correctly marked.487unsafe impl<T: ToOwned + Trace +?Sized> TraceforCow<'static, T>488where489T::Owned: Trace,490{491custom_trace!(this, mark, {492if letCow::Owned(v) = this {493 mark(v);494 }495 });496}497498impl<T: Trace> FinalizeforCell<Option<T>> {}499// SAFETY: Taking and setting is done in a single action, and recursive traces should find a `None`500// value instead of the original `T`, making this safe.501unsafe impl<T: Trace> TraceforCell<Option<T>> {502custom_trace!(this, mark, {503if letSome(v) = this.take() {504 mark(&v);505 this.set(Some(v));506 }507 });508}509510impl<T: Trace> FinalizeforOnceCell<T> {}511// SAFETY: We only trace the inner cell if the cell has a value.512unsafe impl<T: Trace> TraceforOnceCell<T> {513custom_trace!(this, mark, {514if letSome(v) = this.get() {515 mark(v);516 }517 });518}519520#[cfg(feature ="icu")]521modicu {522useicu_locale_core::{LanguageIdentifier, Locale};523524use crate::{Finalize, Trace};525526implFinalizeforLanguageIdentifier {}527528// SAFETY: `LanguageIdentifier` doesn't have any traceable data.529unsafe implTraceforLanguageIdentifier {530empty_trace!();531 }532533implFinalizeforLocale {}534535// SAFETY: `LanguageIdentifier` doesn't have any traceable data.536unsafe implTraceforLocale {537empty_trace!();538 }539}540541#[cfg(feature ="boa_string")]542modboa_string_trace {543use crate::{Finalize, Trace};544545// SAFETY: `boa_string::JsString` doesn't have any traceable data.546unsafe implTraceforboa_string::JsString {547empty_trace!();548 }549550implFinalizeforboa_string::JsString {}551}552553#[cfg(feature ="either")]554modeither_trace {555use crate::{Finalize, Trace};556557impl<L: Trace, R: Trace> Finalizeforeither::Either<L, R> {}558559unsafe impl<L: Trace, R: Trace> Traceforeither::Either<L, R> {560custom_trace!(this, mark, {561matchthis {562 either::Either::Left(l) => mark(l),563 either::Either::Right(r) => mark(r),564 }565 });566 }567}