diff options
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/dom/bindings/constant.rs | 69 | ||||
-rw-r--r-- | components/script/dom/bindings/conversions.rs | 140 | ||||
-rw-r--r-- | components/script/dom/bindings/error.rs | 2 | ||||
-rw-r--r-- | components/script/dom/bindings/import.rs | 2 | ||||
-rw-r--r-- | components/script/dom/bindings/interface.rs | 2 | ||||
-rw-r--r-- | components/script/dom/bindings/mod.rs | 1 | ||||
-rw-r--r-- | components/script/dom/bindings/namespace.rs | 2 | ||||
-rw-r--r-- | components/script/dom/bindings/root.rs | 402 | ||||
-rw-r--r-- | components/script/dom/bindings/trace.rs | 26 | ||||
-rw-r--r-- | components/script/dom/document.rs | 2 | ||||
-rw-r--r-- | components/script/dom/element.rs | 80 | ||||
-rw-r--r-- | components/script/dom/htmlcanvaselement.rs | 2 | ||||
-rw-r--r-- | components/script/dom/messageport.rs | 3 | ||||
-rw-r--r-- | components/script/dom/node.rs | 22 | ||||
-rw-r--r-- | components/script/dom/webgl2renderingcontext.rs | 2 | ||||
-rw-r--r-- | components/script/dom/workerglobalscope.rs | 2 | ||||
-rw-r--r-- | components/script/script_runtime.rs | 49 | ||||
-rw-r--r-- | components/script/script_thread.rs | 2 |
18 files changed, 111 insertions, 699 deletions
diff --git a/components/script/dom/bindings/constant.rs b/components/script/dom/bindings/constant.rs deleted file mode 100644 index 7364ee2086d..00000000000 --- a/components/script/dom/bindings/constant.rs +++ /dev/null @@ -1,69 +0,0 @@ -/* 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/. */ - -//! WebIDL constants. - -use std::ffi::CStr; - -use js::jsapi::{JSPROP_ENUMERATE, JSPROP_PERMANENT, JSPROP_READONLY}; -use js::jsval::{BooleanValue, DoubleValue, Int32Value, JSVal, NullValue, UInt32Value}; -use js::rust::wrappers::JS_DefineProperty; -use js::rust::HandleObject; - -use crate::script_runtime::JSContext; - -/// Representation of an IDL constant. -#[derive(Clone)] -pub(crate) struct ConstantSpec { - /// name of the constant. - pub(crate) name: &'static CStr, - /// value of the constant. - pub(crate) value: ConstantVal, -} - -/// Representation of an IDL constant value. -#[derive(Clone)] -#[allow(dead_code)] -pub(crate) enum ConstantVal { - /// `long` constant. - Int(i32), - /// `unsigned long` constant. - Uint(u32), - /// `double` constant. - Double(f64), - /// `boolean` constant. - Bool(bool), - /// `null` constant. - Null, -} - -impl ConstantSpec { - /// Returns a `JSVal` that represents the value of this `ConstantSpec`. - pub(crate) fn get_value(&self) -> JSVal { - match self.value { - ConstantVal::Null => NullValue(), - ConstantVal::Int(i) => Int32Value(i), - ConstantVal::Uint(u) => UInt32Value(u), - ConstantVal::Double(d) => DoubleValue(d), - ConstantVal::Bool(b) => BooleanValue(b), - } - } -} - -/// Defines constants on `obj`. -/// Fails on JSAPI failure. -pub(crate) fn define_constants(cx: JSContext, obj: HandleObject, constants: &[ConstantSpec]) { - for spec in constants { - rooted!(in(*cx) let value = spec.get_value()); - unsafe { - assert!(JS_DefineProperty( - *cx, - obj, - spec.name.as_ptr(), - value.handle(), - (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT) as u32 - )); - } - } -} diff --git a/components/script/dom/bindings/conversions.rs b/components/script/dom/bindings/conversions.rs index 7d276923c7c..11d838230d3 100644 --- a/components/script/dom/bindings/conversions.rs +++ b/components/script/dom/bindings/conversions.rs @@ -32,17 +32,17 @@ //! | sequences | `Vec<T>` | | //! | union types | `T` | | -use std::{ffi, ptr}; +use std::ffi; pub(crate) use js::conversions::{ ConversionBehavior, ConversionResult, FromJSValConvertible, ToJSValConvertible, }; use js::error::throw_type_error; -use js::glue::{GetProxyReservedSlot, IsWrapper, JS_GetReservedSlot, UnwrapObjectDynamic}; +use js::glue::GetProxyReservedSlot; use js::jsapi::{Heap, IsWindowProxy, JSContext, JSObject, JS_IsExceptionPending}; use js::jsval::UndefinedValue; use js::rust::wrappers::{IsArrayObject, JS_GetProperty, JS_HasProperty}; -use js::rust::{is_dom_object, HandleId, HandleObject, HandleValue, MutableHandleValue}; +use js::rust::{HandleId, HandleObject, HandleValue, MutableHandleValue}; use num_traits::Float; pub(crate) use script_bindings::conversions::*; @@ -93,21 +93,6 @@ impl<T: Float + FromJSValConvertible<Config = ()>> FromJSValConvertible for Fini } } -impl<T: DomObject + IDLInterface> FromJSValConvertible for DomRoot<T> { - type Config = (); - - unsafe fn from_jsval( - cx: *mut JSContext, - value: HandleValue, - _config: Self::Config, - ) -> Result<ConversionResult<DomRoot<T>>, ()> { - Ok(match root_from_handlevalue(value, cx) { - Ok(result) => ConversionResult::Success(result), - Err(()) => ConversionResult::Failure("value is not an object".into()), - }) - } -} - impl<T: ToJSValConvertible + JSTraceable> ToJSValConvertible for RootedTraceableBox<T> { #[inline] unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) { @@ -157,79 +142,6 @@ pub(crate) unsafe fn jsid_to_string(cx: *mut JSContext, id: HandleId) -> Option< pub(crate) use script_bindings::conversions::is_dom_proxy; -/// The index of the slot wherein a pointer to the reflected DOM object is -/// stored for non-proxy bindings. -// We use slot 0 for holding the raw object. This is safe for both -// globals and non-globals. -pub(crate) const DOM_OBJECT_SLOT: u32 = 0; - -/// Get the private pointer of a DOM object from a given reflector. -pub(crate) unsafe fn private_from_object(obj: *mut JSObject) -> *const libc::c_void { - let mut value = UndefinedValue(); - if is_dom_object(obj) { - JS_GetReservedSlot(obj, DOM_OBJECT_SLOT, &mut value); - } else { - debug_assert!(is_dom_proxy(obj)); - GetProxyReservedSlot(obj, 0, &mut value); - }; - if value.is_undefined() { - ptr::null() - } else { - value.to_private() - } -} - -pub(crate) enum PrototypeCheck { - Derive(fn(&'static DOMClass) -> bool), - Depth { depth: usize, proto_id: u16 }, -} - -/// Get a `*const libc::c_void` for the given DOM object, unwrapping any -/// wrapper around it first, and checking if the object is of the correct type. -/// -/// Returns Err(()) if `obj` is an opaque security wrapper or if the object is -/// not an object for a DOM object of the given type (as defined by the -/// proto_id and proto_depth). -#[inline] -pub(crate) unsafe fn private_from_proto_check( - mut obj: *mut JSObject, - cx: *mut JSContext, - proto_check: PrototypeCheck, -) -> Result<*const libc::c_void, ()> { - let dom_class = get_dom_class(obj).or_else(|_| { - if IsWrapper(obj) { - trace!("found wrapper"); - obj = UnwrapObjectDynamic(obj, cx, /* stopAtWindowProxy = */ false); - if obj.is_null() { - trace!("unwrapping security wrapper failed"); - Err(()) - } else { - assert!(!IsWrapper(obj)); - trace!("unwrapped successfully"); - get_dom_class(obj) - } - } else { - trace!("not a dom wrapper"); - Err(()) - } - })?; - - let prototype_matches = match proto_check { - PrototypeCheck::Derive(f) => (f)(dom_class), - PrototypeCheck::Depth { depth, proto_id } => { - dom_class.interface_chain[depth] as u16 == proto_id - }, - }; - - if prototype_matches { - trace!("good prototype"); - Ok(private_from_object(obj)) - } else { - trace!("bad prototype"); - Err(()) - } -} - /// Get a `*const libc::c_void` for the given DOM object, unless it is a DOM /// wrapper, and checking if the object is of the correct type. /// @@ -250,17 +162,6 @@ unsafe fn private_from_proto_check_static( } } -/// Get a `*const T` for a DOM object accessible from a `JSObject`. -pub(crate) fn native_from_object<T>(obj: *mut JSObject, cx: *mut JSContext) -> Result<*const T, ()> -where - T: DomObject + IDLInterface, -{ - unsafe { - private_from_proto_check(obj, cx, PrototypeCheck::Derive(T::derives)) - .map(|ptr| ptr as *const T) - } -} - /// Get a `*const T` for a DOM object accessible from a `JSObject`, where the DOM object /// is guaranteed not to be a wrapper. pub(crate) fn native_from_object_static<T>(obj: *mut JSObject) -> Result<*const T, ()> @@ -276,19 +177,6 @@ where /// Returns Err(()) if `obj` is an opaque security wrapper or if the object is /// not a reflector for a DOM object of the given type (as defined by the /// proto_id and proto_depth). -pub(crate) fn root_from_object<T>(obj: *mut JSObject, cx: *mut JSContext) -> Result<DomRoot<T>, ()> -where - T: DomObject + IDLInterface, -{ - native_from_object(obj, cx).map(|ptr| unsafe { DomRoot::from_ref(&*ptr) }) -} - -/// Get a `DomRoot<T>` for the given DOM object, unwrapping any wrapper -/// around it first, and checking if the object is of the correct type. -/// -/// Returns Err(()) if `obj` is an opaque security wrapper or if the object is -/// not a reflector for a DOM object of the given type (as defined by the -/// proto_id and proto_depth). pub(crate) fn root_from_object_static<T>(obj: *mut JSObject) -> Result<DomRoot<T>, ()> where T: DomObject + IDLInterface, @@ -305,19 +193,7 @@ where if !v.get().is_object() { return Err(()); } - native_from_object(v.get().to_object(), cx) -} - -/// Get a `DomRoot<T>` for a DOM object accessible from a `HandleValue`. -/// Caller is responsible for throwing a JS exception if needed in case of error. -pub(crate) fn root_from_handlevalue<T>(v: HandleValue, cx: *mut JSContext) -> Result<DomRoot<T>, ()> -where - T: DomObject + IDLInterface, -{ - if !v.get().is_object() { - return Err(()); - } - root_from_object(v.get().to_object(), cx) + unsafe { native_from_object(v.get().to_object(), cx) } } /// Get a `DomRoot<T>` for a DOM object accessible from a `HandleObject`. @@ -328,13 +204,7 @@ pub(crate) fn root_from_handleobject<T>( where T: DomObject + IDLInterface, { - root_from_object(obj.get(), cx) -} - -impl<T: DomObject> ToJSValConvertible for DomRoot<T> { - unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) { - self.reflector().to_jsval(cx, rval); - } + unsafe { root_from_object(obj.get(), cx) } } /// Returns whether `value` is an array-like object (Array, FileList, diff --git a/components/script/dom/bindings/error.rs b/components/script/dom/bindings/error.rs index e809e2df552..abf394b6ed9 100644 --- a/components/script/dom/bindings/error.rs +++ b/components/script/dom/bindings/error.rs @@ -220,7 +220,7 @@ impl ErrorInfo { } fn from_dom_exception(object: HandleObject, cx: SafeJSContext) -> Option<ErrorInfo> { - let exception = match root_from_object::<DOMException>(object.get(), *cx) { + let exception = match unsafe { root_from_object::<DOMException>(object.get(), *cx) } { Ok(exception) => exception, Err(_) => return None, }; diff --git a/components/script/dom/bindings/import.rs b/components/script/dom/bindings/import.rs index c24de0363a1..2afe1b0e534 100644 --- a/components/script/dom/bindings/import.rs +++ b/components/script/dom/bindings/import.rs @@ -97,6 +97,7 @@ pub(crate) mod module { jsapi, typedarray, JSCLASS_GLOBAL_SLOT_COUNT, JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL, JSCLASS_RESERVED_SLOTS_MASK, JS_CALLEE, }; + pub(crate) use script_bindings::constant::{ConstantSpec, ConstantVal}; pub(crate) use servo_config::pref; pub(crate) use super::base::*; @@ -109,7 +110,6 @@ pub(crate) mod module { pub(crate) use crate::dom::bindings::codegen::{ InterfaceObjectMap, PrototypeList, RegisterBindings, }; - pub(crate) use crate::dom::bindings::constant::{ConstantSpec, ConstantVal}; pub(crate) use crate::dom::bindings::constructor::{ call_default_constructor, call_html_constructor, pop_current_element_queue, push_new_element_queue, diff --git a/components/script/dom/bindings/interface.rs b/components/script/dom/bindings/interface.rs index 168abfc1503..45a5b9ffbb7 100644 --- a/components/script/dom/bindings/interface.rs +++ b/components/script/dom/bindings/interface.rs @@ -31,11 +31,11 @@ use js::rust::{ define_methods, define_properties, get_object_class, is_dom_class, maybe_wrap_object, HandleObject, HandleValue, MutableHandleObject, RealmOptions, }; +use script_bindings::constant::{define_constants, ConstantSpec}; use servo_url::MutableOrigin; use crate::dom::bindings::codegen::InterfaceObjectMap::Globals; use crate::dom::bindings::codegen::PrototypeList; -use crate::dom::bindings::constant::{define_constants, ConstantSpec}; use crate::dom::bindings::conversions::{get_dom_class, DOM_OBJECT_SLOT}; use crate::dom::bindings::guard::Guard; use crate::dom::bindings::principals::ServoJSPrincipals; diff --git a/components/script/dom/bindings/mod.rs b/components/script/dom/bindings/mod.rs index e37cb3e485c..e29a18a5917 100644 --- a/components/script/dom/bindings/mod.rs +++ b/components/script/dom/bindings/mod.rs @@ -138,7 +138,6 @@ pub(crate) mod buffer_source; pub(crate) mod callback; #[allow(dead_code)] pub(crate) mod cell; -pub(crate) mod constant; pub(crate) mod constructor; pub(crate) mod conversions; pub(crate) mod error; diff --git a/components/script/dom/bindings/namespace.rs b/components/script/dom/bindings/namespace.rs index 3f5e9d846d5..2eca9dbd3f2 100644 --- a/components/script/dom/bindings/namespace.rs +++ b/components/script/dom/bindings/namespace.rs @@ -9,8 +9,8 @@ use std::ptr; use js::jsapi::{JSClass, JSFunctionSpec}; use js::rust::{HandleObject, MutableHandleObject}; +use script_bindings::constant::ConstantSpec; -use super::constant::ConstantSpec; use crate::dom::bindings::guard::Guard; use crate::dom::bindings::interface::{create_object, define_on_global_object}; use crate::script_runtime::JSContext; diff --git a/components/script/dom/bindings/root.rs b/components/script/dom/bindings/root.rs index 912ed9acee4..4e8cbf21882 100644 --- a/components/script/dom/bindings/root.rs +++ b/components/script/dom/bindings/root.rs @@ -24,232 +24,24 @@ //! originating `DomRoot<T>`. //! -use std::cell::{Cell, OnceCell, UnsafeCell}; +use std::cell::{OnceCell, UnsafeCell}; use std::default::Default; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; -use std::ops::Deref; use std::{mem, ptr}; use js::jsapi::{JSObject, JSTracer}; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; +pub(crate) use script_bindings::root::*; use script_layout_interface::TrustedNodeAddress; use style::thread_state; use crate::dom::bindings::conversions::DerivedFrom; use crate::dom::bindings::inheritance::Castable; -use crate::dom::bindings::reflector::{DomObject, MutDomObject, Reflector}; -use crate::dom::bindings::trace::{trace_reflector, JSTraceable}; +use crate::dom::bindings::reflector::DomObject; +use crate::dom::bindings::trace::JSTraceable; use crate::dom::node::Node; -/// A rooted value. -#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)] -pub(crate) struct Root<T: StableTraceObject> { - /// The value to root. - value: T, - /// List that ensures correct dynamic root ordering - root_list: *const RootCollection, -} - -impl<T> Root<T> -where - T: StableTraceObject + 'static, -{ - /// Create a new stack-bounded root for the provided value. - /// It cannot outlive its associated `RootCollection`, and it gives - /// out references which cannot outlive this new `Root`. - #[cfg_attr(crown, allow(crown::unrooted_must_root))] - pub(crate) unsafe fn new(value: T) -> Self { - unsafe fn add_to_root_list(object: *const dyn JSTraceable) -> *const RootCollection { - assert_in_script(); - STACK_ROOTS.with(|root_list| { - let root_list = &*root_list.get().unwrap(); - root_list.root(object); - root_list - }) - } - - let root_list = add_to_root_list(value.stable_trace_object()); - Root { value, root_list } - } -} - -/// `StableTraceObject` represents values that can be rooted through a stable address that will -/// not change for their whole lifetime. -/// It is an unsafe trait that requires implementors to ensure certain safety guarantees. -/// -/// # Safety -/// -/// Implementors of this trait must ensure that the `trace` method correctly accounts for all -/// owned and referenced objects, so that the garbage collector can accurately determine which -/// objects are still in use. Failing to adhere to this contract may result in undefined behavior, -/// such as use-after-free errors. -pub(crate) unsafe trait StableTraceObject { - /// Returns a stable trace object which address won't change for the whole - /// lifetime of the value. - fn stable_trace_object(&self) -> *const dyn JSTraceable; -} - -unsafe impl<T> StableTraceObject for Dom<T> -where - T: DomObject, -{ - fn stable_trace_object(&self) -> *const dyn JSTraceable { - // The JSTraceable impl for Reflector doesn't actually do anything, - // so we need this shenanigan to actually trace the reflector of the - // T pointer in Dom<T>. - #[cfg_attr(crown, allow(crown::unrooted_must_root))] - struct ReflectorStackRoot(Reflector); - unsafe impl JSTraceable for ReflectorStackRoot { - unsafe fn trace(&self, tracer: *mut JSTracer) { - trace_reflector(tracer, "on stack", &self.0); - } - } - unsafe { &*(self.reflector() as *const Reflector as *const ReflectorStackRoot) } - } -} - -unsafe impl<T> StableTraceObject for MaybeUnreflectedDom<T> -where - T: DomObject, -{ - fn stable_trace_object(&self) -> *const dyn JSTraceable { - // The JSTraceable impl for Reflector doesn't actually do anything, - // so we need this shenanigan to actually trace the reflector of the - // T pointer in Dom<T>. - #[cfg_attr(crown, allow(crown::unrooted_must_root))] - struct MaybeUnreflectedStackRoot<T>(T); - unsafe impl<T> JSTraceable for MaybeUnreflectedStackRoot<T> - where - T: DomObject, - { - unsafe fn trace(&self, tracer: *mut JSTracer) { - if self.0.reflector().get_jsobject().is_null() { - self.0.trace(tracer); - } else { - trace_reflector(tracer, "on stack", self.0.reflector()); - } - } - } - unsafe { &*(self.ptr.as_ptr() as *const T as *const MaybeUnreflectedStackRoot<T>) } - } -} - -impl<T> Deref for Root<T> -where - T: Deref + StableTraceObject, -{ - type Target = <T as Deref>::Target; - - fn deref(&self) -> &Self::Target { - assert_in_script(); - &self.value - } -} - -impl<T> Drop for Root<T> -where - T: StableTraceObject, -{ - fn drop(&mut self) { - unsafe { - (*self.root_list).unroot(self.value.stable_trace_object()); - } - } -} - -/// A rooted reference to a DOM object. -pub(crate) type DomRoot<T> = Root<Dom<T>>; - -impl<T: Castable> DomRoot<T> { - /// Cast a DOM object root upwards to one of the interfaces it derives from. - pub(crate) fn upcast<U>(root: DomRoot<T>) -> DomRoot<U> - where - U: Castable, - T: DerivedFrom<U>, - { - unsafe { mem::transmute::<DomRoot<T>, DomRoot<U>>(root) } - } - - /// Cast a DOM object root downwards to one of the interfaces it might implement. - pub(crate) fn downcast<U>(root: DomRoot<T>) -> Option<DomRoot<U>> - where - U: DerivedFrom<T>, - { - if root.is::<U>() { - Some(unsafe { mem::transmute::<DomRoot<T>, DomRoot<U>>(root) }) - } else { - None - } - } -} - -impl<T: DomObject> DomRoot<T> { - /// Generate a new root from a reference - pub(crate) fn from_ref(unrooted: &T) -> DomRoot<T> { - unsafe { DomRoot::new(Dom::from_ref(unrooted)) } - } - - /// Create a traced version of this rooted object. - /// - /// # Safety - /// - /// This should never be used to create on-stack values. Instead these values should always - /// end up as members of other DOM objects. - #[cfg_attr(crown, allow(crown::unrooted_must_root))] - pub(crate) fn as_traced(&self) -> Dom<T> { - Dom::from_ref(self) - } -} - -impl<T> MallocSizeOf for DomRoot<T> -where - T: DomObject + MallocSizeOf, -{ - fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { - (**self).size_of(ops) - } -} - -impl<T> PartialEq for DomRoot<T> -where - T: DomObject, -{ - fn eq(&self, other: &Self) -> bool { - self.value == other.value - } -} - -impl<T> Clone for DomRoot<T> -where - T: DomObject, -{ - fn clone(&self) -> DomRoot<T> { - DomRoot::from_ref(self) - } -} - -unsafe impl<T> JSTraceable for DomRoot<T> -where - T: DomObject, -{ - unsafe fn trace(&self, _: *mut JSTracer) { - // Already traced. - } -} - -/// A rooting mechanism for reflectors on the stack. -/// LIFO is not required. -/// -/// See also [*Exact Stack Rooting - Storing a GCPointer on the CStack*][cstack]. -/// -/// [cstack]: https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Internals/GC/Exact_Stack_Rooting -pub(crate) struct RootCollection { - roots: UnsafeCell<Vec<*const dyn JSTraceable>>, -} - -thread_local!(static STACK_ROOTS: Cell<Option<*const RootCollection>> = const { Cell::new(None) }); - pub(crate) struct ThreadLocalStackRoots<'a>(PhantomData<&'a u32>); impl<'a> ThreadLocalStackRoots<'a> { @@ -265,48 +57,6 @@ impl Drop for ThreadLocalStackRoots<'_> { } } -impl RootCollection { - /// Create an empty collection of roots - pub(crate) fn new() -> RootCollection { - assert_in_script(); - RootCollection { - roots: UnsafeCell::new(vec![]), - } - } - - /// Starts tracking a trace object. - unsafe fn root(&self, object: *const dyn JSTraceable) { - assert_in_script(); - (*self.roots.get()).push(object); - } - - /// Stops tracking a trace object, asserting if it isn't found. - unsafe fn unroot(&self, object: *const dyn JSTraceable) { - assert_in_script(); - let roots = &mut *self.roots.get(); - match roots - .iter() - .rposition(|r| std::ptr::addr_eq(*r as *const (), object as *const ())) - { - Some(idx) => { - roots.remove(idx); - }, - None => panic!("Can't remove a root that was never rooted!"), - } - } -} - -/// SM Callback that traces the rooted reflectors -pub(crate) unsafe fn trace_roots(tracer: *mut JSTracer) { - trace!("tracing stack roots"); - STACK_ROOTS.with(|collection| { - let collection = &*(*collection.get().unwrap()).roots.get(); - for root in collection { - (**root).trace(tracer); - } - }); -} - /// Get a slice of references to DOM objects. pub(crate) trait DomSlice<T> where @@ -327,121 +77,24 @@ where } } -/// A traced reference to a DOM object -/// -/// This type is critical to making garbage collection work with the DOM, -/// but it is very dangerous; if garbage collection happens with a `Dom<T>` -/// on the stack, the `Dom<T>` can point to freed memory. -/// -/// This should only be used as a field in other DOM objects. -#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)] -#[repr(transparent)] -pub(crate) struct Dom<T> { - ptr: ptr::NonNull<T>, -} - -// Dom<T> is similar to Rc<T>, in that it's not always clear how to avoid double-counting. -// For now, we choose not to follow any such pointers. -impl<T> MallocSizeOf for Dom<T> { - fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize { - 0 - } -} - -impl<T> Dom<T> { +pub(crate) trait ToLayout<T> { /// Returns `LayoutDom<T>` containing the same pointer. /// /// # Safety /// /// The `self` parameter to this method must meet all the requirements of [`ptr::NonNull::as_ref`]. - pub(crate) unsafe fn to_layout(&self) -> LayoutDom<T> { - assert_in_layout(); - LayoutDom { - value: self.ptr.as_ref(), - } - } -} - -impl<T: DomObject> Dom<T> { - /// Create a `Dom<T>` from a `&T` - #[cfg_attr(crown, allow(crown::unrooted_must_root))] - pub(crate) fn from_ref(obj: &T) -> Dom<T> { - assert_in_script(); - Dom { - ptr: ptr::NonNull::from(obj), - } - } - - /// Return a rooted version of this DOM object ([`DomRoot<T>`]) suitable for use on the stack. - pub(crate) fn as_rooted(&self) -> DomRoot<T> { - DomRoot::from_ref(self) - } -} - -impl<T: DomObject> Deref for Dom<T> { - type Target = T; - - fn deref(&self) -> &T { - assert_in_script(); - // We can only have &Dom<T> from a rooted thing, so it's safe to deref - // it to &T. - unsafe { &*self.ptr.as_ptr() } - } -} - -unsafe impl<T: DomObject> JSTraceable for Dom<T> { - unsafe fn trace(&self, trc: *mut JSTracer) { - let trace_string; - let trace_info = if cfg!(debug_assertions) { - trace_string = format!("for {} on heap", ::std::any::type_name::<T>()); - &trace_string[..] - } else { - "for DOM object on heap" - }; - trace_reflector(trc, trace_info, (*self.ptr.as_ptr()).reflector()); - } + unsafe fn to_layout(&self) -> LayoutDom<T>; } -/// A traced reference to a DOM object that may not be reflected yet. -#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)] -pub(crate) struct MaybeUnreflectedDom<T> { - ptr: ptr::NonNull<T>, -} - -impl<T> MaybeUnreflectedDom<T> -where - T: DomObject, -{ - #[cfg_attr(crown, allow(crown::unrooted_must_root))] - pub(crate) unsafe fn from_box(value: Box<T>) -> Self { - Self { - ptr: Box::leak(value).into(), +impl<T: DomObject> ToLayout<T> for Dom<T> { + unsafe fn to_layout(&self) -> LayoutDom<T> { + assert_in_layout(); + LayoutDom { + value: self.as_ptr().as_ref().unwrap(), } } } -impl<T> Root<MaybeUnreflectedDom<T>> -where - T: DomObject, -{ - pub(crate) fn as_ptr(&self) -> *const T { - self.value.ptr.as_ptr() - } -} - -impl<T> Root<MaybeUnreflectedDom<T>> -where - T: MutDomObject, -{ - pub(crate) unsafe fn reflect_with(self, obj: *mut JSObject) -> DomRoot<T> { - let ptr = self.as_ptr(); - drop(self); - let root = DomRoot::from_ref(&*ptr); - root.init_reflector(obj); - root - } -} - /// An unrooted reference to a DOM object for use in layout. `Layout*Helpers` /// traits must be implemented on this. #[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)] @@ -498,20 +151,6 @@ where impl<T> Copy for LayoutDom<'_, T> {} -impl<T> PartialEq for Dom<T> { - fn eq(&self, other: &Dom<T>) -> bool { - self.ptr.as_ptr() == other.ptr.as_ptr() - } -} - -impl<'a, T: DomObject> PartialEq<&'a T> for Dom<T> { - fn eq(&self, other: &&'a T) -> bool { - *self == Dom::from_ref(*other) - } -} - -impl<T> Eq for Dom<T> {} - impl<T> PartialEq for LayoutDom<'_, T> { fn eq(&self, other: &Self) -> bool { std::ptr::eq(self.value, other.value) @@ -520,27 +159,12 @@ impl<T> PartialEq for LayoutDom<'_, T> { impl<T> Eq for LayoutDom<'_, T> {} -impl<T> Hash for Dom<T> { - fn hash<H: Hasher>(&self, state: &mut H) { - self.ptr.as_ptr().hash(state) - } -} - impl<T> Hash for LayoutDom<'_, T> { fn hash<H: Hasher>(&self, state: &mut H) { (self.value as *const T).hash(state) } } -impl<T> Clone for Dom<T> { - #[inline] - #[cfg_attr(crown, allow(crown::unrooted_must_root))] - fn clone(&self) -> Self { - assert_in_script(); - Dom { ptr: self.ptr } - } -} - impl<T> Clone for LayoutDom<'_, T> { #[inline] #[allow(clippy::non_canonical_clone_impl)] @@ -616,10 +240,6 @@ impl<T: DomObject + PartialEq> PartialEq<T> for MutDom<T> { } } -pub(crate) fn assert_in_script() { - debug_assert!(thread_state::get().is_script()); -} - pub(crate) fn assert_in_layout() { debug_assert!(thread_state::get().is_layout()); } diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index fc9df6e89e9..a25cfa83774 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -42,12 +42,13 @@ use indexmap::IndexMap; /// A trait to allow tracing (only) DOM objects. pub(crate) use js::gc::Traceable as JSTraceable; pub(crate) use js::gc::{RootableVec, RootedVec}; -use js::glue::{CallObjectTracer, CallScriptTracer, CallStringTracer, CallValueTracer}; -use js::jsapi::{GCTraceKindToAscii, Heap, JSObject, JSScript, JSString, JSTracer, TraceKind}; +use js::glue::{CallScriptTracer, CallStringTracer, CallValueTracer}; +use js::jsapi::{GCTraceKindToAscii, Heap, JSScript, JSString, JSTracer, TraceKind}; use js::jsval::JSVal; use js::rust::{GCMethods, Handle}; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use parking_lot::RwLock; +pub(crate) use script_bindings::trace::*; use servo_arc::Arc as ServoArc; use smallvec::SmallVec; use style::author_styles::AuthorStyles; @@ -61,7 +62,7 @@ use webxr_api::{Finger, Hand}; use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::error::Error; use crate::dom::bindings::refcounted::{Trusted, TrustedPromise}; -use crate::dom::bindings::reflector::{DomObject, Reflector}; +use crate::dom::bindings::reflector::DomObject; use crate::dom::htmlimageelement::SourceSet; use crate::dom::htmlmediaelement::HTMLMediaElementFetchContext; use crate::dom::windowproxy::WindowProxyHandler; @@ -285,25 +286,6 @@ pub(crate) fn trace_jsval(tracer: *mut JSTracer, description: &str, val: &Heap<J } } -/// Trace the `JSObject` held by `reflector`. -#[cfg_attr(crown, allow(crown::unrooted_must_root))] -pub(crate) fn trace_reflector(tracer: *mut JSTracer, description: &str, reflector: &Reflector) { - trace!("tracing reflector {}", description); - trace_object(tracer, description, reflector.rootable()) -} - -/// Trace a `JSObject`. -pub(crate) 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), - ); - } -} - #[allow(dead_code)] /// Trace a `JSString`. pub(crate) fn trace_string(tracer: *mut JSTracer, description: &str, s: &Heap<*mut JSString>) { diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index ac8c86cfb71..2b746ec75a1 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -111,7 +111,7 @@ use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementType use crate::dom::bindings::num::Finite; use crate::dom::bindings::refcounted::{Trusted, TrustedPromise}; use crate::dom::bindings::reflector::{reflect_dom_object_with_proto, DomGlobal}; -use crate::dom::bindings::root::{Dom, DomRoot, DomSlice, LayoutDom, MutNullableDom}; +use crate::dom::bindings::root::{Dom, DomRoot, DomSlice, LayoutDom, MutNullableDom, ToLayout}; use crate::dom::bindings::str::{DOMString, USVString}; use crate::dom::bindings::trace::{HashMapTracedValues, NoTrace}; #[cfg(feature = "webgpu")] diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 7a6936611df..dbdff1f5586 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -86,7 +86,7 @@ use crate::dom::bindings::error::{Error, ErrorResult, Fallible}; use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId}; use crate::dom::bindings::refcounted::{Trusted, TrustedPromise}; use crate::dom::bindings::reflector::DomObject; -use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom}; +use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom, ToLayout}; use crate::dom::bindings::str::{DOMString, USVString}; use crate::dom::bindings::xmlname::{ matches_name_production, namespace_from_domstring, validate_and_extract, @@ -162,7 +162,7 @@ use crate::task::TaskOnce; /// <https://dom.spec.whatwg.org/#element> #[dom_struct] -pub(crate) struct Element { +pub struct Element { node: Node, #[no_trace] local_name: LocalName, @@ -203,12 +203,6 @@ impl fmt::Debug for Element { } } -impl fmt::Debug for DomRoot<Element> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - (**self).fmt(f) - } -} - #[derive(MallocSizeOf, PartialEq)] pub(crate) enum ElementCreator { ParserCreated(u64), @@ -3025,7 +3019,11 @@ impl ElementMethods<crate::DomTypeHolder> for Element { let quirks_mode = doc.quirks_mode(); let element = DomRoot::from_ref(self); - Ok(dom_apis::element_matches(&element, &selectors, quirks_mode)) + Ok(dom_apis::element_matches( + &SelectorWrapper::Borrowed(&element), + &selectors, + quirks_mode, + )) } // https://dom.spec.whatwg.org/#dom-element-webkitmatchesselector @@ -3047,10 +3045,11 @@ impl ElementMethods<crate::DomTypeHolder> for Element { let quirks_mode = doc.quirks_mode(); Ok(dom_apis::element_closest( - DomRoot::from_ref(self), + SelectorWrapper::Owned(DomRoot::from_ref(self)), &selectors, quirks_mode, - )) + ) + .map(SelectorWrapper::into_owned)) } // https://dom.spec.whatwg.org/#dom-element-insertadjacentelement @@ -3831,7 +3830,43 @@ impl VirtualMethods for Element { } } -impl SelectorsElement for DomRoot<Element> { +#[derive(Clone, PartialEq)] +/// A type that wraps a DomRoot value so we can implement the SelectorsElement +/// trait without violating the orphan rule. Since the trait assumes that the +/// return type and self type of various methods is the same type that it is +/// implemented against, we need to be able to represent multiple ownership styles. +pub enum SelectorWrapper<'a> { + Borrowed(&'a DomRoot<Element>), + Owned(DomRoot<Element>), +} + +impl fmt::Debug for SelectorWrapper<'_> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.deref().fmt(f) + } +} + +impl Deref for SelectorWrapper<'_> { + type Target = DomRoot<Element>; + + fn deref(&self) -> &Self::Target { + match self { + SelectorWrapper::Owned(r) => r, + SelectorWrapper::Borrowed(r) => r, + } + } +} + +impl SelectorWrapper<'_> { + fn into_owned(self) -> DomRoot<Element> { + match self { + SelectorWrapper::Owned(r) => r, + SelectorWrapper::Borrowed(r) => r.clone(), + } + } +} + +impl SelectorsElement for SelectorWrapper<'_> { type Impl = SelectorImpl; #[allow(unsafe_code)] @@ -3839,8 +3874,10 @@ impl SelectorsElement for DomRoot<Element> { ::selectors::OpaqueElement::new(unsafe { &*self.reflector().get_jsobject().get() }) } - fn parent_element(&self) -> Option<DomRoot<Element>> { - self.upcast::<Node>().GetParentElement() + fn parent_element(&self) -> Option<Self> { + self.upcast::<Node>() + .GetParentElement() + .map(SelectorWrapper::Owned) } fn parent_node_is_shadow_root(&self) -> bool { @@ -3853,6 +3890,7 @@ impl SelectorsElement for DomRoot<Element> { fn containing_shadow_host(&self) -> Option<Self> { self.containing_shadow_root() .map(|shadow_root| shadow_root.Host()) + .map(SelectorWrapper::Owned) } fn is_pseudo_element(&self) -> bool { @@ -3867,22 +3905,24 @@ impl SelectorsElement for DomRoot<Element> { false } - fn prev_sibling_element(&self) -> Option<DomRoot<Element>> { + fn prev_sibling_element(&self) -> Option<Self> { self.node .preceding_siblings() .filter_map(DomRoot::downcast) .next() + .map(SelectorWrapper::Owned) } - fn next_sibling_element(&self) -> Option<DomRoot<Element>> { + fn next_sibling_element(&self) -> Option<Self> { self.node .following_siblings() .filter_map(DomRoot::downcast) .next() + .map(SelectorWrapper::Owned) } - fn first_element_child(&self) -> Option<DomRoot<Element>> { - self.GetFirstElementChild() + fn first_element_child(&self) -> Option<Self> { + self.GetFirstElementChild().map(SelectorWrapper::Owned) } fn attr_matches( @@ -4039,7 +4079,7 @@ impl SelectorsElement for DomRoot<Element> { if !self_flags.is_empty() { #[allow(unsafe_code)] unsafe { - Dom::from_ref(self.deref()) + Dom::from_ref(&***self) .to_layout() .insert_selector_flags(self_flags); } @@ -4051,7 +4091,7 @@ impl SelectorsElement for DomRoot<Element> { if let Some(p) = self.parent_element() { #[allow(unsafe_code)] unsafe { - Dom::from_ref(p.deref()) + Dom::from_ref(&**p) .to_layout() .insert_selector_flags(parent_flags); } diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs index 4e36395707a..8ab61de9d26 100644 --- a/components/script/dom/htmlcanvaselement.rs +++ b/components/script/dom/htmlcanvaselement.rs @@ -46,7 +46,7 @@ use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::num::Finite; use crate::dom::bindings::refcounted::Trusted; use crate::dom::bindings::reflector::{DomGlobal, DomObject}; -use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom}; +use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, ToLayout}; use crate::dom::bindings::str::{DOMString, USVString}; use crate::dom::blob::Blob; use crate::dom::canvasrenderingcontext2d::{ diff --git a/components/script/dom/messageport.rs b/components/script/dom/messageport.rs index bfbd043fc8e..6fbd787e173 100644 --- a/components/script/dom/messageport.rs +++ b/components/script/dom/messageport.rs @@ -96,6 +96,7 @@ impl MessagePort { } /// <https://html.spec.whatwg.org/multipage/#message-port-post-message-steps> + #[allow(unsafe_code)] fn post_message_impl( &self, cx: SafeJSContext, @@ -115,7 +116,7 @@ impl MessagePort { let ports = transfer .iter() - .filter_map(|&obj| root_from_object::<MessagePort>(obj, *cx).ok()); + .filter_map(|&obj| unsafe { root_from_object::<MessagePort>(obj, *cx).ok() }); for port in ports { // Step 2 if port.message_port_id() == self.message_port_id() { diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 806c95e7ab7..73467d8da37 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -76,7 +76,7 @@ use crate::dom::bindings::inheritance::{ }; use crate::dom::bindings::refcounted::Trusted; use crate::dom::bindings::reflector::{reflect_dom_object_with_proto, DomObject, DomObjectWrap}; -use crate::dom::bindings::root::{Dom, DomRoot, DomSlice, LayoutDom, MutNullableDom}; +use crate::dom::bindings::root::{Dom, DomRoot, DomSlice, LayoutDom, MutNullableDom, ToLayout}; use crate::dom::bindings::str::{DOMString, USVString}; use crate::dom::bindings::xmlname::namespace_from_domstring; use crate::dom::characterdata::{CharacterData, LayoutCharacterDataHelpers}; @@ -85,7 +85,7 @@ use crate::dom::customelementregistry::{try_upgrade_element, CallbackReaction}; use crate::dom::document::{Document, DocumentSource, HasBrowsingContext, IsHTMLDocument}; use crate::dom::documentfragment::DocumentFragment; use crate::dom::documenttype::DocumentType; -use crate::dom::element::{CustomElementCreationMode, Element, ElementCreator}; +use crate::dom::element::{CustomElementCreationMode, Element, ElementCreator, SelectorWrapper}; use crate::dom::event::{Event, EventBubbles, EventCancelable}; use crate::dom::eventtarget::EventTarget; use crate::dom::htmlbodyelement::HTMLBodyElement; @@ -178,12 +178,6 @@ impl fmt::Debug for Node { } } -impl fmt::Debug for DomRoot<Node> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - (**self).fmt(f) - } -} - /// Flags for node items #[derive(Clone, Copy, JSTraceable, MallocSizeOf)] pub(crate) struct NodeFlags(u16); @@ -523,7 +517,11 @@ impl Iterator for QuerySelectorIterator { MatchingForInvalidation::No, ); if let Some(element) = DomRoot::downcast(node) { - if matches_selector_list(selectors, &element, &mut ctx) { + if matches_selector_list( + selectors, + &SelectorWrapper::Borrowed(&element), + &mut ctx, + ) { return Some(DomRoot::upcast(element)); } } @@ -1042,9 +1040,9 @@ impl Node { let mut descendants = self.traverse_preorder(ShadowIncluding::No); // Skip the root of the tree. assert!(&*descendants.next().unwrap() == self); - Ok(descendants - .filter_map(DomRoot::downcast) - .find(|element| matches_selector_list(&selectors, element, &mut ctx))) + Ok(descendants.filter_map(DomRoot::downcast).find(|element| { + matches_selector_list(&selectors, &SelectorWrapper::Borrowed(element), &mut ctx) + })) }, } } diff --git a/components/script/dom/webgl2renderingcontext.rs b/components/script/dom/webgl2renderingcontext.rs index c7cc25526d5..d7f122d24ce 100644 --- a/components/script/dom/webgl2renderingcontext.rs +++ b/components/script/dom/webgl2renderingcontext.rs @@ -40,7 +40,7 @@ use crate::dom::bindings::codegen::UnionTypes::{ }; use crate::dom::bindings::error::{ErrorResult, Fallible}; use crate::dom::bindings::reflector::{reflect_dom_object, DomGlobal, Reflector}; -use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom}; +use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom, ToLayout}; use crate::dom::bindings::str::DOMString; use crate::dom::globalscope::GlobalScope; use crate::dom::htmlcanvaselement::LayoutCanvasRenderingContextHelpers; diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index 20b7895c0ea..d7ee456ba8b 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -59,7 +59,7 @@ use crate::dom::workernavigator::WorkerNavigator; use crate::fetch; use crate::messaging::{CommonScriptMsg, ScriptEventLoopReceiver, ScriptEventLoopSender}; use crate::realms::{enter_realm, InRealm}; -use crate::script_runtime::{CanGc, JSContext, Runtime}; +use crate::script_runtime::{CanGc, JSContext, JSContextHelper, Runtime}; use crate::task::TaskCanceller; use crate::timers::{IsInterval, TimerCallback}; diff --git a/components/script/script_runtime.rs b/components/script/script_runtime.rs index 71e93671f47..584555c2d0f 100644 --- a/components/script/script_runtime.rs +++ b/components/script/script_runtime.rs @@ -931,27 +931,21 @@ unsafe fn set_gc_zeal_options(cx: *mut RawJSContext) { #[cfg(not(feature = "debugmozjs"))] unsafe fn set_gc_zeal_options(_: *mut RawJSContext) {} -#[derive(Clone, Copy)] -#[repr(transparent)] -pub(crate) struct JSContext(*mut RawJSContext); +pub(crate) use script_bindings::script_runtime::JSContext; -#[allow(unsafe_code)] -impl JSContext { - /// Create a new [`JSContext`] object from the given raw pointer. - /// - /// # Safety - /// - /// The `RawJSContext` argument must point to a valid `RawJSContext` in memory. - pub(crate) unsafe fn from_ptr(raw_js_context: *mut RawJSContext) -> Self { - JSContext(raw_js_context) - } +/// Extra methods for the JSContext type defined in script_bindings, when +/// the methods are only called by code in the script crate. +pub(crate) trait JSContextHelper { + fn get_reports(&self, path_seg: String) -> Vec<Report>; +} +impl JSContextHelper for JSContext { #[allow(unsafe_code)] - pub(crate) fn get_reports(&self, path_seg: String) -> Vec<Report> { + fn get_reports(&self, path_seg: String) -> Vec<Report> { SEEN_POINTERS.with(|pointers| pointers.borrow_mut().clear()); let stats = unsafe { let mut stats = ::std::mem::zeroed(); - if !CollectServoSizes(self.0, &mut stats, Some(get_size)) { + if !CollectServoSizes(**self, &mut stats, Some(get_size)) { return vec![]; } stats @@ -1007,15 +1001,6 @@ impl JSContext { } } -#[allow(unsafe_code)] -impl Deref for JSContext { - type Target = *mut RawJSContext; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - pub(crate) struct StreamConsumer(*mut JSStreamConsumer); #[allow(unsafe_code)] @@ -1171,18 +1156,4 @@ impl Runnable { } } -#[derive(Clone, Copy, Debug)] -/// A compile-time marker that there are operations that could trigger a JS garbage collection -/// operation within the current stack frame. It is trivially copyable, so it should be passed -/// as a function argument and reused when calling other functions whenever possible. Since it -/// is only meaningful within the current stack frame, it is impossible to move it to a different -/// thread or into a task that will execute asynchronously. -pub(crate) struct CanGc(std::marker::PhantomData<*mut ()>); - -impl CanGc { - /// Create a new CanGc value, representing that a GC operation is possible within the - /// current stack frame. - pub(crate) fn note() -> CanGc { - CanGc(std::marker::PhantomData) - } -} +pub(crate) use script_bindings::script_runtime::CanGc; diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index b11c814b604..9938a818e96 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -149,7 +149,7 @@ use crate::navigation::{InProgressLoad, NavigationListener}; use crate::realms::enter_realm; use crate::script_module::ScriptFetchOptions; use crate::script_runtime::{ - CanGc, JSContext, Runtime, ScriptThreadEventCategory, ThreadSafeJSContext, + CanGc, JSContext, JSContextHelper, Runtime, ScriptThreadEventCategory, ThreadSafeJSContext, }; use crate::task_queue::TaskQueue; use crate::task_source::{SendableTaskSource, TaskSourceName}; |