diff options
Diffstat (limited to 'components/script/dom/bindings')
-rw-r--r-- | components/script/dom/bindings/callback.rs | 295 | ||||
-rw-r--r-- | components/script/dom/bindings/constructor.rs | 51 | ||||
-rw-r--r-- | components/script/dom/bindings/conversions.rs | 97 | ||||
-rw-r--r-- | components/script/dom/bindings/guard.rs | 96 | ||||
-rw-r--r-- | components/script/dom/bindings/import.rs | 159 | ||||
-rw-r--r-- | components/script/dom/bindings/interface.rs | 696 | ||||
-rw-r--r-- | components/script/dom/bindings/iterable.rs | 180 | ||||
-rw-r--r-- | components/script/dom/bindings/mod.rs | 33 | ||||
-rw-r--r-- | components/script/dom/bindings/namespace.rs | 62 | ||||
-rw-r--r-- | components/script/dom/bindings/principals.rs | 123 | ||||
-rw-r--r-- | components/script/dom/bindings/proxyhandler.rs | 292 | ||||
-rw-r--r-- | components/script/dom/bindings/reflector.rs | 69 | ||||
-rw-r--r-- | components/script/dom/bindings/settings_stack.rs | 143 | ||||
-rw-r--r-- | components/script/dom/bindings/trace.rs | 70 | ||||
-rw-r--r-- | components/script/dom/bindings/utils.rs | 111 | ||||
-rw-r--r-- | components/script/dom/bindings/weakref.rs | 2 |
16 files changed, 57 insertions, 2422 deletions
diff --git a/components/script/dom/bindings/callback.rs b/components/script/dom/bindings/callback.rs deleted file mode 100644 index 6a54255822f..00000000000 --- a/components/script/dom/bindings/callback.rs +++ /dev/null @@ -1,295 +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/. */ - -//! Base classes to work with IDL callbacks. - -use std::default::Default; -use std::ffi::CString; -use std::mem::drop; -use std::rc::Rc; - -use js::jsapi::{ - AddRawValueRoot, EnterRealm, Heap, IsCallable, JSObject, LeaveRealm, Realm, RemoveRawValueRoot, -}; -use js::jsval::{JSVal, ObjectValue, UndefinedValue}; -use js::rust::wrappers::{JS_GetProperty, JS_WrapObject}; -use js::rust::{MutableHandleValue, Runtime}; -use script_bindings::interfaces::DocumentHelpers; -use script_bindings::utils::AsCCharPtrPtr; - -use crate::DomTypes; -use crate::dom::bindings::codegen::Bindings::WindowBinding::Window_Binding::WindowMethods; -use crate::dom::bindings::error::{Error, Fallible}; -use crate::dom::bindings::inheritance::Castable; -use crate::dom::bindings::root::{Dom, DomRoot}; -use crate::dom::bindings::settings_stack::{GenericAutoEntryScript, GenericAutoIncumbentScript}; -use crate::dom::bindings::utils::DomHelpers; -use crate::dom::globalscope::GlobalScopeHelpers; -use crate::realms::{InRealm, enter_realm}; -use crate::script_runtime::{CanGc, JSContext}; - -/// The exception handling used for a call. -#[derive(Clone, Copy, PartialEq)] -pub(crate) enum ExceptionHandling { - /// Report any exception and don't throw it to the caller code. - Report, - /// Throw any exception to the caller code. - Rethrow, -} - -/// A common base class for representing IDL callback function and -/// callback interface types. -#[derive(JSTraceable)] -#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)] -pub(crate) struct CallbackObject<D: DomTypes> { - /// The underlying `JSObject`. - callback: Heap<*mut JSObject>, - permanent_js_root: Heap<JSVal>, - - /// The ["callback context"], that is, the global to use as incumbent - /// global when calling the callback. - /// - /// Looking at the WebIDL standard, it appears as though there would always - /// be a value here, but [sometimes] callback functions are created by - /// hand-waving without defining the value of the callback context, and - /// without any JavaScript code on the stack to grab an incumbent global - /// from. - /// - /// ["callback context"]: https://heycam.github.io/webidl/#dfn-callback-context - /// [sometimes]: https://github.com/whatwg/html/issues/2248 - incumbent: Option<Dom<D::GlobalScope>>, -} - -impl<D: DomTypes> CallbackObject<D> { - #[cfg_attr(crown, allow(crown::unrooted_must_root))] - // These are used by the bindings and do not need `default()` functions. - #[allow(clippy::new_without_default)] - fn new() -> Self { - Self { - callback: Heap::default(), - permanent_js_root: Heap::default(), - incumbent: D::GlobalScope::incumbent().map(|i| Dom::from_ref(&*i)), - } - } - - pub(crate) fn get(&self) -> *mut JSObject { - self.callback.get() - } - - #[allow(unsafe_code)] - unsafe fn init(&mut self, cx: JSContext, callback: *mut JSObject) { - self.callback.set(callback); - self.permanent_js_root.set(ObjectValue(callback)); - assert!(AddRawValueRoot( - *cx, - self.permanent_js_root.get_unsafe(), - b"CallbackObject::root\n".as_c_char_ptr() - )); - } -} - -impl<D: DomTypes> Drop for CallbackObject<D> { - #[allow(unsafe_code)] - fn drop(&mut self) { - unsafe { - if let Some(cx) = Runtime::get() { - RemoveRawValueRoot(cx.as_ptr(), self.permanent_js_root.get_unsafe()); - } - } - } -} - -impl<D: DomTypes> PartialEq for CallbackObject<D> { - fn eq(&self, other: &CallbackObject<D>) -> bool { - self.callback.get() == other.callback.get() - } -} - -/// A trait to be implemented by concrete IDL callback function and -/// callback interface types. -pub(crate) trait CallbackContainer<D: DomTypes> { - /// Create a new CallbackContainer object for the given `JSObject`. - unsafe fn new(cx: JSContext, callback: *mut JSObject) -> Rc<Self>; - /// Returns the underlying `CallbackObject`. - fn callback_holder(&self) -> &CallbackObject<D>; - /// Returns the underlying `JSObject`. - fn callback(&self) -> *mut JSObject { - self.callback_holder().get() - } - /// Returns the ["callback context"], that is, the global to use as - /// incumbent global when calling the callback. - /// - /// ["callback context"]: https://heycam.github.io/webidl/#dfn-callback-context - fn incumbent(&self) -> Option<&D::GlobalScope> { - self.callback_holder().incumbent.as_deref() - } -} - -/// A common base class for representing IDL callback function types. -#[derive(JSTraceable, PartialEq)] -#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)] -pub(crate) struct CallbackFunction<D: DomTypes> { - object: CallbackObject<D>, -} - -impl<D: DomTypes> CallbackFunction<D> { - /// Create a new `CallbackFunction` for this object. - #[cfg_attr(crown, allow(crown::unrooted_must_root))] - // These are used by the bindings and do not need `default()` functions. - #[allow(clippy::new_without_default)] - pub(crate) fn new() -> Self { - Self { - object: CallbackObject::new(), - } - } - - /// Returns the underlying `CallbackObject`. - pub(crate) fn callback_holder(&self) -> &CallbackObject<D> { - &self.object - } - - /// Initialize the callback function with a value. - /// Should be called once this object is done moving. - pub(crate) unsafe fn init(&mut self, cx: JSContext, callback: *mut JSObject) { - self.object.init(cx, callback); - } -} - -/// A common base class for representing IDL callback interface types. -#[derive(JSTraceable, PartialEq)] -#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)] -pub(crate) struct CallbackInterface<D: DomTypes> { - object: CallbackObject<D>, -} - -impl<D: DomTypes> CallbackInterface<D> { - /// Create a new CallbackInterface object for the given `JSObject`. - // These are used by the bindings and do not need `default()` functions. - #[allow(clippy::new_without_default)] - pub(crate) fn new() -> Self { - Self { - object: CallbackObject::new(), - } - } - - /// Returns the underlying `CallbackObject`. - pub(crate) fn callback_holder(&self) -> &CallbackObject<D> { - &self.object - } - - /// Initialize the callback function with a value. - /// Should be called once this object is done moving. - pub(crate) unsafe fn init(&mut self, cx: JSContext, callback: *mut JSObject) { - self.object.init(cx, callback); - } - - /// Returns the property with the given `name`, if it is a callable object, - /// or an error otherwise. - pub(crate) fn get_callable_property(&self, cx: JSContext, name: &str) -> Fallible<JSVal> { - rooted!(in(*cx) let mut callable = UndefinedValue()); - rooted!(in(*cx) let obj = self.callback_holder().get()); - unsafe { - let c_name = CString::new(name).unwrap(); - if !JS_GetProperty(*cx, obj.handle(), c_name.as_ptr(), callable.handle_mut()) { - return Err(Error::JSFailed); - } - - if !callable.is_object() || !IsCallable(callable.to_object()) { - return Err(Error::Type(format!( - "The value of the {} property is not callable", - name - ))); - } - } - Ok(callable.get()) - } -} - -pub(crate) use script_bindings::callback::ThisReflector; - -/// Wraps the reflector for `p` into the realm of `cx`. -pub(crate) fn wrap_call_this_value<T: ThisReflector>( - cx: JSContext, - p: &T, - mut rval: MutableHandleValue, -) -> bool { - rooted!(in(*cx) let mut obj = p.jsobject()); - assert!(!obj.is_null()); - - unsafe { - if !JS_WrapObject(*cx, obj.handle_mut()) { - return false; - } - } - - rval.set(ObjectValue(*obj)); - true -} - -/// A class that performs whatever setup we need to safely make a call while -/// this class is on the stack. After `new` returns, the call is safe to make. -pub(crate) struct CallSetup<D: DomTypes> { - /// The global for reporting exceptions. This is the global object of the - /// (possibly wrapped) callback object. - exception_global: DomRoot<D::GlobalScope>, - /// The `JSContext` used for the call. - cx: JSContext, - /// The realm we were in before the call. - old_realm: *mut Realm, - /// The exception handling used for the call. - handling: ExceptionHandling, - /// <https://heycam.github.io/webidl/#es-invoking-callback-functions> - /// steps 8 and 18.2. - entry_script: Option<GenericAutoEntryScript<D>>, - /// <https://heycam.github.io/webidl/#es-invoking-callback-functions> - /// steps 9 and 18.1. - incumbent_script: Option<GenericAutoIncumbentScript<D>>, -} - -impl<D: DomTypes> CallSetup<D> { - /// Performs the setup needed to make a call. - #[cfg_attr(crown, allow(crown::unrooted_must_root))] - pub(crate) fn new<T: CallbackContainer<D>>(callback: &T, handling: ExceptionHandling) -> Self { - let global = unsafe { D::GlobalScope::from_object(callback.callback()) }; - if let Some(window) = global.downcast::<D::Window>() { - window.Document().ensure_safe_to_run_script_or_layout(); - } - let cx = D::GlobalScope::get_cx(); - - let aes = GenericAutoEntryScript::<D>::new(&global); - let ais = callback.incumbent().map(GenericAutoIncumbentScript::new); - CallSetup { - exception_global: global, - cx, - old_realm: unsafe { EnterRealm(*cx, callback.callback()) }, - handling, - entry_script: Some(aes), - incumbent_script: ais, - } - } - - /// Returns the `JSContext` used for the call. - pub(crate) fn get_context(&self) -> JSContext { - self.cx - } -} - -impl<D: DomTypes> Drop for CallSetup<D> { - fn drop(&mut self) { - unsafe { - LeaveRealm(*self.cx, self.old_realm); - } - if self.handling == ExceptionHandling::Report { - let ar = enter_realm(&*self.exception_global); - <D as DomHelpers<D>>::report_pending_exception( - self.cx, - true, - InRealm::Entered(&ar), - CanGc::note(), - ); - } - drop(self.incumbent_script.take()); - drop(self.entry_script.take().unwrap()); - } -} diff --git a/components/script/dom/bindings/constructor.rs b/components/script/dom/bindings/constructor.rs index ae9305f0767..138dd4520d0 100644 --- a/components/script/dom/bindings/constructor.rs +++ b/components/script/dom/bindings/constructor.rs @@ -11,6 +11,7 @@ use js::glue::{UnwrapObjectDynamic, UnwrapObjectStatic}; use js::jsapi::{CallArgs, CurrentGlobalOrNull, JSAutoRealm, JSObject}; use js::rust::wrappers::{JS_SetPrototype, JS_WrapObject}; use js::rust::{HandleObject, MutableHandleObject, MutableHandleValue}; +use script_bindings::interface::get_desired_proto; use super::utils::ProtoOrIfaceArray; use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; @@ -40,9 +41,8 @@ use crate::dom::bindings::codegen::Bindings::{ }; use crate::dom::bindings::codegen::PrototypeList; use crate::dom::bindings::conversions::DerivedFrom; -use crate::dom::bindings::error::{Error, throw_constructor_without_new, throw_dom_exception}; +use crate::dom::bindings::error::{Error, throw_dom_exception}; use crate::dom::bindings::inheritance::Castable; -use crate::dom::bindings::interface::get_desired_proto; use crate::dom::bindings::reflector::DomObject; use crate::dom::bindings::root::DomRoot; use crate::dom::create::create_native_html_element; @@ -55,7 +55,7 @@ use crate::script_runtime::{CanGc, JSContext, JSContext as SafeJSContext}; use crate::script_thread::ScriptThread; /// <https://html.spec.whatwg.org/multipage/#htmlconstructor> -unsafe fn html_constructor( +fn html_constructor( cx: JSContext, global: &GlobalScope, call_args: &CallArgs, @@ -75,7 +75,9 @@ unsafe fn html_constructor( // The new_target might be a cross-compartment wrapper. Get the underlying object // so we can do the spec's object-identity checks. - rooted!(in(*cx) let new_target_unwrapped = UnwrapObjectDynamic(call_args.new_target().to_object(), *cx, true)); + rooted!(in(*cx) let new_target_unwrapped = unsafe { + UnwrapObjectDynamic(call_args.new_target().to_object(), *cx, true) + }); if new_target_unwrapped.is_null() { throw_dom_exception( cx, @@ -114,7 +116,7 @@ unsafe fn html_constructor( // Step 4. Let isValue be null. let mut is_value = None; - rooted!(in(*cx) let callee = UnwrapObjectStatic(call_args.callee())); + rooted!(in(*cx) let callee = unsafe { UnwrapObjectStatic(call_args.callee()) }); if callee.is_null() { throw_dom_exception(cx, global, Error::Security, can_gc); return Err(()); @@ -123,7 +125,7 @@ unsafe fn html_constructor( { let _ac = JSAutoRealm::new(*cx, callee.get()); rooted!(in(*cx) let mut constructor = ptr::null_mut::<JSObject>()); - rooted!(in(*cx) let global_object = CurrentGlobalOrNull(*cx)); + rooted!(in(*cx) let global_object = unsafe { CurrentGlobalOrNull(*cx) }); // Step 5. If definition's local name is equal to definition's name // (i.e., definition is for an autonomous custom element): @@ -233,13 +235,15 @@ unsafe fn html_constructor( }; rooted!(in(*cx) let mut element = result.reflector().get_jsobject().get()); - if !JS_WrapObject(*cx, element.handle_mut()) { - return Err(()); - } + unsafe { + if !JS_WrapObject(*cx, element.handle_mut()) { + return Err(()); + } - JS_SetPrototype(*cx, element.handle(), prototype.handle()); + JS_SetPrototype(*cx, element.handle(), prototype.handle()); - result.to_jsval(*cx, MutableHandleValue::from_raw(call_args.rval())); + result.to_jsval(*cx, MutableHandleValue::from_raw(call_args.rval())); + } Ok(()) } @@ -395,7 +399,7 @@ pub(crate) fn push_new_element_queue() { ScriptThread::push_new_element_queue(); } -pub(crate) unsafe fn call_html_constructor<T: DerivedFrom<Element> + DomObject>( +pub(crate) fn call_html_constructor<T: DerivedFrom<Element> + DomObject>( cx: JSContext, args: &CallArgs, global: &GlobalScope, @@ -418,26 +422,3 @@ pub(crate) unsafe fn call_html_constructor<T: DerivedFrom<Element> + DomObject>( ) .is_ok() } - -pub(crate) unsafe fn call_default_constructor<D: crate::DomTypes>( - cx: JSContext, - args: &CallArgs, - global: &D::GlobalScope, - proto_id: PrototypeList::ID, - ctor_name: &str, - creator: unsafe fn(JSContext, HandleObject, *mut ProtoOrIfaceArray), - constructor: impl FnOnce(JSContext, &CallArgs, &D::GlobalScope, HandleObject) -> bool, -) -> bool { - if !args.is_constructing() { - throw_constructor_without_new(cx, ctor_name); - return false; - } - - rooted!(in(*cx) let mut desired_proto = ptr::null_mut::<JSObject>()); - let proto_result = get_desired_proto(cx, args, proto_id, creator, desired_proto.handle_mut()); - if proto_result.is_err() { - return false; - } - - constructor(cx, args, global, desired_proto.handle()) -} diff --git a/components/script/dom/bindings/conversions.rs b/components/script/dom/bindings/conversions.rs index 0ea59e6ee83..f01357fda55 100644 --- a/components/script/dom/bindings/conversions.rs +++ b/components/script/dom/bindings/conversions.rs @@ -37,48 +37,15 @@ use std::ffi; pub(crate) use js::conversions::{ ConversionBehavior, ConversionResult, FromJSValConvertible, ToJSValConvertible, }; -use js::glue::GetProxyReservedSlot; -use js::jsapi::{Heap, IsWindowProxy, JS_IsExceptionPending, JSContext, JSObject}; +use js::jsapi::{JS_IsExceptionPending, JSContext, JSObject}; use js::jsval::UndefinedValue; -use js::rust::wrappers::{IsArrayObject, JS_GetProperty, JS_HasProperty}; -use js::rust::{HandleObject, HandleValue, MutableHandleValue}; -pub(crate) use script_bindings::conversions::*; +use js::rust::wrappers::{JS_GetProperty, JS_HasProperty}; +use js::rust::{HandleObject, MutableHandleValue}; +pub(crate) use script_bindings::conversions::{is_dom_proxy, *}; use crate::dom::bindings::error::{Error, Fallible}; use crate::dom::bindings::reflector::DomObject; use crate::dom::bindings::root::DomRoot; -use crate::dom::bindings::trace::{JSTraceable, RootedTraceableBox}; - -impl<T: ToJSValConvertible + JSTraceable> ToJSValConvertible for RootedTraceableBox<T> { - #[inline] - unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) { - let value = &**self; - value.to_jsval(cx, rval); - } -} - -impl<T> FromJSValConvertible for RootedTraceableBox<Heap<T>> -where - T: FromJSValConvertible + js::rust::GCMethods + Copy, - Heap<T>: JSTraceable + Default, -{ - type Config = T::Config; - - unsafe fn from_jsval( - cx: *mut JSContext, - value: HandleValue, - config: Self::Config, - ) -> Result<ConversionResult<Self>, ()> { - T::from_jsval(cx, value, config).map(|result| match result { - ConversionResult::Success(inner) => { - ConversionResult::Success(RootedTraceableBox::from_box(Heap::boxed(inner))) - }, - ConversionResult::Failure(msg) => ConversionResult::Failure(msg), - }) - } -} - -pub(crate) use script_bindings::conversions::is_dom_proxy; /// 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. @@ -104,43 +71,6 @@ where unsafe { root_from_object(obj.get(), cx) } } -/// Returns whether `value` is an array-like object (Array, FileList, -/// HTMLCollection, HTMLFormControlsCollection, HTMLOptionsCollection, -/// NodeList). -pub(crate) unsafe fn is_array_like<D: crate::DomTypes>( - cx: *mut JSContext, - value: HandleValue, -) -> bool { - let mut is_array = false; - assert!(IsArrayObject(cx, value, &mut is_array)); - if is_array { - return true; - } - - let object: *mut JSObject = match FromJSValConvertible::from_jsval(cx, value, ()).unwrap() { - ConversionResult::Success(object) => object, - _ => return false, - }; - - if root_from_object::<D::FileList>(object, cx).is_ok() { - return true; - } - if root_from_object::<D::HTMLCollection>(object, cx).is_ok() { - return true; - } - if root_from_object::<D::HTMLFormControlsCollection>(object, cx).is_ok() { - return true; - } - if root_from_object::<D::HTMLOptionsCollection>(object, cx).is_ok() { - return true; - } - if root_from_object::<D::NodeList>(object, cx).is_ok() { - return true; - } - - false -} - /// Get a property from a JS object. pub(crate) unsafe fn get_property_jsval( cx: *mut JSContext, @@ -191,22 +121,3 @@ where Err(()) => Err(Error::JSFailed), } } - -/// Get a `DomRoot<T>` for a WindowProxy accessible from a `HandleValue`. -/// Caller is responsible for throwing a JS exception if needed in case of error. -pub(crate) unsafe fn windowproxy_from_handlevalue<D: crate::DomTypes>( - v: HandleValue, - _cx: *mut JSContext, -) -> Result<DomRoot<D::WindowProxy>, ()> { - if !v.get().is_object() { - return Err(()); - } - let object = v.get().to_object(); - if !IsWindowProxy(object) { - return Err(()); - } - let mut value = UndefinedValue(); - GetProxyReservedSlot(object, 0, &mut value); - let ptr = value.to_private() as *const D::WindowProxy; - Ok(DomRoot::from_ref(&*ptr)) -} diff --git a/components/script/dom/bindings/guard.rs b/components/script/dom/bindings/guard.rs deleted file mode 100644 index 16b5187abef..00000000000 --- a/components/script/dom/bindings/guard.rs +++ /dev/null @@ -1,96 +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/. */ - -//! Machinery to conditionally expose things. - -use js::rust::HandleObject; -use script_bindings::codegen::Globals::Globals; -use servo_config::prefs::get; - -use crate::DomTypes; -use crate::dom::bindings::interface::is_exposed_in; -use crate::dom::globalscope::GlobalScopeHelpers; -use crate::realms::{AlreadyInRealm, InRealm}; -use crate::script_runtime::JSContext; - -/// A container with a list of conditions. -pub(crate) struct Guard<T: Clone + Copy> { - conditions: &'static [Condition], - value: T, -} - -impl<T: Clone + Copy> Guard<T> { - /// Construct a new guarded value. - pub(crate) const fn new(conditions: &'static [Condition], value: T) -> Self { - Guard { conditions, value } - } - - /// Expose the value if the conditions are satisfied. - /// - /// The passed handle is the object on which the value may be exposed. - pub(crate) fn expose<D: DomTypes>( - &self, - cx: JSContext, - obj: HandleObject, - global: HandleObject, - ) -> Option<T> { - let mut exposed_on_global = false; - let conditions_satisfied = self.conditions.iter().all(|c| match c { - Condition::Satisfied => { - exposed_on_global = true; - true - }, - // If there are multiple Exposed conditions, we just need one of them to be true - Condition::Exposed(globals) => { - exposed_on_global |= is_exposed_in(global, *globals); - true - }, - _ => c.is_satisfied::<D>(cx, obj, global), - }); - - if conditions_satisfied && exposed_on_global { - Some(self.value) - } else { - None - } - } -} - -/// A condition to expose things. -#[derive(Clone, Copy)] -pub(crate) enum Condition { - /// The condition is satisfied if the function returns true. - Func(fn(JSContext, HandleObject) -> bool), - /// The condition is satisfied if the preference is set. - Pref(&'static str), - // The condition is satisfied if the interface is exposed in the global. - Exposed(Globals), - SecureContext(), - /// The condition is always satisfied. - Satisfied, -} - -fn is_secure_context<D: DomTypes>(cx: JSContext) -> bool { - unsafe { - let in_realm_proof = AlreadyInRealm::assert_for_cx(JSContext::from_ptr(*cx)); - D::GlobalScope::from_context(*cx, InRealm::Already(&in_realm_proof)).is_secure_context() - } -} - -impl Condition { - pub(crate) fn is_satisfied<D: DomTypes>( - &self, - cx: JSContext, - obj: HandleObject, - global: HandleObject, - ) -> bool { - match *self { - Condition::Pref(name) => get().get_value(name).try_into().unwrap_or(false), - Condition::Func(f) => f(cx, obj), - Condition::Exposed(globals) => is_exposed_in(global, globals), - Condition::SecureContext() => is_secure_context::<D>(cx), - Condition::Satisfied => true, - } - } -} diff --git a/components/script/dom/bindings/import.rs b/components/script/dom/bindings/import.rs index 71ba5e4c994..5042eba1c05 100644 --- a/components/script/dom/bindings/import.rs +++ b/components/script/dom/bindings/import.rs @@ -2,169 +2,24 @@ * 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/. */ -#[allow(unused_imports)] pub(crate) mod base { pub(crate) use std::ptr; - pub(crate) use std::rc::Rc; - pub(crate) use js::error::throw_type_error; - pub(crate) use js::jsapi::{ - CurrentGlobalOrNull, HandleValue as RawHandleValue, HandleValueArray, Heap, IsCallable, - JS_NewObject, JSContext, JSObject, - }; - pub(crate) use js::jsval::{JSVal, NullValue, ObjectOrNullValue, ObjectValue, UndefinedValue}; - pub(crate) use js::panic::maybe_resume_unwind; - pub(crate) use js::rust::wrappers::{Call, JS_WrapValue}; - pub(crate) use js::rust::{HandleObject, HandleValue, MutableHandleObject, MutableHandleValue}; - pub(crate) use script_bindings::lock::ThreadUnsafeOnceLock; + pub(crate) use js::rust::{HandleObject, MutableHandleObject}; - pub(crate) use crate::dom::bindings::callback::{ - CallSetup, CallbackContainer, CallbackFunction, CallbackInterface, CallbackObject, - ExceptionHandling, ThisReflector, wrap_call_this_value, - }; - pub(crate) use crate::dom::bindings::codegen::Bindings::AudioNodeBinding::{ - ChannelCountMode, ChannelCountModeValues, ChannelInterpretation, - ChannelInterpretationValues, - }; - pub(crate) use crate::dom::bindings::codegen::DomTypes::DomTypes; - pub(crate) use crate::dom::bindings::codegen::{GenericUnionTypes, UnionTypes}; - pub(crate) use crate::dom::bindings::conversions::{ - ConversionBehavior, ConversionResult, FromJSValConvertible, StringificationBehavior, - ToJSValConvertible, root_from_handlevalue, - }; - pub(crate) use crate::dom::bindings::error::Error::JSFailed; - pub(crate) use crate::dom::bindings::error::{Fallible, throw_dom_exception}; - pub(crate) use crate::dom::bindings::num::Finite; - pub(crate) use crate::dom::bindings::proxyhandler::CrossOriginProperties; - pub(crate) use crate::dom::bindings::reflector::{DomGlobalGeneric, DomObject}; - pub(crate) use crate::dom::bindings::root::DomRoot; - pub(crate) use crate::dom::bindings::str::{ByteString, DOMString, USVString}; - pub(crate) use crate::dom::bindings::trace::RootedTraceableBox; - pub(crate) use crate::dom::bindings::utils::{ - DomHelpers, get_dictionary_property, set_dictionary_property, - }; - pub(crate) use crate::dom::globalscope::{GlobalScope, GlobalScopeHelpers}; - pub(crate) use crate::dom::promise::PromiseHelpers; - pub(crate) use crate::realms::{AlreadyInRealm, InRealm}; pub(crate) use crate::script_runtime::{CanGc, JSContext as SafeJSContext}; } -#[allow(unused_imports)] pub(crate) mod module { - pub(crate) use std::cmp; - pub(crate) use std::ffi::CString; - pub(crate) use std::ptr::NonNull; - - pub(crate) use js::glue::{ - CreateProxyHandler, GetProxyReservedSlot, JS_GetReservedSlot, ProxyTraps, - SetProxyReservedSlot, - }; - pub(crate) use js::jsapi::{ - __BindgenBitfieldUnit, CallArgs, GCContext, GetRealmErrorPrototype, - GetRealmFunctionPrototype, GetRealmIteratorPrototype, GetRealmObjectPrototype, - GetWellKnownSymbol, Handle as RawHandle, HandleId as RawHandleId, - HandleObject as RawHandleObject, JS_AtomizeAndPinString, JS_ForwardGetPropertyTo, - JS_GetPropertyDescriptorById, JS_HasPropertyById, JS_NewPlainObject, JS_SetReservedSlot, - JSAutoRealm, JSCLASS_FOREGROUND_FINALIZE, JSCLASS_RESERVED_SLOTS_SHIFT, JSClass, - JSClassOps, JSFunctionSpec, JSITER_HIDDEN, JSITER_OWNONLY, JSITER_SYMBOLS, - JSJitGetterCallArgs, JSJitInfo, JSJitInfo__bindgen_ty_1, JSJitInfo__bindgen_ty_2, - JSJitInfo__bindgen_ty_3, JSJitInfo_AliasSet, JSJitInfo_ArgType, JSJitInfo_OpType, - JSJitMethodCallArgs, JSJitSetterCallArgs, JSNativeWrapper, JSPROP_ENUMERATE, - JSPROP_PERMANENT, JSPROP_READONLY, JSPropertySpec, JSPropertySpec_Accessor, - JSPropertySpec_AccessorsOrValue, JSPropertySpec_AccessorsOrValue_Accessors, - JSPropertySpec_Kind, JSPropertySpec_Name, JSPropertySpec_ValueWrapper, - JSPropertySpec_ValueWrapper__bindgen_ty_1, JSPropertySpec_ValueWrapper_Type, JSTracer, - JSTypedMethodJitInfo, JSValueType, MutableHandle as RawMutableHandle, - MutableHandleIdVector as RawMutableHandleIdVector, - MutableHandleObject as RawMutableHandleObject, MutableHandleValue as RawMutableHandleValue, - ObjectOpResult, PropertyDescriptor, SymbolCode, UndefinedHandleValue, jsid, - }; - pub(crate) use js::jsval::PrivateValue; - pub(crate) use js::panic::wrap_panic; - pub(crate) use js::rust::wrappers::{ - AppendToIdVector, Call, GetPropertyKeys, JS_CopyOwnPropertiesAndPrivateFields, - JS_DefineProperty, JS_DefinePropertyById2, JS_GetProperty, - JS_InitializePropertiesFromCompatibleNativeObject, JS_NewObjectWithGivenProto, - JS_NewObjectWithoutMetadata, JS_SetImmutablePrototype, JS_SetProperty, JS_SetPrototype, - JS_WrapObject, NewProxyObject, RUST_INTERNED_STRING_TO_JSID, RUST_SYMBOL_TO_JSID, - int_to_jsid, - }; - pub(crate) use js::rust::{ - CustomAutoRooterGuard, GCMethods, Handle, MutableHandle, get_context_realm, - get_object_class, get_object_realm, - }; - pub(crate) use js::typedarray::{ - ArrayBuffer, ArrayBufferView, Float32Array, Float64Array, Uint8Array, Uint8ClampedArray, - }; - pub(crate) use js::{ - JS_CALLEE, JSCLASS_GLOBAL_SLOT_COUNT, JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL, - JSCLASS_RESERVED_SLOTS_MASK, jsapi, typedarray, - }; - pub(crate) use script_bindings::codegen::Globals::Globals; - pub(crate) use script_bindings::constant::{ConstantSpec, ConstantVal}; - pub(crate) use script_bindings::finalize::{ - finalize_common, finalize_global, finalize_weak_referenceable, - }; - pub(crate) use script_bindings::interfaces::*; - pub(crate) use script_bindings::record::Record; - pub(crate) use script_bindings::reflector::DomObject; - pub(crate) use servo_config::pref; + pub(crate) use script_bindings::codegen::PrototypeList; + pub(crate) use script_bindings::conversions::IDLInterface; + pub(crate) use script_bindings::utils::DOMClass; pub(crate) use super::base::*; - pub(crate) use crate::dom::bindings::codegen::Bindings::AnalyserNodeBinding::AnalyserOptions; - pub(crate) use crate::dom::bindings::codegen::Bindings::AudioNodeBinding::{ - AudioNode_Binding, ChannelCountMode, ChannelCountModeValues, ChannelInterpretation, - ChannelInterpretationValues, - }; - pub(crate) use crate::dom::bindings::codegen::Bindings::EventTargetBinding::EventTarget_Binding; - pub(crate) use crate::dom::bindings::codegen::{ - InterfaceObjectMap, PrototypeList, RegisterBindings, - }; - pub(crate) use crate::dom::bindings::constructor::{ - call_default_constructor, call_html_constructor, pop_current_element_queue, - push_new_element_queue, - }; - pub(crate) use crate::dom::bindings::conversions::{ - DOM_OBJECT_SLOT, IDLInterface, StringificationBehavior, ToJSValConvertible, is_array_like, - jsid_to_string, native_from_handlevalue, native_from_object_static, - }; - pub(crate) use crate::dom::bindings::error::{ - Error, ErrorResult, throw_constructor_without_new, - }; - pub(crate) use crate::dom::bindings::guard::{Condition, Guard}; - pub(crate) use crate::dom::bindings::inheritance::Castable; - pub(crate) use crate::dom::bindings::interface::{ - ConstructorClassHook, InterfaceConstructorBehavior, NonCallbackInterfaceObjectClass, - ProtoOrIfaceIndex, create_callback_interface_object, create_global_object, - create_interface_prototype_object, create_named_constructors, - create_noncallback_interface_object, define_dom_interface, define_guarded_methods, - define_guarded_properties, get_desired_proto, get_per_interface_object_handle, - is_exposed_in, - }; - pub(crate) use crate::dom::bindings::iterable::{Iterable, IterableIterator, IteratorType}; - pub(crate) use crate::dom::bindings::like::{Maplike, Setlike}; - pub(crate) use crate::dom::bindings::namespace::{ - NamespaceObjectClass, create_namespace_object, - }; - pub(crate) use crate::dom::bindings::proxyhandler; - pub(crate) use crate::dom::bindings::proxyhandler::{ - ensure_expando_object, get_expando_object, set_property_descriptor, - }; + pub(crate) use crate::dom::bindings::iterable::IterableIterator; pub(crate) use crate::dom::bindings::reflector::{ DomObjectIteratorWrap, DomObjectWrap, Reflector, }; - pub(crate) use crate::dom::bindings::root::{Dom, DomSlice, MaybeUnreflectedDom, Root}; - pub(crate) use crate::dom::bindings::trace::JSTraceable; - pub(crate) use crate::dom::bindings::utils::{ - AsVoidPtr, DOM_PROTO_UNFORGEABLE_HOLDER_SLOT, DOMClass, DOMJSClass, JSCLASS_DOM_GLOBAL, - ProtoOrIfaceArray, enumerate_global, exception_to_promise, generic_getter, - generic_lenient_getter, generic_lenient_setter, generic_method, generic_setter, - generic_static_promise_method, get_array_index_from_id, get_property_on_prototype, - has_property_on_prototype, resolve_global, trace_global, - }; - pub(crate) use crate::dom::bindings::weakref::{DOM_WEAK_SLOT, WeakReferenceable}; - pub(crate) use crate::dom::types::{AnalyserNode, AudioNode, BaseAudioContext, EventTarget}; - pub(crate) use crate::mem::malloc_size_of_including_raw_self; - pub(crate) use crate::realms::{AlreadyInRealm, InRealm}; - pub(crate) use crate::script_runtime::CanGc; + pub(crate) use crate::dom::bindings::root::{Dom, Root}; + pub(crate) use crate::dom::bindings::weakref::WeakReferenceable; } diff --git a/components/script/dom/bindings/interface.rs b/components/script/dom/bindings/interface.rs deleted file mode 100644 index d1c191be3a4..00000000000 --- a/components/script/dom/bindings/interface.rs +++ /dev/null @@ -1,696 +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/. */ - -//! Machinery to initialise interface prototype objects and interface objects. - -use std::convert::TryFrom; -use std::ffi::CStr; -use std::ptr; - -use js::error::throw_type_error; -use js::glue::UncheckedUnwrapObject; -use js::jsapi::JS::CompartmentIterResult; -use js::jsapi::{ - CallArgs, CheckedUnwrapStatic, Compartment, CompartmentSpecifier, CurrentGlobalOrNull, - GetFunctionRealm, GetNonCCWObjectGlobal, GetRealmGlobalOrNull, GetWellKnownSymbol, - HandleObject as RawHandleObject, IsSharableCompartment, IsSystemCompartment, - JS_AtomizeAndPinString, JS_GetFunctionObject, JS_GetProperty, JS_IterateCompartments, - JS_NewFunction, JS_NewGlobalObject, JS_NewObject, JS_NewPlainObject, JS_NewStringCopyN, - JS_SetReservedSlot, JS_WrapObject, JSAutoRealm, JSClass, JSClassOps, JSContext, - JSFUN_CONSTRUCTOR, JSFunctionSpec, JSObject, JSPROP_PERMANENT, JSPROP_READONLY, - JSPROP_RESOLVING, JSPropertySpec, JSString, JSTracer, ObjectOps, OnNewGlobalHookOption, - SymbolCode, TrueHandleValue, Value, jsid, -}; -use js::jsval::{JSVal, NullValue, PrivateValue}; -use js::rust::wrappers::{ - JS_DefineProperty, JS_DefineProperty3, JS_DefineProperty4, JS_DefineProperty5, - JS_DefinePropertyById5, JS_FireOnNewGlobalObject, JS_LinkConstructorAndPrototype, - JS_NewObjectWithGivenProto, RUST_SYMBOL_TO_JSID, -}; -use js::rust::{ - HandleObject, HandleValue, MutableHandleObject, RealmOptions, define_methods, - define_properties, get_object_class, is_dom_class, maybe_wrap_object, -}; -use script_bindings::constant::{ConstantSpec, define_constants}; -use servo_url::MutableOrigin; - -use crate::DomTypes; -use crate::dom::bindings::codegen::InterfaceObjectMap::Globals; -use crate::dom::bindings::codegen::PrototypeList; -use crate::dom::bindings::conversions::{DOM_OBJECT_SLOT, get_dom_class}; -use crate::dom::bindings::guard::Guard; -use crate::dom::bindings::principals::ServoJSPrincipals; -use crate::dom::bindings::utils::{ - DOM_PROTOTYPE_SLOT, DOMJSClass, JSCLASS_DOM_GLOBAL, ProtoOrIfaceArray, get_proto_or_iface_array, -}; -use crate::script_runtime::JSContext as SafeJSContext; - -/// The class of a non-callback interface object. -#[derive(Clone, Copy)] -pub(crate) struct NonCallbackInterfaceObjectClass { - /// The SpiderMonkey class structure. - pub(crate) _class: JSClass, - /// The prototype id of that interface, used in the hasInstance hook. - pub(crate) _proto_id: PrototypeList::ID, - /// The prototype depth of that interface, used in the hasInstance hook. - pub(crate) _proto_depth: u16, - /// The string representation of the object. - pub(crate) representation: &'static [u8], -} - -unsafe impl Sync for NonCallbackInterfaceObjectClass {} - -impl NonCallbackInterfaceObjectClass { - /// Create a new `NonCallbackInterfaceObjectClass` structure. - pub(crate) const fn new( - constructor_behavior: &'static InterfaceConstructorBehavior, - string_rep: &'static [u8], - proto_id: PrototypeList::ID, - proto_depth: u16, - ) -> NonCallbackInterfaceObjectClass { - NonCallbackInterfaceObjectClass { - _class: JSClass { - name: c"Function".as_ptr(), - flags: 0, - cOps: &constructor_behavior.0, - spec: 0 as *const _, - ext: 0 as *const _, - oOps: &OBJECT_OPS, - }, - _proto_id: proto_id, - _proto_depth: proto_depth, - representation: string_rep, - } - } - - /// cast own reference to `JSClass` reference - pub(crate) fn as_jsclass(&self) -> &JSClass { - unsafe { &*(self as *const _ as *const JSClass) } - } -} - -/// A constructor class hook. -pub(crate) type ConstructorClassHook = - unsafe extern "C" fn(cx: *mut JSContext, argc: u32, vp: *mut Value) -> bool; - -/// The constructor behavior of a non-callback interface object. -pub(crate) struct InterfaceConstructorBehavior(JSClassOps); - -impl InterfaceConstructorBehavior { - /// An interface constructor that unconditionally throws a type error. - pub(crate) const fn throw() -> Self { - InterfaceConstructorBehavior(JSClassOps { - addProperty: None, - delProperty: None, - enumerate: None, - newEnumerate: None, - resolve: None, - mayResolve: None, - finalize: None, - call: Some(invalid_constructor), - construct: Some(invalid_constructor), - trace: None, - }) - } - - /// An interface constructor that calls a native Rust function. - pub(crate) const fn call(hook: ConstructorClassHook) -> Self { - InterfaceConstructorBehavior(JSClassOps { - addProperty: None, - delProperty: None, - enumerate: None, - newEnumerate: None, - resolve: None, - mayResolve: None, - finalize: None, - call: Some(non_new_constructor), - construct: Some(hook), - trace: None, - }) - } -} - -/// A trace hook. -pub(crate) type TraceHook = unsafe extern "C" fn(trc: *mut JSTracer, obj: *mut JSObject); - -/// Create a global object with the given class. -pub(crate) unsafe fn create_global_object<D: DomTypes>( - cx: SafeJSContext, - class: &'static JSClass, - private: *const libc::c_void, - trace: TraceHook, - mut rval: MutableHandleObject, - origin: &MutableOrigin, -) { - assert!(rval.is_null()); - - let mut options = RealmOptions::default(); - options.creationOptions_.traceGlobal_ = Some(trace); - options.creationOptions_.sharedMemoryAndAtomics_ = false; - select_compartment(cx, &mut options); - - let principal = ServoJSPrincipals::new::<D>(origin); - - rval.set(JS_NewGlobalObject( - *cx, - class, - principal.as_raw(), - OnNewGlobalHookOption::DontFireOnNewGlobalHook, - &*options, - )); - assert!(!rval.is_null()); - - // Initialize the reserved slots before doing anything that can GC, to - // avoid getting trace hooks called on a partially initialized object. - let private_val = PrivateValue(private); - JS_SetReservedSlot(rval.get(), DOM_OBJECT_SLOT, &private_val); - let proto_array: Box<ProtoOrIfaceArray> = - Box::new([ptr::null_mut::<JSObject>(); PrototypeList::PROTO_OR_IFACE_LENGTH]); - let val = PrivateValue(Box::into_raw(proto_array) as *const libc::c_void); - JS_SetReservedSlot(rval.get(), DOM_PROTOTYPE_SLOT, &val); - - let _ac = JSAutoRealm::new(*cx, rval.get()); - JS_FireOnNewGlobalObject(*cx, rval.handle()); -} - -/// Choose the compartment to create a new global object in. -fn select_compartment(cx: SafeJSContext, options: &mut RealmOptions) { - type Data = *mut Compartment; - unsafe extern "C" fn callback( - _cx: *mut JSContext, - data: *mut libc::c_void, - compartment: *mut Compartment, - ) -> CompartmentIterResult { - let data = data as *mut Data; - - if !IsSharableCompartment(compartment) || IsSystemCompartment(compartment) { - return CompartmentIterResult::KeepGoing; - } - - // Choose any sharable, non-system compartment in this context to allow - // same-agent documents to share JS and DOM objects. - *data = compartment; - CompartmentIterResult::Stop - } - - let mut compartment: Data = ptr::null_mut(); - unsafe { - JS_IterateCompartments( - *cx, - (&mut compartment) as *mut Data as *mut libc::c_void, - Some(callback), - ); - } - - if compartment.is_null() { - options.creationOptions_.compSpec_ = CompartmentSpecifier::NewCompartmentAndZone; - } else { - options.creationOptions_.compSpec_ = CompartmentSpecifier::ExistingCompartment; - options.creationOptions_.__bindgen_anon_1.comp_ = compartment; - } -} - -/// Create and define the interface object of a callback interface. -pub(crate) fn create_callback_interface_object<D: DomTypes>( - cx: SafeJSContext, - global: HandleObject, - constants: &[Guard<&[ConstantSpec]>], - name: &CStr, - mut rval: MutableHandleObject, -) { - assert!(!constants.is_empty()); - unsafe { - rval.set(JS_NewObject(*cx, ptr::null())); - } - assert!(!rval.is_null()); - define_guarded_constants::<D>(cx, rval.handle(), constants, global); - define_name(cx, rval.handle(), name); - define_on_global_object(cx, global, name, rval.handle()); -} - -/// Create the interface prototype object of a non-callback interface. -#[allow(clippy::too_many_arguments)] -pub(crate) fn create_interface_prototype_object<D: DomTypes>( - cx: SafeJSContext, - global: HandleObject, - proto: HandleObject, - class: &'static JSClass, - regular_methods: &[Guard<&'static [JSFunctionSpec]>], - regular_properties: &[Guard<&'static [JSPropertySpec]>], - constants: &[Guard<&[ConstantSpec]>], - unscopable_names: &[&CStr], - mut rval: MutableHandleObject, -) { - create_object::<D>( - cx, - global, - proto, - class, - regular_methods, - regular_properties, - constants, - rval.reborrow(), - ); - - if !unscopable_names.is_empty() { - rooted!(in(*cx) let mut unscopable_obj = ptr::null_mut::<JSObject>()); - create_unscopable_object(cx, unscopable_names, unscopable_obj.handle_mut()); - unsafe { - let unscopable_symbol = GetWellKnownSymbol(*cx, SymbolCode::unscopables); - assert!(!unscopable_symbol.is_null()); - - rooted!(in(*cx) let mut unscopable_id: jsid); - RUST_SYMBOL_TO_JSID(unscopable_symbol, unscopable_id.handle_mut()); - - assert!(JS_DefinePropertyById5( - *cx, - rval.handle(), - unscopable_id.handle(), - unscopable_obj.handle(), - JSPROP_READONLY as u32 - )) - } - } -} - -/// Create and define the interface object of a non-callback interface. -#[allow(clippy::too_many_arguments)] -pub(crate) fn create_noncallback_interface_object<D: DomTypes>( - cx: SafeJSContext, - global: HandleObject, - proto: HandleObject, - class: &'static NonCallbackInterfaceObjectClass, - static_methods: &[Guard<&'static [JSFunctionSpec]>], - static_properties: &[Guard<&'static [JSPropertySpec]>], - constants: &[Guard<&[ConstantSpec]>], - interface_prototype_object: HandleObject, - name: &CStr, - length: u32, - legacy_window_alias_names: &[&CStr], - mut rval: MutableHandleObject, -) { - create_object::<D>( - cx, - global, - proto, - class.as_jsclass(), - static_methods, - static_properties, - constants, - rval.reborrow(), - ); - unsafe { - assert!(JS_LinkConstructorAndPrototype( - *cx, - rval.handle(), - interface_prototype_object - )); - } - define_name(cx, rval.handle(), name); - define_length(cx, rval.handle(), i32::try_from(length).expect("overflow")); - define_on_global_object(cx, global, name, rval.handle()); - - if is_exposed_in(global, Globals::WINDOW) { - for legacy_window_alias in legacy_window_alias_names { - define_on_global_object(cx, global, legacy_window_alias, rval.handle()); - } - } -} - -/// Create and define the named constructors of a non-callback interface. -pub(crate) fn create_named_constructors( - cx: SafeJSContext, - global: HandleObject, - named_constructors: &[(ConstructorClassHook, &CStr, u32)], - interface_prototype_object: HandleObject, -) { - rooted!(in(*cx) let mut constructor = ptr::null_mut::<JSObject>()); - - for &(native, name, arity) in named_constructors { - unsafe { - let fun = JS_NewFunction(*cx, Some(native), arity, JSFUN_CONSTRUCTOR, name.as_ptr()); - assert!(!fun.is_null()); - constructor.set(JS_GetFunctionObject(fun)); - assert!(!constructor.is_null()); - - assert!(JS_DefineProperty3( - *cx, - constructor.handle(), - c"prototype".as_ptr(), - interface_prototype_object, - (JSPROP_PERMANENT | JSPROP_READONLY) as u32 - )); - } - - define_on_global_object(cx, global, name, constructor.handle()); - } -} - -/// Create a new object with a unique type. -#[allow(clippy::too_many_arguments)] -pub(crate) fn create_object<D: DomTypes>( - cx: SafeJSContext, - global: HandleObject, - proto: HandleObject, - class: &'static JSClass, - methods: &[Guard<&'static [JSFunctionSpec]>], - properties: &[Guard<&'static [JSPropertySpec]>], - constants: &[Guard<&[ConstantSpec]>], - mut rval: MutableHandleObject, -) { - unsafe { - rval.set(JS_NewObjectWithGivenProto(*cx, class, proto)); - } - assert!(!rval.is_null()); - define_guarded_methods::<D>(cx, rval.handle(), methods, global); - define_guarded_properties::<D>(cx, rval.handle(), properties, global); - define_guarded_constants::<D>(cx, rval.handle(), constants, global); -} - -/// Conditionally define constants on an object. -pub(crate) fn define_guarded_constants<D: DomTypes>( - cx: SafeJSContext, - obj: HandleObject, - constants: &[Guard<&[ConstantSpec]>], - global: HandleObject, -) { - for guard in constants { - if let Some(specs) = guard.expose::<D>(cx, obj, global) { - define_constants(cx, obj, specs); - } - } -} - -/// Conditionally define methods on an object. -pub(crate) fn define_guarded_methods<D: DomTypes>( - cx: SafeJSContext, - obj: HandleObject, - methods: &[Guard<&'static [JSFunctionSpec]>], - global: HandleObject, -) { - for guard in methods { - if let Some(specs) = guard.expose::<D>(cx, obj, global) { - unsafe { - define_methods(*cx, obj, specs).unwrap(); - } - } - } -} - -/// Conditionally define properties on an object. -pub(crate) fn define_guarded_properties<D: DomTypes>( - cx: SafeJSContext, - obj: HandleObject, - properties: &[Guard<&'static [JSPropertySpec]>], - global: HandleObject, -) { - for guard in properties { - if let Some(specs) = guard.expose::<D>(cx, obj, global) { - unsafe { - define_properties(*cx, obj, specs).unwrap(); - } - } - } -} - -/// Returns whether an interface with exposure set given by `globals` should -/// be exposed in the global object `obj`. -pub(crate) fn is_exposed_in(object: HandleObject, globals: Globals) -> bool { - unsafe { - let unwrapped = UncheckedUnwrapObject(object.get(), /* stopAtWindowProxy = */ false); - let dom_class = get_dom_class(unwrapped).unwrap(); - globals.contains(dom_class.global) - } -} - -/// Define a property with a given name on the global object. Should be called -/// through the resolve hook. -pub(crate) fn define_on_global_object( - cx: SafeJSContext, - global: HandleObject, - name: &CStr, - obj: HandleObject, -) { - unsafe { - assert!(JS_DefineProperty3( - *cx, - global, - name.as_ptr(), - obj, - JSPROP_RESOLVING - )); - } -} - -const OBJECT_OPS: ObjectOps = ObjectOps { - lookupProperty: None, - defineProperty: None, - hasProperty: None, - getProperty: None, - setProperty: None, - getOwnPropertyDescriptor: None, - deleteProperty: None, - getElements: None, - funToString: Some(fun_to_string_hook), -}; - -unsafe extern "C" fn fun_to_string_hook( - cx: *mut JSContext, - obj: RawHandleObject, - _is_to_source: bool, -) -> *mut JSString { - let js_class = get_object_class(obj.get()); - assert!(!js_class.is_null()); - let repr = (*(js_class as *const NonCallbackInterfaceObjectClass)).representation; - assert!(!repr.is_empty()); - let ret = JS_NewStringCopyN(cx, repr.as_ptr() as *const libc::c_char, repr.len()); - assert!(!ret.is_null()); - ret -} - -fn create_unscopable_object(cx: SafeJSContext, names: &[&CStr], mut rval: MutableHandleObject) { - assert!(!names.is_empty()); - assert!(rval.is_null()); - unsafe { - rval.set(JS_NewPlainObject(*cx)); - assert!(!rval.is_null()); - for &name in names { - assert!(JS_DefineProperty( - *cx, - rval.handle(), - name.as_ptr(), - HandleValue::from_raw(TrueHandleValue), - JSPROP_READONLY as u32, - )); - } - } -} - -fn define_name(cx: SafeJSContext, obj: HandleObject, name: &CStr) { - unsafe { - rooted!(in(*cx) let name = JS_AtomizeAndPinString(*cx, name.as_ptr())); - assert!(!name.is_null()); - assert!(JS_DefineProperty4( - *cx, - obj, - c"name".as_ptr(), - name.handle(), - JSPROP_READONLY as u32 - )); - } -} - -fn define_length(cx: SafeJSContext, obj: HandleObject, length: i32) { - unsafe { - assert!(JS_DefineProperty5( - *cx, - obj, - c"length".as_ptr(), - length, - JSPROP_READONLY as u32 - )); - } -} - -unsafe extern "C" fn invalid_constructor( - cx: *mut JSContext, - _argc: libc::c_uint, - _vp: *mut JSVal, -) -> bool { - throw_type_error(cx, "Illegal constructor."); - false -} - -unsafe extern "C" fn non_new_constructor( - cx: *mut JSContext, - _argc: libc::c_uint, - _vp: *mut JSVal, -) -> bool { - throw_type_error(cx, "This constructor needs to be called with `new`."); - false -} - -pub(crate) enum ProtoOrIfaceIndex { - ID(PrototypeList::ID), - Constructor(PrototypeList::Constructor), -} - -impl From<ProtoOrIfaceIndex> for usize { - fn from(index: ProtoOrIfaceIndex) -> usize { - match index { - ProtoOrIfaceIndex::ID(id) => id as usize, - ProtoOrIfaceIndex::Constructor(constructor) => constructor as usize, - } - } -} - -pub(crate) fn get_per_interface_object_handle( - cx: SafeJSContext, - global: HandleObject, - id: ProtoOrIfaceIndex, - creator: unsafe fn(SafeJSContext, HandleObject, *mut ProtoOrIfaceArray), - mut rval: MutableHandleObject, -) { - unsafe { - assert!(((*get_object_class(global.get())).flags & JSCLASS_DOM_GLOBAL) != 0); - - /* Check to see whether the interface objects are already installed */ - let proto_or_iface_array = get_proto_or_iface_array(global.get()); - let index: usize = id.into(); - rval.set((*proto_or_iface_array)[index]); - if !rval.get().is_null() { - return; - } - - creator(cx, global, proto_or_iface_array); - rval.set((*proto_or_iface_array)[index]); - assert!(!rval.get().is_null()); - } -} - -pub(crate) fn define_dom_interface( - cx: SafeJSContext, - global: HandleObject, - id: ProtoOrIfaceIndex, - creator: unsafe fn(SafeJSContext, HandleObject, *mut ProtoOrIfaceArray), - enabled: fn(SafeJSContext, HandleObject) -> bool, -) { - assert!(!global.get().is_null()); - - if !enabled(cx, global) { - return; - } - - rooted!(in(*cx) let mut proto = ptr::null_mut::<JSObject>()); - get_per_interface_object_handle(cx, global, id, creator, proto.handle_mut()); - assert!(!proto.is_null()); -} - -fn get_proto_id_for_new_target(new_target: HandleObject) -> Option<PrototypeList::ID> { - unsafe { - let new_target_class = get_object_class(*new_target); - if is_dom_class(&*new_target_class) { - let domjsclass: *const DOMJSClass = new_target_class as *const DOMJSClass; - let dom_class = &(*domjsclass).dom_class; - return Some(dom_class.interface_chain[dom_class.depth as usize]); - } - None - } -} - -pub(crate) fn get_desired_proto( - cx: SafeJSContext, - args: &CallArgs, - proto_id: PrototypeList::ID, - creator: unsafe fn(SafeJSContext, HandleObject, *mut ProtoOrIfaceArray), - mut desired_proto: MutableHandleObject, -) -> Result<(), ()> { - unsafe { - // This basically implements - // https://heycam.github.io/webidl/#internally-create-a-new-object-implementing-the-interface - // step 3. - - assert!(args.is_constructing()); - - // The desired prototype depends on the actual constructor that was invoked, - // which is passed to us as the newTarget in the callargs. We want to do - // something akin to the ES6 specification's GetProtototypeFromConstructor (so - // get .prototype on the newTarget, with a fallback to some sort of default). - - // First, a fast path for the case when the the constructor is in fact one of - // our DOM constructors. This is safe because on those the "constructor" - // property is non-configurable and non-writable, so we don't have to do the - // slow JS_GetProperty call. - rooted!(in(*cx) let mut new_target = args.new_target().to_object()); - rooted!(in(*cx) let original_new_target = *new_target); - // See whether we have a known DOM constructor here, such that we can take a - // fast path. - let target_proto_id = get_proto_id_for_new_target(new_target.handle()).or_else(|| { - // We might still have a cross-compartment wrapper for a known DOM - // constructor. CheckedUnwrapStatic is fine here, because we're looking for - // DOM constructors and those can't be cross-origin objects. - new_target.set(CheckedUnwrapStatic(*new_target)); - if !new_target.is_null() && *new_target != *original_new_target { - get_proto_id_for_new_target(new_target.handle()) - } else { - None - } - }); - - if let Some(proto_id) = target_proto_id { - let global = GetNonCCWObjectGlobal(*new_target); - let proto_or_iface_cache = get_proto_or_iface_array(global); - desired_proto.set((*proto_or_iface_cache)[proto_id as usize]); - if *new_target != *original_new_target && !JS_WrapObject(*cx, desired_proto.into()) { - return Err(()); - } - return Ok(()); - } - - // Slow path. This basically duplicates the ES6 spec's - // GetPrototypeFromConstructor except that instead of taking a string naming - // the fallback prototype we determine the fallback based on the proto id we - // were handed. - rooted!(in(*cx) let mut proto_val = NullValue()); - if !JS_GetProperty( - *cx, - original_new_target.handle().into(), - c"prototype".as_ptr(), - proto_val.handle_mut().into(), - ) { - return Err(()); - } - - if proto_val.is_object() { - desired_proto.set(proto_val.to_object()); - return Ok(()); - } - - // Fall back to getting the proto for our given proto id in the realm that - // GetFunctionRealm(newTarget) returns. - let realm = GetFunctionRealm(*cx, new_target.handle().into()); - - if realm.is_null() { - return Err(()); - } - - { - let _realm = JSAutoRealm::new(*cx, GetRealmGlobalOrNull(realm)); - rooted!(in(*cx) let global = CurrentGlobalOrNull(*cx)); - get_per_interface_object_handle( - cx, - global.handle(), - ProtoOrIfaceIndex::ID(proto_id), - creator, - desired_proto.reborrow(), - ); - if desired_proto.is_null() { - return Err(()); - } - } - - maybe_wrap_object(*cx, desired_proto); - Ok(()) - } -} diff --git a/components/script/dom/bindings/iterable.rs b/components/script/dom/bindings/iterable.rs deleted file mode 100644 index c81551f7960..00000000000 --- a/components/script/dom/bindings/iterable.rs +++ /dev/null @@ -1,180 +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/. */ - -#![allow(unsafe_code)] - -//! Implementation of `iterable<...>` and `iterable<..., ...>` WebIDL declarations. - -use std::cell::Cell; -use std::marker::PhantomData; -use std::ptr; -use std::ptr::NonNull; - -use dom_struct::dom_struct; -use js::conversions::ToJSValConvertible; -use js::jsapi::{Heap, JSObject}; -use js::jsval::UndefinedValue; -use js::rust::{HandleObject, HandleValue, MutableHandleObject}; -use script_bindings::conversions::IDLInterface; -pub(crate) use script_bindings::iterable::*; -use script_bindings::utils::DOMClass; - -use crate::DomTypes; -use crate::dom::bindings::codegen::Bindings::IterableIteratorBinding::{ - IterableKeyAndValueResult, IterableKeyOrValueResult, -}; -use crate::dom::bindings::error::Fallible; -use crate::dom::bindings::reflector::{ - DomGlobalGeneric, DomObjectIteratorWrap, DomObjectWrap, Reflector, -}; -use crate::dom::bindings::root::{Dom, DomRoot, Root}; -use crate::dom::bindings::trace::{JSTraceable, NoTrace, RootedTraceableBox}; -use crate::dom::bindings::utils::DomHelpers; -use crate::realms::InRealm; -use crate::script_runtime::{CanGc, JSContext}; - -/// An iterator over the iterable entries of a given DOM interface. -#[dom_struct] -pub(crate) struct IterableIterator< - D: DomTypes, - T: DomObjectIteratorWrap<D> + JSTraceable + Iterable + DomGlobalGeneric<D>, -> { - reflector: Reflector, - iterable: Dom<T>, - type_: IteratorType, - index: Cell<u32>, - _marker: NoTrace<PhantomData<D>>, -} - -impl<D: DomTypes, T: DomObjectIteratorWrap<D> + JSTraceable + Iterable> IterableIterator<D, T> { - pub fn global_(&self, realm: InRealm) -> DomRoot<D::GlobalScope> { - <Self as DomGlobalGeneric<D>>::global_(self, realm) - } -} - -impl< - D: DomTypes, - T: DomObjectIteratorWrap<D> - + JSTraceable - + Iterable - + DomGlobalGeneric<D> - + IDLInterface - + IteratorDerives, -> IDLInterface for IterableIterator<D, T> -{ - fn derives(class: &'static DOMClass) -> bool { - <T as IteratorDerives>::derives(class) - } -} - -impl<D: DomTypes, T: DomObjectIteratorWrap<D> + JSTraceable + Iterable + DomGlobalGeneric<D>> - IterableIterator<D, T> -{ - /// Create a new iterator instance for the provided iterable DOM interface. - pub(crate) fn new(iterable: &T, type_: IteratorType, realm: InRealm) -> DomRoot<Self> { - let iterator = Box::new(IterableIterator { - reflector: Reflector::new(), - type_, - iterable: Dom::from_ref(iterable), - index: Cell::new(0), - _marker: NoTrace(PhantomData), - }); - <D as DomHelpers<D>>::reflect_dom_object(iterator, &*iterable.global_(realm), CanGc::note()) - } - - /// Return the next value from the iterable object. - #[allow(non_snake_case)] - pub(crate) fn Next(&self, cx: JSContext) -> Fallible<NonNull<JSObject>> { - let index = self.index.get(); - rooted!(in(*cx) let mut value = UndefinedValue()); - rooted!(in(*cx) let mut rval = ptr::null_mut::<JSObject>()); - let result = if index >= self.iterable.get_iterable_length() { - dict_return(cx, rval.handle_mut(), true, value.handle()) - } else { - match self.type_ { - IteratorType::Keys => { - unsafe { - self.iterable - .get_key_at_index(index) - .to_jsval(*cx, value.handle_mut()); - } - dict_return(cx, rval.handle_mut(), false, value.handle()) - }, - IteratorType::Values => { - unsafe { - self.iterable - .get_value_at_index(index) - .to_jsval(*cx, value.handle_mut()); - } - dict_return(cx, rval.handle_mut(), false, value.handle()) - }, - IteratorType::Entries => { - rooted!(in(*cx) let mut key = UndefinedValue()); - unsafe { - self.iterable - .get_key_at_index(index) - .to_jsval(*cx, key.handle_mut()); - self.iterable - .get_value_at_index(index) - .to_jsval(*cx, value.handle_mut()); - } - key_and_value_return(cx, rval.handle_mut(), key.handle(), value.handle()) - }, - } - }; - self.index.set(index + 1); - result.map(|_| NonNull::new(rval.get()).expect("got a null pointer")) - } -} - -impl<D: DomTypes, T: DomObjectIteratorWrap<D> + JSTraceable + Iterable + DomGlobalGeneric<D>> - DomObjectWrap<D> for IterableIterator<D, T> -{ - const WRAP: unsafe fn( - JSContext, - &D::GlobalScope, - Option<HandleObject>, - Box<Self>, - CanGc, - ) -> Root<Dom<Self>> = T::ITER_WRAP; -} - -fn dict_return( - cx: JSContext, - mut result: MutableHandleObject, - done: bool, - value: HandleValue, -) -> Fallible<()> { - let mut dict = IterableKeyOrValueResult::empty(); - dict.done = done; - dict.value.set(value.get()); - rooted!(in(*cx) let mut dict_value = UndefinedValue()); - unsafe { - dict.to_jsval(*cx, dict_value.handle_mut()); - } - result.set(dict_value.to_object()); - Ok(()) -} - -fn key_and_value_return( - cx: JSContext, - mut result: MutableHandleObject, - key: HandleValue, - value: HandleValue, -) -> Fallible<()> { - let mut dict = IterableKeyAndValueResult::empty(); - dict.done = false; - dict.value = Some( - vec![key, value] - .into_iter() - .map(|handle| RootedTraceableBox::from_box(Heap::boxed(handle.get()))) - .collect(), - ); - rooted!(in(*cx) let mut dict_value = UndefinedValue()); - unsafe { - dict.to_jsval(*cx, dict_value.handle_mut()); - } - result.set(dict_value.to_object()); - Ok(()) -} diff --git a/components/script/dom/bindings/mod.rs b/components/script/dom/bindings/mod.rs index b4234e0cc39..ae9e26e8a54 100644 --- a/components/script/dom/bindings/mod.rs +++ b/components/script/dom/bindings/mod.rs @@ -135,7 +135,6 @@ #![deny(non_snake_case)] pub(crate) mod buffer_source; -pub(crate) mod callback; #[allow(dead_code)] pub(crate) mod cell; pub(crate) mod constructor; @@ -143,13 +142,9 @@ pub(crate) mod conversions; pub(crate) mod error; pub(crate) mod frozenarray; pub(crate) mod function; -pub(crate) mod guard; pub(crate) mod import; pub(crate) mod inheritance; -pub(crate) mod interface; -pub(crate) mod iterable; pub(crate) mod like; -pub(crate) mod namespace; pub(crate) mod principals; pub(crate) mod proxyhandler; pub(crate) mod refcounted; @@ -165,7 +160,7 @@ pub(crate) mod utils; pub(crate) mod weakref; pub(crate) mod xmlname; -pub(crate) use script_bindings::num; +pub(crate) use script_bindings::{callback, iterable, num}; /// Generated JS-Rust bindings. #[allow(missing_docs, non_snake_case)] @@ -173,13 +168,7 @@ pub(crate) mod codegen { pub(crate) mod DomTypeHolder { include!(concat!(env!("BINDINGS_OUT_DIR"), "/DomTypeHolder.rs")); } - pub(crate) mod DomTypes { - include!(concat!(env!("BINDINGS_OUT_DIR"), "/DomTypes.rs")); - } - #[allow(dead_code)] - pub(crate) mod GenericBindings { - include!(concat!(env!("BINDINGS_OUT_DIR"), "/Bindings/mod.rs")); - } + pub(crate) use script_bindings::codegen::GenericBindings; #[allow(dead_code)] pub(crate) mod Bindings { include!(concat!( @@ -189,30 +178,14 @@ 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)] 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")); - } - #[allow( - non_camel_case_types, - unused_imports, - unused_variables, - clippy::large_enum_variant, - clippy::upper_case_acronyms, - clippy::enum_variant_names - )] - pub(crate) mod GenericUnionTypes { - include!(concat!(env!("BINDINGS_OUT_DIR"), "/GenericUnionTypes.rs")); - } + pub(crate) use script_bindings::codegen::{PrototypeList, RegisterBindings}; #[allow(dead_code)] pub(crate) mod UnionTypes { include!(concat!(env!("BINDINGS_OUT_DIR"), "/UnionTypes.rs")); diff --git a/components/script/dom/bindings/namespace.rs b/components/script/dom/bindings/namespace.rs deleted file mode 100644 index ad0a5801519..00000000000 --- a/components/script/dom/bindings/namespace.rs +++ /dev/null @@ -1,62 +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/. */ - -//! Machinery to initialise namespace objects. - -use std::ffi::CStr; -use std::ptr; - -use js::jsapi::{JSClass, JSFunctionSpec}; -use js::rust::{HandleObject, MutableHandleObject}; -use script_bindings::constant::ConstantSpec; - -use crate::DomTypes; -use crate::dom::bindings::guard::Guard; -use crate::dom::bindings::interface::{create_object, define_on_global_object}; -use crate::script_runtime::JSContext; - -/// The class of a namespace object. -#[derive(Clone, Copy)] -pub(crate) struct NamespaceObjectClass(JSClass); - -unsafe impl Sync for NamespaceObjectClass {} - -impl NamespaceObjectClass { - /// Create a new `NamespaceObjectClass` structure. - pub(crate) const unsafe fn new(name: &'static CStr) -> Self { - NamespaceObjectClass(JSClass { - name: name.as_ptr(), - flags: 0, - cOps: 0 as *mut _, - spec: ptr::null(), - ext: ptr::null(), - oOps: ptr::null(), - }) - } -} - -/// Create a new namespace object. -#[allow(clippy::too_many_arguments)] -pub(crate) fn create_namespace_object<D: DomTypes>( - cx: JSContext, - global: HandleObject, - proto: HandleObject, - class: &'static NamespaceObjectClass, - methods: &[Guard<&'static [JSFunctionSpec]>], - constants: &[Guard<&'static [ConstantSpec]>], - name: &CStr, - mut rval: MutableHandleObject, -) { - create_object::<D>( - cx, - global, - proto, - &class.0, - methods, - &[], - constants, - rval.reborrow(), - ); - define_on_global_object(cx, global, name, rval.handle()); -} diff --git a/components/script/dom/bindings/principals.rs b/components/script/dom/bindings/principals.rs index e51a98e454a..0594b77022c 100644 --- a/components/script/dom/bindings/principals.rs +++ b/components/script/dom/bindings/principals.rs @@ -2,132 +2,17 @@ * 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::marker::PhantomData; -use std::mem::ManuallyDrop; -use std::ops::Deref; use std::ptr::NonNull; -use js::glue::{ - CreateRustJSPrincipals, DestroyRustJSPrincipals, GetRustJSPrincipalsPrivate, - JSPrincipalsCallbacks, -}; +use js::glue::{DestroyRustJSPrincipals, GetRustJSPrincipalsPrivate, JSPrincipalsCallbacks}; use js::jsapi::{ - JS_DropPrincipals, JS_HoldPrincipals, JS_ReadUint32Pair, JSContext, JSPrincipals, - JSStructuredCloneReader, JSStructuredCloneWriter, + JS_ReadUint32Pair, JSContext, JSPrincipals, JSStructuredCloneReader, JSStructuredCloneWriter, }; -use js::rust::Runtime; +use script_bindings::principals::{ServoJSPrincipals, ServoJSPrincipalsRef}; use servo_url::MutableOrigin; use super::structuredclone::StructuredCloneTags; -use crate::dom::bindings::utils::DomHelpers; -use crate::{DomTypeHolder, DomTypes}; - -/// An owned reference to Servo's `JSPrincipals` instance. -#[repr(transparent)] -pub(crate) struct ServoJSPrincipals(NonNull<JSPrincipals>); - -impl ServoJSPrincipals { - pub(crate) fn new<D: DomTypes>(origin: &MutableOrigin) -> Self { - unsafe { - let private: Box<MutableOrigin> = Box::new(origin.clone()); - let raw = CreateRustJSPrincipals( - <D as DomHelpers<D>>::principals_callbacks(), - Box::into_raw(private) as _, - ); - // The created `JSPrincipals` object has an initial reference - // count of zero, so the following code will set it to one - Self::from_raw_nonnull(NonNull::new_unchecked(raw)) - } - } - - /// Construct `Self` from a raw `*mut JSPrincipals`, incrementing its - /// reference count. - #[inline] - pub(crate) unsafe fn from_raw_nonnull(raw: NonNull<JSPrincipals>) -> Self { - JS_HoldPrincipals(raw.as_ptr()); - Self(raw) - } - - #[inline] - pub(crate) unsafe fn origin(&self) -> MutableOrigin { - let origin = GetRustJSPrincipalsPrivate(self.0.as_ptr()) as *mut MutableOrigin; - (*origin).clone() - } - - #[inline] - pub(crate) fn as_raw_nonnull(&self) -> NonNull<JSPrincipals> { - self.0 - } - - #[inline] - pub(crate) fn as_raw(&self) -> *mut JSPrincipals { - self.0.as_ptr() - } -} - -impl Clone for ServoJSPrincipals { - #[inline] - fn clone(&self) -> Self { - unsafe { Self::from_raw_nonnull(self.as_raw_nonnull()) } - } -} - -impl Drop for ServoJSPrincipals { - #[inline] - fn drop(&mut self) { - if let Some(cx) = Runtime::get() { - unsafe { JS_DropPrincipals(cx.as_ptr(), self.as_raw()) }; - } - } -} - -/// A borrowed reference to Servo's `JSPrincipals` instance. Does not update the -/// reference count on creation and deletion. -pub(crate) struct ServoJSPrincipalsRef<'a>(ManuallyDrop<ServoJSPrincipals>, PhantomData<&'a ()>); - -impl ServoJSPrincipalsRef<'_> { - /// Construct `Self` from a raw `NonNull<JSPrincipals>`. - /// - /// # Safety - /// - /// `ServoJSPrincipalsRef` does not update the reference count of the - /// wrapped `JSPrincipals` object. It's up to the caller to ensure the - /// returned `ServoJSPrincipalsRef` object or any clones are not used past - /// the lifetime of the wrapped object. - #[inline] - pub(crate) unsafe fn from_raw_nonnull(raw: NonNull<JSPrincipals>) -> Self { - // Don't use `ServoJSPrincipals::from_raw_nonnull`; we don't want to - // update the reference count - Self(ManuallyDrop::new(ServoJSPrincipals(raw)), PhantomData) - } - - /// Construct `Self` from a raw `*mut JSPrincipals`. - /// - /// # Safety - /// - /// The behavior is undefined if `raw` is null. See also - /// [`Self::from_raw_nonnull`]. - #[inline] - pub(crate) unsafe fn from_raw_unchecked(raw: *mut JSPrincipals) -> Self { - Self::from_raw_nonnull(NonNull::new_unchecked(raw)) - } -} - -impl Clone for ServoJSPrincipalsRef<'_> { - #[inline] - fn clone(&self) -> Self { - Self(ManuallyDrop::new(ServoJSPrincipals(self.0.0)), PhantomData) - } -} - -impl Deref for ServoJSPrincipalsRef<'_> { - type Target = ServoJSPrincipals; - - #[inline] - fn deref(&self) -> &Self::Target { - &self.0 - } -} +use crate::DomTypeHolder; #[allow(unused)] pub(crate) unsafe extern "C" fn destroy_servo_jsprincipal(principals: *mut JSPrincipals) { diff --git a/components/script/dom/bindings/proxyhandler.rs b/components/script/dom/bindings/proxyhandler.rs index 5dfe0839502..2e203a81fa9 100644 --- a/components/script/dom/bindings/proxyhandler.rs +++ b/components/script/dom/bindings/proxyhandler.rs @@ -6,30 +6,12 @@ #![deny(missing_docs)] -use std::ptr; - -use js::conversions::ToJSValConvertible; -use js::glue::{GetProxyHandler, InvokeGetOwnPropertyDescriptor}; -use js::jsapi; -use js::jsapi::{ - GetObjectRealmOrNull, GetRealmPrincipals, HandleId as RawHandleId, - HandleObject as RawHandleObject, HandleValue as RawHandleValue, JS_IsExceptionPending, - JSAutoRealm, JSContext, JSObject, MutableHandle as RawMutableHandle, - MutableHandleObject as RawMutableHandleObject, MutableHandleValue as RawMutableHandleValue, - ObjectOpResult, PropertyDescriptor, -}; -use js::jsval::UndefinedValue; -use js::rust::{HandleObject, HandleValue, MutableHandle, MutableHandleObject, get_context_realm}; +use js::jsapi::{GetObjectRealmOrNull, GetRealmPrincipals, HandleObject as RawHandleObject}; +use js::rust::get_context_realm; +use script_bindings::principals::ServoJSPrincipalsRef; pub(crate) use script_bindings::proxyhandler::*; -use crate::DomTypes; -use crate::dom::bindings::error::Error; -use crate::dom::bindings::principals::ServoJSPrincipalsRef; -use crate::dom::bindings::reflector::DomObject; -use crate::dom::bindings::utils::DomHelpers; -use crate::dom::globalscope::GlobalScopeHelpers; -use crate::realms::{AlreadyInRealm, InRealm}; -use crate::script_runtime::{CanGc, JSContext as SafeJSContext}; +use crate::script_runtime::JSContext as SafeJSContext; /// <https://html.spec.whatwg.org/multipage/#isplatformobjectsameorigin-(-o-)> pub(crate) unsafe fn is_platform_object_same_origin( @@ -64,269 +46,3 @@ pub(crate) unsafe fn is_platform_object_same_origin( result } - -/// Report a cross-origin denial for a property, Always returns `false`, so it -/// can be used as `return report_cross_origin_denial(...);`. -/// -/// What this function does corresponds to the operations in -/// <https://html.spec.whatwg.org/multipage/#the-location-interface> denoted as -/// "Throw a `SecurityError` DOMException". -pub(crate) unsafe fn report_cross_origin_denial<D: DomTypes>( - cx: SafeJSContext, - id: RawHandleId, - access: &str, -) -> bool { - debug!( - "permission denied to {} property {} on cross-origin object", - access, - id_to_source(cx, id).as_deref().unwrap_or("< error >"), - ); - let in_realm_proof = AlreadyInRealm::assert_for_cx(cx); - if !JS_IsExceptionPending(*cx) { - let global = D::GlobalScope::from_context(*cx, InRealm::Already(&in_realm_proof)); - // TODO: include `id` and `access` in the exception message - <D as DomHelpers<D>>::throw_dom_exception(cx, &global, Error::Security, CanGc::note()); - } - false -} - -/// Implementation of `[[Set]]` for [`Location`]. -/// -/// [`Location`]: https://html.spec.whatwg.org/multipage/#location-set -pub(crate) unsafe extern "C" fn maybe_cross_origin_set_rawcx<D: DomTypes>( - cx: *mut JSContext, - proxy: RawHandleObject, - id: RawHandleId, - v: RawHandleValue, - receiver: RawHandleValue, - result: *mut ObjectOpResult, -) -> bool { - let cx = SafeJSContext::from_ptr(cx); - - if !<D as DomHelpers<D>>::is_platform_object_same_origin(cx, proxy) { - return cross_origin_set::<D>(cx, proxy, id, v, receiver, result); - } - - // Safe to enter the Realm of proxy now. - let _ac = JSAutoRealm::new(*cx, proxy.get()); - - // OrdinarySet - // <https://tc39.es/ecma262/#sec-ordinaryset> - rooted!(in(*cx) let mut own_desc = PropertyDescriptor::default()); - let mut is_none = false; - if !InvokeGetOwnPropertyDescriptor( - GetProxyHandler(*proxy), - *cx, - proxy, - id, - own_desc.handle_mut().into(), - &mut is_none, - ) { - return false; - } - - js::jsapi::SetPropertyIgnoringNamedGetter( - *cx, - proxy, - id, - v, - receiver, - own_desc.handle().into(), - result, - ) -} - -/// Implementation of `[[GetPrototypeOf]]` for [`Location`]. -/// -/// [`Location`]: https://html.spec.whatwg.org/multipage/#location-getprototypeof -pub(crate) unsafe fn maybe_cross_origin_get_prototype<D: DomTypes>( - cx: SafeJSContext, - proxy: RawHandleObject, - get_proto_object: unsafe fn(cx: SafeJSContext, global: HandleObject, rval: MutableHandleObject), - proto: RawMutableHandleObject, -) -> bool { - // > 1. If ! IsPlatformObjectSameOrigin(this) is true, then return ! OrdinaryGetPrototypeOf(this). - if is_platform_object_same_origin(cx, proxy) { - let ac = JSAutoRealm::new(*cx, proxy.get()); - let global = D::GlobalScope::from_context(*cx, InRealm::Entered(&ac)); - get_proto_object( - cx, - global.reflector().get_jsobject(), - MutableHandleObject::from_raw(proto), - ); - return !proto.is_null(); - } - - // > 2. Return null. - proto.set(ptr::null_mut()); - true -} - -/// Implementation of [`CrossOriginGet`]. -/// -/// `cx` and `proxy` are expected to be different-Realm here. `proxy` is a proxy -/// for a maybe-cross-origin object. -/// -/// [`CrossOriginGet`]: https://html.spec.whatwg.org/multipage/#crossoriginget-(-o,-p,-receiver-) -pub(crate) unsafe fn cross_origin_get<D: DomTypes>( - cx: SafeJSContext, - proxy: RawHandleObject, - receiver: RawHandleValue, - id: RawHandleId, - vp: RawMutableHandleValue, -) -> bool { - // > 1. Let `desc` be `? O.[[GetOwnProperty]](P)`. - rooted!(in(*cx) let mut descriptor = PropertyDescriptor::default()); - let mut is_none = false; - if !InvokeGetOwnPropertyDescriptor( - GetProxyHandler(*proxy), - *cx, - proxy, - id, - descriptor.handle_mut().into(), - &mut is_none, - ) { - return false; - } - - // > 2. Assert: `desc` is not undefined. - assert!( - !is_none, - "Callees should throw in all cases when they are not finding \ - a property decriptor" - ); - - // > 3. If `! IsDataDescriptor(desc)` is true, then return `desc.[[Value]]`. - if is_data_descriptor(&descriptor) { - vp.set(descriptor.value_); - return true; - } - - // > 4. Assert: `IsAccessorDescriptor(desc)` is `true`. - assert!(is_accessor_descriptor(&descriptor)); - - // > 5. Let `getter` be `desc.[[Get]]`. - // > - // > 6. If `getter` is `undefined`, then throw a `SecurityError` - // > `DOMException`. - rooted!(in(*cx) let mut getter = ptr::null_mut::<JSObject>()); - get_getter_object(&descriptor, getter.handle_mut().into()); - if getter.get().is_null() { - return report_cross_origin_denial::<D>(cx, id, "get"); - } - - rooted!(in(*cx) let mut getter_jsval = UndefinedValue()); - getter.get().to_jsval(*cx, getter_jsval.handle_mut()); - - // > 7. Return `? Call(getter, Receiver)`. - jsapi::Call( - *cx, - receiver, - getter_jsval.handle().into(), - &jsapi::HandleValueArray::empty(), - vp, - ) -} - -/// Implementation of [`CrossOriginSet`]. -/// -/// `cx` and `proxy` are expected to be different-Realm here. `proxy` is a proxy -/// for a maybe-cross-origin object. -/// -/// [`CrossOriginSet`]: https://html.spec.whatwg.org/multipage/#crossoriginset-(-o,-p,-v,-receiver-) -pub(crate) unsafe fn cross_origin_set<D: DomTypes>( - cx: SafeJSContext, - proxy: RawHandleObject, - id: RawHandleId, - v: RawHandleValue, - receiver: RawHandleValue, - result: *mut ObjectOpResult, -) -> bool { - // > 1. Let desc be ? O.[[GetOwnProperty]](P). - rooted!(in(*cx) let mut descriptor = PropertyDescriptor::default()); - let mut is_none = false; - if !InvokeGetOwnPropertyDescriptor( - GetProxyHandler(*proxy), - *cx, - proxy, - id, - descriptor.handle_mut().into(), - &mut is_none, - ) { - return false; - } - - // > 2. Assert: desc is not undefined. - assert!( - !is_none, - "Callees should throw in all cases when they are not finding \ - a property decriptor" - ); - - // > 3. If desc.[[Set]] is present and its value is not undefined, - // > then: [...] - rooted!(in(*cx) let mut setter = ptr::null_mut::<JSObject>()); - get_setter_object(&descriptor, setter.handle_mut().into()); - if setter.get().is_null() { - // > 4. Throw a "SecurityError" DOMException. - return report_cross_origin_denial::<D>(cx, id, "set"); - } - - rooted!(in(*cx) let mut setter_jsval = UndefinedValue()); - setter.get().to_jsval(*cx, setter_jsval.handle_mut()); - - // > 3.1. Perform ? Call(setter, Receiver, «V»). - // > - // > 3.2. Return true. - rooted!(in(*cx) let mut ignored = UndefinedValue()); - if !jsapi::Call( - *cx, - receiver, - setter_jsval.handle().into(), - // FIXME: Our binding lacks `HandleValueArray(Handle<Value>)` - // <https://searchfox.org/mozilla-central/rev/072710086ddfe25aa2962c8399fefb2304e8193b/js/public/ValueArray.h#54-55> - &jsapi::HandleValueArray { - length_: 1, - elements_: v.ptr, - }, - ignored.handle_mut().into(), - ) { - return false; - } - - (*result).code_ = 0 /* OkCode */; - true -} - -/// Implementation of [`CrossOriginPropertyFallback`]. -/// -/// `cx` and `proxy` are expected to be different-Realm here. `proxy` is a proxy -/// for a maybe-cross-origin object. -/// -/// [`CrossOriginPropertyFallback`]: https://html.spec.whatwg.org/multipage/#crossoriginpropertyfallback-(-p-) -pub(crate) unsafe fn cross_origin_property_fallback<D: DomTypes>( - cx: SafeJSContext, - _proxy: RawHandleObject, - id: RawHandleId, - desc: RawMutableHandle<PropertyDescriptor>, - is_none: &mut bool, -) -> bool { - assert!(*is_none, "why are we being called?"); - - // > 1. If P is `then`, `@@toStringTag`, `@@hasInstance`, or - // > `@@isConcatSpreadable`, then return `PropertyDescriptor{ [[Value]]: - // > undefined, [[Writable]]: false, [[Enumerable]]: false, - // > [[Configurable]]: true }`. - if is_cross_origin_allowlisted_prop(cx, id) { - set_property_descriptor( - MutableHandle::from_raw(desc), - HandleValue::undefined(), - jsapi::JSPROP_READONLY as u32, - is_none, - ); - return true; - } - - // > 2. Throw a `SecurityError` `DOMException`. - report_cross_origin_denial::<D>(cx, id, "access") -} diff --git a/components/script/dom/bindings/reflector.rs b/components/script/dom/bindings/reflector.rs index 3593578a66f..0a5afbce487 100644 --- a/components/script/dom/bindings/reflector.rs +++ b/components/script/dom/bindings/reflector.rs @@ -5,15 +5,14 @@ //! The `Reflector` struct. use js::rust::HandleObject; +use script_bindings::interfaces::GlobalScopeHelpers; use crate::DomTypes; use crate::dom::bindings::conversions::DerivedFrom; -use crate::dom::bindings::iterable::{Iterable, IterableIterator}; -use crate::dom::bindings::root::{Dom, DomRoot, Root}; -use crate::dom::bindings::trace::JSTraceable; -use crate::dom::globalscope::{GlobalScope, GlobalScopeHelpers}; -use crate::realms::{AlreadyInRealm, InRealm}; -use crate::script_runtime::{CanGc, JSContext}; +use crate::dom::bindings::root::DomRoot; +use crate::dom::globalscope::GlobalScope; +use crate::realms::InRealm; +use crate::script_runtime::CanGc; /// Create the reflector for a new DOM object and yield ownership to the /// reflector. @@ -42,31 +41,6 @@ where unsafe { T::WRAP(D::GlobalScope::get_cx(), global_scope, proto, obj, can_gc) } } -pub(crate) trait DomGlobalGeneric<D: DomTypes>: DomObject { - /// Returns the [`GlobalScope`] of the realm that the [`DomObject`] was created in. If this - /// object is a `Node`, this will be different from it's owning `Document` if adopted by. For - /// `Node`s it's almost always better to use `NodeTraits::owning_global`. - fn global_(&self, realm: InRealm) -> DomRoot<D::GlobalScope> - where - Self: Sized, - { - D::GlobalScope::from_reflector(self, realm) - } - - /// Returns the [`GlobalScope`] of the realm that the [`DomObject`] was created in. If this - /// object is a `Node`, this will be different from it's owning `Document` if adopted by. For - /// `Node`s it's almost always better to use `NodeTraits::owning_global`. - fn global(&self) -> DomRoot<D::GlobalScope> - where - Self: Sized, - { - let realm = AlreadyInRealm::assert_for_cx(D::GlobalScope::get_cx()); - D::GlobalScope::from_reflector(self, InRealm::already(&realm)) - } -} - -impl<D: DomTypes, T: DomObject> DomGlobalGeneric<D> for T {} - pub(crate) trait DomGlobal { fn global_(&self, realm: InRealm) -> DomRoot<GlobalScope>; fn global(&self) -> DomRoot<GlobalScope>; @@ -81,35 +55,4 @@ impl<T: DomGlobalGeneric<crate::DomTypeHolder>> DomGlobal for T { } } -pub(crate) use script_bindings::reflector::{DomObject, MutDomObject, Reflector}; - -/// A trait to provide a function pointer to wrap function for DOM objects. -pub(crate) trait DomObjectWrap<D: DomTypes>: - Sized + DomObject + DomGlobalGeneric<D> -{ - /// Function pointer to the general wrap function type - #[allow(clippy::type_complexity)] - const WRAP: unsafe fn( - JSContext, - &D::GlobalScope, - Option<HandleObject>, - Box<Self>, - CanGc, - ) -> Root<Dom<Self>>; -} - -/// A trait to provide a function pointer to wrap function for -/// DOM iterator interfaces. -pub(crate) trait DomObjectIteratorWrap<D: DomTypes>: - DomObjectWrap<D> + JSTraceable + Iterable -{ - /// Function pointer to the wrap function for `IterableIterator<T>` - #[allow(clippy::type_complexity)] - const ITER_WRAP: unsafe fn( - JSContext, - &D::GlobalScope, - Option<HandleObject>, - Box<IterableIterator<D, Self>>, - CanGc, - ) -> Root<Dom<IterableIterator<D, Self>>>; -} +pub(crate) use script_bindings::reflector::*; diff --git a/components/script/dom/bindings/settings_stack.rs b/components/script/dom/bindings/settings_stack.rs index 1284931c349..8e00d03a953 100644 --- a/components/script/dom/bindings/settings_stack.rs +++ b/components/script/dom/bindings/settings_stack.rs @@ -3,36 +3,20 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use std::cell::RefCell; -use std::marker::PhantomData; -use std::thread; -use js::jsapi::{GetScriptedCallerGlobal, HideScriptedCaller, JSTracer, UnhideScriptedCaller}; +use js::jsapi::{GetScriptedCallerGlobal, JSTracer}; use js::rust::Runtime; +use script_bindings::settings_stack::*; -use crate::DomTypes; -use crate::dom::bindings::root::{Dom, DomRoot}; +//use script_bindings::interfaces::{DomHelpers, GlobalScopeHelpers}; +use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::trace::JSTraceable; -use crate::dom::bindings::utils::DomHelpers; -use crate::dom::globalscope::{GlobalScope, GlobalScopeHelpers}; -use crate::script_runtime::CanGc; +use crate::dom::globalscope::GlobalScope; thread_local!(pub(super) static STACK: RefCell<Vec<StackEntry<crate::DomTypeHolder>>> = const { RefCell::new(Vec::new()) }); -#[derive(Debug, Eq, JSTraceable, PartialEq)] -enum StackEntryKind { - Incumbent, - Entry, -} - -#[cfg_attr(crown, allow(crown::unrooted_must_root))] -#[derive(JSTraceable)] -pub(crate) struct StackEntry<D: DomTypes> { - global: Dom<D::GlobalScope>, - kind: StackEntryKind, -} - /// Traces the script settings stack. pub(crate) unsafe fn trace(tracer: *mut JSTracer) { STACK.with(|stack| { @@ -46,61 +30,6 @@ pub(crate) fn is_execution_stack_empty() -> bool { pub(crate) type AutoEntryScript = GenericAutoEntryScript<crate::DomTypeHolder>; -/// RAII struct that pushes and pops entries from the script settings stack. -pub(crate) struct GenericAutoEntryScript<D: DomTypes> { - global: DomRoot<D::GlobalScope>, - #[cfg(feature = "tracing")] - #[allow(dead_code)] - span: tracing::span::EnteredSpan, -} - -impl<D: DomTypes> GenericAutoEntryScript<D> { - /// <https://html.spec.whatwg.org/multipage/#prepare-to-run-script> - pub(crate) fn new(global: &D::GlobalScope) -> Self { - let settings_stack = <D as DomHelpers<D>>::settings_stack(); - settings_stack.with(|stack| { - trace!("Prepare to run script with {:p}", global); - let mut stack = stack.borrow_mut(); - stack.push(StackEntry { - global: Dom::from_ref(global), - kind: StackEntryKind::Entry, - }); - Self { - global: DomRoot::from_ref(global), - #[cfg(feature = "tracing")] - span: tracing::info_span!( - "ScriptEvaluate", - servo_profiling = true, - url = global.get_url().to_string(), - ) - .entered(), - } - }) - } -} - -impl<D: DomTypes> Drop for GenericAutoEntryScript<D> { - /// <https://html.spec.whatwg.org/multipage/#clean-up-after-running-script> - fn drop(&mut self) { - let settings_stack = <D as DomHelpers<D>>::settings_stack(); - settings_stack.with(|stack| { - let mut stack = stack.borrow_mut(); - let entry = stack.pop().unwrap(); - assert_eq!( - &*entry.global as *const D::GlobalScope, &*self.global as *const D::GlobalScope, - "Dropped AutoEntryScript out of order." - ); - assert_eq!(entry.kind, StackEntryKind::Entry); - trace!("Clean up after running script with {:p}", &*entry.global); - }); - - // Step 5 - if !thread::panicking() && incumbent_global().is_none() { - self.global.perform_a_microtask_checkpoint(CanGc::note()); - } - } -} - /// Returns the ["entry"] global object. /// /// ["entry"]: https://html.spec.whatwg.org/multipage/#entry @@ -117,67 +46,7 @@ pub(crate) fn entry_global() -> DomRoot<GlobalScope> { .unwrap() } -/// RAII struct that pushes and pops entries from the script settings stack. -pub(crate) struct GenericAutoIncumbentScript<D: DomTypes> { - global: usize, - _marker: PhantomData<D>, -} - -pub(crate) type AutoIncumbentScript = GenericAutoIncumbentScript<crate::DomTypeHolder>; - -impl<D: DomTypes> GenericAutoIncumbentScript<D> { - /// <https://html.spec.whatwg.org/multipage/#prepare-to-run-a-callback> - pub(crate) fn new(global: &D::GlobalScope) -> Self { - // Step 2-3. - unsafe { - let cx = - Runtime::get().expect("Creating a new incumbent script after runtime shutdown"); - HideScriptedCaller(cx.as_ptr()); - } - let settings_stack = <D as DomHelpers<D>>::settings_stack(); - settings_stack.with(|stack| { - trace!("Prepare to run a callback with {:p}", global); - // Step 1. - let mut stack = stack.borrow_mut(); - stack.push(StackEntry { - global: Dom::from_ref(global), - kind: StackEntryKind::Incumbent, - }); - Self { - global: global as *const _ as usize, - _marker: PhantomData, - } - }) - } -} - -impl<D: DomTypes> Drop for GenericAutoIncumbentScript<D> { - /// <https://html.spec.whatwg.org/multipage/#clean-up-after-running-a-callback> - fn drop(&mut self) { - let settings_stack = <D as DomHelpers<D>>::settings_stack(); - settings_stack.with(|stack| { - // Step 4. - let mut stack = stack.borrow_mut(); - let entry = stack.pop().unwrap(); - // Step 3. - assert_eq!( - &*entry.global as *const D::GlobalScope as usize, self.global, - "Dropped AutoIncumbentScript out of order." - ); - assert_eq!(entry.kind, StackEntryKind::Incumbent); - trace!( - "Clean up after running a callback with {:p}", - &*entry.global - ); - }); - unsafe { - // Step 1-2. - if let Some(cx) = Runtime::get() { - UnhideScriptedCaller(cx.as_ptr()); - } - } - } -} +pub type AutoIncumbentScript = GenericAutoIncumbentScript<crate::DomTypeHolder>; /// Returns the ["incumbent"] global object. /// diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index b0c65b9fd9d..5d48e4c4e0f 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -33,15 +33,12 @@ use std::collections::HashMap; use std::collections::hash_map::RandomState; use std::fmt::Display; use std::hash::{BuildHasher, Hash}; -use std::mem; -use std::ops::{Deref, DerefMut}; /// A trait to allow tracing (only) DOM objects. pub(crate) use js::gc::Traceable as JSTraceable; 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}; pub(crate) use script_bindings::trace::*; @@ -267,70 +264,3 @@ unsafe impl<T: DomObject> JSTraceable for Trusted<T> { // Do nothing } } - -/// Roots any JSTraceable thing -/// -/// If you have a valid DomObject, use DomRoot. -/// If you have GC things like *mut JSObject or JSVal, use rooted!. -/// If you have an arbitrary number of DomObjects to root, use rooted_vec!. -/// If you know what you're doing, use this. -#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)] -pub(crate) struct RootedTraceableBox<T: JSTraceable + 'static>(js::gc::RootedTraceableBox<T>); - -unsafe impl<T: JSTraceable + 'static> JSTraceable for RootedTraceableBox<T> { - unsafe fn trace(&self, tracer: *mut JSTracer) { - self.0.trace(tracer); - } -} - -impl<T: JSTraceable + 'static> RootedTraceableBox<T> { - /// DomRoot a JSTraceable thing for the life of this RootedTraceableBox - pub(crate) fn new(traceable: T) -> RootedTraceableBox<T> { - Self(js::gc::RootedTraceableBox::new(traceable)) - } - - /// Consumes a boxed JSTraceable and roots it for the life of this RootedTraceableBox. - pub(crate) fn from_box(boxed_traceable: Box<T>) -> RootedTraceableBox<T> { - Self(js::gc::RootedTraceableBox::from_box(boxed_traceable)) - } -} - -impl<T> RootedTraceableBox<Heap<T>> -where - Heap<T>: JSTraceable + 'static, - T: GCMethods + Copy, -{ - pub(crate) fn handle(&self) -> Handle<T> { - self.0.handle() - } -} - -impl<T: JSTraceable + MallocSizeOf> MallocSizeOf for RootedTraceableBox<T> { - fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { - // Briefly resurrect the real Box value so we can rely on the existing calculations. - // Then immediately forget about it again to avoid dropping the box. - let inner = unsafe { Box::from_raw(self.0.ptr()) }; - let size = inner.size_of(ops); - mem::forget(inner); - size - } -} - -impl<T: JSTraceable + Default> Default for RootedTraceableBox<T> { - fn default() -> RootedTraceableBox<T> { - RootedTraceableBox::new(T::default()) - } -} - -impl<T: JSTraceable> Deref for RootedTraceableBox<T> { - type Target = T; - fn deref(&self) -> &T { - self.0.deref() - } -} - -impl<T: JSTraceable> DerefMut for RootedTraceableBox<T> { - fn deref_mut(&mut self) -> &mut T { - self.0.deref_mut() - } -} diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs index 5f16d3a96d2..f97a7d9a130 100644 --- a/components/script/dom/bindings/utils.rs +++ b/components/script/dom/bindings/utils.rs @@ -6,17 +6,15 @@ use std::cell::RefCell; use std::thread::LocalKey; -use std::{ptr, slice}; use js::conversions::ToJSValConvertible; use js::glue::{IsWrapper, JSPrincipalsCallbacks, UnwrapObjectDynamic, UnwrapObjectStatic}; use js::jsapi::{ - CallArgs, DOMCallbacks, HandleId as RawHandleId, HandleObject as RawHandleObject, - JS_DeprecatedStringHasLatin1Chars, JS_EnumerateStandardClasses, JS_FreezeObject, - JS_GetLatin1StringCharsAndLength, JS_IsGlobalObject, JS_ResolveStandardClass, JSContext, - JSObject, MutableHandleIdVector as RawMutableHandleIdVector, + CallArgs, DOMCallbacks, HandleObject as RawHandleObject, JS_FreezeObject, JSContext, JSObject, }; -use js::rust::{Handle, HandleObject, MutableHandleValue, get_object_class, is_dom_class}; +use js::rust::{HandleObject, MutableHandleValue, get_object_class, is_dom_class}; +use script_bindings::interfaces::DomHelpers; +use script_bindings::settings_stack::StackEntry; use crate::DomTypes; use crate::dom::bindings::codegen::{InterfaceObjectMap, PrototypeList}; @@ -29,7 +27,7 @@ use crate::dom::bindings::principals::PRINCIPALS_CALLBACKS; use crate::dom::bindings::proxyhandler::is_platform_object_same_origin; use crate::dom::bindings::reflector::{DomObject, DomObjectWrap, reflect_dom_object}; use crate::dom::bindings::root::DomRoot; -use crate::dom::bindings::settings_stack::{self, StackEntry}; +use crate::dom::bindings::settings_stack; use crate::dom::globalscope::GlobalScope; use crate::dom::windowproxy::WindowProxyHandler; use crate::realms::InRealm; @@ -105,61 +103,6 @@ fn is_platform_object( } } -/// Enumerate lazy properties of a global object. -pub(crate) unsafe extern "C" fn enumerate_global<D: DomTypes>( - cx: *mut JSContext, - obj: RawHandleObject, - _props: RawMutableHandleIdVector, - _enumerable_only: bool, -) -> bool { - assert!(JS_IsGlobalObject(obj.get())); - if !JS_EnumerateStandardClasses(cx, obj) { - return false; - } - for init_fun in <D as DomHelpers<D>>::interface_map().values() { - init_fun(SafeJSContext::from_ptr(cx), Handle::from_raw(obj)); - } - true -} - -/// Resolve a lazy global property, for interface objects and named constructors. -pub(crate) unsafe extern "C" fn resolve_global<D: DomTypes>( - cx: *mut JSContext, - obj: RawHandleObject, - id: RawHandleId, - rval: *mut bool, -) -> bool { - assert!(JS_IsGlobalObject(obj.get())); - if !JS_ResolveStandardClass(cx, obj, id, rval) { - return false; - } - if *rval { - return true; - } - if !id.is_string() { - *rval = false; - return true; - } - - let string = id.to_string(); - if !JS_DeprecatedStringHasLatin1Chars(string) { - *rval = false; - return true; - } - let mut length = 0; - let ptr = JS_GetLatin1StringCharsAndLength(cx, ptr::null(), string, &mut length); - assert!(!ptr.is_null()); - let bytes = slice::from_raw_parts(ptr, length); - - if let Some(init_fun) = <D as DomHelpers<D>>::interface_map().get(bytes) { - init_fun(SafeJSContext::from_ptr(cx), Handle::from_raw(obj)); - *rval = true; - } else { - *rval = false; - } - true -} - unsafe extern "C" fn instance_class_has_proto_at_depth( clasp: *const js::jsapi::JSClass, proto_id: u32, @@ -175,48 +118,6 @@ pub(crate) const DOM_CALLBACKS: DOMCallbacks = DOMCallbacks { instanceClassMatchesProto: Some(instance_class_has_proto_at_depth), }; -/// Operations that must be invoked from the generated bindings. -pub(crate) trait DomHelpers<D: DomTypes> { - fn throw_dom_exception( - cx: SafeJSContext, - global: &D::GlobalScope, - result: Error, - can_gc: CanGc, - ); - - unsafe fn call_html_constructor<T: DerivedFrom<D::Element> + DomObject>( - cx: SafeJSContext, - args: &CallArgs, - global: &D::GlobalScope, - proto_id: crate::dom::bindings::codegen::PrototypeList::ID, - creator: unsafe fn(SafeJSContext, HandleObject, *mut ProtoOrIfaceArray), - can_gc: CanGc, - ) -> bool; - - fn settings_stack() -> &'static LocalKey<RefCell<Vec<StackEntry<D>>>>; - - fn principals_callbacks() -> &'static JSPrincipalsCallbacks; - - fn is_platform_object_same_origin(cx: SafeJSContext, obj: RawHandleObject) -> bool; - - fn interface_map() -> &'static phf::Map<&'static [u8], for<'a> fn(SafeJSContext, HandleObject)>; - - fn push_new_element_queue(); - fn pop_current_element_queue(can_gc: CanGc); - - fn reflect_dom_object<T, U>(obj: Box<T>, global: &U, can_gc: CanGc) -> DomRoot<T> - where - T: DomObject + DomObjectWrap<D>, - U: DerivedFrom<D::GlobalScope>; - - fn report_pending_exception( - cx: SafeJSContext, - dispatch_event: bool, - realm: InRealm, - can_gc: CanGc, - ); -} - impl DomHelpers<crate::DomTypeHolder> for crate::DomTypeHolder { fn throw_dom_exception( cx: SafeJSContext, @@ -227,7 +128,7 @@ impl DomHelpers<crate::DomTypeHolder> for crate::DomTypeHolder { throw_dom_exception(cx, global, result, can_gc) } - unsafe fn call_html_constructor< + fn call_html_constructor< T: DerivedFrom<<crate::DomTypeHolder as DomTypes>::Element> + DomObject, >( cx: SafeJSContext, diff --git a/components/script/dom/bindings/weakref.rs b/components/script/dom/bindings/weakref.rs index 1c86b68c706..c1cb012b7c2 100644 --- a/components/script/dom/bindings/weakref.rs +++ b/components/script/dom/bindings/weakref.rs @@ -8,7 +8,7 @@ use std::ops::{Deref, DerefMut, Drop}; use js::jsapi::JSTracer; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; -pub use script_bindings::weakref::*; +pub(crate) use script_bindings::weakref::*; use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::root::DomRoot; |