mirror of
https://github.com/servo/servo.git
synced 2025-09-27 15:20:09 +01:00
Update Rustc to 1.89. Reviewable by commit. Leftover work: - #37330 - #38777 --------- Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> Co-authored-by: sagudev <16504129+sagudev@users.noreply.github.com>
421 lines
12 KiB
Rust
421 lines
12 KiB
Rust
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
|
|
use std::cell::OnceCell;
|
|
use std::fmt::Display;
|
|
use std::hash::{BuildHasher, Hash};
|
|
use std::marker::PhantomData;
|
|
use std::mem;
|
|
use std::ops::{Deref, DerefMut};
|
|
|
|
use crossbeam_channel::Sender;
|
|
use html5ever::interface::{Tracer as HtmlTracer, TreeSink};
|
|
use html5ever::tokenizer::{TokenSink, Tokenizer};
|
|
use html5ever::tree_builder::TreeBuilder;
|
|
use indexmap::IndexMap;
|
|
use js::gc::{GCMethods, Handle};
|
|
use js::glue::CallObjectTracer;
|
|
use js::jsapi::{GCTraceKindToAscii, Heap, JSObject, JSTracer, TraceKind};
|
|
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
|
use parking_lot::RwLock;
|
|
use servo_arc::Arc as ServoArc;
|
|
use smallvec::SmallVec;
|
|
use style::author_styles::AuthorStyles;
|
|
use style::stylesheet_set::{AuthorStylesheetSet, DocumentStylesheetSet};
|
|
use tendril::TendrilSink;
|
|
use tendril::fmt::UTF8;
|
|
use tendril::stream::LossyDecoder;
|
|
#[cfg(feature = "webxr")]
|
|
use webxr_api::{Finger, Hand};
|
|
use xml5ever::interface::TreeSink as XmlTreeSink;
|
|
use xml5ever::tokenizer::XmlTokenizer;
|
|
use xml5ever::tree_builder::{Tracer as XmlTracer, XmlTreeBuilder};
|
|
|
|
use crate::JSTraceable;
|
|
use crate::error::Error;
|
|
use crate::reflector::Reflector;
|
|
use crate::str::{DOMString, USVString};
|
|
|
|
/// Trace the `JSObject` held by `reflector`.
|
|
///
|
|
/// # Safety
|
|
/// tracer must point to a valid, non-null JS tracer.
|
|
#[cfg_attr(crown, allow(crown::unrooted_must_root))]
|
|
pub unsafe fn trace_reflector(tracer: *mut JSTracer, description: &str, reflector: &Reflector) {
|
|
trace!("tracing reflector {}", description);
|
|
unsafe { trace_object(tracer, description, reflector.rootable()) }
|
|
}
|
|
|
|
/// Trace a `JSObject`.
|
|
///
|
|
/// # Safety
|
|
/// tracer must point to a valid, non-null JS tracer.
|
|
pub(crate) unsafe fn trace_object(
|
|
tracer: *mut JSTracer,
|
|
description: &str,
|
|
obj: &Heap<*mut JSObject>,
|
|
) {
|
|
unsafe {
|
|
trace!("tracing {}", description);
|
|
CallObjectTracer(
|
|
tracer,
|
|
obj.ptr.get() as *mut _,
|
|
GCTraceKindToAscii(TraceKind::Object),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// For use on non-jsmanaged types
|
|
/// Use #[derive(JSTraceable)] on JS managed types
|
|
macro_rules! unsafe_no_jsmanaged_fields(
|
|
($($ty:ty),+) => (
|
|
$(
|
|
#[allow(unsafe_code)]
|
|
unsafe impl crate::JSTraceable for $ty {
|
|
#[inline]
|
|
unsafe fn trace(&self, _: *mut ::js::jsapi::JSTracer) {
|
|
// Do nothing
|
|
}
|
|
}
|
|
)+
|
|
);
|
|
);
|
|
|
|
unsafe_no_jsmanaged_fields!(DOMString);
|
|
unsafe_no_jsmanaged_fields!(USVString);
|
|
unsafe_no_jsmanaged_fields!(Error);
|
|
|
|
/// A trait to allow tracing only DOM sub-objects.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// This trait is unsafe; if it is implemented incorrectly, the GC may end up collecting objects
|
|
/// that are still reachable.
|
|
pub unsafe trait CustomTraceable {
|
|
/// Trace `self`.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// The `JSTracer` argument must point to a valid `JSTracer` in memory. In addition,
|
|
/// implementors of this method must ensure that all active objects are properly traced
|
|
/// or else the garbage collector may end up collecting objects that are still reachable.
|
|
unsafe fn trace(&self, trc: *mut JSTracer);
|
|
}
|
|
|
|
unsafe impl<T: CustomTraceable> CustomTraceable for Box<T> {
|
|
#[inline]
|
|
unsafe fn trace(&self, trc: *mut JSTracer) {
|
|
unsafe { (**self).trace(trc) };
|
|
}
|
|
}
|
|
|
|
unsafe impl<T: JSTraceable> CustomTraceable for OnceCell<T> {
|
|
unsafe fn trace(&self, tracer: *mut JSTracer) {
|
|
if let Some(value) = self.get() {
|
|
unsafe { value.trace(tracer) }
|
|
}
|
|
}
|
|
}
|
|
|
|
unsafe impl<T> CustomTraceable for Sender<T> {
|
|
unsafe fn trace(&self, _: *mut JSTracer) {}
|
|
}
|
|
|
|
unsafe impl<T: JSTraceable> CustomTraceable for ServoArc<T> {
|
|
unsafe fn trace(&self, trc: *mut JSTracer) {
|
|
unsafe { (**self).trace(trc) }
|
|
}
|
|
}
|
|
|
|
unsafe impl<T: JSTraceable> CustomTraceable for RwLock<T> {
|
|
unsafe fn trace(&self, trc: *mut JSTracer) {
|
|
unsafe { self.read().trace(trc) }
|
|
}
|
|
}
|
|
|
|
unsafe impl<T: JSTraceable + Eq + Hash> CustomTraceable for indexmap::IndexSet<T> {
|
|
#[inline]
|
|
unsafe fn trace(&self, trc: *mut JSTracer) {
|
|
for e in self.iter() {
|
|
unsafe { e.trace(trc) };
|
|
}
|
|
}
|
|
}
|
|
|
|
// XXXManishearth Check if the following three are optimized to no-ops
|
|
// if e.trace() is a no-op (e.g it is an unsafe_no_jsmanaged_fields type)
|
|
unsafe impl<T: JSTraceable + 'static> CustomTraceable for SmallVec<[T; 1]> {
|
|
#[inline]
|
|
unsafe fn trace(&self, trc: *mut JSTracer) {
|
|
for e in self.iter() {
|
|
unsafe { e.trace(trc) };
|
|
}
|
|
}
|
|
}
|
|
|
|
unsafe impl<K, V, S> CustomTraceable for IndexMap<K, V, S>
|
|
where
|
|
K: Hash + Eq + JSTraceable,
|
|
V: JSTraceable,
|
|
S: BuildHasher,
|
|
{
|
|
#[inline]
|
|
unsafe fn trace(&self, trc: *mut JSTracer) {
|
|
for (k, v) in self {
|
|
unsafe { k.trace(trc) };
|
|
unsafe { v.trace(trc) };
|
|
}
|
|
}
|
|
}
|
|
|
|
unsafe impl<S> CustomTraceable for DocumentStylesheetSet<S>
|
|
where
|
|
S: JSTraceable + ::style::stylesheets::StylesheetInDocument + PartialEq + 'static,
|
|
{
|
|
unsafe fn trace(&self, tracer: *mut JSTracer) {
|
|
for (s, _origin) in self.iter() {
|
|
unsafe { s.trace(tracer) };
|
|
}
|
|
}
|
|
}
|
|
|
|
unsafe impl<S> CustomTraceable for AuthorStylesheetSet<S>
|
|
where
|
|
S: JSTraceable + ::style::stylesheets::StylesheetInDocument + PartialEq + 'static,
|
|
{
|
|
unsafe fn trace(&self, tracer: *mut JSTracer) {
|
|
for s in self.iter() {
|
|
unsafe { s.trace(tracer) };
|
|
}
|
|
}
|
|
}
|
|
|
|
unsafe impl<S> CustomTraceable for AuthorStyles<S>
|
|
where
|
|
S: JSTraceable + ::style::stylesheets::StylesheetInDocument + PartialEq + 'static,
|
|
{
|
|
unsafe fn trace(&self, tracer: *mut JSTracer) {
|
|
unsafe { self.stylesheets.trace(tracer) };
|
|
}
|
|
}
|
|
|
|
unsafe impl<Sink> CustomTraceable for LossyDecoder<Sink>
|
|
where
|
|
Sink: JSTraceable + TendrilSink<UTF8>,
|
|
{
|
|
unsafe fn trace(&self, tracer: *mut JSTracer) {
|
|
unsafe { self.inner_sink().trace(tracer) };
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "webxr")]
|
|
unsafe impl<J> CustomTraceable for Hand<J>
|
|
where
|
|
J: JSTraceable,
|
|
{
|
|
#[inline]
|
|
unsafe fn trace(&self, trc: *mut JSTracer) {
|
|
// exhaustive match so we don't miss new fields
|
|
let Hand {
|
|
ref wrist,
|
|
ref thumb_metacarpal,
|
|
ref thumb_phalanx_proximal,
|
|
ref thumb_phalanx_distal,
|
|
ref thumb_phalanx_tip,
|
|
ref index,
|
|
ref middle,
|
|
ref ring,
|
|
ref little,
|
|
} = *self;
|
|
unsafe {
|
|
wrist.trace(trc);
|
|
thumb_metacarpal.trace(trc);
|
|
thumb_phalanx_proximal.trace(trc);
|
|
thumb_phalanx_distal.trace(trc);
|
|
thumb_phalanx_tip.trace(trc);
|
|
index.trace(trc);
|
|
middle.trace(trc);
|
|
ring.trace(trc);
|
|
little.trace(trc);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "webxr")]
|
|
unsafe impl<J> CustomTraceable for Finger<J>
|
|
where
|
|
J: JSTraceable,
|
|
{
|
|
#[inline]
|
|
unsafe fn trace(&self, trc: *mut JSTracer) {
|
|
// exhaustive match so we don't miss new fields
|
|
let Finger {
|
|
ref metacarpal,
|
|
ref phalanx_proximal,
|
|
ref phalanx_intermediate,
|
|
ref phalanx_distal,
|
|
ref phalanx_tip,
|
|
} = *self;
|
|
unsafe {
|
|
metacarpal.trace(trc);
|
|
phalanx_proximal.trace(trc);
|
|
phalanx_intermediate.trace(trc);
|
|
phalanx_distal.trace(trc);
|
|
phalanx_tip.trace(trc);
|
|
}
|
|
}
|
|
}
|
|
|
|
unsafe impl<Handle: JSTraceable + Clone, Sink: TreeSink<Handle = Handle> + JSTraceable>
|
|
CustomTraceable for TreeBuilder<Handle, Sink>
|
|
{
|
|
unsafe fn trace(&self, trc: *mut JSTracer) {
|
|
struct Tracer<Handle>(*mut JSTracer, PhantomData<Handle>);
|
|
let tracer = Tracer::<Handle>(trc, PhantomData);
|
|
|
|
impl<Handle: JSTraceable> HtmlTracer for Tracer<Handle> {
|
|
type Handle = Handle;
|
|
#[cfg_attr(crown, allow(crown::unrooted_must_root))]
|
|
fn trace_handle(&self, node: &Handle) {
|
|
unsafe {
|
|
node.trace(self.0);
|
|
}
|
|
}
|
|
}
|
|
|
|
self.trace_handles(&tracer);
|
|
unsafe { self.sink.trace(trc) };
|
|
}
|
|
}
|
|
|
|
#[allow(unsafe_code)]
|
|
unsafe impl<Handle: JSTraceable + Clone, Sink: TokenSink<Handle = Handle> + CustomTraceable>
|
|
CustomTraceable for Tokenizer<Sink>
|
|
{
|
|
unsafe fn trace(&self, trc: *mut JSTracer) {
|
|
unsafe { self.sink.trace(trc) };
|
|
}
|
|
}
|
|
|
|
#[allow(unsafe_code)]
|
|
unsafe impl<Handle: JSTraceable + Clone, Sink: JSTraceable + XmlTreeSink<Handle = Handle>>
|
|
CustomTraceable for XmlTokenizer<XmlTreeBuilder<Handle, Sink>>
|
|
{
|
|
unsafe fn trace(&self, trc: *mut JSTracer) {
|
|
struct Tracer<Handle>(*mut JSTracer, PhantomData<Handle>);
|
|
let tracer = Tracer(trc, PhantomData);
|
|
|
|
impl<Handle: JSTraceable> XmlTracer for Tracer<Handle> {
|
|
type Handle = Handle;
|
|
#[cfg_attr(crown, allow(crown::unrooted_must_root))]
|
|
fn trace_handle(&self, node: &Handle) {
|
|
unsafe {
|
|
node.trace(self.0);
|
|
}
|
|
}
|
|
}
|
|
|
|
let tree_builder = &self.sink;
|
|
tree_builder.trace_handles(&tracer);
|
|
unsafe { tree_builder.sink.trace(trc) };
|
|
}
|
|
}
|
|
|
|
/// Roots any JSTraceable thing
|
|
///
|
|
/// If you have a valid DomObject, use DomRoot.
|
|
/// If you have GC things like *mut JSObject or JSVal, use rooted!.
|
|
/// If you have an arbitrary number of DomObjects to root, use rooted_vec!.
|
|
/// If you know what you're doing, use this.
|
|
#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]
|
|
pub struct RootedTraceableBox<T: JSTraceable + 'static>(js::gc::RootedTraceableBox<T>);
|
|
|
|
unsafe impl<T: JSTraceable + 'static> JSTraceable for RootedTraceableBox<T> {
|
|
unsafe fn trace(&self, tracer: *mut JSTracer) {
|
|
unsafe { self.0.trace(tracer) };
|
|
}
|
|
}
|
|
|
|
impl<T: JSTraceable + 'static> RootedTraceableBox<T> {
|
|
/// DomRoot a JSTraceable thing for the life of this RootedTraceableBox
|
|
pub fn new(traceable: T) -> RootedTraceableBox<T> {
|
|
Self(js::gc::RootedTraceableBox::new(traceable))
|
|
}
|
|
|
|
/// Consumes a boxed JSTraceable and roots it for the life of this RootedTraceableBox.
|
|
pub fn from_box(boxed_traceable: Box<T>) -> RootedTraceableBox<T> {
|
|
Self(js::gc::RootedTraceableBox::from_box(boxed_traceable))
|
|
}
|
|
}
|
|
|
|
impl<T> RootedTraceableBox<Heap<T>>
|
|
where
|
|
Heap<T>: JSTraceable + 'static,
|
|
T: GCMethods + Copy,
|
|
{
|
|
pub fn handle(&self) -> Handle<'_, T> {
|
|
self.0.handle()
|
|
}
|
|
}
|
|
|
|
impl<T: JSTraceable + MallocSizeOf> MallocSizeOf for RootedTraceableBox<T> {
|
|
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
|
|
// Briefly resurrect the real Box value so we can rely on the existing calculations.
|
|
// Then immediately forget about it again to avoid dropping the box.
|
|
let inner = unsafe { Box::from_raw(self.0.ptr()) };
|
|
let size = inner.size_of(ops);
|
|
mem::forget(inner);
|
|
size
|
|
}
|
|
}
|
|
|
|
impl<T: JSTraceable + Default> Default for RootedTraceableBox<T> {
|
|
fn default() -> RootedTraceableBox<T> {
|
|
RootedTraceableBox::new(T::default())
|
|
}
|
|
}
|
|
|
|
impl<T: JSTraceable> Deref for RootedTraceableBox<T> {
|
|
type Target = T;
|
|
fn deref(&self) -> &T {
|
|
self.0.deref()
|
|
}
|
|
}
|
|
|
|
impl<T: JSTraceable> DerefMut for RootedTraceableBox<T> {
|
|
fn deref_mut(&mut self) -> &mut T {
|
|
self.0.deref_mut()
|
|
}
|
|
}
|
|
|
|
/// Wrapper type for nop traceble
|
|
///
|
|
/// SAFETY: Inner type must not impl JSTraceable
|
|
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
|
#[cfg_attr(crown, crown::trace_in_no_trace_lint::must_not_have_traceable)]
|
|
pub(crate) struct NoTrace<T>(pub(crate) T);
|
|
|
|
impl<T: Display> Display for NoTrace<T> {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
self.0.fmt(f)
|
|
}
|
|
}
|
|
|
|
impl<T> From<T> for NoTrace<T> {
|
|
fn from(item: T) -> Self {
|
|
Self(item)
|
|
}
|
|
}
|
|
|
|
#[allow(unsafe_code)]
|
|
unsafe impl<T> JSTraceable for NoTrace<T> {
|
|
#[inline]
|
|
unsafe fn trace(&self, _: *mut ::js::jsapi::JSTracer) {}
|
|
}
|
|
|
|
impl<T: MallocSizeOf> MallocSizeOf for NoTrace<T> {
|
|
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
|
|
self.0.size_of(ops)
|
|
}
|
|
}
|