aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--components/script/dom/bindings/conversions.rs45
-rw-r--r--components/script/dom/bindings/inheritance.rs52
-rw-r--r--components/script/dom/bindings/mod.rs16
-rw-r--r--components/script/dom/bindings/utils.rs45
-rw-r--r--components/script/dom/node.rs18
-rw-r--r--components/script/layout_dom/node.rs4
-rw-r--r--components/script/script_runtime.rs17
-rw-r--r--components/script_bindings/Cargo.toml1
-rw-r--r--components/script_bindings/codegen/CodegenRust.py109
-rw-r--r--components/script_bindings/codegen/run.py2
-rw-r--r--components/script_bindings/conversions.rs52
-rw-r--r--components/script_bindings/inheritance.rs53
-rw-r--r--components/script_bindings/lib.rs18
-rw-r--r--components/script_bindings/script_runtime.rs17
-rw-r--r--components/script_bindings/utils.rs48
16 files changed, 291 insertions, 207 deletions
diff --git a/Cargo.lock b/Cargo.lock
index e325ff78acf..f60b7c585c2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -6321,6 +6321,7 @@ dependencies = [
name = "script_bindings"
version = "0.0.1"
dependencies = [
+ "bitflags 2.8.0",
"cssparser",
"html5ever",
"jstraceable_derive",
diff --git a/components/script/dom/bindings/conversions.rs b/components/script/dom/bindings/conversions.rs
index 35a2dd1fc47..a0ce1eb70fe 100644
--- a/components/script/dom/bindings/conversions.rs
+++ b/components/script/dom/bindings/conversions.rs
@@ -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 },
diff --git a/components/script/dom/bindings/inheritance.rs b/components/script/dom/bindings/inheritance.rs
index f226dbb617b..ef60378d55b 100644
--- a/components/script/dom/bindings/inheritance.rs
+++ b/components/script/dom/bindings/inheritance.rs
@@ -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 {
diff --git a/components/script/dom/bindings/mod.rs b/components/script/dom/bindings/mod.rs
index 65629fda46b..ee934ca2af1 100644
--- a/components/script/dom/bindings/mod.rs
+++ b/components/script/dom/bindings/mod.rs
@@ -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"));
}
diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs
index da583b2881b..7567ee00f78 100644
--- a/components/script/dom/bindings/utils.rs
+++ b/components/script/dom/bindings/utils.rs
@@ -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>(
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index 709c2d39936..c23eaa6f680 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -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
},
diff --git a/components/script/layout_dom/node.rs b/components/script/layout_dom/node.rs
index 1d9d5310a3b..841a396fc5f 100644
--- a/components/script/layout_dom/node.rs
+++ b/components/script/layout_dom/node.rs
@@ -36,7 +36,7 @@ use crate::dom::bindings::inheritance::{CharacterDataTypeId, NodeTypeId, TextTyp
use crate::dom::bindings::root::LayoutDom;
use crate::dom::characterdata::LayoutCharacterDataHelpers;
use crate::dom::element::{Element, LayoutElementHelpers};
-use crate::dom::node::{LayoutNodeHelpers, Node, NodeFlags};
+use crate::dom::node::{LayoutNodeHelpers, Node, NodeFlags, NodeTypeIdWrapper};
use crate::dom::text::Text;
/// A wrapper around a `LayoutDom<Node>` which provides a safe interface that
@@ -181,7 +181,7 @@ impl<'dom> LayoutNode<'dom> for ServoLayoutNode<'dom> {
}
fn type_id(&self) -> LayoutNodeType {
- self.script_type_id().into()
+ NodeTypeIdWrapper(self.script_type_id()).into()
}
unsafe fn initialize_style_and_layout_data<RequestedLayoutDataType: LayoutDataTrait>(&self) {
diff --git a/components/script/script_runtime.rs b/components/script/script_runtime.rs
index 8ecf70a9f3b..28e7869bd4f 100644
--- a/components/script/script_runtime.rs
+++ b/components/script/script_runtime.rs
@@ -53,6 +53,7 @@ use malloc_size_of_derive::MallocSizeOf;
use profile_traits::mem::{Report, ReportKind};
use profile_traits::path;
use profile_traits::time::ProfilerCategory;
+use script_bindings::script_runtime::{mark_runtime_dead, runtime_is_alive};
use servo_config::{opts, pref};
use style::thread_state::{self, ThreadState};
@@ -768,10 +769,8 @@ impl Drop for Runtime {
unsafe {
DeleteJobQueue(self.job_queue);
}
- THREAD_ACTIVE.with(|t| {
- LiveDOMReferences::destruct();
- t.set(false);
- });
+ LiveDOMReferences::destruct();
+ mark_runtime_dead();
}
}
@@ -892,17 +891,9 @@ unsafe extern "C" fn debug_gc_callback(
}
}
-thread_local!(
- static THREAD_ACTIVE: Cell<bool> = const { Cell::new(true) };
-);
-
-pub(crate) fn runtime_is_alive() -> bool {
- THREAD_ACTIVE.with(|t| t.get())
-}
-
#[allow(unsafe_code)]
unsafe extern "C" fn trace_rust_roots(tr: *mut JSTracer, _data: *mut os::raw::c_void) {
- if !THREAD_ACTIVE.with(|t| t.get()) {
+ if !runtime_is_alive() {
return;
}
trace!("starting custom root handler");
diff --git a/components/script_bindings/Cargo.toml b/components/script_bindings/Cargo.toml
index 88a68587b99..4da26f81160 100644
--- a/components/script_bindings/Cargo.toml
+++ b/components/script_bindings/Cargo.toml
@@ -21,6 +21,7 @@ phf_shared = "0.11"
serde_json = { workspace = true }
[dependencies]
+bitflags = { workspace = true }
cssparser = { workspace = true }
html5ever = { workspace = true }
js = { workspace = true }
diff --git a/components/script_bindings/codegen/CodegenRust.py b/components/script_bindings/codegen/CodegenRust.py
index de4adafe886..66a6b84848a 100644
--- a/components/script_bindings/codegen/CodegenRust.py
+++ b/components/script_bindings/codegen/CodegenRust.py
@@ -6982,7 +6982,7 @@ class CGNonNamespacedEnum(CGThing):
# Build the enum body.
joinedEntries = ',\n'.join(entries)
- enumstr = f"{comment}pub(crate) enum {enumName} {{\n{joinedEntries}\n}}\n"
+ enumstr = f"{comment}pub enum {enumName} {{\n{joinedEntries}\n}}\n"
if repr:
enumstr = f"#[repr({repr})]\n{enumstr}"
if deriving:
@@ -8211,14 +8211,7 @@ class GlobalGenRoots():
"""
@staticmethod
- def InterfaceObjectMap(config):
- mods = [
- "crate::dom::bindings::codegen",
- "crate::script_runtime::JSContext",
- "js::rust::HandleObject",
- ]
- imports = CGList([CGGeneric(f"use {mod};") for mod in mods], "\n")
-
+ def Globals(config):
global_descriptors = config.getDescriptors(isGlobal=True)
flags = [("EMPTY", 0)]
flags.extend(
@@ -8228,14 +8221,28 @@ class GlobalGenRoots():
global_flags = CGWrapper(CGIndenter(CGList([
CGGeneric(f"const {args[0]} = {args[1]};")
for args in flags
- ], "\n")), pre="#[derive(Clone, Copy)]\npub(crate) struct Globals: u8 {\n", post="\n}")
+ ], "\n")), pre="#[derive(Clone, Copy)]\npub struct Globals: u8 {\n", post="\n}")
globals_ = CGWrapper(CGIndenter(global_flags), pre="bitflags::bitflags! {\n", post="\n}")
+ return CGList([
+ CGGeneric(AUTOGENERATED_WARNING_COMMENT),
+ globals_,
+ ])
+
+ @staticmethod
+ def InterfaceObjectMap(config):
+ mods = [
+ "crate::dom::bindings::codegen",
+ "crate::script_runtime::JSContext",
+ "js::rust::HandleObject",
+ ]
+ imports = CGList([CGGeneric(f"use {mod};") for mod in mods], "\n")
+
phf = CGGeneric("include!(concat!(env!(\"BINDINGS_OUT_DIR\"), \"/InterfaceObjectMapPhf.rs\"));")
return CGList([
CGGeneric(AUTOGENERATED_WARNING_COMMENT),
- CGList([imports, globals_, phf], "\n\n")
+ CGList([imports, phf], "\n\n")
])
@staticmethod
@@ -8270,8 +8277,8 @@ class GlobalGenRoots():
return CGList([
CGGeneric(AUTOGENERATED_WARNING_COMMENT),
- CGGeneric(f"pub(crate) const PROTO_OR_IFACE_LENGTH: usize = {len(protos) + len(constructors)};\n"),
- CGGeneric(f"pub(crate) const MAX_PROTO_CHAIN_LENGTH: usize = {config.maxProtoChainLength};\n\n"),
+ CGGeneric(f"pub const PROTO_OR_IFACE_LENGTH: usize = {len(protos) + len(constructors)};\n"),
+ CGGeneric(f"pub const MAX_PROTO_CHAIN_LENGTH: usize = {config.maxProtoChainLength};\n\n"),
CGGeneric("#[allow(clippy::enum_variant_names, dead_code)]"),
CGNonNamespacedEnum('ID', protos, 0, deriving="PartialEq, Copy, Clone", repr="u16"),
CGNonNamespacedEnum('Constructor', constructors, len(protos),
@@ -8281,7 +8288,7 @@ class GlobalGenRoots():
indentLevel=4),
pre=f"static INTERFACES: [&str; {len(protos)}] = [\n",
post="\n];\n\n"),
- CGGeneric("pub(crate) fn proto_id_to_name(proto_id: u16) -> &'static str {\n"
+ CGGeneric("pub fn proto_id_to_name(proto_id: u16) -> &'static str {\n"
" debug_assert!(proto_id < ID::Last as u16);\n"
" INTERFACES[proto_id as usize]\n"
"}\n\n"),
@@ -8329,17 +8336,13 @@ class GlobalGenRoots():
return curr
@staticmethod
- def InheritTypes(config):
-
+ def ConcreteInheritTypes(config):
descriptors = config.getDescriptors(register=True, isCallback=False)
imports = [CGGeneric("use crate::dom::types::*;\n"),
+ CGGeneric("use script_bindings::codegen::InheritTypes::*;\n"),
CGGeneric("use crate::dom::bindings::conversions::{DerivedFrom, get_dom_class};\n"),
CGGeneric("use crate::dom::bindings::inheritance::Castable;\n"),
- CGGeneric("use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom};\n"),
- CGGeneric("use crate::dom::bindings::trace::JSTraceable;\n"),
- CGGeneric("use crate::dom::bindings::reflector::DomObject;\n"),
- CGGeneric("use js::jsapi::JSTracer;\n\n"),
- CGGeneric("use std::mem;\n\n")]
+ CGGeneric("use crate::dom::bindings::reflector::DomObject;\n\n")]
allprotos = []
topTypes = []
hierarchy = defaultdict(list)
@@ -8369,18 +8372,56 @@ class GlobalGenRoots():
hierarchy[descriptor.interface.parent.identifier.name].append(name)
typeIdCode = []
+
+ for base, derived in hierarchy.items():
+ if base in topTypes:
+ typeIdCode.append(CGGeneric(f"""
+impl {base} {{
+ pub(crate) fn type_id(&self) -> &'static {base}TypeId {{
+ unsafe {{
+ &get_dom_class(self.reflector().get_jsobject().get())
+ .unwrap()
+ .type_id
+ .{base.lower()}
+ }}
+ }}
+}}
+
+"""))
+
+ curr = CGList(imports + typeIdCode + allprotos)
+ curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
+ return curr
+
+ @staticmethod
+ def InheritTypes(config):
+ descriptors = config.getDescriptors(register=True, isCallback=False)
+ topTypes = []
+ hierarchy = defaultdict(list)
+ for descriptor in descriptors:
+ name = descriptor.name
+ upcast = descriptor.hasDescendants()
+ downcast = len(descriptor.prototypeChain) != 1
+
+ if upcast and not downcast:
+ topTypes.append(name)
+
+ if downcast:
+ hierarchy[descriptor.interface.parent.identifier.name].append(name)
+
+ typeIdCode = []
topTypeVariants = [
- ("ID used by abstract interfaces.", "pub(crate) abstract_: ()"),
- ("ID used by interfaces that are not castable.", "pub(crate) alone: ()"),
+ ("ID used by abstract interfaces.", "pub abstract_: ()"),
+ ("ID used by interfaces that are not castable.", "pub alone: ()"),
]
topTypeVariants += [
(f"ID used by interfaces that derive from {typeName}.",
- f"pub(crate) {typeName.lower()}: {typeName}TypeId")
+ f"pub {typeName.lower()}: {typeName}TypeId")
for typeName in topTypes
]
topTypeVariantsAsStrings = [CGGeneric(f"/// {variant[0]}\n{variant[1]},") for variant in topTypeVariants]
typeIdCode.append(CGWrapper(CGIndenter(CGList(topTypeVariantsAsStrings, "\n"), 4),
- pre="#[derive(Copy)]\npub(crate) union TopTypeId {\n",
+ pre="#[derive(Copy)]\npub union TopTypeId {\n",
post="\n}\n\n"))
typeIdCode.append(CGGeneric("""\
@@ -8403,24 +8444,10 @@ impl Clone for TopTypeId {
variants += [CGGeneric(type_id_variant(derivedName)) for derivedName in derived]
derives = "Clone, Copy, Debug, PartialEq"
typeIdCode.append(CGWrapper(CGIndenter(CGList(variants, ",\n"), 4),
- pre=f"#[derive({derives})]\npub(crate) enum {base}TypeId {{\n",
+ pre=f"#[derive({derives})]\npub enum {base}TypeId {{\n",
post="\n}\n\n"))
- if base in topTypes:
- typeIdCode.append(CGGeneric(f"""
-impl {base} {{
- pub(crate) fn type_id(&self) -> &'static {base}TypeId {{
- unsafe {{
- &get_dom_class(self.reflector().get_jsobject().get())
- .unwrap()
- .type_id
- .{base.lower()}
- }}
- }}
-}}
-
-"""))
- curr = CGList(imports + typeIdCode + allprotos)
+ curr = CGList(typeIdCode)
curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
return curr
diff --git a/components/script_bindings/codegen/run.py b/components/script_bindings/codegen/run.py
index dd812cd2d1e..3ef7f296715 100644
--- a/components/script_bindings/codegen/run.py
+++ b/components/script_bindings/codegen/run.py
@@ -52,10 +52,12 @@ def main():
for name, filename in [
("PrototypeList", "PrototypeList.rs"),
("RegisterBindings", "RegisterBindings.rs"),
+ ("Globals", "Globals.rs"),
("InterfaceObjectMap", "InterfaceObjectMap.rs"),
("InterfaceObjectMapData", "InterfaceObjectMapData.json"),
("InterfaceTypes", "InterfaceTypes.rs"),
("InheritTypes", "InheritTypes.rs"),
+ ("ConcreteInheritTypes", "ConcreteInheritTypes.rs"),
("Bindings", "Bindings/mod.rs"),
("UnionTypes", "UnionTypes.rs"),
("DomTypes", "DomTypes.rs"),
diff --git a/components/script_bindings/conversions.rs b/components/script_bindings/conversions.rs
index c9f67605c5a..ec05d0c33f8 100644
--- a/components/script_bindings/conversions.rs
+++ b/components/script_bindings/conversions.rs
@@ -8,16 +8,30 @@ use js::conversions::{
latin1_to_string, ConversionResult, FromJSValConvertible, ToJSValConvertible,
};
use js::error::throw_type_error;
+use js::glue::{GetProxyHandlerExtra, IsProxyHandlerFamily};
use js::jsapi::{
- JSContext, JSString, JS_DeprecatedStringHasLatin1Chars, JS_GetLatin1StringCharsAndLength,
- JS_GetTwoByteStringCharsAndLength, JS_NewStringCopyN,
+ JSContext, JSObject, JSString, JS_DeprecatedStringHasLatin1Chars,
+ JS_GetLatin1StringCharsAndLength, JS_GetTwoByteStringCharsAndLength, JS_NewStringCopyN,
};
use js::jsval::{ObjectValue, StringValue};
-use js::rust::{maybe_wrap_value, HandleValue, MutableHandleValue, ToString};
+use js::rust::{
+ get_object_class, is_dom_class, maybe_wrap_value, HandleValue, MutableHandleValue, ToString,
+};
use servo_config::opts;
+use crate::inheritance::Castable;
use crate::reflector::Reflector;
use crate::str::{ByteString, DOMString, USVString};
+use crate::utils::{DOMClass, DOMJSClass};
+
+/// A trait to check whether a given `JSObject` implements an IDL interface.
+pub 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 trait DerivedFrom<T: Castable>: Castable {}
// http://heycam.github.io/webidl/#es-USVString
impl ToJSValConvertible for USVString {
@@ -201,3 +215,35 @@ impl ToJSValConvertible for Reflector {
maybe_wrap_value(cx, rval);
}
}
+
+/// Get the `DOMClass` from `obj`, or `Err(())` if `obj` is not a DOM object.
+///
+/// # Safety
+/// obj must point to a valid, non-null JS object.
+#[allow(clippy::result_unit_err)]
+pub unsafe fn get_dom_class(obj: *mut JSObject) -> Result<&'static DOMClass, ()> {
+ 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(())
+}
+
+/// Returns whether `obj` is a DOM object implemented as a proxy.
+///
+/// # Safety
+/// obj must point to a valid, non-null JS object.
+pub unsafe fn is_dom_proxy(obj: *mut JSObject) -> bool {
+ unsafe {
+ let clasp = get_object_class(obj);
+ ((*clasp).flags & js::JSCLASS_IS_PROXY) != 0 && IsProxyHandlerFamily(obj)
+ }
+}
diff --git a/components/script_bindings/inheritance.rs b/components/script_bindings/inheritance.rs
new file mode 100644
index 00000000000..d0ede1a42aa
--- /dev/null
+++ b/components/script_bindings/inheritance.rs
@@ -0,0 +1,53 @@
+/* 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/. */
+
+//! The `Castable` trait.
+
+use std::mem;
+
+use crate::conversions::{get_dom_class, DerivedFrom, IDLInterface};
+use crate::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 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
+ }
+ }
+}
diff --git a/components/script_bindings/lib.rs b/components/script_bindings/lib.rs
index 551c0118950..1fb5a5f48b0 100644
--- a/components/script_bindings/lib.rs
+++ b/components/script_bindings/lib.rs
@@ -19,9 +19,27 @@ extern crate malloc_size_of_derive;
pub mod callback;
pub mod conversions;
+pub mod inheritance;
pub mod reflector;
+pub mod script_runtime;
pub mod str;
mod trace;
+pub mod utils;
+
+#[allow(non_snake_case)]
+pub mod codegen {
+ pub mod Globals {
+ include!(concat!(env!("OUT_DIR"), "/Globals.rs"));
+ }
+ #[allow(dead_code, unused_imports, clippy::enum_variant_names)]
+ pub mod InheritTypes {
+ include!(concat!(env!("OUT_DIR"), "/InheritTypes.rs"));
+ }
+ #[allow(clippy::upper_case_acronyms)]
+ pub mod PrototypeList {
+ include!(concat!(env!("OUT_DIR"), "/PrototypeList.rs"));
+ }
+}
// These trait exports are public, because they are used in the DOM bindings.
// Since they are used in derive macros,
diff --git a/components/script_bindings/script_runtime.rs b/components/script_bindings/script_runtime.rs
new file mode 100644
index 00000000000..e5cbde74c9e
--- /dev/null
+++ b/components/script_bindings/script_runtime.rs
@@ -0,0 +1,17 @@
+/* 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::Cell;
+
+thread_local!(
+ static THREAD_ACTIVE: Cell<bool> = const { Cell::new(true) };
+);
+
+pub fn runtime_is_alive() -> bool {
+ THREAD_ACTIVE.with(|t| t.get())
+}
+
+pub fn mark_runtime_dead() {
+ THREAD_ACTIVE.with(|t| t.set(false));
+}
diff --git a/components/script_bindings/utils.rs b/components/script_bindings/utils.rs
new file mode 100644
index 00000000000..fd307fd5ab3
--- /dev/null
+++ b/components/script_bindings/utils.rs
@@ -0,0 +1,48 @@
+/* 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::os::raw::c_void;
+
+use malloc_size_of::MallocSizeOfOps;
+
+use crate::codegen::Globals::Globals;
+use crate::codegen::InheritTypes::TopTypeId;
+use crate::codegen::PrototypeList::{self, MAX_PROTO_CHAIN_LENGTH};
+
+/// The struct that holds inheritance information for DOM object reflectors.
+#[derive(Clone, Copy)]
+pub struct DOMClass {
+ /// A list of interfaces that this object implements, in order of decreasing
+ /// derivedness.
+ pub interface_chain: [PrototypeList::ID; MAX_PROTO_CHAIN_LENGTH],
+
+ /// The last valid index of `interface_chain`.
+ pub depth: u8,
+
+ /// The type ID of that interface.
+ pub type_id: TopTypeId,
+
+ /// The MallocSizeOf function wrapper for that interface.
+ pub malloc_size_of: unsafe fn(ops: &mut MallocSizeOfOps, *const c_void) -> usize,
+
+ /// The `Globals` flag for this global interface, if any.
+ pub global: Globals,
+}
+unsafe impl Sync for DOMClass {}
+
+/// The JSClass used for DOM object reflectors.
+#[derive(Copy)]
+#[repr(C)]
+pub struct DOMJSClass {
+ /// The actual JSClass.
+ pub base: js::jsapi::JSClass,
+ /// Associated data for DOM object reflectors.
+ pub dom_class: DOMClass,
+}
+impl Clone for DOMJSClass {
+ fn clone(&self) -> DOMJSClass {
+ *self
+ }
+}
+unsafe impl Sync for DOMJSClass {}