diff --git a/components/script/dom/bindings/error.rs b/components/script/dom/bindings/error.rs index 779cc04c28b..8d09a4ad8d9 100644 --- a/components/script/dom/bindings/error.rs +++ b/components/script/dom/bindings/error.rs @@ -16,6 +16,7 @@ use js::jsval::UndefinedValue; use js::rust::wrappers::{JS_ErrorFromException, JS_GetPendingException, JS_SetPendingException}; use js::rust::{HandleObject, HandleValue, MutableHandleValue}; use libc::c_uint; +pub(crate) use script_bindings::error::*; #[cfg(feature = "js_backtrace")] use crate::dom::bindings::cell::DomRefCell; @@ -36,74 +37,6 @@ thread_local! { static LAST_EXCEPTION_BACKTRACE: DomRefCell, String)>> = DomRefCell::new(None); } -/// DOM exceptions that can be thrown by a native DOM method. -#[derive(Clone, Debug, MallocSizeOf)] -pub(crate) enum Error { - /// IndexSizeError DOMException - IndexSize, - /// NotFoundError DOMException - NotFound, - /// HierarchyRequestError DOMException - HierarchyRequest, - /// WrongDocumentError DOMException - WrongDocument, - /// InvalidCharacterError DOMException - InvalidCharacter, - /// NotSupportedError DOMException - NotSupported, - /// InUseAttributeError DOMException - InUseAttribute, - /// InvalidStateError DOMException - InvalidState, - /// SyntaxError DOMException - Syntax, - /// NamespaceError DOMException - Namespace, - /// InvalidAccessError DOMException - InvalidAccess, - /// SecurityError DOMException - Security, - /// NetworkError DOMException - Network, - /// AbortError DOMException - Abort, - /// TimeoutError DOMException - Timeout, - /// InvalidNodeTypeError DOMException - InvalidNodeType, - /// DataCloneError DOMException - DataClone, - /// NoModificationAllowedError DOMException - NoModificationAllowed, - /// QuotaExceededError DOMException - QuotaExceeded, - /// TypeMismatchError DOMException - TypeMismatch, - /// InvalidModificationError DOMException - InvalidModification, - /// NotReadableError DOMException - NotReadable, - /// DataError DOMException - Data, - /// OperationError DOMException - Operation, - - /// TypeError JavaScript Error - Type(String), - /// RangeError JavaScript Error - Range(String), - - /// A JavaScript exception is already pending. - JSFailed, -} - -/// The return type for IDL operations that can throw DOM exceptions. -pub(crate) type Fallible = Result; - -/// The return type for IDL operations that can throw DOM exceptions and -/// return `()`. -pub(crate) type ErrorResult = Fallible<()>; - /// Set a pending exception for the given `result` on `cx`. pub(crate) fn throw_dom_exception( cx: SafeJSContext, @@ -341,15 +274,14 @@ pub(crate) fn throw_constructor_without_new(cx: SafeJSContext, name: &str) { unsafe { throw_type_error(*cx, &error) }; } -impl Error { +pub(crate) trait ErrorToJsval { + fn to_jsval(self, cx: SafeJSContext, global: &GlobalScope, rval: MutableHandleValue); +} + +impl ErrorToJsval for Error { /// Convert this error value to a JS value, consuming it in the process. #[allow(clippy::wrong_self_convention)] - pub(crate) fn to_jsval( - self, - cx: SafeJSContext, - global: &GlobalScope, - rval: MutableHandleValue, - ) { + fn to_jsval(self, cx: SafeJSContext, global: &GlobalScope, rval: MutableHandleValue) { match self { Error::JSFailed => (), _ => unsafe { assert!(!JS_IsExceptionPending(*cx)) }, diff --git a/components/script/dom/bindings/iterable.rs b/components/script/dom/bindings/iterable.rs index 4b932dfc262..ddb45348de3 100644 --- a/components/script/dom/bindings/iterable.rs +++ b/components/script/dom/bindings/iterable.rs @@ -17,6 +17,7 @@ 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::dom::bindings::codegen::Bindings::IterableIteratorBinding::{ @@ -31,31 +32,6 @@ use crate::dom::bindings::trace::{JSTraceable, NoTrace, RootedTraceableBox}; use crate::script_runtime::{CanGc, JSContext}; use crate::DomTypes; -/// The values that an iterator will iterate over. -#[derive(JSTraceable, MallocSizeOf)] -pub(crate) enum IteratorType { - /// The keys of the iterable object. - Keys, - /// The values of the iterable object. - Values, - /// The keys and values of the iterable object combined. - Entries, -} - -/// A DOM object that can be iterated over using a pair value iterator. -pub(crate) trait Iterable { - /// The type of the key of the iterator pair. - type Key: ToJSValConvertible; - /// The type of the value of the iterator pair. - type Value: ToJSValConvertible; - /// Return the number of entries that can be iterated over. - fn get_iterable_length(&self) -> u32; - /// Return the value at the provided index. - fn get_value_at_index(&self, index: u32) -> Self::Value; - /// Return the key at the provided index. - fn get_key_at_index(&self, index: u32) -> Self::Key; -} - /// An iterator over the iterable entries of a given DOM interface. #[dom_struct] pub(crate) struct IterableIterator< @@ -162,14 +138,6 @@ impl + JSTraceable + Iterable + DomGlob ) -> Root> = T::ITER_WRAP; } -/// A version of the [IDLInterface] trait that is specific to types that have -/// iterators defined for them. This allows the `script` crate to define the -/// derives check for the concrete interface type, while the [IteratableIterator] -/// type defined in this module can be parameterized over an unknown generic. -pub trait IteratorDerives { - fn derives(class: &'static DOMClass) -> bool; -} - fn dict_return( cx: JSContext, mut result: MutableHandleObject, diff --git a/components/script/dom/bindings/like.rs b/components/script/dom/bindings/like.rs index 23e075629b8..8743b0e1003 100644 --- a/components/script/dom/bindings/like.rs +++ b/components/script/dom/bindings/like.rs @@ -11,67 +11,10 @@ use std::hash::Hash; use indexmap::{IndexMap, IndexSet}; use js::conversions::ToJSValConvertible; +pub(crate) use script_bindings::like::*; -use super::iterable::Iterable; use crate::dom::bindings::cell::DomRefCell; -/// Every Setlike dom_struct must implement this to provide access to underlying storage -/// so codegen can automatically generate all setlike methods -/// -/// In case you use a type that implements Setlike as underlying storage it's recommended to use `setlike` macro. -// In webidl: `setlike` -pub(crate) trait Setlike { - /// The type of the key of the set. - type Key: ToJSValConvertible + Clone; // clone is for impl Maplike for T - - fn get_index(&self, index: u32) -> Option; - - fn size(&self) -> u32; - fn add(&self, key: Self::Key); - fn has(&self, key: Self::Key) -> bool; - fn clear(&self); - fn delete(&self, key: Self::Key) -> bool; -} - -// we can only have one iterable for T -// so we have impl Iterable for T -// and minimal: -impl Maplike for T { - type Key = ::Key; - - type Value = ::Key; - - #[inline] - fn get_index(&self, index: u32) -> Option<(Self::Key, Self::Value)> { - self.get_index(index).map(|k| (k.clone(), k)) - } - - fn get(&self, _key: Self::Key) -> Option { - unimplemented!() - } - - #[inline] - fn size(&self) -> u32 { - self.size() - } - - fn set(&self, _key: Self::Key, _value: Self::Value) { - unimplemented!() - } - - fn has(&self, _key: Self::Key) -> bool { - unimplemented!() - } - - fn clear(&self) { - unimplemented!() - } - - fn delete(&self, _key: Self::Key) -> bool { - unimplemented!() - } -} - impl Setlike for DomRefCell> where K: ToJSValConvertible + Eq + PartialEq + Hash + Clone, @@ -155,51 +98,6 @@ macro_rules! setlike { }; } -/// Every Maplike dom_struct must implement this -/// to provide access to underlying storage -/// so codegen can automatically generate all maplike methods -/// -/// In case you use a type that implements Maplike as underlying storage it's recommended to use `maplike` macro. -// In webidl: `maplike` -pub(crate) trait Maplike { - /// The type of the key of the map. - type Key: ToJSValConvertible; - /// The type of the value of the map. - type Value: ToJSValConvertible; - - fn get_index(&self, index: u32) -> Option<(Self::Key, Self::Value)>; - - fn get(&self, key: Self::Key) -> Option; - fn size(&self) -> u32; - fn set(&self, key: Self::Key, value: Self::Value); - fn has(&self, key: Self::Key) -> bool; - fn clear(&self); - fn delete(&self, key: Self::Key) -> bool; -} - -impl Iterable for T { - type Key = T::Key; - - type Value = T::Value; - - #[inline] - fn get_iterable_length(&self) -> u32 { - self.size() - } - - #[inline] - fn get_value_at_index(&self, index: u32) -> Self::Value { - // SAFETY: we are checking bounds manually - self.get_index(index).unwrap().1 - } - - #[inline] - fn get_key_at_index(&self, index: u32) -> Self::Key { - // SAFETY: we are checking bounds manually - self.get_index(index).unwrap().0 - } -} - impl Maplike for DomRefCell> where K: ToJSValConvertible + Eq + PartialEq + Hash + Clone, diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index a25cfa83774..0497614c533 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -60,7 +60,6 @@ use tendril::TendrilSink; use webxr_api::{Finger, Hand}; use crate::dom::bindings::cell::DomRefCell; -use crate::dom::bindings::error::Error; use crate::dom::bindings::refcounted::{Trusted, TrustedPromise}; use crate::dom::bindings::reflector::DomObject; use crate::dom::htmlimageelement::SourceSet; @@ -352,7 +351,6 @@ where } } -unsafe_no_jsmanaged_fields!(Error); unsafe_no_jsmanaged_fields!(TrustedPromise); unsafe_no_jsmanaged_fields!(WindowProxyHandler); diff --git a/components/script/dom/bindings/weakref.rs b/components/script/dom/bindings/weakref.rs index dccbb608595..1c86b68c706 100644 --- a/components/script/dom/bindings/weakref.rs +++ b/components/script/dom/bindings/weakref.rs @@ -2,169 +2,18 @@ * 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/. */ -//! Weak-referenceable JS-managed DOM objects. -//! -//! IDL interfaces marked as `weakReferenceable` in `Bindings.conf` -//! automatically implement the `WeakReferenceable` trait in codegen. -//! The instance object is responsible for setting `None` in its own -//! own `WeakBox` when it is collected, through the `DOM_WEAK_SLOT` -//! slot. When all associated `WeakRef` values are dropped, the -//! `WeakBox` itself is dropped too. - -use std::cell::{Cell, UnsafeCell}; +use std::cell::UnsafeCell; +use std::mem; use std::ops::{Deref, DerefMut, Drop}; -use std::{mem, ptr}; -use js::glue::JS_GetReservedSlot; -use js::jsapi::{JSTracer, JS_SetReservedSlot}; -use js::jsval::{PrivateValue, UndefinedValue}; -use libc::c_void; +use js::jsapi::JSTracer; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; +pub use script_bindings::weakref::*; use crate::dom::bindings::cell::DomRefCell; -use crate::dom::bindings::reflector::DomObject; use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::trace::JSTraceable; -/// The index of the slot wherein a pointer to the weak holder cell is -/// stored for weak-referenceable bindings. We use slot 1 for holding it, -/// this is unsafe for globals, we disallow weak-referenceable globals -/// directly in codegen. -pub(crate) const DOM_WEAK_SLOT: u32 = 1; - -/// A weak reference to a JS-managed DOM object. -#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)] -pub(crate) struct WeakRef { - ptr: ptr::NonNull>, -} - -/// The inner box of weak references, public for the finalization in codegen. -#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)] -pub(crate) struct WeakBox { - /// The reference count. When it reaches zero, the `value` field should - /// have already been set to `None`. The pointee contributes one to the count. - pub(crate) count: Cell, - /// The pointer to the JS-managed object, set to None when it is collected. - pub(crate) value: Cell>>, -} - -/// Trait implemented by weak-referenceable interfaces. -pub(crate) trait WeakReferenceable: DomObject + Sized { - /// Downgrade a DOM object reference to a weak one. - fn downgrade(&self) -> WeakRef { - unsafe { - let object = self.reflector().get_jsobject().get(); - let mut slot = UndefinedValue(); - JS_GetReservedSlot(object, DOM_WEAK_SLOT, &mut slot); - let mut ptr = slot.to_private() as *mut WeakBox; - if ptr.is_null() { - trace!("Creating new WeakBox holder for {:p}.", self); - ptr = Box::into_raw(Box::new(WeakBox { - count: Cell::new(1), - value: Cell::new(Some(ptr::NonNull::from(self))), - })); - let val = PrivateValue(ptr as *const c_void); - JS_SetReservedSlot(object, DOM_WEAK_SLOT, &val); - } - let box_ = &*ptr; - assert!(box_.value.get().is_some()); - let new_count = box_.count.get() + 1; - trace!( - "Incrementing WeakBox refcount for {:p} to {}.", - self, - new_count - ); - box_.count.set(new_count); - WeakRef { - ptr: ptr::NonNull::new_unchecked(ptr), - } - } - } -} - -impl WeakRef { - /// Create a new weak reference from a `WeakReferenceable` interface instance. - /// This is just a convenience wrapper around `::downgrade` - /// to not have to import `WeakReferenceable`. - pub(crate) fn new(value: &T) -> Self { - value.downgrade() - } - - /// DomRoot a weak reference. Returns `None` if the object was already collected. - pub(crate) fn root(&self) -> Option> { - unsafe { &*self.ptr.as_ptr() } - .value - .get() - .map(|ptr| unsafe { DomRoot::from_ref(&*ptr.as_ptr()) }) - } - - /// Return whether the weakly-referenced object is still alive. - pub(crate) fn is_alive(&self) -> bool { - unsafe { &*self.ptr.as_ptr() }.value.get().is_some() - } -} - -impl Clone for WeakRef { - fn clone(&self) -> WeakRef { - unsafe { - let box_ = &*self.ptr.as_ptr(); - let new_count = box_.count.get() + 1; - box_.count.set(new_count); - WeakRef { ptr: self.ptr } - } - } -} - -impl MallocSizeOf for WeakRef { - fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize { - 0 - } -} - -impl PartialEq for WeakRef { - fn eq(&self, other: &Self) -> bool { - unsafe { - (*self.ptr.as_ptr()).value.get().map(ptr::NonNull::as_ptr) == - (*other.ptr.as_ptr()).value.get().map(ptr::NonNull::as_ptr) - } - } -} - -impl PartialEq for WeakRef { - fn eq(&self, other: &T) -> bool { - unsafe { - match self.ptr.as_ref().value.get() { - Some(ptr) => ptr::eq(ptr.as_ptr(), other), - None => false, - } - } - } -} - -unsafe impl JSTraceable for WeakRef { - unsafe fn trace(&self, _: *mut JSTracer) { - // Do nothing. - } -} - -impl Drop for WeakRef { - fn drop(&mut self) { - unsafe { - let (count, value) = { - let weak_box = &*self.ptr.as_ptr(); - assert!(weak_box.count.get() > 0); - let count = weak_box.count.get() - 1; - weak_box.count.set(count); - (count, weak_box.value.get()) - }; - if count == 0 { - assert!(value.is_none()); - mem::drop(Box::from_raw(self.ptr.as_ptr())); - } - } - } -} - /// A mutable weak reference to a JS-managed DOM object. On tracing, /// the contained weak reference is dropped if the pointee was already /// collected. diff --git a/components/script/dom/cssrulelist.rs b/components/script/dom/cssrulelist.rs index fc4eeb9c6e8..678f04d45bb 100644 --- a/components/script/dom/cssrulelist.rs +++ b/components/script/dom/cssrulelist.rs @@ -12,6 +12,7 @@ use style::stylesheets::{ RulesMutateError, StylesheetLoader as StyleStylesheetLoader, }; +use crate::conversions::Convert; use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::CSSRuleListBinding::CSSRuleListMethods; use crate::dom::bindings::error::{Error, ErrorResult, Fallible}; @@ -27,9 +28,9 @@ use crate::stylesheet_loader::StylesheetLoader; unsafe_no_jsmanaged_fields!(RulesSource); -impl From for Error { - fn from(other: RulesMutateError) -> Self { - match other { +impl Convert for RulesMutateError { + fn convert(self) -> Error { + match self { RulesMutateError::Syntax => Error::Syntax, RulesMutateError::IndexSize => Error::IndexSize, RulesMutateError::HierarchyRequest => Error::HierarchyRequest, @@ -124,16 +125,18 @@ impl CSSRuleList { let loader = owner .as_ref() .map(|element| StylesheetLoader::for_element(element)); - let new_rule = css_rules.insert_rule( - &parent_stylesheet.shared_lock, - rule, - &parent_stylesheet.contents, - index, - containing_rule_types, - parse_relative_rule_type, - loader.as_ref().map(|l| l as &dyn StyleStylesheetLoader), - AllowImportRules::Yes, - )?; + let new_rule = css_rules + .insert_rule( + &parent_stylesheet.shared_lock, + rule, + &parent_stylesheet.contents, + index, + containing_rule_types, + parse_relative_rule_type, + loader.as_ref().map(|l| l as &dyn StyleStylesheetLoader), + AllowImportRules::Yes, + ) + .map_err(Convert::convert)?; let parent_stylesheet = &*self.parent_stylesheet; let dom_rule = CSSRule::new_specific(window, parent_stylesheet, new_rule, can_gc); @@ -150,7 +153,10 @@ impl CSSRuleList { match self.rules { RulesSource::Rules(ref css_rules) => { - css_rules.write_with(&mut guard).remove_rule(index)?; + css_rules + .write_with(&mut guard) + .remove_rule(index) + .map_err(Convert::convert)?; let mut dom_rules = self.dom_rules.borrow_mut(); if let Some(r) = dom_rules[index].get() { r.detach() diff --git a/components/script/dom/promise.rs b/components/script/dom/promise.rs index 49d639753c5..0a586b5ba6f 100644 --- a/components/script/dom/promise.rs +++ b/components/script/dom/promise.rs @@ -31,7 +31,7 @@ use js::rust::wrappers::{ use js::rust::{HandleObject, HandleValue, MutableHandleObject, Runtime}; use crate::dom::bindings::conversions::root_from_object; -use crate::dom::bindings::error::Error; +use crate::dom::bindings::error::{Error, ErrorToJsval}; use crate::dom::bindings::reflector::{DomGlobal, DomObject, MutDomObject, Reflector}; use crate::dom::bindings::settings_stack::AutoEntryScript; use crate::dom::globalscope::GlobalScope; diff --git a/components/script/dom/readablestream.rs b/components/script/dom/readablestream.rs index 42a63d8e40d..41115d42bec 100644 --- a/components/script/dom/readablestream.rs +++ b/components/script/dom/readablestream.rs @@ -24,7 +24,7 @@ use crate::dom::bindings::codegen::Bindings::ReadableStreamDefaultReaderBinding: use crate::dom::bindings::codegen::Bindings::ReadableStreamDefaultControllerBinding::ReadableStreamDefaultController_Binding::ReadableStreamDefaultControllerMethods; use crate::dom::bindings::codegen::Bindings::UnderlyingSourceBinding::UnderlyingSource as JsUnderlyingSource; use crate::dom::bindings::conversions::{ConversionBehavior, ConversionResult}; -use crate::dom::bindings::error::Error; +use crate::dom::bindings::error::{Error, ErrorToJsval}; use crate::dom::bindings::import::module::Fallible; use crate::dom::bindings::codegen::UnionTypes::ReadableStreamDefaultReaderOrReadableStreamBYOBReader as ReadableStreamReader; use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object_with_proto}; diff --git a/components/script/dom/readablestreambyobreader.rs b/components/script/dom/readablestreambyobreader.rs index cd8862d30c9..8053a0523ea 100644 --- a/components/script/dom/readablestreambyobreader.rs +++ b/components/script/dom/readablestreambyobreader.rs @@ -21,7 +21,7 @@ use super::bindings::reflector::reflect_dom_object; use super::readablestreamgenericreader::ReadableStreamGenericReader; use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::ReadableStreamBYOBReaderBinding::ReadableStreamBYOBReaderMethods; -use crate::dom::bindings::error::Error; +use crate::dom::bindings::error::{Error, ErrorToJsval}; use crate::dom::bindings::import::module::Fallible; use crate::dom::bindings::reflector::{reflect_dom_object_with_proto, DomGlobal, Reflector}; use crate::dom::bindings::root::{DomRoot, MutNullableDom}; diff --git a/components/script/dom/readablestreamdefaultcontroller.rs b/components/script/dom/readablestreamdefaultcontroller.rs index 56f32a53195..628c7f6501c 100644 --- a/components/script/dom/readablestreamdefaultcontroller.rs +++ b/components/script/dom/readablestreamdefaultcontroller.rs @@ -20,7 +20,7 @@ use crate::dom::bindings::buffer_source::create_buffer_source; use crate::dom::bindings::callback::ExceptionHandling; use crate::dom::bindings::codegen::Bindings::ReadableStreamDefaultControllerBinding::ReadableStreamDefaultControllerMethods; use crate::dom::bindings::codegen::UnionTypes::ReadableStreamDefaultControllerOrReadableByteStreamController as Controller; -use crate::dom::bindings::import::module::{throw_dom_exception, Error, Fallible}; +use crate::dom::bindings::error::{throw_dom_exception, Error, ErrorToJsval, Fallible}; use crate::dom::bindings::reflector::{reflect_dom_object, DomGlobal, Reflector}; use crate::dom::bindings::root::{DomRoot, MutNullableDom}; use crate::dom::bindings::trace::RootedTraceableBox; diff --git a/components/script/dom/readablestreamdefaultreader.rs b/components/script/dom/readablestreamdefaultreader.rs index 0d681b80de8..d233b17a35e 100644 --- a/components/script/dom/readablestreamdefaultreader.rs +++ b/components/script/dom/readablestreamdefaultreader.rs @@ -19,7 +19,7 @@ use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::ReadableStreamDefaultReaderBinding::{ ReadableStreamDefaultReaderMethods, ReadableStreamReadResult, }; -use crate::dom::bindings::error::Error; +use crate::dom::bindings::error::{Error, ErrorToJsval}; use crate::dom::bindings::import::module::Fallible; use crate::dom::bindings::reflector::{reflect_dom_object_with_proto, DomGlobal, Reflector}; use crate::dom::bindings::root::{Dom, DomRoot}; diff --git a/components/script/dom/readablestreamgenericreader.rs b/components/script/dom/readablestreamgenericreader.rs index 42fe2819cb4..c7ed8c1f008 100644 --- a/components/script/dom/readablestreamgenericreader.rs +++ b/components/script/dom/readablestreamgenericreader.rs @@ -9,7 +9,7 @@ use js::rust::HandleValue as SafeHandleValue; use super::readablestream::ReaderType; use super::types::ReadableStream; -use crate::dom::bindings::error::Error; +use crate::dom::bindings::error::{Error, ErrorToJsval}; use crate::dom::bindings::import::module::Fallible; use crate::dom::bindings::reflector::DomGlobal; use crate::dom::bindings::root::{DomRoot, MutNullableDom}; diff --git a/components/script/dom/writablestreamdefaultcontroller.rs b/components/script/dom/writablestreamdefaultcontroller.rs index 8a069a41941..7f39c4c39e3 100644 --- a/components/script/dom/writablestreamdefaultcontroller.rs +++ b/components/script/dom/writablestreamdefaultcontroller.rs @@ -18,7 +18,7 @@ use crate::dom::bindings::codegen::Bindings::UnderlyingSinkBinding::{ UnderlyingSinkStartCallback, UnderlyingSinkWriteCallback, }; use crate::dom::bindings::codegen::Bindings::WritableStreamDefaultControllerBinding::WritableStreamDefaultControllerMethods; -use crate::dom::bindings::error::Error; +use crate::dom::bindings::error::{Error, ErrorToJsval}; use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; use crate::dom::globalscope::GlobalScope; diff --git a/components/script/dom/writablestreamdefaultwriter.rs b/components/script/dom/writablestreamdefaultwriter.rs index 1a76a23d241..ab26a752804 100644 --- a/components/script/dom/writablestreamdefaultwriter.rs +++ b/components/script/dom/writablestreamdefaultwriter.rs @@ -10,7 +10,7 @@ use js::jsval::UndefinedValue; use js::rust::{HandleObject as SafeHandleObject, HandleValue as SafeHandleValue}; use crate::dom::bindings::codegen::Bindings::WritableStreamDefaultWriterBinding::WritableStreamDefaultWriterMethods; -use crate::dom::bindings::error::Error; +use crate::dom::bindings::error::{Error, ErrorToJsval}; use crate::dom::bindings::reflector::{reflect_dom_object_with_proto, DomGlobal, Reflector}; use crate::dom::bindings::root::{DomRoot, MutNullableDom}; use crate::dom::globalscope::GlobalScope; diff --git a/components/script/script_module.rs b/components/script/script_module.rs index ffe6560b59a..694431e8c06 100644 --- a/components/script/script_module.rs +++ b/components/script/script_module.rs @@ -50,7 +50,7 @@ use crate::document_loader::LoadType; use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::WindowBinding::Window_Binding::WindowMethods; use crate::dom::bindings::conversions::jsstring_to_str; -use crate::dom::bindings::error::{report_pending_exception, Error}; +use crate::dom::bindings::error::{report_pending_exception, Error, ErrorToJsval}; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::refcounted::Trusted; use crate::dom::bindings::reflector::{DomGlobal, DomObject}; diff --git a/components/script_bindings/error.rs b/components/script_bindings/error.rs new file mode 100644 index 00000000000..bd8a5b0cb95 --- /dev/null +++ b/components/script_bindings/error.rs @@ -0,0 +1,71 @@ +/* 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/. */ + +/// DOM exceptions that can be thrown by a native DOM method. +#[derive(Clone, Debug, MallocSizeOf)] +pub enum Error { + /// IndexSizeError DOMException + IndexSize, + /// NotFoundError DOMException + NotFound, + /// HierarchyRequestError DOMException + HierarchyRequest, + /// WrongDocumentError DOMException + WrongDocument, + /// InvalidCharacterError DOMException + InvalidCharacter, + /// NotSupportedError DOMException + NotSupported, + /// InUseAttributeError DOMException + InUseAttribute, + /// InvalidStateError DOMException + InvalidState, + /// SyntaxError DOMException + Syntax, + /// NamespaceError DOMException + Namespace, + /// InvalidAccessError DOMException + InvalidAccess, + /// SecurityError DOMException + Security, + /// NetworkError DOMException + Network, + /// AbortError DOMException + Abort, + /// TimeoutError DOMException + Timeout, + /// InvalidNodeTypeError DOMException + InvalidNodeType, + /// DataCloneError DOMException + DataClone, + /// NoModificationAllowedError DOMException + NoModificationAllowed, + /// QuotaExceededError DOMException + QuotaExceeded, + /// TypeMismatchError DOMException + TypeMismatch, + /// InvalidModificationError DOMException + InvalidModification, + /// NotReadableError DOMException + NotReadable, + /// DataError DOMException + Data, + /// OperationError DOMException + Operation, + + /// TypeError JavaScript Error + Type(String), + /// RangeError JavaScript Error + Range(String), + + /// A JavaScript exception is already pending. + JSFailed, +} + +/// The return type for IDL operations that can throw DOM exceptions. +pub type Fallible = Result; + +/// The return type for IDL operations that can throw DOM exceptions and +/// return `()`. +pub type ErrorResult = Fallible<()>; diff --git a/components/script_bindings/iterable.rs b/components/script_bindings/iterable.rs new file mode 100644 index 00000000000..61cd4540bae --- /dev/null +++ b/components/script_bindings/iterable.rs @@ -0,0 +1,40 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use js::conversions::ToJSValConvertible; + +use crate::utils::DOMClass; + +/// The values that an iterator will iterate over. +#[derive(JSTraceable, MallocSizeOf)] +pub enum IteratorType { + /// The keys of the iterable object. + Keys, + /// The values of the iterable object. + Values, + /// The keys and values of the iterable object combined. + Entries, +} + +/// A DOM object that can be iterated over using a pair value iterator. +pub trait Iterable { + /// The type of the key of the iterator pair. + type Key: ToJSValConvertible; + /// The type of the value of the iterator pair. + type Value: ToJSValConvertible; + /// Return the number of entries that can be iterated over. + fn get_iterable_length(&self) -> u32; + /// Return the value at the provided index. + fn get_value_at_index(&self, index: u32) -> Self::Value; + /// Return the key at the provided index. + fn get_key_at_index(&self, index: u32) -> Self::Key; +} + +/// A version of the [IDLInterface] trait that is specific to types that have +/// iterators defined for them. This allows the `script` crate to define the +/// derives check for the concrete interface type, while the [IteratableIterator] +/// type defined in this module can be parameterized over an unknown generic. +pub trait IteratorDerives { + fn derives(class: &'static DOMClass) -> bool; +} diff --git a/components/script_bindings/lib.rs b/components/script_bindings/lib.rs index 7503580b73d..8090144b73b 100644 --- a/components/script_bindings/lib.rs +++ b/components/script_bindings/lib.rs @@ -20,13 +20,17 @@ extern crate malloc_size_of_derive; pub mod callback; pub mod constant; pub mod conversions; +pub mod error; pub mod inheritance; +pub mod iterable; +pub mod like; pub mod reflector; pub mod root; pub mod script_runtime; pub mod str; pub mod trace; pub mod utils; +pub mod weakref; #[allow(non_snake_case)] pub mod codegen { diff --git a/components/script_bindings/like.rs b/components/script_bindings/like.rs new file mode 100644 index 00000000000..c2b14fb39fb --- /dev/null +++ b/components/script_bindings/like.rs @@ -0,0 +1,111 @@ +/* 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/. */ + +//! Implementation of `setlike<...>` and `maplike<..., ...>` WebIDL declarations. + +use js::conversions::ToJSValConvertible; + +use crate::iterable::Iterable; + +/// Every Setlike dom_struct must implement this to provide access to underlying storage +/// so codegen can automatically generate all setlike methods +/// +/// In case you use a type that implements Setlike as underlying storage it's recommended to use `setlike` macro. +// In webidl: `setlike` +pub trait Setlike { + /// The type of the key of the set. + type Key: ToJSValConvertible + Clone; // clone is for impl Maplike for T + + fn get_index(&self, index: u32) -> Option; + + fn size(&self) -> u32; + fn add(&self, key: Self::Key); + fn has(&self, key: Self::Key) -> bool; + fn clear(&self); + fn delete(&self, key: Self::Key) -> bool; +} + +// we can only have one iterable for T +// so we have impl Iterable for T +// and minimal: +impl Maplike for T { + type Key = ::Key; + + type Value = ::Key; + + #[inline] + fn get_index(&self, index: u32) -> Option<(Self::Key, Self::Value)> { + self.get_index(index).map(|k| (k.clone(), k)) + } + + fn get(&self, _key: Self::Key) -> Option { + unimplemented!() + } + + #[inline] + fn size(&self) -> u32 { + self.size() + } + + fn set(&self, _key: Self::Key, _value: Self::Value) { + unimplemented!() + } + + fn has(&self, _key: Self::Key) -> bool { + unimplemented!() + } + + fn clear(&self) { + unimplemented!() + } + + fn delete(&self, _key: Self::Key) -> bool { + unimplemented!() + } +} + +/// Every Maplike dom_struct must implement this +/// to provide access to underlying storage +/// so codegen can automatically generate all maplike methods +/// +/// In case you use a type that implements Maplike as underlying storage it's recommended to use `maplike` macro. +// In webidl: `maplike` +pub trait Maplike { + /// The type of the key of the map. + type Key: ToJSValConvertible; + /// The type of the value of the map. + type Value: ToJSValConvertible; + + fn get_index(&self, index: u32) -> Option<(Self::Key, Self::Value)>; + + fn get(&self, key: Self::Key) -> Option; + fn size(&self) -> u32; + fn set(&self, key: Self::Key, value: Self::Value); + fn has(&self, key: Self::Key) -> bool; + fn clear(&self); + fn delete(&self, key: Self::Key) -> bool; +} + +impl Iterable for T { + type Key = T::Key; + + type Value = T::Value; + + #[inline] + fn get_iterable_length(&self) -> u32 { + self.size() + } + + #[inline] + fn get_value_at_index(&self, index: u32) -> ::Value { + // SAFETY: we are checking bounds manually + self.get_index(index).unwrap().1 + } + + #[inline] + fn get_key_at_index(&self, index: u32) -> ::Key { + // SAFETY: we are checking bounds manually + self.get_index(index).unwrap().0 + } +} diff --git a/components/script_bindings/trace.rs b/components/script_bindings/trace.rs index 74d7fe1a932..889e8b73709 100644 --- a/components/script_bindings/trace.rs +++ b/components/script_bindings/trace.rs @@ -5,6 +5,7 @@ use js::glue::CallObjectTracer; use js::jsapi::{GCTraceKindToAscii, Heap, JSObject, JSTracer, TraceKind}; +use crate::error::Error; use crate::reflector::Reflector; use crate::str::{DOMString, USVString}; @@ -51,3 +52,4 @@ macro_rules! unsafe_no_jsmanaged_fields( unsafe_no_jsmanaged_fields!(DOMString); unsafe_no_jsmanaged_fields!(USVString); +unsafe_no_jsmanaged_fields!(Error); diff --git a/components/script_bindings/weakref.rs b/components/script_bindings/weakref.rs new file mode 100644 index 00000000000..9288ef5e589 --- /dev/null +++ b/components/script_bindings/weakref.rs @@ -0,0 +1,165 @@ +/* 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/. */ + +//! Weak-referenceable JS-managed DOM objects. +//! +//! IDL interfaces marked as `weakReferenceable` in `Bindings.conf` +//! automatically implement the `WeakReferenceable` trait in codegen. +//! The instance object is responsible for setting `None` in its own +//! own `WeakBox` when it is collected, through the `DOM_WEAK_SLOT` +//! slot. When all associated `WeakRef` values are dropped, the +//! `WeakBox` itself is dropped too. + +use std::cell::Cell; +use std::ops::Drop; +use std::{mem, ptr}; + +use js::glue::JS_GetReservedSlot; +use js::jsapi::{JSTracer, JS_SetReservedSlot}; +use js::jsval::{PrivateValue, UndefinedValue}; +use libc::c_void; +use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; + +use crate::reflector::DomObject; +use crate::root::DomRoot; +use crate::JSTraceable; + +/// The index of the slot wherein a pointer to the weak holder cell is +/// stored for weak-referenceable bindings. We use slot 1 for holding it, +/// this is unsafe for globals, we disallow weak-referenceable globals +/// directly in codegen. +pub const DOM_WEAK_SLOT: u32 = 1; + +/// A weak reference to a JS-managed DOM object. +#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)] +pub struct WeakRef { + ptr: ptr::NonNull>, +} + +/// The inner box of weak references, public for the finalization in codegen. +#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)] +pub struct WeakBox { + /// The reference count. When it reaches zero, the `value` field should + /// have already been set to `None`. The pointee contributes one to the count. + pub count: Cell, + /// The pointer to the JS-managed object, set to None when it is collected. + pub value: Cell>>, +} + +/// Trait implemented by weak-referenceable interfaces. +pub trait WeakReferenceable: DomObject + Sized { + /// Downgrade a DOM object reference to a weak one. + fn downgrade(&self) -> WeakRef { + unsafe { + let object = self.reflector().get_jsobject().get(); + let mut slot = UndefinedValue(); + JS_GetReservedSlot(object, DOM_WEAK_SLOT, &mut slot); + let mut ptr = slot.to_private() as *mut WeakBox; + if ptr.is_null() { + trace!("Creating new WeakBox holder for {:p}.", self); + ptr = Box::into_raw(Box::new(WeakBox { + count: Cell::new(1), + value: Cell::new(Some(ptr::NonNull::from(self))), + })); + let val = PrivateValue(ptr as *const c_void); + JS_SetReservedSlot(object, DOM_WEAK_SLOT, &val); + } + let box_ = &*ptr; + assert!(box_.value.get().is_some()); + let new_count = box_.count.get() + 1; + trace!( + "Incrementing WeakBox refcount for {:p} to {}.", + self, + new_count + ); + box_.count.set(new_count); + WeakRef { + ptr: ptr::NonNull::new_unchecked(ptr), + } + } + } +} + +impl WeakRef { + /// Create a new weak reference from a `WeakReferenceable` interface instance. + /// This is just a convenience wrapper around `::downgrade` + /// to not have to import `WeakReferenceable`. + pub fn new(value: &T) -> Self { + value.downgrade() + } + + /// DomRoot a weak reference. Returns `None` if the object was already collected. + pub fn root(&self) -> Option> { + unsafe { &*self.ptr.as_ptr() } + .value + .get() + .map(|ptr| unsafe { DomRoot::from_ref(&*ptr.as_ptr()) }) + } + + /// Return whether the weakly-referenced object is still alive. + pub fn is_alive(&self) -> bool { + unsafe { &*self.ptr.as_ptr() }.value.get().is_some() + } +} + +impl Clone for WeakRef { + fn clone(&self) -> WeakRef { + unsafe { + let box_ = &*self.ptr.as_ptr(); + let new_count = box_.count.get() + 1; + box_.count.set(new_count); + WeakRef { ptr: self.ptr } + } + } +} + +impl MallocSizeOf for WeakRef { + fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize { + 0 + } +} + +impl PartialEq for WeakRef { + fn eq(&self, other: &Self) -> bool { + unsafe { + (*self.ptr.as_ptr()).value.get().map(ptr::NonNull::as_ptr) == + (*other.ptr.as_ptr()).value.get().map(ptr::NonNull::as_ptr) + } + } +} + +impl PartialEq for WeakRef { + fn eq(&self, other: &T) -> bool { + unsafe { + match self.ptr.as_ref().value.get() { + Some(ptr) => ptr::eq(ptr.as_ptr(), other), + None => false, + } + } + } +} + +unsafe impl JSTraceable for WeakRef { + unsafe fn trace(&self, _: *mut JSTracer) { + // Do nothing. + } +} + +impl Drop for WeakRef { + fn drop(&mut self) { + unsafe { + let (count, value) = { + let weak_box = &*self.ptr.as_ptr(); + assert!(weak_box.count.get() > 0); + let count = weak_box.count.get() - 1; + weak_box.count.set(count); + (count, weak_box.value.get()) + }; + if count == 0 { + assert!(value.is_none()); + mem::drop(Box::from_raw(self.ptr.as_ptr())); + } + } + } +}