Movatterモバイル変換


[0]ホーム

URL:


Docs.rs

boa_gc/
trace.rs

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}

[8]ページ先頭

©2009-2025 Movatter.jp