aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDelan Azabani <dazabani@igalia.com>2023-02-27 22:20:16 +0800
committerDelan Azabani <dazabani@igalia.com>2023-03-23 18:06:17 +0800
commit1f74d4c75bdc3c4a649665bb7e7fb51b6dba854d (patch)
tree0653bb1094e9d6aa1251330896d3400b163d319f
parent4c7f198ee22ba5c6c1393395ceb9889d2d4decaa (diff)
downloadservo-1f74d4c75bdc3c4a649665bb7e7fb51b6dba854d.tar.gz
servo-1f74d4c75bdc3c4a649665bb7e7fb51b6dba854d.zip
revert: Introduce `Untransplantable` trait to indicate transplantability at the type level
(8f7b0cff87f0eab921e13e6990d76e12935e8675)
-rw-r--r--components/domobject_derive/lib.rs46
-rw-r--r--components/script/dom/bindings/reflector.rs56
-rw-r--r--components/script/dom/bindings/root.rs218
-rw-r--r--components/script/dom/bindings/trace.rs4
-rw-r--r--components/script/dom/webgl_extensions/extension.rs4
-rw-r--r--components/script/dom/window.rs13
-rw-r--r--components/script/dom/windowproxy.rs56
-rw-r--r--components/script/script_thread.rs32
8 files changed, 47 insertions, 382 deletions
diff --git a/components/domobject_derive/lib.rs b/components/domobject_derive/lib.rs
index 710e932ae99..c103bb73ece 100644
--- a/components/domobject_derive/lib.rs
+++ b/components/domobject_derive/lib.rs
@@ -12,7 +12,7 @@ extern crate syn;
use proc_macro2;
use quote::TokenStreamExt;
-#[proc_macro_derive(DomObject, attributes(dom_object))]
+#[proc_macro_derive(DomObject)]
pub fn expand_token_stream(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = syn::parse(input).unwrap();
expand_dom_object(input).into()
@@ -29,16 +29,6 @@ fn expand_dom_object(input: syn::DeriveInput) -> proc_macro2::TokenStream {
.split_first()
.expect("#[derive(DomObject)] should not be applied on empty structs");
- // Take additional parameters from `#[dom_object]` helper attributes (if any)
- let mut args = Args::default();
- for attr in input.attrs.iter() {
- if attr.path.is_ident("dom_object") {
- if let Err(e) = attr.parse_meta().and_then(|meta| args.parse_meta(&meta)) {
- return e.to_compile_error().into();
- }
- }
- }
-
let first_field_name = first_field.ident.as_ref().unwrap();
let mut field_types = vec![];
for field in fields {
@@ -74,14 +64,6 @@ fn expand_dom_object(input: syn::DeriveInput) -> proc_macro2::TokenStream {
}
};
- if !args.transplantable {
- items.append_all(quote! {
- impl #impl_generics crate::dom::bindings::reflector::Untransplantable
- for #name #ty_generics #where_clause
- {}
- });
- }
-
let mut params = proc_macro2::TokenStream::new();
params.append_separated(input.generics.type_params().map(|param| &param.ident), ", ");
@@ -118,29 +100,3 @@ fn expand_dom_object(input: syn::DeriveInput) -> proc_macro2::TokenStream {
tokens
}
-
-#[derive(Default)]
-struct Args {
- transplantable: bool,
-}
-
-impl Args {
- fn parse_meta(&mut self, meta: &syn::Meta) -> Result<(), syn::Error> {
- match meta {
- syn::Meta::List(list) => self.parse_meta_list(list),
- _ => return Err(syn::Error::new_spanned(meta, "unrecognized parameter")),
- }
- }
-
- fn parse_meta_list(&mut self, meta_list: &syn::MetaList) -> Result<(), syn::Error> {
- for meta in meta_list.nested.iter() {
- match meta {
- syn::NestedMeta::Meta(syn::Meta::Path(path)) if path.is_ident("transplantable") => {
- self.transplantable = true;
- },
- _ => return Err(syn::Error::new_spanned(meta, "unrecognized parameter")),
- }
- }
- Ok(())
- }
-}
diff --git a/components/script/dom/bindings/reflector.rs b/components/script/dom/bindings/reflector.rs
index 93405380951..04bf9fdbbed 100644
--- a/components/script/dom/bindings/reflector.rs
+++ b/components/script/dom/bindings/reflector.rs
@@ -12,7 +12,7 @@ use crate::dom::globalscope::GlobalScope;
use crate::script_runtime::JSContext;
use js::jsapi::{Heap, JSObject};
use js::rust::HandleObject;
-use std::{default::Default, ops::Deref};
+use std::default::Default;
/// Create the reflector for a new DOM object and yield ownership to the
/// reflector.
@@ -120,57 +120,3 @@ pub trait DomObjectIteratorWrap: DomObjectWrap + JSTraceable + Iterable {
Box<IterableIterator<Self>>,
) -> Root<Dom<IterableIterator<Self>>>;
}
-
-/// A marker trait denoting DOM objects that are constrained to a single
-/// realm. It's implemented by most DOM objects with a notable exception being
-/// `WindowProxy`.
-///
-/// The reflectors of transplantable types may move between realms, and the
-/// compartment invariants [prohibit][1] tracable references from crossing
-/// compartment boundaries. For this reason, references to transplantable types
-/// must be held by `*TransplantableDom*<T>`, which are designed to handle
-/// cross-realm cases. Even when using such reference wrappers, a care must be
-/// taken to ensure cross-realm references do not occur. For instance,
-/// a transplantable DOM object must hold references to other DOM objects by
-/// `*TransplantableDom*<T>` because their realms can "move" in relative to
-/// the transplantable DOM object's.
-///
-/// [1]: https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Internals/Garbage_collection#compartments
-pub trait Untransplantable: DomObject {}
-
-/// Unsafely adds [`Untransplantable`] to the wrapped [`DomObject`].
-#[derive(JSTraceable)]
-#[repr(transparent)]
-pub struct AssertUntransplantable<T: DomObject>(T);
-
-impl<T: DomObject> AssertUntransplantable<T> {
- /// Wrap a reference with `AssertUntransplantable`.
- ///
- /// # Safety
- ///
- /// The constructed `&Self` must not be traced from a GC thing with an
- /// associated compartment. For example, if you create `Dom<T>` from the
- /// returned reference, storing it in a `DomObject` might be unsafe.
- #[inline]
- pub unsafe fn from_ref(x: &T) -> &Self {
- // Safety: `*x` and `Self` has the same representation
- &*(x as *const T as *const Self)
- }
-}
-
-impl<T: DomObject> DomObject for AssertUntransplantable<T> {
- #[inline]
- fn reflector(&self) -> &Reflector {
- self.0.reflector()
- }
-}
-
-impl<T: DomObject> Untransplantable for AssertUntransplantable<T> {}
-
-impl<T: DomObject> Deref for AssertUntransplantable<T> {
- type Target = T;
- #[inline]
- fn deref(&self) -> &Self::Target {
- &self.0
- }
-}
diff --git a/components/script/dom/bindings/root.rs b/components/script/dom/bindings/root.rs
index f6add2f3ae1..b0b7eeb146d 100644
--- a/components/script/dom/bindings/root.rs
+++ b/components/script/dom/bindings/root.rs
@@ -26,7 +26,7 @@
use crate::dom::bindings::conversions::DerivedFrom;
use crate::dom::bindings::inheritance::Castable;
-use crate::dom::bindings::reflector::{DomObject, MutDomObject, Reflector, Untransplantable};
+use crate::dom::bindings::reflector::{DomObject, MutDomObject, Reflector};
use crate::dom::bindings::trace::trace_reflector;
use crate::dom::bindings::trace::JSTraceable;
use crate::dom::node::Node;
@@ -362,7 +362,7 @@ impl<T: DomObject> Deref for Dom<T> {
}
}
-unsafe impl<T: DomObject + Untransplantable> JSTraceable for Dom<T> {
+unsafe impl<T: DomObject> JSTraceable for Dom<T> {
unsafe fn trace(&self, trc: *mut JSTracer) {
let trace_string;
let trace_info = if cfg!(debug_assertions) {
@@ -542,11 +542,11 @@ impl LayoutDom<'_, Node> {
/// on `Dom<T>`.
#[unrooted_must_root_lint::must_root]
#[derive(JSTraceable)]
-pub struct MutDom<T: DomObject + Untransplantable> {
+pub struct MutDom<T: DomObject> {
val: UnsafeCell<Dom<T>>,
}
-impl<T: DomObject + Untransplantable> MutDom<T> {
+impl<T: DomObject> MutDom<T> {
/// Create a new `MutDom`.
pub fn new(initial: &T) -> MutDom<T> {
assert_in_script();
@@ -570,20 +570,20 @@ impl<T: DomObject + Untransplantable> MutDom<T> {
}
}
-impl<T: DomObject + Untransplantable> MallocSizeOf for MutDom<T> {
+impl<T: DomObject> MallocSizeOf for MutDom<T> {
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
// See comment on MallocSizeOf for Dom<T>.
0
}
}
-impl<T: DomObject + Untransplantable> PartialEq for MutDom<T> {
+impl<T: DomObject> PartialEq for MutDom<T> {
fn eq(&self, other: &Self) -> bool {
unsafe { *self.val.get() == *other.val.get() }
}
}
-impl<T: DomObject + Untransplantable + PartialEq> PartialEq<T> for MutDom<T> {
+impl<T: DomObject + PartialEq> PartialEq<T> for MutDom<T> {
fn eq(&self, other: &T) -> bool {
unsafe { **self.val.get() == *other }
}
@@ -605,11 +605,11 @@ pub(crate) fn assert_in_layout() {
/// on `Dom<T>`.
#[unrooted_must_root_lint::must_root]
#[derive(JSTraceable)]
-pub struct MutNullableDom<T: DomObject + Untransplantable> {
+pub struct MutNullableDom<T: DomObject> {
ptr: UnsafeCell<Option<Dom<T>>>,
}
-impl<T: DomObject + Untransplantable> MutNullableDom<T> {
+impl<T: DomObject> MutNullableDom<T> {
/// Create a new `MutNullableDom`.
pub fn new(initial: Option<&T>) -> MutNullableDom<T> {
assert_in_script();
@@ -666,19 +666,19 @@ impl<T: DomObject + Untransplantable> MutNullableDom<T> {
}
}
-impl<T: DomObject + Untransplantable> PartialEq for MutNullableDom<T> {
+impl<T: DomObject> PartialEq for MutNullableDom<T> {
fn eq(&self, other: &Self) -> bool {
unsafe { *self.ptr.get() == *other.ptr.get() }
}
}
-impl<'a, T: DomObject + Untransplantable> PartialEq<Option<&'a T>> for MutNullableDom<T> {
+impl<'a, T: DomObject> PartialEq<Option<&'a T>> for MutNullableDom<T> {
fn eq(&self, other: &Option<&T>) -> bool {
unsafe { *self.ptr.get() == other.map(Dom::from_ref) }
}
}
-impl<T: DomObject + Untransplantable> Default for MutNullableDom<T> {
+impl<T: DomObject> Default for MutNullableDom<T> {
#[allow(unrooted_must_root)]
fn default() -> MutNullableDom<T> {
assert_in_script();
@@ -688,7 +688,7 @@ impl<T: DomObject + Untransplantable> Default for MutNullableDom<T> {
}
}
-impl<T: DomObject + Untransplantable> MallocSizeOf for MutNullableDom<T> {
+impl<T: DomObject> MallocSizeOf for MutNullableDom<T> {
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
// See comment on MallocSizeOf for Dom<T>.
0
@@ -740,7 +740,7 @@ impl<T: DomObject> MallocSizeOf for DomOnceCell<T> {
}
#[allow(unrooted_must_root)]
-unsafe impl<T: DomObject + Untransplantable> JSTraceable for DomOnceCell<T> {
+unsafe impl<T: DomObject> JSTraceable for DomOnceCell<T> {
unsafe fn trace(&self, trc: *mut JSTracer) {
if let Some(ptr) = self.ptr.as_ref() {
ptr.trace(trc);
@@ -748,196 +748,6 @@ unsafe impl<T: DomObject + Untransplantable> JSTraceable for DomOnceCell<T> {
}
}
-/// Essentially a [`MutNullableDom`], but directly references the reflector
-/// so that, with a proper care, a cross-realm reference is prevented from
-/// being formed by transplantation.
-///
-/// This type can hold a reference to an un-[`Untransplantable`] DOM object.
-/// In turn, such objects also need this sort of type to hold references to
-/// other DOM objects whether they are transplantable or not (so the name is
-/// inaccurate, actually).
-///
-/// This should only be used as a field in other DOM objects; see warning
-/// on `Dom<T>`.
-#[unrooted_must_root_lint::must_root]
-pub struct MutNullableTransplantableDom<T: DomObject> {
- /// A reference to the DOM object.
- ptr: UnsafeCell<Option<ptr::NonNull<T>>>,
- /// A tracable reference to the reflector.
- reflector: Heap<*mut JSObject>,
-}
-
-impl<T: DomObject> MutNullableTransplantableDom<T> {
- /// Create a new `MutNullableTransplantableDom`.
- ///
- /// # Safety
- ///
- /// The constructed `MutNullableTransplantableDom` must be pinned before
- /// use.
- ///
- /// FIXME: `std::pin::Pin` might be able to express this better
- pub unsafe fn new() -> MutNullableTransplantableDom<T> {
- assert_in_script();
- MutNullableTransplantableDom {
- ptr: UnsafeCell::new(None),
- reflector: Heap::default(),
- }
- }
-
- /// Get a rooted DOM object out of this object.
- #[allow(unrooted_must_root)]
- pub fn get(&self) -> Option<DomRoot<T>> {
- assert_in_script();
- unsafe { ptr::read(self.ptr.get()).map(|o| DomRoot::from_ref(o.as_ref())) }
- }
-
- /// Set this `MutNullableTransplantableDom` to the given value. The
- /// reflector will be wrapped for `global`'s realm.
- pub fn set(&self, val: Option<&T>, global: &crate::dom::globalscope::GlobalScope) {
- assert_in_script();
- unsafe {
- if let Some(dom) = val {
- let cx = global.get_cx();
- let _ac = crate::realms::enter_realm(global);
- rooted!(in(*cx) let mut reflector = *dom.reflector().get_jsobject());
- js::jsapi::JS_WrapObject(*cx, reflector.handle_mut().into());
- self.reflector.set(reflector.get());
- } else {
- self.reflector.set(std::ptr::null_mut());
- }
-
- *self.ptr.get() = val.map(Into::into);
- }
- }
-}
-
-unsafe impl<T: DomObject> JSTraceable for MutNullableTransplantableDom<T> {
- unsafe fn trace(&self, trc: *mut JSTracer) {
- self.reflector.trace(trc);
- }
-}
-
-impl<T: DomObject> MallocSizeOf for MutNullableTransplantableDom<T> {
- fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
- // See comment on MallocSizeOf for Dom<T>.
- 0
- }
-}
-
-/// Essentially a [`DomOnceCell`], but directly references the reflector
-/// so that, with a proper care, a cross-realm reference is prevented from
-/// being formed by transplantation.
-///
-/// This type can hold a reference to an un-[`Untransplantable`] DOM object.
-/// In turn, such objects also need this sort of type to hold references to
-/// other DOM objects whether they are transplantable or not (so the name is
-/// inaccurate, actually).
-///
-/// This should only be used as a field in other DOM objects; see warning
-/// on `Dom<T>`.
-#[unrooted_must_root_lint::must_root]
-pub struct TransplantableDomOnceCell<T: DomObject> {
- /// A reference to the DOM object.
- ptr: OnceCell<ptr::NonNull<T>>,
- /// A tracable reference to the reflector.
- ///
- /// Invariant: `reflector` points to `ptr.reflector()` or its CCW.
- reflector: Heap<*mut JSObject>,
-}
-
-impl<T: DomObject> TransplantableDomOnceCell<T> {
- /// Create a new `TransplantableDomOnceCell`.
- ///
- /// # Safety
- ///
- /// The constructed `TransplantableDomOnceCell` must be pinned before
- /// use.
- ///
- /// FIXME: `std::pin::Pin` might be able to express this better
- pub unsafe fn new() -> TransplantableDomOnceCell<T> {
- assert_in_script();
- TransplantableDomOnceCell {
- ptr: OnceCell::new(),
- reflector: Heap::default(),
- }
- }
-
- // FIXME: The compartment invariants will be violated if an incorrect global
- // scope is supplied. Should this method be `unsafe fn` because for
- // this reason, or shouldn't it be because there are currently
- // gazillions of other non-`unsafe` ways (`find_document` for one) to
- // obtain other realms' DOM objects?
- /// Set this `TransplantableDomOnceCell` to the given value. The
- /// reflector will be wrapped for `global`'s realm. Does nothing if it's
- /// already set.
- ///
- /// # Errors
- ///
- /// This method returns `Ok(())` if the cell was empty and `Err(())` if
- /// it was full.
- pub fn set<'a>(
- &self,
- val: Option<&T>,
- global: &crate::dom::globalscope::GlobalScope,
- ) -> Result<(), ()> {
- assert_in_script();
-
- if self.ptr.as_ref().is_some() {
- return Err(());
- }
-
- if let Some(dom) = val {
- self.ptr.init_once(|| {
- // We've already checked the emptiness of `self.ptr`
- debug_assert!(self.ptr.as_ref().is_none());
-
- // Initialize `self.reflector`.
- let cx = global.get_cx();
- let _ac = crate::realms::enter_realm(global);
- rooted!(in(*cx) let mut reflector = *dom.reflector().get_jsobject());
- unsafe { js::jsapi::JS_WrapObject(*cx, reflector.handle_mut().into()) };
-
- // The above code isn't supposed to initialize `self` reentrantly
- assert!(self.reflector.get().is_null());
- self.reflector.set(reflector.get());
-
- dom.into()
- });
- }
- Ok(())
- }
-
- /// Get a reference to the DOM object.
- pub fn as_ref(&self) -> Option<&T> {
- self.ptr.as_ref().map(|ptr| unsafe { &*ptr.as_ptr() })
- }
-
- /// Rewrap the reflector with a new realm.
- pub fn rewrap(&self, global: &crate::dom::globalscope::GlobalScope) {
- if self.reflector.get().is_null() {
- return;
- }
- let cx = global.get_cx();
- let _ac = crate::realms::enter_realm(global);
- rooted!(in(*cx) let mut reflector = self.reflector.get());
- unsafe { js::jsapi::JS_WrapObject(*cx, reflector.handle_mut().into()) };
- self.reflector.set(reflector.get());
- }
-}
-
-unsafe impl<T: DomObject> JSTraceable for TransplantableDomOnceCell<T> {
- unsafe fn trace(&self, trc: *mut JSTracer) {
- self.reflector.trace(trc);
- }
-}
-
-impl<T: DomObject> MallocSizeOf for TransplantableDomOnceCell<T> {
- fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
- // See comment on MallocSizeOf for Dom<T>.
- 0
- }
-}
-
impl<'dom, T> LayoutDom<'dom, T>
where
T: 'dom + DomObject,
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs
index 54bb86667c6..a9b5733c9ff 100644
--- a/components/script/dom/bindings/trace.rs
+++ b/components/script/dom/bindings/trace.rs
@@ -32,7 +32,7 @@
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, Reflector, Untransplantable};
+use crate::dom::bindings::reflector::{DomObject, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::{DOMString, USVString};
use crate::dom::bindings::utils::WindowProxyHandler;
@@ -1193,7 +1193,7 @@ impl<'a, T: 'static + JSTraceable> RootedVec<'a, T> {
}
}
-impl<'a, T: 'static + JSTraceable + DomObject + Untransplantable> RootedVec<'a, Dom<T>> {
+impl<'a, T: 'static + JSTraceable + DomObject> RootedVec<'a, Dom<T>> {
/// Create a vector of items of type Dom<T> that is rooted for
/// the lifetime of this struct
pub fn from_iter<I>(root: &'a mut RootableVec<Dom<T>>, iter: I) -> Self
diff --git a/components/script/dom/webgl_extensions/extension.rs b/components/script/dom/webgl_extensions/extension.rs
index 432b0672ce2..3854acee122 100644
--- a/components/script/dom/webgl_extensions/extension.rs
+++ b/components/script/dom/webgl_extensions/extension.rs
@@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use super::WebGLExtensions;
-use crate::dom::bindings::reflector::{DomObject, Untransplantable};
+use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::trace::JSTraceable;
use crate::dom::webglrenderingcontext::WebGLRenderingContext;
@@ -12,7 +12,7 @@ use canvas_traits::webgl::WebGLVersion;
/// Trait implemented by WebGL extensions.
pub trait WebGLExtension: Sized
where
- Self::Extension: DomObject + JSTraceable + Untransplantable,
+ Self::Extension: DomObject + JSTraceable,
{
type Extension;
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index 64ad1d72544..76dcc79424f 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -24,7 +24,7 @@ use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementType
use crate::dom::bindings::num::Finite;
use crate::dom::bindings::refcounted::Trusted;
use crate::dom::bindings::reflector::DomObject;
-use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom, MutNullableTransplantableDom};
+use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
use crate::dom::bindings::str::{DOMString, USVString};
use crate::dom::bindings::structuredclone;
use crate::dom::bindings::trace::{JSTraceable, RootedTraceableBox};
@@ -201,7 +201,7 @@ pub struct Window {
image_cache: Arc<dyn ImageCache>,
#[ignore_malloc_size_of = "channels are hard"]
image_cache_chan: Sender<ImageCacheMsg>,
- window_proxy: MutNullableTransplantableDom<WindowProxy>,
+ window_proxy: MutNullableDom<WindowProxy>,
document: MutNullableDom<Document>,
location: MutNullableDom<Location>,
history: MutNullableDom<History>,
@@ -382,7 +382,7 @@ impl Window {
pub fn clear_js_runtime_for_script_deallocation(&self) {
unsafe {
*self.js_runtime.borrow_for_script_deallocation() = None;
- self.window_proxy.set(None, &self.global().upcast());
+ self.window_proxy.set(None);
self.current_state.set(WindowState::Zombie);
self.ignore_all_tasks();
}
@@ -1682,7 +1682,7 @@ impl Window {
let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
if let Some(currently_active) = proxy.currently_active() {
if currently_active == pipeline_id {
- self.window_proxy.set(None, &self.global());
+ self.window_proxy.set(None);
}
}
}
@@ -2190,7 +2190,7 @@ impl Window {
#[allow(unsafe_code)]
pub fn init_window_proxy(&self, window_proxy: &WindowProxy) {
assert!(self.window_proxy.get().is_none());
- self.window_proxy.set(Some(&window_proxy), &self.global());
+ self.window_proxy.set(Some(&window_proxy));
}
#[allow(unsafe_code)]
@@ -2596,8 +2596,7 @@ impl Window {
location: Default::default(),
history: Default::default(),
custom_element_registry: Default::default(),
- // Safety: This field won't be assigned until it's pinned
- window_proxy: unsafe { MutNullableTransplantableDom::new() },
+ window_proxy: Default::default(),
document: Default::default(),
performance: Default::default(),
navigation_start: Cell::new(navigation_start),
diff --git a/components/script/dom/windowproxy.rs b/components/script/dom/windowproxy.rs
index 0f4264d6bb2..35850f76092 100644
--- a/components/script/dom/windowproxy.rs
+++ b/components/script/dom/windowproxy.rs
@@ -8,7 +8,7 @@ use crate::dom::bindings::error::{throw_dom_exception, Error, Fallible};
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::proxyhandler::set_property_descriptor;
use crate::dom::bindings::reflector::{DomObject, Reflector};
-use crate::dom::bindings::root::{DomRoot, TransplantableDomOnceCell};
+use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::{DOMString, USVString};
use crate::dom::bindings::trace::JSTraceable;
use crate::dom::bindings::utils::{get_array_index_from_id, AsVoidPtr, WindowProxyHandler};
@@ -58,18 +58,10 @@ use std::ptr;
use style::attr::parse_integer;
#[dom_struct]
-// `dom_object(transplantable)` removes `!Untransplantable` impl.
-#[dom_object(transplantable)]
// NOTE: the browsing context for a window is managed in two places:
// here, in script, but also in the constellation. The constellation
// manages the session history, which in script is accessed through
// History objects, messaging the constellation.
-//
-// `WindowProxy` being transplantable means all references to `WindowProxy` must
-// be maintained through cross-realm compatible reference wrappers such as
-// `*TransplantableDom*`. In addition, all DOM references contained within
-// must be wrapped by `*TransplantableDom*` as well because their realms vary
-// from `WindowProxy`'s point of view.
pub struct WindowProxy {
/// The JS WindowProxy object.
/// Unlike other reflectors, we mutate this field because
@@ -109,10 +101,10 @@ pub struct WindowProxy {
is_closing: Cell<bool>,
/// The containing iframe element, if this is a same-origin iframe
- frame_element: TransplantableDomOnceCell<Element>,
+ frame_element: Option<Dom<Element>>,
/// The parent browsing context's window proxy, if this is a nested browsing context
- parent: TransplantableDomOnceCell<WindowProxy>,
+ parent: Option<Dom<WindowProxy>>,
/// https://html.spec.whatwg.org/multipage/#delaying-load-events-mode
delaying_load_events_mode: Cell<bool>,
@@ -128,12 +120,12 @@ pub struct WindowProxy {
}
impl WindowProxy {
- #[allow(unsafe_code)]
pub fn new_inherited(
browsing_context_id: BrowsingContextId,
top_level_browsing_context_id: TopLevelBrowsingContextId,
currently_active: Option<PipelineId>,
frame_element: Option<&Element>,
+ parent: Option<&WindowProxy>,
opener: Option<BrowsingContextId>,
creator: CreatorBrowsingContextInfo,
) -> WindowProxy {
@@ -149,9 +141,8 @@ impl WindowProxy {
discarded: Cell::new(false),
disowned: Cell::new(false),
is_closing: Cell::new(false),
- // Safety: These fields are not set until they are pinned
- frame_element: unsafe { TransplantableDomOnceCell::new() },
- parent: unsafe { TransplantableDomOnceCell::new() },
+ frame_element: frame_element.map(Dom::from_ref),
+ parent: parent.map(Dom::from_ref),
delaying_load_events_mode: Cell::new(false),
opener,
creator_base_url: creator.base_url,
@@ -194,6 +185,7 @@ impl WindowProxy {
top_level_browsing_context_id,
current,
frame_element,
+ parent,
opener,
creator,
));
@@ -216,17 +208,6 @@ impl WindowProxy {
js_proxy.get()
);
window_proxy.reflector.set_jsobject(js_proxy.get());
-
- // Set the remaining fields after pinning.
- window_proxy
- .frame_element
- .set(frame_element, &window_proxy.global())
- .unwrap();
- window_proxy
- .parent
- .set(parent, &window_proxy.global())
- .unwrap();
-
DomRoot::from_ref(&*Box::into_raw(window_proxy))
}
}
@@ -252,6 +233,7 @@ impl WindowProxy {
top_level_browsing_context_id,
None,
None,
+ parent,
opener,
creator,
));
@@ -288,13 +270,6 @@ impl WindowProxy {
js_proxy.get()
);
window_proxy.reflector.set_jsobject(js_proxy.get());
-
- // Set the remaining field after pinning.
- window_proxy
- .parent
- .set(parent, &window_proxy.global())
- .unwrap();
-
DomRoot::from_ref(&*Box::into_raw(window_proxy))
}
}
@@ -448,7 +423,7 @@ impl WindowProxy {
Some(opener_browsing_context_id) => opener_browsing_context_id,
None => return NullValue(),
};
- let parent_browsing_context = self.parent.as_ref();
+ let parent_browsing_context = self.parent.as_deref();
let opener_proxy = match ScriptThread::find_window_proxy(opener_id) {
Some(window_proxy) => window_proxy,
None => {
@@ -618,7 +593,7 @@ impl WindowProxy {
}
pub fn frame_element(&self) -> Option<&Element> {
- self.frame_element.as_ref()
+ self.frame_element.as_deref()
}
pub fn document(&self) -> Option<DomRoot<Document>> {
@@ -628,7 +603,7 @@ impl WindowProxy {
}
pub fn parent(&self) -> Option<&WindowProxy> {
- self.parent.as_ref()
+ self.parent.as_deref()
}
pub fn top(&self) -> &WindowProxy {
@@ -649,11 +624,6 @@ impl WindowProxy {
let handler = CreateWrapperProxyHandler(traps);
assert!(!handler.is_null());
- // FIXME: Disable compacting GC during this operation so that
- // yet-to-be-rewrapped child pointers won't be traced with
- // an incorrect compartment. We need something like
- // `js::AutoDisableCompactingGC`.
-
let cx = window.get_cx();
let window_jsobject = window.reflector().get_jsobject();
let old_js_proxy = self.reflector.get_jsobject();
@@ -681,10 +651,6 @@ impl WindowProxy {
rooted!(in(*cx) let new_js_proxy = JS_TransplantObject(*cx, old_js_proxy, new_js_proxy.handle()));
debug!("Transplanted proxy is {:p}.", new_js_proxy.get());
- // Re-wrap reflectors for the new realm.
- self.frame_element.rewrap(window);
- self.parent.rewrap(window);
-
// Transfer ownership of this browsing context from the old window proxy to the new one.
SetProxyReservedSlot(new_js_proxy.get(), 0, &PrivateValue(self.as_void_ptr()));
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index 8b44f93aa14..b417f453cdf 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -30,7 +30,7 @@ use crate::dom::bindings::conversions::{
};
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::refcounted::Trusted;
-use crate::dom::bindings::reflector::{AssertUntransplantable, DomObject};
+use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::root::ThreadLocalStackRoots;
use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom, RootCollection};
use crate::dom::bindings::str::DOMString;
@@ -522,11 +522,7 @@ pub struct ScriptThread {
documents: DomRefCell<Documents>,
/// The window proxies known by this thread
/// TODO: this map grows, but never shrinks. Issue #15258.
- ///
- /// Safety: `AssertUntransplantable` is safe to be used here because
- /// `ScriptThread` is rooted and not traced by other GC things.
- window_proxies:
- DomRefCell<HashMap<BrowsingContextId, Dom<AssertUntransplantable<WindowProxy>>>>,
+ window_proxies: DomRefCell<HashMap<BrowsingContextId, Dom<WindowProxy>>>,
/// A list of data pertaining to loads that have not yet received a network response
incomplete_loads: DomRefCell<Vec<InProgressLoad>>,
/// A vector containing parser contexts which have not yet been fully processed
@@ -1122,7 +1118,7 @@ impl ScriptThread {
.window_proxies
.borrow()
.get(&id)
- .map(|context| DomRoot::from_ref(&***context))
+ .map(|context| DomRoot::from_ref(&**context))
})
})
}
@@ -1133,7 +1129,7 @@ impl ScriptThread {
let script_thread = unsafe { &*script_thread };
for (_, proxy) in script_thread.window_proxies.borrow().iter() {
if proxy.get_name() == *name {
- return Some(DomRoot::from_ref(&***proxy));
+ return Some(DomRoot::from_ref(&**proxy));
}
}
None
@@ -3149,13 +3145,9 @@ impl ScriptThread {
opener,
creator,
);
-
- // Safety: See `ScriptThread::window_proxies`.
- self.window_proxies.borrow_mut().insert(
- browsing_context_id,
- Dom::from_ref(unsafe { AssertUntransplantable::from_ref(&*window_proxy) }),
- );
-
+ self.window_proxies
+ .borrow_mut()
+ .insert(browsing_context_id, Dom::from_ref(&*window_proxy));
Some(window_proxy)
}
@@ -3210,13 +3202,9 @@ impl ScriptThread {
opener,
creator,
);
-
- // Safety: See `ScriptThread::window_proxies`.
- self.window_proxies.borrow_mut().insert(
- browsing_context_id,
- Dom::from_ref(unsafe { AssertUntransplantable::from_ref(&*window_proxy) }),
- );
-
+ self.window_proxies
+ .borrow_mut()
+ .insert(browsing_context_id, Dom::from_ref(&*window_proxy));
window_proxy
}