mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
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:
parent
eaaad757e8
commit
c0cef69108
16 changed files with 291 additions and 207 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -6321,6 +6321,7 @@ dependencies = [
|
|||
name = "script_bindings"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"bitflags 2.8.0",
|
||||
"cssparser",
|
||||
"html5ever",
|
||||
"jstraceable_derive",
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
|
|
|
@ -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>(
|
||||
|
|
|
@ -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
|
||||
},
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
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");
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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)
|
||||
|
@ -8368,19 +8371,57 @@ class GlobalGenRoots():
|
|||
if downcast:
|
||||
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
|
||||
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
53
components/script_bindings/inheritance.rs
Normal file
53
components/script_bindings/inheritance.rs
Normal file
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
|
|
17
components/script_bindings/script_runtime.rs
Normal file
17
components/script_bindings/script_runtime.rs
Normal file
|
@ -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));
|
||||
}
|
48
components/script_bindings/utils.rs
Normal file
48
components/script_bindings/utils.rs
Normal file
|
@ -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 {}
|
Loading…
Add table
Add a link
Reference in a new issue