Use mozjs tracing infrastructure (#29918)

* Update mozjs

64711ec2e6 also fixes https://github.com/servo/servo/issues/30043

* Move to mozjs Traceable and introduce CustomTraceable
This commit is contained in:
Samson 2023-08-10 23:46:06 +02:00 committed by GitHub
parent 1f7f4cf2be
commit 450f8193a5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 81 additions and 377 deletions

View file

@ -46,32 +46,23 @@ use crate::script_thread::IncompleteParserContexts;
use crate::task::TaskBox;
use indexmap::IndexMap;
use js::glue::{CallObjectTracer, CallScriptTracer, CallStringTracer, CallValueTracer};
use js::jsapi::{
GCTraceKindToAscii, Heap, JSObject, JSScript, JSString, JSTracer, JobQueue, TraceKind,
};
use js::jsapi::{GCTraceKindToAscii, Heap, JSObject, JSScript, JSString, JSTracer, TraceKind};
use js::jsval::JSVal;
use js::rust::{GCMethods, Handle, Runtime, Stencil};
use js::typedarray::TypedArray;
use js::typedarray::TypedArrayElement;
use js::rust::{GCMethods, Handle};
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use parking_lot::RwLock;
use servo_arc::Arc as ServoArc;
use smallvec::SmallVec;
use std::borrow::Cow;
use std::cell::{Cell, RefCell, UnsafeCell};
use std::collections::hash_map::RandomState;
use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
use std::collections::HashMap;
use std::fmt::Display;
use std::hash::{BuildHasher, Hash};
use std::mem;
use std::num::NonZeroU64;
use std::ops::{Deref, DerefMut, Range};
use std::path::PathBuf;
use std::rc::Rc;
use std::sync::atomic::{AtomicBool, AtomicUsize};
use std::sync::Arc;
use std::thread::JoinHandle;
use std::time::{Instant, SystemTime};
use std::ops::{Deref, DerefMut};
use style::author_styles::AuthorStyles;
use style::stylesheet_set::{AuthorStylesheetSet, DocumentStylesheetSet};
use tendril::fmt::UTF8;
@ -79,14 +70,28 @@ use tendril::stream::LossyDecoder;
use tendril::TendrilSink;
use webxr_api::{Finger, Hand};
unsafe_no_jsmanaged_fields!(JoinHandle<()>);
/// A trait to allow tracing (only) DOM objects.
pub unsafe trait JSTraceable {
pub use js::gc::Traceable as JSTraceable;
/// A trait to allow tracing only DOM sub-objects.
pub unsafe trait CustomTraceable {
/// Trace `self`.
unsafe fn trace(&self, trc: *mut JSTracer);
}
unsafe impl<T: CustomTraceable> CustomTraceable for Box<T> {
#[inline]
unsafe fn trace(&self, trc: *mut JSTracer) {
(**self).trace(trc);
}
}
unsafe impl<T: CustomTraceable> CustomTraceable for DomRefCell<T> {
unsafe fn trace(&self, trc: *mut JSTracer) {
(*self).borrow().trace(trc)
}
}
/// Wrapper type for nop traceble
///
/// SAFETY: Inner type must not impl JSTraceable
@ -236,10 +241,7 @@ unsafe_no_jsmanaged_fields!(IncompleteParserContexts);
unsafe_no_jsmanaged_fields!(Reflector);
unsafe_no_jsmanaged_fields!(*mut JobQueue);
unsafe_no_jsmanaged_fields!(Cow<'static, str>);
#[allow(dead_code)]
/// Trace a `JSScript`.
pub fn trace_script(tracer: *mut JSTracer, description: &str, script: &Heap<*mut JSScript>) {
unsafe {
@ -252,6 +254,7 @@ pub fn trace_script(tracer: *mut JSTracer, description: &str, script: &Heap<*mut
}
}
#[allow(dead_code)]
/// Trace a `JSVal`.
pub fn trace_jsval(tracer: *mut JSTracer, description: &str, val: &Heap<JSVal>) {
unsafe {
@ -287,6 +290,7 @@ pub fn trace_object(tracer: *mut JSTracer, description: &str, obj: &Heap<*mut JS
}
}
#[allow(dead_code)]
/// Trace a `JSString`.
pub fn trace_string(tracer: *mut JSTracer, description: &str, s: &Heap<*mut JSString>) {
unsafe {
@ -299,122 +303,25 @@ pub fn trace_string(tracer: *mut JSTracer, description: &str, s: &Heap<*mut JSSt
}
}
unsafe impl<T: JSTraceable> JSTraceable for Rc<T> {
unsafe impl<T: JSTraceable> CustomTraceable for ServoArc<T> {
unsafe fn trace(&self, trc: *mut JSTracer) {
(**self).trace(trc)
}
}
unsafe impl<T: JSTraceable> JSTraceable for Arc<T> {
unsafe fn trace(&self, trc: *mut JSTracer) {
(**self).trace(trc)
}
}
unsafe impl<T: JSTraceable> JSTraceable for ServoArc<T> {
unsafe fn trace(&self, trc: *mut JSTracer) {
(**self).trace(trc)
}
}
unsafe impl<T: JSTraceable> JSTraceable for RwLock<T> {
unsafe impl<T: JSTraceable> CustomTraceable for RwLock<T> {
unsafe fn trace(&self, trc: *mut JSTracer) {
self.read().trace(trc)
}
}
unsafe impl<T: JSTraceable + ?Sized> JSTraceable for Box<T> {
unsafe fn trace(&self, trc: *mut JSTracer) {
(**self).trace(trc)
}
}
unsafe impl<T: JSTraceable> JSTraceable for [T] {
unsafe fn trace(&self, trc: *mut JSTracer) {
for e in self.iter() {
e.trace(trc);
}
}
}
unsafe impl<T: JSTraceable + Copy> JSTraceable for Cell<T> {
unsafe fn trace(&self, trc: *mut JSTracer) {
self.get().trace(trc)
}
}
unsafe impl<T: JSTraceable> JSTraceable for UnsafeCell<T> {
unsafe fn trace(&self, trc: *mut JSTracer) {
(*self.get()).trace(trc)
}
}
unsafe impl<T: JSTraceable> JSTraceable for DomRefCell<T> {
unsafe fn trace(&self, trc: *mut JSTracer) {
(*self).borrow().trace(trc)
}
}
unsafe impl<T: JSTraceable> JSTraceable for RefCell<T> {
unsafe fn trace(&self, trc: *mut JSTracer) {
(*self).borrow().trace(trc)
}
}
unsafe impl JSTraceable for Heap<*mut JSScript> {
unsafe fn trace(&self, trc: *mut JSTracer) {
if self.get().is_null() {
return;
}
trace_script(trc, "heap script", self);
}
}
unsafe impl JSTraceable for Heap<*mut JSObject> {
unsafe fn trace(&self, trc: *mut JSTracer) {
if self.get().is_null() {
return;
}
trace_object(trc, "heap object", self);
}
}
unsafe impl JSTraceable for Heap<*mut JSString> {
unsafe fn trace(&self, trc: *mut JSTracer) {
if self.get().is_null() {
return;
}
trace_string(trc, "heap string", self);
}
}
unsafe impl JSTraceable for Heap<JSVal> {
unsafe fn trace(&self, trc: *mut JSTracer) {
trace_jsval(trc, "heap value", self);
}
}
// 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> JSTraceable for Vec<T> {
#[inline]
unsafe fn trace(&self, trc: *mut JSTracer) {
for e in &*self {
e.trace(trc);
}
}
}
unsafe impl<T: JSTraceable> JSTraceable for VecDeque<T> {
#[inline]
unsafe fn trace(&self, trc: *mut JSTracer) {
for e in &*self {
e.trace(trc);
}
}
}
unsafe impl<T: JSTraceable + Eq + Hash> JSTraceable for indexmap::IndexSet<T> {
unsafe impl<T: JSTraceable + Eq + Hash> CustomTraceable for indexmap::IndexSet<T> {
#[inline]
unsafe fn trace(&self, trc: *mut JSTracer) {
for e in self.iter() {
@ -423,24 +330,9 @@ unsafe impl<T: JSTraceable + Eq + Hash> JSTraceable for indexmap::IndexSet<T> {
}
}
unsafe impl<A, B, C, D> JSTraceable for (A, B, C, D)
where
A: JSTraceable,
B: JSTraceable,
C: JSTraceable,
D: JSTraceable,
{
unsafe fn trace(&self, trc: *mut JSTracer) {
self.0.trace(trc);
self.1.trace(trc);
self.2.trace(trc);
self.3.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> JSTraceable for SmallVec<[T; 1]> {
unsafe impl<T: JSTraceable + 'static> CustomTraceable for SmallVec<[T; 1]> {
#[inline]
unsafe fn trace(&self, trc: *mut JSTracer) {
for e in self.iter() {
@ -449,24 +341,7 @@ unsafe impl<T: JSTraceable + 'static> JSTraceable for SmallVec<[T; 1]> {
}
}
unsafe impl<T: JSTraceable> JSTraceable for Option<T> {
#[inline]
unsafe fn trace(&self, trc: *mut JSTracer) {
self.as_ref().map(|e| e.trace(trc));
}
}
unsafe impl<T: JSTraceable, U: JSTraceable> JSTraceable for Result<T, U> {
#[inline]
unsafe fn trace(&self, trc: *mut JSTracer) {
match *self {
Ok(ref inner) => inner.trace(trc),
Err(ref inner) => inner.trace(trc),
}
}
}
unsafe impl<K, V, S> JSTraceable for HashMap<K, V, S>
unsafe impl<K, V, S> CustomTraceable for IndexMap<K, V, S>
where
K: Hash + Eq + JSTraceable,
V: JSTraceable,
@ -481,107 +356,19 @@ where
}
}
unsafe impl<T, S> JSTraceable for HashSet<T, S>
where
T: Hash + Eq + JSTraceable,
S: BuildHasher,
{
#[inline]
unsafe fn trace(&self, trc: *mut JSTracer) {
for v in &*self {
v.trace(trc);
}
}
}
unsafe impl<K: Ord + JSTraceable, V: JSTraceable> JSTraceable for BTreeMap<K, V> {
#[inline]
unsafe fn trace(&self, trc: *mut JSTracer) {
for (k, v) in self {
k.trace(trc);
v.trace(trc);
}
}
}
unsafe impl<K, V, S> JSTraceable 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 {
k.trace(trc);
v.trace(trc);
}
}
}
unsafe impl<A: JSTraceable, B: JSTraceable> JSTraceable for (A, B) {
#[inline]
unsafe fn trace(&self, trc: *mut JSTracer) {
let (ref a, ref b) = *self;
a.trace(trc);
b.trace(trc);
}
}
unsafe impl<A: JSTraceable, B: JSTraceable, C: JSTraceable> JSTraceable for (A, B, C) {
#[inline]
unsafe fn trace(&self, trc: *mut JSTracer) {
let (ref a, ref b, ref c) = *self;
a.trace(trc);
b.trace(trc);
c.trace(trc);
}
}
unsafe_no_jsmanaged_fields!(bool, f32, f64, String, AtomicBool, AtomicUsize, char);
unsafe_no_jsmanaged_fields!(usize, u8, u16, u32, u64);
unsafe_no_jsmanaged_fields!(isize, i8, i16, i32, i64);
unsafe_no_jsmanaged_fields!(NonZeroU64);
unsafe_no_jsmanaged_fields!(Error);
unsafe_no_jsmanaged_fields!(TrustedPromise);
unsafe_no_jsmanaged_fields!(Runtime);
unsafe_no_jsmanaged_fields!(ContextForRequestInterrupt);
unsafe_no_jsmanaged_fields!(WindowProxyHandler);
unsafe_no_jsmanaged_fields!(DOMString);
unsafe_no_jsmanaged_fields!(USVString);
unsafe_no_jsmanaged_fields!(SystemTime);
unsafe_no_jsmanaged_fields!(Instant);
unsafe_no_jsmanaged_fields!(PathBuf);
unsafe_no_jsmanaged_fields!(WebGPUContextId);
unsafe_no_jsmanaged_fields!(GPUBufferState);
unsafe_no_jsmanaged_fields!(GPUCommandEncoderState);
unsafe_no_jsmanaged_fields!(Range<u64>);
unsafe_no_jsmanaged_fields!(SourceSet);
unsafe_no_jsmanaged_fields!(HTMLMediaElementFetchContext);
unsafe_no_jsmanaged_fields!(StreamConsumer);
unsafe_no_jsmanaged_fields!(Stencil);
unsafe impl<'a> JSTraceable for &'a str {
#[inline]
unsafe fn trace(&self, _: *mut JSTracer) {
// Do nothing
}
}
unsafe impl<A, B> JSTraceable for fn(A) -> B {
#[inline]
unsafe fn trace(&self, _: *mut JSTracer) {
// Do nothing
}
}
unsafe impl JSTraceable for () {
#[inline]
unsafe fn trace(&self, _: *mut JSTracer) {
// Do nothing
}
}
unsafe impl<T: DomObject> JSTraceable for Trusted<T> {
#[inline]
@ -590,16 +377,7 @@ unsafe impl<T: DomObject> JSTraceable for Trusted<T> {
}
}
unsafe impl<T> JSTraceable for TypedArray<T, Box<Heap<*mut JSObject>>>
where
T: TypedArrayElement,
{
unsafe fn trace(&self, trc: *mut JSTracer) {
self.underlying_object().trace(trc);
}
}
unsafe impl<S> JSTraceable for DocumentStylesheetSet<S>
unsafe impl<S> CustomTraceable for DocumentStylesheetSet<S>
where
S: JSTraceable + ::style::stylesheets::StylesheetInDocument + PartialEq + 'static,
{
@ -610,7 +388,7 @@ where
}
}
unsafe impl<S> JSTraceable for AuthorStylesheetSet<S>
unsafe impl<S> CustomTraceable for AuthorStylesheetSet<S>
where
S: JSTraceable + ::style::stylesheets::StylesheetInDocument + PartialEq + 'static,
{
@ -621,7 +399,7 @@ where
}
}
unsafe impl<S> JSTraceable for AuthorStyles<S>
unsafe impl<S> CustomTraceable for AuthorStyles<S>
where
S: JSTraceable + ::style::stylesheets::StylesheetInDocument + PartialEq + 'static,
{
@ -630,7 +408,7 @@ where
}
}
unsafe impl<Sink> JSTraceable for LossyDecoder<Sink>
unsafe impl<Sink> CustomTraceable for LossyDecoder<Sink>
where
Sink: JSTraceable + TendrilSink<UTF8>,
{
@ -639,7 +417,7 @@ where
}
}
unsafe impl<J> JSTraceable for Hand<J>
unsafe impl<J> CustomTraceable for Hand<J>
where
J: JSTraceable,
{
@ -669,7 +447,7 @@ where
}
}
unsafe impl<J> JSTraceable for Finger<J>
unsafe impl<J> CustomTraceable for Finger<J>
where
J: JSTraceable,
{
@ -692,47 +470,7 @@ where
}
/// Holds a set of JSTraceables that need to be rooted
struct RootedTraceableSet {
set: Vec<*const dyn JSTraceable>,
}
thread_local!(
/// TLV Holds a set of JSTraceables that need to be rooted
static ROOTED_TRACEABLES: RefCell<RootedTraceableSet> = RefCell::new(RootedTraceableSet::new());
);
impl RootedTraceableSet {
fn new() -> RootedTraceableSet {
RootedTraceableSet { set: vec![] }
}
unsafe fn remove(traceable: *const dyn JSTraceable) {
ROOTED_TRACEABLES.with(|ref traceables| {
let mut traceables = traceables.borrow_mut();
let idx = match traceables
.set
.iter()
.rposition(|x| *x as *const () == traceable as *const ())
{
Some(idx) => idx,
None => unreachable!(),
};
traceables.set.remove(idx);
});
}
unsafe fn add(traceable: *const dyn JSTraceable) {
ROOTED_TRACEABLES.with(|ref traceables| {
traceables.borrow_mut().set.push(traceable);
})
}
unsafe fn trace(&self, tracer: *mut JSTracer) {
for traceable in &self.set {
(**traceable).trace(tracer);
}
}
}
pub use js::gc::RootedTraceableSet;
/// Roots any JSTraceable thing
///
@ -741,29 +479,23 @@ impl RootedTraceableSet {
/// If you have an arbitrary number of DomObjects to root, use rooted_vec!.
/// If you know what you're doing, use this.
#[unrooted_must_root_lint::allow_unrooted_interior]
pub struct RootedTraceableBox<T: 'static + JSTraceable> {
ptr: *mut T,
}
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) {
(*self.ptr).trace(tracer);
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::from_box(Box::new(traceable))
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> {
let traceable = Box::into_raw(boxed_traceable);
unsafe {
RootedTraceableSet::add(traceable);
}
RootedTraceableBox { ptr: traceable }
Self(js::gc::RootedTraceableBox::from_box(boxed_traceable))
}
}
@ -773,7 +505,7 @@ where
T: GCMethods + Copy,
{
pub fn handle(&self) -> Handle<T> {
unsafe { Handle::from_raw((*self.ptr).handle()) }
self.0.handle()
}
}
@ -781,7 +513,7 @@ 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.ptr) };
let inner = unsafe { Box::from_raw(self.0.ptr()) };
let size = inner.size_of(ops);
mem::forget(inner);
size
@ -797,22 +529,13 @@ impl<T: JSTraceable + Default> Default for RootedTraceableBox<T> {
impl<T: JSTraceable> Deref for RootedTraceableBox<T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.ptr }
self.0.deref()
}
}
impl<T: JSTraceable> DerefMut for RootedTraceableBox<T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.ptr }
}
}
impl<T: JSTraceable + 'static> Drop for RootedTraceableBox<T> {
fn drop(&mut self) {
unsafe {
RootedTraceableSet::remove(self.ptr);
let _ = Box::from_raw(self.ptr);
}
self.0.deref_mut()
}
}
@ -847,7 +570,7 @@ impl<'a, T: 'static + JSTraceable> RootedVec<'a, T> {
unsafe {
RootedTraceableSet::add(root);
}
RootedVec { root: root }
RootedVec { root }
}
}
@ -862,7 +585,7 @@ impl<'a, T: 'static + JSTraceable + DomObject> RootedVec<'a, Dom<T>> {
RootedTraceableSet::add(root);
}
root.v.extend(iter.map(|item| Dom::from_ref(&*item)));
RootedVec { root: root }
RootedVec { root }
}
}
@ -887,12 +610,3 @@ impl<'a, T: JSTraceable> DerefMut for RootedVec<'a, T> {
&mut self.root.v
}
}
/// SM Callback that traces the rooted traceables
pub unsafe fn trace_traceables(tracer: *mut JSTracer) {
trace!("tracing stack-rooted traceables");
ROOTED_TRACEABLES.with(|ref traceables| {
let traceables = traceables.borrow();
traceables.trace(tracer);
});
}