Move more foundational types to script_bindings (#35280)

* script: Move DOMClass to script_bindings.

Signed-off-by: Josh Matthews <josh@joshmatthews.net>

* script: Move DOMJSClass and get_dom_class to script_bindings.

Signed-off-by: Josh Matthews <josh@joshmatthews.net>

* script: Move Castable/DerivedFrom/IDLInterface to script_bindings.

Signed-off-by: Josh Matthews <josh@joshmatthews.net>

---------

Signed-off-by: Josh Matthews <josh@joshmatthews.net>
This commit is contained in:
Josh Matthews 2025-02-04 05:36:30 -05:00 committed by GitHub
parent eaaad757e8
commit c0cef69108
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 291 additions and 207 deletions

View file

@ -42,15 +42,11 @@ use js::glue::{GetProxyReservedSlot, IsWrapper, JS_GetReservedSlot, UnwrapObject
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::{
get_object_class, is_dom_class, is_dom_object, HandleId, HandleObject, HandleValue,
MutableHandleValue,
};
use js::rust::{is_dom_object, HandleId, HandleObject, HandleValue, MutableHandleValue};
use num_traits::Float;
pub(crate) use script_bindings::conversions::*;
use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::num::Finite;
use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::root::DomRoot;
@ -64,15 +60,6 @@ use crate::dom::htmloptionscollection::HTMLOptionsCollection;
use crate::dom::nodelist::NodeList;
use crate::dom::windowproxy::WindowProxy;
/// A trait to check whether a given `JSObject` implements an IDL interface.
pub(crate) trait IDLInterface {
/// Returns whether the given DOM class derives that interface.
fn derives(_: &'static DOMClass) -> bool;
}
/// A trait to mark an IDL interface as deriving from another one.
pub(crate) trait DerivedFrom<T: Castable>: Castable {}
impl<T: Float + ToJSValConvertible> ToJSValConvertible for Finite<T> {
#[inline]
unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
@ -169,14 +156,7 @@ pub(crate) unsafe fn jsid_to_string(cx: *mut JSContext, id: HandleId) -> Option<
None
}
/// Returns whether `obj` is a DOM object implemented as a proxy.
pub(crate) fn is_dom_proxy(obj: *mut JSObject) -> bool {
use js::glue::IsProxyHandlerFamily;
unsafe {
let clasp = get_object_class(obj);
((*clasp).flags & js::JSCLASS_IS_PROXY) != 0 && IsProxyHandlerFamily(obj)
}
}
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.
@ -200,27 +180,6 @@ pub(crate) unsafe fn private_from_object(obj: *mut JSObject) -> *const libc::c_v
}
}
/// Get the `DOMClass` from `obj`, or `Err(())` if `obj` is not a DOM object.
pub(crate) unsafe fn get_dom_class(obj: *mut JSObject) -> Result<&'static DOMClass, ()> {
use js::glue::GetProxyHandlerExtra;
use crate::dom::bindings::utils::DOMJSClass;
let clasp = get_object_class(obj);
if is_dom_class(&*clasp) {
trace!("plain old dom object");
let domjsclass: *const DOMJSClass = clasp as *const DOMJSClass;
return Ok(&(*domjsclass).dom_class);
}
if is_dom_proxy(obj) {
trace!("proxy dom object");
let dom_class: *const DOMClass = GetProxyHandlerExtra(obj) as *const DOMClass;
return Ok(&*dom_class);
}
trace!("not a dom object");
Err(())
}
pub(crate) enum PrototypeCheck {
Derive(fn(&'static DOMClass) -> bool),
Depth { depth: usize, proto_id: u16 },

View file

@ -2,56 +2,8 @@
* 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/. */
//! The `Castable` trait.
use std::mem;
pub(crate) use crate::dom::bindings::codegen::InheritTypes::*;
use crate::dom::bindings::conversions::{get_dom_class, DerivedFrom, IDLInterface};
use crate::dom::bindings::reflector::DomObject;
use crate::script_runtime::runtime_is_alive;
/// A trait to hold the cast functions of IDL interfaces that either derive
/// or are derived from other interfaces.
pub(crate) trait Castable: IDLInterface + DomObject + Sized {
/// Check whether a DOM object implements one of its deriving interfaces.
fn is<T>(&self) -> bool
where
T: DerivedFrom<Self>,
{
// This is a weird place for this check to live, but it should catch any
// attempts to interact with DOM objects from Drop implementations that run
// as a result of the runtime shutting down and finalizing all remaining objects.
debug_assert!(
runtime_is_alive(),
"Attempting to interact with DOM objects after JS runtime has shut down."
);
let class = unsafe { get_dom_class(self.reflector().get_jsobject().get()).unwrap() };
T::derives(class)
}
/// Cast a DOM object upwards to one of the interfaces it derives from.
fn upcast<T>(&self) -> &T
where
T: Castable,
Self: DerivedFrom<T>,
{
unsafe { mem::transmute::<&Self, &T>(self) }
}
/// Cast a DOM object downwards to one of the interfaces it might implement.
fn downcast<T>(&self) -> Option<&T>
where
T: DerivedFrom<Self>,
{
if self.is::<T>() {
Some(unsafe { mem::transmute::<&Self, &T>(self) })
} else {
None
}
}
}
pub(crate) use script_bindings::codegen::InheritTypes::*;
pub(crate) use script_bindings::inheritance::Castable;
#[allow(missing_docs)]
pub(crate) trait HasParent {

View file

@ -184,15 +184,17 @@ pub(crate) mod codegen {
}
pub(crate) mod InterfaceObjectMap {
include!(concat!(env!("BINDINGS_OUT_DIR"), "/InterfaceObjectMap.rs"));
pub(crate) use script_bindings::codegen::Globals::Globals;
}
#[allow(dead_code, unused_imports, clippy::enum_variant_names)]
pub(crate) mod InheritTypes {
include!(concat!(env!("BINDINGS_OUT_DIR"), "/InheritTypes.rs"));
}
#[allow(clippy::upper_case_acronyms)]
pub(crate) mod PrototypeList {
include!(concat!(env!("BINDINGS_OUT_DIR"), "/PrototypeList.rs"));
pub(crate) use script_bindings::codegen::InheritTypes;
#[allow(dead_code)]
pub(crate) mod ConcreteInheritTypes {
include!(concat!(
env!("BINDINGS_OUT_DIR"),
"/ConcreteInheritTypes.rs"
));
}
pub(crate) use script_bindings::codegen::PrototypeList;
pub(crate) mod RegisterBindings {
include!(concat!(env!("BINDINGS_OUT_DIR"), "/RegisterBindings.rs"));
}

View file

@ -5,7 +5,7 @@
//! Various utilities to glue JavaScript and the DOM implementation together.
use std::ffi::CString;
use std::os::raw::{c_char, c_void};
use std::os::raw::c_char;
use std::ptr::NonNull;
use std::sync::OnceLock;
use std::{ptr, slice, str};
@ -35,15 +35,13 @@ use js::rust::{
MutableHandleValue, ToString,
};
use js::JS_CALLEE;
use malloc_size_of::MallocSizeOfOps;
use crate::dom::bindings::codegen::PrototypeList::{MAX_PROTO_CHAIN_LENGTH, PROTO_OR_IFACE_LENGTH};
use crate::dom::bindings::codegen::{InterfaceObjectMap, PrototypeList};
use crate::dom::bindings::codegen::InterfaceObjectMap;
use crate::dom::bindings::codegen::PrototypeList::PROTO_OR_IFACE_LENGTH;
use crate::dom::bindings::conversions::{
jsstring_to_str, private_from_proto_check, PrototypeCheck,
};
use crate::dom::bindings::error::throw_invalid_this;
use crate::dom::bindings::inheritance::TopTypeId;
use crate::dom::bindings::str::DOMString;
use crate::dom::bindings::trace::trace_object;
use crate::dom::windowproxy::WindowProxyHandler;
@ -111,42 +109,7 @@ pub(crate) const DOM_PROTOTYPE_SLOT: u32 = js::JSCLASS_GLOBAL_SLOT_COUNT;
// changes.
pub(crate) const JSCLASS_DOM_GLOBAL: u32 = js::JSCLASS_USERBIT1;
/// The struct that holds inheritance information for DOM object reflectors.
#[derive(Clone, Copy)]
pub(crate) struct DOMClass {
/// A list of interfaces that this object implements, in order of decreasing
/// derivedness.
pub(crate) interface_chain: [PrototypeList::ID; MAX_PROTO_CHAIN_LENGTH],
/// The last valid index of `interface_chain`.
pub(crate) depth: u8,
/// The type ID of that interface.
pub(crate) type_id: TopTypeId,
/// The MallocSizeOf function wrapper for that interface.
pub(crate) malloc_size_of: unsafe fn(ops: &mut MallocSizeOfOps, *const c_void) -> usize,
/// The `Globals` flag for this global interface, if any.
pub(crate) global: InterfaceObjectMap::Globals,
}
unsafe impl Sync for DOMClass {}
/// The JSClass used for DOM object reflectors.
#[derive(Copy)]
#[repr(C)]
pub(crate) struct DOMJSClass {
/// The actual JSClass.
pub(crate) base: js::jsapi::JSClass,
/// Associated data for DOM object reflectors.
pub(crate) dom_class: DOMClass,
}
impl Clone for DOMJSClass {
fn clone(&self) -> DOMJSClass {
*self
}
}
unsafe impl Sync for DOMJSClass {}
pub(crate) use script_bindings::utils::{DOMClass, DOMJSClass};
/// Returns a JSVal representing the frozen JavaScript array
pub(crate) fn to_frozen_array<T: ToJSValConvertible>(

View file

@ -3802,21 +3802,25 @@ impl UniqueId {
}
}
impl From<NodeTypeId> for LayoutNodeType {
pub(crate) struct NodeTypeIdWrapper(pub(crate) NodeTypeId);
impl From<NodeTypeIdWrapper> for LayoutNodeType {
#[inline(always)]
fn from(node_type: NodeTypeId) -> LayoutNodeType {
match node_type {
NodeTypeId::Element(e) => LayoutNodeType::Element(e.into()),
fn from(node_type: NodeTypeIdWrapper) -> LayoutNodeType {
match node_type.0 {
NodeTypeId::Element(e) => LayoutNodeType::Element(ElementTypeIdWrapper(e).into()),
NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => LayoutNodeType::Text,
x => unreachable!("Layout should not traverse nodes of type {:?}", x),
}
}
}
impl From<ElementTypeId> for LayoutElementType {
struct ElementTypeIdWrapper(ElementTypeId);
impl From<ElementTypeIdWrapper> for LayoutElementType {
#[inline(always)]
fn from(element_type: ElementTypeId) -> LayoutElementType {
match element_type {
fn from(element_type: ElementTypeIdWrapper) -> LayoutElementType {
match element_type.0 {
ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBodyElement) => {
LayoutElementType::HTMLBodyElement
},